summaryrefslogtreecommitdiff
path: root/chromium/ui/base
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-07-31 15:50:41 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 12:35:23 +0000
commit7b2ffa587235a47d4094787d72f38102089f402a (patch)
tree30e82af9cbab08a7fa028bb18f4f2987a3f74dfa /chromium/ui/base
parentd94af01c90575348c4e81a418257f254b6f8d225 (diff)
downloadqtwebengine-chromium-7b2ffa587235a47d4094787d72f38102089f402a.tar.gz
BASELINE: Update Chromium to 76.0.3809.94
Change-Id: I321c3f5f929c105aec0f98c5091ef6108822e647 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/ui/base')
-rw-r--r--chromium/ui/base/BUILD.gn15
-rw-r--r--chromium/ui/base/accelerators/accelerator.h2
-rw-r--r--chromium/ui/base/accelerators/global_media_keys_listener_win.h1
-rw-r--r--chromium/ui/base/accelerators/media_keys_listener.h7
-rw-r--r--chromium/ui/base/accelerators/media_keys_listener_mac.mm1
-rw-r--r--chromium/ui/base/accelerators/mpris_media_keys_listener.cc10
-rw-r--r--chromium/ui/base/accelerators/mpris_media_keys_listener.h2
-rw-r--r--chromium/ui/base/accelerators/mpris_media_keys_listener_unittest.cc28
-rw-r--r--chromium/ui/base/accelerators/remote_command_media_keys_listener_mac.h2
-rw-r--r--chromium/ui/base/accelerators/remote_command_media_keys_listener_mac.mm10
-rw-r--r--chromium/ui/base/accelerators/remote_command_media_keys_listener_mac_unittest.mm46
-rw-r--r--chromium/ui/base/accelerators/system_media_controls_media_keys_listener.cc10
-rw-r--r--chromium/ui/base/accelerators/system_media_controls_media_keys_listener.h3
-rw-r--r--chromium/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc32
-rw-r--r--chromium/ui/base/class_property.cc16
-rw-r--r--chromium/ui/base/class_property.h13
-rw-r--r--chromium/ui/base/clipboard/clipboard.h5
-rw-r--r--chromium/ui/base/clipboard/clipboard_aura.cc16
-rw-r--r--chromium/ui/base/clipboard/clipboard_constants.h2
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type.h16
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type_android.cc4
-rw-r--r--chromium/ui/base/clipboard/clipboard_format_type_win.cc74
-rw-r--r--chromium/ui/base/clipboard/clipboard_monitor.cc2
-rw-r--r--chromium/ui/base/clipboard/clipboard_observer.h2
-rw-r--r--chromium/ui/base/clipboard/clipboard_test_template.h2
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_win.cc454
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_win.h31
-rw-r--r--chromium/ui/base/cocoa/nib_loading.h20
-rw-r--r--chromium/ui/base/cocoa/nib_loading.mm38
-rw-r--r--chromium/ui/base/cocoa/ns_view_ids.h49
-rw-r--r--chromium/ui/base/cocoa/ns_view_ids.mm49
-rw-r--r--chromium/ui/base/cocoa/remote_views_window.h25
-rw-r--r--chromium/ui/base/cocoa/remote_views_window.mm45
-rw-r--r--chromium/ui/base/cocoa/views_hostable.h16
-rw-r--r--chromium/ui/base/dragdrop/download_file_interface.h4
-rw-r--r--chromium/ui/base/dragdrop/drag_source_win.h2
-rw-r--r--chromium/ui/base/dragdrop/drop_target_win.cc2
-rw-r--r--chromium/ui/base/dragdrop/file_info.cc4
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data.cc22
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data.h52
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc2
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_factory.cc19
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_factory.h17
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc167
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_win.h18
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc535
-rw-r--r--chromium/ui/base/emoji/emoji_panel_helper_win.cc2
-rw-r--r--chromium/ui/base/idle/BUILD.gn23
-rw-r--r--chromium/ui/base/idle/idle.cc5
-rw-r--r--chromium/ui/base/idle/idle_android.cc4
-rw-r--r--chromium/ui/base/idle/idle_chromeos.cc4
-rw-r--r--chromium/ui/base/idle/idle_internal.cc16
-rw-r--r--chromium/ui/base/idle/idle_internal.h20
-rw-r--r--chromium/ui/base/idle/idle_linux.cc5
-rw-r--r--chromium/ui/base/idle/idle_mac.mm5
-rw-r--r--chromium/ui/base/idle/idle_win.cc4
-rw-r--r--chromium/ui/base/idle/scoped_set_idle_state.cc20
-rw-r--r--chromium/ui/base/idle/scoped_set_idle_state.h26
-rw-r--r--chromium/ui/base/ime/BUILD.gn1
-rw-r--r--chromium/ui/base/ime/constants.cc12
-rw-r--r--chromium/ui/base/ime/constants.h7
-rw-r--r--chromium/ui/base/ime/dummy_text_input_client.cc10
-rw-r--r--chromium/ui/base/ime/dummy_text_input_client.h8
-rw-r--r--chromium/ui/base/ime/ime_engine_handler_interface.h4
-rw-r--r--chromium/ui/base/ime/ime_input_context_handler_interface.h9
-rw-r--r--chromium/ui/base/ime/ime_text_span.cc11
-rw-r--r--chromium/ui/base/ime/ime_text_span.h16
-rw-r--r--chromium/ui/base/ime/init/input_method_factory.cc2
-rw-r--r--chromium/ui/base/ime/input_method_base.cc9
-rw-r--r--chromium/ui/base/ime/input_method_base.h8
-rw-r--r--chromium/ui/base/ime/input_method_delegate.cc8
-rw-r--r--chromium/ui/base/ime/input_method_delegate.h17
-rw-r--r--chromium/ui/base/ime/linux/input_method_auralinux.cc3
-rw-r--r--chromium/ui/base/ime/mock_ime_input_context_handler.cc9
-rw-r--r--chromium/ui/base/ime/mock_ime_input_context_handler.h8
-rw-r--r--chromium/ui/base/ime/mojo/BUILD.gn2
-rw-r--r--chromium/ui/base/ime/mojo/ime.mojom90
-rw-r--r--chromium/ui/base/ime/mojo/ime_engine_factory_registry.mojom13
-rw-r--r--chromium/ui/base/ime/mojo/ime_struct_traits_unittest.cc3
-rw-r--r--chromium/ui/base/ime/text_input_action.h29
-rw-r--r--chromium/ui/base/ime/text_input_client.h9
-rw-r--r--chromium/ui/base/ime/win/BUILD.gn2
-rw-r--r--chromium/ui/base/ime/win/imm32_manager.cc4
-rw-r--r--chromium/ui/base/ime/win/imm32_manager.h2
-rw-r--r--chromium/ui/base/ime/win/input_method_win_base.cc7
-rw-r--r--chromium/ui/base/ime/win/input_method_win_imm32.cc7
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc2
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc2
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc4
-rw-r--r--chromium/ui/base/ime/win/tsf_input_scope.cc14
-rw-r--r--chromium/ui/base/ime/win/tsf_input_scope.h3
-rw-r--r--chromium/ui/base/ime/win/tsf_input_scope_unittest.cc51
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store.cc33
-rw-r--r--chromium/ui/base/ime/win/tsf_text_store_unittest.cc18
-rw-r--r--chromium/ui/base/material_design/material_design_controller.cc2
-rw-r--r--chromium/ui/base/models/combobox_model_observer.h5
-rw-r--r--chromium/ui/base/models/simple_menu_model.cc20
-rw-r--r--chromium/ui/base/models/simple_menu_model.h10
-rw-r--r--chromium/ui/base/models/tree_model.h13
-rw-r--r--chromium/ui/base/models/tree_node_iterator.h2
-rw-r--r--chromium/ui/base/models/tree_node_model.h61
-rw-r--r--chromium/ui/base/models/tree_node_model_unittest.cc6
-rw-r--r--chromium/ui/base/property_data.h22
-rw-r--r--chromium/ui/base/resource/data_pack.cc20
-rw-r--r--chromium/ui/base/resource/data_pack.h1
-rw-r--r--chromium/ui/base/resource/data_pack_literal.cc11
-rw-r--r--chromium/ui/base/resource/data_pack_unittest.cc11
-rw-r--r--chromium/ui/base/resource/resource_bundle.cc11
-rw-r--r--chromium/ui/base/resource/resource_bundle.h4
-rw-r--r--chromium/ui/base/resource/resource_bundle_android.cc21
-rw-r--r--chromium/ui/base/resource/resource_bundle_unittest.cc20
-rw-r--r--chromium/ui/base/resource/resource_data_dll_win.cc4
-rw-r--r--chromium/ui/base/resource/resource_data_dll_win.h1
-rw-r--r--chromium/ui/base/resource/resource_handle.h4
-rw-r--r--chromium/ui/base/ui_base_features.cc35
-rw-r--r--chromium/ui/base/ui_base_features.h24
-rw-r--r--chromium/ui/base/ui_base_paths.cc2
-rw-r--r--chromium/ui/base/webui/web_ui_util.cc6
-rw-r--r--chromium/ui/base/win/hwnd_subclass.cc18
-rw-r--r--chromium/ui/base/win/lock_state.cc2
-rw-r--r--chromium/ui/base/win/scoped_ole_initializer.cc24
-rw-r--r--chromium/ui/base/win/scoped_ole_initializer.h12
-rw-r--r--chromium/ui/base/win/shell.cc2
-rw-r--r--chromium/ui/base/win/system_media_controls/BUILD.gn4
-rw-r--r--chromium/ui/base/win/system_media_controls/mock_system_media_controls_service.h7
-rw-r--r--chromium/ui/base/win/system_media_controls/system_media_controls_service.h13
-rw-r--r--chromium/ui/base/win/system_media_controls/system_media_controls_service_impl.cc163
-rw-r--r--chromium/ui/base/win/system_media_controls/system_media_controls_service_impl.h21
-rw-r--r--chromium/ui/base/win/touch_input.cc9
-rw-r--r--chromium/ui/base/window_tracker_template.h89
-rw-r--r--chromium/ui/base/x/x11_display_util.cc22
-rw-r--r--chromium/ui/base/x/x11_util.cc8
-rw-r--r--chromium/ui/base/x/x11_util.h3
133 files changed, 2304 insertions, 872 deletions
diff --git a/chromium/ui/base/BUILD.gn b/chromium/ui/base/BUILD.gn
index 960d5835fcf..20371e7cd4e 100644
--- a/chromium/ui/base/BUILD.gn
+++ b/chromium/ui/base/BUILD.gn
@@ -44,6 +44,7 @@ component("ui_data_pack") {
deps = [
"//base",
+ "//net",
]
defines = [ "UI_DATA_PACK_IMPLEMENTATION" ]
@@ -108,18 +109,12 @@ jumbo_component("base") {
"cocoa/focus_window_set.mm",
"cocoa/menu_controller.h",
"cocoa/menu_controller.mm",
- "cocoa/nib_loading.h",
- "cocoa/nib_loading.mm",
- "cocoa/ns_view_ids.h",
- "cocoa/ns_view_ids.mm",
"cocoa/quartz_util.h",
"cocoa/quartz_util.mm",
"cocoa/remote_accessibility_api.h",
"cocoa/remote_accessibility_api.mm",
"cocoa/remote_layer_api.h",
"cocoa/remote_layer_api.mm",
- "cocoa/remote_views_window.h",
- "cocoa/remote_views_window.mm",
"cocoa/secure_password_input.h",
"cocoa/secure_password_input.mm",
"cocoa/text_services_context_menu.cc",
@@ -223,7 +218,6 @@ jumbo_component("base") {
"page_transition_types.h",
"platform_window_defaults.cc",
"platform_window_defaults.h",
- "property_data.h",
"resource/resource_bundle.cc",
"resource/resource_bundle.h",
"resource/resource_bundle_android.cc",
@@ -484,11 +478,6 @@ jumbo_component("base") {
}
}
- if (use_aura) {
- deps += [ "//ui/events" ]
- sources += [ "window_tracker_template.h" ]
- }
-
if (!use_aura || !is_linux) {
sources -= [ "resource/resource_bundle_auralinux.cc" ]
}
@@ -670,6 +659,8 @@ jumbo_static_library("test_support") {
"test/cocoa_helper.mm",
"test/menu_test_observer.h",
"test/menu_test_observer.mm",
+ "test/ns_ax_tree_validator.h",
+ "test/ns_ax_tree_validator.mm",
"test/nswindow_fullscreen_notification_waiter.h",
"test/nswindow_fullscreen_notification_waiter.mm",
"test/scoped_fake_full_keyboard_access.h",
diff --git a/chromium/ui/base/accelerators/accelerator.h b/chromium/ui/base/accelerators/accelerator.h
index 5ece4bf4168..9bcf7de889d 100644
--- a/chromium/ui/base/accelerators/accelerator.h
+++ b/chromium/ui/base/accelerators/accelerator.h
@@ -125,7 +125,7 @@ class UI_BASE_EXPORT Accelerator {
bool interrupted_by_mouse_event_;
// The |source_device_id_| of the KeyEvent.
- int source_device_id_ = -1;
+ int source_device_id_ = ui::ED_UNKNOWN_DEVICE;
};
// An interface that classes that want to register for keyboard accelerators
diff --git a/chromium/ui/base/accelerators/global_media_keys_listener_win.h b/chromium/ui/base/accelerators/global_media_keys_listener_win.h
index 4b95a20b1dc..8de4946c61c 100644
--- a/chromium/ui/base/accelerators/global_media_keys_listener_win.h
+++ b/chromium/ui/base/accelerators/global_media_keys_listener_win.h
@@ -32,6 +32,7 @@ class UI_BASE_EXPORT GlobalMediaKeysListenerWin : public MediaKeysListener {
// MediaKeysListener implementation.
bool StartWatchingMediaKey(KeyboardCode key_code) override;
void StopWatchingMediaKey(KeyboardCode key_code) override;
+ void SetIsMediaPlaying(bool is_playing) override {}
private:
// Called by SingletonHwndObserver.
diff --git a/chromium/ui/base/accelerators/media_keys_listener.h b/chromium/ui/base/accelerators/media_keys_listener.h
index 9072523c656..997718d8aff 100644
--- a/chromium/ui/base/accelerators/media_keys_listener.h
+++ b/chromium/ui/base/accelerators/media_keys_listener.h
@@ -49,6 +49,13 @@ class UI_BASE_EXPORT MediaKeysListener {
virtual bool StartWatchingMediaKey(KeyboardCode key_code) = 0;
// Stop listening for a given media key.
virtual void StopWatchingMediaKey(KeyboardCode key_code) = 0;
+
+ // Informs the listener whether or not media is currently playing. In some
+ // implementations this will prevent us from calling PlayPause unnecessarily.
+ // TODO(https://crbug.com/974035): Once the MediaKeysListenerManager has been
+ // refactored to work with system media controls this should no longer be
+ // needed and should be deleted.
+ virtual void SetIsMediaPlaying(bool is_playing) = 0;
};
} // namespace ui
diff --git a/chromium/ui/base/accelerators/media_keys_listener_mac.mm b/chromium/ui/base/accelerators/media_keys_listener_mac.mm
index 71b417ee8b6..f4e3126a4ef 100644
--- a/chromium/ui/base/accelerators/media_keys_listener_mac.mm
+++ b/chromium/ui/base/accelerators/media_keys_listener_mac.mm
@@ -46,6 +46,7 @@ class MediaKeysListenerImpl : public MediaKeysListener {
// MediaKeysListener:
bool StartWatchingMediaKey(KeyboardCode key_code) override;
void StopWatchingMediaKey(KeyboardCode key_code) override;
+ void SetIsMediaPlaying(bool is_playing) override {}
private:
// Callback on media key event.
diff --git a/chromium/ui/base/accelerators/mpris_media_keys_listener.cc b/chromium/ui/base/accelerators/mpris_media_keys_listener.cc
index 7edd4913fdb..816538497ad 100644
--- a/chromium/ui/base/accelerators/mpris_media_keys_listener.cc
+++ b/chromium/ui/base/accelerators/mpris_media_keys_listener.cc
@@ -88,6 +88,10 @@ void MprisMediaKeysListener::StopWatchingMediaKey(KeyboardCode key_code) {
}
}
+void MprisMediaKeysListener::SetIsMediaPlaying(bool is_playing) {
+ is_media_playing_ = is_playing;
+}
+
void MprisMediaKeysListener::OnNext() {
MaybeSendKeyCode(VKEY_MEDIA_NEXT_TRACK);
}
@@ -97,7 +101,8 @@ void MprisMediaKeysListener::OnPrevious() {
}
void MprisMediaKeysListener::OnPause() {
- MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
+ if (is_media_playing_)
+ MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
}
void MprisMediaKeysListener::OnPlayPause() {
@@ -109,7 +114,8 @@ void MprisMediaKeysListener::OnStop() {
}
void MprisMediaKeysListener::OnPlay() {
- MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
+ if (!is_media_playing_)
+ MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
}
void MprisMediaKeysListener::MaybeSendKeyCode(KeyboardCode key_code) {
diff --git a/chromium/ui/base/accelerators/mpris_media_keys_listener.h b/chromium/ui/base/accelerators/mpris_media_keys_listener.h
index 166b2492851..ff95808bdc1 100644
--- a/chromium/ui/base/accelerators/mpris_media_keys_listener.h
+++ b/chromium/ui/base/accelerators/mpris_media_keys_listener.h
@@ -35,6 +35,7 @@ class UI_BASE_EXPORT MprisMediaKeysListener
// MediaKeysListener implementation.
bool StartWatchingMediaKey(KeyboardCode key_code) override;
void StopWatchingMediaKey(KeyboardCode key_code) override;
+ void SetIsMediaPlaying(bool is_playing) override;
// mpris::MprisServiceObserver implementation.
void OnNext() override;
@@ -57,6 +58,7 @@ class UI_BASE_EXPORT MprisMediaKeysListener
MediaKeysListener::Delegate* delegate_;
base::flat_set<KeyboardCode> key_codes_;
mpris::MprisService* service_ = nullptr;
+ bool is_media_playing_ = false;
DISALLOW_COPY_AND_ASSIGN(MprisMediaKeysListener);
};
diff --git a/chromium/ui/base/accelerators/mpris_media_keys_listener_unittest.cc b/chromium/ui/base/accelerators/mpris_media_keys_listener_unittest.cc
index 29b570e37ed..5f4eb42dea8 100644
--- a/chromium/ui/base/accelerators/mpris_media_keys_listener_unittest.cc
+++ b/chromium/ui/base/accelerators/mpris_media_keys_listener_unittest.cc
@@ -118,4 +118,32 @@ TEST_F(MprisMediaKeysListenerTest, ListenForMultipleKeys) {
listener()->OnPrevious();
}
+TEST_F(MprisMediaKeysListenerTest, DoesNotFirePlayPauseOnPauseEventWhenPaused) {
+ // Should be set to true when we start listening for the key.
+ EXPECT_CALL(mock_mpris_service(), SetCanPlay(true));
+ EXPECT_CALL(mock_mpris_service(), SetCanPause(true));
+ EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0);
+
+ listener()->Initialize();
+ listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+ listener()->SetIsMediaPlaying(false);
+
+ // Simulate media key press.
+ listener()->OnPause();
+}
+
+TEST_F(MprisMediaKeysListenerTest, DoesNotFirePlayPauseOnPlayEventWhenPlaying) {
+ // Should be set to true when we start listening for the key.
+ EXPECT_CALL(mock_mpris_service(), SetCanPlay(true));
+ EXPECT_CALL(mock_mpris_service(), SetCanPause(true));
+ EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0);
+
+ listener()->Initialize();
+ listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+ listener()->SetIsMediaPlaying(true);
+
+ // Simulate media key press.
+ listener()->OnPlay();
+}
+
} // namespace ui
diff --git a/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac.h b/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac.h
index e07717568f0..192c921ab29 100644
--- a/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac.h
+++ b/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac.h
@@ -37,6 +37,7 @@ class UI_BASE_EXPORT API_AVAILABLE(macos(10.12.2))
// MediaKeysListener implementation.
bool StartWatchingMediaKey(KeyboardCode key_code) override;
void StopWatchingMediaKey(KeyboardCode key_code) override;
+ void SetIsMediaPlaying(bool is_playing) override;
// now_playing::RemoteCommandCenterDelegateObserver implementation.
void OnNext() override;
@@ -61,6 +62,7 @@ class UI_BASE_EXPORT API_AVAILABLE(macos(10.12.2))
base::flat_set<KeyboardCode> key_codes_;
now_playing::RemoteCommandCenterDelegate* remote_command_center_delegate_ =
nullptr;
+ bool is_media_playing_ = false;
DISALLOW_COPY_AND_ASSIGN(RemoteCommandMediaKeysListenerMac);
};
diff --git a/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac.mm b/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac.mm
index ddcc54426c3..0f7265d6cea 100644
--- a/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac.mm
+++ b/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac.mm
@@ -91,6 +91,10 @@ void RemoteCommandMediaKeysListenerMac::StopWatchingMediaKey(
}
}
+void RemoteCommandMediaKeysListenerMac::SetIsMediaPlaying(bool is_playing) {
+ is_media_playing_ = is_playing;
+}
+
void RemoteCommandMediaKeysListenerMac::OnNext() {
MaybeSend(VKEY_MEDIA_NEXT_TRACK);
}
@@ -100,7 +104,8 @@ void RemoteCommandMediaKeysListenerMac::OnPrevious() {
}
void RemoteCommandMediaKeysListenerMac::OnPause() {
- MaybeSend(VKEY_MEDIA_PLAY_PAUSE);
+ if (is_media_playing_)
+ MaybeSend(VKEY_MEDIA_PLAY_PAUSE);
}
void RemoteCommandMediaKeysListenerMac::OnPlayPause() {
@@ -112,7 +117,8 @@ void RemoteCommandMediaKeysListenerMac::OnStop() {
}
void RemoteCommandMediaKeysListenerMac::OnPlay() {
- MaybeSend(VKEY_MEDIA_PLAY_PAUSE);
+ if (!is_media_playing_)
+ MaybeSend(VKEY_MEDIA_PLAY_PAUSE);
}
void RemoteCommandMediaKeysListenerMac::MaybeSend(KeyboardCode key_code) {
diff --git a/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac_unittest.mm b/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac_unittest.mm
index 123b3f00497..c5860602e3b 100644
--- a/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac_unittest.mm
+++ b/chromium/ui/base/accelerators/remote_command_media_keys_listener_mac_unittest.mm
@@ -118,4 +118,50 @@ TEST_F(RemoteCommandMediaKeysListenerMacTest, ListenForMultipleKeys) {
}
}
+TEST_F(RemoteCommandMediaKeysListenerMacTest,
+ DoesNotFirePlayPauseOnPauseEventWhenPaused) {
+ if (@available(macOS 10.12.2, *)) {
+ now_playing::MockRemoteCommandCenterDelegate rcc_delegate;
+ MockMediaKeysListenerDelegate delegate;
+ RemoteCommandMediaKeysListenerMac listener(&delegate);
+ listener.SetRemoteCommandCenterDelegateForTesting(&rcc_delegate);
+
+ EXPECT_CALL(rcc_delegate, AddObserver(&listener));
+ EXPECT_CALL(rcc_delegate, SetCanPlayPause(true));
+ EXPECT_CALL(rcc_delegate, SetCanPlay(true));
+ EXPECT_CALL(rcc_delegate, SetCanPause(true));
+ EXPECT_CALL(delegate, OnMediaKeysAccelerator(_)).Times(0);
+
+ listener.Initialize();
+ listener.StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+ listener.SetIsMediaPlaying(false);
+
+ // Simulate media key press.
+ listener.OnPause();
+ }
+}
+
+TEST_F(RemoteCommandMediaKeysListenerMacTest,
+ DoesNotFirePlayPauseOnPlayEventWhenPlaying) {
+ if (@available(macOS 10.12.2, *)) {
+ now_playing::MockRemoteCommandCenterDelegate rcc_delegate;
+ MockMediaKeysListenerDelegate delegate;
+ RemoteCommandMediaKeysListenerMac listener(&delegate);
+ listener.SetRemoteCommandCenterDelegateForTesting(&rcc_delegate);
+
+ EXPECT_CALL(rcc_delegate, AddObserver(&listener));
+ EXPECT_CALL(rcc_delegate, SetCanPlayPause(true));
+ EXPECT_CALL(rcc_delegate, SetCanPlay(true));
+ EXPECT_CALL(rcc_delegate, SetCanPause(true));
+ EXPECT_CALL(delegate, OnMediaKeysAccelerator(_)).Times(0);
+
+ listener.Initialize();
+ listener.StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+ listener.SetIsMediaPlaying(true);
+
+ // Simulate media key press.
+ listener.OnPlay();
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.cc b/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.cc
index a07e0eb4d7b..f4de72a8323 100644
--- a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.cc
+++ b/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.cc
@@ -104,6 +104,10 @@ void SystemMediaControlsMediaKeysListener::StopWatchingMediaKey(
}
}
+void SystemMediaControlsMediaKeysListener::SetIsMediaPlaying(bool is_playing) {
+ is_media_playing_ = is_playing;
+}
+
void SystemMediaControlsMediaKeysListener::OnNext() {
MaybeSendKeyCode(VKEY_MEDIA_NEXT_TRACK);
}
@@ -113,7 +117,8 @@ void SystemMediaControlsMediaKeysListener::OnPrevious() {
}
void SystemMediaControlsMediaKeysListener::OnPause() {
- MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
+ if (is_media_playing_)
+ MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
}
void SystemMediaControlsMediaKeysListener::OnStop() {
@@ -121,7 +126,8 @@ void SystemMediaControlsMediaKeysListener::OnStop() {
}
void SystemMediaControlsMediaKeysListener::OnPlay() {
- MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
+ if (!is_media_playing_)
+ MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
}
void SystemMediaControlsMediaKeysListener::MaybeSendKeyCode(
diff --git a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.h b/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.h
index c900d8414c9..1bc133b7af6 100644
--- a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.h
+++ b/chromium/ui/base/accelerators/system_media_controls_media_keys_listener.h
@@ -35,6 +35,7 @@ class UI_BASE_EXPORT SystemMediaControlsMediaKeysListener
// MediaKeysListener implementation.
bool StartWatchingMediaKey(KeyboardCode key_code) override;
void StopWatchingMediaKey(KeyboardCode key_code) override;
+ void SetIsMediaPlaying(bool is_playing) override;
// system_media_controls::SystemMediaControlsServiceObserver implementation.
void OnNext() override;
@@ -61,6 +62,8 @@ class UI_BASE_EXPORT SystemMediaControlsMediaKeysListener
system_media_controls::SystemMediaControlsService* service_ = nullptr;
+ bool is_media_playing_ = false;
+
DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsMediaKeysListener);
};
diff --git a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc b/chromium/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc
index b07c9a59eef..f4d20b0e35f 100644
--- a/chromium/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc
+++ b/chromium/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc
@@ -132,4 +132,36 @@ TEST_F(SystemMediaControlsMediaKeysListenerTest, ListenForMultipleKeys) {
listener()->OnPrevious();
}
+TEST_F(SystemMediaControlsMediaKeysListenerTest,
+ DoesNotFirePlayPauseOnPauseEventWhenPaused) {
+ // Should be set to true when we start listening for the key.
+ EXPECT_CALL(mock_system_media_controls_service(), SetIsPlayEnabled(true));
+ EXPECT_CALL(mock_system_media_controls_service(), SetIsPauseEnabled(true));
+
+ EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0);
+
+ ASSERT_TRUE(listener()->Initialize());
+ listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+ listener()->SetIsMediaPlaying(false);
+
+ // Simulate media key press.
+ listener()->OnPause();
+}
+
+TEST_F(SystemMediaControlsMediaKeysListenerTest,
+ DoesNotFirePlayPauseOnPlayEventWhenPlaying) {
+ // Should be set to true when we start listening for the key.
+ EXPECT_CALL(mock_system_media_controls_service(), SetIsPlayEnabled(true));
+ EXPECT_CALL(mock_system_media_controls_service(), SetIsPauseEnabled(true));
+
+ EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0);
+
+ ASSERT_TRUE(listener()->Initialize());
+ listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+ listener()->SetIsMediaPlaying(true);
+
+ // Simulate media key press.
+ listener()->OnPlay();
+}
+
} // namespace ui
diff --git a/chromium/ui/base/class_property.cc b/chromium/ui/base/class_property.cc
index 162ac890cb8..d6a5378aeb9 100644
--- a/chromium/ui/base/class_property.cc
+++ b/chromium/ui/base/class_property.cc
@@ -20,14 +20,6 @@ int64_t PropertyHandler::SetPropertyInternal(const void* key,
PropertyDeallocator deallocator,
int64_t value,
int64_t default_value) {
- // TODO(https://crbug.com/952087): ideally this code would early out if the
- // value isn't changing. Unfortunately that breaks some assumptions.
- // |is_value_changing| is a best guess at whether the value is changing, and
- // doesn't handle non-POD types.
- const bool is_value_changing =
- value != GetPropertyInternal(key, default_value);
- std::unique_ptr<PropertyData> data =
- BeforePropertyChange(key, is_value_changing);
int64_t old = GetPropertyInternal(key, default_value);
if (value == default_value) {
prop_map_.erase(key);
@@ -38,16 +30,10 @@ int64_t PropertyHandler::SetPropertyInternal(const void* key,
prop_value.deallocator = deallocator;
prop_map_[key] = prop_value;
}
- AfterPropertyChange(key, old, std::move(data));
+ AfterPropertyChange(key, old);
return old;
}
-std::unique_ptr<PropertyData> PropertyHandler::BeforePropertyChange(
- const void* key,
- bool is_value_changing) {
- return nullptr;
-}
-
void PropertyHandler::ClearProperties() {
// Clear properties.
for (std::map<const void*, Value>::const_iterator iter = prop_map_.begin();
diff --git a/chromium/ui/base/class_property.h b/chromium/ui/base/class_property.h
index 7da967e1293..40bcdeb99f5 100644
--- a/chromium/ui/base/class_property.h
+++ b/chromium/ui/base/class_property.h
@@ -8,11 +8,9 @@
#include <stdint.h>
#include <map>
-#include <memory>
#include <set>
#include "base/time/time.h"
-#include "ui/base/property_data.h"
#include "ui/base/ui_base_export.h"
#include "ui/base/ui_base_types.h"
@@ -93,16 +91,7 @@ class UI_BASE_EXPORT PropertyHandler {
protected:
friend class subtle::PropertyHelper;
- // Called from SetPropertyInternal() prior to changing the value. If
- // |is_value_changing| is false, the new value is the same as the old value
- // (in other words, the value isn't really changing, but observers will
- // still be notified).
- virtual std::unique_ptr<PropertyData> BeforePropertyChange(
- const void* key,
- bool is_value_changing);
- virtual void AfterPropertyChange(const void* key,
- int64_t old_value,
- std::unique_ptr<PropertyData> data) {}
+ virtual void AfterPropertyChange(const void* key, int64_t old_value) {}
void ClearProperties();
// Called by the public {Set,Get,Clear}Property functions.
diff --git a/chromium/ui/base/clipboard/clipboard.h b/chromium/ui/base/clipboard/clipboard.h
index 913149dbd93..f6ca0055401 100644
--- a/chromium/ui/base/clipboard/clipboard.h
+++ b/chromium/ui/base/clipboard/clipboard.h
@@ -129,6 +129,7 @@ class COMPONENT_EXPORT(BASE_CLIPBOARD) Clipboard : public base::ThreadChecker {
base::string16* result) const = 0;
// Reads a bookmark from the clipboard, if available.
+ // |title| or |url| may be null.
virtual void ReadBookmark(base::string16* title, std::string* url) const = 0;
// Reads raw data from the clipboard with the given format type. Stores result
@@ -146,8 +147,8 @@ class COMPONENT_EXPORT(BASE_CLIPBOARD) Clipboard : public base::ThreadChecker {
protected:
static Clipboard* Create();
- Clipboard() {}
- virtual ~Clipboard() {}
+ Clipboard() = default;
+ virtual ~Clipboard() = default;
// ObjectType designates the type of data to be stored in the clipboard. This
// designation is shared across all OSes. The system-specific designation
diff --git a/chromium/ui/base/clipboard/clipboard_aura.cc b/chromium/ui/base/clipboard/clipboard_aura.cc
index 653b3ac1f6a..7d73d97f6ba 100644
--- a/chromium/ui/base/clipboard/clipboard_aura.cc
+++ b/chromium/ui/base/clipboard/clipboard_aura.cc
@@ -50,7 +50,7 @@ class ClipboardData {
: web_smart_paste_(false),
format_(0) {}
- virtual ~ClipboardData() {}
+ virtual ~ClipboardData() = default;
// Bitmask of AuraClipboardFormat types.
int format() const { return format_; }
@@ -164,7 +164,7 @@ class AuraClipboard {
AuraClipboard() : sequence_number_(0) {
}
- ~AuraClipboard() {}
+ ~AuraClipboard() = default;
void Clear() {
sequence_number_++;
@@ -279,14 +279,18 @@ class AuraClipboard {
// Reads bookmark from the data at the top of clipboard stack.
void ReadBookmark(base::string16* title, std::string* url) const {
- title->clear();
- url->clear();
+ if (title)
+ title->clear();
+ if (url)
+ url->clear();
if (!HasFormat(BOOKMARK))
return;
const ClipboardData* data = GetData();
- *title = base::UTF8ToUTF16(data->bookmark_title());
- *url = data->bookmark_url();
+ if (title)
+ *title = base::UTF8ToUTF16(data->bookmark_title());
+ if (url)
+ *url = data->bookmark_url();
}
void ReadData(const std::string& type, std::string* result) const {
diff --git a/chromium/ui/base/clipboard/clipboard_constants.h b/chromium/ui/base/clipboard/clipboard_constants.h
index 8c499112292..9f114db255e 100644
--- a/chromium/ui/base/clipboard/clipboard_constants.h
+++ b/chromium/ui/base/clipboard/clipboard_constants.h
@@ -20,7 +20,7 @@ class NSString;
namespace ui {
-#if defined(OS_MACOSX) && !defined(USE_AURA)
+#if defined(OS_MACOSX)
COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES)
extern NSString* const kWebCustomDataPboardType;
#endif
diff --git a/chromium/ui/base/clipboard/clipboard_format_type.h b/chromium/ui/base/clipboard/clipboard_format_type.h
index eb5b91ff29f..07d8e08273e 100644
--- a/chromium/ui/base/clipboard/clipboard_format_type.h
+++ b/chromium/ui/base/clipboard/clipboard_format_type.h
@@ -5,6 +5,8 @@
#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_FORMAT_TYPE_H_
#define UI_BASE_CLIPBOARD_CLIPBOARD_FORMAT_TYPE_H_
+#include <map>
+#include <memory>
#include <string>
#include "base/component_export.h"
@@ -60,7 +62,9 @@ struct COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) ClipboardFormatType {
static const ClipboardFormatType& GetTextHtmlType();
static const ClipboardFormatType& GetCFHDropType();
static const ClipboardFormatType& GetFileDescriptorType();
+ static const ClipboardFormatType& GetFileDescriptorWType();
static const ClipboardFormatType& GetFileContentZeroType();
+ static const ClipboardFormatType& GetFileContentAtIndexType(LONG index);
static const ClipboardFormatType& GetIDListType();
#endif
@@ -99,6 +103,18 @@ struct COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) ClipboardFormatType {
#if defined(OS_WIN)
explicit ClipboardFormatType(UINT native_format);
ClipboardFormatType(UINT native_format, LONG index);
+ ClipboardFormatType(UINT native_format, LONG index, DWORD tymed);
+
+ // When there are multiple files in the data store and they are described
+ // using a file group descriptor, the file contents are retrieved by
+ // requesting the CFSTR_FILECONTENTS clipboard format type and also providing
+ // an index into the data (the first file corresponds to index 0). This
+ // function returns a map of index to CFSTR_FILECONTENTS clipboard format
+ // type.
+ static std::map<LONG, ClipboardFormatType>& GetFileContentTypeMap();
+
+ // FORMATETC:
+ // https://docs.microsoft.com/en-us/windows/desktop/com/the-formatetc-structure
FORMATETC data_;
#elif defined(USE_AURA) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
explicit ClipboardFormatType(const std::string& native_format);
diff --git a/chromium/ui/base/clipboard/clipboard_format_type_android.cc b/chromium/ui/base/clipboard/clipboard_format_type_android.cc
index 74a6e3f4b52..e241d16009b 100644
--- a/chromium/ui/base/clipboard/clipboard_format_type_android.cc
+++ b/chromium/ui/base/clipboard/clipboard_format_type_android.cc
@@ -22,12 +22,12 @@ const char kBookmarkFormat[] = "bookmark";
} // namespace
// ClipboardFormatType implementation.
-ClipboardFormatType::ClipboardFormatType() {}
+ClipboardFormatType::ClipboardFormatType() = default;
ClipboardFormatType::ClipboardFormatType(const std::string& native_format)
: data_(native_format) {}
-ClipboardFormatType::~ClipboardFormatType() {}
+ClipboardFormatType::~ClipboardFormatType() = default;
std::string ClipboardFormatType::Serialize() const {
return data_;
diff --git a/chromium/ui/base/clipboard/clipboard_format_type_win.cc b/chromium/ui/base/clipboard/clipboard_format_type_win.cc
index 86e7d916c8d..bb242e0af5f 100644
--- a/chromium/ui/base/clipboard/clipboard_format_type_win.cc
+++ b/chromium/ui/base/clipboard/clipboard_format_type_win.cc
@@ -8,34 +8,30 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
namespace ui {
// ClipboardFormatType implementation.
-ClipboardFormatType::ClipboardFormatType() : data_() {}
+ClipboardFormatType::ClipboardFormatType() = default;
-ClipboardFormatType::ClipboardFormatType(UINT native_format) : data_() {
- // There's no good way to actually initialize this in the constructor in
- // C++03.
- data_.cfFormat = static_cast<CLIPFORMAT>(native_format);
- data_.dwAspect = DVASPECT_CONTENT;
- data_.lindex = -1;
- data_.tymed = TYMED_HGLOBAL;
-}
+ClipboardFormatType::ClipboardFormatType(UINT native_format)
+ : ClipboardFormatType(native_format, -1) {}
ClipboardFormatType::ClipboardFormatType(UINT native_format, LONG index)
- : data_() {
- // There's no good way to actually initialize this in the constructor in
- // C++03.
- data_.cfFormat = static_cast<CLIPFORMAT>(native_format);
- data_.dwAspect = DVASPECT_CONTENT;
- data_.lindex = index;
- data_.tymed = TYMED_HGLOBAL;
-}
+ : ClipboardFormatType(native_format, index, TYMED_HGLOBAL) {}
-ClipboardFormatType::~ClipboardFormatType() {}
+// In C++ 20, we can use designated initializers.
+ClipboardFormatType::ClipboardFormatType(UINT native_format,
+ LONG index,
+ DWORD tymed)
+ : data_{/* .cfFormat */ static_cast<CLIPFORMAT>(native_format),
+ /* .ptd */ nullptr, /* .dwAspect */ DVASPECT_CONTENT,
+ /* .lindex */ index, /* .tymed*/ tymed} {}
+
+ClipboardFormatType::~ClipboardFormatType() = default;
std::string ClipboardFormatType::Serialize() const {
return base::NumberToString(data_.cfFormat);
@@ -167,21 +163,61 @@ const ClipboardFormatType& ClipboardFormatType::GetCFHDropType() {
return type.Get();
}
+// Nothing prevents the drag source app from using the CFSTR_FILEDESCRIPTORA
+// ANSI format (e.g., it could be that it doesn't support UNICODE). So need to
+// register both the ANSI and UNICODE file group descriptors.
// static
const ClipboardFormatType& ClipboardFormatType::GetFileDescriptorType() {
CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
- type, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR));
+ type, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA));
+ return type.Get();
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetFileDescriptorWType() {
+ CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
+ type, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW));
return type.Get();
}
// static
const ClipboardFormatType& ClipboardFormatType::GetFileContentZeroType() {
+ // Note this uses a storage media type of TYMED_HGLOBAL, which is not commonly
+ // used with CFSTR_FILECONTENTS (but used in Chromium--see
+ // OSExchangeDataProviderWin::SetFileContents). Use GetFileContentAtIndexType
+ // if TYMED_ISTREAM and TYMED_ISTORAGE are needed.
+ // TODO(https://crbug.com/950756): Should TYMED_ISTREAM / TYMED_ISTORAGE be
+ // used instead of TYMED_HGLOBAL in
+ // OSExchangeDataProviderWin::SetFileContents.
CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
type, ::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0);
return type.Get();
}
// static
+std::map<LONG, ClipboardFormatType>&
+ClipboardFormatType::GetFileContentTypeMap() {
+ static base::NoDestructor<std::map<LONG, ClipboardFormatType>>
+ index_to_type_map;
+ return *index_to_type_map;
+}
+
+// static
+const ClipboardFormatType& ClipboardFormatType::GetFileContentAtIndexType(
+ LONG index) {
+ auto& index_to_type_map = GetFileContentTypeMap();
+
+ // Use base::WrapUnique instead of std::make_unique here since
+ // ClipboardFormatType constructor is private. See
+ // https://chromium.googlesource.com/chromium/src/+/HEAD/styleguide/c++/c++-dos-and-donts.md.
+ auto insert_or_assign_result = index_to_type_map.insert(
+ {index,
+ ClipboardFormatType(::RegisterClipboardFormat(CFSTR_FILECONTENTS), index,
+ TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE)});
+ return insert_or_assign_result.first->second;
+}
+
+// static
const ClipboardFormatType& ClipboardFormatType::GetIDListType() {
CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
type, ::RegisterClipboardFormat(CFSTR_SHELLIDLIST));
diff --git a/chromium/ui/base/clipboard/clipboard_monitor.cc b/chromium/ui/base/clipboard/clipboard_monitor.cc
index e9e8cbe7960..b8bd0944d8a 100644
--- a/chromium/ui/base/clipboard/clipboard_monitor.cc
+++ b/chromium/ui/base/clipboard/clipboard_monitor.cc
@@ -9,7 +9,7 @@
namespace ui {
-ClipboardMonitor::ClipboardMonitor() {}
+ClipboardMonitor::ClipboardMonitor() = default;
ClipboardMonitor::~ClipboardMonitor() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/chromium/ui/base/clipboard/clipboard_observer.h b/chromium/ui/base/clipboard/clipboard_observer.h
index 1aa813d63e6..99c1c5bdc01 100644
--- a/chromium/ui/base/clipboard/clipboard_observer.h
+++ b/chromium/ui/base/clipboard/clipboard_observer.h
@@ -17,7 +17,7 @@ class COMPONENT_EXPORT(BASE_CLIPBOARD) ClipboardObserver {
virtual void OnClipboardDataChanged() = 0;
protected:
- virtual ~ClipboardObserver() {}
+ virtual ~ClipboardObserver() = default;
};
} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_test_template.h b/chromium/ui/base/clipboard/clipboard_test_template.h
index f81607b4bd8..c0ee5e19765 100644
--- a/chromium/ui/base/clipboard/clipboard_test_template.h
+++ b/chromium/ui/base/clipboard/clipboard_test_template.h
@@ -59,7 +59,7 @@ namespace ui {
template <typename ClipboardTraits>
class ClipboardTest : public PlatformTest {
public:
- ClipboardTest() {}
+ ClipboardTest() = default;
~ClipboardTest() override = default;
// PlatformTest:
diff --git a/chromium/ui/base/clipboard/clipboard_util_win.cc b/chromium/ui/base/clipboard/clipboard_util_win.cc
index 077df5a6d48..a460c373f18 100644
--- a/chromium/ui/base/clipboard/clipboard_util_win.cc
+++ b/chromium/ui/base/clipboard/clipboard_util_win.cc
@@ -6,14 +6,21 @@
#include <shellapi.h>
#include <wininet.h> // For INTERNET_MAX_URL_LENGTH.
+#include <wrl/client.h>
+#include <algorithm>
+#include <limits>
+#include <utility>
-#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/threading/scoped_blocking_call.h"
#include "base/win/scoped_hglobal.h"
#include "base/win/shlwapi.h"
#include "net/base/filename_util.h"
@@ -85,6 +92,354 @@ void SplitUrlAndTitle(const base::string16& str,
}
}
+// Performs a case-insensitive search for a file path in a vector of existing
+// filepaths. Case-insensivity is needed for file systems such as Windows where
+// A.txt and a.txt are considered the same file name.
+bool ContainsFilePathCaseInsensitive(
+ const std::vector<base::FilePath>& existing_filenames,
+ const base::FilePath& candidate_path) {
+ return std::find_if(std::begin(existing_filenames),
+ std::end(existing_filenames),
+ [&candidate_path](const base::FilePath& elem) {
+ return base::FilePath::CompareEqualIgnoreCase(
+ elem.value(), candidate_path.value());
+ }) != std::end(existing_filenames);
+}
+
+// Returns a unique display name for a virtual file, as it is possible that the
+// filenames found in the file group descriptor are not unique (e.g. multiple
+// emails with the same subject line are dragged out of Outlook.exe).
+// |uniquifier| is incremented on encountering a non-unique file name.
+base::FilePath GetUniqueVirtualFilename(
+ const base::string16& candidate_name,
+ const std::vector<base::FilePath>& existing_filenames,
+ unsigned int* uniquifier) {
+ // Remove any possible filepath components/separators that drag source may
+ // have included in virtual file name.
+ base::FilePath unique_name = base::FilePath(candidate_name).BaseName();
+
+ // To mitigate against running up against MAX_PATH limitations (temp files
+ // failing to be created), truncate the display name.
+ const size_t kTruncatedDisplayNameLength = 128;
+ const base::string16 extension = unique_name.Extension();
+ unique_name = unique_name.RemoveExtension();
+ base::string16 truncated = unique_name.value();
+ if (truncated.length() > kTruncatedDisplayNameLength) {
+ truncated.erase(kTruncatedDisplayNameLength);
+ unique_name = base::FilePath(truncated);
+ }
+ unique_name = unique_name.AddExtension(extension);
+
+ // Replace any file name illegal characters.
+ unique_name = net::GenerateFileName(GURL(), std::string(), std::string(),
+ base::UTF16ToUTF8(unique_name.value()),
+ std::string(), std::string());
+
+ // Make the file name unique. This is more involved than just marching through
+ // |existing_filenames|, finding the first match, uniquifying, then breaking
+ // out of the loop. For example, consider an array of candidate display names
+ // {"A (1) (2)", "A", "A (1) ", "A"}. In the first three iterations of the
+ // outer loop in GetVirtualFilenames, the candidate names are already unique
+ // and so simply pushed to the vector of |filenames|. On the fourth iteration
+ // of the outer loop and second iteration of the inner loop (that in
+ // GetUniqueVirtualFilename), the duplicate name is encountered and the fourth
+ // item is tentatively uniquified to "A (1)". If this inner loop were exited
+ // now, the final |filenames| would be {"A (1) (2)", "A", "A (1) ", "A (1)"}
+ // and would contain duplicate entries. So try not breaking out of the
+ // inner loop. In that case on the third iteration of the inner loop, the
+ // tentative unique name encounters another duplicate, so now gets uniquefied
+ // to "A (1) (2)" and if we then don't restart the loop, we would end up with
+ // the final |filenames| being {"A (1) (2)", "A", "A (1) ", "A (1) (2)"} and
+ // we still have duplicate entries. Instead we need to test against the
+ // entire collection of existing names on each uniquification attempt.
+
+ // Same value used in base::GetUniquePathNumber.
+ static const int kMaxUniqueFiles = 100;
+ int count = 1;
+ for (; count <= kMaxUniqueFiles; ++count) {
+ if (!ContainsFilePathCaseInsensitive(existing_filenames, unique_name))
+ break;
+
+ unique_name = unique_name.InsertBeforeExtensionASCII(
+ base::StringPrintf(" (%d)", (*uniquifier)++));
+ }
+ if (count > kMaxUniqueFiles)
+ unique_name = base::FilePath();
+
+ return unique_name;
+}
+
+// Creates a uniquely-named temporary file based on the suggested filename, or
+// an empty path on error. The file will be empty and all handles closed after
+// this function returns.
+base::FilePath CreateTemporaryFileWithSuggestedName(
+ const base::FilePath& suggested_name) {
+ base::FilePath temp_path1;
+ if (!base::CreateTemporaryFile(&temp_path1))
+ return base::FilePath();
+
+ base::FilePath temp_path2 = temp_path1.DirName().Append(suggested_name);
+
+ // Make filename unique.
+ temp_path2 = base::GetUniquePath(temp_path2);
+
+ base::File::Error replace_file_error = base::File::FILE_OK;
+ if (!ReplaceFile(temp_path1, temp_path2, &replace_file_error))
+ return base::FilePath();
+
+ return temp_path2;
+}
+
+// This method performs file I/O and thus is executed on a worker thread. An
+// empty FilePath for the temp file is returned on failure.
+base::FilePath WriteFileContentsToTempFile(const base::FilePath& suggested_name,
+ HGLOBAL hdata) {
+ base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+ base::BlockingType::MAY_BLOCK);
+
+ base::FilePath temp_path = base::FilePath();
+
+ if (!hdata)
+ return temp_path;
+
+ temp_path = CreateTemporaryFileWithSuggestedName(suggested_name);
+
+ if (!temp_path.empty()) {
+ base::win::ScopedHGlobal<char*> data(hdata);
+ // Don't write to the temp file for empty content--leave it at 0-bytes.
+ if (!(data.Size() == 1 && data.get()[0] == '\0')) {
+ if (base::WriteFile(temp_path, data.get(), data.Size()) < 0) {
+ base::DeleteFile(temp_path, false);
+ return base::FilePath();
+ }
+ }
+ }
+
+ ::GlobalFree(hdata);
+
+ return temp_path;
+}
+
+std::vector<
+ std::pair</*temp path*/ base::FilePath, /*display name*/ base::FilePath>>
+WriteAllFileContentsToTempFiles(
+ const std::vector<base::FilePath>& display_names,
+ const std::vector<HGLOBAL>& memory_backed_contents) {
+ DCHECK_EQ(display_names.size(), memory_backed_contents.size());
+
+ std::vector<std::pair<base::FilePath, base::FilePath>> filepaths_and_names;
+ for (size_t i = 0; i < display_names.size(); i++) {
+ base::FilePath temp_path = WriteFileContentsToTempFile(
+ display_names[i], memory_backed_contents[i]);
+
+ filepaths_and_names.push_back({temp_path, display_names[i]});
+ }
+
+ return filepaths_and_names;
+}
+
+// Caller's responsibility to call GlobalFree on returned HGLOBAL when done with
+// the data. This method must be performed on main thread as it is using the
+// IDataObject marshalled there.
+HGLOBAL CopyFileContentsToHGlobal(IDataObject* data_object, LONG index) {
+ DCHECK(data_object);
+ HGLOBAL hdata = nullptr;
+
+ if (!HasData(data_object,
+ ClipboardFormatType::GetFileContentAtIndexType(index)))
+ return hdata;
+
+ STGMEDIUM content;
+ if (!GetData(data_object,
+ ClipboardFormatType::GetFileContentAtIndexType(index), &content))
+ return hdata;
+
+ HRESULT hr = S_OK;
+
+ if (content.tymed == TYMED_ISTORAGE) {
+ // For example, messages dragged out of Outlook.exe.
+
+ Microsoft::WRL::ComPtr<ILockBytes> lock_bytes;
+ hr = ::CreateILockBytesOnHGlobal(nullptr, /* fDeleteOnRelease*/ FALSE,
+ &lock_bytes);
+
+ Microsoft::WRL::ComPtr<IStorage> storage;
+ if (SUCCEEDED(hr)) {
+ hr = ::StgCreateDocfileOnILockBytes(
+ lock_bytes.Get(), STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0, &storage);
+ }
+
+ if (SUCCEEDED(hr))
+ hr = content.pstg->CopyTo(0, nullptr, nullptr, storage.Get());
+
+ if (SUCCEEDED(hr))
+ hr = storage->Commit(STGC_OVERWRITE);
+
+ if (SUCCEEDED(hr))
+ hr = ::GetHGlobalFromILockBytes(lock_bytes.Get(), &hdata);
+
+ if (FAILED(hr))
+ hdata = nullptr;
+ } else if (content.tymed == TYMED_ISTREAM) {
+ // For example, attachments dragged out of messages in Outlook.exe.
+
+ Microsoft::WRL::ComPtr<IStream> stream;
+ hr =
+ ::CreateStreamOnHGlobal(nullptr, /* fDeleteOnRelease */ FALSE, &stream);
+ if (SUCCEEDED(hr)) {
+ // A properly implemented IDataObject::GetData moves the stream pointer to
+ // the end. Need to seek to the beginning before copying the data then
+ // seek back to the original position.
+ const LARGE_INTEGER zero_displacement = {};
+ ULARGE_INTEGER original_position = {};
+ // Obtain the original stream pointer position. If the stream doesn't
+ // support seek, will still attempt to copy the data unless the failure is
+ // due to access being denied (enterprise protected data e.g.).
+ HRESULT hr_seek = content.pstm->Seek(zero_displacement, STREAM_SEEK_CUR,
+ &original_position);
+ if (hr_seek != E_ACCESSDENIED) {
+ if (SUCCEEDED(hr_seek)) {
+ // Seek to the beginning.
+ hr_seek =
+ content.pstm->Seek(zero_displacement, STREAM_SEEK_SET, nullptr);
+ }
+
+ // Copy all data to the file stream.
+ ULARGE_INTEGER max_bytes;
+ max_bytes.QuadPart = std::numeric_limits<uint64_t>::max();
+ hr = content.pstm->CopyTo(stream.Get(), max_bytes, nullptr, nullptr);
+
+ if (SUCCEEDED(hr_seek)) {
+ // Restore the stream pointer to its original position.
+ LARGE_INTEGER original_offset;
+ original_offset.QuadPart = original_position.QuadPart;
+ content.pstm->Seek(original_offset, STREAM_SEEK_SET, nullptr);
+ }
+ } else {
+ // Access was denied.
+ hr = hr_seek;
+ }
+
+ if (SUCCEEDED(hr))
+ hr = ::GetHGlobalFromStream(stream.Get(), &hdata);
+
+ if (FAILED(hr))
+ hdata = nullptr;
+ }
+ } else if (content.tymed == TYMED_HGLOBAL) {
+ // For example, anchor (internet shortcut) dragged out of Spartan Edge.
+ // Copy the data as it will be written to a file on a worker thread and we
+ // need to call ReleaseStgMedium to free the memory allocated by the drag
+ // source.
+ base::win::ScopedHGlobal<char*> data_source(content.hGlobal);
+ hdata = ::GlobalAlloc(GHND, data_source.Size());
+ if (hdata) {
+ base::win::ScopedHGlobal<char*> data_destination(hdata);
+ memcpy(data_destination.get(), data_source.get(), data_source.Size());
+ }
+ }
+
+ // Safe to release the medium now since all the data has been copied.
+ ReleaseStgMedium(&content);
+
+ return hdata;
+}
+
+base::string16 ConvertString(const char* string) {
+ return base::UTF8ToWide(string);
+}
+
+base::string16 ConvertString(const wchar_t* string) {
+ return string;
+}
+
+template <typename FileGroupDescriptorType>
+struct FileGroupDescriptorData;
+
+template <>
+struct FileGroupDescriptorData<FILEGROUPDESCRIPTORW> {
+ static bool get(IDataObject* data_object, STGMEDIUM* medium) {
+ return GetData(data_object, ClipboardFormatType::GetFileDescriptorWType(),
+ medium);
+ }
+};
+
+template <>
+struct FileGroupDescriptorData<FILEGROUPDESCRIPTORA> {
+ static bool get(IDataObject* data_object, STGMEDIUM* medium) {
+ return GetData(data_object, ClipboardFormatType::GetFileDescriptorType(),
+ medium);
+ }
+};
+
+// Retrieves display names of virtual files, making sure they are unique.
+// Use template parameter of FILEGROUPDESCRIPTORW for retrieving unicode data
+// and FILEGROUPDESCRIPTORA for ascii.
+template <typename FileGroupDescriptorType>
+bool GetVirtualFilenames(IDataObject* data_object,
+ std::vector<base::FilePath>* filenames) {
+ STGMEDIUM medium;
+
+ if (!FileGroupDescriptorData<FileGroupDescriptorType>::get(data_object,
+ &medium))
+ return false;
+
+ {
+ base::win::ScopedHGlobal<FileGroupDescriptorType*> fgd(medium.hGlobal);
+ if (!fgd.get())
+ return false;
+
+ unsigned int num_files = fgd->cItems;
+ // We expect there to be at least one file in here.
+ DCHECK_GE(num_files, 1u);
+
+ // Value to be incremented to ensure a unique display name, as it is
+ // possible that the filenames found in the file group descriptor are not
+ // unique (e.g. multiple emails with the same subject line are dragged out
+ // of Outlook.exe).
+ unsigned int uniquifier = 1;
+
+ for (size_t i = 0; i < num_files; i++) {
+ base::FilePath display_name;
+ // Folder entries not currently supported--skip this item.
+ if ((fgd->fgd[i].dwFlags & FD_ATTRIBUTES) &&
+ (fgd->fgd[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ DLOG(WARNING) << "GetVirtualFilenames: display name '"
+ << ConvertString(fgd->fgd[i].cFileName)
+ << "' refers to a directory (not supported).";
+ continue;
+ }
+ display_name = GetUniqueVirtualFilename(
+ ConvertString(fgd->fgd[i].cFileName), *filenames, &uniquifier);
+
+ filenames->push_back(display_name);
+ }
+ }
+
+ ReleaseStgMedium(&medium);
+ return !filenames->empty();
+}
+
+template <typename FileGroupDescriptorType>
+bool GetFileNameFromFirstDescriptor(IDataObject* data_object,
+ base::string16* filename) {
+ STGMEDIUM medium;
+
+ if (!FileGroupDescriptorData<FileGroupDescriptorType>::get(data_object,
+ &medium))
+ return false;
+
+ {
+ base::win::ScopedHGlobal<FileGroupDescriptorType*> fgd(medium.hGlobal);
+ // We expect there to be at least one file in here.
+ DCHECK_GE(fgd->cItems, 1u);
+ filename->assign(ConvertString(fgd->fgd[0].cFileName));
+ }
+ ReleaseStgMedium(&medium);
+ return true;
+}
+
} // namespace
bool ClipboardUtil::HasUrl(IDataObject* data_object, bool convert_filenames) {
@@ -102,9 +457,21 @@ bool ClipboardUtil::HasFilenames(IDataObject* data_object) {
HasData(data_object, ClipboardFormatType::GetFilenameType());
}
+bool ClipboardUtil::HasVirtualFilenames(IDataObject* data_object) {
+ DCHECK(data_object);
+ // Favor real files on the file system over virtual files.
+ return !HasFilenames(data_object) &&
+ HasData(data_object,
+ ClipboardFormatType::GetFileContentAtIndexType(0)) &&
+ (HasData(data_object, ClipboardFormatType::GetFileDescriptorWType()) ||
+ HasData(data_object, ClipboardFormatType::GetFileDescriptorType()));
+}
+
bool ClipboardUtil::HasFileContents(IDataObject* data_object) {
DCHECK(data_object);
- return HasData(data_object, ClipboardFormatType::GetFileContentZeroType());
+ return HasData(data_object, ClipboardFormatType::GetFileContentZeroType()) &&
+ (HasData(data_object, ClipboardFormatType::GetFileDescriptorWType()) ||
+ HasData(data_object, ClipboardFormatType::GetFileDescriptorType()));
}
bool ClipboardUtil::HasHtml(IDataObject* data_object) {
@@ -216,6 +583,57 @@ bool ClipboardUtil::GetFilenames(IDataObject* data_object,
return false;
}
+bool ClipboardUtil::GetVirtualFilenames(
+ IDataObject* data_object,
+ std::vector<base::FilePath>* filenames) {
+ DCHECK(data_object && filenames);
+ if (!HasVirtualFilenames(data_object))
+ return false;
+
+ // Nothing prevents the drag source app from using the CFSTR_FILEDESCRIPTORA
+ // ANSI format (e.g., it could be that it doesn't support UNICODE). So need to
+ // check for both the ANSI and UNICODE file group descriptors.
+ if (ui::GetVirtualFilenames<FILEGROUPDESCRIPTORW>(data_object, filenames)) {
+ // file group descriptor using unicode.
+ return true;
+ }
+
+ if (ui::GetVirtualFilenames<FILEGROUPDESCRIPTORA>(data_object, filenames)) {
+ // file group descriptor using ascii.
+ return true;
+ }
+
+ return false;
+}
+
+bool ClipboardUtil::GetVirtualFilesAsTempFiles(
+ IDataObject* data_object,
+ base::OnceCallback<
+ void(const std::vector<std::pair</*temp path*/ base::FilePath,
+ /*display name*/ base::FilePath>>&)>
+ callback) {
+ // Retrieve the display names of the virtual files.
+ std::vector<base::FilePath> display_names;
+ if (!GetVirtualFilenames(data_object, &display_names))
+ return false;
+
+ // Write the file contents to global memory.
+ std::vector<HGLOBAL> memory_backed_contents;
+ for (size_t i = 0; i < display_names.size(); i++) {
+ HGLOBAL hdata = CopyFileContentsToHGlobal(data_object, i);
+ memory_backed_contents.push_back(hdata);
+ }
+
+ // Queue a task to actually write the temp files on a worker thread.
+ base::PostTaskWithTraitsAndReplyWithResult(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
+ base::BindOnce(&WriteAllFileContentsToTempFiles, display_names,
+ memory_backed_contents),
+ std::move(callback)); // callback on the UI thread
+
+ return true;
+}
+
bool ClipboardUtil::GetPlainText(IDataObject* data_object,
base::string16* plain_text) {
DCHECK(data_object && plain_text);
@@ -289,10 +707,10 @@ bool ClipboardUtil::GetHtml(IDataObject* data_object,
}
bool ClipboardUtil::GetFileContents(IDataObject* data_object,
- base::string16* filename, std::string* file_contents) {
+ base::string16* filename,
+ std::string* file_contents) {
DCHECK(data_object && filename && file_contents);
- if (!HasData(data_object, ClipboardFormatType::GetFileContentZeroType()) &&
- !HasData(data_object, ClipboardFormatType::GetFileDescriptorType()))
+ if (!HasFileContents(data_object))
return false;
STGMEDIUM content;
@@ -307,18 +725,22 @@ bool ClipboardUtil::GetFileContents(IDataObject* data_object,
ReleaseStgMedium(&content);
}
- STGMEDIUM description;
- if (GetData(data_object, ClipboardFormatType::GetFileDescriptorType(),
- &description)) {
- {
- base::win::ScopedHGlobal<FILEGROUPDESCRIPTOR*> fgd(description.hGlobal);
- // We expect there to be at least one file in here.
- DCHECK_GE(fgd->cItems, 1u);
- filename->assign(fgd->fgd[0].cFileName);
- }
- ReleaseStgMedium(&description);
+ // Nothing prevents the drag source app from using the CFSTR_FILEDESCRIPTORA
+ // ANSI format (e.g., it could be that it doesn't support UNICODE). So need to
+ // check for both the ANSI and UNICODE file group descriptors.
+ if (GetFileNameFromFirstDescriptor<FILEGROUPDESCRIPTORW>(data_object,
+ filename)) {
+ // file group descriptor using unicode.
+ return true;
}
- return true;
+
+ if (GetFileNameFromFirstDescriptor<FILEGROUPDESCRIPTORA>(data_object,
+ filename)) {
+ // file group descriptor using ASCII.
+ return true;
+ }
+
+ return false;
}
bool ClipboardUtil::GetWebCustomData(
diff --git a/chromium/ui/base/clipboard/clipboard_util_win.h b/chromium/ui/base/clipboard/clipboard_util_win.h
index b4d0ae9528f..bfcea85cec8 100644
--- a/chromium/ui/base/clipboard/clipboard_util_win.h
+++ b/chromium/ui/base/clipboard/clipboard_util_win.h
@@ -11,9 +11,11 @@
#include <stddef.h>
#include <string>
#include <unordered_map>
+#include <utility>
#include <vector>
#include "base/component_export.h"
+#include "base/files/file_path.h"
#include "base/strings/string16.h"
class GURL;
@@ -27,6 +29,7 @@ class COMPONENT_EXPORT(BASE_CLIPBOARD) ClipboardUtil {
// Returns true if it does.
static bool HasUrl(IDataObject* data_object, bool convert_filenames);
static bool HasFilenames(IDataObject* data_object);
+ static bool HasVirtualFilenames(IDataObject* data_object);
static bool HasPlainText(IDataObject* data_object);
static bool HasFileContents(IDataObject* data_object);
static bool HasHtml(IDataObject* data_object);
@@ -43,6 +46,32 @@ class COMPONENT_EXPORT(BASE_CLIPBOARD) ClipboardUtil {
// Only returns true if |*filenames| is not empty.
static bool GetFilenames(IDataObject* data_object,
std::vector<base::string16>* filenames);
+
+ // Fills a vector of display names of "virtual files" in the data store, but
+ // does not actually retrieve the file contents. Display names are assured to
+ // be unique. Method is called on drag enter of the Chromium drop target, when
+ // only the display names are needed. Method only returns true if |filenames|
+ // is not empty.
+ static bool GetVirtualFilenames(IDataObject* data_object,
+ std::vector<base::FilePath>* filenames);
+
+ // Retrieves "virtual file" contents via creation of intermediary temp files.
+ // Method is called on dropping on the Chromium drop target. Since creating
+ // the temp files involves file I/O, the method is asynchronous and the caller
+ // must provide a callback function that receives a vector of pairs of temp
+ // file paths and display names. Method immediately returns false if there are
+ // no virtual files in the data object, in which case the callback will never
+ // be invoked.
+ // TODO(https://crbug.com/951574): Implement virtual file extraction to
+ // dynamically stream data to the renderer when File's bytes are actually
+ // requested
+ static bool GetVirtualFilesAsTempFiles(
+ IDataObject* data_object,
+ base::OnceCallback<
+ void(const std::vector<std::pair</*temp path*/ base::FilePath,
+ /*display name*/ base::FilePath>>&)>
+ callback);
+
static bool GetPlainText(IDataObject* data_object,
base::string16* plain_text);
static bool GetHtml(IDataObject* data_object,
@@ -72,6 +101,6 @@ class COMPONENT_EXPORT(BASE_CLIPBOARD) ClipboardUtil {
size_t* fragment_start,
size_t* fragment_end);
};
-}
+} // namespace ui
#endif // UI_BASE_CLIPBOARD_CLIPBOARD_UTIL_WIN_H_
diff --git a/chromium/ui/base/cocoa/nib_loading.h b/chromium/ui/base/cocoa/nib_loading.h
deleted file mode 100644
index 263ac4883b9..00000000000
--- a/chromium/ui/base/cocoa/nib_loading.h
+++ /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.
-
-#ifndef UI_BASE_COCOA_NIB_LOADING_H_
-#define UI_BASE_COCOA_NIB_LOADING_H_
-
-#import <Cocoa/Cocoa.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_BASE_EXPORT NSView* GetViewFromNib(NSString* name);
-
-} // namespace ui
-
-#endif // UI_BASE_COCOA_NIB_LOADING_H_
diff --git a/chromium/ui/base/cocoa/nib_loading.mm b/chromium/ui/base/cocoa/nib_loading.mm
deleted file mode 100644
index bfa1c621cd3..00000000000
--- a/chromium/ui/base/cocoa/nib_loading.mm
+++ /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.
-
-#import "ui/base/cocoa/nib_loading.h"
-
-#include "base/mac/bundle_locations.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/mac/sdk_forward_declarations.h"
-
-namespace ui {
-
-NSView* GetViewFromNib(NSString* name) {
- base::scoped_nsobject<NSNib> nib(
- [[NSNib alloc] initWithNibNamed:name
- bundle:base::mac::FrameworkBundle()]);
- if (!nib)
- return nil;
-
- NSArray* objects;
- BOOL success = [nib instantiateWithOwner:nil topLevelObjects:&objects];
- if (!success)
- return nil;
-
- // For some strange reason, even nibs that appear to have but one top-level
- // object often have more (an NSApplication, etc.). Filter out what isn't
- // desired.
- for (NSView* view in objects) {
- if (![view isKindOfClass:[NSView class]])
- continue;
-
- return [[view retain] autorelease];
- }
-
- return nil;
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/cocoa/ns_view_ids.h b/chromium/ui/base/cocoa/ns_view_ids.h
deleted file mode 100644
index 749fdd14dc0..00000000000
--- a/chromium/ui/base/cocoa/ns_view_ids.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_COCOA_NS_VIEW_IDS_H_
-#define UI_BASE_COCOA_NS_VIEW_IDS_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "ui/base/ui_base_export.h"
-
-@class NSView;
-
-namespace ui {
-
-// A class used to manage NSViews across processes.
-// - NSViews that may be instantiated in another process are assigned an id in
-// the browser process.
-// - Instantiating a ScopedNSViewIdMapping in the process where the NSView is
-// created will make NSViewIds::GetNSView return the specified NSView.
-// - This mechanism is used by mojo methods to refer to NSViews across
-// interfaces (in particular, to specify parent NSViews).
-class UI_BASE_EXPORT NSViewIds {
- public:
- // Get a new id to use with a new NSView. This is to only be called in the
- // browser process.
- static uint64_t GetNewId();
-
- // Return an NSView given its id. This is to be called in an app shim process.
- static NSView* GetNSView(uint64_t ns_view_id);
-};
-
-// A scoped mapping from |ns_view_id| to |view|. While this object exists,
-// NSViewIds::GetNSView will return |view| when queried with |ns_view_id|. This
-// is to be instantiated in the app shim process.
-class UI_BASE_EXPORT ScopedNSViewIdMapping {
- public:
- ScopedNSViewIdMapping(uint64_t ns_view_id, NSView* view);
- ~ScopedNSViewIdMapping();
-
- private:
- const uint64_t ns_view_id_;
- DISALLOW_COPY_AND_ASSIGN(ScopedNSViewIdMapping);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_COCOA_NS_VIEW_IDS_H_
diff --git a/chromium/ui/base/cocoa/ns_view_ids.mm b/chromium/ui/base/cocoa/ns_view_ids.mm
deleted file mode 100644
index 3af9ba81e47..00000000000
--- a/chromium/ui/base/cocoa/ns_view_ids.mm
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/cocoa/ns_view_ids.h"
-
-#import <Cocoa/Cocoa.h>
-#include <map>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/no_destructor.h"
-
-namespace ui {
-
-std::map<uint64_t, NSView*>& GetNSViewIdMap() {
- static base::NoDestructor<std::map<uint64_t, NSView*>> instance;
- return *instance;
-}
-
-// static
-uint64_t NSViewIds::GetNewId() {
- static uint64_t next_id = 1;
- return next_id++;
-}
-
-// static
-NSView* NSViewIds::GetNSView(uint64_t ns_view_id) {
- auto& view_map = GetNSViewIdMap();
- auto found = view_map.find(ns_view_id);
- if (found == view_map.end())
- return nil;
- return found->second;
-}
-
-ScopedNSViewIdMapping::ScopedNSViewIdMapping(uint64_t ns_view_id, NSView* view)
- : ns_view_id_(ns_view_id) {
- auto result = GetNSViewIdMap().insert(std::make_pair(ns_view_id, view));
- DCHECK(result.second);
-}
-
-ScopedNSViewIdMapping::~ScopedNSViewIdMapping() {
- auto& view_map = GetNSViewIdMap();
- auto found = view_map.find(ns_view_id_);
- DCHECK(found != view_map.end());
- view_map.erase(found);
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/cocoa/remote_views_window.h b/chromium/ui/base/cocoa/remote_views_window.h
deleted file mode 100644
index 634d54a9390..00000000000
--- a/chromium/ui/base/cocoa/remote_views_window.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_COCOA_REMOTE_VIEWS_WINDOW_H_
-#define UI_BASE_COCOA_REMOTE_VIEWS_WINDOW_H_
-
-#include "ui/base/ui_base_export.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace ui {
-
-// Returns true if the specified NSWindow corresponds to an NSWindow that is
-// being viewed in a remote process.
-bool UI_BASE_EXPORT IsWindowUsingRemoteViews(gfx::NativeWindow window);
-
-// Create a transparent NSWindow that is in the same position as |window|,
-// but is at the ModalPanel window level, so that it will appear over all
-// other window.
-NSWindow* UI_BASE_EXPORT
-CreateTransparentRemoteViewsClone(gfx::NativeWindow window);
-
-} // namespace ui
-
-#endif // UI_BASE_COCOA_REMOTE_VIEWS_WINDOW_H_
diff --git a/chromium/ui/base/cocoa/remote_views_window.mm b/chromium/ui/base/cocoa/remote_views_window.mm
deleted file mode 100644
index c9531ef7241..00000000000
--- a/chromium/ui/base/cocoa/remote_views_window.mm
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/cocoa/remote_views_window.h"
-
-#import <Cocoa/Cocoa.h>
-
-// An NSWindow is using RemoteMacViews if it has no BridgedNativeWidgetImpl.
-// This is the most expedient method of determining if an NSWindow uses
-// RemoteMacViews.
-namespace views {
-class BridgedNativeWidgetImpl;
-} // namespace views
-
-@interface NSWindow (Private)
-- (views::BridgedNativeWidgetImpl*)bridgeImpl;
-@end
-
-namespace ui {
-
-bool IsWindowUsingRemoteViews(gfx::NativeWindow gfx_window) {
- NSWindow* ns_window = gfx_window.GetNativeNSWindow();
- if ([ns_window respondsToSelector:@selector(bridgeImpl)]) {
- if (![ns_window bridgeImpl])
- return true;
- }
- return false;
-}
-
-NSWindow* UI_BASE_EXPORT
-CreateTransparentRemoteViewsClone(gfx::NativeWindow remote_window) {
- DCHECK(IsWindowUsingRemoteViews(remote_window));
- NSWindow* window = [[NSWindow alloc]
- initWithContentRect:[remote_window.GetNativeNSWindow() frame]
- styleMask:NSWindowStyleMaskBorderless
- backing:NSBackingStoreBuffered
- defer:NO];
- [window setAlphaValue:0];
- [window makeKeyAndOrderFront:nil];
- [window setLevel:NSModalPanelWindowLevel];
- return window;
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/cocoa/views_hostable.h b/chromium/ui/base/cocoa/views_hostable.h
index 58aa58df6f2..5768ced0cf2 100644
--- a/chromium/ui/base/cocoa/views_hostable.h
+++ b/chromium/ui/base/cocoa/views_hostable.h
@@ -11,12 +11,19 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
+namespace remote_cocoa {
+namespace mojom {
+class BridgeFactory;
+} // namespace mojom
+} // namespace remote_cocoa
+
namespace ui {
class Layer;
// Interface that it used to stitch a content::WebContentsView into a
// views::View.
+// TODO(ccameron): Move this to components/remote_cocoa.
class ViewsHostableView {
public:
// Host interface through which the WebContentsView may indicate that its C++
@@ -26,10 +33,11 @@ class ViewsHostableView {
// Query the ui::Layer of the host.
virtual ui::Layer* GetUiLayer() const = 0;
- // Return the id for the process in which the host NSView exists. Used to
- // migrate the content::WebContentsView and content::RenderWidgetHostview
- // to that process.
- virtual uint64_t GetViewsFactoryHostId() const = 0;
+ // Return the mojo interface to the application in a remote process in which
+ // the host NSView exists. Used to migrate the content::WebContentsView and
+ // content::RenderWidgetHostView to that process.
+ virtual remote_cocoa::mojom::BridgeFactory* GetRemoteCocoaApplication()
+ const = 0;
// The id for the views::View's NSView. Used to add the
// content::WebContentsView's NSView as a child view.
diff --git a/chromium/ui/base/dragdrop/download_file_interface.h b/chromium/ui/base/dragdrop/download_file_interface.h
index db82ff2d2c6..294653571e7 100644
--- a/chromium/ui/base/dragdrop/download_file_interface.h
+++ b/chromium/ui/base/dragdrop/download_file_interface.h
@@ -32,7 +32,7 @@ class UI_BASE_EXPORT DownloadFileObserver
protected:
friend class base::RefCountedThreadSafe<DownloadFileObserver>;
- virtual ~DownloadFileObserver() {}
+ virtual ~DownloadFileObserver() = default;
};
// Defines the interface to control how a file is downloaded.
@@ -51,7 +51,7 @@ class UI_BASE_EXPORT DownloadFileProvider
protected:
friend class base::RefCountedThreadSafe<DownloadFileProvider>;
- virtual ~DownloadFileProvider() {}
+ virtual ~DownloadFileProvider() = default;
};
} // namespace ui
diff --git a/chromium/ui/base/dragdrop/drag_source_win.h b/chromium/ui/base/dragdrop/drag_source_win.h
index ccb79aa8cd0..ecb129c7155 100644
--- a/chromium/ui/base/dragdrop/drag_source_win.h
+++ b/chromium/ui/base/dragdrop/drag_source_win.h
@@ -32,7 +32,7 @@ class DragSourceWin
// are an error - it is only public because a WRL helper function creates the
// objects.
DragSourceWin();
- ~DragSourceWin() override {}
+ ~DragSourceWin() override = default;
// Stop the drag operation at the next chance we get. This doesn't
// synchronously stop the drag (since Windows is controlling that),
diff --git a/chromium/ui/base/dragdrop/drop_target_win.cc b/chromium/ui/base/dragdrop/drop_target_win.cc
index 5dddafa3591..9b943290947 100644
--- a/chromium/ui/base/dragdrop/drop_target_win.cc
+++ b/chromium/ui/base/dragdrop/drop_target_win.cc
@@ -14,7 +14,7 @@ IDropTargetHelper* DropTargetWin::cached_drop_target_helper_ = nullptr;
DropTargetWin::DropTargetWin() : hwnd_(nullptr), ref_count_(0) {}
-DropTargetWin::~DropTargetWin() {}
+DropTargetWin::~DropTargetWin() = default;
void DropTargetWin::Init(HWND hwnd) {
DCHECK(!hwnd_);
diff --git a/chromium/ui/base/dragdrop/file_info.cc b/chromium/ui/base/dragdrop/file_info.cc
index e0f63dc582a..dec0d9008ce 100644
--- a/chromium/ui/base/dragdrop/file_info.cc
+++ b/chromium/ui/base/dragdrop/file_info.cc
@@ -6,13 +6,13 @@
namespace ui {
-FileInfo::FileInfo() {}
+FileInfo::FileInfo() = default;
FileInfo::FileInfo(const base::FilePath& path,
const base::FilePath& display_name)
: path(path), display_name(display_name) {}
-FileInfo::~FileInfo() {}
+FileInfo::~FileInfo() = default;
bool FileInfo::operator==(const FileInfo& other) const {
return path == other.path && display_name == other.display_name;
diff --git a/chromium/ui/base/dragdrop/os_exchange_data.cc b/chromium/ui/base/dragdrop/os_exchange_data.cc
index 11cf7dbe66d..d6a4a737117 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data.cc
@@ -4,6 +4,10 @@
#include "ui/base/dragdrop/os_exchange_data.h"
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
#include "base/pickle.h"
#include "build/build_config.h"
#include "ui/base/clipboard/clipboard_format_type.h"
@@ -19,7 +23,7 @@ OSExchangeData::DownloadFileInfo::DownloadFileInfo(
downloader(downloader) {
}
-OSExchangeData::DownloadFileInfo::~DownloadFileInfo() {}
+OSExchangeData::DownloadFileInfo::~DownloadFileInfo() = default;
OSExchangeData::OSExchangeData()
: provider_(OSExchangeDataProviderFactory::CreateProvider()) {
@@ -136,6 +140,22 @@ bool OSExchangeData::GetFileContents(base::FilePath* filename,
return provider_->GetFileContents(filename, file_contents);
}
+bool OSExchangeData::HasVirtualFilenames() const {
+ return provider_->HasVirtualFilenames();
+}
+
+bool OSExchangeData::GetVirtualFilenames(
+ std::vector<FileInfo>* filenames) const {
+ return provider_->GetVirtualFilenames(filenames);
+}
+
+bool OSExchangeData::GetVirtualFilesAsTempFiles(
+ base::OnceCallback<
+ void(const std::vector<std::pair<base::FilePath, base::FilePath>>&)>
+ callback) const {
+ return provider_->GetVirtualFilesAsTempFiles(std::move(callback));
+}
+
void OSExchangeData::SetDownloadFileInfo(const DownloadFileInfo& download) {
provider_->SetDownloadFileInfo(download);
}
diff --git a/chromium/ui/base/dragdrop/os_exchange_data.h b/chromium/ui/base/dragdrop/os_exchange_data.h
index cd915154ea1..343689e41ad 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data.h
@@ -8,6 +8,8 @@
#include <memory>
#include <set>
#include <string>
+#include <utility>
+#include <vector>
#include "build/build_config.h"
@@ -121,6 +123,18 @@ class UI_BASE_EXPORT OSExchangeData {
virtual bool GetFileContents(base::FilePath* filename,
std::string* file_contents) const = 0;
virtual bool HasFileContents() const = 0;
+ virtual bool HasVirtualFilenames() const = 0;
+ virtual bool GetVirtualFilenames(
+ std::vector<FileInfo>* file_names) const = 0;
+ virtual bool GetVirtualFilesAsTempFiles(
+ base::OnceCallback<void(
+ const std::vector<std::pair</*temp path*/ base::FilePath,
+ /*display name*/ base::FilePath>>&)>
+ callback) const = 0;
+ virtual void SetVirtualFileContentsForTesting(
+ const std::vector<std::pair<base::FilePath, std::string>>&
+ filenames_and_contents,
+ DWORD tymed) = 0;
virtual void SetDownloadFileInfo(const DownloadFileInfo& download) = 0;
#endif
@@ -213,6 +227,44 @@ class UI_BASE_EXPORT OSExchangeData {
bool GetFileContents(base::FilePath* filename,
std::string* file_contents) const;
+ // Methods used to query and retrieve file data from a drag source
+ // IDataObject implementation packaging the data with the
+ // CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS clipboard formats instead of the
+ // more common CF_HDROP. These formats are intended to represent "virtual
+ // files," not files that live on the platform file system. For a drop target
+ // to read the file contents, it must be streamed from the drag source
+ // application.
+
+ // Method that returns true if there are virtual files packaged in the data
+ // store.
+ bool HasVirtualFilenames() const;
+
+ // Retrieves names of any "virtual files" in the data store packaged using the
+ // CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS clipboard formats instead of the
+ // more common CF_HDROP used for "real files." Real files are preferred over
+ // virtual files here to avoid duplication, as the data store may package
+ // the same file lists using different formats. GetVirtualFilenames just
+ // retrieves the display names but not the temp file paths. The temp files
+ // are only created upon drop via a call to the async method
+ // GetVirtualFilesAsTempFiles.
+ bool GetVirtualFilenames(std::vector<FileInfo>* file_names) const;
+
+ // Retrieves "virtual file" contents via creation of intermediary temp files.
+ // Method is called on dropping on the Chromium drop target. Since creating
+ // the temp files involves file I/O, the method is asynchronous and the caller
+ // must provide a callback function that receives a vector of pairs of temp
+ // file paths and display names. Method immediately returns false if there are
+ // no virtual files in the data object, in which case the callback will never
+ // be invoked.
+ // TODO(https://crbug.com/951574): Implement virtual file extraction to
+ // dynamically stream data to the renderer when File's bytes are actually
+ // requested
+ bool GetVirtualFilesAsTempFiles(
+ base::OnceCallback<void(const std::vector</*temp path*/ std::pair<
+ base::FilePath,
+ /*display name*/ base::FilePath>>&)> callback)
+ const;
+
// Adds a download file with full path (CF_HDROP).
void SetDownloadFileInfo(const DownloadFileInfo& download);
#endif
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 40dbe89567b..7815313e6cd 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aura.cc
@@ -17,7 +17,7 @@ OSExchangeDataProviderAura::OSExchangeDataProviderAura()
: formats_(0) {
}
-OSExchangeDataProviderAura::~OSExchangeDataProviderAura() {}
+OSExchangeDataProviderAura::~OSExchangeDataProviderAura() = default;
std::unique_ptr<OSExchangeData::Provider>
OSExchangeDataProviderAura::Clone() const {
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.cc
index 9c3a9ab2cbe..30a259cb1d3 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.cc
@@ -18,28 +18,9 @@
namespace ui {
-OSExchangeDataProviderFactory::Factory* factory_ = nullptr;
-
-// static
-void OSExchangeDataProviderFactory::SetFactory(Factory* factory) {
- DCHECK(!factory_ || !factory);
- factory_ = factory;
-}
-
-// static
-OSExchangeDataProviderFactory::Factory*
-OSExchangeDataProviderFactory::TakeFactory() {
- OSExchangeDataProviderFactory::Factory* to_return = factory_;
- factory_ = nullptr;
- return to_return;
-}
-
//static
std::unique_ptr<OSExchangeData::Provider>
OSExchangeDataProviderFactory::CreateProvider() {
- if (factory_)
- return factory_->BuildProvider();
-
#if defined(USE_X11)
return std::make_unique<OSExchangeDataProviderAuraX11>();
#elif defined(OS_LINUX)
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.h b/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.h
index 4029d089f62..626b7ea2f8c 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_factory.h
@@ -12,23 +12,10 @@
namespace ui {
-// Builds OSExchangeDataProviders. We need to be able to switch providers at
-// runtime based on the configuration flags. If no factory is set,
-// CreateProvider() will default to the current operating system's default.
+// Builds platform specific OSExchangeDataProviders.
class UI_BASE_EXPORT OSExchangeDataProviderFactory {
public:
- class Factory {
- public:
- virtual std::unique_ptr<OSExchangeData::Provider> BuildProvider() = 0;
- };
-
- // Sets the factory which builds the providers.
- static void SetFactory(Factory* factory);
-
- // Returns the current factory and sets the factory to null.
- static Factory* TakeFactory();
-
- // Creates a Provider based on the current configuration.
+ // Creates a Provider based on the current platform.
static std::unique_ptr<OSExchangeData::Provider> CreateProvider();
};
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 a9bd4912f3d..291b95010c7 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
@@ -4,6 +4,7 @@
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
+#include <coml2api.h>
#include <objbase.h>
#include <objidl.h>
#include <shlobj.h>
@@ -14,6 +15,8 @@
#include <algorithm>
#include <iterator>
+#include "base/callback.h"
+#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/i18n/file_util_icu.h"
#include "base/logging.h"
@@ -23,6 +26,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_hdc.h"
#include "base/win/scoped_hglobal.h"
+#include "base/win/shlwapi.h"
#include "net/base/filename_util.h"
#include "skia/ext/skia_utils_win.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -372,6 +376,124 @@ void OSExchangeDataProviderWin::SetFilenames(
ClipboardFormatType::GetCFHDropType().ToFormatEtc(), storage));
}
+void OSExchangeDataProviderWin::SetVirtualFileContentsForTesting(
+ const std::vector<std::pair<base::FilePath, std::string>>&
+ filenames_and_contents,
+ DWORD tymed) {
+ size_t num_files = filenames_and_contents.size();
+ if (!num_files)
+ return;
+
+ // Allocate storage for the file group descriptor as CFSTR_FILEDESCRIPTORW.
+ // The fgd[] member of FILEGROUPDESCRIPTORW is of size one, thus sizeof
+ // (FILEDESCRIPTORW) is already the correct allocation size if there is only
+ // one item. Otherwise need to add room for each FILEDESCRIPTORW struct.
+ const size_t total_bytes_fgd = sizeof(FILEGROUPDESCRIPTORW) +
+ (sizeof(FILEDESCRIPTORW) * (num_files - 1));
+
+ HANDLE hdata = ::GlobalAlloc(GPTR, total_bytes_fgd);
+ if (!hdata)
+ return;
+
+ base::win::ScopedHGlobal<FILEGROUPDESCRIPTORW*> locked_mem(hdata);
+
+ FILEGROUPDESCRIPTORW* descriptor = locked_mem.get();
+ descriptor->cItems = num_files;
+
+ STGMEDIUM* storage = new STGMEDIUM;
+ storage->tymed = TYMED_HGLOBAL;
+ storage->hGlobal = hdata;
+ storage->pUnkForRelease = NULL;
+
+ data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
+ ClipboardFormatType::GetFileDescriptorWType().ToFormatEtc(), storage));
+
+ for (size_t i = 0; i < num_files; i++) {
+ // Fill in each FILEDESCRIPTORW with file name.
+ descriptor->fgd[i].dwFlags |= FD_UNICODE;
+ base::string16 file_name = filenames_and_contents[i].first.value();
+ wcsncpy_s(descriptor->fgd[i].cFileName, MAX_PATH, file_name.c_str(),
+ std::min(file_name.size(), static_cast<size_t>(MAX_PATH - 1u)));
+
+ // Add the contents of each file as CFSTR_FILECONTENTS.
+ base::span<const uint8_t> data_buffer =
+ base::make_span(reinterpret_cast<const uint8_t*>(
+ filenames_and_contents[i].second.data()),
+ filenames_and_contents[i].second.length());
+ SetVirtualFileContentAtIndexForTesting(data_buffer, tymed, i);
+ }
+}
+
+void OSExchangeDataProviderWin::SetVirtualFileContentAtIndexForTesting(
+ base::span<const uint8_t> data_buffer,
+ DWORD tymed,
+ size_t index) {
+ std::unique_ptr<STGMEDIUM> storage_for_contents;
+
+ if (tymed == TYMED_ISTORAGE) {
+ storage_for_contents = std::make_unique<STGMEDIUM>();
+ storage_for_contents->pUnkForRelease = nullptr;
+
+ Microsoft::WRL::ComPtr<ILockBytes> lock_bytes;
+ HRESULT hr = ::CreateILockBytesOnHGlobal(
+ nullptr, /* fDeleteOnRelease*/ TRUE, &lock_bytes);
+
+ if (SUCCEEDED(hr)) {
+ hr = ::StgCreateDocfileOnILockBytes(
+ lock_bytes.Get(), STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0, &storage_for_contents->pstg);
+ }
+
+ Microsoft::WRL::ComPtr<IStream> destination_stream;
+ if (SUCCEEDED(hr)) {
+ hr = storage_for_contents->pstg->CreateStream(
+ L"Contents", STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0,
+ 0, &destination_stream);
+ }
+
+ Microsoft::WRL::ComPtr<IStream> source_stream;
+ if (SUCCEEDED(hr)) {
+ source_stream =
+ ::SHCreateMemStream(data_buffer.data(), data_buffer.size_bytes());
+ }
+
+ if (source_stream) {
+ // Copy the data to the storage stream.
+ ULARGE_INTEGER bytes_to_copy;
+ bytes_to_copy.QuadPart = data_buffer.size_bytes();
+ hr = source_stream->CopyTo(destination_stream.Get(), bytes_to_copy,
+ nullptr, nullptr);
+ }
+ if (SUCCEEDED(hr))
+ hr = storage_for_contents->pstg->Commit(STGC_DEFAULT);
+ if (SUCCEEDED(hr))
+ storage_for_contents->tymed = TYMED_ISTORAGE;
+
+ } else if (tymed == TYMED_ISTREAM) {
+ storage_for_contents = std::make_unique<STGMEDIUM>();
+ storage_for_contents->pUnkForRelease = nullptr;
+ storage_for_contents->pstm =
+ ::SHCreateMemStream(data_buffer.data(), data_buffer.size_bytes());
+ if (storage_for_contents->pstm) {
+ // A properly implemented IDataObject::GetData moves the stream pointer
+ // to end.
+ const LARGE_INTEGER zero_displacement = {};
+ HRESULT hr = storage_for_contents->pstm->Seek(zero_displacement,
+ STREAM_SEEK_END, nullptr);
+ if (SUCCEEDED(hr))
+ storage_for_contents->tymed = TYMED_ISTREAM;
+ }
+ } else if (tymed == TYMED_HGLOBAL) {
+ storage_for_contents.reset(
+ GetStorageForBytes(data_buffer.data(), data_buffer.size_bytes()));
+ }
+ ClipboardFormatType type =
+ ClipboardFormatType::GetFileContentAtIndexType(index);
+ // Pass ownership of |storage_for_contents| here.
+ data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
+ type.ToFormatEtc(), storage_for_contents.release()));
+}
+
void OSExchangeDataProviderWin::SetPickledData(
const ClipboardFormatType& format,
const base::Pickle& data) {
@@ -383,12 +505,12 @@ void OSExchangeDataProviderWin::SetPickledData(
void OSExchangeDataProviderWin::SetFileContents(
const base::FilePath& filename,
const std::string& file_contents) {
- // Add CFSTR_FILEDESCRIPTOR
+ // Add CFSTR_FILEDESCRIPTORW.
STGMEDIUM* storage = GetStorageForFileDescriptor(filename);
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
- ClipboardFormatType::GetFileDescriptorType().ToFormatEtc(), storage));
+ ClipboardFormatType::GetFileDescriptorWType().ToFormatEtc(), storage));
- // Add CFSTR_FILECONTENTS
+ // Add CFSTR_FILECONTENTS.
storage = GetStorageForBytes(file_contents.data(), file_contents.length());
data_->contents_.push_back(std::make_unique<DataObjectImpl::StoredDataInfo>(
ClipboardFormatType::GetFileContentZeroType().ToFormatEtc(), storage));
@@ -457,6 +579,39 @@ bool OSExchangeDataProviderWin::GetFilenames(
return success;
}
+bool OSExchangeDataProviderWin::HasVirtualFilenames() const {
+ return ClipboardUtil::HasVirtualFilenames(source_object_.Get());
+}
+
+bool OSExchangeDataProviderWin::GetVirtualFilenames(
+ std::vector<FileInfo>* filenames) const {
+ // ui_base_clipboard can't use FileInfo struct which is part of ui_base, so
+ // use FilePath instead.
+ // TODO(https://crbug.com/950360): ui_base_clipboard can't use FileInfo struct
+ // which is part of ui_base (layering issue).
+ std::vector<base::FilePath> display_names;
+ bool success =
+ ClipboardUtil::GetVirtualFilenames(source_object_.Get(), &display_names);
+
+ if (success) {
+ // On dragenter scenarios, need a placeholder file path for drag metadata
+ // checks without actually creating the temp file.
+ base::FilePath temp_path(FILE_PATH_LITERAL("temp.tmp"));
+
+ for (const auto& display_name : display_names)
+ filenames->push_back(FileInfo(temp_path, display_name));
+ }
+ return success;
+}
+
+bool OSExchangeDataProviderWin::GetVirtualFilesAsTempFiles(
+ base::OnceCallback<
+ void(const std::vector<std::pair<base::FilePath, base::FilePath>>&)>
+ callback) const {
+ return ClipboardUtil::GetVirtualFilesAsTempFiles(source_object_.Get(),
+ std::move(callback));
+}
+
bool OSExchangeDataProviderWin::GetPickledData(
const ClipboardFormatType& format,
base::Pickle* data) const {
@@ -1119,10 +1274,10 @@ static STGMEDIUM* GetStorageForFileDescriptor(
const base::FilePath& path) {
base::string16 file_name = path.value();
DCHECK(!file_name.empty());
- HANDLE hdata = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR));
- base::win::ScopedHGlobal<FILEGROUPDESCRIPTOR*> locked_mem(hdata);
+ HANDLE hdata = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTORW));
+ base::win::ScopedHGlobal<FILEGROUPDESCRIPTORW*> locked_mem(hdata);
- FILEGROUPDESCRIPTOR* descriptor = locked_mem.get();
+ FILEGROUPDESCRIPTORW* descriptor = locked_mem.get();
descriptor->cItems = 1;
descriptor->fgd[0].dwFlags = FD_LINKUI;
wcsncpy_s(descriptor->fgd[0].cFileName, MAX_PATH, file_name.c_str(),
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 96fa77ec763..a914f043ebe 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.h
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.h
@@ -9,6 +9,7 @@
#include <shlobj.h>
#include <stddef.h>
#include <wrl/client.h>
+#include <utility>
#include <memory>
#include <string>
@@ -154,6 +155,13 @@ class UI_BASE_EXPORT OSExchangeDataProviderWin
void SetURL(const GURL& url, const base::string16& title) override;
void SetFilename(const base::FilePath& path) override;
void SetFilenames(const std::vector<FileInfo>& filenames) override;
+ // Test only method for adding virtual file content to the data store. The
+ // first value in the pair is the file display name, the second is a string
+ // providing the file content.
+ void SetVirtualFileContentsForTesting(
+ const std::vector<std::pair<base::FilePath, std::string>>&
+ filenames_and_contents,
+ DWORD tymed) override;
void SetPickledData(const ClipboardFormatType& format,
const base::Pickle& data) override;
void SetFileContents(const base::FilePath& filename,
@@ -166,6 +174,12 @@ class UI_BASE_EXPORT OSExchangeDataProviderWin
base::string16* title) const override;
bool GetFilename(base::FilePath* path) const override;
bool GetFilenames(std::vector<FileInfo>* filenames) const override;
+ bool HasVirtualFilenames() const override;
+ bool GetVirtualFilenames(std::vector<FileInfo>* filenames) const override;
+ bool GetVirtualFilesAsTempFiles(
+ base::OnceCallback<
+ void(const std::vector<std::pair<base::FilePath, base::FilePath>>&)>
+ callback) const override;
bool GetPickledData(const ClipboardFormatType& format,
base::Pickle* data) const override;
bool GetFileContents(base::FilePath* filename,
@@ -185,6 +199,10 @@ class UI_BASE_EXPORT OSExchangeDataProviderWin
gfx::Vector2d GetDragImageOffset() const override;
private:
+ void SetVirtualFileContentAtIndexForTesting(base::span<const uint8_t> data,
+ DWORD tymed,
+ size_t index);
+
scoped_refptr<DataObjectImpl> data_;
Microsoft::WRL::ComPtr<IDataObject> source_object_;
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 161c2519a9b..bf74612e2df 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_win_unittest.cc
@@ -6,10 +6,15 @@
#include <memory>
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
#include "base/win/scoped_hglobal.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/dragdrop/file_info.h"
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
@@ -17,8 +22,41 @@
namespace ui {
+namespace {
+const std::vector<DWORD> kStorageMediaTypesForVirtualFiles = {
+ TYMED_ISTORAGE,
+ TYMED_ISTREAM,
+ TYMED_HGLOBAL,
+};
+
+} // namespace
+
+class OSExchangeDataWinTest : public ::testing::Test {
+ public:
+ OSExchangeDataWinTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
+
+ void OnGotVirtualFilesAsTempFiles(
+ const std::vector<std::pair<base::FilePath, base::FilePath>>&
+ filepaths_and_names) {
+ // Clear any previous results and cache a vector of FileInfo objects for
+ // verification.
+ retrieved_virtual_files_.clear();
+
+ for (const auto& filepath_and_name : filepaths_and_names) {
+ retrieved_virtual_files_.push_back(
+ FileInfo(filepath_and_name.first, filepath_and_name.second));
+ }
+ }
+
+ protected:
+ std::vector<FileInfo> retrieved_virtual_files_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+};
+
// Test getting using the IDataObject COM API
-TEST(OSExchangeDataWinTest, StringDataAccessViaCOM) {
+TEST_F(OSExchangeDataWinTest, StringDataAccessViaCOM) {
OSExchangeData data;
std::wstring input = L"O hai googlz.";
data.SetString(input);
@@ -38,7 +76,7 @@ TEST(OSExchangeDataWinTest, StringDataAccessViaCOM) {
}
// Test setting using the IDataObject COM API
-TEST(OSExchangeDataWinTest, StringDataWritingViaCOM) {
+TEST_F(OSExchangeDataWinTest, StringDataWritingViaCOM) {
OSExchangeData data;
std::wstring input = L"http://www.google.com/";
@@ -72,7 +110,7 @@ TEST(OSExchangeDataWinTest, StringDataWritingViaCOM) {
}
// Verifies SetData invoked twice with the same data clobbers existing data.
-TEST(OSExchangeDataWinTest, RemoveData) {
+TEST_F(OSExchangeDataWinTest, RemoveData) {
OSExchangeData data;
std::wstring input = L"http://www.google.com/";
std::wstring input2 = L"http://www.google2.com/";
@@ -118,7 +156,7 @@ TEST(OSExchangeDataWinTest, RemoveData) {
EXPECT_EQ(GURL(input2).spec(), url_from_data.spec());
}
-TEST(OSExchangeDataWinTest, URLDataAccessViaCOM) {
+TEST_F(OSExchangeDataWinTest, URLDataAccessViaCOM) {
OSExchangeData data;
GURL url("http://www.google.com/");
data.SetURL(url, L"");
@@ -138,7 +176,7 @@ TEST(OSExchangeDataWinTest, URLDataAccessViaCOM) {
ReleaseStgMedium(&medium);
}
-TEST(OSExchangeDataWinTest, MultipleFormatsViaCOM) {
+TEST_F(OSExchangeDataWinTest, MultipleFormatsViaCOM) {
OSExchangeData data;
std::string url_spec = "http://www.google.com/";
GURL url(url_spec);
@@ -173,7 +211,7 @@ TEST(OSExchangeDataWinTest, MultipleFormatsViaCOM) {
ReleaseStgMedium(&medium);
}
-TEST(OSExchangeDataWinTest, EnumerationViaCOM) {
+TEST_F(OSExchangeDataWinTest, EnumerationViaCOM) {
OSExchangeData data;
data.SetURL(GURL("http://www.google.com/"), L"");
data.SetString(L"O hai googlz.");
@@ -262,7 +300,7 @@ TEST(OSExchangeDataWinTest, EnumerationViaCOM) {
}
}
-TEST(OSExchangeDataWinTest, TestURLExchangeFormatsViaCOM) {
+TEST_F(OSExchangeDataWinTest, TestURLExchangeFormatsViaCOM) {
OSExchangeData data;
std::string url_spec = "http://www.google.com/";
GURL url(url_spec);
@@ -291,7 +329,7 @@ TEST(OSExchangeDataWinTest, TestURLExchangeFormatsViaCOM) {
}
}
-TEST(OSExchangeDataWinTest, FileContents) {
+TEST_F(OSExchangeDataWinTest, FileContents) {
OSExchangeData data;
std::string file_contents("data\0with\0nulls", 15);
data.SetFileContents(base::FilePath(L"filename.txt"), file_contents);
@@ -304,7 +342,482 @@ TEST(OSExchangeDataWinTest, FileContents) {
EXPECT_EQ(file_contents, read_contents);
}
-TEST(OSExchangeDataWinTest, CFHtml) {
+TEST_F(OSExchangeDataWinTest, VirtualFiles) {
+ const base::FilePath path_placeholder(FILE_PATH_LITERAL("temp.tmp"));
+
+ const std::vector<std::pair<base::FilePath, std::string>>
+ kTestFilenames_and_Contents = {
+ {base::FilePath(FILE_PATH_LITERAL("filename.txt")),
+ std::string("just some data")},
+ {base::FilePath(FILE_PATH_LITERAL("another filename.txt")),
+ std::string("just some data\0with\0nulls", 25)},
+ {base::FilePath(FILE_PATH_LITERAL("and another filename.txt")),
+ std::string("just some more data")},
+ };
+
+ for (const auto& tymed : kStorageMediaTypesForVirtualFiles) {
+ OSExchangeData data;
+ data.provider().SetVirtualFileContentsForTesting(
+ kTestFilenames_and_Contents, tymed);
+
+ OSExchangeData copy(data.provider().Clone());
+ std::vector<FileInfo> file_infos;
+ EXPECT_TRUE(copy.GetVirtualFilenames(&file_infos));
+ EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size());
+ for (size_t i = 0; i < file_infos.size(); i++) {
+ EXPECT_EQ(kTestFilenames_and_Contents[i].first,
+ file_infos[i].display_name);
+ EXPECT_EQ(path_placeholder, file_infos[i].path);
+ }
+
+ std::string read_contents;
+ base::FilePath temp_dir;
+ EXPECT_TRUE(base::GetTempDir(&temp_dir));
+
+ // Callback for GetVirtualFilesAsTempFiles is executed when all virtual
+ // files are backed by temp files.
+ auto callback =
+ base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles,
+ base::Unretained(this));
+
+ EXPECT_TRUE(copy.GetVirtualFilesAsTempFiles(std::move(callback)));
+
+ // RunUntilIdle assures all async tasks are run.
+ scoped_task_environment_.RunUntilIdle();
+
+ EXPECT_EQ(kTestFilenames_and_Contents.size(),
+ retrieved_virtual_files_.size());
+ for (size_t i = 0; i < retrieved_virtual_files_.size(); i++) {
+ EXPECT_EQ(kTestFilenames_and_Contents[i].first,
+ retrieved_virtual_files_[i].display_name);
+ // Check if the temp files that back the virtual files are actually
+ // created in the temp directory. Need to compare long file paths here
+ // because GetTempDir can return a short ("8.3") path if the test is run
+ // under a username that is too long.
+ EXPECT_EQ(
+ base::MakeLongFilePath(temp_dir),
+ base::MakeLongFilePath(retrieved_virtual_files_[i].path.DirName()));
+ EXPECT_EQ(kTestFilenames_and_Contents[i].first.Extension(),
+ retrieved_virtual_files_[i].path.Extension());
+ EXPECT_TRUE(base::ReadFileToString(retrieved_virtual_files_[i].path,
+ &read_contents));
+ if (tymed != TYMED_ISTORAGE) {
+ EXPECT_EQ(kTestFilenames_and_Contents[i].second, read_contents);
+ } else {
+ // IStorage uses compound files, so temp files won't be flat text files.
+ // Just make sure the original contents appears in the compound files.
+ EXPECT_TRUE(read_contents.find(kTestFilenames_and_Contents[i].second) !=
+ std::string::npos);
+ }
+ }
+ }
+}
+
+TEST_F(OSExchangeDataWinTest, VirtualFilesRealFilesPreferred) {
+ // Verify that no virtual files retrieved if there is real file data.
+ const std::vector<FileInfo> kTestFilenames = {
+ {base::FilePath(FILE_PATH_LITERAL("C:\\tmp\\test_file1")),
+ base::FilePath()},
+ {base::FilePath(FILE_PATH_LITERAL("C:\\tmp\\test_file2")),
+ base::FilePath()},
+ };
+
+ const std::vector<std::pair<base::FilePath, std::string>>
+ kTestFilenames_and_Contents = {
+ {base::FilePath(FILE_PATH_LITERAL("filename.txt")),
+ std::string("just some data")},
+ {base::FilePath(FILE_PATH_LITERAL("another filename.txt")),
+ std::string("just some data\0with\0nulls", 25)},
+ {base::FilePath(FILE_PATH_LITERAL("and another filename.txt")),
+ std::string("just some more data")},
+ };
+
+ for (const auto& tymed : kStorageMediaTypesForVirtualFiles) {
+ OSExchangeData data;
+ data.SetFilenames(kTestFilenames);
+ data.provider().SetVirtualFileContentsForTesting(
+ kTestFilenames_and_Contents, tymed);
+
+ OSExchangeData copy(data.provider().Clone());
+
+ std::vector<FileInfo> real_filenames;
+ EXPECT_TRUE(copy.GetFilenames(&real_filenames));
+ EXPECT_EQ(kTestFilenames.size(), real_filenames.size());
+ EXPECT_EQ(kTestFilenames, real_filenames);
+
+ std::vector<FileInfo> file_infos;
+ EXPECT_FALSE(copy.GetVirtualFilenames(&file_infos));
+ EXPECT_EQ(static_cast<size_t>(0), file_infos.size());
+
+ // Callback for GetVirtualFilesAsTempFiles is executed when all virtual
+ // files are backed by temp files.
+ auto callback =
+ base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles,
+ base::Unretained(this));
+
+ EXPECT_FALSE(copy.GetVirtualFilesAsTempFiles(std::move(callback)));
+
+ // RunUntilIdle assures all async tasks are run.
+ scoped_task_environment_.RunUntilIdle();
+
+ EXPECT_EQ(static_cast<size_t>(0), retrieved_virtual_files_.size());
+ }
+}
+
+TEST_F(OSExchangeDataWinTest, VirtualFilesDuplicateNames) {
+ const std::vector<std::pair<base::FilePath, std::string>>
+ kTestFilenames_and_Contents = {
+ {base::FilePath(FILE_PATH_LITERAL("A (1) (2).txt")),
+ std::string("just some data")},
+ {base::FilePath(FILE_PATH_LITERAL("A.txt")),
+ std::string("just some more data")},
+ {base::FilePath(FILE_PATH_LITERAL("A (1).txt")),
+ std::string("just some more more data")},
+ {base::FilePath(FILE_PATH_LITERAL("A.txt")),
+ std::string("just some more more more data")},
+ };
+
+ for (const auto& tymed : kStorageMediaTypesForVirtualFiles) {
+ OSExchangeData data;
+ data.provider().SetVirtualFileContentsForTesting(
+ kTestFilenames_and_Contents, tymed);
+
+ OSExchangeData copy(data.provider().Clone());
+ std::vector<FileInfo> file_infos;
+ EXPECT_TRUE(copy.GetVirtualFilenames(&file_infos));
+ EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size());
+ for (size_t i = 0; i < file_infos.size(); i++) {
+ // Check that display name is unique.
+ for (size_t j = 0; j < i; j++) {
+ EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase(
+ file_infos[j].display_name.value(),
+ file_infos[i].display_name.value()));
+ }
+ }
+
+ std::string read_contents;
+ base::FilePath temp_dir;
+ EXPECT_TRUE(base::GetTempDir(&temp_dir));
+
+ // Callback for GetVirtualFilesAsTempFiles is executed when all virtual
+ // files are backed by temp files.
+ auto callback =
+ base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles,
+ base::Unretained(this));
+
+ EXPECT_TRUE(copy.GetVirtualFilesAsTempFiles(std::move(callback)));
+
+ // RunUntilIdle assures all async tasks are run.
+ scoped_task_environment_.RunUntilIdle();
+
+ EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size());
+ for (size_t i = 0; i < retrieved_virtual_files_.size(); i++) {
+ // Check that display name is unique.
+ for (size_t j = 0; j < i; j++) {
+ EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase(
+ retrieved_virtual_files_[j].display_name.value(),
+ retrieved_virtual_files_[i].display_name.value()));
+ }
+
+ // Check that temp file path is unique.
+ for (size_t j = 0; j < i; j++) {
+ EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase(
+ retrieved_virtual_files_[j].path.value(),
+ retrieved_virtual_files_[i].path.value()));
+ }
+
+ // Check if the temp files that back the virtual files are actually
+ // created in the temp directory. Need to compare long file paths here
+ // because GetTempDir can return a short ("8.3") path if the test is run
+ // under a username that is too long.
+ EXPECT_EQ(
+ base::MakeLongFilePath(temp_dir),
+ base::MakeLongFilePath(retrieved_virtual_files_[i].path.DirName()));
+ EXPECT_EQ(kTestFilenames_and_Contents[i].first.Extension(),
+ retrieved_virtual_files_[i].path.Extension());
+ EXPECT_TRUE(base::ReadFileToString(retrieved_virtual_files_[i].path,
+ &read_contents));
+ if (tymed != TYMED_ISTORAGE) {
+ EXPECT_EQ(kTestFilenames_and_Contents[i].second, read_contents);
+ } else {
+ // IStorage uses compound files, so temp files won't be flat text files.
+ // Just make sure the original contents appears in the compound files.
+ EXPECT_TRUE(read_contents.find(kTestFilenames_and_Contents[i].second) !=
+ std::string::npos);
+ }
+ }
+ }
+} // namespace ui
+
+TEST_F(OSExchangeDataWinTest, VirtualFilesDuplicateNamesCaseInsensitivity) {
+ const std::vector<std::pair<base::FilePath, std::string>>
+ kTestFilenames_and_Contents = {
+ {base::FilePath(FILE_PATH_LITERAL("a.txt")),
+ std::string("just some data")},
+ {base::FilePath(FILE_PATH_LITERAL("B.txt")),
+ std::string("just some more data")},
+ {base::FilePath(FILE_PATH_LITERAL("A.txt")),
+ std::string("just some more more data")},
+ };
+
+ for (const auto& tymed : kStorageMediaTypesForVirtualFiles) {
+ OSExchangeData data;
+ data.provider().SetVirtualFileContentsForTesting(
+ kTestFilenames_and_Contents, tymed);
+
+ OSExchangeData copy(data.provider().Clone());
+ std::vector<FileInfo> file_infos;
+ EXPECT_TRUE(copy.GetVirtualFilenames(&file_infos));
+ EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size());
+ for (size_t i = 0; i < file_infos.size(); i++) {
+ // Check that display name is unique.
+ for (size_t j = 0; j < i; j++) {
+ EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase(
+ file_infos[j].display_name.value(),
+ file_infos[i].display_name.value()));
+ }
+ }
+
+ std::string read_contents;
+ base::FilePath temp_dir;
+ EXPECT_TRUE(base::GetTempDir(&temp_dir));
+
+ // Callback for GetVirtualFilesAsTempFiles is executed when all virtual
+ // files are backed by temp files.
+ auto callback =
+ base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles,
+ base::Unretained(this));
+
+ EXPECT_TRUE(copy.GetVirtualFilesAsTempFiles(std::move(callback)));
+
+ // RunUntilIdle assures all async tasks are run.
+ scoped_task_environment_.RunUntilIdle();
+
+ EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size());
+ for (size_t i = 0; i < retrieved_virtual_files_.size(); i++) {
+ // Check that display name is unique.
+ for (size_t j = 0; j < i; j++) {
+ EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase(
+ retrieved_virtual_files_[j].display_name.value(),
+ retrieved_virtual_files_[i].display_name.value()));
+ }
+
+ // Check that temp file path is unique.
+ for (size_t j = 0; j < i; j++) {
+ EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase(
+ retrieved_virtual_files_[j].path.value(),
+ retrieved_virtual_files_[i].path.value()));
+ }
+
+ // Check if the temp files that back the virtual files are actually
+ // created in the temp directory. Need to compare long file paths here
+ // because GetTempDir can return a short ("8.3") path if the test is run
+ // under a username that is too long.
+ EXPECT_EQ(
+ base::MakeLongFilePath(temp_dir),
+ base::MakeLongFilePath(retrieved_virtual_files_[i].path.DirName()));
+ EXPECT_EQ(kTestFilenames_and_Contents[i].first.Extension(),
+ retrieved_virtual_files_[i].path.Extension());
+ EXPECT_TRUE(base::ReadFileToString(retrieved_virtual_files_[i].path,
+ &read_contents));
+ if (tymed != TYMED_ISTORAGE) {
+ EXPECT_EQ(kTestFilenames_and_Contents[i].second, read_contents);
+ } else {
+ // IStorage uses compound files, so temp files won't be flat text files.
+ // Just make sure the original contents appears in the compound files.
+ EXPECT_TRUE(read_contents.find(kTestFilenames_and_Contents[i].second) !=
+ std::string::npos);
+ }
+ }
+ }
+}
+
+TEST_F(OSExchangeDataWinTest, VirtualFilesInvalidAndDuplicateNames) {
+ const base::string16 kInvalidFileNameCharacters(
+ FILE_PATH_LITERAL("\\/:*?\"<>|"));
+ const base::string16 kInvalidFilePathCharacters(
+ FILE_PATH_LITERAL("/*?\"<>|"));
+ const base::FilePath pathWithInvalidFileNameCharacters =
+ base::FilePath(kInvalidFileNameCharacters)
+ .AddExtension(FILE_PATH_LITERAL("txt"));
+ const base::FilePath empty_display_name(FILE_PATH_LITERAL(""));
+ const base::FilePath maxpath_display_name =
+ base::FilePath(base::string16(MAX_PATH - 5, L'a'))
+ .AddExtension(FILE_PATH_LITERAL("txt"));
+
+ const std::vector<std::pair<base::FilePath, std::string>>
+ kTestFilenames_and_Contents = {
+ {pathWithInvalidFileNameCharacters, std::string("just some data")},
+ {pathWithInvalidFileNameCharacters,
+ std::string("just some data\0with\0nulls", 25)},
+ {// Test that still get a unique name if a previous uniquified
+ // name is duplicate of this one.
+ pathWithInvalidFileNameCharacters.InsertBeforeExtension(
+ FILE_PATH_LITERAL(" (1)")),
+ std::string("just some more data")},
+ // Expect a default display name to be generated ("download" if it
+ // matters).
+ {empty_display_name, std::string("data for an empty display name")},
+ {empty_display_name,
+ std::string("data for another empty display name")},
+ // Expect a good behavior if the display name length exceeds MAX_PATH.
+ {maxpath_display_name,
+ std::string("data for a >MAX_PATH display name")},
+ {maxpath_display_name,
+ std::string("data for another >MAX_PATH display name")},
+ };
+
+ for (const auto& tymed : kStorageMediaTypesForVirtualFiles) {
+ OSExchangeData data;
+ data.provider().SetVirtualFileContentsForTesting(
+ kTestFilenames_and_Contents, tymed);
+
+ OSExchangeData copy(data.provider().Clone());
+ std::vector<FileInfo> file_infos;
+ EXPECT_TRUE(copy.GetVirtualFilenames(&file_infos));
+ EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size());
+ for (size_t i = 0; i < file_infos.size(); i++) {
+ // Check that display name does not contain invalid characters.
+ EXPECT_EQ(std::string::npos,
+ file_infos[i].display_name.value().find_first_of(
+ kInvalidFileNameCharacters));
+ // Check that display name is unique.
+ for (size_t j = 0; j < i; j++) {
+ EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase(
+ file_infos[j].display_name.value(),
+ file_infos[i].display_name.value()));
+ }
+ }
+
+ std::string read_contents;
+ base::FilePath temp_dir;
+ EXPECT_TRUE(base::GetTempDir(&temp_dir));
+
+ // Callback for GetVirtualFilesAsTempFiles is executed when all virtual
+ // files are backed by temp files.
+ auto callback =
+ base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles,
+ base::Unretained(this));
+
+ EXPECT_TRUE(copy.GetVirtualFilesAsTempFiles(std::move(callback)));
+
+ // RunUntilIdle assures all async tasks are run.
+ scoped_task_environment_.RunUntilIdle();
+
+ EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size());
+ for (size_t i = 0; i < retrieved_virtual_files_.size(); i++) {
+ // Check that display name does not contain invalid characters.
+ EXPECT_EQ(std::string::npos,
+ retrieved_virtual_files_[i].display_name.value().find_first_of(
+ kInvalidFileNameCharacters));
+ // Check that display name is unique.
+ for (size_t j = 0; j < i; j++) {
+ EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase(
+ retrieved_virtual_files_[j].display_name.value(),
+ retrieved_virtual_files_[i].display_name.value()));
+ }
+ // Check that temp file path does not contain invalid characters (except
+ // for separator).
+ EXPECT_EQ(std::string::npos,
+ retrieved_virtual_files_[i].path.value().find_first_of(
+ kInvalidFilePathCharacters));
+ // Check that temp file path is unique.
+ for (size_t j = 0; j < i; j++) {
+ EXPECT_FALSE(base::FilePath::CompareEqualIgnoreCase(
+ retrieved_virtual_files_[j].path.value(),
+ retrieved_virtual_files_[i].path.value()));
+ }
+
+ // Check if the temp files that back the virtual files are actually
+ // created in the temp directory. Need to compare long file paths here
+ // because GetTempDir can return a short ("8.3") path if the test is run
+ // under a username that is too long.
+ EXPECT_EQ(
+ base::MakeLongFilePath(temp_dir),
+ base::MakeLongFilePath(retrieved_virtual_files_[i].path.DirName()));
+ EXPECT_EQ(kTestFilenames_and_Contents[i].first.Extension(),
+ retrieved_virtual_files_[i].path.Extension());
+ // Ability to read the contents implies a temp file was successfully
+ // created on the file system even though the original suggested display
+ // name had invalid filename characters.
+ EXPECT_TRUE(base::ReadFileToString(retrieved_virtual_files_[i].path,
+ &read_contents));
+ if (tymed != TYMED_ISTORAGE) {
+ EXPECT_EQ(kTestFilenames_and_Contents[i].second, read_contents);
+ } else {
+ // IStorage uses compound files, so temp files won't be flat text files.
+ // Just make sure the original contents appears in the compound files.
+ EXPECT_TRUE(read_contents.find(kTestFilenames_and_Contents[i].second) !=
+ std::string::npos);
+ }
+ }
+ }
+}
+
+TEST_F(OSExchangeDataWinTest, VirtualFilesEmptyContents) {
+ const std::vector<std::pair<base::FilePath, std::string>>
+ kTestFilenames_and_Contents = {
+ {base::FilePath(FILE_PATH_LITERAL("file_with_no_contents.txt")),
+ std::string()},
+ };
+
+ for (const auto& tymed : kStorageMediaTypesForVirtualFiles) {
+ OSExchangeData data;
+ data.provider().SetVirtualFileContentsForTesting(
+ kTestFilenames_and_Contents, tymed);
+
+ OSExchangeData copy(data.provider().Clone());
+ std::vector<FileInfo> file_infos;
+ EXPECT_TRUE(copy.GetVirtualFilenames(&file_infos));
+ EXPECT_EQ(kTestFilenames_and_Contents.size(), file_infos.size());
+ for (size_t i = 0; i < file_infos.size(); i++) {
+ EXPECT_EQ(kTestFilenames_and_Contents[i].first,
+ file_infos[i].display_name);
+ }
+
+ std::string read_contents;
+ base::FilePath temp_dir;
+ EXPECT_TRUE(base::GetTempDir(&temp_dir));
+
+ // Callback for GetVirtualFilesAsTempFiles is executed when all virtual
+ // files are backed by temp files.
+ auto callback =
+ base::BindOnce(&OSExchangeDataWinTest::OnGotVirtualFilesAsTempFiles,
+ base::Unretained(this));
+
+ EXPECT_TRUE(copy.GetVirtualFilesAsTempFiles(std::move(callback)));
+
+ // RunUntilIdle assures all async tasks are run.
+ scoped_task_environment_.RunUntilIdle();
+
+ EXPECT_EQ(kTestFilenames_and_Contents.size(),
+ retrieved_virtual_files_.size());
+ for (size_t i = 0; i < retrieved_virtual_files_.size(); i++) {
+ EXPECT_EQ(kTestFilenames_and_Contents[i].first,
+ retrieved_virtual_files_[i].display_name);
+
+ // Check if the temp files that back the virtual files are actually
+ // created in the temp directory. Need to compare long file paths here
+ // because GetTempDir can return a short ("8.3") path if the test is run
+ // under a username that is too long.
+ EXPECT_EQ(
+ base::MakeLongFilePath(temp_dir),
+ base::MakeLongFilePath(retrieved_virtual_files_[i].path.DirName()));
+ EXPECT_EQ(kTestFilenames_and_Contents[i].first.Extension(),
+ retrieved_virtual_files_[i].path.Extension());
+ EXPECT_TRUE(base::ReadFileToString(retrieved_virtual_files_[i].path,
+ &read_contents));
+ // IStorage uses compound files, so temp files won't be flat text files.
+ // Just make sure the original contents appear in the compound files.
+ if (tymed != TYMED_ISTORAGE) {
+ EXPECT_EQ(kTestFilenames_and_Contents[i].second, read_contents);
+ EXPECT_EQ(static_cast<size_t>(0), read_contents.length());
+ }
+ }
+ }
+}
+
+TEST_F(OSExchangeDataWinTest, CFHtml) {
OSExchangeData data;
GURL url("http://www.google.com/");
std::wstring html(
@@ -332,13 +845,13 @@ TEST(OSExchangeDataWinTest, CFHtml) {
ReleaseStgMedium(&medium);
}
-TEST(OSExchangeDataWinTest, SetURLWithMaxPath) {
+TEST_F(OSExchangeDataWinTest, SetURLWithMaxPath) {
OSExchangeData data;
std::wstring long_title(L'a', MAX_PATH + 1);
data.SetURL(GURL("http://google.com"), long_title);
}
-TEST(OSExchangeDataWinTest, ProvideURLForPlainTextURL) {
+TEST_F(OSExchangeDataWinTest, ProvideURLForPlainTextURL) {
OSExchangeData data;
data.SetString(L"http://google.com");
diff --git a/chromium/ui/base/emoji/emoji_panel_helper_win.cc b/chromium/ui/base/emoji/emoji_panel_helper_win.cc
index a4b1eca7ea3..aa0e6492696 100644
--- a/chromium/ui/base/emoji/emoji_panel_helper_win.cc
+++ b/chromium/ui/base/emoji/emoji_panel_helper_win.cc
@@ -14,7 +14,7 @@ namespace ui {
bool IsEmojiPanelSupported() {
// Emoji picker is supported on Windows 10's Spring 2018 Update and
// above.
- return base::win::GetVersion() >= base::win::Version::VERSION_WIN10_RS4;
+ return base::win::GetVersion() >= base::win::Version::WIN10_RS4;
}
void ShowEmojiPanel() {
diff --git a/chromium/ui/base/idle/BUILD.gn b/chromium/ui/base/idle/BUILD.gn
index d9e3eea541d..530d02ade78 100644
--- a/chromium/ui/base/idle/BUILD.gn
+++ b/chromium/ui/base/idle/BUILD.gn
@@ -13,6 +13,13 @@ component("idle") {
defines = [ "IS_UI_BASE_IDLE_IMPL" ]
+ # All targets in this file are allowed to access any of the headers.
+ friend = [ ":*" ]
+
+ public = [
+ "idle.h",
+ ]
+
deps = [
"//base",
"//ui/base",
@@ -26,6 +33,8 @@ component("idle") {
"idle.cc",
"idle.h",
"idle_chromeos.cc",
+ "idle_internal.cc",
+ "idle_internal.h",
"idle_mac.mm",
"idle_win.cc",
]
@@ -66,3 +75,17 @@ component("idle") {
]
}
}
+
+static_library("test_support") {
+ testonly = true
+
+ sources = [
+ "scoped_set_idle_state.cc",
+ "scoped_set_idle_state.h",
+ ]
+
+ deps = [
+ ":idle",
+ "//base",
+ ]
+}
diff --git a/chromium/ui/base/idle/idle.cc b/chromium/ui/base/idle/idle.cc
index 0333fbc18ce..3f0e34d2bdf 100644
--- a/chromium/ui/base/idle/idle.cc
+++ b/chromium/ui/base/idle/idle.cc
@@ -4,9 +4,14 @@
#include "ui/base/idle/idle.h"
+#include "ui/base/idle/idle_internal.h"
+
namespace ui {
IdleState CalculateIdleState(int idle_threshold) {
+ if (IdleStateForTesting().has_value())
+ return IdleStateForTesting().value();
+
if (CheckIdleStateIsLocked())
return IDLE_STATE_LOCKED;
diff --git a/chromium/ui/base/idle/idle_android.cc b/chromium/ui/base/idle/idle_android.cc
index f21e03dbff6..40190e89587 100644
--- a/chromium/ui/base/idle/idle_android.cc
+++ b/chromium/ui/base/idle/idle_android.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "jni/IdleDetector_jni.h"
+#include "ui/base/idle/idle_internal.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
@@ -71,6 +72,9 @@ int CalculateIdleTime() {
}
bool CheckIdleStateIsLocked() {
+ if (IdleStateForTesting().has_value())
+ return IdleStateForTesting().value() == IDLE_STATE_LOCKED;
+
return AndroidIdleMonitor::GetInstance()->CheckIdleStateIsLocked();
}
diff --git a/chromium/ui/base/idle/idle_chromeos.cc b/chromium/ui/base/idle/idle_chromeos.cc
index a58a28591a0..a0f4cde65dc 100644
--- a/chromium/ui/base/idle/idle_chromeos.cc
+++ b/chromium/ui/base/idle/idle_chromeos.cc
@@ -6,6 +6,7 @@
#include "base/time/time.h"
#include "chromeos/dbus/session_manager/session_manager_client.h"
+#include "ui/base/idle/idle_internal.h"
#include "ui/base/user_activity/user_activity_detector.h"
namespace ui {
@@ -17,6 +18,9 @@ int CalculateIdleTime() {
}
bool CheckIdleStateIsLocked() {
+ if (IdleStateForTesting().has_value())
+ return IdleStateForTesting().value() == IDLE_STATE_LOCKED;
+
return chromeos::SessionManagerClient::Get()->IsScreenLocked();
}
diff --git a/chromium/ui/base/idle/idle_internal.cc b/chromium/ui/base/idle/idle_internal.cc
new file mode 100644
index 00000000000..ac62882ee5f
--- /dev/null
+++ b/chromium/ui/base/idle/idle_internal.cc
@@ -0,0 +1,16 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/idle/idle_internal.h"
+
+#include "base/no_destructor.h"
+
+namespace ui {
+
+base::Optional<IdleState>& IdleStateForTesting() {
+ static base::NoDestructor<base::Optional<IdleState>> idle_state;
+ return *idle_state;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/idle/idle_internal.h b/chromium/ui/base/idle/idle_internal.h
new file mode 100644
index 00000000000..01e959854f9
--- /dev/null
+++ b/chromium/ui/base/idle/idle_internal.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IDLE_IDLE_INTERNAL_H_
+#define UI_BASE_IDLE_IDLE_INTERNAL_H_
+
+#include "base/component_export.h"
+#include "base/optional.h"
+#include "ui/base/idle/idle.h"
+
+namespace ui {
+
+// An optional idle state set by tests via a ScopedSetIdleState to override the
+// actual idle state of the system.
+COMPONENT_EXPORT(UI_BASE_IDLE) base::Optional<IdleState>& IdleStateForTesting();
+
+} // namespace ui
+
+#endif // UI_BASE_IDLE_IDLE_INTERNAL_H_
diff --git a/chromium/ui/base/idle/idle_linux.cc b/chromium/ui/base/idle/idle_linux.cc
index 7058b873b82..ec0ed5c89e2 100644
--- a/chromium/ui/base/idle/idle_linux.cc
+++ b/chromium/ui/base/idle/idle_linux.cc
@@ -4,6 +4,8 @@
#include "ui/base/idle/idle.h"
+#include "ui/base/idle/idle_internal.h"
+
#if defined(USE_X11)
#include "ui/base/idle/idle_query_x11.h"
#include "ui/base/idle/screensaver_window_finder_x11.h"
@@ -21,6 +23,9 @@ int CalculateIdleTime() {
}
bool CheckIdleStateIsLocked() {
+ if (IdleStateForTesting().has_value())
+ return IdleStateForTesting().value() == IDLE_STATE_LOCKED;
+
#if defined(USE_X11)
// Usually the screensaver is used to lock the screen.
return ScreensaverWindowFinder::ScreensaverWindowExists();
diff --git a/chromium/ui/base/idle/idle_mac.mm b/chromium/ui/base/idle/idle_mac.mm
index dc355502c7c..54535863d1f 100644
--- a/chromium/ui/base/idle/idle_mac.mm
+++ b/chromium/ui/base/idle/idle_mac.mm
@@ -7,6 +7,8 @@
#include <ApplicationServices/ApplicationServices.h>
#import <Cocoa/Cocoa.h>
+#include "ui/base/idle/idle_internal.h"
+
@interface MacScreenMonitor : NSObject {
@private
BOOL screensaverRunning_;
@@ -92,6 +94,9 @@ int CalculateIdleTime() {
}
bool CheckIdleStateIsLocked() {
+ if (IdleStateForTesting().has_value())
+ return IdleStateForTesting().value() == IDLE_STATE_LOCKED;
+
return [g_screenMonitor isScreensaverRunning] ||
[g_screenMonitor isScreenLocked];
}
diff --git a/chromium/ui/base/idle/idle_win.cc b/chromium/ui/base/idle/idle_win.cc
index 4946406f2f5..2c1d3a7d601 100644
--- a/chromium/ui/base/idle/idle_win.cc
+++ b/chromium/ui/base/idle/idle_win.cc
@@ -7,6 +7,7 @@
#include <limits.h>
#include <windows.h>
+#include "ui/base/idle/idle_internal.h"
#include "ui/base/win/lock_state.h"
namespace ui {
@@ -51,6 +52,9 @@ int CalculateIdleTime() {
}
bool CheckIdleStateIsLocked() {
+ if (IdleStateForTesting().has_value())
+ return IdleStateForTesting().value() == IDLE_STATE_LOCKED;
+
return ui::IsWorkstationLocked() || IsScreensaverRunning();
}
diff --git a/chromium/ui/base/idle/scoped_set_idle_state.cc b/chromium/ui/base/idle/scoped_set_idle_state.cc
new file mode 100644
index 00000000000..93baa00b0df
--- /dev/null
+++ b/chromium/ui/base/idle/scoped_set_idle_state.cc
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/idle/scoped_set_idle_state.h"
+
+#include "ui/base/idle/idle_internal.h"
+
+namespace ui {
+
+ScopedSetIdleState::ScopedSetIdleState(IdleState state)
+ : previous_state_(IdleStateForTesting()) {
+ IdleStateForTesting() = state;
+}
+
+ScopedSetIdleState::~ScopedSetIdleState() {
+ IdleStateForTesting() = previous_state_;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/idle/scoped_set_idle_state.h b/chromium/ui/base/idle/scoped_set_idle_state.h
new file mode 100644
index 00000000000..fa3e61786c5
--- /dev/null
+++ b/chromium/ui/base/idle/scoped_set_idle_state.h
@@ -0,0 +1,26 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IDLE_SCOPED_SET_IDLE_STATE_H_
+#define UI_BASE_IDLE_SCOPED_SET_IDLE_STATE_H_
+
+#include "base/optional.h"
+#include "ui/base/idle/idle.h"
+
+namespace ui {
+
+class ScopedSetIdleState {
+ public:
+ explicit ScopedSetIdleState(IdleState state);
+ ~ScopedSetIdleState();
+
+ private:
+ base::Optional<IdleState> previous_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSetIdleState);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IDLE_SCOPED_SET_IDLE_STATE_H_ \ No newline at end of file
diff --git a/chromium/ui/base/ime/BUILD.gn b/chromium/ui/base/ime/BUILD.gn
index 8826b2124c1..ce594dc2f60 100644
--- a/chromium/ui/base/ime/BUILD.gn
+++ b/chromium/ui/base/ime/BUILD.gn
@@ -7,6 +7,7 @@ import("//build/config/ui.gni")
source_set("text_input_types") {
sources = [
+ "text_input_action.h",
"text_input_flags.h",
"text_input_mode.h",
"text_input_type.h",
diff --git a/chromium/ui/base/ime/constants.cc b/chromium/ui/base/ime/constants.cc
index e9556078fc3..9acc87b7747 100644
--- a/chromium/ui/base/ime/constants.cc
+++ b/chromium/ui/base/ime/constants.cc
@@ -6,6 +6,18 @@
namespace ui {
+// Here, we define attributes of ui::Event::Properties objects
+// kPropertyFromVK
const char kPropertyFromVK[] = "from_vk";
+// Properties of the kPropertyFromVK attribute
+
+// kFromVKIsMirroring is the index of the isMirrorring property on the
+// kPropertyFromVK attribute. This is non-zero if mirroring and zero if not
+// mirroring
+const size_t kPropertyFromVKIsMirroringIndex = 0;
+// kFromVKSize is the size of the kPropertyFromVK attribute
+// It is equal to the number of kPropertyFromVK
+const size_t kPropertyFromVKSize = 1;
+
} // namespace ui
diff --git a/chromium/ui/base/ime/constants.h b/chromium/ui/base/ime/constants.h
index 3224e34e65f..aab369adb8b 100644
--- a/chromium/ui/base/ime/constants.h
+++ b/chromium/ui/base/ime/constants.h
@@ -6,6 +6,7 @@
#define UI_BASE_IME_CONSTANTS_H_
#include "base/component_export.h"
+#include "stddef.h"
namespace ui {
@@ -16,6 +17,12 @@ namespace ui {
// Textfield).
COMPONENT_EXPORT(UI_BASE_IME) extern const char kPropertyFromVK[];
+// kPropertyFromVKIsMirroringIndex is an index into kPropertyFromVK
+// and is used when the key event occurs when mirroring is detected.
+COMPONENT_EXPORT(UI_BASE_IME)
+extern const size_t kPropertyFromVKIsMirroringIndex;
+COMPONENT_EXPORT(UI_BASE_IME) extern const size_t kPropertyFromVKSize;
+
} // namespace ui
#endif // UI_BASE_IME_CONSTANTS_H_
diff --git a/chromium/ui/base/ime/dummy_text_input_client.cc b/chromium/ui/base/ime/dummy_text_input_client.cc
index 1bedbfeb6d6..da3fc28f88d 100644
--- a/chromium/ui/base/ime/dummy_text_input_client.cc
+++ b/chromium/ui/base/ime/dummy_text_input_client.cc
@@ -145,11 +145,15 @@ bool DummyTextInputClient::ShouldDoLearning() {
return false;
}
-#if defined(OS_WIN)
-void DummyTextInputClient::SetCompositionFromExistingText(
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+bool DummyTextInputClient::SetCompositionFromExistingText(
const gfx::Range& range,
- const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) {}
+ const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) {
+ return false;
+}
+#endif
+#if defined(OS_WIN)
void DummyTextInputClient::SetActiveCompositionForAccessibility(
const gfx::Range& range,
const base::string16& active_composition_text,
diff --git a/chromium/ui/base/ime/dummy_text_input_client.h b/chromium/ui/base/ime/dummy_text_input_client.h
index a06a70eb07b..0d9f505357e 100644
--- a/chromium/ui/base/ime/dummy_text_input_client.h
+++ b/chromium/ui/base/ime/dummy_text_input_client.h
@@ -56,11 +56,13 @@ class DummyTextInputClient : public TextInputClient {
ukm::SourceId GetClientSourceForMetrics() const override;
bool ShouldDoLearning() override;
-#if defined(OS_WIN)
- // Overridden from ui::TextInputClient(Windows only):
- void SetCompositionFromExistingText(
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+ bool SetCompositionFromExistingText(
const gfx::Range& range,
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
+#endif
+
+#if defined(OS_WIN)
void SetActiveCompositionForAccessibility(
const gfx::Range& range,
const base::string16& active_composition_text,
diff --git a/chromium/ui/base/ime/ime_engine_handler_interface.h b/chromium/ui/base/ime/ime_engine_handler_interface.h
index 37d015cbc5e..2b10904785b 100644
--- a/chromium/ui/base/ime/ime_engine_handler_interface.h
+++ b/chromium/ui/base/ime/ime_engine_handler_interface.h
@@ -114,10 +114,6 @@ class COMPONENT_EXPORT(UI_BASE_IME) IMEEngineHandlerInterface {
// Called when the composition bounds changed.
virtual void SetCompositionBounds(const std::vector<gfx::Rect>& bounds) = 0;
- // Returns whether the engine is interested in key events.
- // If not, InputMethodChromeOS won't feed it with key events.
- virtual bool IsInterestedInKeyEvent() const = 0;
-
#if defined(OS_CHROMEOS)
// Called when a property is activated or changed.
diff --git a/chromium/ui/base/ime/ime_input_context_handler_interface.h b/chromium/ui/base/ime/ime_input_context_handler_interface.h
index 21c0f45c541..88abe7dd29a 100644
--- a/chromium/ui/base/ime/ime_input_context_handler_interface.h
+++ b/chromium/ui/base/ime/ime_input_context_handler_interface.h
@@ -25,6 +25,15 @@ class COMPONENT_EXPORT(UI_BASE_IME) IMEInputContextHandlerInterface {
// Called when the engine commit a text.
virtual void CommitText(const std::string& text) = 0;
+#if defined(OS_CHROMEOS)
+ // Called when the engine changes the composition range.
+ // Returns whether the operation was successful.
+ virtual bool SetCompositionRange(
+ uint32_t before,
+ uint32_t after,
+ const std::vector<ui::ImeTextSpan>& text_spans) = 0;
+#endif
+
// Called when the engine updates composition text.
virtual void UpdateCompositionText(const CompositionText& text,
uint32_t cursor_pos,
diff --git a/chromium/ui/base/ime/ime_text_span.cc b/chromium/ui/base/ime/ime_text_span.cc
index 14b482ed591..4f3aeadbc2b 100644
--- a/chromium/ui/base/ime/ime_text_span.cc
+++ b/chromium/ui/base/ime/ime_text_span.cc
@@ -9,17 +9,6 @@
namespace ui {
-ImeTextSpan::ImeTextSpan() : ImeTextSpan(0, 0, Thickness::kThin) {}
-
-ImeTextSpan::ImeTextSpan(uint32_t start_offset,
- uint32_t end_offset,
- Thickness thickness)
- : ImeTextSpan(Type::kComposition,
- start_offset,
- end_offset,
- thickness,
- SK_ColorTRANSPARENT) {}
-
ImeTextSpan::ImeTextSpan(Type type,
uint32_t start_offset,
uint32_t end_offset,
diff --git a/chromium/ui/base/ime/ime_text_span.h b/chromium/ui/base/ime/ime_text_span.h
index 4e449567d8d..67902494fcb 100644
--- a/chromium/ui/base/ime/ime_text_span.h
+++ b/chromium/ui/base/ime/ime_text_span.h
@@ -37,18 +37,12 @@ struct COMPONENT_EXPORT(UI_BASE_IME_TYPES) ImeTextSpan {
kThick,
};
- // The default constructor is used by generated Mojo code.
- ImeTextSpan();
- // TODO(huangs): remove this constructor.
- ImeTextSpan(uint32_t start_offset,
- uint32_t end_offset,
- Thickness thickness);
ImeTextSpan(
- Type type,
- uint32_t start_offset,
- uint32_t end_offset,
- Thickness thickness,
- SkColor background_color,
+ Type type = Type::kComposition,
+ uint32_t start_offset = 0,
+ uint32_t end_offset = 0,
+ Thickness thickness = Thickness::kThin,
+ SkColor background_color = SK_ColorTRANSPARENT,
SkColor suggestion_highlight_color = SK_ColorTRANSPARENT,
const std::vector<std::string>& suggestions = std::vector<std::string>());
diff --git a/chromium/ui/base/ime/init/input_method_factory.cc b/chromium/ui/base/ime/init/input_method_factory.cc
index 15147aa7045..81f7f8a9a1e 100644
--- a/chromium/ui/base/ime/init/input_method_factory.cc
+++ b/chromium/ui/base/ime/init/input_method_factory.cc
@@ -61,7 +61,7 @@ std::unique_ptr<InputMethod> CreateInputMethod(
return std::make_unique<InputMethodChromeOS>(delegate);
#elif defined(OS_WIN)
if (base::FeatureList::IsEnabled(features::kTSFImeSupport) &&
- base::win::GetVersion() >= base::win::VERSION_WIN10_RS2) {
+ base::win::GetVersion() >= base::win::Version::WIN10_RS3) {
return std::make_unique<InputMethodWinTSF>(delegate, widget);
}
return std::make_unique<InputMethodWinImm32>(delegate, widget);
diff --git a/chromium/ui/base/ime/input_method_base.cc b/chromium/ui/base/ime/input_method_base.cc
index b2203febab1..b621ced8c27 100644
--- a/chromium/ui/base/ime/input_method_base.cc
+++ b/chromium/ui/base/ime/input_method_base.cc
@@ -254,6 +254,15 @@ void InputMethodBase::UpdateCompositionText(const CompositionText& composition_,
SendFakeProcessKeyEvent(false);
}
+#if defined(OS_CHROMEOS)
+bool InputMethodBase::SetCompositionRange(
+ uint32_t before,
+ uint32_t after,
+ const std::vector<ui::ImeTextSpan>& text_spans) {
+ return false;
+}
+#endif
+
void InputMethodBase::DeleteSurroundingText(int32_t offset, uint32_t length) {}
SurroundingTextInfo InputMethodBase::GetSurroundingTextInfo() {
diff --git a/chromium/ui/base/ime/input_method_base.h b/chromium/ui/base/ime/input_method_base.h
index be649f4f709..fb57c53ccbc 100644
--- a/chromium/ui/base/ime/input_method_base.h
+++ b/chromium/ui/base/ime/input_method_base.h
@@ -90,6 +90,14 @@ class COMPONENT_EXPORT(UI_BASE_IME) InputMethodBase
void UpdateCompositionText(const CompositionText& text,
uint32_t cursor_pos,
bool visible) override;
+
+#if defined(OS_CHROMEOS)
+ bool SetCompositionRange(
+ uint32_t before,
+ uint32_t after,
+ const std::vector<ui::ImeTextSpan>& text_spans) override;
+#endif
+
void DeleteSurroundingText(int32_t offset, uint32_t length) override;
SurroundingTextInfo GetSurroundingTextInfo() override;
void SendKeyEvent(KeyEvent* event) override;
diff --git a/chromium/ui/base/ime/input_method_delegate.cc b/chromium/ui/base/ime/input_method_delegate.cc
index 92c25586fa4..a0e165d5c9b 100644
--- a/chromium/ui/base/ime/input_method_delegate.cc
+++ b/chromium/ui/base/ime/input_method_delegate.cc
@@ -4,19 +4,11 @@
#include "ui/base/ime/input_method_delegate.h"
-#include "base/callback.h"
-#include "ui/base/ime/mojo/ime.mojom.h"
#include "ui/events/event.h"
namespace ui {
namespace internal {
-bool InputMethodDelegate::ConnectToImeEngine(
- ::ime::mojom::ImeEngineRequest engine_request,
- ::ime::mojom::ImeEngineClientPtr client) {
- return false;
-}
-
// static
void InputMethodDelegate::RunDispatchKeyEventPostIMECallback(
KeyEvent* key_event,
diff --git a/chromium/ui/base/ime/input_method_delegate.h b/chromium/ui/base/ime/input_method_delegate.h
index 324982e39ad..c6c238cf228 100644
--- a/chromium/ui/base/ime/input_method_delegate.h
+++ b/chromium/ui/base/ime/input_method_delegate.h
@@ -5,19 +5,8 @@
#ifndef UI_BASE_IME_INPUT_METHOD_DELEGATE_H_
#define UI_BASE_IME_INPUT_METHOD_DELEGATE_H_
-#include "base/callback_forward.h"
+#include "base/callback.h"
#include "base/component_export.h"
-#include "mojo/public/cpp/bindings/interface_ptr.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-
-namespace ime {
-namespace mojom {
-
-class ImeEngine;
-class ImeEngineClient;
-
-} // namespace mojom
-} // namespace ime
namespace ui {
@@ -45,10 +34,6 @@ class COMPONENT_EXPORT(UI_BASE_IME) InputMethodDelegate {
KeyEvent* key_event,
DispatchKeyEventPostIMECallback callback) = 0;
- virtual bool ConnectToImeEngine(
- mojo::InterfaceRequest<::ime::mojom::ImeEngine> engine_request,
- mojo::InterfacePtr<::ime::mojom::ImeEngineClient> client);
-
protected:
static void RunDispatchKeyEventPostIMECallback(
KeyEvent* key_event,
diff --git a/chromium/ui/base/ime/linux/input_method_auralinux.cc b/chromium/ui/base/ime/linux/input_method_auralinux.cc
index 1bfa4258a69..ae5043c43d5 100644
--- a/chromium/ui/base/ime/linux/input_method_auralinux.cc
+++ b/chromium/ui/base/ime/linux/input_method_auralinux.cc
@@ -92,8 +92,7 @@ ui::EventDispatchDetails InputMethodAuraLinux::DispatchKeyEvent(
// or the ET_KEY_RELEASED event of all key.
// 2) |filtered| == true && NeedInsertChar(): the ET_KEY_PRESSED event of
// character key.
- if (text_input_type_ != TEXT_INPUT_TYPE_PASSWORD &&
- GetEngine() && GetEngine()->IsInterestedInKeyEvent() &&
+ if (text_input_type_ != TEXT_INPUT_TYPE_PASSWORD && GetEngine() &&
(!filtered || NeedInsertChar())) {
ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback =
base::BindOnce(&InputMethodAuraLinux::ProcessKeyEventByEngineDone,
diff --git a/chromium/ui/base/ime/mock_ime_input_context_handler.cc b/chromium/ui/base/ime/mock_ime_input_context_handler.cc
index e01c87efa16..fdb9a392026 100644
--- a/chromium/ui/base/ime/mock_ime_input_context_handler.cc
+++ b/chromium/ui/base/ime/mock_ime_input_context_handler.cc
@@ -32,6 +32,15 @@ void MockIMEInputContextHandler::UpdateCompositionText(
last_update_composition_arg_.is_visible = visible;
}
+#if defined(OS_CHROMEOS)
+bool MockIMEInputContextHandler::SetCompositionRange(
+ uint32_t before,
+ uint32_t after,
+ const std::vector<ui::ImeTextSpan>& text_spans) {
+ return false;
+}
+#endif
+
void MockIMEInputContextHandler::DeleteSurroundingText(int32_t offset,
uint32_t length) {
++delete_surrounding_text_call_count_;
diff --git a/chromium/ui/base/ime/mock_ime_input_context_handler.h b/chromium/ui/base/ime/mock_ime_input_context_handler.h
index 2d0df397974..9e66f32375d 100644
--- a/chromium/ui/base/ime/mock_ime_input_context_handler.h
+++ b/chromium/ui/base/ime/mock_ime_input_context_handler.h
@@ -36,6 +36,14 @@ class COMPONENT_EXPORT(UI_BASE_IME) MockIMEInputContextHandler
void UpdateCompositionText(const CompositionText& text,
uint32_t cursor_pos,
bool visible) override;
+
+#if defined(OS_CHROMEOS)
+ bool SetCompositionRange(
+ uint32_t before,
+ uint32_t after,
+ const std::vector<ui::ImeTextSpan>& text_spans) override;
+#endif
+
void DeleteSurroundingText(int32_t offset, uint32_t length) override;
SurroundingTextInfo GetSurroundingTextInfo() override;
void SendKeyEvent(KeyEvent* event) override;
diff --git a/chromium/ui/base/ime/mojo/BUILD.gn b/chromium/ui/base/ime/mojo/BUILD.gn
index 003b9776d81..bdb71a25691 100644
--- a/chromium/ui/base/ime/mojo/BUILD.gn
+++ b/chromium/ui/base/ime/mojo/BUILD.gn
@@ -6,8 +6,6 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojo") {
sources = [
- "ime.mojom",
- "ime_engine_factory_registry.mojom",
"ime_types.mojom",
]
diff --git a/chromium/ui/base/ime/mojo/ime.mojom b/chromium/ui/base/ime/mojo/ime.mojom
deleted file mode 100644
index d28cbf8dd71..00000000000
--- a/chromium/ui/base/ime/mojo/ime.mojom
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module ime.mojom;
-
-import "ui/base/ime/mojo/ime_types.mojom";
-import "ui/events/mojo/event.mojom";
-import "ui/gfx/geometry/mojo/geometry.mojom";
-
-// The data of the text input field for the IME.
-// It is passed from the client to the IME through StartInput method.
-struct EditorInfo {
- ui.mojom.TextInputType type;
- ui.mojom.TextInputMode mode;
- int32 flags;
- ui.mojom.FocusReason focus_reason;
- bool should_do_learning;
-};
-
-// Represents the IME (a.k.a. input-method engine).
-// The client uses this interface to communicate with the IME.
-interface ImeEngine {
- // This method is called when the app starts to receive text (e.g. an input
- // field is focused) and it is ready for this ImeEngine to process received
- // events and send result text back to the app.
- StartInput(EditorInfo info);
-
- // This method is called when the app stops to receive text (e.g. the focused
- // input field lost the focus). The ImeEngine usually handles this to reset
- // its internal states.
- FinishInput();
-
- // This method is called when the app wants to cancel the ongoing composition.
- CancelInput();
-
- // Dispatches a key event to this ImeEngine, which will respond with a boolean
- // value of true means the key event is handled and false unhandled.
- // If the key event is handled, the app should NOT apply its default behaviors
- // (e.g. shortcuts, generate text, etc.).
- ProcessKeyEvent(ui.mojom.Event key_event) => (bool handled);
-
- // Called when a new surrounding text is set by the app.
- // The |text| is the surrounding text and |cursor| is 0 based index of cursor
- // position in |text|. If there is selection range, |anchor| represents
- // opposite index from |cursor|. Otherwise |anchor| is equal to |cursor|.
- // If not all surrounding text is given |offset| indicates the starting
- // offset of |text|.
- UpdateSurroundingInfo(string text, int32 cursor, int32 anchor, int32 offset);
-
- // Called when the composition bounds in screen changes.
- // The composition bounds can be changed when ImeEngine changes composition or
- // the text field's coordinates is changed by the app.
- UpdateCompositionBounds(array<gfx.mojom.Rect> bounds);
-};
-
-// Used by |ImeEngine| to communicate state back to the client.
-// The app should generate the corresponding results to the input field:
-// - immediately if didn't dispatch a key event to IME;
-// (e.g. by IME's on-screen keyboard)
-// - later after the IME responds the |ProcessKeyEvent| with the result;
-interface ImeEngineClient {
- // Called when the IME wants to insert the |text| to the input field.
- CommitText(string text);
-
- // Called when the IME wants to generate/update the composition text to the
- // input field.
- UpdateCompositionText(ui.mojom.CompositionText composition_text,
- uint32 cursor_pos,
- bool visible);
-
- // Called when the IME wants to remove a piece of text in the input field.
- DeleteSurroundingText(int32 offset, uint32 length);
-
- // Called when the IME wants to silumate a physical key event to the app.
- // Usually this is for on-screen keyboard support (e.g. simulate Enter key).
- SendKeyEvent(ui.mojom.Event key_event);
-
- // Called when the ImeEngine is deactivated and this client should reconnect
- // for the new active ImeEngine.
- Reconnect();
-};
-
-// Implemented by the IME.
-// An IME should implement both ImeEngine and ImeEngineFactory interfaces.
-// The |ImeEngineFactoryRegistry| calls |CreateEngine| to make the ImeEngine
-// and ImeEngineClient can hold each other.
-interface ImeEngineFactory {
- CreateEngine(ImeEngine& engine_request, ImeEngineClient client);
-};
diff --git a/chromium/ui/base/ime/mojo/ime_engine_factory_registry.mojom b/chromium/ui/base/ime/mojo/ime_engine_factory_registry.mojom
deleted file mode 100644
index c947a6fae5c..00000000000
--- a/chromium/ui/base/ime/mojo/ime_engine_factory_registry.mojom
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module ime.mojom;
-
-import "ui/base/ime/mojo/ime.mojom";
-
-// Implemented by IMM service and used by ImeEngine to set the active
-// ImeEngineFactory, through which the client can connect to the ImeEngine.
-interface ImeEngineFactoryRegistry {
- ActivateFactory(ImeEngineFactory factory);
-};
diff --git a/chromium/ui/base/ime/mojo/ime_struct_traits_unittest.cc b/chromium/ui/base/ime/mojo/ime_struct_traits_unittest.cc
index 86f6d561751..34e14deaf83 100644
--- a/chromium/ui/base/ime/mojo/ime_struct_traits_unittest.cc
+++ b/chromium/ui/base/ime/mojo/ime_struct_traits_unittest.cc
@@ -99,7 +99,8 @@ TEST_F(IMEStructTraitsTest, TextInputType) {
TEST_F(IMEStructTraitsTest, CompositionText) {
ui::CompositionText input;
input.text = base::UTF8ToUTF16("abcdefghij");
- ui::ImeTextSpan ime_text_span_1(0, 2, ui::ImeTextSpan::Thickness::kThin);
+ ui::ImeTextSpan ime_text_span_1(ui::ImeTextSpan::Type::kComposition, 0, 2,
+ ui::ImeTextSpan::Thickness::kThin);
ime_text_span_1.underline_color = SK_ColorGRAY;
input.ime_text_spans.push_back(ime_text_span_1);
ui::ImeTextSpan ime_text_span_2(ui::ImeTextSpan::Type::kComposition, 3, 6,
diff --git a/chromium/ui/base/ime/text_input_action.h b/chromium/ui/base/ime/text_input_action.h
new file mode 100644
index 00000000000..742a57ce4a7
--- /dev/null
+++ b/chromium/ui/base/ime/text_input_action.h
@@ -0,0 +1,29 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_IME_TEXT_INPUT_ACTION_H_
+#define UI_BASE_IME_TEXT_INPUT_ACTION_H_
+
+namespace ui {
+
+// This mode corresponds to enterkeyhint
+// https://html.spec.whatwg.org/multipage/interaction.html#input-modalities:-the-enterkeyhint-attribute
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.ui.base.ime
+enum class TextInputAction {
+ kDefault,
+ kEnter,
+ kDone,
+ kGo,
+ kNext,
+ kPrevious,
+ kSearch,
+ kSend,
+ kMaxValue = kSend,
+};
+
+} // namespace ui
+
+#endif // UI_BASE_IME_TEXT_INPUT_ACTION_H_
diff --git a/chromium/ui/base/ime/text_input_client.h b/chromium/ui/base/ime/text_input_client.h
index 680be4e6b88..a1e54e19e23 100644
--- a/chromium/ui/base/ime/text_input_client.h
+++ b/chromium/ui/base/ime/text_input_client.h
@@ -204,13 +204,16 @@ class COMPONENT_EXPORT(UI_BASE_IME) TextInputClient {
// fields that are considered 'private' (e.g. in incognito tabs).
virtual bool ShouldDoLearning() = 0;
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
// Start composition over a given UTF-16 code range from existing text. This
// should only be used for composition scenario when IME wants to start
- // composition on existing text.
- virtual void SetCompositionFromExistingText(
+ // composition on existing text. Returns whether the operation was successful.
+ virtual bool SetCompositionFromExistingText(
const gfx::Range& range,
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) = 0;
+#endif
+
+#if defined(OS_WIN)
// Notifies accessibility about active composition. This API is currently
// only defined for TSF which is available only on Windows
// https://docs.microsoft.com/en-us/windows/desktop/api/UIAutomationCore/
diff --git a/chromium/ui/base/ime/win/BUILD.gn b/chromium/ui/base/ime/win/BUILD.gn
index e2416035045..34333cf6523 100644
--- a/chromium/ui/base/ime/win/BUILD.gn
+++ b/chromium/ui/base/ime/win/BUILD.gn
@@ -44,6 +44,8 @@ jumbo_component("win") {
libs = [ "imm32.lib" ]
+ ldflags = [ "/DELAYLOAD:imm32.dll" ]
+
jumbo_excluded_sources = [
# tsf_text_store.cc needs INITGUID to be defined before
# including any header to properly generate GUID objects. That
diff --git a/chromium/ui/base/ime/win/imm32_manager.cc b/chromium/ui/base/ime/win/imm32_manager.cc
index 7fbaf37a7c7..75018d3fffa 100644
--- a/chromium/ui/base/ime/win/imm32_manager.cc
+++ b/chromium/ui/base/ime/win/imm32_manager.cc
@@ -489,4 +489,8 @@ void IMM32Manager::ConvertInputModeToImmFlags(TextInputMode input_mode,
*new_conversion_mode = initial_conversion_mode;
}
+bool IMM32Manager::IsImm32ImeActive() {
+ return ::ImmGetIMEFileName(::GetKeyboardLayout(0), nullptr, 0) > 0;
+}
+
} // namespace ui
diff --git a/chromium/ui/base/ime/win/imm32_manager.h b/chromium/ui/base/ime/win/imm32_manager.h
index 958b3c1965f..7edb11e515e 100644
--- a/chromium/ui/base/ime/win/imm32_manager.h
+++ b/chromium/ui/base/ime/win/imm32_manager.h
@@ -244,6 +244,8 @@ class COMPONENT_EXPORT(UI_BASE_IME_WIN) IMM32Manager {
BOOL* open,
DWORD* new_conversion_mode);
+ // Return true if current active IME is IMM32-bassed.
+ bool IsImm32ImeActive();
protected:
// Retrieves the composition information.
diff --git a/chromium/ui/base/ime/win/input_method_win_base.cc b/chromium/ui/base/ime/win/input_method_win_base.cc
index 7de0c932179..2627f1eae90 100644
--- a/chromium/ui/base/ime/win/input_method_win_base.cc
+++ b/chromium/ui/base/ime/win/input_method_win_base.cc
@@ -38,10 +38,10 @@ constexpr size_t kExtraNumberOfChars = 20;
std::unique_ptr<InputMethodKeyboardController> CreateKeyboardController(
HWND toplevel_window_handle) {
if (base::FeatureList::IsEnabled(features::kInputPaneOnScreenKeyboard) &&
- base::win::GetVersion() >= base::win::VERSION_WIN10_RS4) {
+ base::win::GetVersion() >= base::win::Version::WIN10_RS4) {
return std::make_unique<OnScreenKeyboardDisplayManagerInputPane>(
toplevel_window_handle);
- } else if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+ } else if (base::win::GetVersion() >= base::win::Version::WIN8) {
return std::make_unique<OnScreenKeyboardDisplayManagerTabTip>(
toplevel_window_handle);
}
@@ -245,8 +245,7 @@ ui::EventDispatchDetails InputMethodWinBase::DispatchKeyEvent(
// 1) |char_msgs| is empty when the event is non-character key.
// 2) |char_msgs|.size() == 1 when the event is character key and the WM_CHAR
// messages have been combined in the event processing flow.
- if (char_msgs.size() <= 1 && GetEngine() &&
- GetEngine()->IsInterestedInKeyEvent()) {
+ if (char_msgs.size() <= 1 && GetEngine()) {
ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback =
base::BindOnce(&InputMethodWinBase::ProcessKeyEventDone,
weak_ptr_factory_.GetWeakPtr(),
diff --git a/chromium/ui/base/ime/win/input_method_win_imm32.cc b/chromium/ui/base/ime/win/input_method_win_imm32.cc
index 15030eb55a3..2bd1043590f 100644
--- a/chromium/ui/base/ime/win/input_method_win_imm32.cc
+++ b/chromium/ui/base/ime/win/input_method_win_imm32.cc
@@ -11,6 +11,7 @@
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/metrics/histogram_macros.h"
#include "ui/base/ime/ime_bridge.h"
#include "ui/base/ime/ime_engine_handler_interface.h"
#include "ui/base/ime/text_input_client.h"
@@ -212,6 +213,8 @@ LRESULT InputMethodWinImm32::OnImeStartComposition(HWND window_handle,
composing_window_handle_ = window_handle;
imm32_manager_.CreateImeWindow(window_handle);
imm32_manager_.ResetComposition(window_handle);
+ UMA_HISTOGRAM_BOOLEAN("InputMethod.CompositionWithImm32BasedIme",
+ imm32_manager_.IsImm32ImeActive());
return 0;
}
@@ -338,9 +341,7 @@ void InputMethodWinImm32::UpdateIMEState() {
// We disable input method in password field.
const HWND window_handle = toplevel_window_handle_;
const TextInputType text_input_type =
- (GetEngine() && GetEngine()->IsInterestedInKeyEvent())
- ? TEXT_INPUT_TYPE_NONE
- : GetTextInputType();
+ GetEngine() ? TEXT_INPUT_TYPE_NONE : GetTextInputType();
const TextInputMode text_input_mode = GetTextInputMode();
switch (text_input_type) {
case ui::TEXT_INPUT_TYPE_NONE:
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
index cd84d61f0b9..b114660da81 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
@@ -182,7 +182,7 @@ OnScreenKeyboardDisplayManagerInputPane::
main_task_runner_)),
is_keyboard_visible_(false),
weak_factory_(this) {
- DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN10_RS1);
+ DCHECK_GE(base::win::GetVersion(), base::win::Version::WIN10_RS1);
DCHECK(main_task_runner_->BelongsToCurrentThread());
// We post the initiation of |virtual_keyboard_input_pane_| to the background
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc
index 97a295875a9..60fca60db2b 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_tab_tip.cc
@@ -254,7 +254,7 @@ void OnScreenKeyboardDetector::HandleKeyboardHidden() {
OnScreenKeyboardDisplayManagerTabTip::OnScreenKeyboardDisplayManagerTabTip(
HWND hwnd)
: hwnd_(hwnd) {
- DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN8);
+ DCHECK_GE(base::win::GetVersion(), base::win::Version::WIN8);
}
OnScreenKeyboardDisplayManagerTabTip::~OnScreenKeyboardDisplayManagerTabTip() {}
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc
index 6cc53194ba0..3887fb1512f 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc
@@ -139,7 +139,7 @@ class OnScreenKeyboardTest : public ::testing::Test {
// from the registry.
TEST_F(OnScreenKeyboardTest, OSKPath) {
// The on screen keyboard is only available on Windows 8+.
- if (base::win::GetVersion() < base::win::VERSION_WIN8)
+ if (base::win::GetVersion() < base::win::Version::WIN8)
return;
std::unique_ptr<OnScreenKeyboardDisplayManagerTabTip>
@@ -164,7 +164,7 @@ TEST_F(OnScreenKeyboardTest, OSKPath) {
TEST_F(OnScreenKeyboardTest, InputPane) {
// InputPane is supported only on RS1 and later.
- if (base::win::GetVersion() < base::win::VERSION_WIN10_RS1)
+ if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
return;
std::unique_ptr<OnScreenKeyboardDisplayManagerInputPane>
keyboard_display_manager = CreateInputPane();
diff --git a/chromium/ui/base/ime/win/tsf_input_scope.cc b/chromium/ui/base/ime/win/tsf_input_scope.cc
index 2c0db97324f..aac64cb44f1 100644
--- a/chromium/ui/base/ime/win/tsf_input_scope.cc
+++ b/chromium/ui/base/ime/win/tsf_input_scope.cc
@@ -188,8 +188,18 @@ std::vector<InputScope> GetInputScopes(TextInputType text_input_type,
}
ITfInputScope* CreateInputScope(TextInputType text_input_type,
- TextInputMode text_input_mode) {
- return new TSFInputScope(GetInputScopes(text_input_type, text_input_mode));
+ TextInputMode text_input_mode,
+ bool should_do_learning) {
+ std::vector<InputScope> input_scopes;
+ // Should set input scope to IS_PRIVATE if we are in "incognito" or "guest"
+ // mode. Note that the IS_PRIVATE input scope is only support from WIN10.
+ if (!should_do_learning &&
+ (base::win::GetVersion() >= base::win::Version::WIN10)) {
+ input_scopes.push_back(IS_PRIVATE);
+ } else {
+ input_scopes = GetInputScopes(text_input_type, text_input_mode);
+ }
+ return new TSFInputScope(input_scopes);
}
void SetInputScopeForTsfUnawareWindow(HWND window_handle,
diff --git a/chromium/ui/base/ime/win/tsf_input_scope.h b/chromium/ui/base/ime/win/tsf_input_scope.h
index a895cb13b74..3a62423c118 100644
--- a/chromium/ui/base/ime/win/tsf_input_scope.h
+++ b/chromium/ui/base/ime/win/tsf_input_scope.h
@@ -35,7 +35,8 @@ std::vector<InputScope> GetInputScopes(TextInputType text_input_type,
// reference count.
COMPONENT_EXPORT(UI_BASE_IME_WIN)
ITfInputScope* CreateInputScope(TextInputType text_input_type,
- TextInputMode text_input_mode);
+ TextInputMode text_input_mode,
+ bool should_do_learning);
// A wrapper of the SetInputScopes API exported by msctf.dll.
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms629026.aspx
diff --git a/chromium/ui/base/ime/win/tsf_input_scope_unittest.cc b/chromium/ui/base/ime/win/tsf_input_scope_unittest.cc
index 9c10d47122b..890fee0255f 100644
--- a/chromium/ui/base/ime/win/tsf_input_scope_unittest.cc
+++ b/chromium/ui/base/ime/win/tsf_input_scope_unittest.cc
@@ -6,7 +6,9 @@
#include <InputScope.h>
#include <stddef.h>
+#include <wrl/client.h>
+#include "base/win/windows_version.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ui {
@@ -103,5 +105,54 @@ INSTANTIATE_TEST_SUITE_P(,
TSFInputScopeTest,
::testing::ValuesIn(kGetInputScopesTestCases));
+struct CreateInputScopesTestCase {
+ TextInputType input_type;
+ TextInputMode input_mode;
+ bool should_do_learning;
+ UINT expected_size;
+ InputScope expected_input_scopes[2];
+};
+class TSFCreateInputScopeTest
+ : public testing::TestWithParam<CreateInputScopesTestCase> {};
+const CreateInputScopesTestCase kCreateInputScopesTestCases[] = {
+ // Test cases of TextInputType.
+ {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_DEFAULT, true, 1, {IS_DEFAULT}},
+ {TEXT_INPUT_TYPE_TEXT, TEXT_INPUT_MODE_DEFAULT, false, 1, {IS_PRIVATE}},
+ {TEXT_INPUT_TYPE_PASSWORD, TEXT_INPUT_MODE_DEFAULT, true, 1, {IS_PASSWORD}},
+ {TEXT_INPUT_TYPE_PASSWORD, TEXT_INPUT_MODE_DEFAULT, false, 1, {IS_PRIVATE}},
+ // Test cases of TextInputMode.
+ {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_DEFAULT, true, 1, {IS_DEFAULT}},
+ {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_URL, false, 1, {IS_PRIVATE}},
+ {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_SEARCH, true, 1, {IS_SEARCH}},
+ {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_SEARCH, false, 1, {IS_PRIVATE}},
+ // Mixed test cases.
+ {TEXT_INPUT_TYPE_NUMBER,
+ TEXT_INPUT_MODE_NUMERIC,
+ true,
+ 2,
+ {IS_NUMBER, IS_DIGITS}},
+ {TEXT_INPUT_TYPE_NUMBER, TEXT_INPUT_MODE_NUMERIC, false, 1, {IS_PRIVATE}},
+};
+TEST_P(TSFCreateInputScopeTest, CreateInputScopes) {
+ if (base::win::GetVersion() < base::win::Version::WIN10)
+ return;
+ const CreateInputScopesTestCase& test_case = GetParam();
+ Microsoft::WRL::ComPtr<ITfInputScope> input_scope =
+ tsf_inputscope::CreateInputScope(test_case.input_type,
+ test_case.input_mode,
+ test_case.should_do_learning);
+ UINT c_input_scopes = 0;
+ InputScope* input_scopes = nullptr;
+ HRESULT result = input_scope->GetInputScopes(&input_scopes, &c_input_scopes);
+ EXPECT_EQ(S_OK, result);
+ EXPECT_EQ(test_case.expected_size, c_input_scopes);
+ for (size_t i = 0; i < test_case.expected_size; ++i)
+ EXPECT_EQ(test_case.expected_input_scopes[i], input_scopes[i]);
+ CoTaskMemFree(input_scopes);
+}
+INSTANTIATE_TEST_SUITE_P(,
+ TSFCreateInputScopeTest,
+ ::testing::ValuesIn(kCreateInputScopesTestCases));
+
} // namespace
} // namespace ui
diff --git a/chromium/ui/base/ime/win/tsf_text_store.cc b/chromium/ui/base/ime/win/tsf_text_store.cc
index b82b3e2e93c..5968d0957d0 100644
--- a/chromium/ui/base/ime/win/tsf_text_store.cc
+++ b/chromium/ui/base/ime/win/tsf_text_store.cc
@@ -260,10 +260,12 @@ STDMETHODIMP TSFTextStore::GetText(LONG acp_start,
text_buffer[i] = result[i];
}
- if (run_info_buffer_size) {
+ if (*text_buffer_copied > 0 && 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;
+ } else {
+ *run_info_buffer_copied = 0;
}
*next_acp = acp_end;
@@ -311,7 +313,10 @@ STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie,
tmp_rect.set_width(0);
result_rect = gfx::Rect(tmp_rect);
} else {
- return TS_E_NOLAYOUT;
+ // PPAPI flash does not support GetCompositionCharacterBounds. We need
+ // to call GetCaretBounds instead to get correct text bounds info.
+ // TODO(https://crbug.com/963706): Remove this hack.
+ result_rect = gfx::Rect(text_input_client_->GetCaretBounds());
}
} else if (text_input_client_->GetCompositionCharacterBounds(
start_pos - 1, &tmp_rect)) {
@@ -341,17 +346,20 @@ STDMETHODIMP TSFTextStore::GetTextExt(TsViewCookie view_cookie,
// first character bounds instead of returning TS_E_NOLAYOUT.
}
} else {
- return TS_E_NOLAYOUT;
+ // PPAPI flash does not support GetCompositionCharacterBounds. We need
+ // to call GetCaretBounds instead to get correct text bounds info.
+ // TODO(https://crbug.com/963706): Remove this hack.
+ if (start_pos == 0) {
+ result_rect = gfx::Rect(text_input_client_->GetCaretBounds());
+ } else {
+ return 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_rect = gfx::Rect(text_input_client_->GetCaretBounds());
- } else {
- return TS_E_NOLAYOUT;
- }
+ // Caret Bounds may be incorrect if focus is in flash control and
+ // |start_pos| is not equal to |end_pos|. In this case, it's better to
+ // return previous caret rectangle instead.
+ result_rect = gfx::Rect(text_input_client_->GetCaretBounds());
}
}
*rect = display::win::ScreenWin::DIPToScreenRect(window_handle_, result_rect)
@@ -672,7 +680,8 @@ STDMETHODIMP TSFTextStore::RetrieveRequestedAttrs(
attribute_buffer[0].varValue.vt = VT_UNKNOWN;
attribute_buffer[0].varValue.punkVal =
tsf_inputscope::CreateInputScope(text_input_client_->GetTextInputType(),
- text_input_client_->GetTextInputMode());
+ text_input_client_->GetTextInputMode(),
+ text_input_client_->ShouldDoLearning());
attribute_buffer[0].varValue.punkVal->AddRef();
*attribute_buffer_copied = 1;
return S_OK;
diff --git a/chromium/ui/base/ime/win/tsf_text_store_unittest.cc b/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
index 8ff63eecb50..927a00218da 100644
--- a/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
+++ b/chromium/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -67,7 +67,7 @@ class MockTextInputClient : public TextInputClient {
MOCK_METHOD1(SetTextEditCommandForNextKeyEvent, void(TextEditCommand));
MOCK_CONST_METHOD0(GetClientSourceForMetrics, ukm::SourceId());
MOCK_METHOD2(SetCompositionFromExistingText,
- void(const gfx::Range&, const std::vector<ui::ImeTextSpan>&));
+ bool(const gfx::Range&, const std::vector<ui::ImeTextSpan>&));
MOCK_METHOD3(SetActiveCompositionForAccessibility,
void(const gfx::Range&, const base::string16&, bool));
};
@@ -275,10 +275,14 @@ class TSFTextStoreTestCallback {
ASSERT_EQ(expected_string.size(), text_buffer_copied);
EXPECT_EQ(expected_string,
base::string16(buffer, buffer + text_buffer_copied));
- EXPECT_EQ(1u, run_info_buffer_copied);
- EXPECT_EQ(expected_string.size(), run_info.uCount);
- EXPECT_EQ(TS_RT_PLAIN, run_info.type);
- EXPECT_EQ(expected_next_acp, next_acp);
+ if (text_buffer_copied > 0) {
+ EXPECT_EQ(1u, run_info_buffer_copied);
+ EXPECT_EQ(expected_string.size(), run_info.uCount);
+ EXPECT_EQ(TS_RT_PLAIN, run_info.type);
+ EXPECT_EQ(expected_next_acp, next_acp);
+ } else {
+ EXPECT_EQ(0u, run_info_buffer_copied);
+ }
}
void GetTextErrorTest(LONG acp_start, LONG acp_end, HRESULT error_code) {
@@ -1344,8 +1348,10 @@ class GetTextExtTestCallback : public TSFTextStoreTestCallback {
// GetCompositionCharacterBounds.
SetInternalState(L"a", 0, 0, 1);
layout_prepared_character_num_ = 0;
- has_composition_text_ = false;
GetTextExtTest(view_cookie, 0, 1, 1, 2, 4, 6);
+ SetInternalState(L"abc", 0, 0, 3);
+ GetTextExtNoLayoutTest(view_cookie, 2, 3);
+
return S_OK;
}
diff --git a/chromium/ui/base/material_design/material_design_controller.cc b/chromium/ui/base/material_design/material_design_controller.cc
index bf0caa69189..97e42d5478b 100644
--- a/chromium/ui/base/material_design/material_design_controller.cc
+++ b/chromium/ui/base/material_design/material_design_controller.cc
@@ -69,7 +69,7 @@ void MaterialDesignController::Initialize() {
// TabletModeClient's default state is in non-tablet mode.
automatic_touch_ui_ = true;
#elif defined(OS_WIN)
- if (base::win::GetVersion() >= base::win::VERSION_WIN10) {
+ if (base::win::GetVersion() >= base::win::Version::WIN10) {
// Win 10+ uses dynamic mode by default and checks the current tablet mode
// state to determine whether to start in touch mode.
automatic_touch_ui_ = true;
diff --git a/chromium/ui/base/models/combobox_model_observer.h b/chromium/ui/base/models/combobox_model_observer.h
index f8e281e1842..42d15bdc0e0 100644
--- a/chromium/ui/base/models/combobox_model_observer.h
+++ b/chromium/ui/base/models/combobox_model_observer.h
@@ -5,6 +5,7 @@
#ifndef UI_BASE_MODELS_COMBOBOX_MODEL_OBSERVER_H_
#define UI_BASE_MODELS_COMBOBOX_MODEL_OBSERVER_H_
+#include "base/observer_list_types.h"
#include "ui/base/ui_base_export.h"
namespace ui {
@@ -12,14 +13,14 @@ namespace ui {
class ComboboxModel;
// Observer for the ComboboxModel.
-class UI_BASE_EXPORT ComboboxModelObserver {
+class UI_BASE_EXPORT ComboboxModelObserver : public base::CheckedObserver {
public:
// Invoked when |model| has changed in some way. The observer should assume
// everything changed.
virtual void OnComboboxModelChanged(ComboboxModel* model) = 0;
protected:
- virtual ~ComboboxModelObserver() {}
+ ~ComboboxModelObserver() override = default;
};
} // namespace ui
diff --git a/chromium/ui/base/models/simple_menu_model.cc b/chromium/ui/base/models/simple_menu_model.cc
index 317563bbb9d..709c5844430 100644
--- a/chromium/ui/base/models/simple_menu_model.cc
+++ b/chromium/ui/base/models/simple_menu_model.cc
@@ -122,11 +122,10 @@ void SimpleMenuModel::AddRadioItemWithStringId(int command_id, int string_id,
AddRadioItem(command_id, l10n_util::GetStringUTF16(string_id), group_id);
}
-void SimpleMenuModel::AddHighlightedItemWithStringIdAndIcon(
- int command_id,
- int string_id,
- const gfx::ImageSkia& icon) {
- Item item(command_id, TYPE_HIGHLIGHTED, l10n_util::GetStringUTF16(string_id));
+void SimpleMenuModel::AddHighlightedItemWithIcon(int command_id,
+ const base::string16& label,
+ const gfx::ImageSkia& icon) {
+ Item item(command_id, TYPE_HIGHLIGHTED, label);
item.icon = gfx::Image(icon);
AppendItem(std::move(item));
}
@@ -171,6 +170,17 @@ void SimpleMenuModel::AddSubMenuWithStringId(int command_id,
AddSubMenu(command_id, l10n_util::GetStringUTF16(string_id), model);
}
+void SimpleMenuModel::AddSubMenuWithStringIdAndIcon(
+ int command_id,
+ int string_id,
+ MenuModel* model,
+ const gfx::ImageSkia& icon) {
+ Item item(command_id, TYPE_SUBMENU, l10n_util::GetStringUTF16(string_id));
+ item.submenu = model;
+ item.icon = gfx::Image(icon);
+ AppendItem(std::move(item));
+}
+
void SimpleMenuModel::AddActionableSubMenu(int command_id,
const base::string16& label,
MenuModel* model) {
diff --git a/chromium/ui/base/models/simple_menu_model.h b/chromium/ui/base/models/simple_menu_model.h
index e034b8153bb..7381e707c93 100644
--- a/chromium/ui/base/models/simple_menu_model.h
+++ b/chromium/ui/base/models/simple_menu_model.h
@@ -90,9 +90,9 @@ class UI_BASE_EXPORT SimpleMenuModel : public MenuModel {
void AddCheckItemWithStringId(int command_id, int string_id);
void AddRadioItem(int command_id, const base::string16& label, int group_id);
void AddRadioItemWithStringId(int command_id, int string_id, int group_id);
- void AddHighlightedItemWithStringIdAndIcon(int command_id,
- int string_id,
- const gfx::ImageSkia& icon);
+ void AddHighlightedItemWithIcon(int command_id,
+ const base::string16& label,
+ const gfx::ImageSkia& icon);
// Adds a separator of the specified type to the model.
// - Adding a separator after another separator is always invalid if they
@@ -108,6 +108,10 @@ class UI_BASE_EXPORT SimpleMenuModel : public MenuModel {
const base::string16& label,
MenuModel* model);
void AddSubMenuWithStringId(int command_id, int string_id, MenuModel* model);
+ void AddSubMenuWithStringIdAndIcon(int command_id,
+ int string_id,
+ MenuModel* model,
+ const gfx::ImageSkia& icon);
void AddActionableSubMenu(int command_id,
const base::string16& label,
MenuModel* model);
diff --git a/chromium/ui/base/models/tree_model.h b/chromium/ui/base/models/tree_model.h
index 7be9d24598b..73ae4f0bf65 100644
--- a/chromium/ui/base/models/tree_model.h
+++ b/chromium/ui/base/models/tree_model.h
@@ -63,21 +63,20 @@ class UI_BASE_EXPORT TreeModelObserver {
// hierarchy and observer notification. See tree_node_model.h.
class UI_BASE_EXPORT TreeModel {
public:
+ using Nodes = std::vector<TreeModelNode*>;
+
// Returns the root of the tree. This may or may not be shown in the tree,
// see SetRootShown for details.
virtual TreeModelNode* GetRoot() = 0;
- // Returns the number of children in |parent|.
- virtual int GetChildCount(TreeModelNode* parent) = 0;
-
- // Returns the child node of |parent| at |index|.
- virtual TreeModelNode* GetChild(TreeModelNode* parent, int index) = 0;
+ // Returns the children of |parent|.
+ virtual Nodes GetChildren(const TreeModelNode* parent) const = 0;
// Returns the index of |child| in |parent|.
- virtual int GetIndexOf(TreeModelNode* parent, TreeModelNode* child) = 0;
+ virtual int GetIndexOf(TreeModelNode* parent, TreeModelNode* child) const = 0;
// Returns the parent of |node|, or NULL if |node| is the root.
- virtual TreeModelNode* GetParent(TreeModelNode* node) = 0;
+ virtual TreeModelNode* GetParent(TreeModelNode* node) const = 0;
// Adds an observer of the model.
virtual void AddObserver(TreeModelObserver* observer) = 0;
diff --git a/chromium/ui/base/models/tree_node_iterator.h b/chromium/ui/base/models/tree_node_iterator.h
index 7d53b2dbbe4..755a8a39c47 100644
--- a/chromium/ui/base/models/tree_node_iterator.h
+++ b/chromium/ui/base/models/tree_node_iterator.h
@@ -45,7 +45,7 @@ class TreeNodeIterator {
}
explicit TreeNodeIterator(NodeType* node) {
- if (!node->empty())
+ if (!node->children().empty())
positions_.push(Position<NodeType>(node, 0));
}
diff --git a/chromium/ui/base/models/tree_node_model.h b/chromium/ui/base/models/tree_node_model.h
index 70b8ef1ce5c..fac7dfbc517 100644
--- a/chromium/ui/base/models/tree_node_model.h
+++ b/chromium/ui/base/models/tree_node_model.h
@@ -17,6 +17,10 @@
#include "base/strings/string16.h"
#include "ui/base/models/tree_model.h"
+namespace bookmarks {
+class BookmarkModel;
+}
+
namespace ui {
// TreeNodeModel and TreeNodes provide an implementation of TreeModel around
@@ -72,6 +76,8 @@ namespace ui {
template <class NodeType>
class TreeNode : public TreeModelNode {
public:
+ using TreeNodes = std::vector<std::unique_ptr<NodeType>>;
+
TreeNode() : parent_(nullptr) {}
explicit TreeNode(const base::string16& title)
@@ -84,7 +90,7 @@ class TreeNode : public TreeModelNode {
NodeType* Add(std::unique_ptr<NodeType> node, int index) {
DCHECK(node);
DCHECK_GE(index, 0);
- DCHECK_LE(index, child_count());
+ DCHECK_LE(size_t{index}, children_.size());
DCHECK(!node->parent_);
node->parent_ = static_cast<NodeType*>(this);
NodeType* node_ptr = node.get();
@@ -94,7 +100,8 @@ class TreeNode : public TreeModelNode {
// Removes the node at the given index. Returns the removed node.
std::unique_ptr<NodeType> Remove(int index) {
- DCHECK(index >= 0 && index < child_count());
+ DCHECK_GE(index, 0);
+ DCHECK_LT(size_t{index}, children_.size());
children_[index]->parent_ = nullptr;
std::unique_ptr<NodeType> ptr = std::move(children_[index]);
children_.erase(children_.begin() + index);
@@ -104,12 +111,9 @@ class TreeNode : public TreeModelNode {
// Removes the given node. Prefer to remove by index if you know it to avoid
// the search for the node to remove.
std::unique_ptr<NodeType> Remove(NodeType* node) {
- auto i = std::find_if(children_.begin(), children_.end(),
- [node](const std::unique_ptr<NodeType>& ptr) {
- return ptr.get() == node;
- });
- DCHECK(i != children_.end());
- return Remove(i - children_.begin());
+ int i = GetIndexOf(node);
+ DCHECK_NE(-1, i);
+ return Remove(i);
}
// Removes all the children from this node.
@@ -122,12 +126,12 @@ class TreeNode : public TreeModelNode {
// Returns true if this is the root node.
bool is_root() const { return parent_ == nullptr; }
+ const TreeNodes& children() const { return children_; }
+
// Returns the number of children.
+ // TODO(https://crbug.com/956419): Remove; use children().size().
int child_count() const { return static_cast<int>(children_.size()); }
- // Returns true if this node has no children.
- bool empty() const { return children_.empty(); }
-
// Returns the number of all nodes in the subtree rooted at this node,
// including this node.
int GetTotalNodeCount() const {
@@ -138,9 +142,10 @@ class TreeNode : public TreeModelNode {
}
// Returns the node at |index|.
+ // TODO(https://crbug.com/956419): Remove; use children()[index].
const NodeType* GetChild(int index) const {
DCHECK_GE(index, 0);
- DCHECK_LT(index, child_count());
+ DCHECK_LT(size_t{index}, children_.size());
return children_[index].get();
}
NodeType* GetChild(int index) {
@@ -174,10 +179,10 @@ class TreeNode : public TreeModelNode {
return parent_ ? parent_->HasAncestor(ancestor) : false;
}
- protected:
- std::vector<std::unique_ptr<NodeType>>& children() { return children_; }
-
private:
+ // TODO(https://crbug.com/956314): Remove this.
+ friend class bookmarks::BookmarkModel;
+
// Title displayed in the tree.
base::string16 title_;
@@ -185,7 +190,7 @@ class TreeNode : public TreeModelNode {
NodeType* parent_;
// This node's children.
- typename std::vector<std::unique_ptr<NodeType>> children_;
+ TreeNodes children_;
DISALLOW_COPY_AND_ASSIGN(TreeNode);
};
@@ -226,9 +231,12 @@ class TreeNodeModel : public TreeModel {
: root_(std::move(root)) {}
virtual ~TreeNodeModel() override {}
- NodeType* AsNode(TreeModelNode* model_node) {
+ static NodeType* AsNode(TreeModelNode* model_node) {
return static_cast<NodeType*>(model_node);
}
+ static const NodeType* AsNode(const TreeModelNode* model_node) {
+ return static_cast<const NodeType*>(model_node);
+ }
NodeType* Add(NodeType* parent, std::unique_ptr<NodeType> node, int index) {
DCHECK(parent && node);
@@ -278,22 +286,23 @@ class TreeNodeModel : public TreeModel {
return root_.get();
}
- int GetChildCount(TreeModelNode* parent) override {
- DCHECK(parent);
- return AsNode(parent)->child_count();
- }
-
- NodeType* GetChild(TreeModelNode* parent, int index) override {
+ Nodes GetChildren(const TreeModelNode* parent) const override {
DCHECK(parent);
- return AsNode(parent)->GetChild(index);
+ const auto& children = AsNode(parent)->children();
+ Nodes nodes;
+ nodes.reserve(children.size());
+ std::transform(children.cbegin(), children.cend(),
+ std::back_inserter(nodes),
+ [](const auto& child) { return child.get(); });
+ return nodes;
}
- int GetIndexOf(TreeModelNode* parent, TreeModelNode* child) override {
+ int GetIndexOf(TreeModelNode* parent, TreeModelNode* child) const override {
DCHECK(parent);
return AsNode(parent)->GetIndexOf(AsNode(child));
}
- TreeModelNode* GetParent(TreeModelNode* node) override {
+ TreeModelNode* GetParent(TreeModelNode* node) const override {
DCHECK(node);
return AsNode(node)->parent();
}
diff --git a/chromium/ui/base/models/tree_node_model_unittest.cc b/chromium/ui/base/models/tree_node_model_unittest.cc
index b39d82bccf3..f5df9488777 100644
--- a/chromium/ui/base/models/tree_node_model_unittest.cc
+++ b/chromium/ui/base/models/tree_node_model_unittest.cc
@@ -98,14 +98,14 @@ TEST_F(TreeNodeModelTest, RemoveNode) {
TestNode* child1 = root->Add(std::make_unique<TestNode>(), 0);
- EXPECT_EQ(1, model.GetChildCount(root));
+ EXPECT_FALSE(root->children().empty());
// Now remove |child1| from |root| and release the memory.
model.Remove(root, child1);
EXPECT_EQ("added=0 removed=1 changed=0", GetObserverCountStateAndClear());
- EXPECT_EQ(0, model.GetChildCount(root));
+ EXPECT_TRUE(root->children().empty());
}
// Verifies if the nodes added under the root are all deleted when calling
@@ -140,7 +140,7 @@ TEST_F(TreeNodeModelTest, DeleteAllNodes) {
root.DeleteAll();
EXPECT_EQ(0, root.child_count());
- EXPECT_TRUE(root.empty());
+ EXPECT_TRUE(root.children().empty());
}
// Verifies if GetIndexOf() returns the correct index for the specified node.
diff --git a/chromium/ui/base/property_data.h b/chromium/ui/base/property_data.h
deleted file mode 100644
index abe13cc746b..00000000000
--- a/chromium/ui/base/property_data.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_PROPERTY_DATA_H_
-#define UI_BASE_PROPERTY_DATA_H_
-
-#include "ui/base/ui_base_export.h"
-
-namespace ui {
-
-// Descendants of ui::PropertyHandler may return a descendant of this class
-// when overriding BeforePropertyChange(). This instance is then passed to
-// AfterPropertyChange() in order to preserve and/or communicate data between
-// those two calls.
-struct UI_BASE_EXPORT PropertyData {
- virtual ~PropertyData() {}
-};
-
-}
-
-#endif
diff --git a/chromium/ui/base/resource/data_pack.cc b/chromium/ui/base/resource/data_pack.cc
index f6cbde5fcc5..da3771f0193 100644
--- a/chromium/ui/base/resource/data_pack.cc
+++ b/chromium/ui/base/resource/data_pack.cc
@@ -21,6 +21,7 @@
#include "base/synchronization/lock.h"
#include "base/sys_byteorder.h"
#include "build/build_config.h"
+#include "net/filter/gzip_header.h"
// For details of the file layout, see
// http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalizedstrings
@@ -84,6 +85,14 @@ void MaybePrintResourceId(uint16_t resource_id) {
}
}
+bool HasGzipHeader(base::StringPiece* data) {
+ net::GZipHeader header;
+ const char* header_end = nullptr;
+ net::GZipHeader::Status header_status =
+ header.ReadMore(data->data(), data->length(), &header_end);
+ return header_status == net::GZipHeader::COMPLETE_HEADER;
+}
+
// Convenience class to write data to a file. Usage is the following:
// 1) Create a new instance, passing a base::FilePath.
// 2) Call Write() repeatedly to write all desired data to the file.
@@ -380,6 +389,17 @@ bool DataPack::HasResource(uint16_t resource_id) const {
return !!LookupEntryById(resource_id);
}
+bool DataPack::IsGzipped(uint16_t resource_id, bool* is_gzipped) const {
+ DCHECK(is_gzipped);
+ if (!HasResource(resource_id))
+ return false;
+
+ base::StringPiece data;
+ CHECK(GetStringPiece(resource_id, &data));
+ *is_gzipped = HasGzipHeader(&data);
+ return true;
+}
+
bool DataPack::GetStringPiece(uint16_t resource_id,
base::StringPiece* data) const {
// It won't be hard to make this endian-agnostic, but it's not worth
diff --git a/chromium/ui/base/resource/data_pack.h b/chromium/ui/base/resource/data_pack.h
index 6d252b07ccf..3a8f66c7219 100644
--- a/chromium/ui/base/resource/data_pack.h
+++ b/chromium/ui/base/resource/data_pack.h
@@ -60,6 +60,7 @@ class UI_DATA_PACK_EXPORT DataPack : public ResourceHandle {
// ResourceHandle implementation:
bool HasResource(uint16_t resource_id) const override;
+ bool IsGzipped(uint16_t resource_id, bool* is_gzipped) const override;
bool GetStringPiece(uint16_t resource_id,
base::StringPiece* data) const override;
base::RefCountedStaticMemory* GetStaticMemory(
diff --git a/chromium/ui/base/resource/data_pack_literal.cc b/chromium/ui/base/resource/data_pack_literal.cc
index 3218f848e94..7d35c6a2ccd 100644
--- a/chromium/ui/base/resource/data_pack_literal.cc
+++ b/chromium/ui/base/resource/data_pack_literal.cc
@@ -29,10 +29,15 @@ const char kSamplePakContentsV5[] = {
0x01, 0x00, 0x28, 0x00, 0x00, 0x00, // index entry 1
0x04, 0x00, 0x28, 0x00, 0x00, 0x00, // index entry 4
0x06, 0x00, 0x34, 0x00, 0x00, 0x00, // index entry 6
- 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // extra entry for the size of last
+ 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, // extra entry for the size of last
0x0a, 0x00, 0x01, 0x00, // alias table
- 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '4',
- 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '6'};
+
+ 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '4',
+ // "this is id 6" gzipped with
+ // echo "this is id 6" | gzip -f -c | hexdump -C
+ 0x1f, 0x8b, 0x08, 0x00, 0x2e, 0x15, 0xc1, 0x5c, 0x00, 0x03, 0x2b, 0xc9,
+ 0xc8, 0x2c, 0x56, 0x00, 0xa1, 0x14, 0x05, 0x33, 0x2e, 0x00, 0x10, 0x61,
+ 0x1b, 0x8b, 0x0d, 0x00, 0x00, 0x00};
const size_t kSamplePakSizeV5 = sizeof(kSamplePakContentsV5);
diff --git a/chromium/ui/base/resource/data_pack_unittest.cc b/chromium/ui/base/resource/data_pack_unittest.cc
index 9ddeee9a84a..17bd93d5fb3 100644
--- a/chromium/ui/base/resource/data_pack_unittest.cc
+++ b/chromium/ui/base/resource/data_pack_unittest.cc
@@ -175,7 +175,6 @@ TEST(DataPackTest, LoadFromBufferV5) {
EXPECT_EQ("this is id 4", data);
ASSERT_TRUE(pack.HasResource(6));
ASSERT_TRUE(pack.GetStringPiece(6, &data));
- EXPECT_EQ("this is id 6", data);
// Try reading zero-length data blobs, just in case.
ASSERT_TRUE(pack.GetStringPiece(1, &data));
@@ -186,6 +185,16 @@ TEST(DataPackTest, LoadFromBufferV5) {
// Try looking up an invalid key.
ASSERT_FALSE(pack.HasResource(140));
ASSERT_FALSE(pack.GetStringPiece(140, &data));
+
+ bool is_gzipped;
+ ASSERT_TRUE(pack.IsGzipped(1, &is_gzipped));
+ ASSERT_FALSE(is_gzipped);
+ ASSERT_TRUE(pack.IsGzipped(4, &is_gzipped));
+ ASSERT_FALSE(is_gzipped);
+ ASSERT_TRUE(pack.IsGzipped(6, &is_gzipped));
+ ASSERT_TRUE(is_gzipped);
+ ASSERT_TRUE(pack.IsGzipped(10, &is_gzipped));
+ ASSERT_FALSE(is_gzipped);
}
INSTANTIATE_TEST_SUITE_P(WriteBINARY,
diff --git a/chromium/ui/base/resource/resource_bundle.cc b/chromium/ui/base/resource/resource_bundle.cc
index 340291d8c8f..ab883f7cb8b 100644
--- a/chromium/ui/base/resource/resource_bundle.cc
+++ b/chromium/ui/base/resource/resource_bundle.cc
@@ -415,7 +415,7 @@ base::string16 ResourceBundle::MaybeMangleLocalizedString(
if (!mangle_localized_strings_)
return str;
- // IDS_DEFAULT_FONT_SIZE and friends are localization "strings" that are
+ // IDS_MINIMUM_FONT_SIZE and friends are localization "strings" that are
// actually integral constants. These should not be mangled or they become
// impossible to parse.
int ignored;
@@ -555,6 +555,15 @@ base::StringPiece ResourceBundle::GetRawDataResourceForScale(
return base::StringPiece();
}
+bool ResourceBundle::IsGzipped(int resource_id) const {
+ bool is_gzipped;
+ for (const auto& pack : data_packs_) {
+ if (pack->IsGzipped(resource_id, &is_gzipped))
+ return is_gzipped;
+ }
+ return false;
+}
+
base::string16 ResourceBundle::GetLocalizedString(int resource_id) {
#if DCHECK_IS_ON()
{
diff --git a/chromium/ui/base/resource/resource_bundle.h b/chromium/ui/base/resource/resource_bundle.h
index 1f0f0b575e4..23005f6da22 100644
--- a/chromium/ui/base/resource/resource_bundle.h
+++ b/chromium/ui/base/resource/resource_bundle.h
@@ -217,6 +217,10 @@ class UI_BASE_EXPORT ResourceBundle {
// Loads the raw bytes of a scale independent data resource.
base::RefCountedMemory* LoadDataResourceBytes(int resource_id) const;
+ // Whether the |resource_id| is gzipped in this bundle. False is also returned
+ // if the resource is not found.
+ bool IsGzipped(int resource_id) const;
+
// Loads the raw bytes of a data resource nearest the scale factor
// |scale_factor| into |bytes|, without doing any processing or
// interpretation of the resource. Use ResourceHandle::SCALE_FACTOR_NONE
diff --git a/chromium/ui/base/resource/resource_bundle_android.cc b/chromium/ui/base/resource/resource_bundle_android.cc
index 899bb583517..6686f17a223 100644
--- a/chromium/ui/base/resource/resource_bundle_android.cc
+++ b/chromium/ui/base/resource/resource_bundle_android.cc
@@ -8,7 +8,6 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
#include "base/path_service.h"
#include "jni/ResourceBundle_jni.h"
#include "ui/base/l10n/l10n_util.h"
@@ -78,17 +77,6 @@ std::unique_ptr<DataPack> LoadDataPackFromLocalePak(
return data_pack;
}
-enum class LoadFailureReason {
- kLocalePakNotFound,
- kPackLoadFailedPrimary,
- kPackLoadFailedSecondary,
- kMaxValue = kPackLoadFailedSecondary,
-};
-
-void LogLoadLocaleFailureReason(LoadFailureReason reason) {
- UMA_HISTOGRAM_ENUMERATION("Android.ResourceBundle.LoadLocaleFailure", reason);
-}
-
} // namespace
void ResourceBundle::LoadCommonResources() {
@@ -134,7 +122,6 @@ std::string ResourceBundle::LoadLocaleResources(
if (locale_file_path.empty()) {
// It's possible that there is no locale.pak.
LOG(WARNING) << "locale_file_path.empty() for locale " << app_locale;
- LogLoadLocaleFailureReason(LoadFailureReason::kLocalePakNotFound);
return std::string();
}
int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
@@ -145,10 +132,8 @@ std::string ResourceBundle::LoadLocaleResources(
locale_resources_data_ = LoadDataPackFromLocalePak(
g_locale_pack_fd, g_locale_pack_region);
- if (!locale_resources_data_.get()) {
- LogLoadLocaleFailureReason(LoadFailureReason::kPackLoadFailedPrimary);
+ if (!locale_resources_data_.get())
return std::string();
- }
// Load secondary locale .pak file if it exists. For debug build monochrome,
// a secondary locale pak will always be loaded; however, it should be
@@ -161,10 +146,8 @@ std::string ResourceBundle::LoadLocaleResources(
secondary_locale_resources_data_ = LoadDataPackFromLocalePak(
g_secondary_locale_pack_fd, g_secondary_locale_pack_region);
- if (!secondary_locale_resources_data_.get()) {
- LogLoadLocaleFailureReason(LoadFailureReason::kPackLoadFailedSecondary);
+ if (!secondary_locale_resources_data_.get())
return std::string();
- }
}
return app_locale;
diff --git a/chromium/ui/base/resource/resource_bundle_unittest.cc b/chromium/ui/base/resource/resource_bundle_unittest.cc
index be36b9ad616..4b3f0f50d28 100644
--- a/chromium/ui/base/resource/resource_bundle_unittest.cc
+++ b/chromium/ui/base/resource/resource_bundle_unittest.cc
@@ -35,6 +35,7 @@
using ::testing::_;
using ::testing::Between;
+using ::testing::DoAll;
using ::testing::Property;
using ::testing::Return;
using ::testing::ReturnArg;
@@ -246,6 +247,25 @@ TEST_F(ResourceBundleTest, DelegateGetRawDataResource) {
EXPECT_EQ(string_piece.data(), result.data());
}
+TEST_F(ResourceBundleTest, IsGzipped) {
+ base::ScopedTempDir dir;
+ ASSERT_TRUE(dir.CreateUniqueTempDir());
+ base::FilePath data_path =
+ dir.GetPath().Append(FILE_PATH_LITERAL("sample.pak"));
+ // Dump contents into a pak file and load it.
+ ASSERT_EQ(base::WriteFile(data_path, kSamplePakContentsV5, kSamplePakSizeV5),
+ static_cast<int>(kSamplePakSizeV5));
+ ResourceBundle* resource_bundle = CreateResourceBundle(nullptr);
+ resource_bundle->AddDataPackFromPath(data_path, SCALE_FACTOR_100P);
+
+ ASSERT_FALSE(resource_bundle->IsGzipped(1));
+ ASSERT_FALSE(resource_bundle->IsGzipped(4));
+ ASSERT_TRUE(resource_bundle->IsGzipped(6));
+ ASSERT_FALSE(resource_bundle->IsGzipped(10));
+ // Ask for a non-existent resource ID.
+ ASSERT_FALSE(resource_bundle->IsGzipped(200));
+}
+
TEST_F(ResourceBundleTest, DelegateGetLocalizedString) {
MockResourceBundleDelegate delegate;
ResourceBundle* resource_bundle = CreateResourceBundle(&delegate);
diff --git a/chromium/ui/base/resource/resource_data_dll_win.cc b/chromium/ui/base/resource/resource_data_dll_win.cc
index 12c54c99eb3..153971554c3 100644
--- a/chromium/ui/base/resource/resource_data_dll_win.cc
+++ b/chromium/ui/base/resource/resource_data_dll_win.cc
@@ -28,6 +28,10 @@ bool ResourceDataDLL::HasResource(uint16_t resource_id) const {
&data_size);
}
+bool ResourceDataDLL::IsGzipped(uint16_t resource_id, bool* is_gzipped) const {
+ return false;
+}
+
bool ResourceDataDLL::GetStringPiece(uint16_t resource_id,
base::StringPiece* data) const {
DCHECK(data);
diff --git a/chromium/ui/base/resource/resource_data_dll_win.h b/chromium/ui/base/resource/resource_data_dll_win.h
index c5f0e60ac38..1e21a828e29 100644
--- a/chromium/ui/base/resource/resource_data_dll_win.h
+++ b/chromium/ui/base/resource/resource_data_dll_win.h
@@ -21,6 +21,7 @@ class ResourceDataDLL : public ResourceHandle {
// ResourceHandle implementation:
bool HasResource(uint16_t resource_id) const override;
+ bool IsGzipped(uint16_t resource_id, bool* is_gzipped) const override;
bool GetStringPiece(uint16_t resource_id,
base::StringPiece* data) const override;
base::RefCountedStaticMemory* GetStaticMemory(
diff --git a/chromium/ui/base/resource/resource_handle.h b/chromium/ui/base/resource/resource_handle.h
index 055b0370868..1ebd50032fc 100644
--- a/chromium/ui/base/resource/resource_handle.h
+++ b/chromium/ui/base/resource/resource_handle.h
@@ -31,6 +31,10 @@ class UI_DATA_PACK_EXPORT ResourceHandle {
// Returns true if the DataPack contains a resource with id |resource_id|.
virtual bool HasResource(uint16_t resource_id) const = 0;
+ // Whether a specific |resource_id| is gzipped. Returns false if
+ // !HasResource(resource_id). |is_gzipped| cannot be nullptr.
+ virtual bool IsGzipped(uint16_t resource_id, bool* is_gzipped) const = 0;
+
// Get resource by id |resource_id|, filling in |data|.
// The data is owned by the DataPack object and should not be modified.
// Returns false if the resource id isn't found.
diff --git a/chromium/ui/base/ui_base_features.cc b/chromium/ui/base/ui_base_features.cc
index 32528f9e6e4..396d1cca111 100644
--- a/chromium/ui/base/ui_base_features.cc
+++ b/chromium/ui/base/ui_base_features.cc
@@ -45,7 +45,7 @@ bool IsNotificationIndicatorEnabled() {
// Enables GPU rasterization for all UI drawing (where not blacklisted).
const base::Feature kUiGpuRasterization = {"UiGpuRasterization",
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -85,7 +85,7 @@ const base::Feature kTSFImeSupport = {"TSFImeSupport",
base::FEATURE_ENABLED_BY_DEFAULT};
bool IsUsingWMPointerForTouch() {
- return base::win::GetVersion() >= base::win::VERSION_WIN8 &&
+ return base::win::GetVersion() >= base::win::Version::WIN8 &&
base::FeatureList::IsEnabled(kPointerEventsForTouch);
}
@@ -122,16 +122,15 @@ const base::Feature kDirectManipulationStylus = {
const base::Feature kMash = {"Mash", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kMashOopViz = {"MashOopViz",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
const base::Feature kSingleProcessMash = {"SingleProcessMash",
base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_CHROMEOS)
-// Connecting the client and IME engine via Mojo. https://crbug.com/937167
-const base::Feature kMojoIMF = {"MojoIMF", base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
+const base::Feature kFormControlsRefresh = {"FormControlsRefresh",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsFormControlsRefreshEnabled() {
+ return base::FeatureList::IsEnabled(features::kFormControlsRefresh);
+}
bool IsUsingWindowService() {
return IsSingleProcessMash() || IsMultiProcessMash();
@@ -141,23 +140,11 @@ bool IsMultiProcessMash() {
return base::FeatureList::IsEnabled(features::kMash);
}
-bool IsMashOopVizEnabled() {
- return base::FeatureList::IsEnabled(features::kMashOopViz);
-}
-
bool IsSingleProcessMash() {
return base::FeatureList::IsEnabled(features::kSingleProcessMash) &&
!base::FeatureList::IsEnabled(features::kMash);
}
-bool IsMojoImfEnabled() {
-#if defined(OS_CHROMEOS)
- return base::FeatureList::IsEnabled(features::kMojoIMF);
-#else
- return false;
-#endif
-}
-
bool IsAutomaticUiAdjustmentsForTouchEnabled() {
#if defined(OS_WIN) || defined(OS_CHROMEOS)
return base::FeatureList::IsEnabled(
@@ -186,12 +173,6 @@ bool IsOzoneDrmMojo() {
IsMultiProcessMash();
}
-#if defined(OS_MACOSX)
-const base::Feature kDarkMode = {"DarkMode", base::FEATURE_ENABLED_BY_DEFAULT};
-#else
-const base::Feature kDarkMode = {"DarkMode", base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
-
#if defined(OS_CHROMEOS)
const base::Feature kHandwritingGesture = {"HandwritingGesture",
base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromium/ui/base/ui_base_features.h b/chromium/ui/base/ui_base_features.h
index 462b7ab7905..332d7c4182e 100644
--- a/chromium/ui/base/ui_base_features.h
+++ b/chromium/ui/base/ui_base_features.h
@@ -68,20 +68,15 @@ extern const base::Feature kDirectManipulationStylus;
// TODO(jamescook): Make flag only available in Chrome OS.
COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kMash;
-// Used to run Viz in its own process when kMash is enabled. Viz is run in Ash
-// process by default.
-// TODO(mohsen): Remove this when Viz can run fully in a separate process. Then
-// make it the default kMash behavior.
-COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kMashOopViz;
-
// NOTE: Do not access directly outside of tests. Use IsSingleProcessMash()
// to avoid problems when Mash and SingleProcessMash are both enabled.
COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kSingleProcessMash;
-#if defined(OS_CHROMEOS)
-COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kMojoIMF;
-#endif
+// Used to enable the new controls UI.
+COMPONENT_EXPORT(UI_BASE_FEATURES)
+extern const base::Feature kFormControlsRefresh;
+COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsFormControlsRefreshEnabled();
// Returns true if Chrome's aura usage is backed by the WindowService.
COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsUsingWindowService();
@@ -90,8 +85,6 @@ COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsUsingWindowService();
// service and Viz graphics). See //ash/README.md.
COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsMultiProcessMash();
-COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsMashOopVizEnabled();
-
// Returns true if code outside of ash is using the WindowService. In this mode
// there are two aura::Envs. Ash uses one with Env::Mode::LOCAL. Non-ash code
// uses an aura::Env with a mode of MUS. The non-ash code using mus targets the
@@ -100,11 +93,6 @@ COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsMashOopVizEnabled();
// See //ash/README.md.
COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsSingleProcessMash();
-// Returns true if the client connects the active ime engine through mojo IPCs.
-// This can only return true on Chrome OS, and it can only take effect when
-// IsSingleProcessMash() returns true.
-COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsMojoImfEnabled();
-
// Whether the UI may accommodate touch input in response to hardware changes.
COMPONENT_EXPORT(UI_BASE_FEATURES)
bool IsAutomaticUiAdjustmentsForTouchEnabled();
@@ -126,10 +114,6 @@ COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kEnableOzoneDrmMojo;
COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsOzoneDrmMojo();
-// Whether default UI should use a dark mode color scheme, if enabled on
-// macOS Mojave/Windows 10.
-COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kDarkMode;
-
#if defined(OS_CHROMEOS)
COMPONENT_EXPORT(UI_BASE_FEATURES)
extern const base::Feature kHandwritingGesture;
diff --git a/chromium/ui/base/ui_base_paths.cc b/chromium/ui/base/ui_base_paths.cc
index b3974de5d26..11ead8635aa 100644
--- a/chromium/ui/base/ui_base_paths.cc
+++ b/chromium/ui/base/ui_base_paths.cc
@@ -65,7 +65,7 @@ bool PathProvider(int key, base::FilePath* result) {
if (!base::PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &cur))
return false;
#else
- if (!base::PathService::Get(base::DIR_MODULE, &cur))
+ if (!base::PathService::Get(base::DIR_ASSETS, &cur))
return false;
#endif
cur = cur.AppendASCII("ui_test.pak");
diff --git a/chromium/ui/base/webui/web_ui_util.cc b/chromium/ui/base/webui/web_ui_util.cc
index 489fb7ecd62..29ad19d4bdc 100644
--- a/chromium/ui/base/webui/web_ui_util.cc
+++ b/chromium/ui/base/webui/web_ui_util.cc
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
@@ -115,10 +116,7 @@ void ParsePathAndImageSpec(const GURL& url,
std::string* path,
float* scale_factor,
int* frame_index) {
- *path = net::UnescapeURLComponent(
- url.path().substr(1),
- net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS |
- net::UnescapeRule::SPACES);
+ *path = net::UnescapeBinaryURLComponent(url.path_piece().substr(1));
if (scale_factor)
*scale_factor = 1.0f;
if (frame_index)
diff --git a/chromium/ui/base/win/hwnd_subclass.cc b/chromium/ui/base/win/hwnd_subclass.cc
index 184698ba041..c6325d5628d 100644
--- a/chromium/ui/base/win/hwnd_subclass.cc
+++ b/chromium/ui/base/win/hwnd_subclass.cc
@@ -11,6 +11,7 @@
#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
#include "base/stl_util.h"
+#include "ui/base/win/touch_input.h"
#include "ui/gfx/win/hwnd_util.h"
namespace {
@@ -34,19 +35,6 @@ WNDPROC GetCurrentWndProc(HWND target) {
return reinterpret_cast<WNDPROC>(GetWindowLongPtr(target, GWLP_WNDPROC));
}
-// Not defined before Win7
-BOOL GetTouchInputInfoWrapper(HTOUCHINPUT handle, UINT count,
- PTOUCHINPUT pointer, int size) {
- typedef BOOL(WINAPI *GetTouchInputInfoPtr)(HTOUCHINPUT, UINT,
- PTOUCHINPUT, int);
- GetTouchInputInfoPtr get_touch_input_info_func =
- reinterpret_cast<GetTouchInputInfoPtr>(
- GetProcAddress(GetModuleHandleA("user32.dll"), "GetTouchInputInfo"));
- if (get_touch_input_info_func)
- return get_touch_input_info_func(handle, count, pointer, size);
- return FALSE;
-}
-
} // namespace
namespace ui {
@@ -140,8 +128,8 @@ LRESULT HWNDSubclass::OnWndProc(HWND hwnd,
if (message == WM_TOUCH) {
TOUCHINPUT point;
- if (GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param), 1,
- &point, sizeof(TOUCHINPUT))) {
+ if (ui::GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param), 1,
+ &point, sizeof(TOUCHINPUT))) {
POINT touch_location = {TOUCH_COORD_TO_PIXEL(point.x),
TOUCH_COORD_TO_PIXEL(point.y)};
HWND actual_target = WindowFromPoint(touch_location);
diff --git a/chromium/ui/base/win/lock_state.cc b/chromium/ui/base/win/lock_state.cc
index 3f6d9395367..03e4297d409 100644
--- a/chromium/ui/base/win/lock_state.cc
+++ b/chromium/ui/base/win/lock_state.cc
@@ -29,7 +29,7 @@ bool IsSessionLocked() {
auto session_flags = info->Data.WTSInfoExLevel1.SessionFlags;
// For Windows 7 SessionFlags has inverted logic:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee621019.
- if (base::win::GetVersion() == base::win::VERSION_WIN7)
+ if (base::win::GetVersion() == base::win::Version::WIN7)
is_locked = session_flags == WTS_SESSIONSTATE_UNLOCK;
else
is_locked = session_flags == WTS_SESSIONSTATE_LOCK;
diff --git a/chromium/ui/base/win/scoped_ole_initializer.cc b/chromium/ui/base/win/scoped_ole_initializer.cc
index 48361aa0896..d3d72f883b8 100644
--- a/chromium/ui/base/win/scoped_ole_initializer.cc
+++ b/chromium/ui/base/win/scoped_ole_initializer.cc
@@ -4,31 +4,19 @@
#include "ui/base/win/scoped_ole_initializer.h"
+#include <ole2.h>
+
#include "base/logging.h"
namespace ui {
-ScopedOleInitializer::ScopedOleInitializer()
- :
-#ifndef NDEBUG
- // Using the windows API directly to avoid dependency on platform_thread.
- thread_id_(GetCurrentThreadId()),
-#endif
- hr_(OleInitialize(NULL)) {
-#ifndef NDEBUG
- if (hr_ == S_FALSE) {
- LOG(ERROR) << "Multiple OleInitialize() calls for thread " << thread_id_;
- } else {
- DCHECK_NE(OLE_E_WRONGCOMPOBJ, hr_) << "Incompatible DLLs on machine";
- DCHECK_NE(RPC_E_CHANGED_MODE, hr_) << "Invalid COM thread model change";
- }
-#endif
+ScopedOleInitializer::ScopedOleInitializer() : hr_(OleInitialize(NULL)) {
+ DCHECK_NE(OLE_E_WRONGCOMPOBJ, hr_) << "Incompatible DLLs on machine";
+ DCHECK_NE(RPC_E_CHANGED_MODE, hr_) << "Invalid COM thread model change";
}
ScopedOleInitializer::~ScopedOleInitializer() {
-#ifndef NDEBUG
- DCHECK_EQ(thread_id_, GetCurrentThreadId());
-#endif
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (SUCCEEDED(hr_))
OleUninitialize();
}
diff --git a/chromium/ui/base/win/scoped_ole_initializer.h b/chromium/ui/base/win/scoped_ole_initializer.h
index 255a68ccc23..28085f5f022 100644
--- a/chromium/ui/base/win/scoped_ole_initializer.h
+++ b/chromium/ui/base/win/scoped_ole_initializer.h
@@ -5,9 +5,9 @@
#ifndef UI_BASE_WIN_SCOPED_OLE_INITIALIZER_H_
#define UI_BASE_WIN_SCOPED_OLE_INITIALIZER_H_
-#include <ole2.h>
-
#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "base/win/windows_types.h"
#include "ui/base/ui_base_export.h"
namespace ui {
@@ -18,13 +18,7 @@ class UI_BASE_EXPORT ScopedOleInitializer {
~ScopedOleInitializer();
private:
-#ifndef NDEBUG
- // In debug builds we use this variable to catch a potential bug where a
- // ScopedOleInitializer instance is deleted on a different thread than it
- // was initially created on. If that ever happens it can have bad
- // consequences and the cause can be tricky to track down.
- DWORD thread_id_;
-#endif
+ THREAD_CHECKER(thread_checker_);
HRESULT hr_;
DISALLOW_COPY_AND_ASSIGN(ScopedOleInitializer);
diff --git a/chromium/ui/base/win/shell.cc b/chromium/ui/base/win/shell.cc
index 6301000c92d..1c63dea60d3 100644
--- a/chromium/ui/base/win/shell.cc
+++ b/chromium/ui/base/win/shell.cc
@@ -185,7 +185,7 @@ bool IsAeroGlassEnabled() {
bool IsDwmCompositionEnabled() {
// As of Windows 8, DWM composition is always enabled.
// In Windows 7 this can change at runtime.
- if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+ if (base::win::GetVersion() >= base::win::Version::WIN8) {
return true;
}
BOOL is_enabled;
diff --git a/chromium/ui/base/win/system_media_controls/BUILD.gn b/chromium/ui/base/win/system_media_controls/BUILD.gn
index 41ca48375e5..c205104b118 100644
--- a/chromium/ui/base/win/system_media_controls/BUILD.gn
+++ b/chromium/ui/base/win/system_media_controls/BUILD.gn
@@ -18,6 +18,10 @@ component("system_media_controls") {
"//base",
"//ui/gfx",
]
+
+ public_deps = [
+ "//skia",
+ ]
}
static_library("test_support") {
diff --git a/chromium/ui/base/win/system_media_controls/mock_system_media_controls_service.h b/chromium/ui/base/win/system_media_controls/mock_system_media_controls_service.h
index 4f5c9138eb9..817b51fce39 100644
--- a/chromium/ui/base/win/system_media_controls/mock_system_media_controls_service.h
+++ b/chromium/ui/base/win/system_media_controls/mock_system_media_controls_service.h
@@ -25,6 +25,7 @@ class MockSystemMediaControlsService : public SystemMediaControlsService {
MOCK_METHOD1(AddObserver, void(SystemMediaControlsServiceObserver* observer));
MOCK_METHOD1(RemoveObserver,
void(SystemMediaControlsServiceObserver* observer));
+ MOCK_METHOD1(SetEnabled, void(bool enabled));
MOCK_METHOD1(SetIsNextEnabled, void(bool value));
MOCK_METHOD1(SetIsPreviousEnabled, void(bool value));
MOCK_METHOD1(SetIsPlayEnabled, void(bool value));
@@ -32,6 +33,12 @@ class MockSystemMediaControlsService : public SystemMediaControlsService {
MOCK_METHOD1(SetIsStopEnabled, void(bool value));
MOCK_METHOD1(SetPlaybackStatus,
void(ABI::Windows::Media::MediaPlaybackStatus status));
+ MOCK_METHOD1(SetTitle, void(const base::string16& title));
+ MOCK_METHOD1(SetArtist, void(const base::string16& artist));
+ MOCK_METHOD1(SetThumbnail, void(const SkBitmap& bitmap));
+ MOCK_METHOD0(ClearThumbnail, void());
+ MOCK_METHOD0(ClearMetadata, void());
+ MOCK_METHOD0(UpdateDisplay, void());
private:
DISALLOW_COPY_AND_ASSIGN(MockSystemMediaControlsService);
diff --git a/chromium/ui/base/win/system_media_controls/system_media_controls_service.h b/chromium/ui/base/win/system_media_controls/system_media_controls_service.h
index fe66681f041..8b5eba68a5c 100644
--- a/chromium/ui/base/win/system_media_controls/system_media_controls_service.h
+++ b/chromium/ui/base/win/system_media_controls/system_media_controls_service.h
@@ -8,6 +8,8 @@
#include <windows.media.control.h>
#include "base/component_export.h"
+#include "base/strings/string16.h"
+#include "third_party/skia/include/core/SkBitmap.h"
namespace system_media_controls {
@@ -29,6 +31,9 @@ class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsService {
virtual void AddObserver(SystemMediaControlsServiceObserver* observer) = 0;
virtual void RemoveObserver(SystemMediaControlsServiceObserver* observer) = 0;
+ // Enables/disables the service.
+ virtual void SetEnabled(bool enabled) = 0;
+
// TODO(steimel): Add other controls.
// Enable or disable specific controls.
virtual void SetIsNextEnabled(bool value) = 0;
@@ -40,6 +45,14 @@ class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsService {
// Setters for metadata.
virtual void SetPlaybackStatus(
ABI::Windows::Media::MediaPlaybackStatus status) = 0;
+ virtual void SetTitle(const base::string16& title) = 0;
+ virtual void SetArtist(const base::string16& artist) = 0;
+ virtual void SetThumbnail(const SkBitmap& bitmap) = 0;
+
+ // Helpers for metadata.
+ virtual void ClearThumbnail() = 0;
+ virtual void ClearMetadata() = 0;
+ virtual void UpdateDisplay() = 0;
protected:
virtual ~SystemMediaControlsService();
diff --git a/chromium/ui/base/win/system_media_controls/system_media_controls_service_impl.cc b/chromium/ui/base/win/system_media_controls/system_media_controls_service_impl.cc
index 9d7a1a44b76..7862e3c8bb7 100644
--- a/chromium/ui/base/win/system_media_controls/system_media_controls_service_impl.cc
+++ b/chromium/ui/base/win/system_media_controls/system_media_controls_service_impl.cc
@@ -13,6 +13,7 @@
#include "base/win/core_winrt_util.h"
#include "base/win/scoped_hstring.h"
#include "ui/base/win/system_media_controls/system_media_controls_service_observer.h"
+#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/win/singleton_hwnd.h"
namespace system_media_controls {
@@ -24,6 +25,12 @@ using ABI::Windows::Media::ISystemMediaTransportControlsButtonPressedEventArgs;
using ABI::Windows::Media::SystemMediaTransportControls;
using ABI::Windows::Media::SystemMediaTransportControlsButton;
using ABI::Windows::Media::SystemMediaTransportControlsButtonPressedEventArgs;
+using ABI::Windows::Storage::Streams::IDataWriter;
+using ABI::Windows::Storage::Streams::IDataWriterFactory;
+using ABI::Windows::Storage::Streams::IOutputStream;
+using ABI::Windows::Storage::Streams::IRandomAccessStream;
+using ABI::Windows::Storage::Streams::IRandomAccessStreamReference;
+using ABI::Windows::Storage::Streams::IRandomAccessStreamReferenceStatics;
// static
SystemMediaControlsServiceImpl* SystemMediaControlsServiceImpl::GetInstance() {
@@ -38,7 +45,7 @@ SystemMediaControlsServiceImpl::~SystemMediaControlsServiceImpl() {
if (has_valid_registration_token_) {
DCHECK(system_media_controls_);
system_media_controls_->remove_ButtonPressed(registration_token_);
- system_media_controls_->put_IsEnabled(false);
+ ClearMetadata();
}
}
@@ -81,6 +88,22 @@ bool SystemMediaControlsServiceImpl::Initialize() {
if (FAILED(hr))
return false;
+ hr = system_media_controls_->get_DisplayUpdater(&display_updater_);
+ if (FAILED(hr))
+ return false;
+
+ // The current MediaSession API implementation matches the SMTC music type
+ // most closely, since MediaSession has the artist property which the SMTC
+ // only presents to music playback types.
+ hr = display_updater_->put_Type(
+ ABI::Windows::Media::MediaPlaybackType::MediaPlaybackType_Music);
+ if (FAILED(hr))
+ return false;
+
+ hr = display_updater_->get_MusicProperties(&display_properties_);
+ if (FAILED(hr))
+ return false;
+
initialized_ = true;
return true;
}
@@ -95,6 +118,12 @@ void SystemMediaControlsServiceImpl::RemoveObserver(
observers_.RemoveObserver(observer);
}
+void SystemMediaControlsServiceImpl::SetEnabled(bool enabled) {
+ DCHECK(initialized_);
+ HRESULT hr = system_media_controls_->put_IsEnabled(enabled);
+ DCHECK(SUCCEEDED(hr));
+}
+
void SystemMediaControlsServiceImpl::SetIsNextEnabled(bool value) {
DCHECK(initialized_);
HRESULT hr = system_media_controls_->put_IsNextEnabled(value);
@@ -132,6 +161,138 @@ void SystemMediaControlsServiceImpl::SetPlaybackStatus(
DCHECK(SUCCEEDED(hr));
}
+void SystemMediaControlsServiceImpl::SetTitle(const base::string16& title) {
+ DCHECK(initialized_);
+ DCHECK(display_properties_);
+ base::win::ScopedHString h_title = base::win::ScopedHString::Create(title);
+ HRESULT hr = display_properties_->put_Title(h_title.get());
+ DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetArtist(const base::string16& artist) {
+ DCHECK(initialized_);
+ DCHECK(display_properties_);
+ base::win::ScopedHString h_artist = base::win::ScopedHString::Create(artist);
+ HRESULT hr = display_properties_->put_Artist(h_artist.get());
+ DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetThumbnail(const SkBitmap& bitmap) {
+ DCHECK(initialized_);
+ DCHECK(display_updater_);
+ // Use |icon_data_writer_| to write the bitmap data into |icon_stream_| so we
+ // can populate |icon_stream_reference_| and then give it to the SMTC. All of
+ // these are member variables to avoid a race condition between them being
+ // destructed and the async operation completing.
+ base::win::ScopedHString id = base::win::ScopedHString::Create(
+ RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream);
+ HRESULT hr = base::win::RoActivateInstance(id.get(), &icon_stream_);
+ DCHECK(SUCCEEDED(hr));
+
+ Microsoft::WRL::ComPtr<IDataWriterFactory> data_writer_factory;
+ hr = base::win::GetActivationFactory<
+ IDataWriterFactory, RuntimeClass_Windows_Storage_Streams_DataWriter>(
+ &data_writer_factory);
+ DCHECK(SUCCEEDED(hr));
+
+ Microsoft::WRL::ComPtr<IOutputStream> output_stream;
+ hr = icon_stream_.As(&output_stream);
+ DCHECK(SUCCEEDED(hr));
+
+ hr = data_writer_factory->CreateDataWriter(output_stream.Get(),
+ &icon_data_writer_);
+ DCHECK(SUCCEEDED(hr));
+
+ std::vector<unsigned char> icon_png;
+ gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &icon_png);
+ hr = icon_data_writer_->WriteBytes(icon_png.size(), (BYTE*)icon_png.data());
+ DCHECK(SUCCEEDED(hr));
+
+ // Store the written bytes in the stream, an async operation.
+ Microsoft::WRL::ComPtr<
+ ABI::Windows::Foundation::IAsyncOperation<unsigned int>>
+ store_async_operation;
+ hr = icon_data_writer_->StoreAsync(&store_async_operation);
+ DCHECK(SUCCEEDED(hr));
+
+ // Make a callback that gives the icon to the SMTC once the bits make it into
+ // |icon_stream_|
+ auto store_async_callback = Microsoft::WRL::Callback<
+ ABI::Windows::Foundation::IAsyncOperationCompletedHandler<unsigned int>>(
+ [this](ABI::Windows::Foundation::IAsyncOperation<unsigned int>* async_op,
+ ABI::Windows::Foundation::AsyncStatus status) mutable {
+ // Check the async operation completed successfully.
+ ABI::Windows::Foundation::IAsyncInfo* async_info;
+ HRESULT hr = async_op->QueryInterface(
+ IID_IAsyncInfo, reinterpret_cast<void**>(&async_info));
+ DCHECK(SUCCEEDED(hr));
+ async_info->get_ErrorCode(&hr);
+ if (SUCCEEDED(hr) &&
+ status == ABI::Windows::Foundation::AsyncStatus::Completed) {
+ Microsoft::WRL::ComPtr<IRandomAccessStreamReferenceStatics>
+ reference_statics;
+ HRESULT hr = base::win::GetActivationFactory<
+ IRandomAccessStreamReferenceStatics,
+ RuntimeClass_Windows_Storage_Streams_RandomAccessStreamReference>(
+ &reference_statics);
+ DCHECK(SUCCEEDED(hr));
+
+ hr = reference_statics->CreateFromStream(icon_stream_.Get(),
+ &icon_stream_reference_);
+ DCHECK(SUCCEEDED(hr));
+
+ hr = display_updater_->put_Thumbnail(icon_stream_reference_.Get());
+ DCHECK(SUCCEEDED(hr));
+
+ hr = display_updater_->Update();
+ DCHECK(SUCCEEDED(hr));
+ }
+ return hr;
+ });
+
+ hr = store_async_operation->put_Completed(store_async_callback.Get());
+ DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::ClearThumbnail() {
+ DCHECK(initialized_);
+ DCHECK(display_updater_);
+ HRESULT hr = display_updater_->put_Thumbnail(nullptr);
+ DCHECK(SUCCEEDED(hr));
+
+ hr = display_updater_->Update();
+ DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::ClearMetadata() {
+ DCHECK(initialized_);
+ DCHECK(display_updater_);
+ HRESULT hr = display_updater_->ClearAll();
+ DCHECK(SUCCEEDED(hr));
+
+ // To prevent disabled controls and the executable name from showing up in the
+ // SMTC, we need to tell them that we are disabled.
+ hr = system_media_controls_->put_IsEnabled(false);
+ DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::UpdateDisplay() {
+ DCHECK(initialized_);
+ DCHECK(system_media_controls_);
+ DCHECK(display_updater_);
+ HRESULT hr = system_media_controls_->put_IsEnabled(true);
+ DCHECK(SUCCEEDED(hr));
+
+ // |ClearAll()| unsets the type, if we don't set it again then the artist
+ // won't be displayed.
+ hr = display_updater_->put_Type(
+ ABI::Windows::Media::MediaPlaybackType::MediaPlaybackType_Music);
+ DCHECK(SUCCEEDED(hr));
+
+ hr = display_updater_->Update();
+ DCHECK(SUCCEEDED(hr));
+}
+
void SystemMediaControlsServiceImpl::OnPlay() {
for (SystemMediaControlsServiceObserver& obs : observers_)
obs.OnPlay();
diff --git a/chromium/ui/base/win/system_media_controls/system_media_controls_service_impl.h b/chromium/ui/base/win/system_media_controls/system_media_controls_service_impl.h
index fb10cdecb9e..025ab923a77 100644
--- a/chromium/ui/base/win/system_media_controls/system_media_controls_service_impl.h
+++ b/chromium/ui/base/win/system_media_controls/system_media_controls_service_impl.h
@@ -37,6 +37,7 @@ class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsServiceImpl
// SystemMediaControlsService implementation.
void AddObserver(SystemMediaControlsServiceObserver* observer) override;
void RemoveObserver(SystemMediaControlsServiceObserver* observer) override;
+ void SetEnabled(bool enabled) override;
void SetIsNextEnabled(bool value) override;
void SetIsPreviousEnabled(bool value) override;
void SetIsPlayEnabled(bool value) override;
@@ -44,6 +45,12 @@ class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsServiceImpl
void SetIsStopEnabled(bool value) override;
void SetPlaybackStatus(
ABI::Windows::Media::MediaPlaybackStatus status) override;
+ void SetTitle(const base::string16& title) override;
+ void SetArtist(const base::string16& artist) override;
+ void SetThumbnail(const SkBitmap& bitmap) override;
+ void ClearThumbnail() override;
+ void ClearMetadata() override;
+ void UpdateDisplay() override;
private:
friend struct base::DefaultSingletonTraits<SystemMediaControlsServiceImpl>;
@@ -60,8 +67,22 @@ class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsServiceImpl
void OnPrevious();
void OnStop();
+ // Control and keep track of the metadata.
Microsoft::WRL::ComPtr<ABI::Windows::Media::ISystemMediaTransportControls>
system_media_controls_;
+ Microsoft::WRL::ComPtr<
+ ABI::Windows::Media::ISystemMediaTransportControlsDisplayUpdater>
+ display_updater_;
+ Microsoft::WRL::ComPtr<ABI::Windows::Media::IMusicDisplayProperties>
+ display_properties_;
+ Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IDataWriter>
+ icon_data_writer_;
+ Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream>
+ icon_stream_;
+ Microsoft::WRL::ComPtr<
+ ABI::Windows::Storage::Streams::IRandomAccessStreamReference>
+ icon_stream_reference_;
+
EventRegistrationToken registration_token_;
// True if we've already tried to connect to the SystemMediaTransportControls.
diff --git a/chromium/ui/base/win/touch_input.cc b/chromium/ui/base/win/touch_input.cc
index 0114bdd3a7f..708d5662c82 100644
--- a/chromium/ui/base/win/touch_input.cc
+++ b/chromium/ui/base/win/touch_input.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "ui/base/win/touch_input.h"
+#include "base/win/win_util.h"
namespace ui {
@@ -10,11 +11,9 @@ 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 =
- reinterpret_cast<GetTouchInputInfoPtr>(
- GetProcAddress(GetModuleHandleA("user32.dll"), "GetTouchInputInfo"));
+ static const auto get_touch_input_info_func =
+ reinterpret_cast<decltype(&::GetTouchInputInfo)>(
+ base::win::GetUser32FunctionPointer("GetTouchInputInfo"));
if (get_touch_input_info_func)
return get_touch_input_info_func(handle, count, pointer, size);
return FALSE;
diff --git a/chromium/ui/base/window_tracker_template.h b/chromium/ui/base/window_tracker_template.h
deleted file mode 100644
index e91bdac8077..00000000000
--- a/chromium/ui/base/window_tracker_template.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_WINDOW_TRACKER_TEMPLATE_H_
-#define UI_BASE_WINDOW_TRACKER_TEMPLATE_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/stl_util.h"
-
-namespace ui {
-
-// This class is used to track an ordered list of objects that support an
-// observer interface with the function OnWindowDestroying(). When the object
-// is destroyed it is removed from the ordered list of objects.
-// Examples of T include aura::Window and its corresponding
-// aura::WindowObserver interface.
-template <class T, class TObserver>
-class WindowTrackerTemplate : public TObserver {
- public:
- // A vector<> is used for tracking the windows (instead of a set<>) because
- // the user may want to know about the order of the windows that have been
- // added.
- using WindowList = std::vector<T*>;
-
- explicit WindowTrackerTemplate(const WindowList& windows) {
- for (T* window : windows)
- Add(window);
- }
- WindowTrackerTemplate() {}
- ~WindowTrackerTemplate() override { RemoveAll(); }
-
- // Returns the set of windows being observed.
- const WindowList& windows() const { return windows_; }
-
- // Adds |window| to the set of Windows being tracked.
- void Add(T* window) {
- if (base::ContainsValue(windows_, window))
- return;
-
- window->AddObserver(this);
- windows_.push_back(window);
- }
-
- void RemoveAll() {
- for (T* window : windows_)
- window->RemoveObserver(this);
- windows_.clear();
- }
-
- // Removes |window| from the set of windows being tracked.
- void Remove(T* window) {
- auto iter = std::find(windows_.begin(), windows_.end(), window);
- if (iter != windows_.end()) {
- window->RemoveObserver(this);
- windows_.erase(iter);
- }
- }
-
- T* Pop() {
- DCHECK(!windows_.empty());
- T* result = windows_[0];
- Remove(result);
- return result;
- }
-
- // Returns true if |window| was previously added and has not been removed or
- // deleted.
- bool Contains(T* window) const {
- return base::ContainsValue(windows_, window);
- }
-
- // Observer overrides:
- void OnWindowDestroying(T* window) override {
- DCHECK(Contains(window));
- Remove(window);
- }
-
- private:
- WindowList windows_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTrackerTemplate);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_WINDOW_TRACKER_TEMPLATE_H_
diff --git a/chromium/ui/base/x/x11_display_util.cc b/chromium/ui/base/x/x11_display_util.cc
index e34c5cc6fda..c72d65ce129 100644
--- a/chromium/ui/base/x/x11_display_util.cc
+++ b/chromium/ui/base/x/x11_display_util.cc
@@ -101,6 +101,21 @@ void ClipWorkArea(std::vector<display::Display>* displays,
primary.set_work_area(work_area);
}
+int GetRefreshRateFromXRRModeInfo(XRRModeInfo* modes,
+ int num_of_mode,
+ RRMode current_mode_id) {
+ for (int i = 0; i < num_of_mode; i++) {
+ XRRModeInfo mode_info = modes[i];
+ if (mode_info.id != current_mode_id)
+ continue;
+ if (!mode_info.hTotal || !mode_info.vTotal)
+ return 0;
+
+ // Refresh Rate = Pixel Clock / (Horizontal Total * Vertical Total)
+ return mode_info.dotClock / (mode_info.hTotal * mode_info.vTotal);
+ }
+ return 0;
+}
} // namespace
int GetXrandrVersion(XDisplay* xdisplay) {
@@ -232,9 +247,14 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
gfx::ICCProfile icc_profile = ui::GetICCProfileForMonitor(
monitor_iter == output_to_monitor.end() ? 0 : monitor_iter->second);
icc_profile.HistogramDisplay(display.id());
- display.set_color_space(icc_profile.GetColorSpace());
+ display.set_color_space(icc_profile.GetPrimariesOnlyColorSpace());
}
+ // Set monitor refresh rate
+ int refresh_rate = GetRefreshRateFromXRRModeInfo(
+ resources->modes, resources->nmode, crtc->mode);
+ display.set_display_frequency(refresh_rate);
+
displays.push_back(display);
}
}
diff --git a/chromium/ui/base/x/x11_util.cc b/chromium/ui/base/x/x11_util.cc
index 7a10483eaec..544d5fdbfec 100644
--- a/chromium/ui/base/x/x11_util.cc
+++ b/chromium/ui/base/x/x11_util.cc
@@ -1299,6 +1299,14 @@ gfx::ICCProfile GetICCProfileForMonitor(int monitor) {
return icc_profile;
}
+bool IsSyncExtensionAvailable() {
+ auto* display = gfx::GetXDisplay();
+ int unused;
+ static bool result = XSyncQueryExtension(display, &unused, &unused) &&
+ XSyncInitialize(display, &unused, &unused);
+ return result;
+}
+
XRefcountedMemory::XRefcountedMemory(unsigned char* x11_data, size_t length)
: x11_data_(length ? x11_data : nullptr), length_(length) {
}
diff --git a/chromium/ui/base/x/x11_util.h b/chromium/ui/base/x/x11_util.h
index ee367584b40..daf755e4403 100644
--- a/chromium/ui/base/x/x11_util.h
+++ b/chromium/ui/base/x/x11_util.h
@@ -301,6 +301,9 @@ UI_BASE_X_EXPORT bool WmSupportsHint(XAtom atom);
// Returns the ICCProfile corresponding to |monitor| using XGetWindowProperty.
UI_BASE_X_EXPORT gfx::ICCProfile GetICCProfileForMonitor(int monitor);
+// Return true if the display supports SYNC extension.
+UI_BASE_X_EXPORT bool IsSyncExtensionAvailable();
+
// 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.