diff --git a/AUTHORS b/AUTHORS index ce240aa..840f9f2 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -383,6 +383,7 @@ Evgeny Agafonchikov <evgeny.agafonchikov@akvelon.com> Fabian Henneke <fabian.henneke@gmail.com> Fabien Tassin <fta@sofaraway.org> +Fan Wen <fan.wen.dev@gmail.com> Feifei Wang <alexswang@tencent.com> Felipe Erias Morandeira <felipeerias@gmail.com> Felix H. Dahlke <fhd@ubercode.de>
diff --git a/DEPS b/DEPS index 7ee58ee..37c97c5 100644 --- a/DEPS +++ b/DEPS
@@ -309,15 +309,15 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'd5846fb1f236b9a115f0acd432daa3de18a64419', + 'skia_revision': '2e4223a5f4bf0d20e9862ddd9c44bd0db669482a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '9896bae00b80769ae185b10c4217a2a3e4175a1f', + 'v8_revision': '02bb74d5a62e165ec611839563f66ae9f665a7d0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '9ae918cbd468a0b36475ce67564189eee37f3568', + 'angle_revision': '70f1bf2aad5939ac54ae1b08138cdb10a2680b7e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -325,7 +325,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '850454b6edc7cbd5427de1c19d03e0dc9f63cb6b', + 'pdfium_revision': 'ca3e52a5e4cba5e557ca390f1f1b1496a621b752', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -336,7 +336,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Fuchsia sdk # and whatever else without interference from each other. - 'fuchsia_version': 'version:12.20230412.3.1', + 'fuchsia_version': 'version:12.20230413.0.1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling google-toolbox-for-mac # and whatever else without interference from each other. @@ -396,7 +396,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': 'a6184b773b6cc2b1328777f296bbe0e5a61ddc67', + 'devtools_frontend_revision': 'd01f6a99a5dd2e2bf3471b3afaf66c8d048b51ac', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -436,7 +436,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '3dba94c1d4f113894a878c8ff7709fd4c75b6e8c', + 'dawn_revision': '7c6e873c013f0a3289ad43670c256f18f28276bd', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -460,7 +460,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. - 'nearby_revision': '28f7498580d586ccd0855deaf45057f0498cf5a3', + 'nearby_revision': '37225fab5abf6d897e16c43082b64ed7bdd0fc3c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -472,7 +472,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'cros_components_revision': 'ea96a126b2f418f7e8d64b6dd9d4644f65dc96b6', + 'cros_components_revision': '16652902a23064cd599d7d4049f6e17e365dbcbe', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -795,7 +795,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - 'd24b8851c95b4d40302534895e44111162ec96af', + 'df3c84bdbd04a4324d8e33c8c7ef2a6590263fc9', 'condition': 'checkout_android and checkout_src_internal', }, @@ -984,7 +984,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '0iBHIye2VF9ikEfHvOSFmKHtYuzwGC9TltUjKDEgsKsC', + 'version': 'zWtfYsyHW87Yb3r-WN7EKvOX4uOCccgjboxpDG3dyUsC', }, ], 'condition': 'checkout_android', @@ -1219,13 +1219,13 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '88f79dd119bffa65169f1a062f3f5a7155569c97', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3ca8d0d0caa46532b338c221dbff03220a64bfc1', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '541fe2aea7ad36c962116946870c8eedd2ce6a9e', + 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '172dbf3f463ef70ec79c68536af20280eab43e40', 'condition': 'checkout_src_internal', }, @@ -1233,7 +1233,7 @@ Var('chromium_git') + '/chromium/dom-distiller/dist.git' + '@' + '199de96b345ada7c6e7e6ba3d2fa7a6911b8767d', 'src/third_party/eigen3/src': - Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '33e206f714d16f03cd31fd7bf1aa9d3a0ef66a5e', + Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + 'b0eded878d5d162d61583a286c0d8a45406ad1bc', 'src/third_party/emoji-metadata/src': { 'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '045f146fca682a836e01cd265171312bfb300e06', @@ -1832,7 +1832,7 @@ Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f', 'src/third_party/tflite/src': - Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '364fd6c6121aa3fef8d5ba1909a16664db5fe4c7', + Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + 'ca3bc50b524364bb4d5e587f9de6e339f8fcc485', 'src/third_party/turbine': { 'packages': [ @@ -1885,7 +1885,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '0ac5d460dab4d56f3c07c43eee895557c9d3b9e4', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '921448fbc6765e59590fc4a76d7e5d51ec52b9ca', + Var('webrtc_git') + '/src.git' + '@' + '0ae4d249c71b0ecfc9031efc947e98cfa9f596df', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -1910,7 +1910,7 @@ }, 'src/third_party/xnnpack/src': - Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + '7adae8e6ded8fff33d92212ca1028d2419cd34d4', + Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + 'b9d4073a6913891ce9cbd8965c8d506075d2a45a', 'src/tools/page_cycler/acid3': Var('chromium_git') + '/chromium/deps/acid3.git' + '@' + '6be0a66a1ebd7ebc5abc1b2f405a945f6d871521',
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 4b014b96..f326e10 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -2575,6 +2575,18 @@ <message name="IDS_ASH_HOTSPOT_ON_TITLE" desc="Title used for the system notification shown when the hotspot is turned on."> Hotspot is on </message> + <message name="IDS_ASH_HOTSPOT_ON_MESSAGE_MULTIPLE_CONNECTED_DEVICES" desc="Message displayed in the notification when hotspot is turned on and multiple devices are connected."> + <ph name="DEVICECOUNT">$1</ph> devices connected + </message> + <message name="IDS_ASH_HOTSPOT_ON_MESSAGE_ONE_CONNECTED_DEVICE" desc="Message displayed in the notification when hotspot is turned on and one device is connected."> + 1 device connected + </message> + <message name="IDS_ASH_HOTSPOT_ON_MESSAGE_NO_CONNECTED_DEVICES" desc="Message displayed in the notification when hotspot is turned on and no devices are connected."> + No devices connected + </message> + <message name="IDS_ASH_TURN_OFF_HOTSPOT_LABEL" desc="The label for button used to turn off hotspot."> + Turn off + </message> <message name="IDS_ASH_HOTSPOT_OFF_TITLE" desc="Title used for the system notification shown when the hotspot is turned off."> Hotspot is off </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_HOTSPOT_ON_MESSAGE_MULTIPLE_CONNECTED_DEVICES.png.sha1 b/ash/ash_strings_grd/IDS_ASH_HOTSPOT_ON_MESSAGE_MULTIPLE_CONNECTED_DEVICES.png.sha1 new file mode 100644 index 0000000..18b1aec --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_HOTSPOT_ON_MESSAGE_MULTIPLE_CONNECTED_DEVICES.png.sha1
@@ -0,0 +1 @@ +02efe7ea590aa85dc659d137648aaafd7423fb1e \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_HOTSPOT_ON_MESSAGE_NO_CONNECTED_DEVICES.png.sha1 b/ash/ash_strings_grd/IDS_ASH_HOTSPOT_ON_MESSAGE_NO_CONNECTED_DEVICES.png.sha1 new file mode 100644 index 0000000..f7f592a --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_HOTSPOT_ON_MESSAGE_NO_CONNECTED_DEVICES.png.sha1
@@ -0,0 +1 @@ +5a60463112cfbbd5b9a8ed3943f9d1079bfdf297 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_HOTSPOT_ON_MESSAGE_ONE_CONNECTED_DEVICE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_HOTSPOT_ON_MESSAGE_ONE_CONNECTED_DEVICE.png.sha1 new file mode 100644 index 0000000..1a0af2cf --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_HOTSPOT_ON_MESSAGE_ONE_CONNECTED_DEVICE.png.sha1
@@ -0,0 +1 @@ +4069dca2539c3710d4442c525b181e1e5d0ed488 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_TURN_OFF_HOTSPOT_LABEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_TURN_OFF_HOTSPOT_LABEL.png.sha1 new file mode 100644 index 0000000..28878ae --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_TURN_OFF_HOTSPOT_LABEL.png.sha1
@@ -0,0 +1 @@ +a821d35b75651ddc38241482c5293a34e6c2105b \ No newline at end of file
diff --git a/ash/login/LOGIN_LOCK_METADATA b/ash/login/LOGIN_LOCK_METADATA index 14fae48..042eb1b 100644 --- a/ash/login/LOGIN_LOCK_METADATA +++ b/ash/login/LOGIN_LOCK_METADATA
@@ -1,8 +1,20 @@ +# For more information on DIR_METADATA files, see: +# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/README.md +# +# For the schema of this file, see Metadata message: +# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto + buganizer { + # https://b.corp.google.com/issues?q=status:open%20componentid:1207311 + # ChromeOS > Software > Commercial (Enterprise) > Identity > LURS component_id: 1207311 } + buganizer_public { + # https://issuetracker.google.com/issues?q=status:open%20componentid:1277523 + # ChromeOS Public Tracker > UI > Login and Unlock component_id: 1277523 } + team_email : "cros-lurs@google.com" os: CHROME_OS \ No newline at end of file
diff --git a/ash/system/network/hotspot_notifier.cc b/ash/system/network/hotspot_notifier.cc index ddaf36a3..b0e9452 100644 --- a/ash/system/network/hotspot_notifier.cc +++ b/ash/system/network/hotspot_notifier.cc
@@ -7,6 +7,7 @@ #include "ash/public/cpp/network_config_service.h" #include "ash/public/cpp/notification_utils.h" #include "ash/strings/grit/ash_strings.h" +#include "base/strings/utf_string_conversions.h" #include "ui/base/l10n/l10n_util.h" #include "ui/message_center/message_center.h" #include "ui/message_center/public/cpp/message_center_constants.h" @@ -29,6 +30,9 @@ const char HotspotNotifier::kInternalErrorNotificationId[] = "cros_hotspot_notifier_ids.internal_error"; +const char HotspotNotifier::kHotspotTurnedOnNotificationId[] = + "cros_hotspot_notifier_ids.hotspot_turned_on"; + const char kNotifierHotspot[] = "ash.hotspot"; HotspotNotifier::HotspotNotifier() { @@ -41,6 +45,8 @@ remote_cros_network_config_.BindNewPipeAndPassReceiver()); remote_cros_network_config_->AddObserver( cros_network_config_observer_receiver_.BindNewPipeAndPassRemote()); + remote_cros_hotspot_config_->AddObserver( + hotspot_config_observer_receiver_.BindNewPipeAndPassRemote()); } HotspotNotifier::~HotspotNotifier() = default; @@ -55,9 +61,10 @@ std::vector<message_center::ButtonInfo> notification_actions; std::unique_ptr<message_center::Notification> notification = - CreateNotification(IDS_ASH_HOTSPOT_ON_TITLE, - IDS_ASH_HOTSPOT_WIFI_TURNED_OFF_MESSAGE, - kWiFiTurnedOffNotificationId, delegate); + CreateNotification( + l10n_util::GetStringUTF16(IDS_ASH_HOTSPOT_ON_TITLE), + l10n_util::GetStringUTF16(IDS_ASH_HOTSPOT_WIFI_TURNED_OFF_MESSAGE), + kWiFiTurnedOffNotificationId, delegate); notification_actions.push_back( message_center::ButtonInfo(l10n_util::GetStringUTF16( IDS_ASH_HOTSPOT_NOTIFICATION_WIFI_TURN_ON_BUTTON))); @@ -118,7 +125,9 @@ return; } std::unique_ptr<message_center::Notification> notification = - CreateNotification(title_id, message_id, notification_id, delegate); + CreateNotification(l10n_util::GetStringUTF16(title_id), + l10n_util::GetStringUTF16(message_id), notification_id, + delegate); if (notification_actions.size() > 0) { notification->set_buttons(notification_actions); @@ -131,6 +140,72 @@ message_center->AddNotification(std::move(notification)); } +void HotspotNotifier::OnHotspotInfoChanged() { + remote_cros_hotspot_config_->GetHotspotInfo(base::BindOnce( + &HotspotNotifier::OnGetHotspotInfo, weak_ptr_factory_.GetWeakPtr())); +} + +void HotspotNotifier::OnGetHotspotInfo( + hotspot_config::mojom::HotspotInfoPtr hotspot_info) { + message_center::MessageCenter* message_center = + message_center::MessageCenter::Get(); + if (hotspot_info->state == hotspot_config::mojom::HotspotState::kDisabled) { + message_center->RemoveNotification(kHotspotTurnedOnNotificationId, + /*by_user=*/false); + return; + } + + if (hotspot_info->state == hotspot_config::mojom::HotspotState::kEnabled) { + const std::u16string& title = + l10n_util::GetStringUTF16(IDS_ASH_HOTSPOT_ON_TITLE); + const std::u16string& message = + (hotspot_info->client_count == 0) + ? l10n_util::GetStringUTF16( + IDS_ASH_HOTSPOT_ON_MESSAGE_NO_CONNECTED_DEVICES) + : (hotspot_info->client_count == 1) + ? l10n_util::GetStringUTF16( + IDS_ASH_HOTSPOT_ON_MESSAGE_ONE_CONNECTED_DEVICE) + : l10n_util::GetStringFUTF16( + IDS_ASH_HOTSPOT_ON_MESSAGE_MULTIPLE_CONNECTED_DEVICES, + base::NumberToString16(hotspot_info->client_count)); + scoped_refptr<message_center::NotificationDelegate> delegate = + base::MakeRefCounted<message_center::HandleNotificationClickDelegate>( + base::BindRepeating(&HotspotNotifier::DisableHotspotHandler, + weak_ptr_factory_.GetWeakPtr(), + kHotspotTurnedOnNotificationId)); + std::vector<message_center::ButtonInfo> notification_actions; + notification_actions.push_back(message_center::ButtonInfo( + l10n_util::GetStringUTF16(IDS_ASH_TURN_OFF_HOTSPOT_LABEL))); + std::unique_ptr<message_center::Notification> notification = + CreateNotification(title, message, kHotspotTurnedOnNotificationId, + delegate); + notification->set_pinned(/*pinned=*/true); + notification->set_buttons(notification_actions); + message_center->AddNotification(std::move(notification)); + } +} + +void HotspotNotifier::DisableHotspotHandler(const char* notification_id, + absl::optional<int> button_index) { + if (!button_index) { + return; + } + + if (button_index.value() == 0) { + remote_cros_hotspot_config_->DisableHotspot( + base::BindOnce([](hotspot_config::mojom::HotspotControlResult result) { + if (result == hotspot_config::mojom::HotspotControlResult::kSuccess || + result == hotspot_config::mojom::HotspotControlResult:: + kAlreadyFulfilled) { + message_center::MessageCenter* message_center = + message_center::MessageCenter::Get(); + message_center->RemoveNotification(kHotspotTurnedOnNotificationId, + /*by_user=*/false); + } + })); + } +} + void HotspotNotifier::EnableHotspotHandler(const char* notification_id, absl::optional<int> button_index) { if (!button_index) { @@ -190,15 +265,14 @@ std::unique_ptr<message_center::Notification> HotspotNotifier::CreateNotification( - const int title_id, - const int message_id, + const std::u16string& title_id, + const std::u16string& message_id, const char* notification_id, scoped_refptr<message_center::NotificationDelegate> delegate) { std::unique_ptr<message_center::Notification> notification = ash::CreateSystemNotificationPtr( - message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, - l10n_util::GetStringUTF16(title_id), - l10n_util::GetStringUTF16(message_id), + message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title_id, + message_id, /*display_source=*/std::u16string(), GURL(), message_center::NotifierId( message_center::NotifierType::SYSTEM_COMPONENT, kNotifierHotspot,
diff --git a/ash/system/network/hotspot_notifier.h b/ash/system/network/hotspot_notifier.h index b594142..8b96dccd 100644 --- a/ash/system/network/hotspot_notifier.h +++ b/ash/system/network/hotspot_notifier.h
@@ -26,6 +26,7 @@ // - Hotspot is turned on and has 'n' active connections class ASH_EXPORT HotspotNotifier : public hotspot_config::mojom::HotspotEnabledStateObserver, + public hotspot_config::mojom::CrosHotspotConfigObserver, public chromeos::network_config::CrosNetworkConfigObserver { public: HotspotNotifier(); @@ -38,6 +39,7 @@ static const char kWiFiTurnedOnNotificationId[]; static const char kAutoDisabledNotificationId[]; static const char kInternalErrorNotificationId[]; + static const char kHotspotTurnedOnNotificationId[]; private: friend class HotspotNotifierTest; @@ -54,9 +56,17 @@ std::vector<chromeos::network_config::mojom::DeviceStatePropertiesPtr> devices); + // mojom::CrosHotspotConfigObserver: + void OnHotspotInfoChanged() override; + + void OnGetHotspotInfo(hotspot_config::mojom::HotspotInfoPtr hotspot_info); + + void DisableHotspotHandler(const char* notification_id, + absl::optional<int> index); + std::unique_ptr<message_center::Notification> CreateNotification( - const int title_id, - const int message_id, + const std::u16string& title_id, + const std::u16string& message_id, const char* notification_id, scoped_refptr<message_center::NotificationDelegate> delegate); @@ -73,6 +83,8 @@ cros_network_config_observer_receiver_{this}; mojo::Receiver<hotspot_config::mojom::HotspotEnabledStateObserver> hotspot_enabled_state_observer_receiver_{this}; + mojo::Receiver<hotspot_config::mojom::CrosHotspotConfigObserver> + hotspot_config_observer_receiver_{this}; base::WeakPtrFactory<HotspotNotifier> weak_ptr_factory_{this}; };
diff --git a/ash/system/network/hotspot_notifier_unittest.cc b/ash/system/network/hotspot_notifier_unittest.cc index 835823e..7b8debe 100644 --- a/ash/system/network/hotspot_notifier_unittest.cc +++ b/ash/system/network/hotspot_notifier_unittest.cc
@@ -25,6 +25,18 @@ const char kCellularServicePath[] = "/service/cellular0"; const char kCellularServiceGuid[] = "cellular_guid0"; const char kCellularServiceName[] = "cellular_name0"; +const char kHotspotConfigSSID[] = "hotspot_SSID"; +const char kHotspotConfigPassphrase[] = "hotspot_passphrase"; + +hotspot_config::mojom::HotspotConfigPtr GenerateTestConfig() { + auto mojom_config = hotspot_config::mojom::HotspotConfig::New(); + mojom_config->auto_disable = false; + mojom_config->band = hotspot_config::mojom::WiFiBand::kAutoChoose; + mojom_config->security = hotspot_config::mojom::WiFiSecurityMode::kWpa2; + mojom_config->ssid = kHotspotConfigSSID; + mojom_config->passphrase = kHotspotConfigPassphrase; + return mojom_config; +} } // namespace @@ -100,6 +112,11 @@ base::RunLoop().RunUntilIdle(); } + void SetHotspotConfig(hotspot_config::mojom::HotspotConfigPtr mojom_config) { + cros_hotspot_config_test_helper_->SetHotspotConfig(std::move(mojom_config)); + base::RunLoop().RunUntilIdle(); + } + void NotifyHotspotTurnedOff( hotspot_config::mojom::DisableReason disable_reason) { NetworkHandler* network_handler = NetworkHandler::Get(); @@ -114,6 +131,14 @@ base::RunLoop().RunUntilIdle(); } + void SetHotspotStateInShill(const std::string& state) { + base::Value::Dict status_dict; + status_dict.Set(shill::kTetheringStatusStateProperty, state); + network_handler_test_helper_->manager_test()->SetManagerProperty( + shill::kTetheringStatusProperty, base::Value(std::move(status_dict))); + base::RunLoop().RunUntilIdle(); + } + base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<NetworkHandlerTestHelper> network_handler_test_helper_; std::unique_ptr<network_config::CrosNetworkConfigTestHelper> @@ -224,4 +249,27 @@ HotspotNotifier::kInternalErrorNotificationId)); } +TEST_F(HotspotNotifierTest, HotspotTurnedOn) { + SetValidHotspotCapabilities(); + SetReadinessCheckResultReady(); + AddActiveCellularService(); + helper()->manager_test()->SetSimulateTetheringEnableResult( + FakeShillSimulatedResult::kSuccess, shill::kTetheringEnableResultSuccess); + base::RunLoop().RunUntilIdle(); + + SetHotspotConfig(GenerateTestConfig()); + EnableHotspot(); + SetHotspotStateInShill(shill::kTetheringStateActive); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(message_center::MessageCenter::Get()->FindVisibleNotificationById( + HotspotNotifier::kHotspotTurnedOnNotificationId)); + + message_center::MessageCenter::Get()->ClickOnNotificationButton( + HotspotNotifier::kHotspotTurnedOnNotificationId, 0); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE( + message_center::MessageCenter::Get()->FindVisibleNotificationById( + HotspotNotifier::kHotspotTurnedOnNotificationId)); +} + } // namespace ash
diff --git a/ash/webui/camera_app_ui/PRESUBMIT.py b/ash/webui/camera_app_ui/PRESUBMIT.py index a4f8f391..c726afa 100644 --- a/ash/webui/camera_app_ui/PRESUBMIT.py +++ b/ash/webui/camera_app_ui/PRESUBMIT.py
@@ -33,6 +33,9 @@ results += _CheckHtml(input_api, output_api) if any(f for f in affected if f.LocalPath() in STRING_RESOURCE_FILES): results += _CheckStringResouce(input_api, output_api) + if any(f for f in affected if f.LocalPath().endswith('metrics.ts')): + results += _CheckModifyMetrics(input_api, output_api) + return results @@ -52,3 +55,19 @@ ] return [] + + +def _CheckModifyMetrics(input_api, output_api): + if not input_api.change.METRICS_DOCUMENTATION_UPDATED: + return [ + output_api.PresubmitPromptWarning( + 'Metrics are modified but `METRICS_DOCUMENTATION_UPDATED=true` is ' + + 'not found in the commit messages.\n' + + 'The CL author should confirm CCA metrics are still synced in ' + + 'PDD (go/cca-metrics-pdd) and Schema (go/cca-metrics-schema).\n' + + 'Once done, the CL author should explicitly claim it by including ' + + '`METRICS_DOCUMENTATION_UPDATED=true` in the commit messages.' + ) + ] + + return []
diff --git a/ash/wm/client_controlled_state.cc b/ash/wm/client_controlled_state.cc index b78b898f..e0b30f1 100644 --- a/ash/wm/client_controlled_state.cc +++ b/ash/wm/client_controlled_state.cc
@@ -24,6 +24,7 @@ #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" +#include "ui/compositor/layer.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/wm/core/window_util.h" @@ -188,12 +189,19 @@ const WMEvent* event) { if (!delegate_) return; + auto* const window = window_state->window(); switch (event->type()) { case WM_EVENT_SET_BOUNDS: { const auto* set_bounds_event = static_cast<const SetBoundsWMEvent*>(event); const gfx::Rect& bounds = set_bounds_event->requested_bounds(); if (set_bounds_locally_) { + // Don’t preempt on-going animation (e.g. tucking) for floated windows. + if (window_state->IsFloated() && window->layer() && + window->layer()->GetAnimator()->is_animating()) { + return; + } + switch (next_bounds_change_animation_type_) { case WindowState::BoundsChangeAnimationType::kNone: window_state->SetBoundsDirect(bounds); @@ -221,7 +229,6 @@ // TODO(oshima): Define behavior for pinned app. bounds_change_animation_duration_ = set_bounds_event->duration(); int64_t display_id = set_bounds_event->display_id(); - auto* window = window_state->window(); if (display_id == display::kInvalidDisplayId) { display_id = display::Screen::GetScreen() ->GetDisplayNearestWindow(window)
diff --git a/ash/wm/client_controlled_state_unittest.cc b/ash/wm/client_controlled_state_unittest.cc index 85bf0b3..bacaa12 100644 --- a/ash/wm/client_controlled_state_unittest.cc +++ b/ash/wm/client_controlled_state_unittest.cc
@@ -10,6 +10,7 @@ #include "ash/frame/non_client_frame_view_ash.h" #include "ash/public/cpp/shelf_config.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/screen_util.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" @@ -36,6 +37,7 @@ #include "chromeos/ui/wm/features.h" #include "chromeos/ui/wm/window_util.h" #include "ui/aura/client/aura_constants.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_conversions.h" @@ -915,6 +917,53 @@ gfx::Rect(gfx::Point(padding, padding), initial_bounds.size())); } +TEST_F(ClientControlledStateTest, TuckFloatedWindowInTabletMode) { + ui::ScopedAnimationDurationScaleMode test_duration_mode( + ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); + + auto* const float_controller = Shell::Get()->float_controller(); + + // The AppType must be set to any except `AppType::NON_APP` (default value) to + // make it floatable. + window()->SetProperty(aura::client::kAppType, + static_cast<int>(AppType::ARC_APP)); + widget_delegate()->EnableFloat(); + ASSERT_TRUE(chromeos::wm::CanFloatWindow(window())); + + // Enter tablet mode + Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true); + ASSERT_TRUE(Shell::Get()->tablet_mode_controller()->InTabletMode()); + + // Float window. + const WMEvent float_event(WM_EVENT_FLOAT); + window_state()->OnWMEvent(&float_event); + ApplyPendingRequestedBounds(); + state()->EnterNextState(window_state(), delegate()->new_state()); + EXPECT_TRUE(window_state()->IsFloated()); + EXPECT_EQ(kShellWindowId_FloatContainer, window()->parent()->GetId()); + + // Start dragging in the center of the header and fling it to offscreen. + auto* const header_view = GetHeaderView(); + auto* const event_generator = GetEventGenerator(); + const gfx::Point start = header_view->GetBoundsInScreen().CenterPoint(); + const gfx::Vector2d offset(10, 10); + + event_generator->GestureScrollSequence(start, start + offset, + base::Milliseconds(10), /*steps=*/1); + + // Bounds change should be blocked while animating. + const auto start_bounds = window()->GetBoundsInScreen(); + state()->set_bounds_locally(true); + widget()->SetBounds(gfx::Rect(0, 0, 256, 256)); + state()->set_bounds_locally(false); + EXPECT_EQ(window()->GetBoundsInScreen(), start_bounds); + + EXPECT_TRUE(window()->IsVisible()); + ShellTestApi().WaitForWindowFinishAnimating(window()); + EXPECT_FALSE(window()->IsVisible()); + EXPECT_TRUE(float_controller->IsFloatedWindowTuckedForTablet(window())); +} + TEST_P(ClientControlledStateTestClamshellAndTablet, MoveFloatedWindow) { // The AppType must be set to any except `AppType::NON_APP` (default value) to // make it floatable.
diff --git a/base/allocator/partition_alloc_features.cc b/base/allocator/partition_alloc_features.cc index a68a4bb3..8cae694 100644 --- a/base/allocator/partition_alloc_features.cc +++ b/base/allocator/partition_alloc_features.cc
@@ -138,10 +138,12 @@ {BackupRefPtrMode::kDisabled, "disabled"}, {BackupRefPtrMode::kEnabled, "enabled"}, {BackupRefPtrMode::kEnabledWithoutZapping, "enabled-without-zapping"}, - {BackupRefPtrMode::kEnabledWithoutMemoryReclaimer, - "enabled-without-memory-reclaimer"}, + {BackupRefPtrMode::kEnabledWithMemoryReclaimer, + "enabled-with-memory-reclaimer"}, {BackupRefPtrMode::kDisabledButSplitPartitions2Way, "disabled-but-2-way-split"}, + {BackupRefPtrMode::kDisabledButSplitPartitions2WayWithMemoryReclaimer, + "disabled-but-2-way-split-with-memory-reclaimer"}, {BackupRefPtrMode::kDisabledButSplitPartitions3Way, "disabled-but-3-way-split"}, {BackupRefPtrMode::kDisabledButAddDummyRefCount,
diff --git a/base/allocator/partition_alloc_features.h b/base/allocator/partition_alloc_features.h index ebfd38e9..7398916 100644 --- a/base/allocator/partition_alloc_features.h +++ b/base/allocator/partition_alloc_features.h
@@ -90,14 +90,17 @@ // Same as kEnabled but without zapping quarantined objects. kEnabledWithoutZapping, - // Same as kEnabled but without registering the main partition to memory - // reclaimer. - kEnabledWithoutMemoryReclaimer, + // Same as kEnabled but registers the main partition to memory reclaimer. + kEnabledWithMemoryReclaimer, // BRP is disabled, but the main partition is split out, as if BRP was enabled // in the "previous slot" mode. kDisabledButSplitPartitions2Way, + // Same as kDisabledButSplitPartitions2Way but registers the main partition to + // memory reclaimer. + kDisabledButSplitPartitions2WayWithMemoryReclaimer, + // BRP is disabled, but the main partition *and* aligned partition are split // out, as if BRP was enabled in the "before allocation" mode. kDisabledButSplitPartitions3Way,
diff --git a/base/allocator/partition_alloc_support.cc b/base/allocator/partition_alloc_support.cc index 6405b5e6..4a48f767 100644 --- a/base/allocator/partition_alloc_support.cc +++ b/base/allocator/partition_alloc_support.cc
@@ -338,16 +338,20 @@ brp_group_name = "EnabledBeforeAllocWithoutZapping"; #endif break; - case features::BackupRefPtrMode::kEnabledWithoutMemoryReclaimer: + case features::BackupRefPtrMode::kEnabledWithMemoryReclaimer: #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT) - brp_group_name = "EnabledPrevSlotWithoutMemoryReclaimer"; + brp_group_name = "EnabledPrevSlotWithMemoryReclaimer"; #else - brp_group_name = "EnabledBeforeAllocWithoutMemoryReclaimer"; + brp_group_name = "EnabledBeforeAllocWithMemoryReclaimer"; #endif break; case features::BackupRefPtrMode::kDisabledButSplitPartitions2Way: brp_group_name = "DisabledBut2WaySplit"; break; + case features::BackupRefPtrMode:: + kDisabledButSplitPartitions2WayWithMemoryReclaimer: + brp_group_name = "DisabledBut2WaySplitWithMemoryReclaimer"; + break; case features::BackupRefPtrMode::kDisabledButSplitPartitions3Way: brp_group_name = "DisabledBut3WaySplit"; break; @@ -859,7 +863,7 @@ bool use_dedicated_aligned_partition = false; bool add_dummy_ref_count = false; bool process_affected_by_brp_flag = false; - bool disable_memory_reclaimer = false; + bool enable_memory_reclaimer = false; #if (BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \ BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)) || \ @@ -897,8 +901,8 @@ // Do nothing. Equivalent to !IsEnabled(kPartitionAllocBackupRefPtr). break; - case base::features::BackupRefPtrMode::kEnabledWithoutMemoryReclaimer: - disable_memory_reclaimer = true; + case base::features::BackupRefPtrMode::kEnabledWithMemoryReclaimer: + enable_memory_reclaimer = true; ABSL_FALLTHROUGH_INTENDED; case base::features::BackupRefPtrMode::kEnabled: enable_brp_zapping = true; @@ -923,6 +927,12 @@ split_main_partition = true; break; + case base::features::BackupRefPtrMode:: + kDisabledButSplitPartitions2WayWithMemoryReclaimer: + split_main_partition = true; + enable_memory_reclaimer = true; + break; + case base::features::BackupRefPtrMode::kDisabledButSplitPartitions3Way: split_main_partition = true; use_dedicated_aligned_partition = true; @@ -942,7 +952,7 @@ return {enable_brp, enable_brp_zapping, - !disable_memory_reclaimer, + enable_memory_reclaimer, split_main_partition, use_dedicated_aligned_partition, add_dummy_ref_count,
diff --git a/base/allocator/partition_allocator/dot/bucket.dot b/base/allocator/partition_allocator/dot/bucket.dot new file mode 100644 index 0000000..c4d60060 --- /dev/null +++ b/base/allocator/partition_allocator/dot/bucket.dot
@@ -0,0 +1,60 @@ +digraph { + graph[bgcolor=transparent] + node[shape=plaintext] + edge[style=dashed, color=crimson] + + page1[label=< + <table border="0" cellborder="1" cellspacing="0"><tr> + <!-- head partition page --> + <td port="head" bgcolor="darkgrey" width="40" height="52"></td> + <!-- bucket-external memory - not depicted --> + <td width="160"></td> + <!-- a slot span in this bucket --> + <td port="slotspan" bgcolor="crimson" width="80"></td> + <!-- bucket-external memory - not depicted --> + <td width="320"></td> + <!-- tail partition page --> + <td bgcolor="darkgrey" width="40"></td> + </tr></table> + >] + page2[label=< + <table border="0" cellborder="1" cellspacing="0"><tr> + <!-- head partition page --> + <td port="head" bgcolor="darkgrey" width="40" height="52"></td> + <!-- bucket-external memory - not depicted --> + <td width="280"></td> + <!-- a slot span in this bucket --> + <td port="slotspan" bgcolor="crimson" width="80"></td> + <!-- bucket-external memory - not depicted --> + <td width="200"></td> + <!-- tail partition page --> + <td bgcolor="darkgrey" width="40"></td> + </tr></table> + >] + page3[label=< + <table border="0" cellborder="1" cellspacing="0"><tr> + <!-- head partition page --> + <td port="head" bgcolor="darkgrey" width="40" height="52"></td> + <!-- bucket-external memory - not depicted --> + <td width="40"></td> + <!-- a slot span in this bucket --> + <td port="slotspan1" bgcolor="crimson" width="80"></td> + <!-- bucket-external memory - not depicted --> + <td width="120"></td> + <!-- a slot span in this bucket --> + <td port="slotspan2" bgcolor="crimson" width="80"></td> + <!-- bucket-external memory - not depicted --> + <td width="240"></td> + <!-- tail partition page --> + <td bgcolor="darkgrey" width="40"></td> + </tr></table> + >] + + // Invisibly link the head partition pages to force alignment. + page1:head->page2:head->page3:head[style=invis] + + // Inter-super-page links disable constraints so to let the above + // fully control alignment. + page1:slotspan->page2:slotspan->page3:slotspan1[constraint=false] + page3:slotspan1:s->page3:slotspan2:sw +}
diff --git a/base/allocator/partition_allocator/dot/bucket.png b/base/allocator/partition_allocator/dot/bucket.png new file mode 100644 index 0000000..bf7374b1b --- /dev/null +++ b/base/allocator/partition_allocator/dot/bucket.png Binary files differ
diff --git a/base/allocator/partition_allocator/glossary.md b/base/allocator/partition_allocator/glossary.md index f7394a98..34fd688 100644 --- a/base/allocator/partition_allocator/glossary.md +++ b/base/allocator/partition_allocator/glossary.md
@@ -4,8 +4,6 @@ A weak attempt is made to present terms "in conceptual order" s.t. each term depends mainly upon previously defined ones. -## Top-Level Terms - * **Partition**: A heap that is separated and protected both from other partitions and from non-PartitionAlloc memory. Each partition holds multiple buckets. @@ -15,18 +13,6 @@ "allocator" are all conceptually the same thing. *** -* **Bucket**: A collection of regions in a partition that contains - similar-sized objects. For example, one bucket may hold objects of - size (224, 256], another (256, 320], etc. Bucket size - brackets are geometrically spaced, - [going up to `kMaxBucketed`][max-bucket-comment]. -* **Normal Bucket**: Any bucket whose size ceiling does not exceed - `kMaxBucketed`. This is the common case in PartitionAlloc, and - the "normal" modifier is often dropped in casual reference. -* **Direct Map (Bucket)**: Any allocation whose size exceeds `kMaxBucketed`. - -Buckets consist of slot spans, organized as linked lists (see below). - ## Pages * **System Page**: A memory page defined by the CPU/OS. Commonly @@ -78,6 +64,24 @@ are often handled by a different code path, and that distinction is made purely based on slot size, for simplicity and efficiency. +## Buckets + +* **Bucket**: A collection of regions in a partition that contains + similar-sized objects. For example, one bucket may hold objects of + size (224, 256], another (256, 320], etc. Bucket size + brackets are geometrically spaced, + [going up to `kMaxBucketed`][max-bucket-comment]. + * Plainly put, all slots (ergo the resulting spans) of a given size + class are logically chained into one bucket. + + + +* **Normal Bucket**: Any bucket whose size ceiling does not exceed + `kMaxBucketed`. This is the common case in PartitionAlloc, and + the "normal" modifier is often dropped in casual reference. +* **Direct Map (Bucket)**: Any allocation whose size exceeds `kMaxBucketed`. + ## Other Terms * **Object**: A chunk of memory returned to the allocating invoker
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index 1205a19..a34f9e2 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -12.20230412.2.1 +12.20230413.0.1
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh index c59f9a8..de4081dc 100755 --- a/build/install-build-deps.sh +++ b/build/install-build-deps.sh
@@ -259,6 +259,7 @@ libglib2.0-0 libgl1 libgtk-3-0 + libncurses5 libpam0g libpango-1.0-0 libpangocairo-1.0-0
diff --git a/chrome/VERSION b/chrome/VERSION index 02f3a68..4ba305c 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=114 MINOR=0 -BUILD=5712 +BUILD=5713 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 7fff9253..0b3f429 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -2246,9 +2246,9 @@ QuickDeleteMetricsDelegate.recordHistogram( QuickDeleteMetricsDelegate.QuickDeleteAction.MENU_ITEM_CLICKED); - QuickDeleteController quickDeleteController = - new QuickDeleteController(this, new QuickDeleteDelegateImpl(), - getModalDialogManager(), getSnackbarManager(), getLayoutManager()); + QuickDeleteController quickDeleteController = new QuickDeleteController(this, + new QuickDeleteDelegateImpl(), getModalDialogManager(), getSnackbarManager(), + getLayoutManager(), mTabModelSelector); quickDeleteController.triggerQuickDeleteFlow(); } else { return super.onMenuOrKeyboardAction(id, fromMenu);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java index bffc71e7..d016556 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java
@@ -45,6 +45,8 @@ * An address editor. Can be used for either shipping or billing address editing. */ public class AddressEditor extends EditorBase<AutofillAddress> { + private static final Set<String> SANCTIONED_CONTRIES = Set.of("CU", "IR", "KP", "SD", "SY"); + private final Handler mHandler = new Handler(); private final Map<Integer, EditorFieldModel> mAddressFields = new HashMap<>(); private final Set<CharSequence> mPhoneNumbers = new HashSet<>(); @@ -107,6 +109,18 @@ return addressFields; } + // TODO(crbug.com/1432505): remove temporary sanctioned countries filtering. + private static List<EditorFieldModel.DropdownKeyValue> getSupportedCountries( + boolean filterOutSanctionedCountries) { + List<EditorFieldModel.DropdownKeyValue> supportedCountries = + AutofillProfileBridge.getSupportedCountries(); + if (filterOutSanctionedCountries) { + supportedCountries.removeIf(entry -> SANCTIONED_CONTRIES.contains(entry.getKey())); + } + + return supportedCountries; + } + /** * Builds an address editor. * @@ -207,7 +221,8 @@ if (mCountryField == null) { mCountryField = EditorFieldModel.createDropdown( mContext.getString(R.string.autofill_profile_editor_country), - AutofillProfileBridge.getSupportedCountries(), null /* hint */); + getSupportedCountries(isAccountAddressProfile() && !mIsProfileNew), + /*hint=*/null); } // Changing the country will update which fields are in the model. The actual fields are not @@ -315,12 +330,13 @@ /** Saves the edited profile on disk. */ private void commitChanges(AutofillProfile profile) { - if (willBeSavedInAccount()) { + String country = mCountryField.getValue().toString(); + if (willBeSavedInAccount() && !SANCTIONED_CONTRIES.contains(country)) { profile.setSource(Source.ACCOUNT); } // Country code and phone number are always required and are always collected from the // editor model. - profile.setCountryCode(mCountryField.getValue().toString()); + profile.setCountryCode(country); if (mPhoneField != null) profile.setPhoneNumber(mPhoneField.getValue().toString()); if (mEmailField != null) profile.setEmailAddress(mEmailField.getValue().toString()); if (mHonorificField != null) {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/AddressEditorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/AddressEditorTest.java index 08a0a1b..142dd19 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/AddressEditorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/AddressEditorTest.java
@@ -123,7 +123,12 @@ CoreAccountInfo.createFromEmailAndGaiaId(USER_EMAIL, "gaia_id"); // Note: can't initialize this list statically because of how Robolectric // initializes Android library dependencies. - private final List<DropdownKeyValue> mSupportedCountries = List.of( + private final List<DropdownKeyValue> mSupportedCountries = + List.of(new DropdownKeyValue("US", "United States"), + new DropdownKeyValue("DE", "Germany"), new DropdownKeyValue("CU", "Cuba"), + new DropdownKeyValue("IR", "Iran"), new DropdownKeyValue("KP", "North Korea"), + new DropdownKeyValue("SD", "Sudan"), new DropdownKeyValue("SY", "Syria")); + private final List<DropdownKeyValue> mNonSactionedCountries = List.of( new DropdownKeyValue("US", "United States"), new DropdownKeyValue("DE", "Germany")); private Callback<AutofillAddress> mDoneCallback; @@ -812,4 +817,90 @@ Assert.assertEquals( "New organization", mEditedAutofillAddress.getProfile().getCompanyName()); } + + @Test + @SmallTest + public void accountSavingDisallowedForSanctionedCountry() { + when(mPersonalDataManager.isEligibleForAddressAccountStorage()).thenReturn(true); + mAddressEditor = new AddressEditor( + /*saveToDisk=*/false, /*isUpdate=*/false, /*isMigrationToAccount=*/false); + mAddressEditor.setEditorDialog(mEditorDialog); + setUpAddressUiComponents(sSupportedAddressFields, "US"); + setUpAddressUiComponents(sSupportedAddressFields, "SY"); + mAddressEditor.edit(null, mDoneCallback); + + EditorModel editorModel = mEditorModelCapture.getValue(); + Assert.assertNotNull(editorModel); + List<EditorFieldModel> editorFields = editorModel.getFields(); + Assert.assertEquals(13, editorFields.size()); + + EditorFieldModel countryDropdown = editorFields.get(0); + countryDropdown.setDropdownKey("SY", () -> {}); + + // Set values of the required fields. + editorFields.get(2).setValue("New Name"); + editorFields.get(4).setValue("Locality"); + editorFields.get(5).setValue("Dependent locality"); + editorFields.get(8).setValue("Postal code"); + editorFields.get(9).setValue("Street address"); + editorModel.done(); + + Assert.assertNotNull(mEditedAutofillAddress); + Assert.assertEquals( + Source.LOCAL_OR_SYNCABLE, mEditedAutofillAddress.getProfile().getSource()); + } + + @Test + @SmallTest + public void countryDropDownExcludesSanctionedCountries_saveInAccountFlow() { + mAddressEditor = new AddressEditor( + /*saveToDisk=*/false, /*isUpdate=*/false, /*isMigrationToAccount=*/false); + mAddressEditor.setEditorDialog(mEditorDialog); + setUpAddressUiComponents(sSupportedAddressFields); + AutofillProfile toEdit = new AutofillProfile(sAccountProfile); + mAddressEditor.edit(new AutofillAddress(mActivity, toEdit), mDoneCallback); + + EditorModel editorModel = mEditorModelCapture.getValue(); + Assert.assertNotNull(editorModel); + List<EditorFieldModel> editorFields = editorModel.getFields(); + Assert.assertEquals(13, editorFields.size()); + + assertThat(editorFields.get(0).getDropdownKeys(), containsInAnyOrder("US", "DE")); + } + + @Test + @SmallTest + public void countryDropDownExcludesSanctionedCountries_MigrationFlow() { + mAddressEditor = new AddressEditor( + /*saveToDisk=*/false, /*isUpdate=*/false, /*isMigrationToAccount=*/true); + mAddressEditor.setEditorDialog(mEditorDialog); + setUpAddressUiComponents(sSupportedAddressFields); + AutofillProfile toEdit = new AutofillProfile(sLocalProfile); + mAddressEditor.edit(new AutofillAddress(mActivity, toEdit), mDoneCallback); + + EditorModel editorModel = mEditorModelCapture.getValue(); + Assert.assertNotNull(editorModel); + List<EditorFieldModel> editorFields = editorModel.getFields(); + Assert.assertEquals(13, editorFields.size()); + + assertThat(editorFields.get(0).getDropdownKeys(), containsInAnyOrder("US", "DE")); + } + + @Test + @SmallTest + public void countryDropDownExcludesSanctionedCountries_editExistingAccountProfile() { + mAddressEditor = new AddressEditor( + /*saveToDisk=*/false, /*isUpdate=*/true, /*isMigrationToAccount=*/false); + mAddressEditor.setEditorDialog(mEditorDialog); + setUpAddressUiComponents(sSupportedAddressFields); + AutofillProfile toEdit = new AutofillProfile(sAccountProfile); + mAddressEditor.edit(new AutofillAddress(mActivity, toEdit), mDoneCallback); + + EditorModel editorModel = mEditorModelCapture.getValue(); + Assert.assertNotNull(editorModel); + List<EditorFieldModel> editorFields = editorModel.getFields(); + Assert.assertEquals(13, editorFields.size()); + + assertThat(editorFields.get(0).getDropdownKeys(), containsInAnyOrder("US", "DE")); + } }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 97872091..19c13a64 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -6741,10 +6741,11 @@ "signin/bound_session_credentials/bound_session_cookie_controller_impl.h", "signin/bound_session_credentials/bound_session_cookie_observer.cc", "signin/bound_session_credentials/bound_session_cookie_observer.h", - "signin/bound_session_credentials/bound_session_cookie_refresh_service.cc", "signin/bound_session_credentials/bound_session_cookie_refresh_service.h", "signin/bound_session_credentials/bound_session_cookie_refresh_service_factory.cc", "signin/bound_session_credentials/bound_session_cookie_refresh_service_factory.h", + "signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.cc", + "signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.h", "signin/bound_session_credentials/bound_session_refresh_cookie_fetcher.cc", "signin/bound_session_credentials/bound_session_refresh_cookie_fetcher.h", "signin/bound_session_credentials/registration_token_helper.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 1a9d02f..3944631 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1566,6 +1566,16 @@ // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_FUCHSIA) #if BUILDFLAG(IS_ANDROID) +constexpr FeatureEntry::FeatureParam kOmniboxActionsInSuggestPromoteEntities[] = + { + {"PromoteEntitySuggestion", "true"}, +}; + +constexpr FeatureEntry::FeatureVariation kOmniboxActionsInSuggestVariants[] = { + {"Promote Entities", kOmniboxActionsInSuggestPromoteEntities, + std::size(kOmniboxActionsInSuggestPromoteEntities), nullptr}, +}; + constexpr FeatureEntry::FeatureParam kOmniboxInspireMeWith5Trends[] = { {"AdditionalTrendingQueries", "5"}, {"AdditionalRelatedQueries", "0"}}; @@ -5610,6 +5620,13 @@ // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_FUCHSIA) #if BUILDFLAG(IS_ANDROID) + {"omnibox-actions-in-suggest", + flag_descriptions::kOmniboxActionsInSuggestName, + flag_descriptions::kOmniboxActionsInSuggestDescription, kOsAndroid, + FEATURE_WITH_PARAMS_VALUE_TYPE(omnibox::kActionsInSuggest, + kOmniboxActionsInSuggestVariants, + "OmniboxBundledExperimentV1")}, + {"omnibox-inspire-me", flag_descriptions::kOmniboxInspireMeName, flag_descriptions::kOmniboxInspireMeDescription, kOsAndroid, FEATURE_WITH_PARAMS_VALUE_TYPE(omnibox::kInspireMe, @@ -8638,13 +8655,6 @@ flag_descriptions::kHttpsUpgradesDescription, kOsDesktop | kOsAndroid, FEATURE_VALUE_TYPE(features::kHttpsUpgrades)}, -#if BUILDFLAG(IS_WIN) - {"win-10-tab-search-caption-button", - flag_descriptions::kWin10TabSearchCaptionButtonName, - flag_descriptions::kWin10TabSearchCaptionButtonDescription, kOsWin, - FEATURE_VALUE_TYPE(features::kWin10TabSearchCaptionButton)}, -#endif // BUILDFLAG(IS_WIN) - {"omnibox-updated-connection-security-indicators", flag_descriptions::kOmniboxUpdatedConnectionSecurityIndicatorsName, flag_descriptions::kOmniboxUpdatedConnectionSecurityIndicatorsDescription,
diff --git a/chrome/browser/about_flags_unittest.cc b/chrome/browser/about_flags_unittest.cc index 3b05132a..6ca25d1 100644 --- a/chrome/browser/about_flags_unittest.cc +++ b/chrome/browser/about_flags_unittest.cc
@@ -102,17 +102,22 @@ return variation_ids; } -// Returns the parsed |variation_id|. If it is malformed, returns absl::nullopt. -absl::optional<int> ParseVariationId(const std::string& variation_id) { - // Remove the "t" prefix if it is there. - std::string trimmed_id = - base::StartsWith(variation_id, "t", base::CompareCase::SENSITIVE) - ? variation_id.substr(1) - : variation_id; - int id; - if (base::StringToInt(trimmed_id, &id) && id >= 0) - return id; - return absl::nullopt; +// Returns the parsed pair: <variation_id, is_triggering>. +std::pair<int, bool> ParseVariationId(const std::string& variation_str) { + // Fail if an empty string has been supplied as variation_id. + EXPECT_FALSE(variation_str.empty()) + << "Empty string used to denote variation ID. Use `nullptr` instead."; + + int variation_id{}; + bool is_triggering = variation_str[0] == 't'; + + // Fail if we could not process the integer value. + EXPECT_TRUE( + base::StringToInt(&variation_str[is_triggering ? 1 : 0], &variation_id)) + << "Invalid variation string: \"" << variation_str + << "\": must be either `#######` or `t#######`"; + + return {variation_id, is_triggering}; } } // namespace @@ -166,21 +171,41 @@ testing::GetFeatureEntries(), CHROME_VERSION_MAJOR); } -// Ensures that all variation IDs specified are well-formed and unique. -// Disabled - please see https://crbug.com/1432436. -TEST(AboutFlagsTest, DISABLED_VariationIdsAreValid) { - std::set<int> variation_ids; +// Ensures that all variation IDs specified are well-formed. +// - Variation IDs may be re-used, when multiple variants change client-side +// behavior alone. +// - Variation IDs must be associated with the appropriate pool of valid numbers +TEST(AboutFlagsTest, VariationIdsAreValid) { + std::set<int> nontriggering_variation_ids; + std::set<int> triggering_variation_ids; - for (const std::string& variation_id : GetAllVariationIds()) { - absl::optional<int> id = ParseVariationId(variation_id); - EXPECT_TRUE(id) + // See: go/finch-allocating-gws-ids. + int LOWER_VALID_VARIATION_ID = 3340000; + int UPPER_VALID_VARIATION_ID = 3399999; + + for (const std::string& variation_str : GetAllVariationIds()) { + auto [variation_id, is_triggering] = ParseVariationId(variation_str); + // Reject variation IDs used both as triggering and non-triggering. + // This is generally considered invalid. + EXPECT_FALSE( + // Triggering, but already recorded as visible. + (is_triggering && nontriggering_variation_ids.contains(variation_id)) || + // Visible, but already recorded as triggering. + (!is_triggering && triggering_variation_ids.contains(variation_id))) << "Variation ID \"" << variation_id - << "\" is malformed. It must be a nonnegative integer and can " - "optionally start with a \"t\"."; + << "\" used both as triggering and " + << "non-triggering."; - if (id.has_value()) { - EXPECT_TRUE(variation_ids.insert(id.value()).second) - << "Variation ID " << variation_id << " is duplicated."; + EXPECT_TRUE(variation_id >= LOWER_VALID_VARIATION_ID && + variation_id <= UPPER_VALID_VARIATION_ID) + << "Variation ID \"" << variation_id << "\" falls outside of range of " + << "valid variation IDs: [" << LOWER_VALID_VARIATION_ID << ", " + << UPPER_VALID_VARIATION_ID << "]."; + + if (is_triggering) { + triggering_variation_ids.insert(variation_id); + } else { + nontriggering_variation_ids.insert(variation_id); } } }
diff --git a/chrome/browser/apps/app_service/BUILD.gn b/chrome/browser/apps/app_service/BUILD.gn index bf13e98..c3e6413 100644 --- a/chrome/browser/apps/app_service/BUILD.gn +++ b/chrome/browser/apps/app_service/BUILD.gn
@@ -164,6 +164,8 @@ "promise_apps/promise_app_registry_cache.h", "promise_apps/promise_app_update.cc", "promise_apps/promise_app_update.h", + "promise_apps/promise_app_wrapper.cc", + "promise_apps/promise_app_wrapper.h", "promise_apps/promise_apps.cc", "promise_apps/promise_apps.h", "publishers/arc_apps.cc", @@ -226,6 +228,7 @@ "//ash/public/cpp", "//ash/webui/system_apps/public:system_web_app_type", "//chrome/browser:browser_process", + "//chrome/browser/apps/app_service/promise_apps/proto", "//chrome/browser/ash/crosapi", "//chrome/browser/ash/system_web_apps", "//chrome/browser/ash/system_web_apps/types",
diff --git a/chrome/browser/apps/app_service/promise_apps/promise_app_wrapper.cc b/chrome/browser/apps/app_service/promise_apps/promise_app_wrapper.cc new file mode 100644 index 0000000..09baaa0 --- /dev/null +++ b/chrome/browser/apps/app_service/promise_apps/promise_app_wrapper.cc
@@ -0,0 +1,100 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/apps/app_service/promise_apps/promise_app_wrapper.h" + +#include <vector> + +#include "base/strings/string_util.h" +#include "chrome/browser/apps/app_service/package_id.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "url/gurl.h" + +namespace apps { + +IconWrapper::IconWrapper(proto::PromiseAppResponse::Icon icon_proto) + : icon_proto_(icon_proto) {} + +GURL IconWrapper::GetUrl() const { + return GURL(icon_proto_.url()); +} + +absl::optional<int> IconWrapper::GetWidthInPixels() const { + absl::optional<int> width; + if (icon_proto_.has_width_in_pixels()) { + width = icon_proto_.width_in_pixels(); + } + return width; +} + +std::string IconWrapper::GetMimeType() const { + return icon_proto_.mime_type(); +} + +bool IconWrapper::IsMaskingAllowed() const { + return icon_proto_.is_masking_allowed(); +} + +PromiseAppWrapper::PromiseAppWrapper( + proto::PromiseAppResponse promise_app_proto) + : promise_app_proto_(promise_app_proto), + package_id_(PackageId::FromString(promise_app_proto.package_id())) {} + +PromiseAppWrapper::PromiseAppWrapper(const PromiseAppWrapper&) = default; +PromiseAppWrapper& PromiseAppWrapper::operator=(const PromiseAppWrapper&) = + default; +PromiseAppWrapper::~PromiseAppWrapper() = default; + +absl::optional<PackageId> PromiseAppWrapper::GetPackageId() const { + return package_id_; +} + +absl::optional<std::string> PromiseAppWrapper::GetName() const { + absl::optional<std::string> name; + if (promise_app_proto_.has_name()) { + name = promise_app_proto_.name(); + } + return name; +} + +std::vector<IconWrapper> PromiseAppWrapper::GetIcons() const { + std::vector<IconWrapper> icon_data; + icon_data.reserve(promise_app_proto_.icons().size()); + for (auto icon : promise_app_proto_.icons()) { + icon_data.emplace_back(icon); + } + return icon_data; +} + +std::ostream& operator<<(std::ostream& os, const IconWrapper& icon) { + os << std::boolalpha; + os << "* Url: " << icon.GetUrl().spec() << std::endl; + os << "* Width in pixels: " + << (icon.GetWidthInPixels().has_value() + ? base::NumberToString(icon.GetWidthInPixels().value()) + : "N/A") + << std::endl; + os << "* Mime type: " << icon.GetMimeType() << std::endl; + os << "* Is masking allowed: " << icon.IsMaskingAllowed() << std::endl; + os << std::noboolalpha; + return os; +} + +std::ostream& operator<<(std::ostream& os, + const PromiseAppWrapper& promise_app) { + os << std::boolalpha; + os << "- Package Id: " + << (promise_app.GetPackageId().has_value() + ? promise_app.GetPackageId()->ToString() + : "N/A") + << std::endl; + os << "- Name: " << promise_app.GetName().value_or("N/A") << std::endl; + for (const IconWrapper& icon : promise_app.GetIcons()) { + os << "- Icons: " << icon << std::endl; + } + os << std::noboolalpha; + return os; +} + +} // namespace apps
diff --git a/chrome/browser/apps/app_service/promise_apps/promise_app_wrapper.h b/chrome/browser/apps/app_service/promise_apps/promise_app_wrapper.h new file mode 100644 index 0000000..17f0d245 --- /dev/null +++ b/chrome/browser/apps/app_service/promise_apps/promise_app_wrapper.h
@@ -0,0 +1,56 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_APPS_APP_SERVICE_PROMISE_APPS_PROMISE_APP_WRAPPER_H_ +#define CHROME_BROWSER_APPS_APP_SERVICE_PROMISE_APPS_PROMISE_APP_WRAPPER_H_ + +#include <ostream> +#include <string> +#include <vector> + +#include "chrome/browser/apps/app_service/package_id.h" +#include "chrome/browser/apps/app_service/promise_apps/proto/promise_app.pb.h" +#include "components/services/app_service/public/cpp/app_types.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "url/gurl.h" + +namespace apps { + +class IconWrapper { + public: + explicit IconWrapper(proto::PromiseAppResponse::Icon icon_proto); + GURL GetUrl() const; + absl::optional<int> GetWidthInPixels() const; + std::string GetMimeType() const; + bool IsMaskingAllowed() const; + + private: + proto::PromiseAppResponse::Icon icon_proto_; +}; + +// A wrapper class around a Promise App proto to allow for easier +// extraction and conversion of information. +class PromiseAppWrapper { + public: + explicit PromiseAppWrapper(proto::PromiseAppResponse promise_app_proto); + PromiseAppWrapper(const PromiseAppWrapper&); + PromiseAppWrapper& operator=(const PromiseAppWrapper&); + ~PromiseAppWrapper(); + + absl::optional<PackageId> GetPackageId() const; + absl::optional<std::string> GetName() const; + std::vector<IconWrapper> GetIcons() const; + + private: + proto::PromiseAppResponse promise_app_proto_; + absl::optional<PackageId> package_id_; +}; + +std::ostream& operator<<(std::ostream& os, const IconWrapper& icon); +std::ostream& operator<<(std::ostream& os, + const PromiseAppWrapper& promise_app); + +} // namespace apps + +#endif // CHROME_BROWSER_APPS_APP_SERVICE_PROMISE_APPS_PROMISE_APP_WRAPPER_H_
diff --git a/chrome/browser/apps/app_service/promise_apps/promise_app_wrapper_unittest.cc b/chrome/browser/apps/app_service/promise_apps/promise_app_wrapper_unittest.cc new file mode 100644 index 0000000..758acb1 --- /dev/null +++ b/chrome/browser/apps/app_service/promise_apps/promise_app_wrapper_unittest.cc
@@ -0,0 +1,77 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/apps/app_service/promise_apps/promise_app_wrapper.h" + +#include "chrome/browser/apps/app_service/promise_apps/proto/promise_app.pb.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace apps { + +using PromiseAppWrapperTest = testing::Test; + +TEST_F(PromiseAppWrapperTest, ConversionSuccessful) { + PackageId package_id(AppType::kArc, "test.package.name"); + GURL url("http://www.image.com"); + + proto::PromiseAppResponse response; + response.set_package_id(package_id.ToString()); + response.set_name("Name"); + response.add_icons(); + response.mutable_icons(0)->set_url(url.spec()); + response.mutable_icons(0)->set_width_in_pixels(512); + response.mutable_icons(0)->set_mime_type("image/png"); + response.mutable_icons(0)->set_is_masking_allowed(true); + + PromiseAppWrapper promise_app_wrapper(response); + ASSERT_EQ(promise_app_wrapper.GetPackageId(), package_id); + ASSERT_EQ(promise_app_wrapper.GetName(), "Name"); + + std::vector<IconWrapper> icons = promise_app_wrapper.GetIcons(); + ASSERT_EQ(icons.size(), 1u); + ASSERT_EQ(icons[0].GetUrl(), url); + ASSERT_EQ(icons[0].GetWidthInPixels(), 512); + ASSERT_EQ(icons[0].GetMimeType(), "image/png"); + ASSERT_TRUE(icons[0].IsMaskingAllowed()); +} + +TEST_F(PromiseAppWrapperTest, EmptyFields) { + proto::PromiseAppResponse response; + PromiseAppWrapper promise_app_wrapper(response); + + ASSERT_FALSE(promise_app_wrapper.GetPackageId().has_value()); + ASSERT_FALSE(promise_app_wrapper.GetName().has_value()); + std::vector<IconWrapper> icons = promise_app_wrapper.GetIcons(); + ASSERT_EQ(icons.size(), 0u); +} + +TEST_F(PromiseAppWrapperTest, InvalidPackageIdReturnsNull) { + proto::PromiseAppResponse response; + response.set_package_id("something:package.name"); + PromiseAppWrapper promise_app_wrapper(response); + ASSERT_FALSE(promise_app_wrapper.GetPackageId().has_value()); +} + +TEST_F(PromiseAppWrapperTest, IconWrapperHasNoWidth) { + GURL url("http://www.image.com"); + + proto::PromiseAppResponse response; + response.add_icons(); + + // Set every field except the optional width_in_pixels field. + response.mutable_icons(0)->set_url(url.spec()); + response.mutable_icons(0)->set_mime_type("image/png"); + response.mutable_icons(0)->set_is_masking_allowed(true); + + std::vector<IconWrapper> icons = PromiseAppWrapper(response).GetIcons(); + + ASSERT_EQ(icons.size(), 1u); + ASSERT_EQ(icons[0].GetUrl(), url); + ASSERT_FALSE(icons[0].GetWidthInPixels().has_value()); + ASSERT_EQ(icons[0].GetMimeType(), "image/png"); + ASSERT_TRUE(icons[0].IsMaskingAllowed()); +} + +} // namespace apps
diff --git a/chrome/browser/apps/app_service/promise_apps/proto/BUILD.gn b/chrome/browser/apps/app_service/promise_apps/proto/BUILD.gn new file mode 100644 index 0000000..ee5fc84 --- /dev/null +++ b/chrome/browser/apps/app_service/promise_apps/proto/BUILD.gn
@@ -0,0 +1,11 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/protobuf/proto_library.gni") + +proto_library("proto") { + proto_in_dir = "//" + + sources = [ "promise_app.proto" ] +}
diff --git a/chrome/browser/apps/app_service/promise_apps/proto/promise_app.proto b/chrome/browser/apps/app_service/promise_apps/proto/promise_app.proto new file mode 100644 index 0000000..0f290c36 --- /dev/null +++ b/chrome/browser/apps/app_service/promise_apps/proto/promise_app.proto
@@ -0,0 +1,55 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package apps.proto; + +// This file is a mirror of the proto file maintained in the server code base at +// go/promise-app-proto. Changes should be made by updating the server code +// base and then copying the result to Chromium. + +message PromiseAppRequest { + // The language-country identifier for the user in language in + // "language_COUNTRY" format (eg. "en_US"). + // Must match one of the valid Google recognised codes. See: + // //i18n/identifiers/languagecodeconverter.h + // Note: this should ideally be the user's preferred language, if absent + // use the language specified by the UI. The server will attempt to find the + // best match for this language from the content it has access to, but does + // not guarantee the returned content will be readable for this locale. + optional string language = 1; + + // PackageId for the installable app that the information is being requested + // for. This is always "platform:primary_key", for example + // "android:com.spotify.music" or "web:http://manifest/id" + optional string package_id = 2; +} + +// Outbound response for the Promise App endpoint. +message PromiseAppResponse { + // The name of the requested app. + optional string name = 1; + + // The Icon for the requested app. + repeated Icon icons = 2; + + // PackageId for the installable app that the information is being requested + // for. This is always "platform:primary_key", for example + // "android:com.spotify.music" or "web:http://manifest/id" + optional string package_id = 3; + + message Icon { + // Url to query to get the icon. + optional string url = 1; + // Width of the icon in pixels. + optional int32 width_in_pixels = 2; + // Mime type of the icon. + optional string mime_type = 3; + // Whether or not we have permission from the platform to mask the icon. + optional bool is_masking_allowed = 4; + } +}
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_service_launcher_unittest.cc b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_service_launcher_unittest.cc index cddaccd..7cb9a757 100644 --- a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_service_launcher_unittest.cc +++ b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_service_launcher_unittest.cc
@@ -41,6 +41,7 @@ #include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/instance.h" #include "components/webapps/browser/install_result_code.h" +#include "components/webapps/browser/installable/installable_metrics.h" #include "content/public/browser/web_contents.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -274,7 +275,8 @@ void OnAppUnregistered(std::string app_id, bool success) { ASSERT_TRUE(success); - web_app_provider()->install_manager().NotifyWebAppUninstalled(app_id); + web_app_provider()->install_manager().NotifyWebAppUninstalled( + app_id, webapps::WebappUninstallSource::kSync); } AccountId account_id_;
diff --git a/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc b/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc index cb2c629..bf93ae4 100644 --- a/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc +++ b/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc
@@ -258,7 +258,9 @@ uninstalled_web_app_ids_.push_back(web_app_id); } - void OnWebAppUninstalled(const web_app::AppId& app_id) override { + void OnWebAppUninstalled( + const web_app::AppId& app_id, + webapps::WebappUninstallSource uninstall_source) override { if (app_uninstalled_callback_) { app_uninstalled_callback_.Run(app_id); }
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc index 11571e15..279712f 100644 --- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc +++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
@@ -71,10 +71,6 @@ AddOverlay(first_launch ? DisplayMode::kEducation : DisplayMode::kView); ash::Shell::Get()->AddPreTargetHandler(this); - if (auto* dark_light_mode_controller = - ash::DarkLightModeControllerImpl::Get()) { - dark_light_mode_controller->AddObserver(this); - } } DisplayOverlayController::~DisplayOverlayController() { @@ -85,10 +81,6 @@ return; } - if (auto* dark_light_mode_controller = - ash::DarkLightModeControllerImpl::Get()) { - dark_light_mode_controller->RemoveObserver(this); - } ash::Shell::Get()->RemovePreTargetHandler(this); RemoveOverlayIfAny(); } @@ -728,20 +720,6 @@ ProcessPressedEvent(*event); } -void DisplayOverlayController::OnColorModeChanged(bool dark_mode_enabled) { - // Only make the color mode change responsive when in - // |DisplayMode::kEducation| because: - // 1. Other modes like |DisplayMode::kEdit| and |DisplayMode::kView| only have - // one color mode. - // 2. When in |DisplayMode::kMenu| and changing the color mode, the menu is - // closed and it becomes |DisplayMode::kView| so no need to update color mode. - if (display_mode_ != DisplayMode::kEducation) { - return; - } - SetDisplayMode(DisplayMode::kNone); - SetDisplayMode(DisplayMode::kEducation); -} - void DisplayOverlayController::OnWidgetBoundsChanged( views::Widget* widget, const gfx::Rect& new_bounds) {
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h index af30246..4f582ab 100644 --- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h +++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h
@@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_DISPLAY_OVERLAY_CONTROLLER_H_ #define CHROME_BROWSER_ASH_ARC_INPUT_OVERLAY_DISPLAY_OVERLAY_CONTROLLER_H_ -#include "ash/public/cpp/style/color_mode_observer.h" #include "base/memory/raw_ptr.h" #include "chrome/browser/ash/arc/input_overlay/actions/input_element.h" #include "ui/aura/window_observer.h" @@ -42,7 +41,6 @@ // menu, and educational dialog. It also handles the visibility of the // |ActionEditMenu| and |MessageView| by listening to the |LocatedEvent|. class DisplayOverlayController : public ui::EventHandler, - public ash::ColorModeObserver, public views::WidgetObserver, public aura::WindowObserver { public: @@ -94,9 +92,6 @@ void OnMouseEvent(ui::MouseEvent* event) override; void OnTouchEvent(ui::TouchEvent* event) override; - // ash::ColorModeObserver: - void OnColorModeChanged(bool dark_mode_enabled) override; - // views::WidgetObserver: void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) override;
diff --git a/chrome/browser/ash/arc/input_overlay/ui/educational_view.cc b/chrome/browser/ash/arc/input_overlay/ui/educational_view.cc index ecbffdac..2c72103 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/educational_view.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/educational_view.cc
@@ -25,6 +25,7 @@ #include "ui/gfx/text_constants.h" #include "ui/views/background.h" #include "ui/views/border.h" +#include "ui/views/controls/image_view.h" #include "ui/views/layout/flex_layout.h" namespace arc::input_overlay { @@ -105,6 +106,13 @@ return portrait_mode ? kTitleFontSizePortrait : kTitleFontSizeLandscape; } +void SetBanner(views::ImageView& image) { + image.SetImage(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + ash::DarkLightModeController::Get()->IsDarkModeEnabled() + ? IDS_ARC_INPUT_OVERLAY_ONBOARDING_ILLUSTRATION_DARK_JSON + : IDS_ARC_INPUT_OVERLAY_ONBOARDING_ILLUSTRATION_LIGHT_JSON)); +} + } // namespace // static @@ -129,6 +137,12 @@ EducationalView::~EducationalView() {} +void EducationalView::OnThemeChanged() { + views::View::OnThemeChanged(); + DCHECK(banner_); + SetBanner(*banner_); +} + void EducationalView::Init(const gfx::Size& parent_size) { DCHECK(display_overlay_controller_); @@ -144,9 +158,7 @@ { // UI's banner. auto banner = std::make_unique<views::ImageView>(); - banner->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( - is_dark ? IDS_ARC_INPUT_OVERLAY_ONBOARDING_ILLUSTRATION_DARK_JSON - : IDS_ARC_INPUT_OVERLAY_ONBOARDING_ILLUSTRATION_LIGHT_JSON)); + SetBanner(*banner); if (portrait_mode_) { // Resize the banner image size proportionally. @@ -156,7 +168,7 @@ float ratio = 1.0 * width / size.width(); banner->SetImageSize(gfx::Size(width, size.height() * ratio)); } - AddChildView(std::move(banner)); + banner_ = AddChildView(std::move(banner)); } { // |Game controls [Alpha]| title tag.
diff --git a/chrome/browser/ash/arc/input_overlay/ui/educational_view.h b/chrome/browser/ash/arc/input_overlay/ui/educational_view.h index b0f33171..8e5df51 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/educational_view.h +++ b/chrome/browser/ash/arc/input_overlay/ui/educational_view.h
@@ -15,6 +15,10 @@ class PillButton; } // namespace ash +namespace views { +class ImageView; +} // namespace views + namespace arc::input_overlay { class DisplayOverlayController; @@ -33,6 +37,9 @@ EducationalView& operator=(const EducationalView&) = delete; ~EducationalView() override; + // views::View: + void OnThemeChanged() override; + private: void Init(const gfx::Size& parent_size); void OnAcceptedPressed(); @@ -41,6 +48,8 @@ void AddShadow(); raw_ptr<ash::PillButton> accept_button_ = nullptr; + // Image banner. + raw_ptr<views::ImageView> banner_ = nullptr; // View shadow for this view. std::unique_ptr<ash::ViewShadow> view_shadow_; // Whether or not phone specs should be used.
diff --git a/chrome/browser/ash/crosapi/browser_data_back_migrator.cc b/chrome/browser/ash/crosapi/browser_data_back_migrator.cc index 7c23532..fe6e854 100644 --- a/chrome/browser/ash/crosapi/browser_data_back_migrator.cc +++ b/chrome/browser/ash/crosapi/browser_data_back_migrator.cc
@@ -1395,7 +1395,7 @@ } // static -BrowserDataBackMigrator::Result BrowserDataBackMigrator::ToResult( +BrowserDataBackMigratorBase::Result BrowserDataBackMigrator::ToResult( TaskResult result) { switch (result.status) { case TaskStatus::kSucceeded:
diff --git a/chrome/browser/ash/dbus/proxy_resolution_service_provider.cc b/chrome/browser/ash/dbus/proxy_resolution_service_provider.cc index f7e8b71..ba68d5e 100644 --- a/chrome/browser/ash/dbus/proxy_resolution_service_provider.cc +++ b/chrome/browser/ash/dbus/proxy_resolution_service_provider.cc
@@ -16,6 +16,9 @@ #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h" +#include "chromeos/ash/components/browser_context_helper/browser_context_types.h" +#include "components/user_manager/user_manager.h" #include "content/public/browser/storage_partition.h" #include "dbus/bus.h" #include "dbus/message.h" @@ -246,11 +249,25 @@ // TODO(eroman): Instead of retrieving the profile globally (which could be in // a variety of states during startup/shutdown), pass the BrowserContext in as // a dependency. - auto* primary_profile = ProfileManager::GetPrimaryUserProfile(); - if (!primary_profile) - return nullptr; - auto* storage_partition = primary_profile->GetDefaultStoragePartition(); + // Can be the profile of the primary user logged in the session or the profile + // associated with the sign-in screen. + Profile* profile = nullptr; + auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser(); + if (primary_user) { + profile = Profile::FromBrowserContext( + ash::BrowserContextHelper::Get()->GetBrowserContextByUser( + primary_user)); + } + + if (!profile) { + profile = ProfileManager::GetActiveUserProfile(); + if (!profile || !ash::IsSigninBrowserContext(profile)) { + return nullptr; + } + } + + auto* storage_partition = profile->GetDefaultStoragePartition(); if (!storage_partition) return nullptr;
diff --git a/chrome/browser/ash/dbus/proxy_resolution_service_provider_browsertest.cc b/chrome/browser/ash/dbus/proxy_resolution_service_provider_browsertest.cc index ee96a4a5..ac9f5d4 100644 --- a/chrome/browser/ash/dbus/proxy_resolution_service_provider_browsertest.cc +++ b/chrome/browser/ash/dbus/proxy_resolution_service_provider_browsertest.cc
@@ -6,9 +6,12 @@ #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "chrome/browser/ash/dbus/proxy_resolution_service_provider.h" +#include "chrome/browser/ash/login/login_manager_test.h" +#include "chrome/browser/ash/login/test/login_manager_mixin.h" #include "chrome/browser/ash/net/system_proxy_manager.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/mixin_based_in_process_browser_test.h" #include "chrome/test/base/testing_browser_process.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/content_switches.h" @@ -87,17 +90,17 @@ // Base test fixture that exposes a way to invoke ProxyResolutionServiceProvider // synchronously from the UI thread. class ProxyResolutionServiceProviderBaseBrowserTest - : public InProcessBrowserTest { + : public MixinBasedInProcessBrowserTest { public: void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); + MixinBasedInProcessBrowserTest::SetUpOnMainThread(); proxy_service_ = std::make_unique<ProxyResolutionServiceProviderTestWrapper>(); } void TearDownOnMainThread() override { proxy_service_.reset(); - InProcessBrowserTest::TearDownOnMainThread(); + MixinBasedInProcessBrowserTest::TearDownOnMainThread(); } std::string ResolveProxyAndWait(const std::string& source_url) { @@ -206,4 +209,23 @@ EXPECT_EQ("DIRECT", ResolveProxyAndWait("http://www.test.direct.com")); } +class ProxyResolutionServiceAtLoginScreen + : public ProxyResolutionServiceProviderBaseBrowserTest { + public: + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitchASCII(switches::kProxyPacUrl, + GetPacUrl(kPacData)); + } + + protected: + LoginManagerMixin login_manager_{&mixin_host_}; +}; + +// Tests that the D-Bus proxy resolver returns the proxy configured at the +// sign-in screen. +IN_PROC_BROWSER_TEST_F(ProxyResolutionServiceAtLoginScreen, ResolveProxy) { + EXPECT_EQ("PROXY foo1:80;PROXY foo2:80", + ResolveProxyAndWait("http://www.google.com")); +} + } // namespace ash
diff --git a/chrome/browser/ash/drive/drive_integration_service.cc b/chrome/browser/ash/drive/drive_integration_service.cc index 77eb215a..4f7df01f 100644 --- a/chrome/browser/ash/drive/drive_integration_service.cc +++ b/chrome/browser/ash/drive/drive_integration_service.cc
@@ -1331,56 +1331,17 @@ return; } - auto query_params = drivefs::mojom::QueryParameters::New(); - query_params->page_size = 1000; - query_params->available_offline = true; - - int64_t total_size = 0; - mojo::Remote<drivefs::mojom::SearchQuery> search_query; - - GetDriveFsInterface()->StartSearchQuery( - search_query.BindNewPipeAndPassReceiver(), std::move(query_params)); - - auto* raw_search_query = search_query.get(); - raw_search_query->GetNextPage( - base::BindOnce(&DriveIntegrationService::OnGetOfflineItemsPage, - weak_ptr_factory_.GetWeakPtr(), total_size, - std::move(search_query), std::move(callback))); -} - -void DriveIntegrationService::OnGetOfflineItemsPage( - int64_t total_size, - mojo::Remote<drivefs::mojom::SearchQuery> search_query, - base::OnceCallback<void(int64_t)> callback, - drive::FileError error, - absl::optional<std::vector<drivefs::mojom::QueryItemPtr>> results) { - if (!ash::features::IsDriveFsBulkPinningEnabled() || - error != drive::FILE_ERROR_OK || results->empty() || - callback.IsCancelled()) { - LOG_IF(ERROR, error != drive::FILE_ERROR_OK) - << "Cannot get offline size: " << error; - std::move(callback).Run(total_size); - return; - } - - for (auto& result : *results) { - if (!result->metadata) { - continue; - } - // We only want to show storage used by Drive that a user can action (i.e. - // files that can be unpinned). This should exclude files that DriveFS - // implicitly caches as users can't remove these files. - const drivefs::mojom::FileMetadata& metadata = *result->metadata; - if (metadata.available_offline && metadata.pinned) { - total_size += result->metadata->size; - } - } - - auto* raw_search_query = search_query.get(); - raw_search_query->GetNextPage( - base::BindOnce(&DriveIntegrationService::OnGetOfflineItemsPage, - weak_ptr_factory_.GetWeakPtr(), total_size, - std::move(search_query), std::move(callback))); + GetDriveFsInterface()->GetOfflineFilesSpaceUsage(base::BindOnce( + [](base::OnceCallback<void(int64_t)> callback, drive::FileError error, + int64_t total_size) { + if (error != drive::FILE_ERROR_OK) { + LOG(ERROR) << "Cannot get offline size: " << error; + std::move(callback).Run(-1); + return; + } + std::move(callback).Run(total_size); + }, + std::move(callback))); } void DriveIntegrationService::GetQuickAccessItems(
diff --git a/chrome/browser/ash/drive/drive_integration_service_browsertest.cc b/chrome/browser/ash/drive/drive_integration_service_browsertest.cc index 090db12..0b730b4 100644 --- a/chrome/browser/ash/drive/drive_integration_service_browsertest.cc +++ b/chrome/browser/ash/drive/drive_integration_service_browsertest.cc
@@ -28,6 +28,7 @@ #include "chromeos/components/drivefs/mojom/drivefs_native_messaging.mojom.h" #include "chromeos/crosapi/mojom/drive_integration_service.mojom.h" #include "components/drive/drive_pref_names.h" +#include "components/drive/file_errors.h" #include "components/prefs/pref_service.h" #include "components/prefs/pref_test_utils.h" #include "content/public/test/browser_test.h" @@ -585,62 +586,39 @@ run_loop.Run(); } -class FakeSearchQueryImpl : public drivefs::mojom::SearchQuery { - public: - // Produces 2 pages of fake results, each page with 2 items with a combined - // size of 75 bytes (50 + 25). From the 3rd call onwards, returns an empty - // page. - void GetNextPage(GetNextPageCallback reply) override { - std::vector<drivefs::mojom::QueryItemPtr> page; - - if (pages_counter_ < 2) { - pages_counter_++; - auto qi1 = drivefs::mojom::QueryItem::New(); - auto qi2 = drivefs::mojom::QueryItem::New(); - qi1->metadata = drivefs::mojom::FileMetadata::New(); - qi2->metadata = drivefs::mojom::FileMetadata::New(); - qi1->metadata->capabilities = drivefs::mojom::Capabilities::New(); - qi2->metadata->capabilities = drivefs::mojom::Capabilities::New(); - qi1->metadata->size = 50; - qi2->metadata->size = 25; - qi1->metadata->available_offline = true; - qi2->metadata->available_offline = true; - qi1->metadata->pinned = true; - qi2->metadata->pinned = true; - page.emplace_back(std::move(qi1)); - page.emplace_back(std::move(qi2)); - } - - std::move(reply).Run(drive::FILE_ERROR_OK, std::move(page)); - } - - private: - int pages_counter_ = 0; -}; - IN_PROC_BROWSER_TEST_F(DriveIntegrationBrowserTestWithBulkPinningEnabled, - GetTotalPinnedSize) { + GetTotalPinnedSizeWithErrorIgnoresReturnedSize) { auto* drive_integration_service = DriveIntegrationServiceFactory::FindForProfile(browser()->profile()); auto* fake_drivefs = GetFakeDriveFsForProfile(browser()->profile()); - FakeSearchQueryImpl fake_search_query_impl; - mojo::Receiver<drivefs::mojom::SearchQuery> receiver(&fake_search_query_impl); - - EXPECT_CALL(*fake_drivefs, StartSearchQuery(_, _)) - .WillOnce([&](mojo::PendingReceiver<drivefs::mojom::SearchQuery> - pending_receiver, - drivefs::mojom::QueryParametersPtr query_params) { - receiver.Bind(std::move(pending_receiver)); - }); + EXPECT_CALL(*fake_drivefs, GetOfflineFilesSpaceUsage(_)) + .WillOnce(RunOnceCallback<0>(drive::FILE_ERROR_FAILED, 1000)); base::RunLoop run_loop; base::MockOnceCallback<void(int64_t)> mock_callback; - EXPECT_CALL(mock_callback, Run(/* 2 * (25 + 50) = */ 150)) + EXPECT_CALL(mock_callback, Run(-1)) .WillOnce(RunClosure(run_loop.QuitClosure())); drive_integration_service->GetTotalPinnedSize(mock_callback.Get()); + run_loop.Run(); +} +IN_PROC_BROWSER_TEST_F(DriveIntegrationBrowserTestWithBulkPinningEnabled, + GetTotalPinnedSizeReturnsCorrectSize) { + auto* drive_integration_service = + DriveIntegrationServiceFactory::FindForProfile(browser()->profile()); + auto* fake_drivefs = GetFakeDriveFsForProfile(browser()->profile()); + + EXPECT_CALL(*fake_drivefs, GetOfflineFilesSpaceUsage(_)) + .WillOnce(RunOnceCallback<0>(drive::FILE_ERROR_OK, 1024)); + + base::RunLoop run_loop; + base::MockOnceCallback<void(int64_t)> mock_callback; + EXPECT_CALL(mock_callback, Run(1024)) + .WillOnce(RunClosure(run_loop.QuitClosure())); + + drive_integration_service->GetTotalPinnedSize(mock_callback.Get()); run_loop.Run(); }
diff --git a/chrome/browser/ash/login/screens/lacros_data_backward_migration_screen.cc b/chrome/browser/ash/login/screens/lacros_data_backward_migration_screen.cc index 8f3ee475..41435443 100644 --- a/chrome/browser/ash/login/screens/lacros_data_backward_migration_screen.cc +++ b/chrome/browser/ash/login/screens/lacros_data_backward_migration_screen.cc
@@ -77,12 +77,12 @@ } void LacrosDataBackwardMigrationScreen::OnMigrated( - BrowserDataBackMigrator::Result result) { + BrowserDataBackMigratorBase::Result result) { switch (result) { - case BrowserDataBackMigrator::Result::kSucceeded: + case BrowserDataBackMigratorBase::Result::kSucceeded: chrome::AttemptRestart(); break; - case BrowserDataBackMigrator::Result::kFailed: + case BrowserDataBackMigratorBase::Result::kFailed: view_->SetFailureStatus(); break; }
diff --git a/chrome/browser/ash/login/screens/lacros_data_backward_migration_screen.h b/chrome/browser/ash/login/screens/lacros_data_backward_migration_screen.h index b084f785..1668907 100644 --- a/chrome/browser/ash/login/screens/lacros_data_backward_migration_screen.h +++ b/chrome/browser/ash/login/screens/lacros_data_backward_migration_screen.h
@@ -34,7 +34,7 @@ void OnProgress(int percent); // Called when migration is completed. - void OnMigrated(BrowserDataBackMigrator::Result result); + void OnMigrated(BrowserDataBackMigratorBase::Result result); base::WeakPtr<LacrosDataBackwardMigrationScreenView> view_; std::unique_ptr<BrowserDataBackMigrator> migrator_;
diff --git a/chrome/browser/ash/scanning/scan_service.cc b/chrome/browser/ash/scanning/scan_service.cc index 7f917e9e..df75a1b 100644 --- a/chrome/browser/ash/scanning/scan_service.cc +++ b/chrome/browser/ash/scanning/scan_service.cc
@@ -578,7 +578,8 @@ HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(context_); if (holding_space_keyed_service) { for (const auto& saved_scan_path : scanned_file_paths_) - holding_space_keyed_service->AddScan(saved_scan_path); + holding_space_keyed_service->AddItemOfType(HoldingSpaceItem::Type::kScan, + saved_scan_path); } RecordScanJobResult(failure_mode == lorgnette::SCAN_FAILURE_MODE_NO_FAILURE && !page_save_failed_,
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc b/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc index 5521481..ef0eb5def 100644 --- a/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc +++ b/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc
@@ -1020,6 +1020,7 @@ [&](const apps::AppUpdate& app) { if ((app.AppType() == apps::AppType::kSystemWeb || app.AppType() == apps::AppType::kWeb) && + app.Readiness() != apps::Readiness::kUninstalledByMigration && app.Readiness() != apps::Readiness::kUninstalledByUser) { swa_found = true; }
diff --git a/chrome/browser/banners/app_banner_manager_desktop.cc b/chrome/browser/banners/app_banner_manager_desktop.cc index a72059e..4cc238f 100644 --- a/chrome/browser/banners/app_banner_manager_desktop.cc +++ b/chrome/browser/banners/app_banner_manager_desktop.cc
@@ -206,7 +206,8 @@ } void AppBannerManagerDesktop::OnWebAppUninstalled( - const web_app::AppId& app_id) { + const web_app::AppId& app_id, + webapps::WebappUninstallSource uninstall_source) { if (uninstalling_app_id_ == app_id) RecheckInstallabilityForLoadedPage(validated_url(), true); }
diff --git a/chrome/browser/banners/app_banner_manager_desktop.h b/chrome/browser/banners/app_banner_manager_desktop.h index 9dc0a25a..548ef06 100644 --- a/chrome/browser/banners/app_banner_manager_desktop.h +++ b/chrome/browser/banners/app_banner_manager_desktop.h
@@ -78,7 +78,9 @@ // web_app::WebAppInstallManagerObserver: void OnWebAppInstalled(const web_app::AppId& app_id) override; void OnWebAppWillBeUninstalled(const web_app::AppId& app_id) override; - void OnWebAppUninstalled(const web_app::AppId& app_id) override; + void OnWebAppUninstalled( + const web_app::AppId& app_id, + webapps::WebappUninstallSource uninstall_source) override; void OnWebAppInstallManagerDestroyed() override; void CreateWebApp(WebappInstallSource install_source);
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc index 64b4321f..9bb3273 100644 --- a/chrome/browser/chrome_service_worker_browsertest.cc +++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -509,14 +509,14 @@ // Sync the histogram data between the renderer and browser processes. metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); - histogram_tester.ExpectTotalCount("ServiceWorker.Subresource.Handled.Type", + histogram_tester.ExpectTotalCount("ServiceWorker.Subresource.Handled.Type2", 1); - histogram_tester.ExpectUniqueSample("ServiceWorker.Subresource.Handled.Type", + histogram_tester.ExpectUniqueSample("ServiceWorker.Subresource.Handled.Type2", 2 /* kCSSStyleSheet */, 1); - histogram_tester.ExpectTotalCount("ServiceWorker.Subresource.Fallbacked.Type", - 1); + histogram_tester.ExpectTotalCount( + "ServiceWorker.Subresource.Fallbacked.Type2", 1); histogram_tester.ExpectUniqueSample( - "ServiceWorker.Subresource.Fallbacked.Type", 2 /* kCSSStyleSheet */, 1); + "ServiceWorker.Subresource.Fallbacked.Type2", 2 /* kCSSStyleSheet */, 1); } class ChromeServiceWorkerFetchTest : public ChromeServiceWorkerTest {
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/common/base_telemetry_extension_api_guard_function_browsertest.cc b/chrome/browser/chromeos/extensions/telemetry/api/common/base_telemetry_extension_api_guard_function_browsertest.cc index 0d4d8d1..2a575667 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/common/base_telemetry_extension_api_guard_function_browsertest.cc +++ b/chrome/browser/chromeos/extensions/telemetry/api/common/base_telemetry_extension_api_guard_function_browsertest.cc
@@ -421,6 +421,34 @@ ); chrome.test.succeed(); }, + // Event APIs. + async function isEventSupported() { + await chrome.test.assertPromiseRejects( + chrome.os.events.isEventSupported("audio_jack"), + 'Error: Unauthorized access to ' + + 'chrome.os.events.isEventSupported. ' + + '%s' + ); + chrome.test.succeed(); + }, + async function startCapturingEvents() { + await chrome.test.assertPromiseRejects( + chrome.os.events.startCapturingEvents("audio_jack"), + 'Error: Unauthorized access to ' + + 'chrome.os.events.startCapturingEvents. ' + + '%s' + ); + chrome.test.succeed(); + }, + async function stopCapturingEvents() { + await chrome.test.assertPromiseRejects( + chrome.os.events.stopCapturingEvents("audio_jack"), + 'Error: Unauthorized access to ' + + 'chrome.os.events.stopCapturingEvents. ' + + '%s' + ); + chrome.test.succeed(); + }, ]; chrome.test.runTests([ @@ -434,7 +462,8 @@ } apiNames = [ ...getMethods(chrome.os.telemetry).sort(), - ...getMethods(chrome.os.diagnostics).sort() + ...getMethods(chrome.os.diagnostics).sort(), + ...getMethods(chrome.os.events).sort() ]; chrome.test.assertEq(getTestNames(tests), apiNames); chrome.test.succeed(); @@ -459,6 +488,36 @@ extensions_features::kTelemetryExtensionPendingApprovalApi); } + protected: + std::string GetManifestFile(const std::string& matches_origin) override { + return base::StringPrintf(R"( + { + "key": "%s", + "name": "Test Telemetry Extension", + "version": "1", + "manifest_version": 3, + "chromeos_system_extension": {}, + "background": { + "service_worker": "sw.js" + }, + "permissions": [ + "os.diagnostics", + "os.events", + "os.telemetry", + "os.telemetry.serial_number", + "os.telemetry.network_info" + ], + "externally_connectable": { + "matches": [ + "%s" + ] + }, + "options_page": "options.html" + } + )", + public_key().c_str(), matches_origin.c_str()); + } + private: base::test::ScopedFeatureList feature_list_; };
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/events/BUILD.gn b/chrome/browser/chromeos/extensions/telemetry/api/events/BUILD.gn index 6a8fb36..deeba91 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/events/BUILD.gn +++ b/chrome/browser/chromeos/extensions/telemetry/api/events/BUILD.gn
@@ -16,6 +16,9 @@ ] deps = [ + ":event_converters", + ":event_manager", + ":event_router", "//base", "//build:chromeos_buildflags", "//chrome/browser/chromeos/extensions/telemetry/api/common", @@ -120,6 +123,7 @@ deps = [ ":events", "//chrome/browser/chromeos/extensions/telemetry/api/common:test_support", + "//chrome/test:test_support_ui", "//chromeos/crosapi/mojom", "//content/test:test_support", "//extensions/common", @@ -137,6 +141,10 @@ deps += [ "//chrome/browser/ash/telemetry_extension" ] } + + if (is_chromeos_lacros) { + deps += [ "//chromeos/lacros" ] + } } source_set("unit_tests") {
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/events/event_manager.cc b/chrome/browser/chromeos/extensions/telemetry/api/events/event_manager.cc index 7813c6c1..ff98442e 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/events/event_manager.cc +++ b/chrome/browser/chromeos/extensions/telemetry/api/events/event_manager.cc
@@ -159,7 +159,8 @@ return kPwaClosed; } if (event_router_.IsExtensionObservingForCategory(extension_id, category)) { - return kEventAlreadyObserved; + // Early return in case the category is already observed by the extension. + return kSuccess; } open_pwas_.emplace(extension_id, is_related_pwa_open);
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/events/event_manager.h b/chrome/browser/chromeos/extensions/telemetry/api/events/event_manager.h index 2d97bf8c..bbc86d5 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/events/event_manager.h +++ b/chrome/browser/chromeos/extensions/telemetry/api/events/event_manager.h
@@ -31,7 +31,6 @@ enum RegisterEventResult { kSuccess, kPwaClosed, - kEventAlreadyObserved, }; // extensions::BrowserContextKeyedAPI:
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api.cc b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api.cc index 047940e5..5c81b18 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api.cc +++ b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api.cc
@@ -4,8 +4,16 @@ #include "chrome/browser/chromeos/extensions/telemetry/api/events/events_api.h" -#include "base/notreached.h" +#include "base/check.h" +#include "base/functional/bind.h" #include "build/chromeos_buildflags.h" +#include "chrome/browser/chromeos/extensions/telemetry/api/events/event_manager.h" +#include "chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters.h" +#include "chrome/browser/chromeos/extensions/telemetry/api/events/remote_event_service_strategy.h" +#include "chrome/common/chromeos/extensions/api/events.h" +#include "chromeos/crosapi/mojom/telemetry_extension_exception.mojom.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #if BUILDFLAG(IS_CHROMEOS_LACROS) #include "chromeos/crosapi/mojom/telemetry_event_service.mojom.h" @@ -14,6 +22,12 @@ namespace chromeos { +// EventsApiFunctionBase ------------------------------------------------------- + +EventsApiFunctionBase::EventsApiFunctionBase() = default; + +EventsApiFunctionBase::~EventsApiFunctionBase() = default; + #if BUILDFLAG(IS_CHROMEOS_LACROS) bool EventsApiFunctionBase::IsCrosApiAvailable() { return LacrosService::Get() @@ -21,16 +35,101 @@ } #endif // BUILDFLAG(IS_CHROMEOS_LACROS) -void OsEventsIsEventSupportedFunction::RunIfAllowed() { - NOTIMPLEMENTED(); +template <class Params> +absl::optional<Params> EventsApiFunctionBase::GetParams() { + auto params = Params::Create(args()); + if (!params) { + SetBadMessage(); + Respond(BadMessage()); + } + + return params; } +// OsEventsIsEventSupportedFunction -------------------------------------------- + +void OsEventsIsEventSupportedFunction::RunIfAllowed() { + const auto params = GetParams<api::os_events::IsEventSupported::Params>(); + if (!params) { + return; + } + + auto* event_manager = EventManager::Get(browser_context()); + event_manager->IsEventSupported( + converters::Convert(params->category), + base::BindOnce(&OsEventsIsEventSupportedFunction::OnEventManagerResult, + this)); +} + +void OsEventsIsEventSupportedFunction::OnEventManagerResult( + crosapi::mojom::TelemetryExtensionSupportStatusPtr status) { + if (!status) { + Respond(Error("API internal error.")); + return; + } + + switch (status->which()) { + case crosapi::mojom::internal::TelemetryExtensionSupportStatus_Data:: + TelemetryExtensionSupportStatus_Tag::kUnmappedUnionField: + Respond(Error("API internal error.")); + break; + case crosapi::mojom::internal::TelemetryExtensionSupportStatus_Data:: + TelemetryExtensionSupportStatus_Tag::kException: + Respond(Error(status->get_exception()->debug_message)); + break; + case crosapi::mojom::internal::TelemetryExtensionSupportStatus_Data:: + TelemetryExtensionSupportStatus_Tag::kSupported: { + api::os_events::EventSupportStatusInfo success; + success.status = api::os_events::EventSupportStatus::kSupported; + Respond(ArgumentList( + api::os_events::IsEventSupported::Results::Create(success))); + break; + } + case crosapi::mojom::internal::TelemetryExtensionSupportStatus_Data:: + TelemetryExtensionSupportStatus_Tag::kUnsupported: + api::os_events::EventSupportStatusInfo result; + result.status = api::os_events::EventSupportStatus::kUnsupported; + + Respond(ArgumentList( + api::os_events::IsEventSupported::Results::Create(result))); + break; + } +} + +// OsEventsStartCapturingEventsFunction ---------------------------------------- + void OsEventsStartCapturingEventsFunction::RunIfAllowed() { - NOTIMPLEMENTED(); + const auto params = GetParams<api::os_events::StartCapturingEvents::Params>(); + if (!params) { + return; + } + + auto* event_manager = EventManager::Get(browser_context()); + auto result = event_manager->RegisterExtensionForEvent( + extension_id(), converters::Convert(params->category)); + + switch (result) { + case EventManager::kSuccess: + Respond(NoArguments()); + break; + case EventManager::kPwaClosed: + Respond(Error("Companion PWA UI is not open.")); + break; + } } +// OsEventsStopCapturingEventsFunction ----------------------------------------- + void OsEventsStopCapturingEventsFunction::RunIfAllowed() { - NOTIMPLEMENTED(); + const auto params = GetParams<api::os_events::StartCapturingEvents::Params>(); + if (!params) { + return; + } + + auto* event_manager = EventManager::Get(browser_context()); + event_manager->RemoveObservationsForExtensionAndCategory( + extension_id(), converters::Convert(params->category)); + Respond(NoArguments()); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api.h b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api.h index f46ec826..7bd54829 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api.h +++ b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api.h
@@ -7,20 +7,33 @@ #include "build/chromeos_buildflags.h" #include "chrome/browser/chromeos/extensions/telemetry/api/common/base_telemetry_extension_api_guard_function.h" +#include "chrome/browser/chromeos/extensions/telemetry/api/events/remote_event_service_strategy.h" +#include "chromeos/crosapi/mojom/telemetry_event_service.mojom.h" +#include "chromeos/crosapi/mojom/telemetry_extension_exception.mojom.h" #include "extensions/browser/extension_function.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace chromeos { class EventsApiFunctionBase : public BaseTelemetryExtensionApiGuardFunction { public: - EventsApiFunctionBase() = default; + EventsApiFunctionBase(); protected: - ~EventsApiFunctionBase() override = default; + ~EventsApiFunctionBase() override; #if BUILDFLAG(IS_CHROMEOS_LACROS) bool IsCrosApiAvailable() override; #endif // BUILDFLAG(IS_CHROMEOS_LACROS) + + mojo::Remote<crosapi::mojom::TelemetryEventService>& GetRemoteService(); + + // Gets the parameters passed to the JavaScript call and tries to convert it + // to the `Params` type. If the `Params` can't be created, this resolves the + // corresponding JavaScript call with an error and returns `nullopt`. + template <class Params> + absl::optional<Params> GetParams(); }; class OsEventsIsEventSupportedFunction : public EventsApiFunctionBase { @@ -34,6 +47,8 @@ private: ~OsEventsIsEventSupportedFunction() override = default; + void OnEventManagerResult( + crosapi::mojom::TelemetryExtensionSupportStatusPtr status); }; class OsEventsStartCapturingEventsFunction : public EventsApiFunctionBase {
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_browsertests.cc b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_browsertests.cc index cf91be81..6d2658c3 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_browsertests.cc +++ b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_browsertests.cc
@@ -2,12 +2,36 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <cstddef> +#include <memory> + +#include "base/allocator/partition_allocator/pointers/raw_ptr.h" +#include "base/location.h" +#include "base/test/bind.h" #include "base/test/scoped_feature_list.h" +#include "base/test/test_future.h" +#include "base/time/time.h" #include "chrome/browser/chromeos/extensions/telemetry/api/common/base_telemetry_extension_browser_test.h" +#include "chrome/browser/chromeos/extensions/telemetry/api/events/fake_events_service.h" +#include "chrome/test/base/ui_test_utils.h" +#include "chromeos/crosapi/mojom/telemetry_event_service.mojom.h" +#include "chromeos/crosapi/mojom/telemetry_extension_exception.mojom.h" +#include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" #include "extensions/common/extension_features.h" #include "testing/gtest/include/gtest/gtest.h" +#if BUILDFLAG(IS_CHROMEOS_ASH) +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ash/telemetry_extension/telemetry_event_service_ash.h" +#include "chrome/browser/chromeos/extensions/telemetry/api/events/fake_events_service_factory.h" +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + +#if BUILDFLAG(IS_CHROMEOS_LACROS) +#include "chromeos/lacros/lacros_service.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + namespace chromeos { class PendingApprovalTelemetryExtensionEventsApiBrowserTest @@ -18,6 +42,28 @@ extensions_features::kTelemetryExtensionPendingApprovalApi); } + void SetUpOnMainThread() override { + BaseTelemetryExtensionBrowserTest::SetUpOnMainThread(); +#if BUILDFLAG(IS_CHROMEOS_ASH) + fake_events_service_impl_ = new FakeEventsService(); + // SAFETY: We hand over ownership over the destruction of this pointer to + // the first caller of `TelemetryEventsServiceAsh::Create`. The only + // consumer of this is the `EventManager`, that lives as long as the profile + // and therefore longer than this test, so we are safe to access + // fake_events_service_impl_ in the test body. + fake_events_service_factory_.SetCreateInstanceResponse( + std::unique_ptr<FakeEventsService>(fake_events_service_impl_)); + ash::TelemetryEventServiceAsh::Factory::SetForTesting( + &fake_events_service_factory_); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS_LACROS) + fake_events_service_impl_ = std::make_unique<FakeEventsService>(); + // Replace the production TelemetryEventsService with a fake for testing. + chromeos::LacrosService::Get()->InjectRemoteForTesting( + fake_events_service_impl_->BindNewPipeAndPassRemote()); +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + } + protected: std::string GetManifestFile(const std::string& matches_origin) override { return base::StringPrintf(R"( @@ -48,28 +94,270 @@ public_key().c_str(), matches_origin.c_str()); } + FakeEventsService* GetFakeService() { + return fake_events_service_impl_.get(); + } + private: base::test::ScopedFeatureList feature_list_; + +#if BUILDFLAG(IS_CHROMEOS_ASH) + // SAFETY: This pointer is owned in a unique_ptr by the EventManager. Since + // the EventManager lives longer than this test, it is always safe to access + // the fake in the test body. + raw_ptr<FakeEventsService, base::RawPtrTraits::kMayDangle> + fake_events_service_impl_; + FakeEventsServiceFactory fake_events_service_factory_; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS_LACROS) + std::unique_ptr<FakeEventsService> fake_events_service_impl_; +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) }; IN_PROC_BROWSER_TEST_F(PendingApprovalTelemetryExtensionEventsApiBrowserTest, - SmokeTest) { + IsEventSupported_Error) { + auto exception = crosapi::mojom::TelemetryExtensionException::New(); + exception->reason = + crosapi::mojom::TelemetryExtensionException::Reason::kUnexpected; + exception->debug_message = "My test message"; + + auto input = crosapi::mojom::TelemetryExtensionSupportStatus::NewException( + std::move(exception)); + + GetFakeService()->SetIsEventSupportedResponse(std::move(input)); + CreateExtensionAndRunServiceWorker(R"( chrome.test.runTests([ - async function checkDefinitionsExist() { - chrome.test.assertTrue(chrome.os.events !== undefined); - chrome.test.assertTrue(chrome.os.events.isEventSupported !== undefined); - chrome.test.assertTrue( - chrome.os.events.startCapturingEvents !== undefined); - chrome.test.assertTrue( - chrome.os.events.stopCapturingEvents !== undefined); - chrome.test.assertTrue( - chrome.os.events.onAudioJackEvent !== undefined); + async function isEventSupported() { + await chrome.test.assertPromiseRejects( + chrome.os.events.isEventSupported("audio_jack"), + 'Error: My test message' + ); chrome.test.succeed(); } ]); )"); + + auto unmapped = + crosapi::mojom::TelemetryExtensionSupportStatus::NewUnmappedUnionField(0); + GetFakeService()->SetIsEventSupportedResponse(std::move(unmapped)); + + CreateExtensionAndRunServiceWorker(R"( + chrome.test.runTests([ + async function isEventSupported() { + await chrome.test.assertPromiseRejects( + chrome.os.events.isEventSupported("audio_jack"), + 'Error: API internal error.' + ); + + chrome.test.succeed(); + } + ]); + )"); +} + +IN_PROC_BROWSER_TEST_F(PendingApprovalTelemetryExtensionEventsApiBrowserTest, + IsEventSupported_Success) { + auto supported = + crosapi::mojom::TelemetryExtensionSupportStatus::NewSupported( + crosapi::mojom::TelemetryExtensionSupported::New()); + + GetFakeService()->SetIsEventSupportedResponse(std::move(supported)); + + CreateExtensionAndRunServiceWorker(R"( + chrome.test.runTests([ + async function isEventSupported() { + const result = await chrome.os.events.isEventSupported("audio_jack"); + chrome.test.assertEq(result, { + status: 'supported' + }); + + chrome.test.succeed(); + } + ]); + )"); + + auto unsupported = + crosapi::mojom::TelemetryExtensionSupportStatus::NewUnsupported( + crosapi::mojom::TelemetryExtensionUnsupported::New()); + + GetFakeService()->SetIsEventSupportedResponse(std::move(unsupported)); + + CreateExtensionAndRunServiceWorker(R"( + chrome.test.runTests([ + async function isEventSupported() { + const result = await chrome.os.events.isEventSupported("audio_jack"); + chrome.test.assertEq(result, { + status: 'unsupported' + }); + + chrome.test.succeed(); + } + ]); + )"); +} + +IN_PROC_BROWSER_TEST_F(PendingApprovalTelemetryExtensionEventsApiBrowserTest, + StartListeningToEvents_Success) { + // Open the PWA. + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(pwa_page_url()))); + + // Emit an event as soon as the subscription is registered with the fake. + GetFakeService()->SetOnSubscriptionChange( + base::BindLambdaForTesting([this]() { + auto audio_jack_info = + crosapi::mojom::TelemetryAudioJackEventInfo::New(); + audio_jack_info->state = + crosapi::mojom::TelemetryAudioJackEventInfo::State::kAdd; + + GetFakeService()->EmitEventForCategory( + crosapi::mojom::TelemetryEventCategoryEnum::kAudioJack, + crosapi::mojom::TelemetryEventInfo::NewAudioJackEventInfo( + std::move(audio_jack_info))); + })); + + CreateExtensionAndRunServiceWorker(R"( + chrome.test.runTests([ + async function startCapturingEvents() { + chrome.os.events.onAudioJackEvent.addListener((event) => { + chrome.test.assertEq(event, { + event: 'connected' + }); + + chrome.test.succeed(); + }); + + await chrome.os.events.startCapturingEvents("audio_jack"); + } + ]); + )"); +} + +IN_PROC_BROWSER_TEST_F(PendingApprovalTelemetryExtensionEventsApiBrowserTest, + StartListeningToEvents_ErrorPwaClosed) { + CreateExtensionAndRunServiceWorker(R"( + chrome.test.runTests([ + async function startCapturingEvents() { + await chrome.test.assertPromiseRejects( + chrome.os.events.startCapturingEvents("audio_jack"), + 'Error: Companion PWA UI is not open.' + ); + chrome.test.succeed(); + } + ]); + )"); +} + +IN_PROC_BROWSER_TEST_F(PendingApprovalTelemetryExtensionEventsApiBrowserTest, + StopListeningToEvents) { + // Open the PWA. + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(pwa_page_url()))); + + // Emit an event as soon as the subscription is registered with the fake. + GetFakeService()->SetOnSubscriptionChange( + base::BindLambdaForTesting([this]() { + auto audio_jack_info = + crosapi::mojom::TelemetryAudioJackEventInfo::New(); + audio_jack_info->state = + crosapi::mojom::TelemetryAudioJackEventInfo::State::kAdd; + + GetFakeService()->EmitEventForCategory( + crosapi::mojom::TelemetryEventCategoryEnum::kAudioJack, + crosapi::mojom::TelemetryEventInfo::NewAudioJackEventInfo( + std::move(audio_jack_info))); + })); + + CreateExtensionAndRunServiceWorker(R"( + chrome.test.runTests([ + async function startCapturingEvents() { + chrome.os.events.onAudioJackEvent.addListener((event) => { + chrome.test.assertEq(event, { + event: 'connected' + }); + + chrome.test.succeed(); + }); + + await chrome.os.events.startCapturingEvents("audio_jack"); + } + ]); + )"); + + base::test::TestFuture<size_t> remote_set_size; + GetFakeService()->SetOnSubscriptionChange( + base::BindLambdaForTesting([this, &remote_set_size]() { + auto* remote_set = GetFakeService()->GetObserversByCategory( + crosapi::mojom::TelemetryEventCategoryEnum::kAudioJack); + ASSERT_TRUE(remote_set); + + remote_set->FlushForTesting(); + remote_set_size.SetValue(remote_set->size()); + })); + + // Calling `stopCapturingEvents` will result in the connection being cut. + CreateExtensionAndRunServiceWorker(R"( + chrome.test.runTests([ + async function stopCapturingEvents() { + await chrome.os.events.stopCapturingEvents("audio_jack"); + chrome.test.succeed(); + } + ]); + )"); + + EXPECT_EQ(remote_set_size.Get(), 0UL); +} + +IN_PROC_BROWSER_TEST_F(PendingApprovalTelemetryExtensionEventsApiBrowserTest, + ClosePwaConnection) { + // Open the PWA. + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(pwa_page_url()))); + + // Emit an event as soon as the subscription is registered with the fake. + GetFakeService()->SetOnSubscriptionChange( + base::BindLambdaForTesting([this]() { + auto audio_jack_info = + crosapi::mojom::TelemetryAudioJackEventInfo::New(); + audio_jack_info->state = + crosapi::mojom::TelemetryAudioJackEventInfo::State::kAdd; + + GetFakeService()->EmitEventForCategory( + crosapi::mojom::TelemetryEventCategoryEnum::kAudioJack, + crosapi::mojom::TelemetryEventInfo::NewAudioJackEventInfo( + std::move(audio_jack_info))); + })); + + CreateExtensionAndRunServiceWorker(R"( + chrome.test.runTests([ + async function startCapturingEvents() { + chrome.os.events.onAudioJackEvent.addListener((event) => { + chrome.test.assertEq(event, { + event: 'connected' + }); + + chrome.test.succeed(); + }); + + await chrome.os.events.startCapturingEvents("audio_jack"); + } + ]); + )"); + + base::test::TestFuture<size_t> remote_set_size; + GetFakeService()->SetOnSubscriptionChange( + base::BindLambdaForTesting([this, &remote_set_size]() { + auto* remote_set = GetFakeService()->GetObserversByCategory( + crosapi::mojom::TelemetryEventCategoryEnum::kAudioJack); + ASSERT_TRUE(remote_set); + + remote_set->FlushForTesting(); + remote_set_size.SetValue(remote_set->size()); + })); + + // Closing the PWA will result in the connection being cut. + browser()->tab_strip_model()->CloseSelectedTabs(); + + EXPECT_EQ(remote_set_size.Get(), 0UL); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters.cc b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters.cc index b7fbcdc..6713ac6 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters.cc +++ b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters.cc
@@ -6,6 +6,7 @@ #include "base/notreached.h" #include "chrome/common/chromeos/extensions/api/events.h" +#include "chromeos/crosapi/mojom/telemetry_event_service.mojom.h" namespace chromeos::converters { @@ -35,4 +36,15 @@ NOTREACHED(); } +crosapi::mojom::TelemetryEventCategoryEnum Convert( + api::os_events::EventCategory input) { + switch (input) { + case api::os_events::EventCategory::kNone: + return crosapi::mojom::TelemetryEventCategoryEnum::kUnmappedEnumField; + case api::os_events::EventCategory::kAudioJack: + return crosapi::mojom::TelemetryEventCategoryEnum::kAudioJack; + } + NOTREACHED(); +} + } // namespace chromeos::converters
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters.h b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters.h index 7aa58aa4..79e58a18 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters.h +++ b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters.h
@@ -22,6 +22,9 @@ api::os_events::AudioJackEvent Convert( crosapi::mojom::TelemetryAudioJackEventInfo::State state); +crosapi::mojom::TelemetryEventCategoryEnum Convert( + api::os_events::EventCategory input); + template <class OutputT, class InputT> OutputT ConvertEventPtr(InputT input) { return (!input.is_null()) ? unchecked::UncheckedConvertPtr(std::move(input))
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters_unittest.cc b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters_unittest.cc index d744852c..3d9f950 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters_unittest.cc +++ b/chrome/browser/chromeos/extensions/telemetry/api/events/events_api_converters_unittest.cc
@@ -23,6 +23,14 @@ api::os_events::AudioJackEvent::kDisconnected); } +TEST(TelemetryExtensionEventsApiConvertersUnitTest, ConvertEventCategoryEnum) { + EXPECT_EQ(Convert(api::os_events::EventCategory::kNone), + crosapi::mojom::TelemetryEventCategoryEnum::kUnmappedEnumField); + + EXPECT_EQ(Convert(api::os_events::EventCategory::kAudioJack), + crosapi::mojom::TelemetryEventCategoryEnum::kAudioJack); +} + TEST(TelemetryExtensionEventsApiConvertersUnitTest, ConvertAudioJackEventInfo) { auto input = crosapi::mojom::TelemetryAudioJackEventInfo::New(); input->state = crosapi::mojom::TelemetryAudioJackEventInfo::State::kAdd;
diff --git a/chrome/browser/extensions/api/printing/print_job_controller.cc b/chrome/browser/extensions/api/printing/print_job_controller.cc index 8f27d46..dccb5066 100644 --- a/chrome/browser/extensions/api/printing/print_job_controller.cc +++ b/chrome/browser/extensions/api/printing/print_job_controller.cc
@@ -15,7 +15,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/printing/print_job.h" #include "chrome/browser/printing/printer_query.h" -#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_host.h" #include "content/public/browser/global_routing_id.h" @@ -27,29 +26,6 @@ namespace { -using PrinterQueryCallback = - base::OnceCallback<void(std::unique_ptr<printing::PrinterQuery>)>; - -// Send initialized PrinterQuery to UI thread. -void OnSettingsSetOnIOThread(std::unique_ptr<printing::PrinterQuery> query, - PrinterQueryCallback callback) { - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), std::move(query))); -} - -void CreateQueryOnIOThread(std::unique_ptr<printing::PrintSettings> settings, - PrinterQueryCallback callback) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - auto query = - printing::PrinterQuery::Create(content::GlobalRenderFrameHostId()); - auto* query_ptr = query.get(); - query_ptr->SetSettingsFromPOD( - std::move(settings), - base::BindOnce(&OnSettingsSetOnIOThread, std::move(query), - std::move(callback))); -} - void StartPrinting(scoped_refptr<printing::PrintJob> job, const std::string& extension_id, std::unique_ptr<printing::MetafileSkia> metafile, @@ -87,10 +63,14 @@ auto job = base::MakeRefCounted<printing::PrintJob>( g_browser_process->print_job_manager()); - content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&CreateQueryOnIOThread, std::move(settings), - base::BindOnce(StartPrinting, job, extension_id, - std::move(metafile)))); + + auto query = + printing::PrinterQuery::Create(content::GlobalRenderFrameHostId()); + auto* query_ptr = query.get(); + query_ptr->SetSettingsFromPOD( + std::move(settings), + base::BindOnce(&StartPrinting, job, extension_id, std::move(metafile), + std::move(query))); return job; }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 2ede7a50..923883bc 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -5331,6 +5331,11 @@ "expiry_milestone": 120 }, { + "name": "omnibox-actions-in-suggest", + "owners": [ "ender", "chrome-mobile-search@google.com" ], + "expiry_milestone": 130 + }, + { "name": "omnibox-adapt-narrow-tablet-windows", "owners": [ "pnoland", "chrome-omnibox-team@google.com" ], "expiry_milestone": 120 @@ -7801,11 +7806,6 @@ "expiry_milestone": 130 }, { - "name": "win-10-tab-search-caption-button", - "owners": [ "tluk@google.com", "chrome-cros@google.com" ], - "expiry_milestone": 99 - }, - { "name": "window-layout-menu", "owners": [ "shidi", "chromeos-wmp-eng@google.com" ], "expiry_milestone": 122
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index edac55e9..2b58d6bf 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2044,6 +2044,11 @@ "credential mode disallows. Without this flag enabled, Chrome will always " "try sending client certificates regardless of the credential mode."; +const char kOmniboxActionsInSuggestName[] = "Action in Suggest"; +const char kOmniboxActionsInSuggestDescription[] = + "Actions in Suggest permits optional Action Chips to be attached to " + "Entity suggestions."; + const char kOmniboxAdaptiveSuggestionsCountName[] = "Adaptive Omnibox Suggestions count"; const char kOmniboxAdaptiveSuggestionsCountDescription[] = @@ -4781,11 +4786,6 @@ "printing PDF documents."; #endif // BUILDFLAG(ENABLE_PRINTING) -const char kWin10TabSearchCaptionButtonName[] = - "Windows 10 Tab Search Caption Button"; -const char kWin10TabSearchCaptionButtonDescription[] = - "Move the Tab Search entrypoint besides the window caption buttons on " - "Windows 10 platforms."; #endif // BUILDFLAG(IS_WIN) // Mac -------------------------------------------------------------------------
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 9a31853..83e1319 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1155,6 +1155,9 @@ extern const char kOmitCorsClientCertName[]; extern const char kOmitCorsClientCertDescription[]; +extern const char kOmniboxActionsInSuggestName[]; +extern const char kOmniboxActionsInSuggestDescription[]; + extern const char kOmniboxAdaptiveSuggestionsCountName[]; extern const char kOmniboxAdaptiveSuggestionsCountDescription[]; @@ -2745,8 +2748,6 @@ extern const char kUseXpsForPrintingFromPdfDescription[]; #endif // BUILDFLAG(ENABLE_PRINTING) -extern const char kWin10TabSearchCaptionButtonName[]; -extern const char kWin10TabSearchCaptionButtonDescription[]; #endif // BUILDFLAG(IS_WIN) // Mac ------------------------------------------------------------------------
diff --git a/chrome/browser/printing/printer_query.cc b/chrome/browser/printing/printer_query.cc index 53e3de6..e5171c72 100644 --- a/chrome/browser/printing/printer_query.cc +++ b/chrome/browser/printing/printer_query.cc
@@ -151,6 +151,8 @@ absl::optional<bool> maybe_is_modifiable, std::unique_ptr<PrintSettings> new_settings, mojom::ResultCode result) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + // `this` is owned by `callback`, so `base::Unretained()` is safe. content::GetUIThreadTaskRunner({})->PostTask( FROM_HERE, @@ -294,12 +296,6 @@ return printing_context_->TakeAndResetSettings(); } -bool PrinterQuery::PostTask(const base::Location& from_here, - base::OnceClosure task) { - return content::GetUIThreadTaskRunner({})->PostTask(from_here, - std::move(task)); -} - void PrinterQuery::InvokeSettingsCallback(SettingsCallback callback, mojom::ResultCode result) { std::move(callback).Run(printing_context_->TakeAndResetSettings(), result);
diff --git a/chrome/browser/printing/printer_query.h b/chrome/browser/printing/printer_query.h index afd9eae..ac99fae 100644 --- a/chrome/browser/printing/printer_query.h +++ b/chrome/browser/printing/printer_query.h
@@ -109,9 +109,6 @@ // Returns true if a PrintingContext is still associated to this instance. bool is_valid() const; - // Posts the given task to be run. - bool PostTask(const base::Location& from_here, base::OnceClosure task); - // Provide an override for generating worker threads in tests. static void SetCreatePrinterQueryCallbackForTest( CreatePrinterQueryCallback* callback);
diff --git a/chrome/browser/quick_delete/BUILD.gn b/chrome/browser/quick_delete/BUILD.gn index 9158832..723c4c8 100644 --- a/chrome/browser/quick_delete/BUILD.gn +++ b/chrome/browser/quick_delete/BUILD.gn
@@ -15,10 +15,17 @@ ":java_resources", "//base:base_java", "//chrome/browser/flags:java", + "//chrome/browser/profiles/android:java", + "//chrome/browser/signin/services/android:java", + "//chrome/browser/tab:java", + "//chrome/browser/tabmodel:java", "//chrome/browser/tabmodel:java", "//chrome/browser/ui/android/layouts:java", "//chrome/browser/ui/messages/android:java", "//components/browsing_data/core:java", + "//components/embedder_support/android:util_java", + "//components/signin/public/android:java", + "//content/public/android:content_full_java", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/androidx:androidx_annotation_annotation_jvm_java", "//ui/android:ui_no_recycler_view_java", @@ -51,10 +58,18 @@ "//base:base_java_test_support", "//base:base_junit_test_support", "//chrome/browser/flags:java", + "//chrome/browser/profiles/android:java", + "//chrome/browser/signin/services/android:java", + "//chrome/browser/tab:java", + "//chrome/browser/tabmodel:java", "//chrome/browser/ui/messages/android:java", "//chrome/test/android:chrome_java_integration_test_support", "//chrome/test/android:chrome_java_test_support_common", "//components/browsing_data/core:java", + "//components/embedder_support/android:util_java", + "//components/signin/public/android:java", + "//components/signin/public/android:signin_java_test_support", + "//content/public/android:content_full_java", "//third_party/androidx:androidx_test_runner_java", "//third_party/junit:junit", "//third_party/mockito:mockito_java",
diff --git a/chrome/browser/quick_delete/android/java/res/layout/quick_delete_dialog.xml b/chrome/browser/quick_delete/android/java/res/layout/quick_delete_dialog.xml index b29e016..1096374 100644 --- a/chrome/browser/quick_delete/android/java/res/layout/quick_delete_dialog.xml +++ b/chrome/browser/quick_delete/android/java/res/layout/quick_delete_dialog.xml
@@ -54,4 +54,11 @@ app:chromeDrawableTint="@macro/default_icon_color" android:text="@string/clear_cache_title" android:textAppearance="@style/TextAppearance.TextMedium.Secondary" /> + + <org.chromium.ui.widget.TextViewWithClickableSpans + android:id="@+id/search_history_disambiguation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="16dp" + android:visibility="gone" /> </LinearLayout>
diff --git a/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteController.java b/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteController.java index 88e41dc..4215874 100644 --- a/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteController.java +++ b/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteController.java
@@ -15,6 +15,7 @@ import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault; import org.chromium.chrome.browser.layouts.LayoutManager; import org.chromium.chrome.browser.layouts.LayoutType; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.ui.modaldialog.DialogDismissalCause; @@ -41,16 +42,19 @@ * @param modalDialogManager A {@link ModalDialogManager} to show the quick delete modal dialog. * @param snackbarManager A {@link SnackbarManager} to show the quick delete snackbar. * @param layoutManager {@link LayoutManager} to use for showing the regular overview mode. + * @param tabModelSelector {@link TabModelSelector} to use for opening the links in search + * history disambiguation notice. */ public QuickDeleteController(@NonNull Context context, @NonNull QuickDeleteDelegate delegate, @NonNull ModalDialogManager modalDialogManager, - @NonNull SnackbarManager snackbarManager, @NonNull LayoutManager layoutManager) { + @NonNull SnackbarManager snackbarManager, @NonNull LayoutManager layoutManager, + @NonNull TabModelSelector tabModelSelector) { mContext = context; mDelegate = delegate; mSnackbarManager = snackbarManager; mLayoutManager = layoutManager; - mDialogDelegate = - new QuickDeleteDialogDelegate(context, modalDialogManager, this::onDialogDismissed); + mDialogDelegate = new QuickDeleteDialogDelegate( + context, modalDialogManager, this::onDialogDismissed, tabModelSelector); } /**
diff --git a/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegate.java b/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegate.java index bc1d568..83db50d 100644 --- a/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegate.java +++ b/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegate.java
@@ -5,16 +5,28 @@ package org.chromium.chrome.browser.quick_delete; import android.content.Context; +import android.text.SpannableString; +import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; import android.view.View; import androidx.annotation.NonNull; import org.chromium.base.Callback; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.signin.services.IdentityServicesProvider; +import org.chromium.chrome.browser.tab.TabLaunchType; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.components.embedder_support.util.UrlConstants; +import org.chromium.components.signin.identitymanager.ConsentLevel; +import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogProperties; import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.text.NoUnderlineClickableSpan; +import org.chromium.ui.text.SpanApplier; +import org.chromium.ui.widget.TextViewWithClickableSpans; /** * A delegate responsible for providing logic around the quick delete modal dialog. @@ -23,6 +35,7 @@ private final @NonNull ModalDialogManager mModalDialogManager; private final @NonNull Context mContext; private final @NonNull Callback<Integer> mOnDismissCallback; + private final @NonNull TabModelSelector mTabModelSelector; /**The {@link PropertyModel} of the underlying dialog where the quick dialog view would be * shown.*/ private final PropertyModel mModalDialogPropertyModel; @@ -55,13 +68,17 @@ * delete modal dialog. * @param onDismissCallback A {@link Callback} that will be notified when the user confirms or * cancels the deletion; + * @param tabModelSelector {@link TabModelSelector} to use for opening the links in search + * history disambiguation notice. */ QuickDeleteDialogDelegate(@NonNull Context context, @NonNull ModalDialogManager modalDialogManager, - @NonNull Callback<Integer> onDismissCallback) { + @NonNull Callback<Integer> onDismissCallback, + @NonNull TabModelSelector tabModelSelector) { mContext = context; mModalDialogManager = modalDialogManager; mOnDismissCallback = onDismissCallback; + mTabModelSelector = tabModelSelector; mModalDialogPropertyModel = createQuickDeleteDialogProperty(); } @@ -72,6 +89,30 @@ View quickDeleteDialogView = LayoutInflater.from(mContext).inflate(R.layout.quick_delete_dialog, /*root=*/null); + TextViewWithClickableSpans searchHistoryDisambiguation = + quickDeleteDialogView.findViewById(R.id.search_history_disambiguation); + + if (isSignedIn()) { + // Add search history and other activity links to search history disambiguation notice + // in the dialog. + final SpannableString searchHistoryText = SpanApplier.applySpans( + mContext.getString( + R.string.quick_delete_dialog_search_history_disambiguation_text), + new SpanApplier.SpanInfo("<link1>", "</link1>", + new NoUnderlineClickableSpan(mContext, + (widget) + -> openUrlInNewTab( + UrlConstants.GOOGLE_SEARCH_HISTORY_URL_IN_QD))), + new SpanApplier.SpanInfo("<link2>", "</link2>", + new NoUnderlineClickableSpan(mContext, + (widget) + -> openUrlInNewTab( + UrlConstants.MY_ACTIVITY_URL_IN_QD)))); + searchHistoryDisambiguation.setText(searchHistoryText); + searchHistoryDisambiguation.setMovementMethod(LinkMovementMethod.getInstance()); + searchHistoryDisambiguation.setVisibility(View.VISIBLE); + } + return new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS) .with(ModalDialogProperties.CONTROLLER, mModalDialogController) .with(ModalDialogProperties.TITLE, @@ -88,6 +129,27 @@ } /** + * Opens a url in a new non-incognito tab and dismisses the dialog. + * @param url The URL of the page to load, either GOOGLE_SEARCH_HISTORY_URL_IN_QD or + * MY_ACTIVITY_URL_IN_QD. + */ + private void openUrlInNewTab(final String url) { + mTabModelSelector.openNewTab(new LoadUrlParams(url), TabLaunchType.FROM_CHROME_UI, + mTabModelSelector.getCurrentTab(), false); + mModalDialogManager.dismissDialog( + mModalDialogPropertyModel, DialogDismissalCause.ACTION_ON_CONTENT); + } + + /** + * @return A boolean indicating whether the user is signed in or not. + */ + private boolean isSignedIn() { + Profile profile = mTabModelSelector.getCurrentModel().getProfile(); + return IdentityServicesProvider.get().getIdentityManager(profile).hasPrimaryAccount( + ConsentLevel.SIGNIN); + } + + /** * Shows the Quick delete dialog. */ void showDialog() {
diff --git a/chrome/browser/quick_delete/android/javatests/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegateTest.java b/chrome/browser/quick_delete/android/javatests/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegateTest.java index 3a6dc85..eede269 100644 --- a/chrome/browser/quick_delete/android/javatests/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegateTest.java +++ b/chrome/browser/quick_delete/android/javatests/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegateTest.java
@@ -16,13 +16,12 @@ import android.view.View; import androidx.test.espresso.matcher.ViewMatchers; -import androidx.test.filters.SmallTest; +import androidx.test.filters.MediumTest; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.MockitoAnnotations; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; @@ -34,6 +33,7 @@ import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.util.ChromeRenderTestRule; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; +import org.chromium.chrome.test.util.browser.signin.SigninTestRule; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.modaldialog.ModalDialogProperties; @@ -51,6 +51,9 @@ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); @Rule + public final SigninTestRule mSigninTestRule = new SigninTestRule(); + + @Rule public ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() .setBugComponent(ChromeRenderTestRule.Component.PRIVACY) @@ -58,15 +61,15 @@ @Before public void setUp() { - MockitoAnnotations.initMocks(this); mActivityTestRule.startMainActivityOnBlankPage(); } @Test - @SmallTest + @MediumTest @Feature({"RenderTest"}) public void testQuickDeleteDialogView() throws IOException { openQuickDeleteDialog(); + onView(withText(R.string.quick_delete_dialog_title)).check(matches(isDisplayed())); onView(withText(R.string.quick_delete_dialog_description)).check(matches(isDisplayed())); onView(withText(R.string.clear_history_title)).check(matches(isDisplayed())); @@ -82,6 +85,23 @@ mRenderTestRule.render(dialogView, "quick_delete_dialog"); } + @Test + @MediumTest + @Feature({"RenderTest"}) + public void testSearchHistoryDisambiguationTextShown_WhenUserIsSignedIn() throws IOException { + mSigninTestRule.addTestAccountThenSignin(); + openQuickDeleteDialog(); + + onView(withId(R.id.search_history_disambiguation)).check(matches(isDisplayed())); + + View dialogView = mActivityTestRule.getActivity() + .getModalDialogManager() + .getCurrentDialogForTest() + .get(ModalDialogProperties.CUSTOM_VIEW); + + mRenderTestRule.render(dialogView, "quick_delete_dialog-signed-in"); + } + private void openQuickDeleteDialog() { // Open 3 dot menu. TestThreadUtils.runOnUiThreadBlocking(() -> {
diff --git a/chrome/browser/quick_delete/android/junit/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegateUnitTest.java b/chrome/browser/quick_delete/android/junit/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegateUnitTest.java index 29c522ac..103a0f5 100644 --- a/chrome/browser/quick_delete/android/junit/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegateUnitTest.java +++ b/chrome/browser/quick_delete/android/junit/src/org/chromium/chrome/browser/quick_delete/QuickDeleteDialogDelegateUnitTest.java
@@ -4,18 +4,23 @@ package org.chromium.chrome.browser.quick_delete; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; import android.app.Activity; +import android.view.View; import androidx.test.filters.SmallTest; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; @@ -23,10 +28,23 @@ import org.chromium.base.Callback; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.Batch; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.signin.services.IdentityServicesProvider; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab.TabLaunchType; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.components.embedder_support.util.UrlConstants; +import org.chromium.components.signin.identitymanager.ConsentLevel; +import org.chromium.components.signin.identitymanager.IdentityManager; +import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.ui.base.TestActivity; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; +import org.chromium.ui.modaldialog.ModalDialogProperties; import org.chromium.ui.test.util.modaldialog.FakeModalDialogManager; +import org.chromium.ui.widget.TextViewWithClickableSpans; /** * Unit tests for Quick Delete dialog. @@ -35,35 +53,148 @@ @Batch(Batch.UNIT_TESTS) public class QuickDeleteDialogDelegateUnitTest { @Mock - private Callback<Integer> mOnDismissCallback; + private Callback<Integer> mOnDismissCallbackMock; + + @Mock + private TabModelSelector mTabModelSelectorMock; + + @Mock + private IdentityServicesProvider mIdentityServicesProviderMock; + + @Mock + private Profile mProfileMock; + + @Mock + private Tab mTabMock; + + @Mock + private TabModel mTabModelMock; + + @Mock + private IdentityManager mIdentityManagerMock; private FakeModalDialogManager mModalDialogManager; + private Activity mActivity; + @Before public void setUp() { MockitoAnnotations.initMocks(this); - Activity activity = Robolectric.buildActivity(TestActivity.class).setup().get(); + + mActivity = Robolectric.buildActivity(TestActivity.class).setup().get(); mModalDialogManager = new FakeModalDialogManager(ModalDialogManager.ModalDialogType.APP); - new QuickDeleteDialogDelegate(activity, mModalDialogManager, mOnDismissCallback) - .showDialog(); + + when(mTabModelSelectorMock.getCurrentModel()).thenReturn(mTabModelMock); + when(mTabModelMock.getProfile()).thenReturn(mProfileMock); + + when(mIdentityServicesProviderMock.getIdentityManager(mProfileMock)) + .thenReturn(mIdentityManagerMock); + when(mTabModelSelectorMock.getCurrentTab()).thenReturn(mTabMock); + IdentityServicesProvider.setInstanceForTests(mIdentityServicesProviderMock); } @After public void tearDown() { - verifyNoMoreInteractions(mOnDismissCallback); + verifyNoMoreInteractions(mOnDismissCallbackMock); + } + + private void setSignedInStatus(boolean isSignedIn) { + when(mIdentityManagerMock.hasPrimaryAccount(ConsentLevel.SIGNIN)).thenReturn(isSignedIn); } @Test @SmallTest public void testCancelQuickDelete() { + setSignedInStatus(false); + new QuickDeleteDialogDelegate( + mActivity, mModalDialogManager, mOnDismissCallbackMock, mTabModelSelectorMock) + .showDialog(); + mModalDialogManager.clickNegativeButton(); - verify(mOnDismissCallback, times(1)).onResult(DialogDismissalCause.NEGATIVE_BUTTON_CLICKED); + verify(mOnDismissCallbackMock, times(1)) + .onResult(DialogDismissalCause.NEGATIVE_BUTTON_CLICKED); } @Test @SmallTest public void testConfirmQuickDelete() { + setSignedInStatus(false); + new QuickDeleteDialogDelegate( + mActivity, mModalDialogManager, mOnDismissCallbackMock, mTabModelSelectorMock) + .showDialog(); + mModalDialogManager.clickPositiveButton(); - verify(mOnDismissCallback, times(1)).onResult(DialogDismissalCause.POSITIVE_BUTTON_CLICKED); + verify(mOnDismissCallbackMock, times(1)) + .onResult(DialogDismissalCause.POSITIVE_BUTTON_CLICKED); + } + + @Test + @SmallTest + public void testSearchHistoryDisambiguationNotShown_WhenUserIsSignedOut() { + setSignedInStatus(false); + new QuickDeleteDialogDelegate( + mActivity, mModalDialogManager, mOnDismissCallbackMock, mTabModelSelectorMock) + .showDialog(); + + View dialogView = + mModalDialogManager.getShownDialogModel().get(ModalDialogProperties.CUSTOM_VIEW); + + TextViewWithClickableSpans searchHistoryDisambiguation = + dialogView.findViewById(R.id.search_history_disambiguation); + + Assert.assertEquals(searchHistoryDisambiguation.getVisibility(), View.GONE); + } + + @Test + @SmallTest + public void testSearchHistoryDisambiguation_SearchHistoryLink() { + setSignedInStatus(true); + new QuickDeleteDialogDelegate( + mActivity, mModalDialogManager, mOnDismissCallbackMock, mTabModelSelectorMock) + .showDialog(); + + View dialogView = + mModalDialogManager.getShownDialogModel().get(ModalDialogProperties.CUSTOM_VIEW); + + TextViewWithClickableSpans searchHistoryDisambiguation = + dialogView.findViewById(R.id.search_history_disambiguation); + + Assert.assertEquals(searchHistoryDisambiguation.getClickableSpans().length, 2); + searchHistoryDisambiguation.getClickableSpans()[0].onClick(searchHistoryDisambiguation); + + ArgumentCaptor<LoadUrlParams> argument = ArgumentCaptor.forClass(LoadUrlParams.class); + + verify(mTabModelSelectorMock, times(1)) + .openNewTab(argument.capture(), eq(TabLaunchType.FROM_CHROME_UI), eq(mTabMock), + eq(false)); + Assert.assertEquals( + UrlConstants.GOOGLE_SEARCH_HISTORY_URL_IN_QD, argument.getValue().getUrl()); + verify(mOnDismissCallbackMock, times(1)).onResult(DialogDismissalCause.ACTION_ON_CONTENT); + } + + @Test + @SmallTest + public void testSearchHistoryDisambiguation_OtherActivityLink() { + setSignedInStatus(true); + new QuickDeleteDialogDelegate( + mActivity, mModalDialogManager, mOnDismissCallbackMock, mTabModelSelectorMock) + .showDialog(); + + View dialogView = + mModalDialogManager.getShownDialogModel().get(ModalDialogProperties.CUSTOM_VIEW); + + TextViewWithClickableSpans searchHistoryDisambiguation = + dialogView.findViewById(R.id.search_history_disambiguation); + + Assert.assertEquals(searchHistoryDisambiguation.getClickableSpans().length, 2); + searchHistoryDisambiguation.getClickableSpans()[1].onClick(searchHistoryDisambiguation); + + ArgumentCaptor<LoadUrlParams> argument = ArgumentCaptor.forClass(LoadUrlParams.class); + + verify(mTabModelSelectorMock, times(1)) + .openNewTab(argument.capture(), eq(TabLaunchType.FROM_CHROME_UI), eq(mTabMock), + eq(false)); + Assert.assertEquals(UrlConstants.MY_ACTIVITY_URL_IN_QD, argument.getValue().getUrl()); + verify(mOnDismissCallbackMock, times(1)).onResult(DialogDismissalCause.ACTION_ON_CONTENT); } }
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts index ce2e039..f3b1780 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
@@ -106,15 +106,10 @@ private searchExtensionEnabled: boolean; private incognito: boolean; private gifSupport: boolean; - - private scrollTimeout: number|null = null; - private groupScrollTimeout: number|null = null; - private groupButtonScrollTimeout: number|null = null; private activeVariant: EmojiGroupComponent|null = null; private apiProxy: EmojiPickerApiProxy = EmojiPickerApiProxyImpl.getInstance(); private autoScrollingToGroup: boolean = false; private highlightBarMoving: boolean = false; - private groupTabsMoving: boolean = false; private nextGifPos: {[key: string]: string}; private status: Status|null; private previousGifValidation: Date; @@ -661,13 +656,9 @@ } private onEmojiScroll() { - // the scroll event is fired very frequently while scrolling. - // only update active tab 100ms after last scroll event by setting - // a timeout. - if (this.scrollTimeout) { - clearTimeout(this.scrollTimeout); - } - this.scrollTimeout = setTimeout(() => { + // The scroll event is fired very frequently while scrolling. + // Thus we wrap it with `requestAnimationFrame` + requestAnimationFrame(() => { this.updateActiveCategory(); this.updateActiveGroup(); // Using ! here as this.status will always exist when GIF support is on. @@ -675,7 +666,7 @@ !this.isGifInErrorState(this.status!)) { this.checkScrollPosition(); } - }, 100); + }); } private onRightChevronClick() { @@ -685,7 +676,6 @@ constants.EMOJI_NUM_TABS_IN_FIRST_PAGE; this.scrollToGroup( EMOJI_GROUP_TABS[constants.GROUP_PER_ROW - 1]?.groupId); - this.groupTabsMoving = true; this.$.bar.style.left = constants.EMOJI_PICKER_TOTAL_EMOJI_WIDTH_PX; } else { const maxPagination = @@ -705,8 +695,6 @@ this.emojiGroupTabs.find((tab) => tab.pagination === this.pagination); if (this.category === CategoryEnum.GIF && nextTab) { this.setGifGroupElements(nextTab.groupId); - } else { - this.groupTabsMoving = true; } this.scrollToGroup(nextTab?.groupId); } @@ -729,18 +717,7 @@ return; } - this.groupTabsMoving = true; - - if (this.groupButtonScrollTimeout) { - clearTimeout(this.groupButtonScrollTimeout); - } - this.groupButtonScrollTimeout = - setTimeout(this.groupTabScrollFinished.bind(this), 100); - } - - private groupTabScrollFinished() { - this.groupTabsMoving = false; - this.updateActiveGroup(); + requestAnimationFrame(() => this.updateActiveGroup()); } private updateChevrons() { @@ -903,7 +880,7 @@ } // Once tab scroll is updated, update the position of the highlight bar. - if (!this.highlightBarMoving && !this.groupTabsMoving) { + if (!this.highlightBarMoving) { // Update the scroll position of the emoji groups so that active group is // visible. if (!this.textSubcategoryBarEnabled) {
diff --git a/chrome/browser/resources/password_manager/checkup_list_item.html b/chrome/browser/resources/password_manager/checkup_list_item.html index 3857a199..9a3e1d1 100644 --- a/chrome/browser/resources/password_manager/checkup_list_item.html +++ b/chrome/browser/resources/password_manager/checkup_list_item.html
@@ -25,6 +25,7 @@ color: var(--cr-secondary-text-color); font-size: inherit; margin-inline-start: 4px; + max-width: 10ch; } #usernameContainer {
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn index 69c8e93e..9122fb8 100644 --- a/chrome/browser/resources/settings/BUILD.gn +++ b/chrome/browser/resources/settings/BUILD.gn
@@ -265,9 +265,6 @@ if (is_chromeos) { web_component_files += [ "controls/password_prompt_dialog.ts" ] } - if (is_chrome_branded) { - web_component_files += [ "get_most_chrome_page/get_most_chrome_page.ts" ] - } # -----------------web_component_files end ----------------------------------
diff --git a/chrome/browser/resources/settings/about_page/about_page.ts b/chrome/browser/resources/settings/about_page/about_page.ts index 52c24ff3..4608d09d 100644 --- a/chrome/browser/resources/settings/about_page/about_page.ts +++ b/chrome/browser/resources/settings/about_page/about_page.ts
@@ -31,11 +31,6 @@ import {loadTimeData} from '../i18n_setup.js'; import {RelaunchMixin, RestartType} from '../relaunch_mixin.js'; -// <if expr="_google_chrome"> -import {routes} from '../route.js'; -import {Router} from '../router.js'; - -// </if> import {getTemplate} from './about_page.html.js'; import {AboutPageBrowserProxy, AboutPageBrowserProxyImpl, UpdateStatus, UpdateStatusChangedEvent} from './about_page_browser_proxy.js'; @@ -45,7 +40,6 @@ // </if> // clang-format on - const SettingsAboutPageElementBase = RelaunchMixin(WebUiListenerMixin(I18nMixin(PolymerElement))); @@ -88,8 +82,7 @@ showGetTheMostOutOfChromeSection_: { type: Boolean, value() { - return loadTimeData.getBoolean('showGetTheMostOutOfChromeSection') && - !loadTimeData.getBoolean('isGuest'); + return loadTimeData.getBoolean('showGetTheMostOutOfChromeSection'); }, }, // </if> @@ -349,8 +342,8 @@ this.aboutBrowserProxy_.openFeedbackDialog(); } - private onGetTheMostOutOfChromeTap_() { - Router.getInstance().navigateTo(routes.GET_MOST_CHROME); + private onGetTheMostOutOfChromeClick_() { + // TODO(crbug.com/1423278): implement. } // </if>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html index 2c9d775..55ad4f0 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.html +++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -205,16 +205,6 @@ <settings-reset-page prefs="{{prefs}}"></settings-reset-page> </settings-section> </template> -<if expr="_google_chrome"> - <template is="dom-if" - if="[[showGetMostChrome_(pageVisibility.getMostChrome)]]" - restamp> - <settings-section page-title="$i18n{getTheMostOutOfChrome}" - section="getMostChrome"> - <settings-get-most-chrome-page></settings-get-most-chrome-page> - </settings-section> - </template> -</if> </div> </template> </settings-idle-load>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.ts b/chrome/browser/resources/settings/basic_page/basic_page.ts index bea931e..000a5c0 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.ts +++ b/chrome/browser/resources/settings/basic_page/basic_page.ts
@@ -395,11 +395,6 @@ } // <if expr="_google_chrome"> - private showGetMostChrome_(visibility?: boolean): boolean { - return visibility !== false && - loadTimeData.getBoolean('showGetTheMostOutOfChromeSection'); - } - private onSendHighEfficiencyFeedbackClick_(e: Event) { e.stopPropagation(); this.performanceBrowserProxy_.openHighEfficiencyFeedbackDialog();
diff --git a/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.html b/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.html deleted file mode 100644 index 7c89b54..0000000 --- a/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.html +++ /dev/null
@@ -1 +0,0 @@ -<div></div>
diff --git a/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.ts b/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.ts deleted file mode 100644 index 029614ab..0000000 --- a/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.ts +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview - * 'settings-get-most-chrome-page' is the settings page information about how - * to get the most out of Chrome. - */ - -import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {getTemplate} from './get_most_chrome_page.html.js'; - -export class SettingsGetMostChromePageElement extends PolymerElement { - static get is() { - return 'settings-get-most-chrome-page'; - } - - static get template() { - return getTemplate(); - } -} - -declare global { - interface HTMLElementTagNameMap { - 'settings-get-most-chrome-page': SettingsGetMostChromePageElement; - } -} - -customElements.define( - SettingsGetMostChromePageElement.is, SettingsGetMostChromePageElement);
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts index 04d16b8..4fc7d32 100644 --- a/chrome/browser/resources/settings/lazy_load.ts +++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -66,9 +66,6 @@ // Sections import './a11y_page/a11y_page.js'; import './downloads_page/downloads_page.js'; -// <if expr="_google_chrome"> -import './get_most_chrome_page/get_most_chrome_page.js'; -// </if> // <if expr="not chromeos_ash"> import './languages_page/languages_page.js'; import './languages_page/spell_check_page.js'; @@ -141,9 +138,6 @@ export {SettingsSliderElement} from './controls/settings_slider.js'; export {DownloadsBrowserProxy, DownloadsBrowserProxyImpl} from './downloads_page/downloads_browser_proxy.js'; export {SettingsDownloadsPageElement} from './downloads_page/downloads_page.js'; -// <if expr="_google_chrome"> -export {SettingsGetMostChromePageElement} from './get_most_chrome_page/get_most_chrome_page.js'; -// </if> // <if expr="_google_chrome and is_win"> export {IncompatibleApplicationItemElement} from './incompatible_applications_page/incompatible_application_item.js'; export {ActionTypes, IncompatibleApplication, IncompatibleApplicationsBrowserProxy, IncompatibleApplicationsBrowserProxyImpl} from './incompatible_applications_page/incompatible_applications_browser_proxy.js';
diff --git a/chrome/browser/resources/settings/page_visibility.ts b/chrome/browser/resources/settings/page_visibility.ts index 0234474..c4829c17 100644 --- a/chrome/browser/resources/settings/page_visibility.ts +++ b/chrome/browser/resources/settings/page_visibility.ts
@@ -15,7 +15,6 @@ defaultBrowser?: boolean; downloads?: boolean; extensions?: boolean; - getMostChrome?: boolean; languages?: boolean; onStartup?: boolean; people?: boolean; @@ -56,7 +55,6 @@ defaultBrowser: false, downloads: false, extensions: false, - getMostChrome: false, languages: false, onStartup: false, people: false, @@ -89,7 +87,6 @@ downloads: true, a11y: true, extensions: false, - getMostChrome: false, languages: true, performance: false, };
diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts index 7b63dfed..13971aa 100644 --- a/chrome/browser/resources/settings/route.ts +++ b/chrome/browser/resources/settings/route.ts
@@ -262,14 +262,6 @@ '/performance', 'performance', loadTimeData.getString('performancePageTitle')); } - - // <if expr="_google_chrome"> - if (visibility.getMostChrome !== false) { - r.GET_MOST_CHROME = r.ADVANCED.createSection( - '/getMostChrome', 'getMostChrome', - loadTimeData.getString('getTheMostOutOfChrome')); - } - // </if> } return r as unknown as SettingsRoutes; }
diff --git a/chrome/browser/resources/settings/router.ts b/chrome/browser/resources/settings/router.ts index c24a1ac..5656181 100644 --- a/chrome/browser/resources/settings/router.ts +++ b/chrome/browser/resources/settings/router.ts
@@ -29,9 +29,6 @@ DOWNLOADS: Route; EDIT_DICTIONARY: Route; FONTS: Route; - // <if expr="_google_chrome"> - GET_MOST_CHROME: Route; - // </if> IMPORT_DATA: Route; INCOMPATIBLE_APPLICATIONS: Route; LANGUAGES: Route;
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service.h b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service.h index fb72bd3..3b7ed40 100644 --- a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service.h +++ b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service.h
@@ -5,88 +5,36 @@ #ifndef CHROME_BROWSER_SIGNIN_BOUND_SESSION_CREDENTIALS_BOUND_SESSION_COOKIE_REFRESH_SERVICE_H_ #define CHROME_BROWSER_SIGNIN_BOUND_SESSION_CREDENTIALS_BOUND_SESSION_COOKIE_REFRESH_SERVICE_H_ -#include <memory> #include "base/functional/callback_forward.h" -#include "chrome/browser/signin/bound_session_credentials/bound_session_cookie_controller.h" #include "components/keyed_service/core/keyed_service.h" -#include "components/signin/public/identity_manager/identity_manager.h" -using signin::IdentityManager; - -class SigninClient; - -// This service is responsible for the following: -// - Tracking bound session -// - It owns `cookie_controller_` that fully manages a bound session cookie -// - Monitors cookie changes and update the renderers +// BoundSessionCookieRefreshService is responsible for maintaining cookies +// associated with bound sessions. This class does the following: +// - Tracks bound sessions // - Provides bound session params to renderers -// This class is still work in progress. -// -// BoundSessionCookieFetcher -// ^ -// | 1 -// | -// BoundSessionCookieRefreshService------> BoundSessionCookieController -// | 1 -// | -// V -// BoundSessionCookieObserver -class BoundSessionCookieRefreshService - : public KeyedService, - public BoundSessionCookieController::Delegate { +// - Monitors cookie changes and update renderers +// - Preemptively refreshes bound session cookies +class BoundSessionCookieRefreshService : public KeyedService { public: - explicit BoundSessionCookieRefreshService(SigninClient* client, - IdentityManager* identity_manager); - ~BoundSessionCookieRefreshService() override; + BoundSessionCookieRefreshService() = default; - void Initialize(); + BoundSessionCookieRefreshService(const BoundSessionCookieRefreshService&) = + delete; + BoundSessionCookieRefreshService& operator=( + const BoundSessionCookieRefreshService&) = delete; + + virtual void Initialize() = 0; // Returns true if session is bound. - bool IsBoundSession() const; + virtual bool IsBoundSession() const = 0; // Called when a network request requires a fresh SIDTS cookie. This function // is intended to be called by network requests throttlers. // The callback will be called once the cookie is fresh or the session is // terminated. Note: The callback might be called synchronously if the // previous conditions apply. - void OnRequestBlockedOnCookie(base::OnceClosure resume_blocked_request); - - private: - class BoundSessionStateTracker; - friend class BoundSessionCookieRefreshServiceTest; - - // Used by tests to provide their own implementation of the - // `BoundSessionCookieController`. - using BoundSessionCookieControllerFactoryForTesting = - base::RepeatingCallback<std::unique_ptr<BoundSessionCookieController>( - const GURL& url, - const std::string& cookie_name, - Delegate* delegate)>; - - void set_controller_factory_for_testing( - const BoundSessionCookieControllerFactoryForTesting& - controller_factory_for_testing) { - controller_factory_for_testing_ = controller_factory_for_testing; - } - - // BoundSessionCookieController::Delegate - void OnCookieExpirationDateChanged() override; - - std::unique_ptr<BoundSessionCookieController> - CreateBoundSessionCookieController(const GURL& url, - const std::string& cookie_name); - void StartManagingBoundSessionCookie(); - void StopManagingBoundSessionCookie(); - void OnBoundSessionUpdated(); - - void UpdateAllRenderers(); - - const raw_ptr<SigninClient> client_; - const raw_ptr<IdentityManager> identity_manager_; - BoundSessionCookieControllerFactoryForTesting controller_factory_for_testing_; - - std::unique_ptr<BoundSessionStateTracker> bound_session_tracker_; - std::unique_ptr<BoundSessionCookieController> cookie_controller_; + virtual void OnRequestBlockedOnCookie( + base::OnceClosure resume_blocked_request) = 0; }; #endif // CHROME_BROWSER_SIGNIN_BOUND_SESSION_CREDENTIALS_BOUND_SESSION_COOKIE_REFRESH_SERVICE_H_
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_factory.cc b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_factory.cc index 42ff2f4..2580dcf 100644 --- a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_factory.cc +++ b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_factory.cc
@@ -3,12 +3,14 @@ // found in the LICENSE file. #include "chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_factory.h" +#include <memory> #include "base/no_destructor.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_keyed_service_factory.h" #include "chrome/browser/signin/account_consistency_mode_manager_factory.h" #include "chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service.h" +#include "chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.h" #include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" @@ -44,7 +46,8 @@ BoundSessionCookieRefreshServiceFactory:: ~BoundSessionCookieRefreshServiceFactory() = default; -KeyedService* BoundSessionCookieRefreshServiceFactory::BuildServiceInstanceFor( +std::unique_ptr<KeyedService> +BoundSessionCookieRefreshServiceFactory::BuildServiceInstanceForBrowserContext( content::BrowserContext* context) const { Profile* profile = Profile::FromBrowserContext(context); // The account consistency method should not change during the lifetime of a @@ -53,10 +56,11 @@ return nullptr; } - auto* bound_session_cookie_refresh_service = - new BoundSessionCookieRefreshService( - ChromeSigninClientFactory::GetForProfile(profile), - IdentityManagerFactory::GetForProfile(profile)); + std::unique_ptr<BoundSessionCookieRefreshService> + bound_session_cookie_refresh_service = + std::make_unique<BoundSessionCookieRefreshServiceImpl>( + ChromeSigninClientFactory::GetForProfile(profile), + IdentityManagerFactory::GetForProfile(profile)); bound_session_cookie_refresh_service->Initialize(); return bound_session_cookie_refresh_service; }
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_factory.h b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_factory.h index f707ddc..d0ecd22 100644 --- a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_factory.h +++ b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_factory.h
@@ -24,8 +24,8 @@ BoundSessionCookieRefreshServiceFactory(); ~BoundSessionCookieRefreshServiceFactory() override; - // BrowserContextKeyedServiceFactory: - KeyedService* BuildServiceInstanceFor( + // ProfileKeyedServiceFactory: + std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext( content::BrowserContext* context) const override; };
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service.cc b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.cc similarity index 77% rename from chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service.cc rename to chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.cc index ac5e367d..04a8f9c 100644 --- a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service.cc +++ b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service.h" +#include "chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.h" #include <memory> #include "base/check_op.h" @@ -13,14 +13,16 @@ #include "components/signin/public/base/consent_level.h" #include "components/signin/public/base/signin_client.h" #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h" +#include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/primary_account_change_event.h" #include "google_apis/gaia/core_account_id.h" #include "google_apis/gaia/gaia_urls.h" using signin::ConsentLevel; +using signin::IdentityManager; using signin::PrimaryAccountChangeEvent; -class BoundSessionCookieRefreshService::BoundSessionStateTracker +class BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker : public IdentityManager::Observer { public: BoundSessionStateTracker(IdentityManager* identity_manager, @@ -56,7 +58,7 @@ identity_manager_observation_{this}; }; -BoundSessionCookieRefreshService::BoundSessionStateTracker:: +BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker:: BoundSessionStateTracker(IdentityManager* identity_manager, base::RepeatingCallback<void()> callback) : identity_manager_(identity_manager), callback_(callback) { @@ -66,10 +68,10 @@ is_bound_session_ = ComputeIsBoundSession(); } -BoundSessionCookieRefreshService::BoundSessionStateTracker:: +BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker:: ~BoundSessionStateTracker() = default; -bool BoundSessionCookieRefreshService::BoundSessionStateTracker:: +bool BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker:: ComputeIsBoundSession() { if (!identity_manager_->HasPrimaryAccount(ConsentLevel::kSignin)) { return false; @@ -91,12 +93,12 @@ return is_primary_account_valid; } -void BoundSessionCookieRefreshService::BoundSessionStateTracker:: +void BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker:: UpdateIsBoundSession() { SetIsBoundSession(ComputeIsBoundSession()); } -void BoundSessionCookieRefreshService::BoundSessionStateTracker:: +void BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker:: SetIsBoundSession(bool new_value) { if (is_bound_session_ == new_value) { return; @@ -106,7 +108,7 @@ callback_.Run(); } -void BoundSessionCookieRefreshService::BoundSessionStateTracker:: +void BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker:: OnPrimaryAccountChanged(const PrimaryAccountChangeEvent& event_details) { if (event_details.GetEventTypeFor(ConsentLevel::kSignin) == PrimaryAccountChangeEvent::Type::kNone) { @@ -116,12 +118,12 @@ UpdateIsBoundSession(); } -void BoundSessionCookieRefreshService::BoundSessionStateTracker:: +void BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker:: OnEndBatchOfRefreshTokenStateChanges() { UpdateIsBoundSession(); } -void BoundSessionCookieRefreshService::BoundSessionStateTracker:: +void BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker:: OnErrorStateOfRefreshTokenUpdatedForAccount( const CoreAccountInfo& account_info, const GoogleServiceAuthError& error) { @@ -132,12 +134,12 @@ UpdateIsBoundSession(); } -void BoundSessionCookieRefreshService::BoundSessionStateTracker:: +void BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker:: OnRefreshTokensLoaded() { UpdateIsBoundSession(); } -void BoundSessionCookieRefreshService::BoundSessionStateTracker:: +void BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker:: OnAccountsInCookieUpdated( const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info, const GoogleServiceAuthError& error) { @@ -154,35 +156,36 @@ // TODO: May be cache last known default user. } -bool BoundSessionCookieRefreshService::BoundSessionStateTracker:: +bool BoundSessionCookieRefreshServiceImpl::BoundSessionStateTracker:: is_bound_session() const { return is_bound_session_; } -BoundSessionCookieRefreshService::BoundSessionCookieRefreshService( +BoundSessionCookieRefreshServiceImpl::BoundSessionCookieRefreshServiceImpl( SigninClient* client, IdentityManager* identity_manager) : client_(client), identity_manager_(identity_manager) {} -BoundSessionCookieRefreshService::~BoundSessionCookieRefreshService() = default; +BoundSessionCookieRefreshServiceImpl::~BoundSessionCookieRefreshServiceImpl() = + default; -void BoundSessionCookieRefreshService::Initialize() { +void BoundSessionCookieRefreshServiceImpl::Initialize() { // `base::Unretained(this)` is safe because `this` owns // `bound_session_tracker_`. bound_session_tracker_ = std::make_unique<BoundSessionStateTracker>( identity_manager_, base::BindRepeating( - &BoundSessionCookieRefreshService::OnBoundSessionUpdated, + &BoundSessionCookieRefreshServiceImpl::OnBoundSessionUpdated, base::Unretained(this))); OnBoundSessionUpdated(); } -bool BoundSessionCookieRefreshService::IsBoundSession() const { +bool BoundSessionCookieRefreshServiceImpl::IsBoundSession() const { DCHECK(bound_session_tracker_); return bound_session_tracker_->is_bound_session(); } -void BoundSessionCookieRefreshService::OnRequestBlockedOnCookie( +void BoundSessionCookieRefreshServiceImpl::OnRequestBlockedOnCookie( base::OnceClosure resume_blocked_request) { if (!IsBoundSession()) { // Session has been terminated. @@ -194,12 +197,12 @@ std::move(resume_blocked_request)); } -void BoundSessionCookieRefreshService::OnCookieExpirationDateChanged() { +void BoundSessionCookieRefreshServiceImpl::OnCookieExpirationDateChanged() { UpdateAllRenderers(); } std::unique_ptr<BoundSessionCookieController> -BoundSessionCookieRefreshService::CreateBoundSessionCookieController( +BoundSessionCookieRefreshServiceImpl::CreateBoundSessionCookieController( const GURL& url, const std::string& cookie_name) { return controller_factory_for_testing_.is_null() @@ -208,7 +211,7 @@ : controller_factory_for_testing_.Run(url, cookie_name, this); } -void BoundSessionCookieRefreshService::StartManagingBoundSessionCookie() { +void BoundSessionCookieRefreshServiceImpl::StartManagingBoundSessionCookie() { DCHECK(!cookie_controller_); constexpr char kSIDTSCookieName[] = "__Secure-1PSIDTS"; @@ -217,11 +220,11 @@ cookie_controller_->Initialize(); } -void BoundSessionCookieRefreshService::StopManagingBoundSessionCookie() { +void BoundSessionCookieRefreshServiceImpl::StopManagingBoundSessionCookie() { cookie_controller_.reset(); } -void BoundSessionCookieRefreshService::OnBoundSessionUpdated() { +void BoundSessionCookieRefreshServiceImpl::OnBoundSessionUpdated() { UpdateAllRenderers(); if (!IsBoundSession()) { StopManagingBoundSessionCookie(); @@ -230,6 +233,6 @@ } } -void BoundSessionCookieRefreshService::UpdateAllRenderers() { +void BoundSessionCookieRefreshServiceImpl::UpdateAllRenderers() { NOTIMPLEMENTED(); }
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.h b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.h new file mode 100644 index 0000000..3e9c665 --- /dev/null +++ b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.h
@@ -0,0 +1,78 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SIGNIN_BOUND_SESSION_CREDENTIALS_BOUND_SESSION_COOKIE_REFRESH_SERVICE_IMPL_H_ +#define CHROME_BROWSER_SIGNIN_BOUND_SESSION_CREDENTIALS_BOUND_SESSION_COOKIE_REFRESH_SERVICE_IMPL_H_ + +#include "chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service.h" + +#include <memory> +#include "base/functional/callback_forward.h" +#include "chrome/browser/signin/bound_session_credentials/bound_session_cookie_controller.h" +#include "components/keyed_service/core/keyed_service.h" +#include "components/signin/public/identity_manager/identity_manager.h" + +class SigninClient; + +class BoundSessionCookieRefreshServiceImpl + : public BoundSessionCookieRefreshService, + public BoundSessionCookieController::Delegate { + public: + explicit BoundSessionCookieRefreshServiceImpl( + SigninClient* client, + signin::IdentityManager* identity_manager); + ~BoundSessionCookieRefreshServiceImpl() override; + + void Initialize() override; + + // Returns true if session is bound. + bool IsBoundSession() const override; + + // Called when a network request requires a fresh SIDTS cookie. This function + // is intended to be called by network requests throttlers. + // The callback will be called once the cookie is fresh or the session is + // terminated. Note: The callback might be called synchronously if the + // previous conditions apply. + void OnRequestBlockedOnCookie( + base::OnceClosure resume_blocked_request) override; + + private: + class BoundSessionStateTracker; + friend class BoundSessionCookieRefreshServiceImplTest; + + // Used by tests to provide their own implementation of the + // `BoundSessionCookieController`. + using BoundSessionCookieControllerFactoryForTesting = + base::RepeatingCallback<std::unique_ptr<BoundSessionCookieController>( + const GURL& url, + const std::string& cookie_name, + Delegate* delegate)>; + + void set_controller_factory_for_testing( + const BoundSessionCookieControllerFactoryForTesting& + controller_factory_for_testing) { + controller_factory_for_testing_ = controller_factory_for_testing; + } + + // BoundSessionCookieController::Delegate + void OnCookieExpirationDateChanged() override; + + std::unique_ptr<BoundSessionCookieController> + CreateBoundSessionCookieController(const GURL& url, + const std::string& cookie_name); + void StartManagingBoundSessionCookie(); + void StopManagingBoundSessionCookie(); + void OnBoundSessionUpdated(); + + void UpdateAllRenderers(); + + const raw_ptr<SigninClient> client_; + const raw_ptr<signin::IdentityManager> identity_manager_; + BoundSessionCookieControllerFactoryForTesting controller_factory_for_testing_; + + std::unique_ptr<BoundSessionStateTracker> bound_session_tracker_; + std::unique_ptr<BoundSessionCookieController> cookie_controller_; +}; + +#endif // CHROME_BROWSER_SIGNIN_BOUND_SESSION_CREDENTIALS_BOUND_SESSION_COOKIE_REFRESH_SERVICE_IMPL_H_
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_unittest.cc b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl_unittest.cc similarity index 81% rename from chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_unittest.cc rename to chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl_unittest.cc index d4e44fb..5e5df385 100644 --- a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_unittest.cc +++ b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service.h" +#include "chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.h" #include <memory> #include <utility> @@ -68,14 +68,14 @@ }; } // namespace -class BoundSessionCookieRefreshServiceTest : public testing::Test { +class BoundSessionCookieRefreshServiceImplTest : public testing::Test { public: - BoundSessionCookieRefreshServiceTest() + BoundSessionCookieRefreshServiceImplTest() : identity_test_env_(&test_url_loader_factory_, nullptr, signin::AccountConsistencyMethod::kDice) {} - ~BoundSessionCookieRefreshServiceTest() override = default; + ~BoundSessionCookieRefreshServiceImplTest() override = default; std::unique_ptr<BoundSessionCookieController> GetBoundSessionCookieController( const GURL& url, @@ -85,7 +85,7 @@ std::make_unique<FakeBoundSessionCookieController>(url, cookie_name, delegate); controller->set_on_destroy_callback(base::BindOnce( - &BoundSessionCookieRefreshServiceTest::OnCookieControllerDestroy, + &BoundSessionCookieRefreshServiceImplTest::OnCookieControllerDestroy, base::Unretained(this))); cookie_controller_ = controller.get(); return controller; @@ -93,13 +93,13 @@ void OnCookieControllerDestroy() { cookie_controller_ = nullptr; } - BoundSessionCookieRefreshService* CreateCookieRefreshService() { + BoundSessionCookieRefreshServiceImpl* CreateCookieRefreshServiceImpl() { if (!cookie_refresh_service_) { cookie_refresh_service_ = - std::make_unique<BoundSessionCookieRefreshService>( + std::make_unique<BoundSessionCookieRefreshServiceImpl>( /*client=*/nullptr, identity_manager()); cookie_refresh_service_->set_controller_factory_for_testing( - base::BindRepeating(&BoundSessionCookieRefreshServiceTest:: + base::BindRepeating(&BoundSessionCookieRefreshServiceImplTest:: GetBoundSessionCookieController, base::Unretained(this))); cookie_refresh_service_->Initialize(); @@ -126,14 +126,15 @@ sync_preferences::TestingPrefServiceSyncable prefs_; network::TestURLLoaderFactory test_url_loader_factory_; signin::IdentityTestEnvironment identity_test_env_; - std::unique_ptr<BoundSessionCookieRefreshService> cookie_refresh_service_; + std::unique_ptr<BoundSessionCookieRefreshServiceImpl> cookie_refresh_service_; raw_ptr<FakeBoundSessionCookieController> cookie_controller_; }; -TEST_F(BoundSessionCookieRefreshServiceTest, VerifyControllerParams) { +TEST_F(BoundSessionCookieRefreshServiceImplTest, VerifyControllerParams) { identity_test_env()->MakePrimaryAccountAvailable(kEmail, ConsentLevel::kSignin); - BoundSessionCookieRefreshService* service = CreateCookieRefreshService(); + BoundSessionCookieRefreshServiceImpl* service = + CreateCookieRefreshServiceImpl(); EXPECT_TRUE(service->IsBoundSession()); FakeBoundSessionCookieController* controller = cookie_controller(); EXPECT_TRUE(controller); @@ -142,11 +143,12 @@ EXPECT_EQ(controller->cookie_expiration_time(), base::Time()); } -TEST_F(BoundSessionCookieRefreshServiceTest, +TEST_F(BoundSessionCookieRefreshServiceImplTest, RefreshBoundSessionCookieBoundSession) { identity_test_env()->MakePrimaryAccountAvailable(kEmail, ConsentLevel::kSignin); - BoundSessionCookieRefreshService* service = CreateCookieRefreshService(); + BoundSessionCookieRefreshServiceImpl* service = + CreateCookieRefreshServiceImpl(); EXPECT_TRUE(service->IsBoundSession()); base::test::TestFuture<void> future; service->OnRequestBlockedOnCookie(future.GetCallback()); @@ -157,9 +159,10 @@ EXPECT_TRUE(future.IsReady()); } -TEST_F(BoundSessionCookieRefreshServiceTest, +TEST_F(BoundSessionCookieRefreshServiceImplTest, RefreshBoundSessionCookieUnboundSession) { - BoundSessionCookieRefreshService* service = CreateCookieRefreshService(); + BoundSessionCookieRefreshServiceImpl* service = + CreateCookieRefreshServiceImpl(); EXPECT_FALSE(service->IsBoundSession()); // Unbound session, the callback should be called immediately. @@ -168,41 +171,46 @@ EXPECT_TRUE(future.IsReady()); } -TEST_F(BoundSessionCookieRefreshServiceTest, IsBoundSession_NoPrimaryAccount) { +TEST_F(BoundSessionCookieRefreshServiceImplTest, + IsBoundSession_NoPrimaryAccount) { EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); - BoundSessionCookieRefreshService* service = CreateCookieRefreshService(); + BoundSessionCookieRefreshServiceImpl* service = + CreateCookieRefreshServiceImpl(); EXPECT_FALSE(service->IsBoundSession()); } -TEST_F(BoundSessionCookieRefreshServiceTest, +TEST_F(BoundSessionCookieRefreshServiceImplTest, IsBoundSessionSigninPrimaryAccount) { identity_test_env()->MakePrimaryAccountAvailable(kEmail, ConsentLevel::kSignin); EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); - BoundSessionCookieRefreshService* service = CreateCookieRefreshService(); + BoundSessionCookieRefreshServiceImpl* service = + CreateCookieRefreshServiceImpl(); EXPECT_TRUE(service->IsBoundSession()); identity_test_env()->WaitForRefreshTokensLoaded(); EXPECT_TRUE(service->IsBoundSession()); EXPECT_TRUE(cookie_controller()); } -TEST_F(BoundSessionCookieRefreshServiceTest, +TEST_F(BoundSessionCookieRefreshServiceImplTest, IsBoundSessionAccountsNotLoadedYet) { identity_test_env()->MakePrimaryAccountAvailable(kEmail, ConsentLevel::kSignin); EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); identity_test_env()->ResetToAccountsNotYetLoadedFromDiskState(); - BoundSessionCookieRefreshService* service = CreateCookieRefreshService(); + BoundSessionCookieRefreshServiceImpl* service = + CreateCookieRefreshServiceImpl(); EXPECT_TRUE(service->IsBoundSession()); EXPECT_TRUE(cookie_controller()); } -TEST_F(BoundSessionCookieRefreshServiceTest, +TEST_F(BoundSessionCookieRefreshServiceImplTest, IsBoundSessionRefreshTokenInPersistentErrorState) { identity_test_env()->MakePrimaryAccountAvailable(kEmail, ConsentLevel::kSignin); EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); - BoundSessionCookieRefreshService* service = CreateCookieRefreshService(); + BoundSessionCookieRefreshServiceImpl* service = + CreateCookieRefreshServiceImpl(); EXPECT_TRUE(service->IsBoundSession()); EXPECT_TRUE(cookie_controller()); @@ -216,7 +224,7 @@ identity_test_env()->ResetToAccountsNotYetLoadedFromDiskState(); ResetCookieRefreshService(); - service = CreateCookieRefreshService(); + service = CreateCookieRefreshServiceImpl(); EXPECT_TRUE(service->IsBoundSession()); EXPECT_TRUE(cookie_controller()); @@ -226,9 +234,10 @@ EXPECT_FALSE(cookie_controller()); } -TEST_F(BoundSessionCookieRefreshServiceTest, +TEST_F(BoundSessionCookieRefreshServiceImplTest, IsBoundSessionOnPrimaryAccountChanged) { - BoundSessionCookieRefreshService* service = CreateCookieRefreshService(); + BoundSessionCookieRefreshServiceImpl* service = + CreateCookieRefreshServiceImpl(); identity_test_env()->WaitForRefreshTokensLoaded(); EXPECT_FALSE(service->IsBoundSession()); EXPECT_FALSE(cookie_controller()); @@ -248,11 +257,13 @@ EXPECT_FALSE(cookie_controller()); } -TEST_F(BoundSessionCookieRefreshServiceTest, IsBoundSessionEmptyGaiaAccounts) { +TEST_F(BoundSessionCookieRefreshServiceImplTest, + IsBoundSessionEmptyGaiaAccounts) { identity_test_env()->MakePrimaryAccountAvailable(kEmail, ConsentLevel::kSignin); EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); - BoundSessionCookieRefreshService* service = CreateCookieRefreshService(); + BoundSessionCookieRefreshServiceImpl* service = + CreateCookieRefreshServiceImpl(); EXPECT_TRUE(service->IsBoundSession()); EXPECT_TRUE(cookie_controller());
diff --git a/chrome/browser/supervised_user/supervised_user_service.cc b/chrome/browser/supervised_user/supervised_user_service.cc index 29a6e413..e29d239e 100644 --- a/chrome/browser/supervised_user/supervised_user_service.cc +++ b/chrome/browser/supervised_user/supervised_user_service.cc
@@ -421,10 +421,6 @@ RefreshApprovedExtensionsFromPrefs(); #endif // BUILDFLAG(ENABLE_EXTENSIONS) -#if BUILDFLAG(IS_CHROMEOS) - // TODO(b/270535171): Remove platform-specific #ifdef. - BrowserList::AddObserver(this); -#endif } else { remote_web_approvals_manager_.ClearApprovalRequestsCreators(); @@ -443,11 +439,6 @@ url_filter_.Clear(); for (SupervisedUserServiceObserver& observer : observer_list_) observer.OnURLFilterChanged(); - -#if BUILDFLAG(IS_CHROMEOS) - // TODO(b/270535171): Remove platform-specific #ifdef. - BrowserList::RemoveObserver(this); -#endif } } @@ -920,18 +911,6 @@ } #endif // BUILDFLAG(ENABLE_EXTENSIONS) -#if BUILDFLAG(IS_CHROMEOS) -void SupervisedUserService::OnBrowserSetLastActive(Browser* browser) { - bool profile_became_active = profile_->IsSameOrParent(browser->profile()); - if (!is_profile_active_ && profile_became_active) - base::RecordAction(UserMetricsAction("ManagedUsers_OpenProfile")); - else if (is_profile_active_ && !profile_became_active) - base::RecordAction(UserMetricsAction("ManagedUsers_SwitchProfile")); - - is_profile_active_ = profile_became_active; -} -#endif // BUILDFLAG(IS_CHROMEOS) - void SupervisedUserService::OnSiteListUpdated() { for (SupervisedUserServiceObserver& observer : observer_list_) observer.OnURLFilterChanged();
diff --git a/chrome/browser/supervised_user/supervised_user_service.h b/chrome/browser/supervised_user/supervised_user_service.h index e4ed430..46db4cc 100644 --- a/chrome/browser/supervised_user/supervised_user_service.h +++ b/chrome/browser/supervised_user/supervised_user_service.h
@@ -33,14 +33,6 @@ #include "extensions/browser/management_policy.h" #endif -#if BUILDFLAG(IS_CHROMEOS) -#include "chrome/browser/ui/browser_list_observer.h" -#endif // BUILDFLAG(IS_CHROMEOS) - -#if BUILDFLAG(IS_CHROMEOS) -class Browser; -#endif // BUILDFLAG(IS_CHROMEOS) - class PrefService; class Profile; class SupervisedUserServiceObserver; @@ -85,9 +77,6 @@ public extensions::ExtensionRegistryObserver, public extensions::ManagementPolicy::Provider, #endif -#if BUILDFLAG(IS_CHROMEOS) - public BrowserListObserver, -#endif public supervised_user::SupervisedUserURLFilter::Observer { public: class Delegate { @@ -195,11 +184,6 @@ // ProfileKeyedService override: void Shutdown() override; -#if BUILDFLAG(IS_CHROMEOS) - // BrowserListObserver implementation: - void OnBrowserSetLastActive(Browser* browser) override; -#endif // BUILDFLAG(IS_CHROMEOS) - // SupervisedUserURLFilter::Observer implementation: void OnSiteListUpdated() override; @@ -396,8 +380,6 @@ PrefChangeRegistrar pref_change_registrar_; - bool is_profile_active_ = false; - // True only when |Init()| method has been called. bool did_init_ = false;
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 6155b39..cf1f33bd 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -5756,6 +5756,9 @@ <message name="IDS_QUICK_DELETE_DIALOG_DESCRIPTION" desc="Description of the dialog when asking users to confirm deleting the last 15 minutes of browsing data."> Following data from the last 15 minutes will be deleted </message> + <message name="IDS_QUICK_DELETE_DIALOG_SEARCH_HISTORY_DISAMBIGUATION_TEXT" desc="Text for signed in users only in the Quick Delete dialog, that is shown when the user clicks on 'Delete last 15 minutes' option in the three dots menu, informing signed in users that search history and other forms of Activity saved in their Google account will not be deleted."> + <ph name="BEGIN_LINK1"><link1></ph>Search history<ph name="END_LINK1"></link1></ph> and <ph name="BEGIN_LINK2"><link2></ph>other forms of activity<ph name="END_LINK2"></link2></ph> may be saved in your Google Account + </message> <message name="IDS_QUICK_DELETE_SNACKBAR_MESSAGE" desc="Text inside the snackbar which is shown once the user confirms deletion via the 'Delete last 15 minutes' option present inside the three dots menu."> Deleted history, cookies, and other data </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_QUICK_DELETE_DIALOG_SEARCH_HISTORY_DISAMBIGUATION_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_QUICK_DELETE_DIALOG_SEARCH_HISTORY_DISAMBIGUATION_TEXT.png.sha1 new file mode 100644 index 0000000..4199385 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_QUICK_DELETE_DIALOG_SEARCH_HISTORY_DISAMBIGUATION_TEXT.png.sha1
@@ -0,0 +1 @@ +674ff18ecd5555cecfde587bee982fd3e31e9f03 \ No newline at end of file
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc index 3e3af9d..c4d15c8 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
@@ -230,10 +230,6 @@ progress); } -void HoldingSpaceKeyedService::AddScan(const base::FilePath& file_path) { - AddItemOfType(HoldingSpaceItem::Type::kScan, file_path); -} - void HoldingSpaceKeyedService::SetSuggestions( const std::vector<std::pair<HoldingSpaceItem::Type, base::FilePath>>& suggestions) {
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h index 9cea52c..b345f65 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h
@@ -98,10 +98,6 @@ const base::FilePath& item_path, const HoldingSpaceProgress& progress); - // TODO(http://b/274477308): Remove one-off API. - // Adds a scanned item backed by the provided absolute file path. - void AddScan(const base::FilePath& file_path); - // Replaces the existing suggestions with `suggestions`. The order among // `suggestions` is respected, which means that if a suggestion A is in front // of a suggestion B in the given array, after calling this function, the
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc index f16d119..2e17fc4 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
@@ -2627,8 +2627,6 @@ /*from_incognito_profile=*/false); break; case HoldingSpaceItem::Type::kScan: - holding_space_service->AddScan(file_path); - break; case HoldingSpaceItem::Type::kScreenRecording: case HoldingSpaceItem::Type::kScreenRecordingGif: case HoldingSpaceItem::Type::kScreenshot:
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index 3981f97..0665b3f 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -777,9 +777,10 @@ const FormFieldData& field, base::WeakPtr<AutofillManager> autofill_manager) { #if BUILDFLAG(IS_ANDROID) - const GURL& url = web_contents()->GetLastCommittedURL(); - return GetFastCheckoutClient()->TryToStart(url, form, field, - autofill_manager); + return base::FeatureList::IsEnabled(::features::kFastCheckout) && + GetFastCheckoutClient()->TryToStart( + web_contents()->GetLastCommittedURL(), form, field, + autofill_manager); #else return false; #endif @@ -807,7 +808,8 @@ bool ChromeAutofillClient::IsShowingFastCheckoutUI() { #if BUILDFLAG(IS_ANDROID) - return GetFastCheckoutClient()->IsShowing(); + return base::FeatureList::IsEnabled(::features::kFastCheckout) && + GetFastCheckoutClient()->IsShowing(); #else return false; #endif
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client_unittest.cc b/chrome/browser/ui/autofill/chrome_autofill_client_unittest.cc index d6ad82e..b1b07bd1 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client_unittest.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client_unittest.cc
@@ -26,8 +26,6 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -using base::test::ScopedFeatureList; - namespace autofill { namespace { @@ -72,13 +70,6 @@ return test_autofill_manager_injector_[web_contents()]; } -#if BUILDFLAG(IS_ANDROID) - MockFastCheckoutClient* fast_checkout_client() { - return static_cast<MockFastCheckoutClient*>( - client()->GetFastCheckoutClient()); - } -#endif - private: void PreparePersonalDataManager() { personal_data_manager_ = @@ -162,16 +153,27 @@ } #if BUILDFLAG(IS_ANDROID) -TEST_F(ChromeAutofillClientTest, IsFastCheckoutSupportedWithDisabledFeature) { +class ChromeAutofillClientTestForFastCheckout + : public ChromeAutofillClientTest { + protected: + MockFastCheckoutClient* fast_checkout_client() { + return static_cast<MockFastCheckoutClient*>( + client()->GetFastCheckoutClient()); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_{::features::kFastCheckout}; +}; + +TEST_F(ChromeAutofillClientTestForFastCheckout, + IsFastCheckoutSupportedWithDisabledFeature) { FormData form; FormFieldData field; - ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(::features::kFastCheckout); EXPECT_FALSE( client()->IsFastCheckoutSupported(form, field, *autofill_manager())); } -TEST_F(ChromeAutofillClientTest, +TEST_F(ChromeAutofillClientTestForFastCheckout, HideFastCheckout_IsShowing_CallsStopOnFastCheckoutClient) { ON_CALL(*fast_checkout_client(), IsShowing) .WillByDefault(testing::Return(true)); @@ -179,7 +181,7 @@ client()->HideFastCheckout(/*allow_further_runs=*/true); } -TEST_F(ChromeAutofillClientTest, +TEST_F(ChromeAutofillClientTestForFastCheckout, HideFastCheckout_NotShowing_DoesNotCallStopOnFastCheckoutClient) { ON_CALL(*fast_checkout_client(), IsShowing) .WillByDefault(testing::Return(false)); @@ -187,13 +189,13 @@ client()->HideFastCheckout(/*allow_further_runs=*/true); } -TEST_F(ChromeAutofillClientTest, IsShowingFastCheckoutUI) { +TEST_F(ChromeAutofillClientTestForFastCheckout, IsShowingFastCheckoutUI) { EXPECT_CALL(*fast_checkout_client(), IsShowing) .WillOnce(testing::Return(true)); EXPECT_TRUE(client()->IsShowingFastCheckoutUI()); } -TEST_F(ChromeAutofillClientTest, TryToShowFastCheckout) { +TEST_F(ChromeAutofillClientTestForFastCheckout, TryToShowFastCheckout) { EXPECT_CALL(*fast_checkout_client(), TryToStart) .WillOnce(testing::Return(true)); EXPECT_TRUE(client()->TryToShowFastCheckout(
diff --git a/chrome/browser/ui/frame/window_frame_util.cc b/chrome/browser/ui/frame/window_frame_util.cc index db93bd1..2aba331b 100644 --- a/chrome/browser/ui/frame/window_frame_util.cc +++ b/chrome/browser/ui/frame/window_frame_util.cc
@@ -34,8 +34,7 @@ bool WindowFrameUtil::IsWin10TabSearchCaptionButtonEnabled( const Browser* browser) { #if BUILDFLAG(IS_WIN) - return browser->is_type_normal() && - base::FeatureList::IsEnabled(features::kWin10TabSearchCaptionButton); + return browser->is_type_normal(); #else return false; #endif // BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/ui/startup/first_run_service.cc b/chrome/browser/ui/startup/first_run_service.cc index 1b846a3..c9eb3223 100644 --- a/chrome/browser/ui/startup/first_run_service.cc +++ b/chrome/browser/ui/startup/first_run_service.cc
@@ -153,18 +153,22 @@ return PolicyEffect::kNone; } +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. enum class FinishedReason { - kFinishedFlow, - kProfileAlreadySetUp, - kSkippedByPolicies, #if BUILDFLAG(ENABLE_DICE_SUPPORT) - kExperimentCounterfactual, + kExperimentCounterfactual = 0, #endif + kFinishedFlow = 1, + kProfileAlreadySetUp = 2, + kSkippedByPolicies = 3, + kMaxValue = kSkippedByPolicies, }; void SetFirstRunFinished(FinishedReason reason) { PrefService* local_state = g_browser_process->local_state(); local_state->SetBoolean(prefs::kFirstRunFinished, true); + base::UmaHistogramEnumeration("ProfilePicker.FirstRun.FinishReason", reason); #if BUILDFLAG(IS_CHROMEOS_LACROS) absl::optional<ProfileMetrics::ProfileSignedInFlowOutcome> outcome; @@ -365,6 +369,8 @@ base::UmaHistogramEnumeration( "Profile.LacrosPrimaryProfileFirstRunEntryPoint", entry_point); #endif + base::UmaHistogramEnumeration("ProfilePicker.FirstRun.EntryPoint", + entry_point); // Note: we call `Show()` even if the FRE might be already open and rely on // the ProfilePicker to decide what it wants to do with `callback`. @@ -439,12 +445,14 @@ } if (!base::FeatureList::IsEnabled(kForYouFre)) { + base::UmaHistogramBoolean("ProfilePicker.FirstRun.ServiceCreated", false); SetFirstRunFinished(FinishedReason::kExperimentCounterfactual); return nullptr; } #endif auto* instance = new FirstRunService(profile); + base::UmaHistogramBoolean("ProfilePicker.FirstRun.ServiceCreated", true); #if BUILDFLAG(IS_CHROMEOS_LACROS) // Check if we should turn Sync on from the background and skip the FRE.
diff --git a/chrome/browser/ui/startup/first_run_service_browsertest.cc b/chrome/browser/ui/startup/first_run_service_browsertest.cc index 836cc02..130aab4 100644 --- a/chrome/browser/ui/startup/first_run_service_browsertest.cc +++ b/chrome/browser/ui/startup/first_run_service_browsertest.cc
@@ -220,6 +220,16 @@ profiles::testing::WaitForPickerWidgetCreated(); EXPECT_FALSE(GetFirstRunFinishedPrefValue()); + histogram_tester.ExpectUniqueSample("ProfilePicker.FirstRun.ServiceCreated", + true, 1); +#if BUILDFLAG(IS_CHROMEOS_LACROS) + histogram_tester.ExpectUniqueSample( + "Profile.LacrosPrimaryProfileFirstRunEntryPoint", + FirstRunService::EntryPoint::kOther, 1); +#endif + histogram_tester.ExpectUniqueSample("ProfilePicker.FirstRun.EntryPoint", + FirstRunService::EntryPoint::kOther, 1); + // We don't expect synthetic trials to be registered here, since no group // is configured with the feature. For the positive test case, see // `FirstRunServiceCohortBrowserTest.GroupRegisteredAfterFre`. @@ -238,6 +248,7 @@ histogram_tester.ExpectUniqueSample( "ProfilePicker.FirstRun.ExitStatus", ProfilePicker::FirstRunExitStatus::kQuitEarly, 1); + histogram_tester.ExpectTotalCount("ProfilePicker.FirstRun.FinishReason", 0); #elif BUILDFLAG(ENABLE_DICE_SUPPORT) histogram_tester.ExpectUniqueSample( "Signin.SignIn.Offered", @@ -246,6 +257,8 @@ histogram_tester.ExpectUniqueSample( "ProfilePicker.FirstRun.ExitStatus", ProfilePicker::FirstRunExitStatus::kQuitAtEnd, 1); + histogram_tester.ExpectUniqueSample("ProfilePicker.FirstRun.FinishReason", + /*kFinishedFlow*/ 1, 1); #endif }
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc index 5b82f79..1bd7126 100644 --- a/chrome/browser/ui/ui_features.cc +++ b/chrome/browser/ui/ui_features.cc
@@ -342,16 +342,6 @@ } #endif -#if BUILDFLAG(IS_WIN) - -// Moves the Tab Search button into the browser frame's caption button area on -// Windows 10 (crbug.com/1223847). -BASE_FEATURE(kWin10TabSearchCaptionButton, - "Win10TabSearchCaptionButton", - base::FEATURE_ENABLED_BY_DEFAULT); - -#endif - // Reduce resource usage when view is hidden by not rendering loading animation. BASE_FEATURE(kStopLoadingAnimationForHiddenWindow, "StopLoadingAnimationForHiddenWindow",
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h index c0b02fa..57accbc 100644 --- a/chrome/browser/ui/ui_features.h +++ b/chrome/browser/ui/ui_features.h
@@ -209,10 +209,6 @@ int GetLocationPermissionsExperimentLabelPromptLimit(); #endif -#if BUILDFLAG(IS_WIN) -BASE_DECLARE_FEATURE(kWin10TabSearchCaptionButton); -#endif - BASE_DECLARE_FEATURE(kStopLoadingAnimationForHiddenWindow); } // namespace features
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc index fe0d9d6..e31f1ae7 100644 --- a/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc
@@ -31,11 +31,6 @@ scoped_feature_list_.InitAndDisableFeature( features::kChromeOSTabSearchCaptionButton); #endif - -#if BUILDFLAG(IS_WIN) - scoped_feature_list_.InitAndDisableFeature( - features::kWin10TabSearchCaptionButton); -#endif InProcessBrowserTest::SetUp(); } @@ -98,8 +93,10 @@ move_forward_over_tab(tab_2); EXPECT_TRUE(new_tab_button()->HasFocus()); +#if !BUILDFLAG(IS_WIN) press_right(); EXPECT_TRUE(tab_search_button()->HasFocus()); +#endif // !BUILDFLAG(IS_WIN) // Focus should cycle back around to tab_0. press_right(); @@ -134,8 +131,10 @@ EXPECT_TRUE(tab_0->HasFocus()); // Pressing left should immediately cycle back around to the last button. +#if !BUILDFLAG(IS_WIN) press_left(); EXPECT_TRUE(tab_search_button()->HasFocus()); +#endif // !BUILDFLAG(IS_WIN) press_left(); EXPECT_TRUE(new_tab_button()->HasFocus()); @@ -163,15 +162,18 @@ // The first tab should be active. EXPECT_TRUE(tab_0->HasFocus()); +#if !BUILDFLAG(IS_WIN) EXPECT_TRUE(tab_strip_region_view()->AcceleratorPressed( tab_strip_region_view()->end_key())); EXPECT_TRUE(tab_search_button()->HasFocus()); +#endif // !BUILDFLAG(IS_WIN) EXPECT_TRUE(tab_strip_region_view()->AcceleratorPressed( tab_strip_region_view()->home_key())); EXPECT_TRUE(tab_0->HasFocus()); } +#if !BUILDFLAG(IS_WIN) IN_PROC_BROWSER_TEST_F(TabStripRegionViewBrowserTest, TestSearchButtonIsEndAligned) { const int kRightMargin = @@ -179,3 +181,4 @@ EXPECT_EQ(tab_strip_region_view()->GetLocalBounds().right() - kRightMargin, tab_search_button()->bounds().right()); } +#endif // !BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc b/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc index 17de737..aa7c3c7 100644 --- a/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc +++ b/chrome/browser/ui/views/tabs/tab_search_button_browsertest.cc
@@ -34,15 +34,6 @@ class TabSearchButtonBrowserTest : public InProcessBrowserTest { public: -#if BUILDFLAG(IS_WIN) - // InProcessBrowserTest: - void SetUp() override { - scoped_feature_list_.InitAndDisableFeature( - features::kWin10TabSearchCaptionButton); - InProcessBrowserTest::SetUp(); - } -#endif // BUILDFLAG(IS_WIN); - BrowserView* browser_view() { return BrowserView::GetBrowserViewForBrowser(browser()); } @@ -67,11 +58,6 @@ run_loop.Run(); ASSERT_EQ(nullptr, bubble_manager()->GetBubbleWidget()); } - -#if BUILDFLAG(IS_WIN) - private: - base::test::ScopedFeatureList scoped_feature_list_; -#endif // BUILDFLAG(IS_WIN); }; IN_PROC_BROWSER_TEST_F(TabSearchButtonBrowserTest, ButtonClickCreatesBubble) { @@ -88,13 +74,6 @@ class TabSearchButtonBrowserUITest : public DialogBrowserTest { public: // DialogBrowserTest: -#if BUILDFLAG(IS_WIN) - void SetUp() override { - scoped_feature_list_.InitAndDisableFeature( - features::kWin10TabSearchCaptionButton); - DialogBrowserTest::SetUp(); - } -#endif // BUILDFLAG(IS_WIN); void ShowUi(const std::string& name) override { AppendTab(chrome::kChromeUISettingsURL); AppendTab(chrome::kChromeUIHistoryURL); @@ -108,11 +87,6 @@ void AppendTab(std::string url) { chrome::AddTabAt(browser(), GURL(url), -1, true); } - -#if BUILDFLAG(IS_WIN) - private: - base::test::ScopedFeatureList scoped_feature_list_; -#endif // BUILDFLAG(IS_WIN); }; // Invokes a tab search bubble.
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc index 0095ef48..5034e682 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc +++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
@@ -491,12 +491,13 @@ class UninstallCompleteWaiter final : public BrowserListObserver, public WebAppInstallManagerObserver { public: - explicit UninstallCompleteWaiter(Profile* profile, const AppId& app_id) + explicit UninstallCompleteWaiter( + Profile* profile, + const AppId& app_id, + apps::Readiness readiness = apps::Readiness::kUninstalledByUser) : profile_(profile), app_id_(app_id), - app_unregistration_waiter_(profile, - app_id, - apps::Readiness::kUninstalledByUser) { + app_unregistration_waiter_(profile, app_id, readiness) { BrowserList::AddObserver(this); WebAppProvider* provider = WebAppProvider::GetForTest(profile); observation_.Observe(&provider->install_manager()); @@ -519,7 +520,9 @@ void OnBrowserRemoved(Browser* browser) override { MaybeFinishWaiting(); } // WebAppInstallManagerObserver - void OnWebAppUninstalled(const AppId& app_id) override { + void OnWebAppUninstalled( + const AppId& app_id, + webapps::WebappUninstallSource uninstall_source) override { if (app_id != app_id_) { return; } @@ -2247,7 +2250,8 @@ DCHECK(policy_app); base::RunLoop run_loop; - UninstallCompleteWaiter uninstall_waiter(profile(), policy_app->id); + UninstallCompleteWaiter uninstall_waiter( + profile(), policy_app->id, apps::Readiness::kUninstalledByMigration); WebAppInstallManagerObserverAdapter observer(profile()); observer.SetWebAppUninstalledDelegate( base::BindLambdaForTesting([&](const AppId& app_id) { @@ -3685,7 +3689,7 @@ const AppId& id) { base::RunLoop run_loop; AppReadinessWaiter app_registration_waiter( - profile, id, apps::Readiness::kUninstalledByUser); + profile, id, apps::Readiness::kUninstalledByMigration); WebAppInstallManagerObserverAdapter observer(profile); observer.SetWebAppUninstalledDelegate( base::BindLambdaForTesting([&](const AppId& app_id) {
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.cc b/chrome/browser/ui/web_applications/web_app_browser_controller.cc index 90433e7e1..5e6671b2 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.cc
@@ -315,7 +315,8 @@ #endif // BUILDFLAG(IS_CHROMEOS_LACROS) void WebAppBrowserController::OnWebAppUninstalled( - const AppId& uninstalled_app_id) { + const AppId& uninstalled_app_id, + webapps::WebappUninstallSource uninstall_source) { if (uninstalled_app_id == app_id()) chrome::CloseWindow(browser()); }
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.h b/chrome/browser/ui/web_applications/web_app_browser_controller.h index fd5724d..bf7b0caaa 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.h +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.h
@@ -122,7 +122,9 @@ #endif // WebAppInstallManagerObserver: - void OnWebAppUninstalled(const AppId& app_id) override; + void OnWebAppUninstalled( + const AppId& app_id, + webapps::WebappUninstallSource uninstall_source) override; void OnWebAppManifestUpdated(const AppId& app_id, base::StringPiece old_name) override; void OnWebAppInstallManagerDestroyed() override;
diff --git a/chrome/browser/ui/webui/app_settings/web_app_settings_ui.cc b/chrome/browser/ui/webui/app_settings/web_app_settings_ui.cc index f7a97a3..b795d7d 100644 --- a/chrome/browser/ui/webui/app_settings/web_app_settings_ui.cc +++ b/chrome/browser/ui/webui/app_settings/web_app_settings_ui.cc
@@ -109,7 +109,9 @@ app_management_page_handler_factory_->Bind(std::move(receiver)); } -void WebAppSettingsUI::OnWebAppUninstalled(const web_app::AppId& app_id) { +void WebAppSettingsUI::OnWebAppUninstalled( + const web_app::AppId& app_id, + webapps::WebappUninstallSource uninstall_source) { auto* web_contents = web_ui()->GetWebContents(); const web_app::AppId current_app_id = web_app::GetAppIdFromAppSettingsUrl(web_contents->GetURL());
diff --git a/chrome/browser/ui/webui/app_settings/web_app_settings_ui.h b/chrome/browser/ui/webui/app_settings/web_app_settings_ui.h index 67af2c75..a4dc21db 100644 --- a/chrome/browser/ui/webui/app_settings/web_app_settings_ui.h +++ b/chrome/browser/ui/webui/app_settings/web_app_settings_ui.h
@@ -36,7 +36,9 @@ receiver); // WebAppInstallManagerObserver: - void OnWebAppUninstalled(const web_app::AppId& app_id) override; + void OnWebAppUninstalled( + const web_app::AppId& app_id, + webapps::WebappUninstallSource uninstall_source) override; void OnWebAppInstallManagerDestroyed() override; private:
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc index 3c9edd2..52a0753 100644 --- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc +++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -592,7 +592,9 @@ base::Value(!extension_id_prompting_.empty())); } -void AppLauncherHandler::OnWebAppUninstalled(const web_app::AppId& app_id) { +void AppLauncherHandler::OnWebAppUninstalled( + const web_app::AppId& app_id, + webapps::WebappUninstallSource uninstall_source) { // This can be redundant in most cases, however it is not uncommon for the // chrome://apps page to be loaded, or reloaded, during the uninstallation of // an app. In this state, the app is still in the registry, but the
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.h b/chrome/browser/ui/webui/ntp/app_launcher_handler.h index d7cb982..0877bcb 100644 --- a/chrome/browser/ui/webui/ntp/app_launcher_handler.h +++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.h
@@ -106,7 +106,9 @@ // web_app::OnWebAppInstallManagerObserver: void OnWebAppInstalled(const web_app::AppId& app_id) override; void OnWebAppWillBeUninstalled(const web_app::AppId& app_id) override; - void OnWebAppUninstalled(const web_app::AppId& app_id) override; + void OnWebAppUninstalled( + const web_app::AppId& app_id, + webapps::WebappUninstallSource uninstall_source) override; void OnWebAppInstallManagerDestroyed() override; // web_app::AppRegistrarObserver:
diff --git a/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc b/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc index f39c04c..05ef737 100644 --- a/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc +++ b/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc
@@ -130,7 +130,8 @@ } void ProtocolHandlersHandler::OnWebAppUninstalled( - const web_app::AppId& app_id) { + const web_app::AppId& app_id, + webapps::WebappUninstallSource uninstall_source) { OnWebAppProtocolSettingsChanged(); }
diff --git a/chrome/browser/ui/webui/settings/protocol_handlers_handler.h b/chrome/browser/ui/webui/settings/protocol_handlers_handler.h index 11d7efd..f3ecf96e 100644 --- a/chrome/browser/ui/webui/settings/protocol_handlers_handler.h +++ b/chrome/browser/ui/webui/settings/protocol_handlers_handler.h
@@ -51,7 +51,9 @@ void OnProtocolHandlerRegistryChanged() override; // web_app::WebAppInstallManagerObserver: - void OnWebAppUninstalled(const web_app::AppId& app_id) override; + void OnWebAppUninstalled( + const web_app::AppId& app_id, + webapps::WebappUninstallSource uninstall_source) override; void OnWebAppInstallManagerDestroyed() override; // web_app::AppRegistrarObserver:
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc index 21c232c2..062a4d3 100644 --- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc +++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
@@ -274,6 +274,34 @@ } } +apps::Readiness ConvertWebappUninstallSourceToReadiness( + webapps::WebappUninstallSource source) { + switch (source) { + case webapps::WebappUninstallSource::kUnknown: + case webapps::WebappUninstallSource::kAppMenu: + case webapps::WebappUninstallSource::kAppsPage: + case webapps::WebappUninstallSource::kOsSettings: + case webapps::WebappUninstallSource::kSync: + case webapps::WebappUninstallSource::kAppManagement: + case webapps::WebappUninstallSource::kAppList: + case webapps::WebappUninstallSource::kShelf: + case webapps::WebappUninstallSource::kPlaceholderReplacement: + case webapps::WebappUninstallSource::kArc: + case webapps::WebappUninstallSource::kSubApp: + case webapps::WebappUninstallSource::kStartupCleanup: + case webapps::WebappUninstallSource::kParentUninstall: + case webapps::WebappUninstallSource::kTestCleanup: + return apps::Readiness::kUninstalledByUser; + case webapps::WebappUninstallSource::kMigration: + case webapps::WebappUninstallSource::kInternalPreinstalled: + case webapps::WebappUninstallSource::kExternalPreinstalled: + case webapps::WebappUninstallSource::kExternalPolicy: + case webapps::WebappUninstallSource::kSystemPreinstalled: + case webapps::WebappUninstallSource::kExternalLockScreen: + return apps::Readiness::kUninstalledByMigration; + } +} + bool IsNoteTakingWebApp(const WebApp& web_app) { return web_app.note_taking_new_note_url().is_valid(); } @@ -728,10 +756,10 @@ } apps::AppPtr WebAppPublisherHelper::ConvertUninstalledWebApp( - const AppId& app_id) { + const AppId& app_id, + webapps::WebappUninstallSource uninstall_source) { auto app = std::make_unique<apps::App>(app_type(), app_id); - // TODO(crbug.com/1423775): Plumb uninstall source (reason) here. - app->readiness = apps::Readiness::kUninstalledByUser; + app->readiness = ConvertWebappUninstallSourceToReadiness(uninstall_source); return app; } @@ -1280,7 +1308,9 @@ } } -void WebAppPublisherHelper::OnWebAppUninstalled(const AppId& app_id) { +void WebAppPublisherHelper::OnWebAppUninstalled( + const AppId& app_id, + webapps::WebappUninstallSource uninstall_source) { paused_apps_.MaybeRemoveApp(app_id); #if BUILDFLAG(IS_CHROMEOS) @@ -1291,7 +1321,7 @@ result.microphone); #endif - delegate_->PublishWebApp(ConvertUninstalledWebApp(app_id)); + delegate_->PublishWebApp(ConvertUninstalledWebApp(app_id, uninstall_source)); } void WebAppPublisherHelper::OnWebAppInstallManagerDestroyed() {
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.h b/chrome/browser/web_applications/app_service/web_app_publisher_helper.h index 59114a7..daa23c8 100644 --- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.h +++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.h
@@ -167,7 +167,9 @@ // Constructs an App with only the information required to identify an // uninstallation. - apps::AppPtr ConvertUninstalledWebApp(const AppId& app_id); + apps::AppPtr ConvertUninstalledWebApp( + const AppId& app_id, + webapps::WebappUninstallSource uninstall_source); // Constructs an App with only the information required to update // last launch time. @@ -317,7 +319,9 @@ void OnWebAppInstalledWithOsHooks(const AppId& app_id) override; void OnWebAppManifestUpdated(const AppId& app_id, base::StringPiece old_name) override; - void OnWebAppUninstalled(const AppId& app_id) override; + void OnWebAppUninstalled( + const AppId& app_id, + webapps::WebappUninstallSource uninstall_source) override; void OnWebAppInstallManagerDestroyed() override; // AppRegistrarObserver:
diff --git a/chrome/browser/web_applications/commands/web_app_uninstall_command.cc b/chrome/browser/web_applications/commands/web_app_uninstall_command.cc index c321bc0..238b5cd 100644 --- a/chrome/browser/web_applications/commands/web_app_uninstall_command.cc +++ b/chrome/browser/web_applications/commands/web_app_uninstall_command.cc
@@ -30,7 +30,7 @@ namespace { bool CanUninstallAllManagementSources( - const webapps::WebappUninstallSource& uninstall_source) { + webapps::WebappUninstallSource uninstall_source) { // Check that the source was from a known 'user' or allowed ones such // as kMigration. return uninstall_source == webapps::WebappUninstallSource::kUnknown || @@ -217,7 +217,7 @@ void WebAppUninstallCommand::Uninstall( const AppId& app_id, - const webapps::WebappUninstallSource& uninstall_source) { + webapps::WebappUninstallSource uninstall_source) { QueueSubAppsForUninstallIfAny(app_id); auto uninstall_job = WebAppUninstallJob::CreateAndStart( @@ -227,7 +227,7 @@ weak_factory_.GetWeakPtr(), app_id, uninstall_source), lock_->os_integration_manager(), lock_->sync_bridge(), lock_->icon_manager(), lock_->registrar(), lock_->install_manager(), - lock_->translation_manager(), *profile_prefs_); + lock_->translation_manager(), *profile_prefs_, uninstall_source); apps_pending_uninstall_[app_id] = std::move(uninstall_job); } @@ -244,7 +244,7 @@ void WebAppUninstallCommand::RemoveManagementTypeAfterOsUninstallRegistration( const AppId& app_id, const WebAppManagement::Type& management_type, - const webapps::WebappUninstallSource& uninstall_source, + webapps::WebappUninstallSource uninstall_source, OsHooksErrors os_hooks_errors) { { ScopedRegistryUpdate update(&lock_->sync_bridge()); @@ -266,7 +266,7 @@ void WebAppUninstallCommand::OnSingleUninstallComplete( const AppId& app_id, - const webapps::WebappUninstallSource& source, + webapps::WebappUninstallSource source, webapps::UninstallResultCode code) { DCHECK(base::Contains(apps_pending_uninstall_, app_id)); apps_pending_uninstall_.erase(app_id);
diff --git a/chrome/browser/web_applications/commands/web_app_uninstall_command.h b/chrome/browser/web_applications/commands/web_app_uninstall_command.h index ec8a39d..c40c3e1 100644 --- a/chrome/browser/web_applications/commands/web_app_uninstall_command.h +++ b/chrome/browser/web_applications/commands/web_app_uninstall_command.h
@@ -105,15 +105,15 @@ void AppendUninstallResultsToDebugLog(const AppId& app_id); void Abort(webapps::UninstallResultCode code); void Uninstall(const AppId& app_id, - const webapps::WebappUninstallSource& uninstall_source); + webapps::WebappUninstallSource uninstall_source); void QueueSubAppsForUninstallIfAny(const AppId& app_id); void RemoveManagementTypeAfterOsUninstallRegistration( const AppId& app_id, const WebAppManagement::Type& install_source, - const webapps::WebappUninstallSource& uninstall_source, + webapps::WebappUninstallSource uninstall_source, OsHooksErrors os_hooks_errors); void OnSingleUninstallComplete(const AppId& app_id, - const webapps::WebappUninstallSource& source, + webapps::WebappUninstallSource source, webapps::UninstallResultCode code); void MaybeFinishUninstallAndDestruct();
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_browsertest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_browsertest.cc index bb50517..7ac0d18e 100644 --- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_browsertest.cc +++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_browsertest.cc
@@ -27,6 +27,7 @@ #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h" #include "components/web_package/test_support/signed_web_bundles/web_bundle_signer.h" #include "components/web_package/web_bundle_builder.h" +#include "content/public/browser/web_contents.h" #include "content/public/common/content_features.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" @@ -158,6 +159,18 @@ return app_window->tab_strip_model()->GetActiveWebContents(); } + content::RenderFrameHost* Navigate(const GURL& url) { + Browser* app_window = CreateAppWindow(); + AttachWebContents(app_window); + + content::RenderFrameHost* render_frame_host = NavigateToURLWithDisposition( + app_window, url, WindowOpenDisposition::CURRENT_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); + + CHECK(render_frame_host); + return render_frame_host; + } + void NavigateAndWaitForTitle(const GURL& url, const std::u16string& page_title) { Browser* app_window = CreateAppWindow(); @@ -392,6 +405,67 @@ u"data from web bundle data from service worker"); } +class IsolatedWebAppURLLoaderFactoryFrameBrowserTest + : public IsolatedWebAppURLLoaderFactoryBrowserTest { + protected: + void NavigateAndCheckForErrors(web_package::WebBundleBuilder&& builder) { + base::FilePath bundle_path = + SignAndWriteBundleToDisk(builder.CreateBundle()); + std::unique_ptr<WebApp> iwa = CreateIsolatedWebApp( + kUrl, WebApp::IsolationData{InstalledBundle{.path = bundle_path}}); + RegisterWebApp(std::move(iwa)); + TrustWebBundleId(); + + auto* rfh = Navigate(kUrl); + + // It is not easily possible from JavaScript to determine whether a frame + // has loaded successfully or errored (`frame.onload` also triggers when an + // error page is loaded in the frame, `frame.onerror` never triggers). Thus, + // we eval JS inside the created frame to compare the frame's content to the + // expected content. + int sub_frame_count = 0; + rfh->ForEachRenderFrameHost( + [&sub_frame_count](content::RenderFrameHost* rfh) { + if (rfh->IsInPrimaryMainFrame()) { + return; + } + ++sub_frame_count; + EXPECT_THAT(content::EvalJs(rfh, "document.body.innerText"), + Eq("inner frame content")); + }); + EXPECT_THAT(sub_frame_count, Eq(1)); + } +}; + +IN_PROC_BROWSER_TEST_F(IsolatedWebAppURLLoaderFactoryFrameBrowserTest, + CanUseDataUrlForFrame) { + web_package::WebBundleBuilder builder; + builder.AddExchange( + kUrl, {{":status", "200"}, {"content-type", "text/html"}}, + "<iframe src=\"data:text/html,<h1>inner frame content</h1>\"></iframe>"); + ASSERT_NO_FATAL_FAILURE(NavigateAndCheckForErrors(std::move(builder))); +} + +IN_PROC_BROWSER_TEST_F(IsolatedWebAppURLLoaderFactoryFrameBrowserTest, + CanUseBlobUrlForFrame) { + web_package::WebBundleBuilder builder; + builder.AddExchange(kUrl, {{":status", "200"}, {"content-type", "text/html"}}, + "<script src=\"script.js\"></script>"); + builder.AddExchange( + kUrl.Resolve("/script.js"), + {{":status", "200"}, {"content-type", "application/javascript"}}, + R"( +const iframe = document.createElement("iframe"); +document.currentScript.appendChild(iframe); +const blob = new Blob( + ['<h1>inner frame content</h1>'], + {type : 'text/html'} +); +iframe.src = window.URL.createObjectURL(blob); + )"); + ASSERT_NO_FATAL_FAILURE(NavigateAndCheckForErrors(std::move(builder))); +} + class IsolatedWebAppURLLoaderFactoryCSPBrowserTest : public IsolatedWebAppURLLoaderFactoryBrowserTest, public ::testing::WithParamInterface<bool> {
diff --git a/chrome/browser/web_applications/test/web_app_test_observers.cc b/chrome/browser/web_applications/test/web_app_test_observers.cc index 91bc62f9..e273855 100644 --- a/chrome/browser/web_applications/test/web_app_test_observers.cc +++ b/chrome/browser/web_applications/test/web_app_test_observers.cc
@@ -91,7 +91,8 @@ } void WebAppInstallManagerObserverAdapter::OnWebAppUninstalled( - const AppId& app_id) { + const AppId& app_id, + webapps::WebappUninstallSource uninstall_source) { if (app_uninstalled_delegate_) app_uninstalled_delegate_.Run(app_id); }
diff --git a/chrome/browser/web_applications/test/web_app_test_observers.h b/chrome/browser/web_applications/test/web_app_test_observers.h index a17d08f..dd161092 100644 --- a/chrome/browser/web_applications/test/web_app_test_observers.h +++ b/chrome/browser/web_applications/test/web_app_test_observers.h
@@ -58,7 +58,9 @@ void OnWebAppManifestUpdated(const AppId& app_id, base::StringPiece old_name) override; void OnWebAppWillBeUninstalled(const AppId& app_id) override; - void OnWebAppUninstalled(const AppId& app_id) override; + void OnWebAppUninstalled( + const AppId& app_id, + webapps::WebappUninstallSource uninstall_source) override; void OnWebAppInstallManagerDestroyed() override; protected:
diff --git a/chrome/browser/web_applications/web_app_install_manager.cc b/chrome/browser/web_applications/web_app_install_manager.cc index 7958f7a5..31c591c 100644 --- a/chrome/browser/web_applications/web_app_install_manager.cc +++ b/chrome/browser/web_applications/web_app_install_manager.cc
@@ -121,9 +121,11 @@ // the webapps::WebappInstallSource in this event. } -void WebAppInstallManager::NotifyWebAppUninstalled(const AppId& app_id) { +void WebAppInstallManager::NotifyWebAppUninstalled( + const AppId& app_id, + webapps::WebappUninstallSource uninstall_source) { for (WebAppInstallManagerObserver& observer : observers_) { - observer.OnWebAppUninstalled(app_id); + observer.OnWebAppUninstalled(app_id, uninstall_source); } }
diff --git a/chrome/browser/web_applications/web_app_install_manager.h b/chrome/browser/web_applications/web_app_install_manager.h index a2c7e50..21e6583 100644 --- a/chrome/browser/web_applications/web_app_install_manager.h +++ b/chrome/browser/web_applications/web_app_install_manager.h
@@ -38,7 +38,9 @@ virtual void NotifyWebAppInstalled(const AppId& app_id); virtual void NotifyWebAppInstalledWithOsHooks(const AppId& app_id); - virtual void NotifyWebAppUninstalled(const AppId& app_id); + virtual void NotifyWebAppUninstalled( + const AppId& app_id, + webapps::WebappUninstallSource uninstall_source); virtual void NotifyWebAppManifestUpdated(const AppId& app_id, base::StringPiece old_name); virtual void NotifyWebAppWillBeUninstalled(const AppId& app_id);
diff --git a/chrome/browser/web_applications/web_app_install_manager_observer.h b/chrome/browser/web_applications/web_app_install_manager_observer.h index 947630e1..9797c13b 100644 --- a/chrome/browser/web_applications/web_app_install_manager_observer.h +++ b/chrome/browser/web_applications/web_app_install_manager_observer.h
@@ -27,7 +27,9 @@ // Called after a web app is uninstalled. |app_id| is no longer registered in // the WebAppRegistrar, all OS hooks are uninstalled, and icons have been // deleted. - virtual void OnWebAppUninstalled(const AppId& app_id) {} + virtual void OnWebAppUninstalled( + const AppId& app_id, + webapps::WebappUninstallSource uninstall_source) {} // Called when any field of a web app's local manifest is updated. // Note that |old_name| will always be the same as the current name as we
diff --git a/chrome/browser/web_applications/web_app_uninstall_job.cc b/chrome/browser/web_applications/web_app_uninstall_job.cc index baade27..e0416f239 100644 --- a/chrome/browser/web_applications/web_app_uninstall_job.cc +++ b/chrome/browser/web_applications/web_app_uninstall_job.cc
@@ -33,11 +33,12 @@ WebAppRegistrar& registrar, WebAppInstallManager& install_manager, WebAppTranslationManager& translation_manager, - PrefService& profile_prefs) { + PrefService& profile_prefs, + webapps::WebappUninstallSource uninstall_source) { return base::WrapUnique(new WebAppUninstallJob( app_id, app_origin, std::move(callback), os_integration_manager, sync_bridge, icon_manager, registrar, install_manager, - translation_manager, profile_prefs)); + translation_manager, profile_prefs, uninstall_source)); } WebAppUninstallJob::WebAppUninstallJob( @@ -50,12 +51,14 @@ WebAppRegistrar& registrar, WebAppInstallManager& install_manager, WebAppTranslationManager& translation_manager, - PrefService& profile_prefs) + PrefService& profile_prefs, + webapps::WebappUninstallSource uninstall_source) : app_id_(app_id), callback_(std::move(callback)), registrar_(®istrar), sync_bridge_(&sync_bridge), - install_manager_(&install_manager) { + install_manager_(&install_manager), + uninstall_source_(uninstall_source) { Start(app_origin, os_integration_manager, icon_manager, translation_manager, profile_prefs); } @@ -143,7 +146,7 @@ ScopedRegistryUpdate update(sync_bridge_); update->DeleteApp(app_id_); } - install_manager_->NotifyWebAppUninstalled(app_id_); + install_manager_->NotifyWebAppUninstalled(app_id_, uninstall_source_); std::move(callback_).Run(errors_ ? webapps::UninstallResultCode::kError : webapps::UninstallResultCode::kSuccess); }
diff --git a/chrome/browser/web_applications/web_app_uninstall_job.h b/chrome/browser/web_applications/web_app_uninstall_job.h index 9e761af..5111ed9 100644 --- a/chrome/browser/web_applications/web_app_uninstall_job.h +++ b/chrome/browser/web_applications/web_app_uninstall_job.h
@@ -53,7 +53,8 @@ WebAppRegistrar& registrar, WebAppInstallManager& install_manager, WebAppTranslationManager& translation_manager, - PrefService& profile_prefs); + PrefService& profile_prefs, + webapps::WebappUninstallSource uninstall_source); ~WebAppUninstallJob(); @@ -67,7 +68,8 @@ WebAppRegistrar& registrar, WebAppInstallManager& install_manager, WebAppTranslationManager& translation_manager, - PrefService& profile_prefs); + PrefService& profile_prefs, + webapps::WebappUninstallSource uninstall_source); // The given `app_id` must correspond to an app in the `registrar`. // This modifies the app to set `is_uninstalling()` to true, and delete the @@ -99,6 +101,7 @@ raw_ptr<WebAppSyncBridge> sync_bridge_; raw_ptr<WebAppInstallManager> install_manager_; + webapps::WebappUninstallSource uninstall_source_; bool app_data_deleted_ = false; bool translation_data_deleted_ = false; bool hooks_uninstalled_ = false;
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 88f9a6c..2235213 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1681322360-fa14f3ca9370bbbcc5b536eb04e26cc723dbdc08.profdata +chrome-linux-main-1681365349-a1c645037b3087e9ed029de4dff0c7b97146f8b0.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 3233f16a..54e21a6 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1681343974-c505acca0eb8e50d56370215187eb440b3cb01cd.profdata +chrome-mac-arm-main-1681372596-7988930414c3a1348e3b39aa217bc6dfc18a59aa.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index d52d2c5..5f5e5cf 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1681322360-12c9b62fcc5daad4f9b0b181ecbc98e56afad583.profdata +chrome-mac-main-1681343974-bcdd422afba71c878998d68ac19614e1d25561b8.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index aad18798..67c39c5 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1681333180-dceb0c169b66545c2c80a056eb77ad3053927ae2.profdata +chrome-win32-main-1681343974-c76ffa8d693c3d71cec1f50665331390d9a5e5dd.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 69db130..17f7b09 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1681333180-514b86a7d287c1ffd986630fffc776d452007759.profdata +chrome-win64-main-1681365349-464daa767d91bc77874f79e81cfb95a3660efa28.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 5324dbae..81e5355 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2512,6 +2512,7 @@ "../browser/ui/views/device_id/pen_id_browsertest_win.cc", "../browser/ui/views/web_apps/web_app_integration_browsertest_win.cc", ] + sources -= [ "../browser/ui/views/tabs/tab_search_button_browsertest.cc" ] } if (is_win || is_linux) { @@ -6580,7 +6581,7 @@ sources += [ "../browser/signin/bound_session_credentials/bound_session_cookie_controller_impl_unittest.cc", "../browser/signin/bound_session_credentials/bound_session_cookie_observer_unittest.cc", - "../browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_unittest.cc", + "../browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl_unittest.cc", "../browser/signin/bound_session_credentials/bound_session_refresh_cookie_fetcher_unittest.cc", "../browser/signin/bound_session_credentials/bound_session_test_cookie_manager.cc", "../browser/signin/bound_session_credentials/bound_session_test_cookie_manager.h", @@ -7516,6 +7517,7 @@ "../browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc", "../browser/apps/app_service/promise_apps/promise_app_registry_cache_unittest.cc", "../browser/apps/app_service/promise_apps/promise_app_update_unittest.cc", + "../browser/apps/app_service/promise_apps/promise_app_wrapper_unittest.cc", "../browser/apps/app_service/promise_apps/promise_apps_unittest.cc", "../browser/apps/app_service/publishers/arc_apps_unittest.cc", "../browser/apps/app_service/publishers/bruschetta_apps_unittest.cc", @@ -7687,6 +7689,7 @@ "//chrome/browser/apps/app_deduplication_service/proto", "//chrome/browser/apps/app_preload_service:unit_tests", "//chrome/browser/apps/app_provisioning_service/proto", + "//chrome/browser/apps/app_service/promise_apps/proto", "//chrome/browser/ash", "//chrome/browser/ash:arc_test_support", "//chrome/browser/ash:test_support",
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn index e29a69f..bc0a325 100644 --- a/chrome/test/data/webui/settings/BUILD.gn +++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -201,10 +201,6 @@ files += [ "incompatible_applications_page_test.ts" ] } - if (is_chrome_branded) { - files += [ "get_most_chrome_page_test.ts" ] - } - ts_path_mappings = [ # Settings tests should only be importing from one of the URLs below, so # that tests work both in optimize_webui=true/false modes.
diff --git a/chrome/test/data/webui/settings/advanced_page_test.ts b/chrome/test/data/webui/settings/advanced_page_test.ts index ae5b9e0..1ff212d 100644 --- a/chrome/test/data/webui/settings/advanced_page_test.ts +++ b/chrome/test/data/webui/settings/advanced_page_test.ts
@@ -82,9 +82,6 @@ test('advanced pages', function() { const sections = ['a11y', 'languages', 'downloads', 'reset']; - // <if expr="_google_chrome"> - sections.push('getMostChrome'); - // </if> for (let i = 0; i < sections.length; i++) { const section = getSection(basicPage, sections[i]!); assertTrue(!!section);
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index ff8713f..b037f55 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -1005,10 +1005,6 @@ registerTest('MetricsReporting', 'metrics_reporting_tests.js'); GEN('#endif'); -GEN('#if BUILDFLAG(GOOGLE_CHROME_BRANDING)'); -registerTest('GetMostChromePage', 'get_most_chrome_page_test.js'); -GEN('#endif'); - function registerTest(testName, module, caseName) { const className = `CrSettings${testName}Test`; this[className] = class extends CrSettingsBrowserTest {
diff --git a/chrome/test/data/webui/settings/get_most_chrome_page_test.ts b/chrome/test/data/webui/settings/get_most_chrome_page_test.ts deleted file mode 100644 index 68cafbb..0000000 --- a/chrome/test/data/webui/settings/get_most_chrome_page_test.ts +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'chrome://settings/lazy_load.js'; - -import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {SettingsGetMostChromePageElement} from 'chrome://settings/lazy_load.js'; -import {assertTrue} from 'chrome://webui-test/chai_assert.js'; - -/** @fileoverview Suite of tests for get_most_chrome_page. */ -suite('GetMostChromePage', function() { - let testElement: SettingsGetMostChromePageElement; - - setup(function() { - document.body.innerHTML = window.trustedTypes!.emptyHTML; - testElement = document.createElement('settings-get-most-chrome-page'); - document.body.appendChild(testElement); - flush(); - }); - - test('Basic', function() { - assertTrue(!!testElement); - // TODO(crbug.com/143278): Expand this test as the element gets implemented. - }); -});
diff --git a/chromeos/ash/components/cryptohome/DIR_METADATA b/chromeos/ash/components/cryptohome/DIR_METADATA index 6d05a16..88df346 100644 --- a/chromeos/ash/components/cryptohome/DIR_METADATA +++ b/chromeos/ash/components/cryptohome/DIR_METADATA
@@ -1,3 +1 @@ -monorail { - component: "OS>Systems>Security" -} +mixins: "//ash/login/LOGIN_LOCK_METADATA"
diff --git a/chromeos/ash/components/cryptohome/OWNERS b/chromeos/ash/components/cryptohome/OWNERS index 911c45d4..878ee9e4 100644 --- a/chromeos/ash/components/cryptohome/OWNERS +++ b/chromeos/ash/components/cryptohome/OWNERS
@@ -1,2 +1,3 @@ -antrim@chromium.org +file://ash/login/LOGIN_LOCK_OWNERS + hashimoto@chromium.org
diff --git a/chromeos/ash/components/dbus/biod/DIR_METADATA b/chromeos/ash/components/dbus/biod/DIR_METADATA index 8245a197..88df346 100644 --- a/chromeos/ash/components/dbus/biod/DIR_METADATA +++ b/chromeos/ash/components/dbus/biod/DIR_METADATA
@@ -1,3 +1 @@ -monorail { - component: "UI>Shell>LockScreen" -} +mixins: "//ash/login/LOGIN_LOCK_METADATA"
diff --git a/chromeos/ash/components/drivefs/fake_drivefs.cc b/chromeos/ash/components/drivefs/fake_drivefs.cc index 990bfce1..7f5d0e4 100644 --- a/chromeos/ash/components/drivefs/fake_drivefs.cc +++ b/chromeos/ash/components/drivefs/fake_drivefs.cc
@@ -656,9 +656,4 @@ std::move(callback).Run(drive::FILE_ERROR_OK); } -void FakeDriveFs::GetOfflineFilesSpaceUsage( - drivefs::mojom::DriveFs::GetOfflineFilesSpaceUsageCallback callback) { - std::move(callback).Run(drive::FILE_ERROR_OK, 1024); -} - } // namespace drivefs
diff --git a/chromeos/ash/components/drivefs/fake_drivefs.h b/chromeos/ash/components/drivefs/fake_drivefs.h index 0431de9..ff7a8c83 100644 --- a/chromeos/ash/components/drivefs/fake_drivefs.h +++ b/chromeos/ash/components/drivefs/fake_drivefs.h
@@ -86,6 +86,12 @@ drivefs::mojom::QueryParametersPtr query_params), (override)); + MOCK_METHOD( + void, + GetOfflineFilesSpaceUsage, + (drivefs::mojom::DriveFs::GetOfflineFilesSpaceUsageCallback callback), + (override)); + const base::FilePath& mount_path() { return mount_path_; } absl::optional<bool> IsItemPinned(const std::string& path); @@ -204,10 +210,6 @@ bool enabled, drivefs::mojom::DriveFs::SetDocsOfflineEnabledCallback callback) override; - void GetOfflineFilesSpaceUsage( - drivefs::mojom::DriveFs::GetOfflineFilesSpaceUsageCallback callback) - override; - const base::FilePath mount_path_; int64_t next_stable_id_ = 1;
diff --git a/chromeos/ash/components/login/DIR_METADATA b/chromeos/ash/components/login/DIR_METADATA index 2371e02..88df346 100644 --- a/chromeos/ash/components/login/DIR_METADATA +++ b/chromeos/ash/components/login/DIR_METADATA
@@ -1,3 +1 @@ -monorail { - component: "UI>Shell>StartScreen" -} +mixins: "//ash/login/LOGIN_LOCK_METADATA"
diff --git a/chromeos/ash/components/login/hibernate/DIR_METADATA b/chromeos/ash/components/login/hibernate/DIR_METADATA new file mode 100644 index 0000000..e2ca13d4 --- /dev/null +++ b/chromeos/ash/components/login/hibernate/DIR_METADATA
@@ -0,0 +1,14 @@ +# For more information on DIR_METADATA files, see: +# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/README.md +# +# For the schema of this file, see Metadata message: +# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto + +buganizer { + # https://b.corp.google.com/issues?q=status:open%20componentid:167191 + # ChromeOS > Platform > System > Power + component_id: 167191 +} + +team_email : "chromeos-hibernate@google.com" +os: CHROME_OS \ No newline at end of file
diff --git a/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.cc b/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.cc index d27b6e2e..96be6cfd 100644 --- a/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.cc +++ b/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.cc
@@ -26,4 +26,10 @@ cros_hotspot_config_impl_->EnableHotspot(base::DoNothing()); } +void CrosHotspotConfigTestHelper::SetHotspotConfig( + hotspot_config::mojom::HotspotConfigPtr hotspot_config) { + cros_hotspot_config_impl_->SetHotspotConfig(std::move(hotspot_config), + base::DoNothing()); +} + } // namespace ash::hotspot_config
diff --git a/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.h b/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.h index 610ab4a..4cf1a88e 100644 --- a/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.h +++ b/chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.h
@@ -28,6 +28,8 @@ void EnableHotspot(); + void SetHotspotConfig(hotspot_config::mojom::HotspotConfigPtr hotspot_config); + protected: // Called in |~CrosHotspotConfigTestHelper()| to destroy // cros_hotspot_config_impl_.
diff --git a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/util/UrlConstants.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/util/UrlConstants.java index 6cb9a9fa..fc670ab9 100644 --- a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/util/UrlConstants.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/util/UrlConstants.java
@@ -101,6 +101,12 @@ public static final String MY_ACTIVITY_URL_IN_HISTORY = "https://myactivity.google.com/myactivity/?utm_source=chrome_h"; + public static final String GOOGLE_SEARCH_HISTORY_URL_IN_QD = + "https://myactivity.google.com/product/search?utm_source=chrome_qd"; + + public static final String MY_ACTIVITY_URL_IN_QD = + "https://myactivity.google.com/myactivity?utm_source=chrome_qd"; + public static final String EXPLORE_HOST = "explore"; public static final String EXPLORE_URL = "chrome-native://explore/"; public static final String CHROME_DINO_URL = "chrome://dino/";
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc index f478de2..2b9aa29 100644 --- a/components/omnibox/browser/autocomplete_result.cc +++ b/components/omnibox/browser/autocomplete_result.cc
@@ -332,8 +332,9 @@ // `stripped_destination_url` to detect result changes. If // `stripped_destination_url` is already set, i.e. it was not a pre-deduped // search suggestion, `ComputeStrippedDestinationURL()` will early exit. - if (DiscourageTopMatchFromBeingSearchEntity(&matches_)) + if (UndedupTopSearchEntityMatch(&matches_)) { matches_[0].ComputeStrippedDestinationURL(input, template_url_service); + } } const bool is_zero_suggest = input.IsZeroSuggest(); @@ -813,8 +814,7 @@ } // static -bool AutocompleteResult::DiscourageTopMatchFromBeingSearchEntity( - ACMatches* matches) { +bool AutocompleteResult::UndedupTopSearchEntityMatch(ACMatches* matches) { if (matches->empty()) return false; @@ -868,10 +868,10 @@ } if (non_entity_it != top_match->duplicate_matches.end()) { - // Copy the non-entity match, then erase it from the list of duplicates. + // Move out the non-entity match, then erase it from the list of duplicates. // We do this first, because the insertion operation invalidates all // iterators, including |top_match|. - AutocompleteMatch non_entity_match_copy = *non_entity_it; + AutocompleteMatch non_entity_match_copy{std::move(*non_entity_it)}; top_match->duplicate_matches.erase(non_entity_it); // When we spawn our non-entity match copy, we still want to preserve any @@ -881,9 +881,22 @@ non_entity_match_copy.entity_id = top_match->entity_id; } - // Promote the non-entity match to the top, then immediately return, since - // all our iterators are invalid after the insertion. - matches->insert(matches->begin(), std::move(non_entity_match_copy)); + // Unless the entity match has Actions in Suggest, promote the non-entity + // match to the top. Otherwise keep the entity match at the top followed by + // the non-entity match. + bool top_match_has_actions = + !!top_match->GetActionWhere([](const auto& action) { + return action->ActionId() == OmniboxActionId::ACTION_IN_SUGGEST; + }); + + if (top_match_has_actions && + OmniboxFieldTrial::kActionsInSuggestPromoteEntitySuggestion.Get()) { + matches->insert(std::next(matches->begin()), + std::move(non_entity_match_copy)); + } else { + matches->insert(matches->begin(), std::move(non_entity_match_copy)); + } + // Immediately return as all our iterators are invalid after the insertion. return true; }
diff --git a/components/omnibox/browser/autocomplete_result.h b/components/omnibox/browser/autocomplete_result.h index 59439b3e..6670c22 100644 --- a/components/omnibox/browser/autocomplete_result.h +++ b/components/omnibox/browser/autocomplete_result.h
@@ -178,9 +178,11 @@ ACMatches* matches); // If the top match is a Search Entity, and it was deduplicated with a - // non-entity match, split off the non-entity match from the list of - // duplicates, promote it to the top, and return true. - static bool DiscourageTopMatchFromBeingSearchEntity(ACMatches* matches); + // non-entity match, splits off the non-entity match from the list of + // duplicates and returns true. Otherwise returns false. + // The non-entity duplicate is promoted to the top, unless the entity match + // has Action in Suggest where it remains at the top. + static bool UndedupTopSearchEntityMatch(ACMatches* matches); // Just a helper function to encapsulate the logic of deciding how many // matches to keep, with respect to configured maximums, URL limits,
diff --git a/components/omnibox/browser/autocomplete_result_unittest.cc b/components/omnibox/browser/autocomplete_result_unittest.cc index d3e855f2..2143b3d 100644 --- a/components/omnibox/browser/autocomplete_result_unittest.cc +++ b/components/omnibox/browser/autocomplete_result_unittest.cc
@@ -2870,8 +2870,6 @@ TEST_F(AutocompleteResultTest, Android_TrimOmniboxActions) { scoped_refptr<FakeAutocompleteProvider> provider = new FakeAutocompleteProvider(AutocompleteProvider::Type::TYPE_SEARCH); - const OmniboxAction::LabelStrings dummy_labels(u"", u"", u"", u""); - using OmniboxActionId::ACTION_IN_SUGGEST; using OmniboxActionId::HISTORY_CLUSTERS; using OmniboxActionId::PEDAL; @@ -2991,3 +2989,100 @@ } } #endif // BUILDFLAG(IS_ANDROID) + +TEST_F(AutocompleteResultTest, Android_UndedupTopSearch) { + scoped_refptr<FakeAutocompleteProvider> provider = + new FakeAutocompleteProvider(AutocompleteProvider::Type::TYPE_SEARCH); + + // 4 different matches to cover variety of scenarios. + // Matches are recognized by their type and actions presence. + // `search` is marked as a duplicate of both `entity` matches. + AutocompleteMatch what_you_typed( + provider.get(), 1, false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED); + AutocompleteMatch search(provider.get(), 1, false, + AutocompleteMatchType::SEARCH_SUGGEST); + search.allowed_to_be_default_match = true; + + AutocompleteMatch entity_without_action( + provider.get(), 1, false, AutocompleteMatchType::SEARCH_SUGGEST_ENTITY); + AutocompleteMatch entity_with_action( + provider.get(), 1, false, AutocompleteMatchType::SEARCH_SUGGEST_ENTITY); + entity_with_action.actions.push_back(base::MakeRefCounted<FakeOmniboxAction>( + OmniboxActionId::ACTION_IN_SUGGEST)); + entity_with_action.duplicate_matches.push_back(search); + entity_without_action.duplicate_matches.push_back(search); + + struct UndedupTestData { + std::string test_name; + bool promote_entities; + std::vector<AutocompleteMatch> input; + std::vector<AutocompleteMatch> expected_result; + } test_cases[]{ + {"no op with no matches", true, {}, {}}, + {"no op with no entities / 1", true, {what_you_typed}, {what_you_typed}}, + {"no op with no entities / 2", + true, + {what_you_typed, search}, + {what_you_typed, search}}, + {"no op with entities with no actions", + true, + {what_you_typed, entity_without_action}, + {what_you_typed, entity_without_action}}, + {"no op with entities with actions at low positions", + true, + {what_you_typed, entity_with_action}, + {what_you_typed, entity_with_action}}, + + // Undedup and possibly rotate eligible cases. + {"no rotation when promotion is disabled with no actions at top position", + false, + {entity_without_action}, + {search, entity_without_action}}, + {"no rotation when promotion is enabled with no actions at top position", + true, + {entity_without_action}, + {search, entity_without_action}}, + {"no rotation when promotion is disabled with actions at top position", + false, + {entity_with_action}, + {search, entity_with_action}}, + {"rotation when promotion is enabled with actions at top position", + true, + {entity_with_action}, + {entity_with_action, search}}, + }; + + // Crete matches following the `input_matches_and_actions` input. + // The input specifies what type of OMNIBOX_ACTION should be added to every + // individual match. + // Once done, run the trimming and verify that the output contains exactly the + // matches we want to see. + for (const auto& test_case : test_cases) { + auto result = test_case.input; + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeatureWithParameters( + omnibox::kActionsInSuggest, + {{OmniboxFieldTrial::kActionsInSuggestPromoteEntitySuggestion.name, + test_case.promote_entities ? "true" : "false"}}); + AutocompleteResult::UndedupTopSearchEntityMatch(&result); + + EXPECT_EQ(result.size(), test_case.expected_result.size()); + for (size_t index = 0u; index < result.size(); ++index) { + const auto& found_match = result[index]; + const auto& expect_match = test_case.expected_result[index]; + EXPECT_EQ(found_match.type, expect_match.type) + << "at index " << index + << " while testing variant: " << test_case.test_name; + EXPECT_EQ(found_match.actions.size(), expect_match.actions.size()) + << "at index " << index + << " while testing variant: " << test_case.test_name; + for (size_t action_index = 0u; action_index < found_match.actions.size(); + ++action_index) { + EXPECT_EQ(found_match.actions[action_index]->ActionId(), + expect_match.actions[action_index]->ActionId()) + << "action " << action_index << " at index " << index + << " while testing variant: " << test_case.test_name; + } + } + } +}
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc index 400bbc3..bac138c 100644 --- a/components/omnibox/browser/omnibox_field_trial.cc +++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -1165,6 +1165,15 @@ // <- Inspire Me // --------------------------------------------------------- +// Actions In Suggest -> +// When set to true, permits Entity suggestion with associated Actions to be +// promoted over the Escape Hatch. +const base::FeatureParam<bool> kActionsInSuggestPromoteEntitySuggestion( + &omnibox::kActionsInSuggest, + "PromoteEntitySuggestion", + false); +// <- Actions In Suggest +// --------------------------------------------------------- } // namespace OmniboxFieldTrial
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h index 035c01d89..3257b6c8 100644 --- a/components/omnibox/browser/omnibox_field_trial.h +++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -726,6 +726,13 @@ // <- Inspire Me // --------------------------------------------------------- +// Actions In Suggest -> +// +// When set to true, permits Entity suggestion with associated Actions to be +// promoted over the Escape Hatch. +extern const base::FeatureParam<bool> kActionsInSuggestPromoteEntitySuggestion; +// <- Actions In Suggest +// --------------------------------------------------------- // New params should be inserted above this comment. They should be ordered // consistently with `omnibox_features.h`. They should be formatted as:
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc index af7086b..4046ac0 100644 --- a/components/omnibox/common/omnibox_features.cc +++ b/components/omnibox/common/omnibox_features.cc
@@ -706,4 +706,10 @@ // the suggestion list on the NTP and SRP. BASE_FEATURE(kInspireMe, "OmniboxInspireMe", base::FEATURE_DISABLED_BY_DEFAULT); +// Actions in Suggest is a data-driven feature; it's considered enabled when the +// data is available. +// The feature flag below helps us tune feature behaviors. +BASE_FEATURE(kActionsInSuggest, + "OmniboxActionsInSuggest", + base::FEATURE_ENABLED_BY_DEFAULT); } // namespace omnibox
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h index 73809fd..f646e5f 100644 --- a/components/omnibox/common/omnibox_features.h +++ b/components/omnibox/common/omnibox_features.h
@@ -160,6 +160,10 @@ // Inspire Me - additional suggestions based on user's location and interests. BASE_DECLARE_FEATURE(kInspireMe); +// Actions in Suggest - Action Chips for Entity Suggestions. +// Data driven feature; flag helps tune behavior. +BASE_DECLARE_FEATURE(kActionsInSuggest); + } // namespace omnibox #endif // COMPONENTS_OMNIBOX_COMMON_OMNIBOX_FEATURES_H_
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn index a353ae04..1b669ef 100644 --- a/components/performance_manager/BUILD.gn +++ b/components/performance_manager/BUILD.gn
@@ -74,6 +74,7 @@ "graph/node_base.cc", "graph/node_base.h", "graph/node_data_describer.cc", + "graph/node_data_describer_util.cc", "graph/node_type.h", "graph/page_node.cc", "graph/page_node_impl.cc", @@ -134,7 +135,6 @@ "public/graph/node_attached_data.h", "public/graph/node_data_describer.h", "public/graph/node_data_describer_registry.h", - "public/graph/node_data_describer_util.cc", "public/graph/node_data_describer_util.h", "public/graph/node_state.h", "public/graph/page_node.h", @@ -291,6 +291,7 @@ "graph/graph_registered_unittest.cc", "graph/node_attached_data_unittest.cc", "graph/node_base_unittest.cc", + "graph/node_data_describer_util_unittest.cc", "graph/page_node_impl_unittest.cc", "graph/policies/process_priority_policy_unittest.cc", "graph/process_node_impl_unittest.cc",
diff --git a/components/performance_manager/graph/node_data_describer_util.cc b/components/performance_manager/graph/node_data_describer_util.cc new file mode 100644 index 0000000..0ce619b6 --- /dev/null +++ b/components/performance_manager/graph/node_data_describer_util.cc
@@ -0,0 +1,86 @@ +// Copyright 2020 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/performance_manager/public/graph/node_data_describer_util.h" + +#include "base/i18n/time_formatting.h" +#include "base/task/task_traits.h" +#include "components/performance_manager/graph/frame_node_impl.h" +#include "components/performance_manager/graph/frame_node_impl_describer.h" +#include "components/performance_manager/graph/node_base.h" +#include "components/performance_manager/graph/node_type.h" +#include "components/performance_manager/graph/page_node_impl.h" +#include "components/performance_manager/graph/page_node_impl_describer.h" +#include "components/performance_manager/graph/process_node_impl.h" +#include "components/performance_manager/graph/process_node_impl_describer.h" +#include "components/performance_manager/graph/worker_node_impl.h" +#include "components/performance_manager/graph/worker_node_impl_describer.h" +#include "components/performance_manager/public/graph/node.h" +#include "components/performance_manager/public/graph/node_data_describer.h" +#include "components/performance_manager/public/graph/node_data_describer_registry.h" + +namespace performance_manager { + +base::Value TimeDeltaFromNowToValue(base::TimeTicks time_ticks) { + base::TimeDelta delta = base::TimeTicks::Now() - time_ticks; + + std::u16string out; + bool succeeded = TimeDurationFormat(delta, base::DURATION_WIDTH_WIDE, &out); + DCHECK(succeeded); + + return base::Value(out); +} + +base::Value MaybeNullStringToValue(base::StringPiece str) { + if (str.data() == nullptr) { + return base::Value(); + } + return base::Value(str); +} + +base::Value PriorityAndReasonToValue( + const execution_context_priority::PriorityAndReason& priority_and_reason) { + base::Value::Dict priority; + priority.Set("priority", + base::TaskPriorityToString(priority_and_reason.priority())); + priority.Set("reason", MaybeNullStringToValue(priority_and_reason.reason())); + return base::Value(std::move(priority)); +} + +std::string DumpNodeDescription(const Node* node) { + const NodeBase* node_base = NodeBase::FromNode(node); + switch (node_base->type()) { + case NodeTypeEnum::kFrame: + return FrameNodeImplDescriber() + .DescribeNodeData(FrameNodeImpl::FromNodeBase(node_base)) + .DebugString(); + case NodeTypeEnum::kPage: + return PageNodeImplDescriber() + .DescribeNodeData(PageNodeImpl::FromNodeBase(node_base)) + .DebugString(); + case NodeTypeEnum::kProcess: + return ProcessNodeImplDescriber() + .DescribeNodeData(ProcessNodeImpl::FromNodeBase(node_base)) + .DebugString(); + case NodeTypeEnum::kSystem: + // SystemNodeImpl has no default describer. Return an empty dictionary. + return base::Value::Dict().DebugString(); + case NodeTypeEnum::kWorker: + return WorkerNodeImplDescriber() + .DescribeNodeData(WorkerNodeImpl::FromNodeBase(node_base)) + .DebugString(); + case NodeTypeEnum::kInvalidType: + NOTREACHED_NORETURN(); + } + NOTREACHED_NORETURN(); +} + +std::string DumpRegisteredDescribers(const Node* node) { + return node->GetGraph() + ->GetNodeDataDescriberRegistry() + ->DescribeNodeData(node) + .DebugString(); +} + +} // namespace performance_manager
diff --git a/components/performance_manager/graph/node_data_describer_util_unittest.cc b/components/performance_manager/graph/node_data_describer_util_unittest.cc new file mode 100644 index 0000000..7339a2ae --- /dev/null +++ b/components/performance_manager/graph/node_data_describer_util_unittest.cc
@@ -0,0 +1,118 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/performance_manager/public/graph/node_data_describer_util.h" + +#include "base/json/json_reader.h" +#include "base/strings/string_piece.h" +#include "base/values.h" +#include "components/performance_manager/public/graph/node_data_describer.h" +#include "components/performance_manager/public/graph/node_data_describer_registry.h" +#include "components/performance_manager/test_support/graph_test_harness.h" +#include "components/performance_manager/test_support/mock_graphs.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace performance_manager { + +namespace { + +class TestNodeDataDescriber final : public NodeDataDescriber { + public: + base::Value::Dict DescribeFrameNodeData(const FrameNode*) const final { + return Describe("FrameNode"); + } + base::Value::Dict DescribePageNodeData(const PageNode*) const final { + return Describe("PageNode"); + } + base::Value::Dict DescribeProcessNodeData( + const ProcessNode* node) const final { + return Describe("ProcessNode"); + } + base::Value::Dict DescribeSystemNodeData(const SystemNode*) const final { + return Describe("SystemNode"); + } + base::Value::Dict DescribeWorkerNodeData(const WorkerNode*) const final { + return Describe("WorkerNode"); + } + + private: + base::Value::Dict Describe(base::StringPiece node_type) const { + base::Value::Dict description; + description.Set("node_type", node_type); + return description; + } +}; + +class NodeDataDescriberUtilTest : public GraphTestHarness { + protected: + void ExpectEmptyDict(base::StringPiece msg, base::StringPiece json) { + return ExpectDict(msg, json, true); + } + + void ExpectNonEmptyDict(base::StringPiece msg, base::StringPiece json) { + return ExpectDict(msg, json, false); + } + + private: + void ExpectDict(base::StringPiece msg, + base::StringPiece json, + bool expect_empty_dict) { + SCOPED_TRACE(::testing::Message() << msg << " " << json); + absl::optional<base::Value> parsed_json = base::JSONReader::Read(json); + ASSERT_TRUE(parsed_json.has_value()); + ASSERT_TRUE(parsed_json.value().is_dict()); + EXPECT_EQ(parsed_json.value().GetDict().empty(), expect_empty_dict); + } +}; + +TEST_F(NodeDataDescriberUtilTest, DumpNodeDescription) { + MockSinglePageWithFrameAndWorkerInSingleProcessGraph mock_graph(graph()); + + // Even though no describers are registered, these should all return + // dictionaries. + ExpectNonEmptyDict("Frame", DumpNodeDescription(mock_graph.frame.get())); + ExpectNonEmptyDict("Page", DumpNodeDescription(mock_graph.page.get())); + ExpectNonEmptyDict("Process", DumpNodeDescription(mock_graph.process.get())); + ExpectNonEmptyDict("Worker", DumpNodeDescription(mock_graph.worker.get())); + + // SystemNodeImpl has no default describer. + ExpectEmptyDict("System", DumpNodeDescription(mock_graph.system.get())); +} + +TEST_F(NodeDataDescriberUtilTest, EmptyDumpRegisteredDescribers) { + MockSinglePageWithFrameAndWorkerInSingleProcessGraph mock_graph(graph()); + + // With no describers registered, each call should return an empty + // dictionary. + ExpectEmptyDict("Frame", DumpRegisteredDescribers(mock_graph.frame.get())); + ExpectEmptyDict("Page", DumpRegisteredDescribers(mock_graph.page.get())); + ExpectEmptyDict("Process", + DumpRegisteredDescribers(mock_graph.process.get())); + ExpectEmptyDict("System", DumpRegisteredDescribers(mock_graph.system.get())); + ExpectEmptyDict("Worker", DumpRegisteredDescribers(mock_graph.worker.get())); +} + +TEST_F(NodeDataDescriberUtilTest, DumpRegisteredDescribers) { + MockSinglePageWithFrameAndWorkerInSingleProcessGraph mock_graph(graph()); + TestNodeDataDescriber test_describer; + graph()->GetNodeDataDescriberRegistry()->RegisterDescriber(&test_describer, + "TestDescriber"); + + // The registered describer should be called each time. + ExpectNonEmptyDict("Frame", DumpRegisteredDescribers(mock_graph.frame.get())); + ExpectNonEmptyDict("Page", DumpRegisteredDescribers(mock_graph.page.get())); + ExpectNonEmptyDict("Process", + DumpRegisteredDescribers(mock_graph.process.get())); + ExpectNonEmptyDict("System", + DumpRegisteredDescribers(mock_graph.system.get())); + ExpectNonEmptyDict("Worker", + DumpRegisteredDescribers(mock_graph.worker.get())); + + graph()->GetNodeDataDescriberRegistry()->UnregisterDescriber(&test_describer); +} + +} // namespace + +} // namespace performance_manager
diff --git a/components/performance_manager/public/graph/node_data_describer_util.cc b/components/performance_manager/public/graph/node_data_describer_util.cc deleted file mode 100644 index 89b086f..0000000 --- a/components/performance_manager/public/graph/node_data_describer_util.cc +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/performance_manager/public/graph/node_data_describer_util.h" - -#include "base/i18n/time_formatting.h" -#include "base/task/task_traits.h" - -namespace performance_manager { - -base::Value TimeDeltaFromNowToValue(base::TimeTicks time_ticks) { - base::TimeDelta delta = base::TimeTicks::Now() - time_ticks; - - std::u16string out; - bool succeeded = TimeDurationFormat(delta, base::DURATION_WIDTH_WIDE, &out); - DCHECK(succeeded); - - return base::Value(out); -} - -base::Value MaybeNullStringToValue(base::StringPiece str) { - if (str.data() == nullptr) - return base::Value(); - return base::Value(str); -} - -base::Value PriorityAndReasonToValue( - const execution_context_priority::PriorityAndReason& priority_and_reason) { - base::Value::Dict priority; - priority.Set("priority", - base::TaskPriorityToString(priority_and_reason.priority())); - priority.Set("reason", MaybeNullStringToValue(priority_and_reason.reason())); - return base::Value(std::move(priority)); -} - -} // namespace performance_manager
diff --git a/components/performance_manager/public/graph/node_data_describer_util.h b/components/performance_manager/public/graph/node_data_describer_util.h index fc5c519..1669da3 100644 --- a/components/performance_manager/public/graph/node_data_describer_util.h +++ b/components/performance_manager/public/graph/node_data_describer_util.h
@@ -15,6 +15,8 @@ namespace performance_manager { +class Node; + // Converts a Mojo enum to a human-readable string. template <typename T> std::string MojoEnumToString(T value) { @@ -35,6 +37,14 @@ base::Value PriorityAndReasonToValue( const execution_context_priority::PriorityAndReason& priority_and_reason); +// Returns `node`'s description as described by its primary data describer as +// a formatted string. +std::string DumpNodeDescription(const Node* node); + +// Returns the output of all registered data describers for `node` as a +// formatted string. +std::string DumpRegisteredDescribers(const Node* node); + } // namespace performance_manager #endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_NODE_DATA_DESCRIBER_UTIL_H_
diff --git a/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmAllowed.yaml b/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmAllowed.yaml index 0d754b4..a53d190 100644 --- a/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmAllowed.yaml +++ b/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmAllowed.yaml
@@ -14,8 +14,8 @@ - caption: Do not allow devices to use a PluginVm value: false owners: -- okalitova@chromium.org -- aoldemeier@chromium.org +- timloh@google.com +- parallels-cros@google.com schema: type: boolean supported_on:
diff --git a/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmDataCollectionAllowed.yaml b/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmDataCollectionAllowed.yaml index e5ebc68..a755b70 100644 --- a/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmDataCollectionAllowed.yaml +++ b/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmDataCollectionAllowed.yaml
@@ -14,8 +14,8 @@ - caption: Disable sharing diagnostics data to PluginVm value: false owners: -- okalitova@chromium.org -- janagrill@google.com +- timloh@google.com +- parallels-cros@google.com schema: type: boolean supported_on:
diff --git a/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmImage.yaml b/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmImage.yaml index c1eb0a1..f67d5d4 100644 --- a/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmImage.yaml +++ b/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmImage.yaml
@@ -10,8 +10,8 @@ dynamic_refresh: true per_profile: false owners: -- okalitova@chromium.org -- aoldemeier@chromium.org +- timloh@google.com +- parallels-cros@google.com schema: properties: hash:
diff --git a/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmLicenseKey.yaml b/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmLicenseKey.yaml index 8e4d3fd1..3d5bf464 100644 --- a/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmLicenseKey.yaml +++ b/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmLicenseKey.yaml
@@ -9,8 +9,8 @@ features: dynamic_refresh: true owners: -- okalitova@chromium.org -- aoldemeier@chromium.org +- timloh@google.com +- parallels-cros@google.com schema: sensitiveValue: true type: string
diff --git a/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmRequiredFreeDiskSpace.yaml b/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmRequiredFreeDiskSpace.yaml index c27cde9..28b04787 100644 --- a/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmRequiredFreeDiskSpace.yaml +++ b/components/policy/resources/templates/policy_definitions/PluginVm/PluginVmRequiredFreeDiskSpace.yaml
@@ -9,8 +9,8 @@ dynamic_refresh: true per_profile: false owners: -- okalitova@chromium.org -- janagrill@google.com +- timloh@google.com +- parallels-cros@google.com schema: maximum: 1000 minimum: 0
diff --git a/components/policy/resources/templates/policy_definitions/PluginVm/UserPluginVmAllowed.yaml b/components/policy/resources/templates/policy_definitions/PluginVm/UserPluginVmAllowed.yaml index 0c67a7b9..ce396fc 100644 --- a/components/policy/resources/templates/policy_definitions/PluginVm/UserPluginVmAllowed.yaml +++ b/components/policy/resources/templates/policy_definitions/PluginVm/UserPluginVmAllowed.yaml
@@ -16,8 +16,8 @@ - caption: Do not allow users to use a PluginVm value: false owners: -- okalitova@chromium.org -- janagrill@google.com +- timloh@google.com +- parallels-cros@google.com schema: type: boolean supported_on:
diff --git a/components/policy/resources/webui/policy_precedence_row.html b/components/policy/resources/webui/policy_precedence_row.html index ddc6ddc..d35c747 100644 --- a/components/policy/resources/webui/policy_precedence_row.html +++ b/components/policy/resources/webui/policy_precedence_row.html
@@ -68,6 +68,9 @@ display: block; flex: 1; } +.precedence.row .name { + white-space: pre-wrap; +} </if> </style> <div class="precedence row" role="row">
diff --git a/components/signin/public/base/signin_switches.cc b/components/signin/public/base/signin_switches.cc index cc3ab23..5195d10 100644 --- a/components/signin/public/base/signin_switches.cc +++ b/components/signin/public/base/signin_switches.cc
@@ -46,6 +46,15 @@ #endif // Enables a new version of the sync confirmation UI. -BASE_FEATURE(kTangibleSync, "TangibleSync", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kTangibleSync, + "TangibleSync", +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) + base::FEATURE_DISABLED_BY_DEFAULT +#else + // Fully rolled out on desktop: crbug.com/1430054 + base::FEATURE_ENABLED_BY_DEFAULT +#endif + +); } // namespace switches
diff --git a/content/browser/back_forward_cache_internal_browsertest.cc b/content/browser/back_forward_cache_internal_browsertest.cc index d16bf4f..2e7b99d 100644 --- a/content/browser/back_forward_cache_internal_browsertest.cc +++ b/content/browser/back_forward_cache_internal_browsertest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/types/expected.h" #include "content/browser/back_forward_cache_browsertest.h" #include "base/command_line.h" @@ -14,6 +15,7 @@ #include "build/build_config.h" #include "content/browser/accessibility/browser_accessibility.h" #include "content/browser/renderer_host/back_forward_cache_disable.h" +#include "content/browser/renderer_host/back_forward_cache_impl.h" #include "content/browser/renderer_host/navigation_request.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" @@ -415,8 +417,9 @@ EXPECT_TRUE(rfh_a->IsInBackForwardCache()); // Verify proxies are stored as well. - auto* cached_entry = cache.GetEntry(rfh_a->nav_entry_id()); - EXPECT_EQ(2u, cached_entry->proxy_hosts_size()); + auto cached_entry = cache.GetOrEvictEntry(rfh_a->nav_entry_id()); + EXPECT_TRUE(cached_entry.has_value()); + EXPECT_EQ(2u, cached_entry.value()->proxy_hosts_size()); // 3. Navigate from an uncacheable to a cached page page (B->A). ASSERT_TRUE(HistoryGoBack(web_contents())); @@ -453,8 +456,9 @@ EXPECT_TRUE(rfh_a->IsInBackForwardCache()); // Verify proxies are stored as well. - cached_entry = cache.GetEntry(rfh_a->nav_entry_id()); - EXPECT_EQ(2u, cached_entry->proxy_hosts_size()); + cached_entry = cache.GetOrEvictEntry(rfh_a->nav_entry_id()); + EXPECT_TRUE(cached_entry.has_value()); + EXPECT_EQ(2u, cached_entry.value()->proxy_hosts_size()); // 5. Navigate from a cacheable page to a cached page (C->A). ASSERT_TRUE(HistoryGoBack(web_contents())); @@ -472,8 +476,9 @@ EXPECT_TRUE(rfh_c->IsInBackForwardCache()); // Verify proxies are stored as well. - cached_entry = cache.GetEntry(rfh_c->nav_entry_id()); - EXPECT_EQ(3u, cached_entry->proxy_hosts_size()); + cached_entry = cache.GetOrEvictEntry(rfh_c->nav_entry_id()); + EXPECT_TRUE(cached_entry.has_value()); + EXPECT_EQ(3u, cached_entry.value()->proxy_hosts_size()); } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
diff --git a/content/browser/back_forward_cache_no_store_browsertest.cc b/content/browser/back_forward_cache_no_store_browsertest.cc index 1ebf241..cd24a7c 100644 --- a/content/browser/back_forward_cache_no_store_browsertest.cc +++ b/content/browser/back_forward_cache_no_store_browsertest.cc
@@ -1378,10 +1378,15 @@ // Test that a page with `Cache-control: no-store` header gets evicted without // crashes if some cookie is modified immediately before the back navigation. -// TODO(crbug.com/1429151): Re-enable after fixing the race condition. +// TODO: this test could be potentially flaky if the notification to +// CookieChangeListener is only received after the entire back navigation +// completes. If any flaky case is reported in the future, we should fix that by +// ensuring the eviction to happen after the NavigationRequest starts to process +// response but before it finishes committing the navigation. +// See discussion from https://crrev.com/c/4408607. IN_PROC_BROWSER_TEST_F( BackForwardCacheBrowserTestRestoreCacheControlNoStoreUnlessCookieChange, - DISABLED_PagesWithCacheControlNoStoreNotBFCachedWithCookieSetImmediatelyBeforeNavigateBack) { + PagesWithCacheControlNoStoreNotBFCachedWithCookieSetImmediatelyBeforeNavigateBack) { CreateHttpsServer(); net::test_server::ControllableHttpResponse response(https_server(), "/title1.html");
diff --git a/content/browser/preloading/prerender/prerender_host_registry.cc b/content/browser/preloading/prerender/prerender_host_registry.cc index 4e337c0..1a895db8 100644 --- a/content/browser/preloading/prerender/prerender_host_registry.cc +++ b/content/browser/preloading/prerender/prerender_host_registry.cc
@@ -899,7 +899,9 @@ CHECK(back_entry); const GURL& back_url = back_entry->GetURL(); - if (controller.GetBackForwardCache().GetEntry(back_entry->GetUniqueID())) { + if (controller.GetBackForwardCache() + .GetOrEvictEntry(back_entry->GetUniqueID()) + .has_value()) { RecordPrerenderBackNavigationEligibility( predictor, PrerenderBackNavigationEligibility::kBfcacheEntryExists, nullptr);
diff --git a/content/browser/renderer_host/back_forward_cache_commit_deferring_condition.cc b/content/browser/renderer_host/back_forward_cache_commit_deferring_condition.cc index d60579b6..86802cc 100644 --- a/content/browser/renderer_host/back_forward_cache_commit_deferring_condition.cc +++ b/content/browser/renderer_host/back_forward_cache_commit_deferring_condition.cc
@@ -49,12 +49,18 @@ // If an entry doesn't exist (it was evicted?) there's no need to defer the // commit as we'll end up performing a new navigation. - BackForwardCacheImpl::Entry* bfcache_entry = bfcache.GetEntry( + auto bfcache_entry = bfcache.GetOrEvictEntry( NavigationRequest::From(&GetNavigationHandle())->nav_entry_id()); - if (!bfcache_entry) + // TODO(crbug.com/1430653): Check the + // `BackForwardCacheImpl::GetEntryFailureCase` in the return value and cancel + // the NavigationRequest to avoid use-after-free if we know that it will be + // restarted. + if (!bfcache_entry.has_value()) { return Result::kProceed; + } - bfcache.WillCommitNavigationToCachedEntry(*bfcache_entry, std::move(resume)); + bfcache.WillCommitNavigationToCachedEntry(*(bfcache_entry.value()), + std::move(resume)); return Result::kDefer; }
diff --git a/content/browser/renderer_host/back_forward_cache_impl.cc b/content/browser/renderer_host/back_forward_cache_impl.cc index 4e179bf..735b299 100644 --- a/content/browser/renderer_host/back_forward_cache_impl.cc +++ b/content/browser/renderer_host/back_forward_cache_impl.cc
@@ -18,6 +18,7 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/trace_event/typed_macros.h" +#include "base/types/expected.h" #include "build/build_config.h" #include "content/browser/bad_message.h" #include "content/browser/renderer_host/back_forward_cache_can_store_document_result.h" @@ -1251,17 +1252,26 @@ return entries_for_rvhi; } -BackForwardCacheImpl::Entry* BackForwardCacheImpl::GetEntry( - int navigation_entry_id) { +base::expected<BackForwardCacheImpl::Entry*, + BackForwardCacheImpl::GetEntryFailureCase> +BackForwardCacheImpl::GetOrEvictEntry(int navigation_entry_id) { auto matching_entry = base::ranges::find( entries_, navigation_entry_id, [](std::unique_ptr<Entry>& entry) { return entry->render_frame_host()->nav_entry_id(); }); - if (matching_entry == entries_.end()) - return nullptr; + if (matching_entry == entries_.end()) { + return base::unexpected( + BackForwardCacheImpl::GetEntryFailureCase::kEntryNotFound); + } auto* render_frame_host = (*matching_entry)->render_frame_host(); + // Don't return the entry if it was evicted. + if (render_frame_host->is_evicted_from_back_forward_cache()) { + return base::unexpected( + BackForwardCacheImpl::GetEntryFailureCase::kEntryEvictedBefore); + } + // If we are in the experiments to allow pages with cache-control:no-store // in back/forward cache and the page has cache-control:no-store, we should // record them as reasons. It might not be possible to restore the entry even @@ -1272,12 +1282,10 @@ if (!bfcache_eligibility.CanRestore()) { render_frame_host->EvictFromBackForwardCacheWithFlattenedAndTreeReasons( bfcache_eligibility); + return base::unexpected( + BackForwardCacheImpl::GetEntryFailureCase::kEntryIneligibleAndEvicted); } - // Don't return the frame if it is evicted. - if (render_frame_host->is_evicted_from_back_forward_cache()) - return nullptr; - return (*matching_entry).get(); }
diff --git a/content/browser/renderer_host/back_forward_cache_impl.h b/content/browser/renderer_host/back_forward_cache_impl.h index 493f5c4..73511d5 100644 --- a/content/browser/renderer_host/back_forward_cache_impl.h +++ b/content/browser/renderer_host/back_forward_cache_impl.h
@@ -18,6 +18,7 @@ #include "base/memory/weak_ptr.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" +#include "base/types/expected.h" #include "content/browser/renderer_host/back_forward_cache_can_store_document_result.h" #include "content/browser/renderer_host/back_forward_cache_metrics.h" #include "content/browser/renderer_host/page_impl.h" @@ -276,15 +277,38 @@ // those events are depends on the cache limit policy. void EnforceCacheSizeLimit(); + enum GetEntryFailureCase { + // No matched BFCache entry is found. + kEntryNotFound, + // BFCache entry is found, but it was evicted before the `GetOrEvictEntry()` + // call. + kEntryEvictedBefore, + // BFCache entry is found and not evicted, but it's no longer eligible for + // BFCache, and gets evicted in the `GetOrEvictEntry()` call. + kEntryIneligibleAndEvicted, + }; + // Returns a pointer to a cached BackForwardCache entry matching - // |navigation_entry_id| if it exists in the BackForwardCache. Returns nullptr - // if no matching entry is found. - // + // `navigation_entry_id`. + // Returns nullptr if no matching entry is found or if the entry is evicted. + // If the returned entry is null, this method will also return a + // `BackForwardCacheImpl::GetEntryResult`, which contains information about + // whether it's because a matching entry was found or the entry was evicted. + // Note: The returned pointer should be used temporarily only within the // execution of a single task on the event loop. Beyond that, there is no // guarantee the pointer will be valid, because the document may be // removed/evicted from the cache. - Entry* GetEntry(int navigation_entry_id); + + // WARNING: Calling this method may result in the eviction of the BFCache + // entry if it is no longer eligible for the BFCache but has not been evicted + // yet. If the eviction is triggered while there is an ongoing BFCache + // restore, the caller must discard the NavigationRequest that is about to + // commit the restore, otherwise the NavigationRequest may try to access the + // RenderFrameHost after it has been deleted. + base::expected<BackForwardCacheImpl::Entry*, + BackForwardCacheImpl::GetEntryFailureCase> + GetOrEvictEntry(int navigation_entry_id); // During a history navigation, moves an entry out of the BackForwardCache // knowing its |navigation_entry_id|. |page_restore_params| includes
diff --git a/content/browser/renderer_host/isolated_web_app_throttle.cc b/content/browser/renderer_host/isolated_web_app_throttle.cc index 4cf680e..75d7791 100644 --- a/content/browser/renderer_host/isolated_web_app_throttle.cc +++ b/content/browser/renderer_host/isolated_web_app_throttle.cc
@@ -230,17 +230,28 @@ return block_action; } - // Block iframe navigations to the app's origin if the parent frame doesn't - // belong to the app. This prevents non-app frames from having access to an - // app frame. if (!navigation_handle()->IsInMainFrame()) { - const url::SchemeHostPort& parent_tuple = - navigation_handle() - ->GetParentFrame() - ->GetLastCommittedOrigin() - .GetTupleOrPrecursorTupleIfOpaque(); - if (parent_tuple != web_contents_isolation_tuple) { - return block_action; + { + // Block iframe navigations to the app's origin if the parent frame + // doesn't belong to the app. This prevents non-app frames from having + // access to an app frame. + const url::SchemeHostPort& parent_tuple = + navigation_handle() + ->GetParentFrame() + ->GetLastCommittedOrigin() + .GetTupleOrPrecursorTupleIfOpaque(); + if (parent_tuple != web_contents_isolation_tuple) { + return block_action; + } + } + + // Allow iframe same-origin navigations to blob: and data: URLs + // (cross-origin iframe navigation are already allowed and handled further + // up as part of the `dest_tuple != web_contents_isolation_tuple` + // condition). + if (navigation_handle()->GetURL().SchemeIs(url::kDataScheme) || + navigation_handle()->GetURL().SchemeIsBlob()) { + return NavigationThrottle::PROCEED; } }
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc index 7f1e3a3..daf495b 100644 --- a/content/browser/renderer_host/navigation_controller_impl.cc +++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -3205,7 +3205,7 @@ // BackForwardCache: // Navigate immediately if the document is in the BackForwardCache. - if (back_forward_cache_.GetEntry(nav_entry_id)) { + if (back_forward_cache_.GetOrEvictEntry(nav_entry_id).has_value()) { TRACE_EVENT0("navigation", "BackForwardCache_CreateNavigationRequest"); DCHECK_EQ(reload_type, ReloadType::NONE); auto navigation_request = CreateNavigationRequestFromEntry(
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index 76a84e4..6ed6d986 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc
@@ -228,7 +228,7 @@ "base-uri 'none';" "default-src 'self';" "object-src 'none';" - "frame-src 'self' https:;" + "frame-src 'self' https: blob: data:;" "connect-src 'self' https:;" "script-src 'self' 'wasm-unsafe-eval';" "img-src 'self' https: blob: data:;" @@ -1229,15 +1229,18 @@ base::WeakPtr<RenderFrameHostImpl> rfh_restored_from_back_forward_cache = nullptr; if (entry) { - BackForwardCacheImpl::Entry* restored_entry = - frame_tree_node->navigator() - .controller() - .GetBackForwardCache() - .GetEntry(entry->GetUniqueID()); - if (restored_entry) { + auto restored_entry = frame_tree_node->navigator() + .controller() + .GetBackForwardCache() + .GetOrEvictEntry(entry->GetUniqueID()); + // TODO(crbug.com/1430653): Check the + // `BackForwardCacheImpl::GetEntryFailureCase` in the return value and + // cancel the NavigationRequest to avoid use-after-free if we know that it + // will be restarted. + if (restored_entry.has_value()) { if (frame_tree_node->IsMainFrame()) { rfh_restored_from_back_forward_cache = - restored_entry->render_frame_host()->GetWeakPtr(); + restored_entry.value()->render_frame_host()->GetWeakPtr(); } else { // We have a matching BFCache entry for a subframe navigation. This // shouldn't happen as we should've triggered deletion of BFCache @@ -2167,22 +2170,25 @@ } if (IsServedFromBackForwardCache()) { - BackForwardCacheImpl::Entry* bfcache_entry = - GetNavigationController()->GetBackForwardCache().GetEntry( + auto bfcache_entry = + GetNavigationController()->GetBackForwardCache().GetOrEvictEntry( nav_entry_id()); - if (!bfcache_entry) - return; - - RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID( - bfcache_entry->render_frame_host()->GetGlobalId()); - // RFH could have been deleted. E.g. eviction timer fired - if (rfh && rfh->IsInBackForwardCache()) { - // rfh is still in the cache so the navigation must have failed. But we - // have already disabled eviction so the safest thing to do here to - // recover is to evict. - rfh->EvictFromBackForwardCacheWithReason( - BackForwardCacheMetrics::NotRestoredReason:: - kNavigationCancelledWhileRestoring); + // TODO(crbug.com/1430653): Check the + // `BackForwardCacheImpl::GetEntryFailureCase` in the return value and + // cancel the NavigationRequest to avoid use-after-free if we know that it + // will be restarted. + if (bfcache_entry.has_value()) { + RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID( + bfcache_entry.value()->render_frame_host()->GetGlobalId()); + // RFH could have been deleted. E.g. eviction timer fired + if (rfh && rfh->IsInBackForwardCache()) { + // rfh is still in the cache so the navigation must have failed. But + // we have already disabled eviction so the safest thing to do here to + // recover is to evict. + rfh->EvictFromBackForwardCacheWithReason( + BackForwardCacheMetrics::NotRestoredReason:: + kNavigationCancelledWhileRestoring); + } } } } @@ -4185,18 +4191,25 @@ // If the current navigation is being restarted, it should not try to make // any further progress. CHECK(!restarting_back_forward_cached_navigation_); - if (!rfh_restored_from_back_forward_cache_) { - // The RenderFrameHost to restore has been evicted and deleted. We should - // stop processing this back/forward cache restore navigation, as the - // navigation will soon be restarted as a normal history navigation. + NavigationControllerImpl* controller = GetNavigationController(); + auto entry = + controller->GetBackForwardCache().GetOrEvictEntry(nav_entry_id_); + if (!rfh_restored_from_back_forward_cache_ || + (!entry.has_value() && + entry.error() == BackForwardCacheImpl::kEntryIneligibleAndEvicted)) { + // If the RenderFrameHost to restore has been evicted and deleted, or the + // current navigation is being restarted due to the `GetOrEvictEntry` + // call, we should stop processing this back/forward cache restore + // navigation, as the navigation will soon be restarted as a normal + // history navigation. + + // TODO(crbug.com/1430653): Cancel the NavigationRequest to avoid + // use-after-free if we know that it will be restarted. return; } - NavigationControllerImpl* controller = GetNavigationController(); - BackForwardCacheImpl::Entry* entry = - controller->GetBackForwardCache().GetEntry(nav_entry_id_); - CHECK(entry); - CHECK(entry->render_frame_host()); - render_frame_host_ = entry->render_frame_host()->GetSafeRef(); + CHECK(entry.has_value() && entry.value()); + CHECK(entry.value()->render_frame_host()); + render_frame_host_ = entry.value()->render_frame_host()->GetSafeRef(); } else if (IsPrerenderedPageActivation()) { // Prerendering requires changing pages starting at the root node. DCHECK(IsInMainFrame());
diff --git a/content/browser/renderer_host/navigation_request_unittest.cc b/content/browser/renderer_host/navigation_request_unittest.cc index 07deaa3b..91cd7cfd 100644 --- a/content/browser/renderer_host/navigation_request_unittest.cc +++ b/content/browser/renderer_host/navigation_request_unittest.cc
@@ -915,7 +915,8 @@ EXPECT_EQ("'none'", csp->raw_directives[Directive::BaseURI]); EXPECT_EQ("'none'", csp->raw_directives[Directive::ObjectSrc]); EXPECT_EQ("'self'", csp->raw_directives[Directive::DefaultSrc]); - EXPECT_EQ("'self' https:", csp->raw_directives[Directive::FrameSrc]); + EXPECT_EQ("'self' https: blob: data:", + csp->raw_directives[Directive::FrameSrc]); EXPECT_EQ("'self' https:", csp->raw_directives[Directive::ConnectSrc]); EXPECT_EQ("'self' 'wasm-unsafe-eval'", csp->raw_directives[Directive::ScriptSrc]);
diff --git a/content/common/common_param_traits_unittest.cc b/content/common/common_param_traits_unittest.cc index 0dea6853..e75ea1a 100644 --- a/content/common/common_param_traits_unittest.cc +++ b/content/common/common_param_traits_unittest.cc
@@ -120,20 +120,6 @@ EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output)); } -// Tests net::HostPortPair serialization -TEST(IPCMessageTest, HostPortPair) { - net::HostPortPair input("host.com", 12345); - - IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); - IPC::ParamTraits<net::HostPortPair>::Write(&msg, input); - - net::HostPortPair output; - base::PickleIterator iter(msg); - EXPECT_TRUE(IPC::ParamTraits<net::HostPortPair>::Read(&msg, &iter, &output)); - EXPECT_EQ(input.host(), output.host()); - EXPECT_EQ(input.port(), output.port()); -} - // Tests net::SSLInfo serialization TEST(IPCMessageTest, SSLInfo) { // Build a SSLInfo. Avoid false for booleans as that's the default value.
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index 910a2fc..b76e4927 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -212,6 +212,8 @@ if (is_ios) { sources += [ + "browser/bluetooth/shell_bluetooth_delegate_impl_client.cc", + "browser/bluetooth/shell_bluetooth_delegate_impl_client.h", "browser/shell_file_select_helper.cc", "browser/shell_file_select_helper.h", "browser/shell_platform_delegate_ios.mm", @@ -359,6 +361,7 @@ if (is_ios) { deps += [ + "//components/permissions", "//services/tracing/public/cpp", "//services/tracing/public/mojom:mojom", "//ui/shell_dialogs",
diff --git a/content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.cc b/content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.cc new file mode 100644 index 0000000..00716ddb --- /dev/null +++ b/content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.cc
@@ -0,0 +1,47 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.h" + +#include "content/public/browser/render_frame_host.h" + +namespace content { + +ShellBluetoothDelegateImplClient::ShellBluetoothDelegateImplClient() = default; + +ShellBluetoothDelegateImplClient::~ShellBluetoothDelegateImplClient() = default; + +permissions::BluetoothChooserContext* +ShellBluetoothDelegateImplClient::GetBluetoothChooserContext( + RenderFrameHost* frame) { + // TODO(crbug.com/1431447): Implement ShellBluetoothChooserContextFactory. + return nullptr; +} + +std::unique_ptr<content::BluetoothChooser> +ShellBluetoothDelegateImplClient::RunBluetoothChooser( + RenderFrameHost* frame, + const BluetoothChooser::EventHandler& event_handler) { + // TODO(crbug.com/1431447): Implement BluetoothChooser for iOS. + return nullptr; +} + +std::unique_ptr<BluetoothScanningPrompt> +ShellBluetoothDelegateImplClient::ShowBluetoothScanningPrompt( + RenderFrameHost* frame, + const BluetoothScanningPrompt::EventHandler& event_handler) { + // TODO(crbug.com/1431447): Implement BluetoothScanningPrompt for iOS. + return nullptr; +} + +void ShellBluetoothDelegateImplClient::ShowBluetoothDevicePairDialog( + RenderFrameHost* frame, + const std::u16string& device_identifier, + BluetoothDelegate::PairPromptCallback callback, + BluetoothDelegate::PairingKind, + const absl::optional<std::u16string>& pin) { + std::move(callback).Run(BluetoothDelegate::PairPromptResult( + BluetoothDelegate::PairPromptStatus::kCancelled)); +} +} // namespace content
diff --git a/content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.h b/content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.h new file mode 100644 index 0000000..6b753c0 --- /dev/null +++ b/content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.h
@@ -0,0 +1,51 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_SHELL_BROWSER_BLUETOOTH_SHELL_BLUETOOTH_DELEGATE_IMPL_CLIENT_H_ +#define CONTENT_SHELL_BROWSER_BLUETOOTH_SHELL_BLUETOOTH_DELEGATE_IMPL_CLIENT_H_ + +#include <memory> + +#include "components/permissions/bluetooth_delegate_impl.h" + +namespace permissions { +class BluetoothChooserContext; +class BluetoothChooser; +} // namespace permissions + +namespace content { + +class RenderFrameHost; + +class ShellBluetoothDelegateImplClient + : public permissions::BluetoothDelegateImpl::Client { + public: + ShellBluetoothDelegateImplClient(); + ~ShellBluetoothDelegateImplClient() override; + + ShellBluetoothDelegateImplClient(const ShellBluetoothDelegateImplClient&) = + delete; + ShellBluetoothDelegateImplClient& operator=( + const ShellBluetoothDelegateImplClient&) = delete; + + // BluetoothDelegateImpl::Client: + permissions::BluetoothChooserContext* GetBluetoothChooserContext( + RenderFrameHost* frame) override; + std::unique_ptr<BluetoothChooser> RunBluetoothChooser( + RenderFrameHost* frame, + const BluetoothChooser::EventHandler& event_handler) override; + std::unique_ptr<BluetoothScanningPrompt> ShowBluetoothScanningPrompt( + RenderFrameHost* frame, + const BluetoothScanningPrompt::EventHandler& event_handler) override; + + void ShowBluetoothDevicePairDialog( + RenderFrameHost* frame, + const std::u16string& device_identifier, + BluetoothDelegate::PairPromptCallback callback, + BluetoothDelegate::PairingKind pairing_kind, + const absl::optional<std::u16string>& pin) override; +}; + +} // namespace content +#endif // CONTENT_SHELL_BROWSER_BLUETOOTH_SHELL_BLUETOOTH_DELEGATE_IMPL_CLIENT_H_
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc index e3f3e84..6feb11a7 100644 --- a/content/shell/browser/shell_content_browser_client.cc +++ b/content/shell/browser/shell_content_browser_client.cc
@@ -120,6 +120,11 @@ #include "services/network/public/mojom/ct_log_info.mojom.h" #endif +#if BUILDFLAG(IS_IOS) +#include "components/permissions/bluetooth_delegate_impl.h" +#include "content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.h" +#endif + namespace content { namespace { @@ -681,6 +686,16 @@ return {browser_context()->GetPath()}; } +#if BUILDFLAG(IS_IOS) +BluetoothDelegate* ShellContentBrowserClient::GetBluetoothDelegate() { + if (!bluetooth_delegate_) { + bluetooth_delegate_ = std::make_unique<permissions::BluetoothDelegateImpl>( + std::make_unique<ShellBluetoothDelegateImplClient>()); + } + return bluetooth_delegate_.get(); +} +#endif + void ShellContentBrowserClient::BindBrowserControlInterface( mojo::ScopedMessagePipeHandle pipe) { if (!pipe.is_valid())
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h index 958a6597..8715ce5 100644 --- a/content/shell/browser/shell_content_browser_client.h +++ b/content/shell/browser/shell_content_browser_client.h
@@ -18,6 +18,12 @@ class PrefService; +#if BUILDFLAG(IS_IOS) +namespace permissions { +class BluetoothDelegateImpl; +} +#endif + namespace content { class ShellBrowserContext; class ShellBrowserMainParts; @@ -134,6 +140,9 @@ cert_verifier::mojom::CertVerifierCreationParams* cert_verifier_creation_params) override; std::vector<base::FilePath> GetNetworkContextsParentDirectory() override; +#if BUILDFLAG(IS_IOS) + BluetoothDelegate* GetBluetoothDelegate() override; +#endif void BindBrowserControlInterface(mojo::ScopedMessagePipeHandle pipe) override; void GetHyphenationDictionary( base::OnceCallback<void(const base::FilePath&)>) override; @@ -228,6 +237,9 @@ create_throttles_for_navigation_callback_; base::RepeatingCallback<void(blink::web_pref::WebPreferences*)> override_web_preferences_callback_; +#if BUILDFLAG(IS_IOS) + std::unique_ptr<permissions::BluetoothDelegateImpl> bluetooth_delegate_; +#endif // NOTE: Tests may install a second ShellContentBrowserClient that becomes // the ContentBrowserClient used by content. This has subtle implications
diff --git a/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt index 147af324..d7d4730b 100644 --- a/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/maps_expectations.txt
@@ -86,7 +86,7 @@ # Non-"Skip" expectations go here to suppress regular flakes/failures. # Flaking frequently on Fuchsia and nobody has triaged why. -crbug.com/1288217 [ fuchsia ] Maps_maps [ Failure ] +crbug.com/1288217 [ angle-swiftshader fuchsia fuchsia-board-qemu-x64 google-0xc0de ] Maps_maps [ Failure ] ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index 8e515f4..87fd7c2 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -480,7 +480,6 @@ crbug.com/772651 [ mac nvidia ] conformance/glsl/bugs/vector-scalar-arithmetic-inside-loop-complex.html [ Failure ] crbug.com/795052 [ mac nvidia-0xfe9 ] conformance2/uniforms/draw-with-uniform-blocks.html [ Failure ] crbug.com/1037650 [ mac nvidia-0xfe9 ] conformance2/textures/canvas_sub_rectangle/* [ RetryOnFailure ] -crbug.com/1416275 [ mac nvidia-0xfe9 ] deqp/functional/gles3/occlusionquery_strict.html [ Failure ] crbug.com/1338004 [ mac nvidia-0xfe9 passthrough ] deqp/functional/gles3/multisample/fbo_4_samples.html [ RetryOnFailure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index 77c8830..8969c970 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -549,16 +549,15 @@ # Was too difficult to suppress these failures on individual bots. crbug.com/1165751 [ android-nougat ] conformance/glsl/bugs/vector-matrix-constructor-scalarization.html [ Failure ] -# These video tests appear to be flaky. -crbug.com/834933 [ android-chromium android-s android-sm-a235m angle-disabled no-passthrough qualcomm renderer-skia-gl target-cpu-32 ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ RetryOnFailure ] # These video tests are flakey on many configurations. crbug.com/1347077 [ android-nexus-5x android-nougat angle-opengles passthrough qualcomm renderer-skia-gl target-cpu-64 ] conformance/textures/misc/video-rotation.html [ Failure ] crbug.com/1347077 [ android-s android-sm-a235m angle-disabled no-passthrough qualcomm renderer-skia-gl target-cpu-32 ] conformance/textures/misc/video-rotation.html [ Failure ] # finder:group-start crbug.com/1426535 Flaky DCHECK on Pixel 4 and 6 -crbug.com/1426535 [ android ] conformance/state/gl-enable-enum-test.html [ RetryOnFailure ] -crbug.com/1426535 [ android ] conformance/state/gl-get-calls.html [ RetryOnFailure ] +crbug.com/1426535 [ android-pixel-4 android-r angle-opengles no-clang-coverage passthrough qualcomm renderer-skia-gl target-cpu-32 ] conformance/state/gl-enable-enum-test.html [ RetryOnFailure ] +crbug.com/1426535 [ android-pixel-4 android-r angle-opengles no-clang-coverage passthrough qualcomm renderer-skia-gl target-cpu-32 ] conformance/state/gl-get-calls.html [ RetryOnFailure ] +crbug.com/1426535 [ android-pixel-6 android-t angle-opengles arm no-clang-coverage passthrough renderer-skia-vulkan target-cpu-64 ] conformance/state/gl-get-calls.html [ RetryOnFailure ] crbug.com/1426535 [ android ] conformance/state/gl-initial-state.html [ RetryOnFailure ] # finder:group-end @@ -585,17 +584,6 @@ crbug.com/1175223 [ android android-pixel-4 angle-opengles passthrough ] conformance/extensions/angle-instanced-arrays-out-of-bounds.html [ Failure ] crbug.com/1175226 [ android android-pixel-4 no-passthrough ] conformance/rendering/blending.html [ Failure ] -# finder:group-start crbug.com/1382796 failures happen in many tests, so can be classified as stale for one specific test -# finder:disable-narrowing -crbug.com/1382796 [ android android-pixel-4 ] conformance/canvas/rapid-resizing.html [ RetryOnFailure ] -crbug.com/1382796 [ android android-pixel-4 ] conformance/canvas/to-data-url-test.html [ RetryOnFailure ] -crbug.com/1382796 [ android android-pixel-4 ] conformance/context/context-release-with-workers.html [ RetryOnFailure ] -crbug.com/1382796 [ android android-pixel-4 ] conformance/ogles/GL/biConstants/biConstants_001_to_008.html [ RetryOnFailure ] -crbug.com/1382796 [ android android-pixel-4 ] conformance/textures/misc/texture-corner-case-videos.html [ RetryOnFailure ] -crbug.com/1382796 [ android android-pixel-4 ] conformance/textures/image_bitmap_from_video/* [ RetryOnFailure ] -crbug.com/1382796 [ android android-pixel-4 ] conformance/textures/video/* [ RetryOnFailure ] -# finder:enable-narrowing -# finder:group-end ## Pixel 6 ## @@ -693,13 +681,9 @@ crbug.com/angleproject/5038 [ chromeos no-passthrough ] conformance/extensions/ext-color-buffer-half-float.html [ Failure ] ## Arm-based issues. ## -crbug.com/957807 [ chromeos chromeos-board-kevin ] conformance/rendering/clipping-wide-points.html [ Failure ] crbug.com/957807 [ chromeos chromeos-board-kevin ] deqp/data/gles2/shaders/conversions* [ Failure ] crbug.com/957807 [ chromeos chromeos-board-kevin ] deqp/data/gles2/shaders/swizzles* [ Failure ] -# There is a crash, likely in this test, causing the root partition to become -# read-only. -crbug.com/1043953 [ chromeos chromeos-board-kevin ] conformance/textures/misc/texture-size-limit.html [ RetryOnFailure ] crbug.com/1080400 [ chromeos chromeos-board-kevin ] WebglExtension_EXT_color_buffer_half_float [ Failure ] crbug.com/1080356 [ chromeos chromeos-board-kevin ] WebglExtension_EXT_frag_depth [ Failure ] @@ -713,7 +697,6 @@ crbug.com/1080380 [ chromeos chromeos-board-kevin ] conformance/offscreencanvas/context-lost-restored.html [ Failure ] crbug.com/1108368 [ chromeos chromeos-board-kevin ] conformance/misc/shader-precision-format.html [ Failure ] crbug.com/1357064 [ chromeos chromeos-board-kevin no-passthrough ] conformance/rendering/blending.html [ Failure ] -crbug.com/1374285 [ chromeos chromeos-board-kevin no-passthrough ] conformance/ogles/GL/default/default_001_to_001.html [ Failure ] crbug.com/1374285 [ chromeos chromeos-board-kevin no-passthrough ] conformance/ogles/GL/mix/mix_001_to_006.html [ Failure ] ## VM Issues ##
diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing.cc b/gpu/command_buffer/service/shared_image/d3d_image_backing.cc index 4e85fce..f3d6bbc9 100644 --- a/gpu/command_buffer/service/shared_image/d3d_image_backing.cc +++ b/gpu/command_buffer/service/shared_image/d3d_image_backing.cc
@@ -10,7 +10,6 @@ #include "base/functional/callback_helpers.h" #include "base/memory/ptr_util.h" #include "base/memory/raw_ptr.h" -#include "components/viz/common/resources/resource_sizes.h" #include "gpu/command_buffer/common/shared_image_trace_utils.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/command_buffer/service/dxgi_shared_handle_manager.h" @@ -68,29 +67,31 @@ viz::SharedImageFormat PlaneFormat(DXGI_FORMAT dxgi_format, size_t plane) { DCHECK_LT(plane, NumPlanes(dxgi_format)); - viz::ResourceFormat format; + viz::SharedImageFormat format; switch (dxgi_format) { case DXGI_FORMAT_NV12: // Y plane is accessed as R8 and UV plane is accessed as RG88 in D3D. - format = plane == 0 ? viz::RED_8 : viz::RG_88; + format = plane == 0 ? viz::SinglePlaneFormat::kR_8 + : viz::SinglePlaneFormat::kRG_88; break; case DXGI_FORMAT_P010: - format = plane == 0 ? viz::R16_EXT : viz::RG16_EXT; + format = plane == 0 ? viz::SinglePlaneFormat::kR_16 + : viz::SinglePlaneFormat::kRG_1616; break; case DXGI_FORMAT_B8G8R8A8_UNORM: - format = viz::BGRA_8888; + format = viz::SinglePlaneFormat::kBGRA_8888; break; case DXGI_FORMAT_R10G10B10A2_UNORM: - format = viz::RGBA_1010102; + format = viz::SinglePlaneFormat::kRGBA_1010102; break; case DXGI_FORMAT_R16G16B16A16_FLOAT: - format = viz::RGBA_F16; + format = viz::SinglePlaneFormat::kRGBA_F16; break; default: NOTREACHED(); - format = viz::BGRA_8888; + format = viz::SinglePlaneFormat::kBGRA_8888; } - return viz::SharedImageFormat::SinglePlane(format); + return format; } WGPUTextureFormat DXGIToWGPUFormat(DXGI_FORMAT dxgi_format) { @@ -341,7 +342,7 @@ std::unique_ptr<D3DImageBacking> D3DImageBacking::CreateFromGLTexture( const Mailbox& mailbox, - viz::ResourceFormat format, + viz::SharedImageFormat format, const gfx::Size& size, const gfx::ColorSpace& color_space, GrSurfaceOrigin surface_origin, @@ -356,9 +357,8 @@ base::PassKey<D3DImageBacking>(), std::move(gl_texture), gl::ScopedEGLImage()); return base::WrapUnique(new D3DImageBacking( - mailbox, viz::SharedImageFormat::SinglePlane(format), size, color_space, - surface_origin, alpha_type, usage, std::move(d3d11_texture), - {std::move(gl_texture_holder)}, + mailbox, format, size, color_space, surface_origin, alpha_type, usage, + std::move(d3d11_texture), {std::move(gl_texture_holder)}, /*dxgi_shared_handle_state=*/nullptr, texture_target, array_slice)); }
diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing.h b/gpu/command_buffer/service/shared_image/d3d_image_backing.h index 3c393ce..bfddc2d 100644 --- a/gpu/command_buffer/service/shared_image/d3d_image_backing.h +++ b/gpu/command_buffer/service/shared_image/d3d_image_backing.h
@@ -13,7 +13,7 @@ #include "base/containers/flat_map.h" #include "base/memory/scoped_refptr.h" #include "base/types/pass_key.h" -#include "components/viz/common/resources/resource_format.h" +#include "components/viz/common/resources/shared_image_format.h" #include "gpu/command_buffer/service/dxgi_shared_handle_manager.h" #include "gpu/command_buffer/service/memory_tracking.h" #include "gpu/command_buffer/service/shared_context_state.h" @@ -82,7 +82,7 @@ // TODO(sunnyps): Remove this after migrating DXVA decoder to EGLImage. static std::unique_ptr<D3DImageBacking> CreateFromGLTexture( const Mailbox& mailbox, - viz::ResourceFormat format, + viz::SharedImageFormat format, const gfx::Size& size, const gfx::ColorSpace& color_space, GrSurfaceOrigin surface_origin,
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 5259124..1c9f65b 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -28820,6 +28820,128 @@ description_html: "This builder measures Android build performance with and without remote caches.<br/>The build configs and the bot specs should be in sync with <a href=\"https://ci.chromium.org/p/chromium/builders/try/android-pie-arm64-rel-compilator\">android-pie-arm64-rel-compilator</a>." } builders { + name: "build-perf-android-siso" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builder:build-perf-android-siso" + dimensions: "cores:32" + dimensions: "cpu:x86-64" + dimensions: "os:Ubuntu-18.04" + dimensions: "pool:luci.chromium.ci" + dimensions: "ssd:1" + exe { + cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" + cipd_version: "refs/heads/main" + cmd: "luciexe" + } + properties: + '{' + ' "$build/chromium_tests_builder_config": {' + ' "builder_config": {' + ' "builder_db": {' + ' "entries": [' + ' {' + ' "builder_id": {' + ' "bucket": "ci",' + ' "builder": "build-perf-android-siso",' + ' "project": "chromium"' + ' },' + ' "builder_spec": {' + ' "builder_group": "chromium.fyi",' + ' "execution_mode": "COMPILE_AND_TEST",' + ' "legacy_android_config": {' + ' "config": "main_builder"' + ' },' + ' "legacy_chromium_config": {' + ' "apply_configs": [' + ' "mb"' + ' ],' + ' "build_config": "Release",' + ' "config": "android",' + ' "target_bits": 64,' + ' "target_platform": "android"' + ' },' + ' "legacy_gclient_config": {' + ' "apply_configs": [' + ' "android",' + ' "chromium_no_telemetry_dependencies"' + ' ],' + ' "config": "chromium"' + ' }' + ' }' + ' }' + ' ]' + ' },' + ' "builder_ids": [' + ' {' + ' "bucket": "ci",' + ' "builder": "build-perf-android-siso",' + ' "project": "chromium"' + ' }' + ' ]' + ' }' + ' },' + ' "$build/reclient": {' + ' "instance": "rbe-chromium-untrusted",' + ' "jobs": 300,' + ' "metrics_project": "chromium-reclient-metrics"' + ' },' + ' "$recipe_engine/resultdb/test_presentation": {' + ' "column_keys": [],' + ' "grouping_keys": [' + ' "status",' + ' "v.test_suite"' + ' ]' + ' },' + ' "builder_group": "chromium.fyi",' + ' "recipe": "build_perf_siso"' + '}' + priority: 35 + execution_timeout_secs: 36000 + build_numbers: YES + service_account: "chromium-build-perf-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium_swarming.expose_merge_script_failures" + value: 100 + } + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "ci_test_results" + test_results {} + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "gpu_ci_test_results" + test_results { + predicate { + test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+" + } + } + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "blink_web_tests_ci_test_results" + test_results { + predicate { + test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + description_html: "This builder measures Android build performance with Siso<br/>The build configs and the bot specs should be in sync with <a href=\"https://ci.chromium.org/p/chromium/builders/try/android-pie-arm64-rel-compilator\">android-pie-arm64-rel-compilator</a>." + } + builders { name: "build-perf-linux" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" @@ -28939,6 +29061,124 @@ description_html: "This builder measures Linux build performance with and without remote caches.<br/>The build configs and the bot specs should be in sync with <a href=\"https://ci.chromium.org/p/chromium/builders/try/linux-rel-compilator\">linux-rel-compilator</a>." } builders { + name: "build-perf-linux-siso" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builder:build-perf-linux-siso" + dimensions: "cores:16" + dimensions: "cpu:x86-64" + dimensions: "os:Ubuntu-18.04" + dimensions: "pool:luci.chromium.ci" + dimensions: "ssd:1" + exe { + cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" + cipd_version: "refs/heads/main" + cmd: "luciexe" + } + properties: + '{' + ' "$build/chromium_tests_builder_config": {' + ' "builder_config": {' + ' "builder_db": {' + ' "entries": [' + ' {' + ' "builder_id": {' + ' "bucket": "ci",' + ' "builder": "build-perf-linux-siso",' + ' "project": "chromium"' + ' },' + ' "builder_spec": {' + ' "builder_group": "chromium.fyi",' + ' "execution_mode": "COMPILE_AND_TEST",' + ' "legacy_chromium_config": {' + ' "apply_configs": [' + ' "mb"' + ' ],' + ' "config": "chromium"' + ' },' + ' "legacy_gclient_config": {' + ' "apply_configs": [' + ' "chromium_no_telemetry_dependencies"' + ' ],' + ' "config": "chromium"' + ' }' + ' }' + ' }' + ' ]' + ' },' + ' "builder_ids": [' + ' {' + ' "bucket": "ci",' + ' "builder": "build-perf-linux-siso",' + ' "project": "chromium"' + ' }' + ' ]' + ' }' + ' },' + ' "$build/code_coverage": {' + ' "use_clang_coverage": true' + ' },' + ' "$build/reclient": {' + ' "instance": "rbe-chromium-untrusted",' + ' "jobs": 300,' + ' "metrics_project": "chromium-reclient-metrics"' + ' },' + ' "$recipe_engine/resultdb/test_presentation": {' + ' "column_keys": [],' + ' "grouping_keys": [' + ' "status",' + ' "v.test_suite"' + ' ]' + ' },' + ' "builder_group": "chromium.fyi",' + ' "recipe": "build_perf_siso"' + '}' + priority: 35 + execution_timeout_secs: 21600 + build_numbers: YES + service_account: "chromium-build-perf-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium_swarming.expose_merge_script_failures" + value: 100 + } + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "ci_test_results" + test_results {} + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "gpu_ci_test_results" + test_results { + predicate { + test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+" + } + } + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "blink_web_tests_ci_test_results" + test_results { + predicate { + test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + description_html: "This builder measures Linux build performance with Siso.<br/>The build configs and the bot specs should be in sync with <a href=\"https://ci.chromium.org/p/chromium/builders/try/linux-rel-compilator\">linux-rel-compilator</a>." + } + builders { name: "build-perf-windows" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" @@ -29058,6 +29298,124 @@ description_html: "This builder measures Windows build performance with and without remote caches.<br/>The build configs and the bot specs should be in sync with <a href=\"https://ci.chromium.org/p/chromium/builders/try/win-rel-compilator\">win-rel-compilator</a>." } builders { + name: "build-perf-windows-siso" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builder:build-perf-windows-siso" + dimensions: "cores:32" + dimensions: "cpu:x86-64" + dimensions: "os:Windows-10" + dimensions: "pool:luci.chromium.ci" + dimensions: "ssd:1" + exe { + cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" + cipd_version: "refs/heads/main" + cmd: "luciexe" + } + properties: + '{' + ' "$build/chromium_tests_builder_config": {' + ' "builder_config": {' + ' "builder_db": {' + ' "entries": [' + ' {' + ' "builder_id": {' + ' "bucket": "ci",' + ' "builder": "build-perf-windows-siso",' + ' "project": "chromium"' + ' },' + ' "builder_spec": {' + ' "builder_group": "chromium.fyi",' + ' "execution_mode": "COMPILE_AND_TEST",' + ' "legacy_chromium_config": {' + ' "apply_configs": [' + ' "mb"' + ' ],' + ' "config": "chromium"' + ' },' + ' "legacy_gclient_config": {' + ' "apply_configs": [' + ' "chromium_no_telemetry_dependencies"' + ' ],' + ' "config": "chromium"' + ' }' + ' }' + ' }' + ' ]' + ' },' + ' "builder_ids": [' + ' {' + ' "bucket": "ci",' + ' "builder": "build-perf-windows-siso",' + ' "project": "chromium"' + ' }' + ' ]' + ' }' + ' },' + ' "$build/code_coverage": {' + ' "use_clang_coverage": true' + ' },' + ' "$build/reclient": {' + ' "instance": "rbe-chromium-untrusted",' + ' "jobs": 300,' + ' "metrics_project": "chromium-reclient-metrics"' + ' },' + ' "$recipe_engine/resultdb/test_presentation": {' + ' "column_keys": [],' + ' "grouping_keys": [' + ' "status",' + ' "v.test_suite"' + ' ]' + ' },' + ' "builder_group": "chromium.fyi",' + ' "recipe": "build_perf_siso"' + '}' + priority: 35 + execution_timeout_secs: 21600 + build_numbers: YES + service_account: "chromium-build-perf-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium_swarming.expose_merge_script_failures" + value: 100 + } + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "ci_test_results" + test_results {} + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "gpu_ci_test_results" + test_results { + predicate { + test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+" + } + } + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "blink_web_tests_ci_test_results" + test_results { + predicate { + test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + description_html: "This builder measures Windows build performance with Siso.<br/>The build configs and the bot specs should be in sync with <a href=\"https://ci.chromium.org/p/chromium/builders/try/win-rel-compilator\">win-rel-compilator</a>." + } + builders { name: "chromeos-amd64-generic-asan-rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index f7a1525..e87e351 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -9485,16 +9485,31 @@ short_name: "and" } builders { + name: "buildbucket/luci.chromium.ci/build-perf-android-siso" + category: "buildperf" + short_name: "andss" + } + builders { name: "buildbucket/luci.chromium.ci/build-perf-linux" category: "buildperf" short_name: "lnx" } builders { + name: "buildbucket/luci.chromium.ci/build-perf-linux-siso" + category: "buildperf" + short_name: "lnxss" + } + builders { name: "buildbucket/luci.chromium.ci/build-perf-windows" category: "buildperf" short_name: "win" } builders { + name: "buildbucket/luci.chromium.ci/build-perf-windows-siso" + category: "buildperf" + short_name: "winss" + } + builders { name: "buildbucket/luci.chromium.ci/android-fieldtrial-rel" category: "android" }
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg index 19dacff..0acc8d7 100644 --- a/infra/config/generated/luci/luci-scheduler.cfg +++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -3919,6 +3919,15 @@ } } job { + id: "build-perf-android-siso" + realm: "ci" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "ci" + builder: "build-perf-android-siso" + } +} +job { id: "build-perf-linux" realm: "ci" buildbucket { @@ -3928,6 +3937,15 @@ } } job { + id: "build-perf-linux-siso" + realm: "ci" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "ci" + builder: "build-perf-linux-siso" + } +} +job { id: "build-perf-windows" realm: "ci" buildbucket { @@ -3937,6 +3955,15 @@ } } job { + id: "build-perf-windows-siso" + realm: "ci" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "ci" + builder: "build-perf-windows-siso" + } +} +job { id: "chromeos-amd64-generic-asan-rel" realm: "ci" buildbucket { @@ -6461,8 +6488,11 @@ triggers: "android-webview-pie-x86-wpt-fyi-rel" triggers: "android-x86-rel" triggers: "build-perf-android" + triggers: "build-perf-android-siso" triggers: "build-perf-linux" + triggers: "build-perf-linux-siso" triggers: "build-perf-windows" + triggers: "build-perf-windows-siso" triggers: "chromeos-amd64-generic-asan-rel" triggers: "chromeos-amd64-generic-cfi-thin-lto-rel" triggers: "chromeos-amd64-generic-dbg"
diff --git a/infra/config/recipes.star b/infra/config/recipes.star index 15b101a1..85226585 100644 --- a/infra/config/recipes.star +++ b/infra/config/recipes.star
@@ -120,6 +120,10 @@ ) build_recipe( + name = "recipe:build_perf_siso", +) + +build_recipe( name = "recipe:celab", )
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star index 31fd924..12c0bf5 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -1553,6 +1553,49 @@ ) ci.builder( + name = "build-perf-android-siso", + description_html = """\ +This builder measures Android build performance with Siso<br/>\ +The build configs and the bot specs should be in sync with <a href="https://ci.chromium.org/p/chromium/builders/try/android-pie-arm64-rel-compilator">android-pie-arm64-rel-compilator</a>.\ +""", + executable = "recipe:build_perf_siso", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config( + config = "chromium", + apply_configs = [ + "android", + "chromium_no_telemetry_dependencies", + ], + ), + chromium_config = builder_config.chromium_config( + config = "android", + apply_configs = [ + "mb", + ], + build_config = builder_config.build_config.RELEASE, + target_bits = 64, + target_platform = builder_config.target_platform.ANDROID, + ), + android_config = builder_config.android_config( + config = "main_builder", + ), + ), + builderless = False, + cores = 32, + # Target luci-chromium-ci-bionic-us-central1-c-1000-ssd-hm32-*. + os = os.LINUX_DEFAULT, + ssd = True, + console_view_entry = consoles.console_view_entry( + category = "buildperf", + short_name = "andss", + ), + execution_timeout = 10 * time.hour, + reclient_instance = reclient.instance.DEFAULT_UNTRUSTED, + reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ, + service_account = "chromium-build-perf-ci-builder@chops-service-accounts.iam.gserviceaccount.com", +) + +ci.builder( name = "build-perf-linux", description_html = """\ This builder measures Linux build performance with and without remote caches.<br/>\ @@ -1590,6 +1633,43 @@ ) ci.builder( + name = "build-perf-linux-siso", + description_html = """\ +This builder measures Linux build performance with Siso.<br/>\ +The build configs and the bot specs should be in sync with <a href="https://ci.chromium.org/p/chromium/builders/try/linux-rel-compilator">linux-rel-compilator</a>.\ +""", + executable = "recipe:build_perf_siso", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config( + config = "chromium", + apply_configs = [ + "chromium_no_telemetry_dependencies", + ], + ), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = [ + "mb", + ], + ), + ), + builderless = False, + cores = 16, + # Target luci-chromium-ci-bionic-us-central1-b-ssd-16-*. + os = os.LINUX_DEFAULT, + ssd = True, + console_view_entry = consoles.console_view_entry( + category = "buildperf", + short_name = "lnxss", + ), + execution_timeout = 6 * time.hour, + reclient_instance = reclient.instance.DEFAULT_UNTRUSTED, + reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ, + service_account = "chromium-build-perf-ci-builder@chops-service-accounts.iam.gserviceaccount.com", + use_clang_coverage = True, +) + +ci.builder( name = "build-perf-windows", description_html = """\ This builder measures Windows build performance with and without remote caches.<br/>\ @@ -1627,6 +1707,43 @@ ) ci.builder( + name = "build-perf-windows-siso", + description_html = """\ +This builder measures Windows build performance with Siso.<br/>\ +The build configs and the bot specs should be in sync with <a href="https://ci.chromium.org/p/chromium/builders/try/win-rel-compilator">win-rel-compilator</a>.\ +""", + executable = "recipe:build_perf_siso", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config( + config = "chromium", + apply_configs = [ + "chromium_no_telemetry_dependencies", + ], + ), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = [ + "mb", + ], + ), + ), + builderless = False, + cores = 32, + # Target luci-chromium-ci-win10-ssd-32-*. + os = os.WINDOWS_DEFAULT, + ssd = True, + console_view_entry = consoles.console_view_entry( + category = "buildperf", + short_name = "winss", + ), + execution_timeout = 6 * time.hour, + reclient_instance = reclient.instance.DEFAULT_UNTRUSTED, + reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ, + service_account = "chromium-build-perf-ci-builder@chops-service-accounts.iam.gserviceaccount.com", + use_clang_coverage = True, +) + +ci.builder( name = "Linux Builder (j-500) (reclient)", schedule = "triggered", builder_spec = builder_config.builder_spec(
diff --git a/ios/chrome/browser/main/BUILD.gn b/ios/chrome/browser/main/BUILD.gn index d4a7d657..d5753a74 100644 --- a/ios/chrome/browser/main/BUILD.gn +++ b/ios/chrome/browser/main/BUILD.gn
@@ -57,6 +57,7 @@ "//ios/chrome/browser/metrics:metrics_browser_agent", "//ios/chrome/browser/ntp:features", "//ios/chrome/browser/policy", + "//ios/chrome/browser/reading_list", "//ios/chrome/browser/send_tab_to_self", "//ios/chrome/browser/sessions", "//ios/chrome/browser/sessions:restoration_agent", @@ -66,6 +67,7 @@ "//ios/chrome/browser/snapshots", "//ios/chrome/browser/sync:sync_error_browser_agent", "//ios/chrome/browser/tabs", + "//ios/chrome/browser/tabs:features", "//ios/chrome/browser/ui/start_surface", "//ios/chrome/browser/upgrade", "//ios/chrome/browser/url_loading",
diff --git a/ios/chrome/browser/main/browser_agent_util.mm b/ios/chrome/browser/main/browser_agent_util.mm index 7e76425..fb2ff9b 100644 --- a/ios/chrome/browser/main/browser_agent_util.mm +++ b/ios/chrome/browser/main/browser_agent_util.mm
@@ -16,6 +16,7 @@ #import "ios/chrome/browser/metrics/tab_usage_recorder_browser_agent.h" #import "ios/chrome/browser/ntp/features.h" #import "ios/chrome/browser/policy/policy_watcher_browser_agent.h" +#import "ios/chrome/browser/reading_list/reading_list_browser_agent.h" #import "ios/chrome/browser/send_tab_to_self/send_tab_to_self_browser_agent.h" #import "ios/chrome/browser/sessions/live_tab_context_browser_agent.h" #import "ios/chrome/browser/sessions/session_restoration_browser_agent.h" @@ -23,6 +24,7 @@ #import "ios/chrome/browser/snapshots/snapshot_browser_agent.h" #import "ios/chrome/browser/sync/sync_error_browser_agent.h" #import "ios/chrome/browser/tabs/closing_web_state_observer_browser_agent.h" +#import "ios/chrome/browser/tabs/features.h" #import "ios/chrome/browser/tabs/synced_window_delegate_browser_agent.h" #import "ios/chrome/browser/tabs/tab_parenting_browser_agent.h" #import "ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h" @@ -91,7 +93,7 @@ // SessionRestorartionAgent requires WebUsageEnablerBrowserAgent. SessionRestorationBrowserAgent::CreateForBrowser( - browser, [SessionServiceIOS sharedService]); + browser, [SessionServiceIOS sharedService], IsPinnedTabsEnabled()); // TabUsageRecorderBrowserAgent and WebStateListMetricsBrowserAgent observe // the SessionRestorationBrowserAgent, so they should be created after the the @@ -112,6 +114,8 @@ UpgradeCenterBrowserAgent::CreateForBrowser(browser, [UpgradeCenter sharedInstance]); + WebStateUpdateBrowserAgent::CreateForBrowser(browser); + ReadingListBrowserAgent::CreateForBrowser(browser); WebStateUpdateBrowserAgent::CreateForBrowser(browser); PagePlaceholderBrowserAgent::CreateForBrowser(browser);
diff --git a/ios/chrome/browser/reading_list/BUILD.gn b/ios/chrome/browser/reading_list/BUILD.gn index 5d90ef6..c3decce5 100644 --- a/ios/chrome/browser/reading_list/BUILD.gn +++ b/ios/chrome/browser/reading_list/BUILD.gn
@@ -11,6 +11,8 @@ "offline_page_tab_helper.mm", "offline_url_utils.h", "offline_url_utils.mm", + "reading_list_browser_agent.h", + "reading_list_browser_agent.mm", "reading_list_distiller_page.h", "reading_list_distiller_page.mm", "reading_list_distiller_page_factory.h", @@ -42,22 +44,32 @@ "//components/reading_list/features:flags", "//components/reading_list/ios", "//components/sync", + "//components/ukm/ios:ukm_url_recorder", + "//ios/chrome/app/strings:ios_strings_grit", "//ios/chrome/browser/application_context", "//ios/chrome/browser/browser_state", "//ios/chrome/browser/favicon", "//ios/chrome/browser/flags:system_flags", "//ios/chrome/browser/history", + "//ios/chrome/browser/main:public", "//ios/chrome/browser/paths", + "//ios/chrome/browser/shared/public/commands", + "//ios/chrome/browser/shared/public/features", "//ios/chrome/browser/shared/ui/util", + "//ios/chrome/browser/shared/ui/util:url_with_title", + "//ios/chrome/browser/signin", "//ios/chrome/browser/sync:model_type_store_service_factory", "//ios/chrome/browser/url:constants", + "//ios/chrome/browser/web_state_list", "//ios/chrome/common", "//ios/components/webui:url_constants", + "//ios/third_party/material_components_ios", "//ios/web/common", "//ios/web/public", "//ios/web/public/js_messaging:js_messaging", "//ios/web/public/security", "//net", + "//services/metrics/public/cpp:ukm_builders", "//services/network/public/cpp", "//services/network/public/mojom", "//ui/base",
diff --git a/ios/chrome/browser/reading_list/reading_list_browser_agent.h b/ios/chrome/browser/reading_list/reading_list_browser_agent.h new file mode 100644 index 0000000..af63c88 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_browser_agent.h
@@ -0,0 +1,37 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_READING_LIST_READING_LIST_BROWSER_AGENT_H_ +#define IOS_CHROME_BROWSER_READING_LIST_READING_LIST_BROWSER_AGENT_H_ + +#import "base/scoped_multi_source_observation.h" +#import "base/scoped_observation.h" +#import "ios/chrome/browser/main/browser_user_data.h" +#import "ios/chrome/browser/shared/ui/util/url_with_title.h" + +class Browser; + +class ReadingListBrowserAgent + : public BrowserUserData<ReadingListBrowserAgent> { + public: + ~ReadingListBrowserAgent() override; + + // Not copyable or assignable. + ReadingListBrowserAgent(const ReadingListBrowserAgent&) = delete; + ReadingListBrowserAgent& operator=(const ReadingListBrowserAgent&) = delete; + void AddURLsToReadingList(NSArray<URLWithTitle*>* URLs); + + private: + friend class BrowserUserData<ReadingListBrowserAgent>; + BROWSER_USER_DATA_KEY_DECL(); + + explicit ReadingListBrowserAgent(Browser* browser); + + void AddURLToReadingListwithTitle(const GURL& URL, NSString* title); + + // The browser associated with this agent. + Browser* browser_; +}; + +#endif // IOS_CHROME_BROWSER_READING_LIST_READING_LIST_BROWSER_AGENT_H_
diff --git a/ios/chrome/browser/reading_list/reading_list_browser_agent.mm b/ios/chrome/browser/reading_list/reading_list_browser_agent.mm new file mode 100644 index 0000000..63c00eaf --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_browser_agent.mm
@@ -0,0 +1,115 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/reading_list/reading_list_browser_agent.h" + +#import <MaterialComponents/MaterialSnackbar.h> + +#import "base/i18n/message_formatter.h" +#import "base/metrics/user_metrics.h" +#import "base/strings/sys_string_conversions.h" +#import "components/reading_list/core/reading_list_model.h" +#import "components/signin/public/identity_manager/identity_manager.h" +#import "components/ukm/ios/ukm_url_recorder.h" +#import "ios/chrome/browser/browser_state/chrome_browser_state.h" +#import "ios/chrome/browser/reading_list/reading_list_model_factory.h" +#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" +#import "ios/chrome/browser/shared/public/commands/snackbar_commands.h" +#import "ios/chrome/browser/shared/public/features/features.h" +#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h" +#import "ios/chrome/browser/signin/identity_manager_factory.h" +#import "ios/chrome/browser/web_state_list/web_state_list.h" +#import "ios/chrome/grit/ios_strings.h" +#import "ios/web/public/web_state.h" +#import "services/metrics/public/cpp/ukm_builders.h" +#import "ui/base/l10n/l10n_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +BROWSER_USER_DATA_KEY_IMPL(ReadingListBrowserAgent) + +ReadingListBrowserAgent::ReadingListBrowserAgent(Browser* browser) { + browser_ = browser; +} + +ReadingListBrowserAgent::~ReadingListBrowserAgent() {} + +#pragma mark - Public + +// Adds the given urls to the reading list. +void ReadingListBrowserAgent::AddURLsToReadingList( + NSArray<URLWithTitle*>* urls) { + DCHECK(urls.count > 0) << "Urls are missing"; + + for (URLWithTitle* url_with_title in urls) { + AddURLToReadingListwithTitle(url_with_title.URL, url_with_title.title); + } + + TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess); + + ReadingListModel* reading_model = + ReadingListModelFactory::GetInstance()->GetForBrowserState( + browser_->GetBrowserState()); + CoreAccountId account_id = + reading_model->GetAccountWhereEntryIsSavedTo(urls.lastObject.URL); + signin::IdentityManager* identity_manager = + IdentityManagerFactory::GetForBrowserState( + browser_->GetBrowserState()->GetOriginalChromeBrowserState()); + AccountInfo account_info = + identity_manager->FindExtendedAccountInfoByAccountId(account_id); + + NSString* snackbar_text = nil; + if (!account_info.IsEmpty() && + base::FeatureList::IsEnabled( + kEnableEmailInBookmarksReadingListSnackbar)) { + std::u16string pattern = l10n_util::GetStringUTF16( + IDS_IOS_READING_LIST_SNACKBAR_MESSAGE_FOR_ACCOUNT); + std::u16string utf16Text = + base::i18n::MessageFormatter::FormatWithNamedArgs( + pattern, "count", (int)urls.count, "email", account_info.email); + snackbar_text = base::SysUTF16ToNSString(utf16Text); + } else { + snackbar_text = + l10n_util::GetNSString(IDS_IOS_READING_LIST_SNACKBAR_MESSAGE); + } + + MDCSnackbarMessage* message = + [MDCSnackbarMessage messageWithText:snackbar_text]; + message.accessibilityLabel = snackbar_text; + message.duration = 2.0; + + CommandDispatcher* dispatcher = browser_->GetCommandDispatcher(); + id<SnackbarCommands> snackbar_commands_handler = + HandlerForProtocol(dispatcher, SnackbarCommands); + [snackbar_commands_handler showSnackbarMessage:message]; +} + +#pragma mark - Private + +void ReadingListBrowserAgent::AddURLToReadingListwithTitle(const GURL& url, + NSString* title) { + web::WebState* current_web_state = + browser_->GetWebStateList()->GetActiveWebState(); + if (current_web_state && + current_web_state->GetVisibleURL().spec() == url.spec()) { + // Log UKM if the current page is being added to Reading List. + ukm::SourceId source_id = + ukm::GetSourceIdForWebStateDocument(current_web_state); + if (source_id != ukm::kInvalidSourceId) { + ukm::builders::IOS_PageAddedToReadingList(source_id) + .SetAddedFromMessages(false) + .Record(ukm::UkmRecorder::Get()); + } + } + + base::RecordAction(base::UserMetricsAction("MobileReadingListAdd")); + ReadingListModel* reading_model = + ReadingListModelFactory::GetInstance()->GetForBrowserState( + browser_->GetBrowserState()); + reading_model->AddOrReplaceEntry(url, base::SysNSStringToUTF8(title), + reading_list::ADDED_VIA_CURRENT_APP, + /*estimated_read_time=*/base::TimeDelta()); +}
diff --git a/ios/chrome/browser/sessions/session_restoration_browser_agent.h b/ios/chrome/browser/sessions/session_restoration_browser_agent.h index a4489f3..ad040cf 100644 --- a/ios/chrome/browser/sessions/session_restoration_browser_agent.h +++ b/ios/chrome/browser/sessions/session_restoration_browser_agent.h
@@ -84,7 +84,8 @@ BROWSER_USER_DATA_KEY_DECL(); SessionRestorationBrowserAgent(Browser* browser, - SessionServiceIOS* session_service); + SessionServiceIOS* session_service, + bool enable_pinned_web_states); // Returns array of CRWSessionStorage for the provided session restoration // `scope`. This method is mainly needed to remove the dropped session @@ -152,6 +153,8 @@ // True when session restoration is in progress. bool restoring_session_ = false; + const bool enable_pinned_web_states_; + // Observer for the active web state in `browser_`'s web state list. std::unique_ptr<AllWebStateObservationForwarder> all_web_state_observer_; };
diff --git a/ios/chrome/browser/sessions/session_restoration_browser_agent.mm b/ios/chrome/browser/sessions/session_restoration_browser_agent.mm index 4fb96c5..28142a9 100644 --- a/ios/chrome/browser/sessions/session_restoration_browser_agent.mm +++ b/ios/chrome/browser/sessions/session_restoration_browser_agent.mm
@@ -36,13 +36,15 @@ SessionRestorationBrowserAgent::SessionRestorationBrowserAgent( Browser* browser, - SessionServiceIOS* session_service) + SessionServiceIOS* session_service, + bool enable_pinned_web_states) : session_service_(session_service), web_state_list_(browser->GetWebStateList()), web_enabler_(WebUsageEnablerBrowserAgent::FromBrowser(browser)), browser_state_(browser->GetBrowserState()), session_ios_factory_( [[SessionIOSFactory alloc] initWithWebStateList:web_state_list_]), + enable_pinned_web_states_(enable_pinned_web_states), all_web_state_observer_( std::make_unique<AllWebStateObservationForwarder>(web_state_list_, this)) { @@ -81,9 +83,6 @@ bool SessionRestorationBrowserAgent::RestoreSessionWindow( SessionWindowIOS* window, SessionRestorationScope scope) { - if (!window.sessions.count) - return false; - // Start the session restoration. restoring_session_ = true; @@ -100,12 +99,12 @@ base::BindOnce(^(WebStateList* web_state_list) { web::WebState::CreateParams create_params(browser_state_); DeserializeWebStateList( - web_state_list, window, scope, + web_state_list, window, scope, enable_pinned_web_states_, base::BindRepeating(&web::WebState::CreateWithStorageSession, create_params)); })); - DCHECK_GT(web_state_list_->count(), old_count); + DCHECK_GE(web_state_list_->count(), old_count); int restored_count = web_state_list_->count() - old_count; int restored_pinned_count = web_state_list_->GetIndexOfFirstNonPinnedWebState() -
diff --git a/ios/chrome/browser/sessions/session_restoration_browser_agent_unittest.mm b/ios/chrome/browser/sessions/session_restoration_browser_agent_unittest.mm index d6d7e63..f70a08d5 100644 --- a/ios/chrome/browser/sessions/session_restoration_browser_agent_unittest.mm +++ b/ios/chrome/browser/sessions/session_restoration_browser_agent_unittest.mm
@@ -157,6 +157,13 @@ AuthenticationServiceFactory::CreateAndInitializeForBrowserState( chrome_browser_state_.get(), std::make_unique<FakeAuthenticationServiceDelegate>()); + + session_identifier_ = [[NSUUID UUID] UUIDString]; + } + + ~SessionRestorationBrowserAgentTest() override = default; + + void SetUp() override { // This test requires that some TabHelpers are attached to the WebStates, so // it needs to use a WebStateList with the full BrowserWebStateListDelegate, // rather than the TestWebStateList delegate used in the default TestBrowser @@ -169,17 +176,8 @@ web_usage_enabler_ = WebUsageEnablerBrowserAgent::FromBrowser(browser_.get()); web_usage_enabler_->SetWebUsageEnabled(false); - - session_identifier_ = [[NSUUID UUID] UUIDString]; - SessionRestorationBrowserAgent::CreateForBrowser(browser_.get(), - test_session_service_); - session_restoration_agent_ = - SessionRestorationBrowserAgent::FromBrowser(browser_.get()); - session_restoration_agent_->SetSessionID(session_identifier_); } - ~SessionRestorationBrowserAgentTest() override = default; - void TearDown() override { @autoreleasepool { browser_->GetWebStateList()->CloseAllWebStates( @@ -191,12 +189,16 @@ NSString* session_id() { return session_identifier_; } protected: - // Creates a WebState with the given parameters and insert it in the - // Browser's WebStateList. - web::WebState* InsertNewWebState(const GURL& url, - web::WebState* parent, - int index, - bool background) { + void CreateSessionRestorationBrowserAgent(bool enable_pinned_web_states) { + SessionRestorationBrowserAgent::CreateForBrowser( + browser_.get(), test_session_service_, enable_pinned_web_states); + session_restoration_agent_ = + SessionRestorationBrowserAgent::FromBrowser(browser_.get()); + session_restoration_agent_->SetSessionID(session_identifier_); + } + + // Creates a WebState with the given parameters. + std::unique_ptr<web::WebState> CreateWebState(const GURL& url) { web::NavigationManager::WebLoadParams load_params(url); load_params.transition_type = ui::PAGE_TRANSITION_TYPED; @@ -213,9 +215,25 @@ return !web_state_ptr->IsLoading(); })); + return web_state; + } + + // Creates a WebState with the given parameters and insert it in the + // Browser's WebStateList. + web::WebState* InsertNewWebState(const GURL& url, + web::WebState* parent, + int index, + bool pinned, + bool background) { + std::unique_ptr<web::WebState> web_state = CreateWebState(url); + int insertion_flags = WebStateList::INSERT_FORCE_INDEX; - if (!background) + if (!background) { insertion_flags |= WebStateList::INSERT_ACTIVATE; + } + if (pinned) { + insertion_flags |= WebStateList::INSERT_PINNED; + } browser_->GetWebStateList()->InsertWebState( index, std::move(web_state), insertion_flags, WebStateOpener(parent)); return browser_->GetWebStateList()->GetWebStateAt(index); @@ -234,6 +252,8 @@ // Tests that CRWSessionStorage with empty item_storages are not restored. TEST_F(SessionRestorationBrowserAgentTest, RestoreEmptySessions) { + CreateSessionRestorationBrowserAgent(true); + NSMutableArray<CRWSessionStorage*>* sessions = [NSMutableArray array]; for (int i = 0; i < 3; i++) { CRWSessionStorage* session_storage = [[CRWSessionStorage alloc] init]; @@ -252,6 +272,8 @@ // Tests that restoring a session works correctly on empty WebStateList. TEST_F(SessionRestorationBrowserAgentTest, RestoreSessionOnEmptyWebStateList) { + CreateSessionRestorationBrowserAgent(true); + SessionWindowIOS* window = CreateSessionWindow(SessionInfo<5>{.active_index = 1, .tab_infos = { @@ -272,17 +294,18 @@ EXPECT_EQ(browser_->GetWebStateList()->GetWebStateAt(0), browser_->GetWebStateList()->GetOpenerOfWebStateAt(1).opener); - // Check that the first tab is pinned if pinned tab support is enabled - // or that the pinned flag has been removed otherwise. - EXPECT_EQ(IsPinnedTabsEnabled(), - browser_->GetWebStateList()->IsWebStatePinnedAt(0)); + // Check that the first tab is pinned. + ASSERT_TRUE(browser_->GetWebStateList()->IsWebStatePinnedAt(0)); } // Tests that restoring a session works correctly on non empty WebStatelist. TEST_F(SessionRestorationBrowserAgentTest, RestoreSessionWithNonEmptyWebStateList) { - web::WebState* web_state = InsertNewWebState( - GURL(kURL1), /*parent=*/nullptr, /*index=*/0, /*background=*/false); + CreateSessionRestorationBrowserAgent(true); + + web::WebState* web_state = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/false, /*background=*/false); SessionWindowIOS* window = CreateSessionWindow(SessionInfo<3>{.active_index = 2, @@ -303,13 +326,340 @@ EXPECT_NE(web_state, browser_->GetWebStateList()->GetWebStateAt(3)); } +// Tests that restoring a session with scope `kAll` works correctly on non +// empty WebStatelist with pinned WebStates present. +TEST_F(SessionRestorationBrowserAgentTest, RestoreAllWebStatesInSession) { + CreateSessionRestorationBrowserAgent(true); + + web::WebState* pinned_web_state_0 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_1 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/1, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_2 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/2, + /*pinned=*/true, /*background=*/false); + + web::WebState* regular_web_state_0 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/3, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_1 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/4, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_2 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/5, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_3 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/6, + /*pinned=*/false, /*background=*/false); + + SessionWindowIOS* window = + CreateSessionWindow(SessionInfo<5>{.active_index = 1, + .tab_infos = { + TabInfo{.pinned = true}, + TabInfo{.pinned = true}, + TabInfo{}, + TabInfo{}, + TabInfo{}, + }}); + + session_restoration_agent_->RestoreSessionWindow( + window, SessionRestorationScope::kAll); + + ASSERT_EQ(12, browser_->GetWebStateList()->count()); + EXPECT_EQ(browser_->GetWebStateList()->GetWebStateAt(4), + browser_->GetWebStateList()->GetActiveWebState()); + EXPECT_EQ(pinned_web_state_0, browser_->GetWebStateList()->GetWebStateAt(0)); + EXPECT_EQ(pinned_web_state_1, browser_->GetWebStateList()->GetWebStateAt(1)); + EXPECT_EQ(pinned_web_state_2, browser_->GetWebStateList()->GetWebStateAt(2)); + EXPECT_EQ(regular_web_state_0, browser_->GetWebStateList()->GetWebStateAt(5)); + EXPECT_EQ(regular_web_state_1, browser_->GetWebStateList()->GetWebStateAt(6)); + EXPECT_EQ(regular_web_state_2, browser_->GetWebStateList()->GetWebStateAt(7)); + EXPECT_EQ(regular_web_state_3, browser_->GetWebStateList()->GetWebStateAt(8)); +} + +// Tests that restoring a session with scope `kPinnedOnly` works correctly on +// non empty WebStatelist with pinned WebStates present. +TEST_F(SessionRestorationBrowserAgentTest, + RestorePinnedWebStatesOnlyInSession) { + CreateSessionRestorationBrowserAgent(true); + + web::WebState* pinned_web_state_0 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_1 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/1, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_2 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/2, + /*pinned=*/true, /*background=*/false); + + web::WebState* regular_web_state_0 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/3, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_1 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/4, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_2 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/5, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_3 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/6, + /*pinned=*/false, /*background=*/false); + + SessionWindowIOS* window = + CreateSessionWindow(SessionInfo<5>{.active_index = 2, + .tab_infos = { + TabInfo{.pinned = true}, + TabInfo{.pinned = true}, + TabInfo{}, + TabInfo{}, + TabInfo{}, + }}); + + session_restoration_agent_->RestoreSessionWindow( + window, SessionRestorationScope::kPinnedOnly); + + ASSERT_EQ(9, browser_->GetWebStateList()->count()); + EXPECT_EQ(browser_->GetWebStateList()->GetActiveWebState(), + regular_web_state_3); + EXPECT_EQ(pinned_web_state_0, browser_->GetWebStateList()->GetWebStateAt(0)); + EXPECT_EQ(pinned_web_state_1, browser_->GetWebStateList()->GetWebStateAt(1)); + EXPECT_EQ(pinned_web_state_2, browser_->GetWebStateList()->GetWebStateAt(2)); + EXPECT_EQ(regular_web_state_0, browser_->GetWebStateList()->GetWebStateAt(5)); + EXPECT_EQ(regular_web_state_1, browser_->GetWebStateList()->GetWebStateAt(6)); + EXPECT_EQ(regular_web_state_2, browser_->GetWebStateList()->GetWebStateAt(7)); + EXPECT_EQ(regular_web_state_3, browser_->GetWebStateList()->GetWebStateAt(8)); +} + +// Tests that restoring a session with scope `kRegularOnly` works correctly on +// non empty WebStatelist with pinned WebStates present. +TEST_F(SessionRestorationBrowserAgentTest, + RestoreRegularWebStatesOnlyInSession) { + CreateSessionRestorationBrowserAgent(true); + + web::WebState* pinned_web_state_0 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_1 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/1, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_2 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/2, + /*pinned=*/true, /*background=*/false); + + web::WebState* regular_web_state_0 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/3, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_1 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/4, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_2 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/5, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_3 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/6, + /*pinned=*/false, /*background=*/false); + + SessionWindowIOS* window = + CreateSessionWindow(SessionInfo<5>{.active_index = 3, + .tab_infos = { + TabInfo{.pinned = true}, + TabInfo{.pinned = true}, + TabInfo{}, + TabInfo{}, + TabInfo{}, + }}); + + session_restoration_agent_->RestoreSessionWindow( + window, SessionRestorationScope::kRegularOnly); + + ASSERT_EQ(10, browser_->GetWebStateList()->count()); + EXPECT_EQ(browser_->GetWebStateList()->GetActiveWebState(), + browser_->GetWebStateList()->GetWebStateAt(8)); + EXPECT_EQ(pinned_web_state_0, browser_->GetWebStateList()->GetWebStateAt(0)); + EXPECT_EQ(pinned_web_state_1, browser_->GetWebStateList()->GetWebStateAt(1)); + EXPECT_EQ(pinned_web_state_2, browser_->GetWebStateList()->GetWebStateAt(2)); + EXPECT_EQ(regular_web_state_0, browser_->GetWebStateList()->GetWebStateAt(3)); + EXPECT_EQ(regular_web_state_1, browser_->GetWebStateList()->GetWebStateAt(4)); + EXPECT_EQ(regular_web_state_2, browser_->GetWebStateList()->GetWebStateAt(5)); + EXPECT_EQ(regular_web_state_3, browser_->GetWebStateList()->GetWebStateAt(6)); +} + +// Tests that restoring a session with scope `kAll` but disabled pinned tabs +// works correctly on non empty WebStatelist with pinned WebStates present. +TEST_F(SessionRestorationBrowserAgentTest, + RestoreAllWebStatesInSessionWithPinnedTabsDisabled) { + CreateSessionRestorationBrowserAgent(false); + + web::WebState* pinned_web_state_0 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_1 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/1, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_2 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/2, + /*pinned=*/true, /*background=*/false); + + web::WebState* regular_web_state_0 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/3, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_1 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/4, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_2 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/5, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_3 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/6, + /*pinned=*/false, /*background=*/false); + + SessionWindowIOS* window = + CreateSessionWindow(SessionInfo<5>{.active_index = 2, + .tab_infos = { + TabInfo{.pinned = true}, + TabInfo{.pinned = true}, + TabInfo{}, + TabInfo{}, + TabInfo{}, + }}); + + session_restoration_agent_->RestoreSessionWindow( + window, SessionRestorationScope::kAll); + + ASSERT_EQ(12, browser_->GetWebStateList()->count()); + EXPECT_EQ(browser_->GetWebStateList()->GetWebStateAt(9), + browser_->GetWebStateList()->GetActiveWebState()); + EXPECT_EQ(pinned_web_state_0, browser_->GetWebStateList()->GetWebStateAt(0)); + EXPECT_EQ(pinned_web_state_1, browser_->GetWebStateList()->GetWebStateAt(1)); + EXPECT_EQ(pinned_web_state_2, browser_->GetWebStateList()->GetWebStateAt(2)); + EXPECT_EQ(regular_web_state_0, browser_->GetWebStateList()->GetWebStateAt(3)); + EXPECT_EQ(regular_web_state_1, browser_->GetWebStateList()->GetWebStateAt(4)); + EXPECT_EQ(regular_web_state_2, browser_->GetWebStateList()->GetWebStateAt(5)); + EXPECT_EQ(regular_web_state_3, browser_->GetWebStateList()->GetWebStateAt(6)); +} + +// Tests that restoring a session with scope `kPinnedOnly` but disabled pinned +// tabs works correctly on non empty WebStatelist with pinned WebStates +// present. +TEST_F(SessionRestorationBrowserAgentTest, + RestorePinnedWebStatesOnlyInSessionWithPinnedTabsDisabled) { + CreateSessionRestorationBrowserAgent(false); + + web::WebState* pinned_web_state_0 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_1 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/1, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_2 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/2, + /*pinned=*/true, /*background=*/false); + + web::WebState* regular_web_state_0 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/3, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_1 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/4, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_2 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/5, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_3 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/6, + /*pinned=*/false, /*background=*/false); + + SessionWindowIOS* window = + CreateSessionWindow(SessionInfo<5>{.active_index = 2, + .tab_infos = { + TabInfo{.pinned = true}, + TabInfo{.pinned = true}, + TabInfo{}, + TabInfo{}, + TabInfo{}, + }}); + + session_restoration_agent_->RestoreSessionWindow( + window, SessionRestorationScope::kPinnedOnly); + + ASSERT_EQ(7, browser_->GetWebStateList()->count()); + EXPECT_EQ(browser_->GetWebStateList()->GetActiveWebState(), + regular_web_state_3); + EXPECT_EQ(pinned_web_state_0, browser_->GetWebStateList()->GetWebStateAt(0)); + EXPECT_EQ(pinned_web_state_1, browser_->GetWebStateList()->GetWebStateAt(1)); + EXPECT_EQ(pinned_web_state_2, browser_->GetWebStateList()->GetWebStateAt(2)); + EXPECT_EQ(regular_web_state_0, browser_->GetWebStateList()->GetWebStateAt(3)); + EXPECT_EQ(regular_web_state_1, browser_->GetWebStateList()->GetWebStateAt(4)); + EXPECT_EQ(regular_web_state_2, browser_->GetWebStateList()->GetWebStateAt(5)); + EXPECT_EQ(regular_web_state_3, browser_->GetWebStateList()->GetWebStateAt(6)); +} + +// Tests that restoring a session with scope `kRegularOnly` but disabled +// pinned tabs works correctly on non empty WebStatelist with pinned WebStates +// present. +TEST_F(SessionRestorationBrowserAgentTest, + RestoreRegularWebStatesOnlyInSessionWithPinnedTabsDisabled) { + CreateSessionRestorationBrowserAgent(false); + + web::WebState* pinned_web_state_0 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_1 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/1, + /*pinned=*/true, /*background=*/false); + web::WebState* pinned_web_state_2 = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/2, + /*pinned=*/true, /*background=*/false); + + web::WebState* regular_web_state_0 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/3, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_1 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/4, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_2 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/5, + /*pinned=*/false, /*background=*/false); + web::WebState* regular_web_state_3 = + InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/6, + /*pinned=*/false, /*background=*/false); + + SessionWindowIOS* window = + CreateSessionWindow(SessionInfo<5>{.active_index = 3, + .tab_infos = { + TabInfo{.pinned = true}, + TabInfo{.pinned = true}, + TabInfo{}, + TabInfo{}, + TabInfo{}, + }}); + + session_restoration_agent_->RestoreSessionWindow( + window, SessionRestorationScope::kRegularOnly); + + ASSERT_EQ(12, browser_->GetWebStateList()->count()); + EXPECT_EQ(browser_->GetWebStateList()->GetActiveWebState(), + browser_->GetWebStateList()->GetWebStateAt(10)); + EXPECT_EQ(pinned_web_state_0, browser_->GetWebStateList()->GetWebStateAt(0)); + EXPECT_EQ(pinned_web_state_1, browser_->GetWebStateList()->GetWebStateAt(1)); + EXPECT_EQ(pinned_web_state_2, browser_->GetWebStateList()->GetWebStateAt(2)); + EXPECT_EQ(regular_web_state_0, browser_->GetWebStateList()->GetWebStateAt(3)); + EXPECT_EQ(regular_web_state_1, browser_->GetWebStateList()->GetWebStateAt(4)); + EXPECT_EQ(regular_web_state_2, browser_->GetWebStateList()->GetWebStateAt(5)); + EXPECT_EQ(regular_web_state_3, browser_->GetWebStateList()->GetWebStateAt(6)); +} + // TODO(crbug.com/888674): This test requires commiting item to // NavigationManagerImpl which is not possible, migrate this to EG test so // it can be tested. TEST_F(SessionRestorationBrowserAgentTest, DISABLED_RestoreSessionOnNTPTest) { + CreateSessionRestorationBrowserAgent(true); + web::WebState* web_state = InsertNewWebState(GURL(kChromeUINewTabURL), /*parent=*/nullptr, - /*index=*/0, /*background=*/false); + /*index=*/0, /*pinned=*/false, /*background=*/false); // Create NTPTabHelper to ensure VisibleURL is set to kChromeUINewTabURL. id delegate = OCMProtocolMock(@protocol(NewTabPageTabHelperDelegate)); @@ -338,7 +688,10 @@ // Tests that saving a non-empty session, then saving an empty session, then // restoring, restores zero web states, and not the non-empty session. TEST_F(SessionRestorationBrowserAgentTest, SaveAndRestoreEmptySession) { + CreateSessionRestorationBrowserAgent(true); + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/false, /*background=*/false); [test_session_service_ setPerformIO:YES]; @@ -367,10 +720,15 @@ // Tests that saving a session with web states, then clearing the WebStatelist // and then restoring the session will restore the web states correctly. TEST_F(SessionRestorationBrowserAgentTest, SaveAndRestoreSession) { - web::WebState* web_state = InsertNewWebState( - GURL(kURL1), /*parent=*/nullptr, /*index=*/0, /*background=*/false); - InsertNewWebState(GURL(kURL1), web_state, /*index=*/1, /*background=*/false); - InsertNewWebState(GURL(kURL2), web_state, /*index=*/0, /*background=*/false); + CreateSessionRestorationBrowserAgent(true); + + web::WebState* web_state = + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/false, /*background=*/false); + InsertNewWebState(GURL(kURL1), web_state, /*index=*/1, /*pinned=*/false, + /*background=*/false); + InsertNewWebState(GURL(kURL2), web_state, /*index=*/0, /*pinned=*/false, + /*background=*/false); ASSERT_EQ(3, browser_->GetWebStateList()->count()); browser_->GetWebStateList()->ActivateWebStateAt(1); @@ -404,6 +762,8 @@ // clearing the WebStatelist and restoring the session will restore the web // states correctly. TEST_F(SessionRestorationBrowserAgentTest, SaveInProgressAndRestoreSession) { + CreateSessionRestorationBrowserAgent(true); + SessionWindowIOS* window = CreateSessionWindow(SessionInfo<5>{.active_index = 1, .tab_infos = { @@ -442,7 +802,10 @@ // Tests that SessionRestorationObserver methods are called when sessions is // restored. TEST_F(SessionRestorationBrowserAgentTest, ObserverCalledWithRestore) { + CreateSessionRestorationBrowserAgent(true); + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/false, /*background=*/false); TestRestorationObserver observer; @@ -469,14 +832,19 @@ // changes. TEST_F(SessionRestorationBrowserAgentTest, SaveSessionWithActiveWebStateChange) { + CreateSessionRestorationBrowserAgent(true); + InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/false, /*background=*/true); InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/1, + /*pinned=*/false, /*background=*/true); EXPECT_EQ(test_session_service_.saveSessionCallsCount, 0); // Inserting new active webState. InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/2, + /*pinned=*/false, /*background=*/false); EXPECT_EQ(test_session_service_.saveSessionCallsCount, 1); @@ -502,8 +870,10 @@ EXPECT_EQ(test_session_service_.saveSessionCallsCount, 6); InsertNewWebState(GURL(kURL1), /*parent=*/nullptr, /*index=*/0, + /*pinned=*/false, /*background=*/true); InsertNewWebState(GURL(kURL2), /*parent=*/nullptr, /*index=*/1, + /*pinned=*/false, /*background=*/true); browser_->GetWebStateList()->CloseAllWebStates(WebStateList::CLOSE_NO_FLAGS); EXPECT_EQ(test_session_service_.saveSessionCallsCount, 7);
diff --git a/ios/chrome/browser/shared/coordinator/layout_guide/BUILD.gn b/ios/chrome/browser/shared/coordinator/layout_guide/BUILD.gn index 9e33b4d..42d65465 100644 --- a/ios/chrome/browser/shared/coordinator/layout_guide/BUILD.gn +++ b/ios/chrome/browser/shared/coordinator/layout_guide/BUILD.gn
@@ -2,11 +2,40 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +source_set("layout_guide_scene_agent") { + configs += [ "//build/config/compiler:enable_arc" ] + sources = [ + "layout_guide_scene_agent.h", + "layout_guide_scene_agent.mm", + ] + deps = [ + "//base", + "//ios/chrome/browser/shared/coordinator/scene:observing_scene_agent", + "//ios/chrome/browser/shared/ui/util:util_swift", + ] + frameworks = [ "UIKit.framework" ] +} + source_set("layout_guide") { configs += [ "//build/config/compiler:enable_arc" ] - sources = [ "layout_guide_util.h" ] + sources = [ + "layout_guide_util.h", + "layout_guide_util.mm", + ] deps = [ - "//ios/chrome/browser/shared/ui/layout_guide", - "//ios/chrome/browser/ui/main:layout_guide_util", + ":layout_guide_scene_agent", + "//ios/chrome/browser/browser_state", + "//ios/chrome/browser/shared/coordinator/scene:scene_state_browser_agent", + "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", + ] +} + +source_set("unit_tests") { + configs += [ "//build/config/compiler:enable_arc" ] + testonly = true + sources = [ "layout_guide_scene_agent_unittest.mm" ] + deps = [ + ":layout_guide_scene_agent", + "//testing/gtest", ] }
diff --git a/ios/chrome/browser/ui/main/layout_guide_scene_agent.h b/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent.h similarity index 71% rename from ios/chrome/browser/ui/main/layout_guide_scene_agent.h rename to ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent.h index d58724048..43824bc 100644 --- a/ios/chrome/browser/ui/main/layout_guide_scene_agent.h +++ b/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef IOS_CHROME_BROWSER_UI_MAIN_LAYOUT_GUIDE_SCENE_AGENT_H_ -#define IOS_CHROME_BROWSER_UI_MAIN_LAYOUT_GUIDE_SCENE_AGENT_H_ +#ifndef IOS_CHROME_BROWSER_SHARED_COORDINATOR_LAYOUT_GUIDE_LAYOUT_GUIDE_SCENE_AGENT_H_ +#define IOS_CHROME_BROWSER_SHARED_COORDINATOR_LAYOUT_GUIDE_LAYOUT_GUIDE_SCENE_AGENT_H_ #import "ios/chrome/browser/shared/coordinator/scene/observing_scene_state_agent.h" @@ -20,4 +20,4 @@ @end -#endif // IOS_CHROME_BROWSER_UI_MAIN_LAYOUT_GUIDE_SCENE_AGENT_H_ +#endif // IOS_CHROME_BROWSER_SHARED_COORDINATOR_LAYOUT_GUIDE_LAYOUT_GUIDE_SCENE_AGENT_H_
diff --git a/ios/chrome/browser/ui/main/layout_guide_scene_agent.mm b/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent.mm similarity index 86% rename from ios/chrome/browser/ui/main/layout_guide_scene_agent.mm rename to ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent.mm index e198fed..764a862 100644 --- a/ios/chrome/browser/ui/main/layout_guide_scene_agent.mm +++ b/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/chrome/browser/ui/main/layout_guide_scene_agent.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent.h" #import "ios/chrome/browser/shared/ui/util/util_swift.h"
diff --git a/ios/chrome/browser/ui/main/layout_guide_scene_agent_unittest.mm b/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent_unittest.mm similarity index 86% rename from ios/chrome/browser/ui/main/layout_guide_scene_agent_unittest.mm rename to ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent_unittest.mm index f192ed41..9e6e39f 100644 --- a/ios/chrome/browser/ui/main/layout_guide_scene_agent_unittest.mm +++ b/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent_unittest.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/chrome/browser/ui/main/layout_guide_scene_agent.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent.h" #import "testing/platform_test.h"
diff --git a/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h b/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h index 23276a68..c650d371 100644 --- a/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h +++ b/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h
@@ -1,11 +1,15 @@ -// Copyright 2023 The Chromium Authors +// Copyright 2022 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef IOS_CHROME_BROWSER_SHARED_COORDINATOR_LAYOUT_GUIDE_LAYOUT_GUIDE_UTIL_H_ #define IOS_CHROME_BROWSER_SHARED_COORDINATOR_LAYOUT_GUIDE_LAYOUT_GUIDE_UTIL_H_ -// Temporary include. -#import "ios/chrome/browser/ui/main/layout_guide_util.h" +class Browser; +@class LayoutGuideCenter; + +// Returns the layout guide center assigned to the given `browser`. If there is +// none, it returns a global shared layout guide center. +LayoutGuideCenter* LayoutGuideCenterForBrowser(Browser* browser); #endif // IOS_CHROME_BROWSER_SHARED_COORDINATOR_LAYOUT_GUIDE_LAYOUT_GUIDE_UTIL_H_
diff --git a/ios/chrome/browser/ui/main/layout_guide_util.mm b/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.mm similarity index 90% rename from ios/chrome/browser/ui/main/layout_guide_util.mm rename to ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.mm index 8a7fb6bc..2d5778c 100644 --- a/ios/chrome/browser/ui/main/layout_guide_util.mm +++ b/ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.mm
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/chrome/browser/ui/main/layout_guide_util.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/browser_state/chrome_browser_state.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_state.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_state_browser_agent.h" #import "ios/chrome/browser/shared/ui/util/util_swift.h" -#import "ios/chrome/browser/ui/main/layout_guide_scene_agent.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/shared/coordinator/scene/BUILD.gn b/ios/chrome/browser/shared/coordinator/scene/BUILD.gn index bcbd057a..61981e67 100644 --- a/ios/chrome/browser/shared/coordinator/scene/BUILD.gn +++ b/ios/chrome/browser/shared/coordinator/scene/BUILD.gn
@@ -111,6 +111,7 @@ "//ios/chrome/browser/sessions:scene_util", "//ios/chrome/browser/sessions:session_saving", "//ios/chrome/browser/sessions:session_service", + "//ios/chrome/browser/shared/coordinator/layout_guide:layout_guide_scene_agent", "//ios/chrome/browser/shared/public/commands:commands", "//ios/chrome/browser/shared/public/features", "//ios/chrome/browser/shared/ui/util", @@ -138,7 +139,6 @@ "//ios/chrome/browser/ui/main:browser_interface_provider", "//ios/chrome/browser/ui/main:default_browser_scene_agent", "//ios/chrome/browser/ui/main:incognito_blocker_scene_agent", - "//ios/chrome/browser/ui/main:layout_guide_scene_agent", "//ios/chrome/browser/ui/main:scene", "//ios/chrome/browser/ui/ntp:feature_flags", "//ios/chrome/browser/ui/policy:user_policy_scene_agent",
diff --git a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm index b3de660..4fe94b1 100644 --- a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm +++ b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
@@ -72,6 +72,7 @@ #import "ios/chrome/browser/screenshot/screenshot_delegate.h" #import "ios/chrome/browser/sessions/session_saving_scene_agent.h" #import "ios/chrome/browser/sessions/session_service_ios.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_scene_agent.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_ui_provider.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" #import "ios/chrome/browser/shared/public/commands/browser_commands.h" @@ -117,7 +118,6 @@ #import "ios/chrome/browser/ui/main/browser_view_wrangler.h" #import "ios/chrome/browser/ui/main/default_browser_scene_agent.h" #import "ios/chrome/browser/ui/main/incognito_blocker_scene_agent.h" -#import "ios/chrome/browser/ui/main/layout_guide_scene_agent.h" #import "ios/chrome/browser/ui/main/ui_blocker_scene_agent.h" #import "ios/chrome/browser/ui/ntp/new_tab_page_feature.h" #import "ios/chrome/browser/ui/policy/signin_policy_scene_agent.h"
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn index 7c1e4d0c..0846e52 100644 --- a/ios/chrome/browser/ui/browser_view/BUILD.gn +++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -92,6 +92,7 @@ "//ios/chrome/browser/sessions:serialisation", "//ios/chrome/browser/shared/coordinator/alert", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", + "//ios/chrome/browser/shared/coordinator/layout_guide", "//ios/chrome/browser/shared/coordinator/scene:scene_state_browser_agent", "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", "//ios/chrome/browser/shared/public/commands", @@ -145,7 +146,6 @@ "//ios/chrome/browser/ui/lens:coordinator", "//ios/chrome/browser/ui/main:browser_interface_provider", "//ios/chrome/browser/ui/main:default_browser_scene_agent", - "//ios/chrome/browser/ui/main:layout_guide_util", "//ios/chrome/browser/ui/main_content:main_content_ui", "//ios/chrome/browser/ui/main_content:main_content_ui_broadcasting_util", "//ios/chrome/browser/ui/ntp",
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm index 7712301..26571a5d 100644 --- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm +++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -13,7 +13,6 @@ #import "components/feature_engagement/public/tracker.h" #import "components/password_manager/core/common/password_manager_features.h" #import "components/profile_metrics/browser_profile_type.h" -#import "components/reading_list/core/reading_list_model.h" #import "components/safe_browsing/core/common/features.h" #import "components/signin/ios/browser/active_state_manager.h" #import "components/translate/core/browser/translate_manager.h" @@ -42,9 +41,10 @@ #import "ios/chrome/browser/prerender/prerender_service.h" #import "ios/chrome/browser/prerender/prerender_service_factory.h" #import "ios/chrome/browser/promos_manager/features.h" -#import "ios/chrome/browser/reading_list/reading_list_model_factory.h" +#import "ios/chrome/browser/reading_list/reading_list_browser_agent.h" #import "ios/chrome/browser/sessions/session_restoration_browser_agent.h" #import "ios/chrome/browser/shared/coordinator/alert/repost_form_coordinator.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_state_browser_agent.h" #import "ios/chrome/browser/shared/public/commands/activity_service_commands.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" @@ -67,7 +67,6 @@ #import "ios/chrome/browser/shared/public/commands/qr_generation_commands.h" #import "ios/chrome/browser/shared/public/commands/share_highlight_command.h" #import "ios/chrome/browser/shared/public/commands/show_signin_command.h" -#import "ios/chrome/browser/shared/public/commands/snackbar_commands.h" #import "ios/chrome/browser/shared/public/commands/text_zoom_commands.h" #import "ios/chrome/browser/shared/public/commands/web_content_commands.h" #import "ios/chrome/browser/shared/public/commands/whats_new_commands.h" @@ -125,7 +124,6 @@ #import "ios/chrome/browser/ui/lens/lens_coordinator.h" #import "ios/chrome/browser/ui/main/browser_interface_provider.h" #import "ios/chrome/browser/ui/main/default_browser_scene_agent.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/ntp/new_tab_page_component_factory.h" #import "ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h" #import "ios/chrome/browser/ui/open_in/features.h" @@ -665,6 +663,8 @@ dependencies:_viewControllerDependencies]; self.tabLifecycleMediator.baseViewController = self.viewController; self.tabLifecycleMediator.delegate = self.viewController; + _viewController.readingListBrowserAgent = + ReadingListBrowserAgent::FromBrowser(self.browser); WebNavigationBrowserAgent::FromBrowser(self.browser)->SetDelegate(self); @@ -871,19 +871,12 @@ HandlerForProtocol(_dispatcher, HelpCommands); _viewControllerDependencies.popupMenuCommandsHandler = HandlerForProtocol(_dispatcher, PopupMenuCommands); - // TODO(crbug.com/1413769) SnackbarCoordinator is not created yet and - // therefore not dispatching SnackbarCommands. Typecast should be performed - // using HandlerForProtocol method. - _viewControllerDependencies.snackbarCommandsHandler = - static_cast<id<SnackbarCommands>>(_dispatcher); _viewControllerDependencies.applicationCommandsHandler = HandlerForProtocol(_dispatcher, ApplicationCommands); _viewControllerDependencies.browserCoordinatorCommandsHandler = HandlerForProtocol(_dispatcher, BrowserCoordinatorCommands); _viewControllerDependencies.findInPageCommandsHandler = HandlerForProtocol(_dispatcher, FindInPageCommands); - _viewControllerDependencies.toolbarCommandsHandler = - HandlerForProtocol(_dispatcher, ToolbarCommands); _viewControllerDependencies.loadQueryCommandsHandler = _loadQueryCommandsHandler; // TODO(crbug.com/1413769) Typecast should be performed using @@ -904,9 +897,6 @@ LayoutGuideCenterForBrowser(self.browser); _viewControllerDependencies.webStateList = self.browser->GetWebStateList()->AsWeakPtr(); - _viewControllerDependencies.readingModel = - ReadingListModelFactory::GetForBrowserState( - self.browser->GetBrowserState()); _viewControllerDependencies.voiceSearchController = _voiceSearchController; _viewControllerDependencies.secondaryToolbarContainerCoordinator = [[ToolbarContainerCoordinator alloc] @@ -966,14 +956,11 @@ _viewControllerDependencies.textZoomHandler = nil; _viewControllerDependencies.helpHandler = nil; _viewControllerDependencies.popupMenuCommandsHandler = nil; - _viewControllerDependencies.snackbarCommandsHandler = nil; _viewControllerDependencies.applicationCommandsHandler = nil; _viewControllerDependencies.browserCoordinatorCommandsHandler = nil; _viewControllerDependencies.findInPageCommandsHandler = nil; - _viewControllerDependencies.toolbarCommandsHandler = nil; _viewControllerDependencies.loadQueryCommandsHandler = nil; _viewControllerDependencies.omniboxCommandsHandler = nil; - _viewControllerDependencies.readingModel = nil; _viewControllerDependencies.voiceSearchController = nil; _viewControllerDependencies.secondaryToolbarContainerCoordinator = nil; _viewControllerDependencies.safeAreaProvider = nil;
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm index d0d7700..741e6923 100644 --- a/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm
@@ -111,7 +111,7 @@ chrome_browser_state_.get(), std::make_unique<FakeAuthenticationServiceDelegate>()); SessionRestorationBrowserAgent::CreateForBrowser( - browser_.get(), [[TestSessionService alloc] init]); + browser_.get(), [[TestSessionService alloc] init], false); SessionRestorationBrowserAgent::FromBrowser(browser_.get()) ->SetSessionID([[NSUUID UUID] UUIDString]);
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.h b/ios/chrome/browser/ui/browser_view/browser_view_controller.h index dd5e454..ec50270 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.h +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.h
@@ -10,8 +10,8 @@ #import "base/ios/block_types.h" #import "base/memory/weak_ptr.h" -#import "components/reading_list/core/reading_list_model.h" #import "ios/chrome/browser/metrics/tab_usage_recorder_browser_agent.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/public/commands/browser_commands.h" #import "ios/chrome/browser/ui/authentication/signin_presenter.h" #import "ios/chrome/browser/ui/browser_view/key_commands_provider.h" @@ -19,7 +19,6 @@ #import "ios/chrome/browser/ui/browser_view/tab_consumer.h" #import "ios/chrome/browser/ui/find_bar/find_bar_coordinator.h" #import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_consumer.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/ntp/logo_animation_controller.h" #import "ios/chrome/browser/ui/omnibox/omnibox_focus_delegate.h" #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_presenter.h" @@ -58,21 +57,19 @@ @protocol PopupMenuUIUpdating; class PrerenderService; @class PrimaryToolbarCoordinator; +class ReadingListBrowserAgent; @class SafeAreaProvider; @class SecondaryToolbarCoordinator; @class SideSwipeController; -@protocol SnackbarCommands; @class TabStripCoordinator; @class TabStripLegacyCoordinator; class TabUsageRecorderBrowserAgent; @protocol TextZoomCommands; @class ToolbarAccessoryPresenter; -@protocol ToolbarCommands; @class ToolbarContainerCoordinator; @protocol IncognitoReauthCommands; @class LayoutGuideCenter; @protocol LoadQueryCommands; -class ReadingListModel; class UrlLoadingBrowserAgent; class UrlLoadingNotifierBrowserAgent; @protocol VoiceSearchController; @@ -96,17 +93,14 @@ id<TextZoomCommands> textZoomHandler; id<HelpCommands> helpHandler; id<PopupMenuCommands> popupMenuCommandsHandler; - id<SnackbarCommands> snackbarCommandsHandler; id<ApplicationCommands> applicationCommandsHandler; id<BrowserCoordinatorCommands> browserCoordinatorCommandsHandler; id<FindInPageCommands> findInPageCommandsHandler; - id<ToolbarCommands> toolbarCommandsHandler; id<LoadQueryCommands> loadQueryCommandsHandler; LayoutGuideCenter* layoutGuideCenter; id<OmniboxCommands> omniboxCommandsHandler; BOOL isOffTheRecord; PagePlaceholderBrowserAgent* pagePlaceholderBrowserAgent; - ReadingListModel* readingModel; UrlLoadingBrowserAgent* urlLoadingBrowserAgent; UrlLoadingNotifierBrowserAgent* urlLoadingNotifierBrowserAgent; id<VoiceSearchController> voiceSearchController; @@ -172,6 +166,9 @@ @property(nonatomic, weak) id<DefaultPromoNonModalPresentationDelegate> nonModalPromoPresentationDelegate; +// TODO(crbug.com/1272540): Remove this command. +@property(nonatomic) ReadingListBrowserAgent* readingListBrowserAgent; + // Whether the receiver is currently the primary BVC. - (void)setPrimary:(BOOL)primary;
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm index 7746e03..a67652c 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -6,15 +6,9 @@ #import "ios/chrome/browser/ui/browser_view/browser_view_controller+delegates.h" #import "ios/chrome/browser/ui/browser_view/browser_view_controller+private.h" -#import <MaterialComponents/MaterialSnackbar.h> - -#import "base/i18n/message_formatter.h" #import "base/mac/bundle_locations.h" #import "base/mac/foundation_util.h" -#import "base/metrics/user_metrics.h" -#import "base/metrics/user_metrics_action.h" #import "base/strings/sys_string_conversions.h" -#import "base/strings/utf_string_conversions.h" #import "base/task/sequenced_task_runner.h" #import "components/password_manager/core/browser/ui/credential_ui_entry.h" #import "components/signin/public/identity_manager/identity_manager.h" @@ -30,13 +24,13 @@ #import "ios/chrome/browser/ntp/new_tab_page_util.h" #import "ios/chrome/browser/overscroll_actions/overscroll_actions_tab_helper.h" #import "ios/chrome/browser/prerender/prerender_service.h" +#import "ios/chrome/browser/reading_list/reading_list_browser_agent.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" #import "ios/chrome/browser/shared/public/commands/browser_coordinator_commands.h" #import "ios/chrome/browser/shared/public/commands/find_in_page_commands.h" #import "ios/chrome/browser/shared/public/commands/help_commands.h" #import "ios/chrome/browser/shared/public/commands/popup_menu_commands.h" #import "ios/chrome/browser/shared/public/commands/reading_list_add_command.h" -#import "ios/chrome/browser/shared/public/commands/snackbar_commands.h" #import "ios/chrome/browser/shared/public/commands/text_zoom_commands.h" #import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/shared/ui/util/named_guide.h" @@ -116,8 +110,6 @@ #error "This file requires ARC support." #endif -using base::UserMetricsAction; - namespace { // When the tab strip moves beyond this origin offset, switch the status bar @@ -130,11 +122,6 @@ // This header stay on screen and covers part of the content. Overlap }; - -// Snackbar category for browser view controller. -NSString* const kBrowserViewControllerSnackbarCategory = - @"BrowserViewControllerSnackbarCategory"; - } // namespace #pragma mark - ToolbarContainerView @@ -299,8 +286,6 @@ // Used to get the layout guide center. LayoutGuideCenter* _layoutGuideCenter; - ReadingListModel* _readingModel; - // Used to add or cancel a page placeholder for next navigation. PagePlaceholderBrowserAgent* _pagePlaceholderBrowserAgent; } @@ -380,9 +365,6 @@ // Command handler for popup menu commands @property(nonatomic, weak) id<PopupMenuCommands> popupMenuCommandsHandler; -// Command handler for snackbar commands -@property(nonatomic, weak) id<SnackbarCommands> snackbarCommandsHandler; - // Command handler for application commands @property(nonatomic, weak) id<ApplicationCommands> applicationCommandsHandler; @@ -393,9 +375,6 @@ // Command handler for find in page commands @property(nonatomic, weak) id<FindInPageCommands> findInPageCommandsHandler; -// Command handler for toolbar commands -@property(nonatomic, weak) id<ToolbarCommands> toolbarCommandsHandler; - // The FullscreenController. @property(nonatomic, assign) FullscreenController* fullscreenController; @@ -486,12 +465,10 @@ self.textZoomHandler = dependencies.textZoomHandler; self.helpHandler = dependencies.helpHandler; self.popupMenuCommandsHandler = dependencies.popupMenuCommandsHandler; - self.snackbarCommandsHandler = dependencies.snackbarCommandsHandler; self.applicationCommandsHandler = dependencies.applicationCommandsHandler; self.browserCoordinatorCommandsHandler = dependencies.browserCoordinatorCommandsHandler; self.findInPageCommandsHandler = dependencies.findInPageCommandsHandler; - self.toolbarCommandsHandler = dependencies.toolbarCommandsHandler; self.loadQueryCommandsHandler = dependencies.loadQueryCommandsHandler; self.omniboxCommandsHandler = dependencies.omniboxCommandsHandler; _isOffTheRecord = dependencies.isOffTheRecord; @@ -502,7 +479,6 @@ _webNavigationBrowserAgent = dependencies.webNavigationBrowserAgent; _layoutGuideCenter = dependencies.layoutGuideCenter; _webStateList = dependencies.webStateList; - _readingModel = dependencies.readingModel; _voiceSearchController = dependencies.voiceSearchController; self.secondaryToolbarContainerCoordinator = dependencies.secondaryToolbarContainerCoordinator; @@ -972,7 +948,6 @@ [_voiceSearchController disconnect]; _fullscreenDisabler = nullptr; [[NSNotificationCenter defaultCenter] removeObserver:self]; - _bookmarksCoordinator = nil; } @@ -2056,73 +2031,6 @@ } #pragma mark - Private Methods: Reading List -// TODO(crbug.com/1272540): Remove these methods from the BVC. - -// Adds the given urls to the reading list. -- (void)addURLsToReadingList:(NSArray<URLWithTitle*>*)URLs { - DCHECK(URLs.count > 0) << "URLs are missing"; - - for (URLWithTitle* urlWithTitle in URLs) { - [self addURLToReadingList:urlWithTitle.URL withTitle:urlWithTitle.title]; - } - - TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess); - - // The identity manager should not be null in incognito mode, as the new items - // are added to the original account's reading list if the user is signed in. - // To reduce the risk of misuse, it is not added as a property to the BVC, - // and will be moved outside of BVC in https://crbug.com/1272540 soon. - signin::IdentityManager* identityManager = - IdentityManagerFactory::GetForBrowserState( - self.browserState->GetOriginalChromeBrowserState()); - CoreAccountId accountId = - _readingModel->GetAccountWhereEntryIsSavedTo(URLs.lastObject.URL); - AccountInfo accountInfo = - identityManager->FindExtendedAccountInfoByAccountId(accountId); - - NSString* snackbarText = nil; - if (!accountInfo.IsEmpty() && - base::FeatureList::IsEnabled( - kEnableEmailInBookmarksReadingListSnackbar)) { - std::u16string pattern = l10n_util::GetStringUTF16( - IDS_IOS_READING_LIST_SNACKBAR_MESSAGE_FOR_ACCOUNT); - std::u16string utf16Text = - base::i18n::MessageFormatter::FormatWithNamedArgs( - pattern, "count", (int)URLs.count, "email", accountInfo.email); - snackbarText = base::SysUTF16ToNSString(utf16Text); - } else { - snackbarText = - l10n_util::GetNSString(IDS_IOS_READING_LIST_SNACKBAR_MESSAGE); - } - - MDCSnackbarMessage* message = - [MDCSnackbarMessage messageWithText:snackbarText]; - message.accessibilityLabel = snackbarText; - message.duration = 2.0; - message.category = kBrowserViewControllerSnackbarCategory; - - [self.snackbarCommandsHandler showSnackbarMessage:message]; -} - -- (void)addURLToReadingList:(const GURL&)URL withTitle:(NSString*)title { - if (self.currentWebState && - self.currentWebState->GetVisibleURL().spec() == URL.spec()) { - // Log UKM if the current page is being added to Reading List. - ukm::SourceId sourceID = - ukm::GetSourceIdForWebStateDocument(self.currentWebState); - if (sourceID != ukm::kInvalidSourceId) { - ukm::builders::IOS_PageAddedToReadingList(sourceID) - .SetAddedFromMessages(false) - .Record(ukm::UkmRecorder::Get()); - } - } - - base::RecordAction(UserMetricsAction("MobileReadingListAdd")); - - _readingModel->AddOrReplaceEntry(URL, base::SysNSStringToUTF8(title), - reading_list::ADDED_VIA_CURRENT_APP, - /*estimated_read_time=*/base::TimeDelta()); -} // TODO(crbug.com/1345210) Remove `isNTPActiveForCurrentWebState` method from // BVC @@ -2943,7 +2851,7 @@ // TODO(crbug.com/1272540): Remove this command and factor it into a model // update helper function as part of the reading list API. - (void)addToReadingList:(ReadingListAddCommand*)command { - [self addURLsToReadingList:command.URLs]; + self.readingListBrowserAgent->AddURLsToReadingList(command.URLs); } - (void)prepareForOverflowMenuPresentation { @@ -3369,7 +3277,7 @@ self.secondaryToolbarContainerView.accessibilityElementsHidden = NO; } -#pragma mark - LensPresentationDelegate: +#pragma mark - LensPresentationDelegate - (CGRect)webContentAreaForLensCoordinator:(LensCoordinator*)lensCoordinator { DCHECK(lensCoordinator);
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm index caaf082..6869a18f 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
@@ -11,9 +11,7 @@ #import <memory> #import "components/open_from_clipboard/fake_clipboard_recent_content.h" -#import "components/reading_list/core/reading_list_model.h" #import "components/search_engines/template_url_service.h" -#import "components/signin/public/identity_manager/identity_manager.h" #import "ios/chrome/browser/bookmarks/local_or_syncable_bookmark_model_factory.h" #import "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #import "ios/chrome/browser/favicon/favicon_service_factory.h" @@ -24,7 +22,6 @@ #import "ios/chrome/browser/main/test_browser.h" #import "ios/chrome/browser/metrics/tab_usage_recorder_browser_agent.h" #import "ios/chrome/browser/prerender/fake_prerender_service.h" -#import "ios/chrome/browser/reading_list/reading_list_model_factory.h" #import "ios/chrome/browser/search_engines/template_url_service_factory.h" #import "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h" #import "ios/chrome/browser/sessions/session_restoration_browser_agent.h" @@ -42,7 +39,6 @@ #import "ios/chrome/browser/shared/public/commands/text_zoom_commands.h" #import "ios/chrome/browser/signin/authentication_service_factory.h" #import "ios/chrome/browser/signin/fake_authentication_service_delegate.h" -#import "ios/chrome/browser/signin/identity_manager_factory.h" #import "ios/chrome/browser/tabs/tab_helper_util.h" #import "ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h" #import "ios/chrome/browser/ui/browser_container/browser_container_view_controller.h" @@ -145,7 +141,7 @@ ->SetWebUsageEnabled(true); SessionRestorationBrowserAgent::CreateForBrowser( - browser_.get(), [[TestSessionService alloc] init]); + browser_.get(), [[TestSessionService alloc] init], false); SessionRestorationBrowserAgent::FromBrowser(browser_.get()) ->SetSessionID([[NSUUID UUID] UUIDString]); @@ -284,8 +280,6 @@ dependencies.layoutGuideCenter = LayoutGuideCenterForBrowser(browser_.get()); dependencies.webStateList = browser_->GetWebStateList()->AsWeakPtr(); - dependencies.readingModel = ReadingListModelFactory::GetForBrowserState( - browser_.get()->GetBrowserState()); dependencies.secondaryToolbarContainerCoordinator = [[ToolbarContainerCoordinator alloc] initWithBrowser:browser_.get()
diff --git a/ios/chrome/browser/ui/browser_view/key_commands_provider.mm b/ios/chrome/browser/ui/browser_view/key_commands_provider.mm index f4c239d..49afe2a 100644 --- a/ios/chrome/browser/ui/browser_view/key_commands_provider.mm +++ b/ios/chrome/browser/ui/browser_view/key_commands_provider.mm
@@ -18,6 +18,7 @@ #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/ntp/new_tab_page_util.h" #import "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/public/commands/bookmark_add_command.h" #import "ios/chrome/browser/shared/public/commands/bookmarks_commands.h" #import "ios/chrome/browser/shared/public/commands/open_new_tab_command.h" @@ -29,7 +30,6 @@ #import "ios/chrome/browser/shared/ui/util/util_swift.h" #import "ios/chrome/browser/tabs/tab_title_util.h" #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/url/chrome_url_constants.h" #import "ios/chrome/browser/url_loading/url_loading_util.h" #import "ios/chrome/browser/web/web_navigation_browser_agent.h"
diff --git a/ios/chrome/browser/ui/download/BUILD.gn b/ios/chrome/browser/ui/download/BUILD.gn index 307e24f5..4c24622d 100644 --- a/ios/chrome/browser/ui/download/BUILD.gn +++ b/ios/chrome/browser/ui/download/BUILD.gn
@@ -42,13 +42,13 @@ "//ios/chrome/browser/overlays/public/common/confirmation", "//ios/chrome/browser/shared/coordinator/alert", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", + "//ios/chrome/browser/shared/coordinator/layout_guide", "//ios/chrome/browser/shared/public/commands", "//ios/chrome/browser/shared/public/features", "//ios/chrome/browser/shared/ui/symbols", "//ios/chrome/browser/shared/ui/util", "//ios/chrome/browser/store_kit", "//ios/chrome/browser/ui/download/activities", - "//ios/chrome/browser/ui/main:layout_guide_util", "//ios/chrome/browser/ui/presenters", "//ios/chrome/browser/web:web_internal", "//ios/chrome/browser/web_state_list:web_state_list",
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator.mm b/ios/chrome/browser/ui/download/download_manager_coordinator.mm index 2cee662..d57b030f 100644 --- a/ios/chrome/browser/ui/download/download_manager_coordinator.mm +++ b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
@@ -31,13 +31,13 @@ #import "ios/chrome/browser/overlays/public/common/confirmation/confirmation_overlay_response.h" #import "ios/chrome/browser/overlays/public/overlay_callback_manager.h" #import "ios/chrome/browser/overlays/public/overlay_request_queue.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/public/commands/browser_coordinator_commands.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" #import "ios/chrome/browser/store_kit/store_kit_coordinator.h" #import "ios/chrome/browser/ui/download/activities/open_downloads_folder_activity.h" #import "ios/chrome/browser/ui/download/download_manager_mediator.h" #import "ios/chrome/browser/ui/download/download_manager_view_controller.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/presenters/contained_presenter.h" #import "ios/chrome/browser/ui/presenters/contained_presenter_delegate.h" #import "ios/chrome/browser/web_state_list/web_state_list.h"
diff --git a/ios/chrome/browser/ui/location_bar/BUILD.gn b/ios/chrome/browser/ui/location_bar/BUILD.gn index 8686d33..f7b5443 100644 --- a/ios/chrome/browser/ui/location_bar/BUILD.gn +++ b/ios/chrome/browser/ui/location_bar/BUILD.gn
@@ -51,6 +51,7 @@ "//ios/chrome/browser/search_engines", "//ios/chrome/browser/search_engines:search_engines_util", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", + "//ios/chrome/browser/shared/coordinator/layout_guide", "//ios/chrome/browser/shared/coordinator/scene:scene_state_browser_agent", "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", "//ios/chrome/browser/shared/public/commands", @@ -66,7 +67,6 @@ "//ios/chrome/browser/ui/fullscreen:ui", "//ios/chrome/browser/ui/lens:lens_entrypoint", "//ios/chrome/browser/ui/main:default_browser_scene_agent", - "//ios/chrome/browser/ui/main:layout_guide_util", "//ios/chrome/browser/ui/omnibox:omnibox", "//ios/chrome/browser/ui/omnibox:omnibox_internal", "//ios/chrome/browser/ui/omnibox:omnibox_popup_shared",
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm index 7313d39..c7aae70 100644 --- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm +++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -31,6 +31,7 @@ #import "ios/chrome/browser/ntp/new_tab_page_util.h" #import "ios/chrome/browser/overlays/public/overlay_presenter.h" #import "ios/chrome/browser/search_engines/template_url_service_factory.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_state_browser_agent.h" #import "ios/chrome/browser/shared/public/commands/browser_coordinator_commands.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" @@ -55,7 +56,6 @@ #import "ios/chrome/browser/ui/location_bar/location_bar_url_loader.h" #import "ios/chrome/browser/ui/location_bar/location_bar_view_controller.h" #import "ios/chrome/browser/ui/main/default_browser_scene_agent.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/omnibox/omnibox_controller_delegate.h" #import "ios/chrome/browser/ui/omnibox/omnibox_coordinator.h" #import "ios/chrome/browser/ui/omnibox/omnibox_focus_delegate.h"
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn index 659478a..54a616dd 100644 --- a/ios/chrome/browser/ui/main/BUILD.gn +++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -38,34 +38,6 @@ frameworks = [ "UIKit.framework" ] } -source_set("layout_guide_scene_agent") { - configs += [ "//build/config/compiler:enable_arc" ] - sources = [ - "layout_guide_scene_agent.h", - "layout_guide_scene_agent.mm", - ] - deps = [ - "//base", - "//ios/chrome/browser/shared/coordinator/scene:observing_scene_agent", - "//ios/chrome/browser/shared/ui/util:util_swift", - ] - frameworks = [ "UIKit.framework" ] -} - -source_set("layout_guide_util") { - configs += [ "//build/config/compiler:enable_arc" ] - sources = [ - "layout_guide_util.h", - "layout_guide_util.mm", - ] - deps = [ - ":layout_guide_scene_agent", - "//ios/chrome/browser/browser_state", - "//ios/chrome/browser/shared/coordinator/scene:scene_state_browser_agent", - "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", - ] -} - source_set("scene") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ @@ -176,12 +148,10 @@ "browser_view_wrangler_unittest.mm", "default_browser_scene_agent_unittest.mm", "incognito_blocker_scene_agent_unittest.mm", - "layout_guide_scene_agent_unittest.mm", ] deps = [ ":default_browser_scene_agent", ":incognito_blocker_scene_agent", - ":layout_guide_scene_agent", ":main", "//base", "//base/test:test_support",
diff --git a/ios/chrome/browser/ui/main/layout_guide_util.h b/ios/chrome/browser/ui/main/layout_guide_util.h deleted file mode 100644 index 520d576..0000000 --- a/ios/chrome/browser/ui/main/layout_guide_util.h +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_MAIN_LAYOUT_GUIDE_UTIL_H_ -#define IOS_CHROME_BROWSER_UI_MAIN_LAYOUT_GUIDE_UTIL_H_ - -class Browser; -@class LayoutGuideCenter; - -// Returns the layout guide center assigned to the given `browser`. If there is -// none, it returns a global shared layout guide center. -LayoutGuideCenter* LayoutGuideCenterForBrowser(Browser* browser); - -#endif // IOS_CHROME_BROWSER_UI_MAIN_LAYOUT_GUIDE_UTIL_H_
diff --git a/ios/chrome/browser/ui/ntp/BUILD.gn b/ios/chrome/browser/ui/ntp/BUILD.gn index 380dab01..b3cffe4d 100644 --- a/ios/chrome/browser/ui/ntp/BUILD.gn +++ b/ios/chrome/browser/ui/ntp/BUILD.gn
@@ -112,6 +112,7 @@ "//ios/chrome/browser/search_engines", "//ios/chrome/browser/shared/coordinator/alert", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", + "//ios/chrome/browser/shared/coordinator/layout_guide", "//ios/chrome/browser/shared/coordinator/scene:scene_state_browser_agent", "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", "//ios/chrome/browser/shared/coordinator/scene:scene_state_observer", @@ -129,7 +130,6 @@ "//ios/chrome/browser/ui/content_suggestions:metrics", "//ios/chrome/browser/ui/context_menu/link_preview", "//ios/chrome/browser/ui/follow", - "//ios/chrome/browser/ui/main:layout_guide_util", "//ios/chrome/browser/ui/ntp/feed_management", "//ios/chrome/browser/ui/ntp/feed_promos", "//ios/chrome/browser/ui/ntp/feed_top_section",
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm index 76416da..e887b4e2 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -42,6 +42,7 @@ #import "ios/chrome/browser/prefs/pref_names.h" #import "ios/chrome/browser/search_engines/template_url_service_factory.h" #import "ios/chrome/browser/shared/coordinator/alert/action_sheet_coordinator.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_state.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_state_browser_agent.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" @@ -69,7 +70,6 @@ #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h" #import "ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h" #import "ios/chrome/browser/ui/context_menu/link_preview/link_preview_coordinator.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/ntp/discover_feed_constants.h" #import "ios/chrome/browser/ui/ntp/discover_feed_preview_delegate.h" #import "ios/chrome/browser/ui/ntp/feed_control_delegate.h"
diff --git a/ios/chrome/browser/ui/omnibox/BUILD.gn b/ios/chrome/browser/ui/omnibox/BUILD.gn index 227eb62..7080d709 100644 --- a/ios/chrome/browser/ui/omnibox/BUILD.gn +++ b/ios/chrome/browser/ui/omnibox/BUILD.gn
@@ -170,6 +170,7 @@ "//ios/chrome/browser/search_engines:search_engines_util", "//ios/chrome/browser/sessions", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", + "//ios/chrome/browser/shared/coordinator/layout_guide", "//ios/chrome/browser/shared/coordinator/scene:scene_state_browser_agent", "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", "//ios/chrome/browser/shared/public/commands", @@ -181,7 +182,6 @@ "//ios/chrome/browser/ui/lens:lens_entrypoint", "//ios/chrome/browser/ui/location_bar:constants", "//ios/chrome/browser/ui/main:default_browser_scene_agent", - "//ios/chrome/browser/ui/main:layout_guide_util", "//ios/chrome/browser/ui/omnibox/popup", "//ios/chrome/browser/ui/omnibox/popup:popup_ui_protocols", "//ios/chrome/browser/ui/orchestrator:orchestrator",
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm index c7f28f9..b0ff6f63 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
@@ -21,6 +21,7 @@ #import "ios/chrome/browser/feature_engagement/tracker_factory.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/search_engines/template_url_service_factory.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_state_browser_agent.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" #import "ios/chrome/browser/shared/public/commands/browser_commands.h" @@ -35,7 +36,6 @@ #import "ios/chrome/browser/ui/gestures/view_revealing_animatee.h" #import "ios/chrome/browser/ui/location_bar/location_bar_constants.h" #import "ios/chrome/browser/ui/main/default_browser_scene_agent.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/omnibox/keyboard_assist/omnibox_assistive_keyboard_delegate.h" #import "ios/chrome/browser/ui/omnibox/keyboard_assist/omnibox_assistive_keyboard_views.h" #import "ios/chrome/browser/ui/omnibox/keyboard_assist/omnibox_keyboard_accessory_view.h"
diff --git a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn index 6c3228e..5ae113b 100644 --- a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn +++ b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
@@ -87,6 +87,7 @@ "//ios/chrome/browser/policy:policy_util", "//ios/chrome/browser/search_engines", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", + "//ios/chrome/browser/shared/coordinator/layout_guide", "//ios/chrome/browser/shared/coordinator/scene:scene_state_browser_agent", "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", "//ios/chrome/browser/shared/public/commands", @@ -97,7 +98,6 @@ "//ios/chrome/browser/ui/default_promo", "//ios/chrome/browser/ui/favicon", "//ios/chrome/browser/ui/main:default_browser_scene_agent", - "//ios/chrome/browser/ui/main:layout_guide_util", "//ios/chrome/browser/ui/menu", "//ios/chrome/browser/ui/omnibox:features", "//ios/chrome/browser/ui/omnibox:omnibox_util",
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm index 52036f8..3b08e51 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
@@ -25,6 +25,7 @@ #import "ios/chrome/browser/ntp/new_tab_page_util.h" #import "ios/chrome/browser/policy/policy_util.h" #import "ios/chrome/browser/search_engines/template_url_service_factory.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_state_browser_agent.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" @@ -33,7 +34,6 @@ #import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/ui/favicon/favicon_attributes_provider.h" #import "ios/chrome/browser/ui/main/default_browser_scene_agent.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/menu/browser_action_factory.h" #import "ios/chrome/browser/ui/omnibox/omnibox_ui_features.h" #import "ios/chrome/browser/ui/omnibox/popup/carousel_item.h"
diff --git a/ios/chrome/browser/ui/open_in/BUILD.gn b/ios/chrome/browser/ui/open_in/BUILD.gn index e6a681e..a4a54404 100644 --- a/ios/chrome/browser/ui/open_in/BUILD.gn +++ b/ios/chrome/browser/ui/open_in/BUILD.gn
@@ -23,8 +23,8 @@ "//ios/chrome/browser/main:public", "//ios/chrome/browser/open_in", "//ios/chrome/browser/shared/coordinator/alert", + "//ios/chrome/browser/shared/coordinator/layout_guide", "//ios/chrome/browser/shared/ui/util", - "//ios/chrome/browser/ui/main:layout_guide_util", "//ios/chrome/browser/ui/sharing/activity_services", "//ios/chrome/common/ui/colors", "//ios/chrome/common/ui/util", @@ -80,7 +80,7 @@ ":open_in_ui", "//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/main:test_support", - "//ios/chrome/browser/ui/main:layout_guide_util", + "//ios/chrome/browser/shared/coordinator/layout_guide", "//ios/chrome/browser/web_state_list", "//ios/chrome/browser/web_state_list:test_support", "//ios/web/public/test",
diff --git a/ios/chrome/browser/ui/open_in/open_in_controller.mm b/ios/chrome/browser/ui/open_in/open_in_controller.mm index d1793579..47828a32 100644 --- a/ios/chrome/browser/ui/open_in/open_in_controller.mm +++ b/ios/chrome/browser/ui/open_in/open_in_controller.mm
@@ -21,10 +21,10 @@ #import "base/threading/scoped_blocking_call.h" #import "components/strings/grit/components_strings.h" #import "ios/chrome/browser/shared/coordinator/alert/alert_coordinator.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/ui/util/layout_guide_names.h" #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h" #import "ios/chrome/browser/shared/ui/util/util_swift.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/open_in/features.h" #import "ios/chrome/browser/ui/open_in/open_in_activity_delegate.h" #import "ios/chrome/browser/ui/open_in/open_in_activity_view_controller.h"
diff --git a/ios/chrome/browser/ui/popup_menu/BUILD.gn b/ios/chrome/browser/ui/popup_menu/BUILD.gn index 207dd92..e641b35 100644 --- a/ios/chrome/browser/ui/popup_menu/BUILD.gn +++ b/ios/chrome/browser/ui/popup_menu/BUILD.gn
@@ -78,6 +78,7 @@ "//ios/chrome/browser/search_engines", "//ios/chrome/browser/search_engines:search_engines_util", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", + "//ios/chrome/browser/shared/coordinator/layout_guide", "//ios/chrome/browser/shared/coordinator/scene:scene_state_browser_agent", "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", "//ios/chrome/browser/shared/public/commands", @@ -94,7 +95,6 @@ "//ios/chrome/browser/ui/bubble", "//ios/chrome/browser/ui/content_suggestions/cells:constants", "//ios/chrome/browser/ui/lens:lens_entrypoint", - "//ios/chrome/browser/ui/main:layout_guide_util", "//ios/chrome/browser/ui/ntp/metrics", "//ios/chrome/browser/ui/popup_menu:metrics_protocols", "//ios/chrome/browser/ui/popup_menu/cells",
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm index 1918fd1..be2e1aa 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
@@ -25,6 +25,7 @@ #import "ios/chrome/browser/promos_manager/promos_manager_factory.h" #import "ios/chrome/browser/reading_list/reading_list_model_factory.h" #import "ios/chrome/browser/search_engines/template_url_service_factory.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/public/commands/bookmarks_commands.h" #import "ios/chrome/browser/shared/public/commands/browser_commands.h" #import "ios/chrome/browser/shared/public/commands/browser_coordinator_commands.h" @@ -44,7 +45,6 @@ #import "ios/chrome/browser/ui/browser_container/browser_container_mediator.h" #import "ios/chrome/browser/ui/bubble/bubble_presenter.h" #import "ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.h" #import "ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.h" #import "ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_swift.h"
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_help_coordinator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_help_coordinator.mm index 53297e8..9cc9154 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_help_coordinator.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_help_coordinator.mm
@@ -12,13 +12,13 @@ #import "ios/chrome/app/tests_hook.h" #import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/feature_engagement/tracker_factory.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_state.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_state_browser_agent.h" #import "ios/chrome/browser/shared/ui/util/layout_guide_names.h" #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h" #import "ios/chrome/browser/shared/ui/util/util_swift.h" #import "ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.h" #import "ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_swift.h" #import "ios/chrome/browser/ui/popup_menu/public/popup_menu_ui_updating.h"
diff --git a/ios/chrome/browser/ui/reading_list/BUILD.gn b/ios/chrome/browser/ui/reading_list/BUILD.gn index 0171ba6..4f59bea 100644 --- a/ios/chrome/browser/ui/reading_list/BUILD.gn +++ b/ios/chrome/browser/ui/reading_list/BUILD.gn
@@ -33,6 +33,7 @@ "//components/reading_list/features:flags", "//components/reading_list/ios", "//components/signin/public/identity_manager/objc", + "//components/ukm/ios:ukm_url_recorder", "//components/url_formatter", "//ios/chrome/app/strings", "//ios/chrome/browser/browser_state", @@ -51,6 +52,7 @@ "//ios/chrome/browser/shared/ui/table_view", "//ios/chrome/browser/shared/ui/table_view:styler", "//ios/chrome/browser/shared/ui/table_view/cells", + "//ios/chrome/browser/shared/ui/util:url_with_title", "//ios/chrome/browser/signin", "//ios/chrome/browser/sync", "//ios/chrome/browser/tabs", @@ -71,14 +73,17 @@ "//ios/chrome/common/ui/favicon", "//ios/chrome/common/ui/favicon:favicon_constants", "//ios/chrome/common/ui/table_view", + "//ios/third_party/material_components_ios", "//ios/web", "//ios/web/common", "//ios/web/public", + "//services/metrics/public/cpp:ukm_builders", "//ui/base", "//ui/strings", "//url", ] allow_circular_includes_from = [ "//ios/chrome/browser/ui/side_swipe" ] + public_deps = [ "//ios/third_party/material_components_ios" ] frameworks = [ "UIKit.framework" ] configs += [ "//build/config/compiler:enable_arc" ] }
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn index 00e47a9..ba717f17 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn
@@ -45,6 +45,7 @@ "//ios/chrome/browser/sessions:serialisation", "//ios/chrome/browser/shared/coordinator/alert", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", + "//ios/chrome/browser/shared/coordinator/layout_guide", "//ios/chrome/browser/shared/coordinator/scene:scene_state_browser_agent", "//ios/chrome/browser/shared/public/commands", "//ios/chrome/browser/shared/public/features", @@ -68,7 +69,6 @@ "//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_scene_agent", "//ios/chrome/browser/ui/main", "//ios/chrome/browser/ui/main:default_browser_scene_agent", - "//ios/chrome/browser/ui/main:layout_guide_util", "//ios/chrome/browser/ui/menu", "//ios/chrome/browser/ui/menu:tab_context_menu_delegate", "//ios/chrome/browser/ui/recent_tabs",
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm index 5f72ebb8..86f65b55 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -27,6 +27,7 @@ #import "ios/chrome/browser/search_engines/template_url_service_factory.h" #import "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h" #import "ios/chrome/browser/shared/coordinator/alert/action_sheet_coordinator.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/coordinator/scene/scene_state_browser_agent.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" #import "ios/chrome/browser/shared/public/commands/bookmarks_commands.h" @@ -59,7 +60,6 @@ #import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h" #import "ios/chrome/browser/ui/main/bvc_container_view_controller.h" #import "ios/chrome/browser/ui/main/default_browser_scene_agent.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/menu/tab_context_menu_delegate.h" #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.h" #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_helper.h"
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator_unittest.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator_unittest.mm index 2cc4449..4c2ae88 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator_unittest.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator_unittest.mm
@@ -273,8 +273,8 @@ void PrepareForRestoration() { TestSessionService* test_session_service = [[TestSessionService alloc] init]; - SessionRestorationBrowserAgent::CreateForBrowser(browser_.get(), - test_session_service); + SessionRestorationBrowserAgent::CreateForBrowser( + browser_.get(), test_session_service, false); SessionRestorationBrowserAgent::FromBrowser(browser_.get()) ->SetSessionID([[NSUUID UUID] UUIDString]); }
diff --git a/ios/chrome/browser/ui/toolbar/BUILD.gn b/ios/chrome/browser/ui/toolbar/BUILD.gn index 1259a60..9407f88 100644 --- a/ios/chrome/browser/ui/toolbar/BUILD.gn +++ b/ios/chrome/browser/ui/toolbar/BUILD.gn
@@ -47,6 +47,7 @@ "//ios/chrome/browser/search_engines", "//ios/chrome/browser/search_engines:search_engines_util", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", + "//ios/chrome/browser/shared/coordinator/layout_guide", "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", "//ios/chrome/browser/shared/public/commands", "//ios/chrome/browser/shared/public/features", @@ -57,7 +58,6 @@ "//ios/chrome/browser/ui/fullscreen", "//ios/chrome/browser/ui/gestures", "//ios/chrome/browser/ui/location_bar", - "//ios/chrome/browser/ui/main:layout_guide_util", "//ios/chrome/browser/ui/menu", "//ios/chrome/browser/ui/ntp", "//ios/chrome/browser/ui/ntp:coordinator",
diff --git a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_coordinator.mm index f2dbdc7..c34dfc9 100644 --- a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_coordinator.mm +++ b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_coordinator.mm
@@ -11,6 +11,7 @@ #import "ios/chrome/browser/ntp/new_tab_page_util.h" #import "ios/chrome/browser/overlays/public/overlay_presenter.h" #import "ios/chrome/browser/search_engines/template_url_service_factory.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/public/commands/activity_service_commands.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" @@ -19,7 +20,6 @@ #import "ios/chrome/browser/shared/public/commands/popup_menu_commands.h" #import "ios/chrome/browser/shared/ui/symbols/symbols.h" #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/menu/browser_action_factory.h" #import "ios/chrome/browser/ui/toolbar/adaptive_toolbar_coordinator+subclassing.h" #import "ios/chrome/browser/ui/toolbar/adaptive_toolbar_view_controller.h"
diff --git a/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm index 5dfb3fa3..254caaa 100644 --- a/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm +++ b/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.mm
@@ -17,6 +17,7 @@ #import "ios/chrome/browser/ntp/new_tab_page_util.h" #import "ios/chrome/browser/prerender/prerender_service.h" #import "ios/chrome/browser/prerender/prerender_service_factory.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" #import "ios/chrome/browser/shared/public/commands/find_in_page_commands.h" @@ -27,7 +28,6 @@ #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h" #import "ios/chrome/browser/ui/location_bar/location_bar_coordinator.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h" #import "ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.h" #import "ios/chrome/browser/ui/toolbar/adaptive_toolbar_coordinator+subclassing.h"
diff --git a/ios/chrome/browser/ui/toolbar/secondary_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/secondary_toolbar_coordinator.mm index d1cedbdd..e52533c 100644 --- a/ios/chrome/browser/ui/toolbar/secondary_toolbar_coordinator.mm +++ b/ios/chrome/browser/ui/toolbar/secondary_toolbar_coordinator.mm
@@ -5,10 +5,10 @@ #import "ios/chrome/browser/ui/toolbar/secondary_toolbar_coordinator.h" #import "ios/chrome/browser/main/browser.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" #import "ios/chrome/browser/shared/public/commands/omnibox_commands.h" #import "ios/chrome/browser/shared/public/commands/popup_menu_commands.h" -#import "ios/chrome/browser/ui/main/layout_guide_util.h" #import "ios/chrome/browser/ui/toolbar/adaptive_toolbar_coordinator+subclassing.h" #import "ios/chrome/browser/ui/toolbar/secondary_toolbar_view_controller.h"
diff --git a/ios/chrome/browser/web_state_list/web_state_list_serialization.h b/ios/chrome/browser/web_state_list/web_state_list_serialization.h index 4289050..aeeff36 100644 --- a/ios/chrome/browser/web_state_list/web_state_list_serialization.h +++ b/ios/chrome/browser/web_state_list/web_state_list_serialization.h
@@ -40,6 +40,7 @@ void DeserializeWebStateList(WebStateList* web_state_list, SessionWindowIOS* session_window, SessionRestorationScope session_restoration_scope, + bool enable_pinned_web_states, const WebStateFactory& web_state_factory); #endif // IOS_CHROME_BROWSER_WEB_STATE_LIST_WEB_STATE_LIST_SERIALIZATION_H_
diff --git a/ios/chrome/browser/web_state_list/web_state_list_serialization.mm b/ios/chrome/browser/web_state_list/web_state_list_serialization.mm index cfa74b8..95710d0f 100644 --- a/ios/chrome/browser/web_state_list/web_state_list_serialization.mm +++ b/ios/chrome/browser/web_state_list/web_state_list_serialization.mm
@@ -15,7 +15,6 @@ #import "base/mac/foundation_util.h" #import "base/strings/sys_string_conversions.h" #import "ios/chrome/browser/sessions/session_window_ios.h" -#import "ios/chrome/browser/tabs/features.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/chrome/browser/web_state_list/web_state_list_order_controller.h" #import "ios/chrome/browser/web_state_list/web_state_list_removing_indexes.h" @@ -72,15 +71,17 @@ // Checks whether provided `web_state` is in the `session_restoration_scope`. bool IsWebStateInRestorationScope( web::WebState* web_state, - SessionRestorationScope session_restoration_scope) { + SessionRestorationScope session_restoration_scope, + bool enable_pinned_web_states) { switch (session_restoration_scope) { case SessionRestorationScope::kAll: return true; case SessionRestorationScope::kPinnedOnly: - return IsPinnedTabsEnabled() ? GetPinnedStateForWebState(web_state) - : false; + return enable_pinned_web_states ? GetPinnedStateForWebState(web_state) + : false; case SessionRestorationScope::kRegularOnly: - return !GetPinnedStateForWebState(web_state); + return enable_pinned_web_states ? !GetPinnedStateForWebState(web_state) + : true; } } @@ -181,6 +182,7 @@ void DeserializeWebStateList(WebStateList* web_state_list, SessionWindowIOS* session_window, SessionRestorationScope session_restoration_scope, + bool enable_pinned_web_states, const WebStateFactory& web_state_factory) { const int old_count = web_state_list->count(); for (CRWSessionStorage* session in session_window.sessions) { @@ -188,7 +190,8 @@ // Drop WebState that is not in the restoration scope. if (!IsWebStateInRestorationScope(web_state.get(), - session_restoration_scope)) { + session_restoration_scope, + enable_pinned_web_states)) { continue; } @@ -197,6 +200,12 @@ WebStateList::INSERT_FORCE_INDEX, WebStateOpener()); } + const NSInteger restored_sessions_count = web_state_list->count() - old_count; + + if (restored_sessions_count == 0) { + return; + } + // Restore the WebStates pinned state and opener-opened relationship. for (int index = old_count; index < web_state_list->count(); ++index) { web::WebState* web_state = web_state_list->GetWebStateAt(index); @@ -229,7 +238,6 @@ WebStateOpener(opener, [boxed_opener_navigation_index intValue])); } - const NSInteger restored_sessions_count = web_state_list->count() - old_count; const NSInteger selected_index = GetAdjustedSelectedIndex( session_window, restored_sessions_count, session_restoration_scope); @@ -239,7 +247,7 @@ } // By default all the restored tabs are not pinned. - if (IsPinnedTabsEnabled()) { + if (enable_pinned_web_states) { // Restore the WebStates pinned state. This should be done in a separate // cycle, since pinning the WebStates may cause WebStates indexes to change. for (int index = old_count; index < web_state_list->count(); ++index) {
diff --git a/ios/chrome/browser/web_state_list/web_state_list_serialization_unittest.mm b/ios/chrome/browser/web_state_list/web_state_list_serialization_unittest.mm index 16518d2..8a77713 100644 --- a/ios/chrome/browser/web_state_list/web_state_list_serialization_unittest.mm +++ b/ios/chrome/browser/web_state_list/web_state_list_serialization_unittest.mm
@@ -125,7 +125,7 @@ DeserializeWebStateList( &restored_web_state_list, session_window, SessionRestorationScope::kAll, - base::BindRepeating(&CreateWebStateWithSessionStorage)); + false, base::BindRepeating(&CreateWebStateWithSessionStorage)); EXPECT_EQ(5, restored_web_state_list.count()); EXPECT_EQ(2, restored_web_state_list.active_index());
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn index 0fa31f1..f05cee4 100644 --- a/ios/chrome/test/BUILD.gn +++ b/ios/chrome/test/BUILD.gn
@@ -255,6 +255,7 @@ "//ios/chrome/browser/send_tab_to_self:unit_tests", "//ios/chrome/browser/sessions:unit_tests", "//ios/chrome/browser/shared/coordinator/alert:unit_tests", + "//ios/chrome/browser/shared/coordinator/layout_guide:unit_tests", "//ios/chrome/browser/shared/coordinator/scene:unit_tests", "//ios/chrome/browser/shared/public/commands:unit_tests", "//ios/chrome/browser/shared/ui/elements:unit_tests",
diff --git a/media/audio/cras/cras_input.cc b/media/audio/cras/cras_input.cc index 05c9caa..f3dae3e8 100644 --- a/media/audio/cras/cras_input.cc +++ b/media/audio/cras/cras_input.cc
@@ -171,7 +171,9 @@ rc = libcras_client_get_loopback_dev_idx(client_, &pin_device_); } if (rc < 0) { - DLOG(WARNING) << "Couldn't find CRAS loopback device."; + DLOG(WARNING) << "Couldn't find CRAS loopback device " + << (is_loopback_without_chrome_ ? " for flexible loopback." + : " for full loopback."); ReportStreamOpenResult( StreamOpenResult::kCallbackOpenCannotFindLoopbackDevice); libcras_client_destroy(client_);
diff --git a/media/gpu/vaapi/vaapi_unittest.cc b/media/gpu/vaapi/vaapi_unittest.cc index 7596120..28301b4 100644 --- a/media/gpu/vaapi/vaapi_unittest.cc +++ b/media/gpu/vaapi/vaapi_unittest.cc
@@ -329,6 +329,17 @@ for (const auto& profile : VaapiWrapper::GetSupportedEncodeProfiles()) { const auto va_profile = ConvertToVAProfile(profile.profile); ASSERT_TRUE(va_profile.has_value()); + constexpr VAProfile kSupportableVideoEncoderProfiles[] = { + VAProfileH264ConstrainedBaseline, + VAProfileH264Main, + VAProfileH264High, + VAProfileVP8Version0_3, + VAProfileVP9Profile0, + VAProfileAV1Profile0, + }; + // Check if VaapiWrapper reports a profile that is not supported by + // VaapiVideoEncodeAccelerator. + ASSERT_TRUE(base::Contains(kSupportableVideoEncoderProfiles, va_profile)); EXPECT_TRUE(base::Contains(va_info.at(*va_profile), VAEntrypointEncSlice) || base::Contains(va_info.at(*va_profile), VAEntrypointEncSliceLP))
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc index 738fbe7b..9825704 100644 --- a/media/gpu/vaapi/vaapi_wrapper.cc +++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -609,8 +609,7 @@ } // Maps a VideoCodecProfile |profile| to a VAProfile, or VAProfileNone. -VAProfile ProfileToVAProfile(VideoCodecProfile profile, - VaapiWrapper::CodecMode mode) { +VAProfile ProfileToVAProfile(VideoCodecProfile profile) { const auto& profiles = GetProfileCodecMap(); const auto& maybe_profile = profiles.find(profile); if (maybe_profile == profiles.end()) @@ -618,15 +617,29 @@ return maybe_profile->second; } -bool IsVAProfileSupported(VAProfile va_profile) { - const auto& profiles = GetProfileCodecMap(); +bool IsVAProfileSupported(VAProfile va_profile, bool is_encoding) { // VAProfileJPEGBaseline and VAProfileProtected are always recognized but are // not video codecs per se. - return va_profile == VAProfileJPEGBaseline || + if (va_profile == VAProfileJPEGBaseline) { + return true; + } #if BUILDFLAG(IS_CHROMEOS_ASH) - va_profile == VAProfileProtected || + if (va_profile == VAProfileProtected) { + return true; + } #endif - base::Contains(profiles, va_profile, + if (is_encoding) { + constexpr VAProfile kSupportableEncoderProfiles[] = { + VAProfileH264ConstrainedBaseline, + VAProfileH264Main, + VAProfileH264High, + VAProfileVP8Version0_3, + VAProfileVP9Profile0, + VAProfileAV1Profile0, + }; + return base::Contains(kSupportableEncoderProfiles, va_profile); + } + return base::Contains(GetProfileCodecMap(), va_profile, &ProfileCodecMap::value_type::second); } @@ -1248,7 +1261,7 @@ continue; if ((mode != VaapiWrapper::kVideoProcess) && - !IsVAProfileSupported(va_profile)) { + !IsVAProfileSupported(va_profile, IsModeEncoding(mode))) { continue; } @@ -1591,7 +1604,6 @@ VAProfileH264Main, VAProfileH264High, VAProfileVP9Profile0, - VAProfileVP9Profile2, VAProfileAV1Profile0, }; if (!base::Contains(kSupportedLowPowerEncodeProfiles, va_profile)) @@ -1677,7 +1689,7 @@ EncryptionScheme encryption_scheme, const ReportErrorToUMACB& report_error_to_uma_cb, bool enforce_sequence_affinity) { - const VAProfile va_profile = ProfileToVAProfile(profile, mode); + const VAProfile va_profile = ProfileToVAProfile(profile); return Create(mode, va_profile, encryption_scheme, report_error_to_uma_cb, enforce_sequence_affinity); } @@ -2936,8 +2948,7 @@ size_t* max_ref_frames) { CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); - const VAProfile va_profile = - ProfileToVAProfile(profile, CodecMode::kEncodeConstantBitrate); + const VAProfile va_profile = ProfileToVAProfile(profile); VAConfigAttrib attrib; attrib.type = VAConfigAttribEncMaxRefFrames; @@ -2956,8 +2967,7 @@ bool& packed_slice) { CHECK(!enforce_sequence_affinity_ || sequence_checker_.CalledOnValidSequence()); - const VAProfile va_profile = - ProfileToVAProfile(profile, CodecMode::kEncodeConstantBitrate); + const VAProfile va_profile = ProfileToVAProfile(profile); VAConfigAttrib attrib{}; attrib.type = VAConfigAttribEncPackedHeaders; base::AutoLockMaybe auto_lock(va_lock_.get());
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc index 4ec3a5da..39e7b30 100644 --- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc +++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -3210,7 +3210,8 @@ gl::GLImage::ToGLImageEGLStream(picture_buffer->gl_image().get()); if (gl_image_egl_stream) { shared_image = gpu::D3DImageBacking::CreateFromGLTexture( - mailbox, viz_formats[texture_idx], + mailbox, + viz::SharedImageFormat::SinglePlane(viz_formats[texture_idx]), picture_buffer->texture_size(texture_idx), picture_buffer->color_space(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, shared_image_usage,
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc index 27b10c6..8d9ade2a 100644 --- a/net/nqe/network_quality_estimator.cc +++ b/net/nqe/network_quality_estimator.cc
@@ -213,16 +213,9 @@ if (!RequestSchemeIsHTTPOrHTTPS(request)) return; - // Update |estimated_quality_at_last_main_frame_| if this is a main frame - // request. // TODO(tbansal): Refactor this to a separate method. if (request.load_flags() & LOAD_MAIN_FRAME_DEPRECATED) { - base::TimeTicks now = tick_clock_->NowTicks(); - last_main_frame_request_ = now; - ComputeEffectiveConnectionType(); - effective_connection_type_at_last_main_frame_ = effective_connection_type_; - estimated_quality_at_last_main_frame_ = network_quality_; } else { MaybeComputeEffectiveConnectionType(); } @@ -293,7 +286,6 @@ if (request.load_flags() & LOAD_MAIN_FRAME_DEPRECATED) { ComputeEffectiveConnectionType(); - RecordMetricsOnMainFrameRequest(); } LoadTimingInfo load_timing_info; @@ -477,8 +469,6 @@ network_quality_ = nqe::internal::NetworkQuality(); end_to_end_rtt_ = absl::nullopt; effective_connection_type_ = EFFECTIVE_CONNECTION_TYPE_UNKNOWN; - effective_connection_type_at_last_main_frame_ = - EFFECTIVE_CONNECTION_TYPE_UNKNOWN; rtt_observations_size_at_last_ect_computation_ = 0; throughput_observations_size_at_last_ect_computation_ = 0; new_rtt_observations_since_last_ect_computation_ = 0; @@ -486,7 +476,6 @@ transport_rtt_observation_count_last_ect_computation_ = 0; end_to_end_rtt_observation_count_at_last_ect_computation_ = 0; last_socket_watcher_rtt_notification_ = base::TimeTicks(); - estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality(); cached_estimate_applied_ = false; GatherEstimatesForNextConnectionType(); @@ -527,7 +516,6 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Update the local state as part of preparation for the new connection. current_network_id_ = network_id; - RecordNetworkIDAvailability(); // Read any cached estimates for the new network. If cached estimates are // unavailable, add the default estimates. @@ -537,47 +525,6 @@ ComputeEffectiveConnectionType(); } -void NetworkQualityEstimator::RecordNetworkIDAvailability() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (current_network_id_.type == - NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI || - NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type)) { - UMA_HISTOGRAM_BOOLEAN("NQE.NetworkIdAvailable", - !current_network_id_.id.empty()); - } -} - -void NetworkQualityEstimator::RecordMetricsOnMainFrameRequest() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (estimated_quality_at_last_main_frame_.http_rtt() != - nqe::internal::InvalidRTT()) { - // Add the 50th percentile value. - LOCAL_HISTOGRAM_TIMES("NQE.MainFrame.RTT.Percentile50", - estimated_quality_at_last_main_frame_.http_rtt()); - } - - if (estimated_quality_at_last_main_frame_.transport_rtt() != - nqe::internal::InvalidRTT()) { - // Add the 50th percentile value. - LOCAL_HISTOGRAM_TIMES( - "NQE.MainFrame.TransportRTT.Percentile50", - estimated_quality_at_last_main_frame_.transport_rtt()); - } - - if (estimated_quality_at_last_main_frame_.downstream_throughput_kbps() != - nqe::internal::INVALID_RTT_THROUGHPUT) { - // Add the 50th percentile value. - LOCAL_HISTOGRAM_COUNTS_1000000( - "NQE.MainFrame.Kbps.Percentile50", - estimated_quality_at_last_main_frame_.downstream_throughput_kbps()); - } - - LOCAL_HISTOGRAM_ENUMERATION("NQE.MainFrame.EffectiveConnectionType", - effective_connection_type_at_last_main_frame_, - EFFECTIVE_CONNECTION_TYPE_LAST); -} - void NetworkQualityEstimator::ComputeEffectiveConnectionType() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -599,31 +546,14 @@ network_quality_ = nqe::internal::NetworkQuality(http_rtt, transport_rtt, downstream_throughput_kbps); ClampKbpsBasedOnEct(); - - UMA_HISTOGRAM_ENUMERATION("NQE.EffectiveConnectionType.OnECTComputation", - effective_connection_type_, - EFFECTIVE_CONNECTION_TYPE_LAST); if (network_quality_.http_rtt() != nqe::internal::InvalidRTT()) { UMA_HISTOGRAM_TIMES("NQE.RTT.OnECTComputation", network_quality_.http_rtt()); } - if (network_quality_.transport_rtt() != nqe::internal::InvalidRTT()) { - UMA_HISTOGRAM_TIMES("NQE.TransportRTT.OnECTComputation", - network_quality_.transport_rtt()); - } - - if (end_to_end_rtt != nqe::internal::InvalidRTT()) { - UMA_HISTOGRAM_TIMES("NQE.EndToEndRTT.OnECTComputation", end_to_end_rtt); - } end_to_end_rtt_ = absl::nullopt; - if (end_to_end_rtt != nqe::internal::InvalidRTT()) + if (end_to_end_rtt != nqe::internal::InvalidRTT()) { end_to_end_rtt_ = end_to_end_rtt; - - if (network_quality_.downstream_throughput_kbps() != - nqe::internal::INVALID_RTT_THROUGHPUT) { - UMA_HISTOGRAM_COUNTS_1M("NQE.Kbps.OnECTComputation", - network_quality_.downstream_throughput_kbps()); } NotifyObserversOfRTTOrThroughputComputed(); @@ -690,8 +620,6 @@ params_->http_rtt_transport_rtt_min_count() || end_to_end_rtt_observation_count_at_last_ect_computation_ >= params_->http_rtt_transport_rtt_min_count()) { - UMA_HISTOGRAM_TIMES("NQE.HttpRttReduction.BasedOnRTTCounts", - base::TimeDelta()); return; } @@ -701,8 +629,6 @@ tick_clock_->NowTicks() - last_connection_change_; if (cached_estimate_applied_ && time_since_connection_change <= base::Minutes(1)) { - UMA_HISTOGRAM_TIMES("NQE.HttpRttReduction.BasedOnRTTCounts", - base::TimeDelta()); return; } @@ -711,8 +637,6 @@ // HTTP RTT can't be trusted due to hanging GETs. In that case, return the // typical HTTP RTT for a fast connection. if (current_network_id_.type == net::NetworkChangeNotifier::CONNECTION_NONE) { - UMA_HISTOGRAM_TIMES("NQE.HttpRttReduction.BasedOnRTTCounts", - base::TimeDelta()); return; } @@ -720,15 +644,10 @@ params_->TypicalNetworkQuality(net::EFFECTIVE_CONNECTION_TYPE_4G) .http_rtt(); if (upper_bound_http_rtt > *http_rtt) { - UMA_HISTOGRAM_TIMES("NQE.HttpRttReduction.BasedOnRTTCounts", - base::TimeDelta()); return; } DCHECK_LE(upper_bound_http_rtt, *http_rtt); - - UMA_HISTOGRAM_TIMES("NQE.HttpRttReduction.BasedOnRTTCounts", - *http_rtt - upper_bound_http_rtt); *http_rtt = upper_bound_http_rtt; } @@ -1036,11 +955,10 @@ const bool cached_estimate_available = network_quality_store_->GetById( current_network_id_, &cached_network_quality); - UMA_HISTOGRAM_BOOLEAN("NQE.CachedNetworkQualityAvailable", - cached_estimate_available); - if (!cached_estimate_available) + if (!cached_estimate_available) { return false; + } EffectiveConnectionType effective_connection_type = cached_network_quality.effective_connection_type(); @@ -1195,10 +1113,6 @@ ++new_throughput_observations_since_last_ect_computation_; http_downstream_throughput_kbps_observations_.AddObservation(observation); - LOCAL_HISTOGRAM_ENUMERATION("NQE.Kbps.ObservationSource", - observation.source(), - NETWORK_QUALITY_OBSERVATION_SOURCE_MAX); - // Maybe recompute the effective connection type since a new throughput // observation is available. if (observation.source() != @@ -1507,20 +1421,6 @@ if (p2p_connections_count_ == count) return; - if (p2p_connections_count_ == 0 && count > 0) { - DCHECK(!p2p_connections_count_active_timestamp_); - p2p_connections_count_active_timestamp_ = tick_clock_->NowTicks(); - } - - if (p2p_connections_count_ > 0 && count == 0) { - DCHECK(p2p_connections_count_active_timestamp_); - base::TimeDelta duration = tick_clock_->NowTicks() - - p2p_connections_count_active_timestamp_.value(); - LOCAL_HISTOGRAM_CUSTOM_TIMES("NQE.PeerToPeerConnectionsDuration", duration, - base::Milliseconds(1), base::Hours(1), 50); - p2p_connections_count_active_timestamp_ = absl::nullopt; - } - p2p_connections_count_ = count; for (auto& observer : peer_to_peer_type_observer_list_) {
diff --git a/net/nqe/network_quality_estimator.h b/net/nqe/network_quality_estimator.h index 6927a05..6268c2e 100644 --- a/net/nqe/network_quality_estimator.h +++ b/net/nqe/network_quality_estimator.h
@@ -442,13 +442,6 @@ // should discard RTT if it is set to the value returned by |InvalidRTT()|. static const base::TimeDelta InvalidRTT(); - // Records UMA on whether the NetworkID was available or not. Called right - // after a network change event. - void RecordNetworkIDAvailability() const; - - // Records UMA on main frame requests. - void RecordMetricsOnMainFrameRequest() const; - // Records a downstream throughput observation to the observation buffer if // a valid observation is available. |downstream_kbps| is the downstream // throughput in kilobits per second. @@ -532,11 +525,6 @@ // type. void ClampKbpsBasedOnEct(); - // Earliest timestamp since when there is at least one active peer to peer - // connection count. Set to current timestamp when |p2p_connections_count_| - // changes from 0 to 1. Reset to null when |p2p_connections_count_| becomes 0. - absl::optional<base::TimeTicks> p2p_connections_count_active_timestamp_; - // Determines if the requests to local host can be used in estimating the // network quality. Set to true only for tests. bool use_localhost_requests_ = false; @@ -567,15 +555,6 @@ ObservationBuffer rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_COUNT]; - // Time when the transaction for the last main frame request was started. - base::TimeTicks last_main_frame_request_; - - // Estimated network quality when the transaction for the last main frame - // request was started. - nqe::internal::NetworkQuality estimated_quality_at_last_main_frame_; - EffectiveConnectionType effective_connection_type_at_last_main_frame_ = - EFFECTIVE_CONNECTION_TYPE_UNKNOWN; - // Observer lists for round trip times and throughput measurements. base::ObserverList<RTTObserver>::Unchecked rtt_observer_list_; base::ObserverList<ThroughputObserver>::Unchecked throughput_observer_list_;
diff --git a/net/nqe/network_quality_estimator_unittest.cc b/net/nqe/network_quality_estimator_unittest.cc index 013bdb6..2b79481 100644 --- a/net/nqe/network_quality_estimator_unittest.cc +++ b/net/nqe/network_quality_estimator_unittest.cc
@@ -216,8 +216,6 @@ estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test"); - histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable", - false, 2); base::TimeDelta rtt; int32_t kbps; @@ -270,18 +268,11 @@ "downstream_throughput_kbps")); // Check UMA histograms. - histogram_tester.ExpectUniqueSample( - "NQE.MainFrame.EffectiveConnectionType", - EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 1); EXPECT_LE(1u, histogram_tester.GetAllSamples("NQE.RTT.OnECTComputation").size()); - EXPECT_LE(1u, - histogram_tester.GetAllSamples("NQE.Kbps.OnECTComputation").size()); histogram_tester.ExpectBucketCount( "NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, 1); - histogram_tester.ExpectBucketCount( - "NQE.Kbps.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, 1); std::unique_ptr<URLRequest> request2( context->CreateRequest(estimator.GetEchoURL(), DEFAULT_PRIORITY, @@ -289,12 +280,9 @@ request2->SetLoadFlags(request2->load_flags() | LOAD_MAIN_FRAME_DEPRECATED); request2->Start(); test_delegate.RunUntilComplete(); - histogram_tester.ExpectTotalCount("NQE.MainFrame.EffectiveConnectionType", 2); estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); - histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable", - false, 3); histogram_tester.ExpectTotalCount("NQE.RatioMedianRTT.WiFi", 0); EXPECT_FALSE(estimator.GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_HTTP, @@ -302,16 +290,8 @@ EXPECT_FALSE( estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps)); - // Verify that metrics are logged correctly on main-frame requests. - histogram_tester.ExpectTotalCount("NQE.MainFrame.RTT.Percentile50", 1); - histogram_tester.ExpectTotalCount("NQE.MainFrame.TransportRTT.Percentile50", - 0); - histogram_tester.ExpectTotalCount("NQE.MainFrame.Kbps.Percentile50", 1); - estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, std::string()); - histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable", - false, 4); EXPECT_FALSE(estimator.GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_HTTP, base::TimeTicks(), &rtt, nullptr)); @@ -324,15 +304,9 @@ request3->SetLoadFlags(request2->load_flags() | LOAD_MAIN_FRAME_DEPRECATED); request3->Start(); test_delegate.RunUntilComplete(); - histogram_tester.ExpectBucketCount( - "NQE.MainFrame.EffectiveConnectionType", - EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 2); - histogram_tester.ExpectTotalCount("NQE.MainFrame.EffectiveConnectionType", 3); estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test"); - histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", false, - 4); } // Tests that the network quality estimator writes and reads network quality @@ -354,8 +328,6 @@ : ""; estimator.SimulateNetworkChange(connection_type, connection_id); - histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable", - false, 2); base::TimeDelta rtt; int32_t kbps; @@ -402,9 +374,6 @@ base::TimeTicks(), &rtt, nullptr)); EXPECT_FALSE(estimator.GetTransportRTT()); - histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", - false, 2); - // Add the observers before changing the network type. TestEffectiveConnectionTypeObserver observer; estimator.AddEffectiveConnectionTypeObserver(&observer); @@ -430,10 +399,6 @@ NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 1); histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 4); - histogram_tester.ExpectBucketCount( - "NQE.Kbps.ObservationSource", - NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE, 1); - // Verify the contents of the net log. EXPECT_LE( 1, estimator.GetEntriesCount(NetLogEventType::NETWORK_QUALITY_CHANGED) - @@ -452,9 +417,6 @@ NetLogEventType::NETWORK_QUALITY_CHANGED, "effective_connection_type")); - histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", - true, 1); - histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 3); base::RunLoop().RunUntilIdle(); // Verify that the cached network quality was read, and observers were @@ -481,7 +443,6 @@ estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test"); - histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 0); base::TimeDelta rtt; int32_t kbps; @@ -524,8 +485,6 @@ base::TimeTicks(), &rtt, nullptr)); EXPECT_FALSE(estimator.GetTransportRTT()); - histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 0); - // Add the observers before changing the network type. TestRTTObserver rtt_observer; estimator.AddRTTObserver(&rtt_observer); @@ -535,7 +494,6 @@ estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test"); - histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 0); base::RunLoop().RunUntilIdle(); // Verify that the cached network quality was read, and observers were @@ -560,7 +518,6 @@ NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, 1); histogram_tester.ExpectBucketCount( "NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC, 1); - histogram_tester.ExpectTotalCount("NQE.EndToEndRTT.OnECTComputation", 1); histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 2); // Verify that the QUIC RTT samples are used when computing transport RTT @@ -582,7 +539,6 @@ absl::nullopt); histogram_tester.ExpectBucketCount( "NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC, 1); - histogram_tester.ExpectTotalCount("NQE.EndToEndRTT.OnECTComputation", 1); histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 1); EXPECT_EQ(base::Milliseconds(10), estimator.GetTransportRTT()); @@ -603,7 +559,6 @@ histogram_tester.ExpectBucketCount( "NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_H2_PINGS, 1); - histogram_tester.ExpectTotalCount("NQE.EndToEndRTT.OnECTComputation", 1); histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 1); EXPECT_EQ(base::Milliseconds(10), estimator.GetTransportRTT()); @@ -731,11 +686,7 @@ histogram_tester.ExpectBucketCount( "NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM, 1); - histogram_tester.ExpectBucketCount( - "NQE.Kbps.ObservationSource", - NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM, 1); histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 2); - histogram_tester.ExpectTotalCount("NQE.Kbps.ObservationSource", 1); // Default observations should be added on connection change. estimator.SimulateNetworkChange( @@ -746,11 +697,7 @@ histogram_tester.ExpectBucketCount( "NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM, 2); - histogram_tester.ExpectBucketCount( - "NQE.Kbps.ObservationSource", - NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM, 2); histogram_tester.ExpectTotalCount("NQE.RTT.ObservationSource", 4); - histogram_tester.ExpectTotalCount("NQE.Kbps.ObservationSource", 2); base::TimeDelta rtt; int32_t kbps; @@ -1394,9 +1341,6 @@ NetLogEventType::NETWORK_QUALITY_CHANGED, "downstream_throughput_kbps")); - histogram_tester.ExpectUniqueSample("NQE.MainFrame.EffectiveConnectionType", - EFFECTIVE_CONNECTION_TYPE_2G, 1); - // Next request should not trigger recomputation of effective connection type // since there has been no change in the clock. std::unique_ptr<URLRequest> request2( @@ -1765,12 +1709,6 @@ request->Start(); test_delegate.RunUntilComplete(); EXPECT_EQ(1U, observer.effective_connection_types().size()); - histogram_tester.ExpectUniqueSample("NQE.MainFrame.EffectiveConnectionType", - EFFECTIVE_CONNECTION_TYPE_2G, 1); - EXPECT_LE(1u, - histogram_tester - .GetAllSamples("NQE.EffectiveConnectionType.OnECTComputation") - .size()); size_t expected_effective_connection_type_notifications = 1; EXPECT_EQ(expected_effective_connection_type_notifications, @@ -1932,11 +1870,6 @@ EXPECT_EQ(quic_rtt, estimator.end_to_end_rtt_.value()); EXPECT_LT( 0u, estimator.end_to_end_rtt_observation_count_at_last_ect_computation_); - const std::vector<base::Bucket> end_to_end_rtt_samples = - histogram_tester.GetAllSamples("NQE.EndToEndRTT.OnECTComputation"); - EXPECT_FALSE(end_to_end_rtt_samples.empty()); - for (const auto& bucket : end_to_end_rtt_samples) - EXPECT_EQ(quic_rtt.InMilliseconds(), bucket.min); } TEST_F(NetworkQualityEstimatorTest, TestGlobalSocketWatcherThrottle) { @@ -2087,32 +2020,11 @@ estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); - // Verify that metrics are logged correctly on main-frame requests. - histogram_tester.ExpectTotalCount("NQE.MainFrame.TransportRTT.Percentile50", - num_requests); - - histogram_tester.ExpectTotalCount("NQE.MainFrame.EffectiveConnectionType", - num_requests); - histogram_tester.ExpectBucketCount("NQE.MainFrame.EffectiveConnectionType", - EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 0); ExpectBucketCountAtLeast(&histogram_tester, "NQE.RTT.ObservationSource", NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, 1); - ExpectBucketCountAtLeast(&histogram_tester, "NQE.Kbps.ObservationSource", - NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, 1); - EXPECT_LE(1u, - histogram_tester - .GetAllSamples("NQE.EffectiveConnectionType.OnECTComputation") - .size()); - EXPECT_LE(1u, - histogram_tester.GetAllSamples("NQE.TransportRTT.OnECTComputation") - .size()); EXPECT_LE(1u, histogram_tester.GetAllSamples("NQE.RTT.OnECTComputation").size()); - histogram_tester.ExpectBucketCount( - "NQE.Kbps.ObservationSource", - NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 0); - estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test"); histogram_tester.ExpectBucketCount( @@ -2126,44 +2038,6 @@ NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 2); } -TEST_F(NetworkQualityEstimatorTest, TestRecordNetworkIDAvailability) { - TestNetworkQualityEstimator estimator; - - // Create the histogram tester after |estimator| is constructed. This ensures - // that any network checks done at the time of |estimator| construction do not - // affect |histogram_tester|. - base::HistogramTester histogram_tester; - - // The NetworkID is recorded as available on Wi-Fi connection. - estimator.SimulateNetworkChange( - NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); - histogram_tester.ExpectUniqueSample("NQE.NetworkIdAvailable", 1, 1); - - // The histogram is not recorded on an unknown connection. - estimator.SimulateNetworkChange( - NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, ""); - histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 1); - - // The NetworkID is recorded as not being available on a Wi-Fi connection - // with an empty SSID. - estimator.SimulateNetworkChange( - NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, ""); - histogram_tester.ExpectBucketCount("NQE.NetworkIdAvailable", 0, 1); - histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 2); - - // The NetworkID is recorded as being available on a Wi-Fi connection. - estimator.SimulateNetworkChange( - NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); - histogram_tester.ExpectBucketCount("NQE.NetworkIdAvailable", 1, 2); - histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 3); - - // The NetworkID is recorded as being available on a cellular connection. - estimator.SimulateNetworkChange( - NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1"); - histogram_tester.ExpectBucketCount("NQE.NetworkIdAvailable", 1, 3); - histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 4); -} - class TestNetworkQualitiesCacheObserver : public nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver { public: @@ -2893,29 +2767,6 @@ } } -TEST_F(NetworkQualityEstimatorTest, PeerToPeerConnectionCounts) { - base::SimpleTestTickClock tick_clock; - TestNetworkQualityEstimator estimator; - estimator.SetTickClockForTesting(&tick_clock); - estimator.OnPeerToPeerConnectionsCountChange(3u); - - base::TimeDelta advance_1 = base::Minutes(4); - tick_clock.Advance(advance_1); - - base::HistogramTester histogram_tester; - histogram_tester.ExpectTotalCount("NQE.PeerToPeerConnectionsDuration", 0); - - estimator.OnPeerToPeerConnectionsCountChange(1u); - base::TimeDelta advance_2 = base::Minutes(6); - tick_clock.Advance(advance_2); - histogram_tester.ExpectTotalCount("NQE.PeerToPeerConnectionsDuration", 0); - - estimator.OnPeerToPeerConnectionsCountChange(0u); - histogram_tester.ExpectUniqueSample("NQE.PeerToPeerConnectionsDuration", - (advance_1 + advance_2).InMilliseconds(), - 1); -} - TEST_F(NetworkQualityEstimatorTest, TestPeerToPeerConnectionsCountObserver) { TestPeerToPeerConnectionsCountObserver observer; TestNetworkQualityEstimator estimator;
diff --git a/services/device/fingerprint/DIR_METADATA b/services/device/fingerprint/DIR_METADATA index de56d19..88df346 100644 --- a/services/device/fingerprint/DIR_METADATA +++ b/services/device/fingerprint/DIR_METADATA
@@ -1,11 +1 @@ -# Metadata information for this directory. -# -# For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md -# -# For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto - -monorail { - component: "UI>Shell>LockScreen" -} \ No newline at end of file +mixins: "//ash/login/LOGIN_LOCK_METADATA"
diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn index ec6fbe4..41863b3 100644 --- a/services/network/public/cpp/BUILD.gn +++ b/services/network/public/cpp/BUILD.gn
@@ -450,6 +450,7 @@ "//net", "//services/network/public/mojom:cookies_mojom", "//services/network/public/mojom:mojom_first_party_sets", + "//services/network/public/mojom:mojom_network_isolation_key", "//services/network/public/mojom:url_loader_base", ] defines = [ "IS_NETWORK_CPP_BASE_IMPL" ]
diff --git a/services/network/public/cpp/content_security_policy/csp_source.cc b/services/network/public/cpp/content_security_policy/csp_source.cc index ec39e14..40ec6bf 100644 --- a/services/network/public/cpp/content_security_policy/csp_source.cc +++ b/services/network/public/cpp/content_security_policy/csp_source.cc
@@ -159,21 +159,23 @@ return SourceAllowPath(source, url.path()); } -bool requiresUpgrade(const PortMatchingResult result) { +bool requiresUpgrade(PortMatchingResult result) { return result == PortMatchingResult::MatchingUpgrade; } -bool requiresUpgrade(const SchemeMatchingResult result) { +bool requiresUpgrade(SchemeMatchingResult result) { return result == SchemeMatchingResult::MatchingUpgrade; } -bool canUpgrade(const PortMatchingResult result) { - return result == PortMatchingResult::MatchingUpgrade || - result == PortMatchingResult::MatchingWildcard; +bool canUpgrade(PortMatchingResult result, CSPSourceContext context) { + return (result == PortMatchingResult::MatchingUpgrade || + result == PortMatchingResult::MatchingWildcard) && + context == CSPSourceContext::ContentSecurityPolicy; } -bool canUpgrade(const SchemeMatchingResult result) { - return result == SchemeMatchingResult::MatchingUpgrade; +bool canUpgrade(SchemeMatchingResult result, CSPSourceContext context) { + return result == SchemeMatchingResult::MatchingUpgrade && + context == CSPSourceContext::ContentSecurityPolicy; } } // namespace @@ -185,6 +187,7 @@ bool CheckCSPSource(const mojom::CSPSource& source, const GURL& url, const mojom::CSPSource& self_source, + CSPSourceContext context, bool has_followed_redirect, bool is_opaque_fenced_frame) { // Opaque fenced frames only allow https urls. @@ -214,10 +217,12 @@ PortMatchingResult portResult = SourceAllowPort(source, url); SchemeMatchingResult schemeResult = SourceAllowScheme(source, url, self_source); - if (requiresUpgrade(schemeResult) && !canUpgrade(portResult)) + if (requiresUpgrade(schemeResult) && !canUpgrade(portResult, context)) { return false; - if (requiresUpgrade(portResult) && !canUpgrade(schemeResult)) + } + if (requiresUpgrade(portResult) && !canUpgrade(schemeResult, context)) { return false; + } return schemeResult != SchemeMatchingResult::NotMatching && SourceAllowHost(source, url) && portResult != PortMatchingResult::NotMatching &&
diff --git a/services/network/public/cpp/content_security_policy/csp_source.h b/services/network/public/cpp/content_security_policy/csp_source.h index bd3df51..edcee16 100644 --- a/services/network/public/cpp/content_security_policy/csp_source.h +++ b/services/network/public/cpp/content_security_policy/csp_source.h
@@ -13,6 +13,17 @@ namespace network { +// We now use CSPSource matching for both Content Security Policies and +// Permissions Policies. This emum is used to differentiate between them. +enum class CSPSourceContext { + // This is the default context for which the code path was written. + ContentSecurityPolicy, + + // Unlike the ContentSecurityPolicy context, this one prevents 'upgrade' + // matching (e.g., an https URL matching an http CSP Source). + PermissionsPolicy +}; + // Check if a CSP |source| matches the scheme-source grammar. bool CSPSourceIsSchemeOnly(const mojom::CSPSource& source); @@ -21,6 +32,7 @@ bool CheckCSPSource(const mojom::CSPSource& source, const GURL& url, const mojom::CSPSource& self_source, + CSPSourceContext context, bool has_followed_redirect = false, bool is_opaque_fenced_frame = false);
diff --git a/services/network/public/cpp/content_security_policy/csp_source_list.cc b/services/network/public/cpp/content_security_policy/csp_source_list.cc index 2ba80abd..9ebc355 100644 --- a/services/network/public/cpp/content_security_policy/csp_source_list.cc +++ b/services/network/public/cpp/content_security_policy/csp_source_list.cc
@@ -24,9 +24,11 @@ bool has_followed_redirect, bool is_opaque_fenced_frame) { for (const auto& source : sources) { - if (CheckCSPSource(*source, url, self_source, has_followed_redirect, - is_opaque_fenced_frame)) + if (CheckCSPSource(*source, url, self_source, + CSPSourceContext::ContentSecurityPolicy, + has_followed_redirect, is_opaque_fenced_frame)) { return true; + } } return false; } @@ -229,8 +231,9 @@ } if (source_list.allow_self && - CheckCSPSource(self_source, url, self_source, has_followed_redirect, - is_opaque_fenced_frame)) { + CheckCSPSource(self_source, url, self_source, + CSPSourceContext::ContentSecurityPolicy, + has_followed_redirect, is_opaque_fenced_frame)) { return true; }
diff --git a/services/network/public/cpp/content_security_policy/csp_source_unittest.cc b/services/network/public/cpp/content_security_policy/csp_source_unittest.cc index 11f49d2..bda0b696 100644 --- a/services/network/public/cpp/content_security_policy/csp_source_unittest.cc +++ b/services/network/public/cpp/content_security_policy/csp_source_unittest.cc
@@ -16,17 +16,6 @@ // 'self'. It doesn't match any URL. static const network::mojom::CSPSource no_self; -// Allow() is an abbreviation of CSPSource::Allow(). Useful for writing test -// expectations on one line. -bool Allow(const network::mojom::CSPSource& source, - const GURL& url, - const network::mojom::CSPSource& self_source = no_self, - bool is_redirect = false, - bool is_opaque_fenced_frame = false) { - return CheckCSPSource(source, url, self_source, is_redirect, - is_opaque_fenced_frame); -} - network::mojom::CSPSourcePtr CSPSource(const std::string& raw) { scoped_refptr<net::HttpResponseHeaders> headers( new net::HttpResponseHeaders("HTTP/1.1 200 OK")); @@ -40,7 +29,29 @@ } // namespace -TEST(CSPSourceTest, BasicMatching) { +class CSPSourceTest : public testing::TestWithParam<CSPSourceContext> { + public: + bool Allow(const network::mojom::CSPSource& source, + const GURL& url, + const network::mojom::CSPSource& self_source = no_self, + bool is_redirect = false, + bool is_opaque_fenced_frame = false) { + return CheckCSPSource(source, url, self_source, GetParam(), is_redirect, + is_opaque_fenced_frame); + } + + bool IsPermissionsPolicyContext() { + return GetParam() == CSPSourceContext::PermissionsPolicy; + } +}; + +INSTANTIATE_TEST_SUITE_P( + All, + CSPSourceTest, + ::testing::Values(CSPSourceContext::ContentSecurityPolicy, + CSPSourceContext::PermissionsPolicy)); + +TEST_P(CSPSourceTest, BasicMatching) { auto source = network::mojom::CSPSource::New("http", "example.com", 8000, "/foo/", false, false); @@ -54,8 +65,7 @@ EXPECT_FALSE(Allow(*source, GURL("HTTP://example.com:8000/FOO/BAR"))); } -TEST(CSPSourceTest, AllowScheme) { - +TEST_P(CSPSourceTest, AllowScheme) { // http -> {http, https}. { auto source = network::mojom::CSPSource::New( @@ -116,7 +126,9 @@ auto self_source = network::mojom::CSPSource::New("http", "a.com", 80, "", false, false); EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source)); - EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source)); + // Upgrades are disallowed for permission policies. + EXPECT_EQ(Allow(*source, GURL("https://a.com"), *self_source), + !IsPermissionsPolicyContext()); EXPECT_FALSE(Allow(*source, GURL("ftp://a.com"), *self_source)); } @@ -153,7 +165,7 @@ } } -TEST(CSPSourceTest, AllowHost) { +TEST_P(CSPSourceTest, AllowHost) { auto self_source = network::mojom::CSPSource::New("http", "example.com", 80, "", false, false); // Host is * (source-expression = "http://*") @@ -191,7 +203,7 @@ } } -TEST(CSPSourceTest, AllowPort) { +TEST_P(CSPSourceTest, AllowPort) { auto self_source = network::mojom::CSPSource::New("http", "example.com", 80, "", false, false); @@ -204,11 +216,15 @@ EXPECT_FALSE(Allow(*source, GURL("http://a.com:443"), *self_source)); EXPECT_FALSE(Allow(*source, GURL("https://a.com:80"), *self_source)); EXPECT_FALSE(Allow(*source, GURL("https://a.com:8080"), *self_source)); - EXPECT_TRUE(Allow(*source, GURL("https://a.com:443"), *self_source)); + // Upgrades are disallowed for permission policies. + EXPECT_EQ(Allow(*source, GURL("https://a.com:443"), *self_source), + !IsPermissionsPolicyContext()); EXPECT_FALSE(Allow(*source, GURL("unknown://a.com:80"), *self_source)); EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source)); EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source)); - EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source)); + // Upgrades are disallowed for permission policies. + EXPECT_EQ(Allow(*source, GURL("https://a.com"), *self_source), + !IsPermissionsPolicyContext()); } // Source's port is "*". @@ -218,9 +234,13 @@ EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source)); EXPECT_TRUE(Allow(*source, GURL("http://a.com:80"), *self_source)); EXPECT_TRUE(Allow(*source, GURL("http://a.com:8080"), *self_source)); - EXPECT_TRUE(Allow(*source, GURL("https://a.com:8080"), *self_source)); - EXPECT_TRUE(Allow(*source, GURL("https://a.com:0"), *self_source)); - EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source)); + // Upgrades are disallowed for permission policies. + EXPECT_EQ(Allow(*source, GURL("https://a.com:8080"), *self_source), + !IsPermissionsPolicyContext()); + EXPECT_EQ(Allow(*source, GURL("https://a.com:0"), *self_source), + !IsPermissionsPolicyContext()); + EXPECT_EQ(Allow(*source, GURL("https://a.com"), *self_source), + !IsPermissionsPolicyContext()); } // Source has a port. @@ -230,14 +250,18 @@ EXPECT_TRUE(Allow(*source, GURL("http://a.com:80"), *self_source)); EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source)); EXPECT_FALSE(Allow(*source, GURL("http://a.com:8080"), *self_source)); - EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source)); + // Upgrades are disallowed for permission policies. + EXPECT_EQ(Allow(*source, GURL("https://a.com"), *self_source), + !IsPermissionsPolicyContext()); } // Allow upgrade from :80 to :443 { auto source = network::mojom::CSPSource::New("", "a.com", 80, "", false, false); - EXPECT_TRUE(Allow(*source, GURL("https://a.com:443"), *self_source)); + // Upgrades are disallowed for permission policies. + EXPECT_EQ(Allow(*source, GURL("https://a.com:443"), *self_source), + !IsPermissionsPolicyContext()); // Should not allow scheme upgrades unless both port and scheme are // upgraded. EXPECT_FALSE(Allow(*source, GURL("http://a.com:443"), *self_source)); @@ -252,7 +276,7 @@ } } -TEST(CSPSourceTest, AllowPath) { +TEST_P(CSPSourceTest, AllowPath) { auto self_source = network::mojom::CSPSource::New("http", "example.com", 80, "", false, false); @@ -328,7 +352,7 @@ } } -TEST(CSPSourceTest, RedirectMatching) { +TEST_P(CSPSourceTest, RedirectMatching) { auto source = network::mojom::CSPSource::New("http", "a.com", 8000, "/bar/", false, false); @@ -340,7 +364,7 @@ EXPECT_FALSE(Allow(*source, GURL("http://a.com:9000/foo/"), no_self, false)); } -TEST(CSPSourceTest, Intersect) { +TEST_P(CSPSourceTest, Intersect) { struct TestCase { const char* a; const char* b; @@ -409,7 +433,7 @@ } } -TEST(CSPSourceTest, DoesNotSubsume) { +TEST_P(CSPSourceTest, DoesNotSubsume) { struct TestCase { const char* a; const char* b; @@ -440,7 +464,7 @@ } } -TEST(CSPSourceTest, Subsumes) { +TEST_P(CSPSourceTest, Subsumes) { struct TestCase { const char* a; const char* b; @@ -503,7 +527,7 @@ } } -TEST(CSPSourceTest, HostWildcardSubsumes) { +TEST_P(CSPSourceTest, HostWildcardSubsumes) { const char* a = "http://*.example.org"; const char* b = "http://www.example.org"; const char* c = "http://example.org"; @@ -533,7 +557,7 @@ << b << " should not subsume " << d; } -TEST(CSPSourceTest, PortWildcardSubsumes) { +TEST_P(CSPSourceTest, PortWildcardSubsumes) { const char* a = "http://example.org:*"; const char* b = "http://example.org"; const char* c = "https://example.org:*"; @@ -554,7 +578,7 @@ << c << " should not subsume " << b; } -TEST(CSPSourceTest, SchemesOnlySubsumes) { +TEST_P(CSPSourceTest, SchemesOnlySubsumes) { struct TestCase { const char* a; const char* b; @@ -587,7 +611,7 @@ } } -TEST(CSPSourceTest, ToString) { +TEST_P(CSPSourceTest, ToString) { { auto source = network::mojom::CSPSource::New( "http", "", url::PORT_UNSPECIFIED, "", false, false); @@ -630,18 +654,21 @@ } } -TEST(CSPSourceTest, UpgradeRequests) { +TEST_P(CSPSourceTest, UpgradeRequests) { auto source = network::mojom::CSPSource::New("http", "a.com", 80, "", false, false); EXPECT_TRUE(Allow(*source, GURL("http://a.com:80"), no_self, true)); EXPECT_FALSE(Allow(*source, GURL("https://a.com:80"), no_self, true)); EXPECT_FALSE(Allow(*source, GURL("http://a.com:443"), no_self, true)); - EXPECT_TRUE(Allow(*source, GURL("https://a.com:443"), no_self, true)); - EXPECT_TRUE(Allow(*source, GURL("https://a.com"), no_self, true)); + // Upgrades are disallowed for permission policies. + EXPECT_EQ(Allow(*source, GURL("https://a.com:443"), no_self, true), + !IsPermissionsPolicyContext()); + EXPECT_EQ(Allow(*source, GURL("https://a.com"), no_self, true), + !IsPermissionsPolicyContext()); } -TEST(CSPSourceTest, CustomSchemeWithHost) { +TEST_P(CSPSourceTest, CustomSchemeWithHost) { std::string uri = "custom-scheme://a/b"; auto csp_source = CSPSource(uri); auto url = GURL(uri); @@ -659,25 +686,25 @@ // See test: CSPSourceTest.CustomScheme } -TEST(CSPSourceTest, CustomScheme) { +TEST_P(CSPSourceTest, CustomScheme) { auto csp_source = CSPSource("custom-scheme:"); // Scheme only CSP. EXPECT_TRUE(Allow(*csp_source, GURL("custom-scheme://a/b"))); EXPECT_FALSE(Allow(*csp_source, GURL("other-scheme://a/b"))); } -TEST(CSPSourceTest, OpaqueURLMatchingAllowSchemeHttps) { +TEST_P(CSPSourceTest, OpaqueURLMatchingAllowSchemeHttps) { auto source = CSPSource("https:"); EXPECT_TRUE(Allow(*source, GURL("https://a.com"), no_self, /*is_redirect=*/false, /*is_opaque_fenced_frame=*/true)); } -TEST(CSPSourceTest, OpaqueURLMatchingAllowSchemeNonHttps) { +TEST_P(CSPSourceTest, OpaqueURLMatchingAllowSchemeNonHttps) { auto source = CSPSource("http:"); EXPECT_FALSE(Allow(*source, GURL("https://a.com"), no_self, /*is_redirect=*/false, /*is_opaque_fenced_frame=*/true)); } -TEST(CSPSourceTest, OpaqueURLMatchingAllowHostAndPort) { +TEST_P(CSPSourceTest, OpaqueURLMatchingAllowHostAndPort) { { auto source = CSPSource("https://*:*"); EXPECT_TRUE(Allow(*source, GURL("https://a.com"), no_self,
diff --git a/services/network/public/cpp/net_ipc_param_traits.cc b/services/network/public/cpp/net_ipc_param_traits.cc index 25e991b..bf4bf053 100644 --- a/services/network/public/cpp/net_ipc_param_traits.cc +++ b/services/network/public/cpp/net_ipc_param_traits.cc
@@ -84,29 +84,6 @@ l->append("<HashValue>"); } -void ParamTraits<net::HostPortPair>::Write(base::Pickle* m, - const param_type& p) { - WriteParam(m, p.host()); - WriteParam(m, p.port()); -} - -bool ParamTraits<net::HostPortPair>::Read(const base::Pickle* m, - base::PickleIterator* iter, - param_type* r) { - std::string host; - uint16_t port; - if (!ReadParam(m, iter, &host) || !ReadParam(m, iter, &port)) - return false; - - r->set_host(host); - r->set_port(port); - return true; -} - -void ParamTraits<net::HostPortPair>::Log(const param_type& p, std::string* l) { - l->append(p.ToString()); -} - void ParamTraits<net::IPEndPoint>::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.address()); WriteParam(m, p.port()); @@ -209,42 +186,6 @@ l->append("<HttpResponseHeaders>"); } -void ParamTraits<net::ProxyServer>::Write(base::Pickle* m, - const param_type& p) { - net::ProxyServer::Scheme scheme = p.scheme(); - WriteParam(m, scheme); - // When scheme is either 'direct' or 'invalid' |host_port_pair| - // should not be called, as per the method implementation body. - if (scheme != net::ProxyServer::SCHEME_DIRECT && - scheme != net::ProxyServer::SCHEME_INVALID) { - WriteParam(m, p.host_port_pair()); - } -} - -bool ParamTraits<net::ProxyServer>::Read(const base::Pickle* m, - base::PickleIterator* iter, - param_type* r) { - net::ProxyServer::Scheme scheme; - if (!ReadParam(m, iter, &scheme)) - return false; - - // When scheme is either 'direct' or 'invalid' |host_port_pair| - // should not be called, as per the method implementation body. - net::HostPortPair host_port_pair; - if (scheme != net::ProxyServer::SCHEME_DIRECT && - scheme != net::ProxyServer::SCHEME_INVALID && - !ReadParam(m, iter, &host_port_pair)) { - return false; - } - - *r = net::ProxyServer(scheme, host_port_pair); - return true; -} - -void ParamTraits<net::ProxyServer>::Log(const param_type& p, std::string* l) { - l->append("<ProxyServer>"); -} - void ParamTraits<net::OCSPVerifyResult>::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.response_status); @@ -279,33 +220,6 @@ l->append("<ResolveErrorInfo>"); } -void ParamTraits<scoped_refptr<net::SSLCertRequestInfo>>::Write( - base::Pickle* m, - const param_type& p) { - DCHECK(p); - WriteParam(m, p->host_and_port); - WriteParam(m, p->is_proxy); - WriteParam(m, p->cert_authorities); - WriteParam(m, p->cert_key_types); -} - -bool ParamTraits<scoped_refptr<net::SSLCertRequestInfo>>::Read( - const base::Pickle* m, - base::PickleIterator* iter, - param_type* r) { - *r = base::MakeRefCounted<net::SSLCertRequestInfo>(); - return ReadParam(m, iter, &(*r)->host_and_port) && - ReadParam(m, iter, &(*r)->is_proxy) && - ReadParam(m, iter, &(*r)->cert_authorities) && - ReadParam(m, iter, &(*r)->cert_key_types); -} - -void ParamTraits<scoped_refptr<net::SSLCertRequestInfo>>::Log( - const param_type& p, - std::string* l) { - l->append("<SSLCertRequestInfo>"); -} - void ParamTraits<net::SSLInfo>::Write(base::Pickle* m, const param_type& p) { WriteParam(m, p.is_valid()); if (!p.is_valid())
diff --git a/services/network/public/cpp/net_ipc_param_traits.h b/services/network/public/cpp/net_ipc_param_traits.h index a85514f..7aac5c6 100644 --- a/services/network/public/cpp/net_ipc_param_traits.h +++ b/services/network/public/cpp/net_ipc_param_traits.h
@@ -30,7 +30,6 @@ #include "net/http/http_response_info.h" #include "net/http/http_version.h" #include "net/nqe/effective_connection_type.h" -#include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_info.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/url_request/redirect_info.h" @@ -88,17 +87,6 @@ template <> struct COMPONENT_EXPORT(NETWORK_CPP_NETWORK_PARAM) - ParamTraits<net::HostPortPair> { - typedef net::HostPortPair param_type; - static void Write(base::Pickle* m, const param_type& p); - static bool Read(const base::Pickle* m, - base::PickleIterator* iter, - param_type* r); - static void Log(const param_type& p, std::string* l); -}; - -template <> -struct COMPONENT_EXPORT(NETWORK_CPP_NETWORK_PARAM) ParamTraits<net::IPEndPoint> { typedef net::IPEndPoint param_type; static void Write(base::Pickle* m, const param_type& p); @@ -131,17 +119,6 @@ template <> struct COMPONENT_EXPORT(NETWORK_CPP_NETWORK_PARAM) - ParamTraits<net::ProxyServer> { - typedef net::ProxyServer param_type; - static void Write(base::Pickle* m, const param_type& p); - static bool Read(const base::Pickle* m, - base::PickleIterator* iter, - param_type* r); - static void Log(const param_type& p, std::string* l); -}; - -template <> -struct COMPONENT_EXPORT(NETWORK_CPP_NETWORK_PARAM) ParamTraits<net::OCSPVerifyResult> { typedef net::OCSPVerifyResult param_type; static void Write(base::Pickle* m, const param_type& p); @@ -163,17 +140,6 @@ }; template <> -struct COMPONENT_EXPORT(NETWORK_CPP_NETWORK_PARAM) - ParamTraits<scoped_refptr<net::SSLCertRequestInfo>> { - typedef scoped_refptr<net::SSLCertRequestInfo> param_type; - static void Write(base::Pickle* m, const param_type& p); - static bool Read(const base::Pickle* m, - base::PickleIterator* iter, - param_type* r); - static void Log(const param_type& p, std::string* l); -}; - -template <> struct COMPONENT_EXPORT(NETWORK_CPP_NETWORK_PARAM) ParamTraits<net::SSLInfo> { typedef net::SSLInfo param_type; static void Write(base::Pickle* m, const param_type& p); @@ -277,9 +243,6 @@ IPC_ENUM_TRAITS_MAX_VALUE(net::ct::SCTVerifyStatus, net::ct::SCT_STATUS_MAX) IPC_ENUM_TRAITS_MAX_VALUE(net::RequestPriority, net::MAXIMUM_PRIORITY) -IPC_ENUM_TRAITS_MAX_VALUE(net::SSLClientCertType, - net::SSLClientCertType::CLIENT_CERT_INVALID_TYPE) - IPC_ENUM_TRAITS_MAX_VALUE(net::SSLInfo::HandshakeType, net::SSLInfo::HANDSHAKE_FULL)
diff --git a/services/network/public/cpp/network_param_mojom_traits.cc b/services/network/public/cpp/network_param_mojom_traits.cc index 71338230..62f25a9 100644 --- a/services/network/public/cpp/network_param_mojom_traits.cc +++ b/services/network/public/cpp/network_param_mojom_traits.cc
@@ -4,7 +4,11 @@ #include "services/network/public/cpp/network_param_mojom_traits.h" +#include "base/memory/scoped_refptr.h" +#include "base/notreached.h" #include "mojo/public/cpp/bindings/struct_traits.h" +#include "net/ssl/ssl_cert_request_info.h" +#include "net/ssl/ssl_client_cert_type.h" namespace mojo { @@ -54,4 +58,158 @@ return true; } +network::mojom::ProxyScheme +EnumTraits<network::mojom::ProxyScheme, net::ProxyServer::Scheme>::ToMojom( + net::ProxyServer::Scheme scheme) { + using net::ProxyServer; + switch (scheme) { + case ProxyServer::SCHEME_INVALID: + return network::mojom::ProxyScheme::kInvalid; + case ProxyServer::SCHEME_DIRECT: + return network::mojom::ProxyScheme::kDirect; + case ProxyServer::SCHEME_HTTP: + return network::mojom::ProxyScheme::kHttp; + case ProxyServer::SCHEME_SOCKS4: + return network::mojom::ProxyScheme::kSocks4; + case ProxyServer::SCHEME_SOCKS5: + return network::mojom::ProxyScheme::kSocks5; + case ProxyServer::SCHEME_HTTPS: + return network::mojom::ProxyScheme::kHttps; + case ProxyServer::SCHEME_QUIC: + return network::mojom::ProxyScheme::kQuic; + } + NOTREACHED_NORETURN(); +} + +bool EnumTraits<network::mojom::ProxyScheme, net::ProxyServer::Scheme>:: + FromMojom(network::mojom::ProxyScheme scheme, + net::ProxyServer::Scheme* out) { + using net::ProxyServer; + switch (scheme) { + case network::mojom::ProxyScheme::kInvalid: + *out = ProxyServer::SCHEME_INVALID; + return true; + case network::mojom::ProxyScheme::kDirect: + *out = ProxyServer::SCHEME_DIRECT; + return true; + case network::mojom::ProxyScheme::kHttp: + *out = ProxyServer::SCHEME_HTTP; + return true; + case network::mojom::ProxyScheme::kSocks4: + *out = ProxyServer::SCHEME_SOCKS4; + return true; + case network::mojom::ProxyScheme::kSocks5: + *out = ProxyServer::SCHEME_SOCKS5; + return true; + case network::mojom::ProxyScheme::kHttps: + *out = ProxyServer::SCHEME_HTTPS; + return true; + case network::mojom::ProxyScheme::kQuic: + *out = ProxyServer::SCHEME_QUIC; + return true; + } + return false; +} + +absl::optional<net::HostPortPair> +StructTraits<network::mojom::ProxyServerDataView, + net::ProxyServer>::host_and_port(const net::ProxyServer& s) { + if (s.scheme() == net::ProxyServer::SCHEME_DIRECT || + s.scheme() == net::ProxyServer::SCHEME_INVALID) { + return absl::nullopt; + } + return s.host_port_pair(); +} + +bool StructTraits<network::mojom::ProxyServerDataView, net::ProxyServer>::Read( + network::mojom::ProxyServerDataView data, + net::ProxyServer* out) { + net::ProxyServer::Scheme scheme; + if (!data.ReadScheme(&scheme)) { + return false; + } + + absl::optional<net::HostPortPair> host_and_port; + if (!data.ReadHostAndPort(&host_and_port)) { + return false; + } + + if (scheme == net::ProxyServer::SCHEME_INVALID || + scheme == net::ProxyServer::SCHEME_DIRECT) { + if (host_and_port) { + return false; + } + *out = net::ProxyServer(scheme, net::HostPortPair()); + return true; + } else { + if (!host_and_port) { + return false; + } + *out = net::ProxyServer(scheme, std::move(*host_and_port)); + return true; + } +} + +// static +network::mojom::SSLClientCertType +EnumTraits<network::mojom::SSLClientCertType, net::SSLClientCertType>::ToMojom( + net::SSLClientCertType scheme) { + switch (scheme) { + case net::SSLClientCertType::CLIENT_CERT_RSA_SIGN: + return network::mojom::SSLClientCertType::kRsaSign; + case net::SSLClientCertType::CLIENT_CERT_ECDSA_SIGN: + return network::mojom::SSLClientCertType::kEcdsaSign; + case net::SSLClientCertType::CLIENT_CERT_INVALID_TYPE: + return network::mojom::SSLClientCertType::kInvalid; + } + NOTREACHED_NORETURN(); +} + +// static +bool EnumTraits<network::mojom::SSLClientCertType, net::SSLClientCertType>:: + FromMojom(network::mojom::SSLClientCertType scheme, + net::SSLClientCertType* out) { + switch (scheme) { + case network::mojom::SSLClientCertType::kRsaSign: + *out = net::SSLClientCertType::CLIENT_CERT_RSA_SIGN; + return true; + case network::mojom::SSLClientCertType::kEcdsaSign: + *out = net::SSLClientCertType::CLIENT_CERT_ECDSA_SIGN; + return true; + case network::mojom::SSLClientCertType::kInvalid: + *out = net::SSLClientCertType::CLIENT_CERT_INVALID_TYPE; + return true; + } + return false; +} + +// static +bool StructTraits<network::mojom::SSLCertRequestInfoDataView, + scoped_refptr<net::SSLCertRequestInfo>>:: + Read(network::mojom::SSLCertRequestInfoDataView data, + scoped_refptr<net::SSLCertRequestInfo>* out) { + net::HostPortPair host_and_port; + if (!data.ReadHostAndPort(&host_and_port)) { + return false; + } + std::vector<std::string> cert_authorities; + if (!data.ReadCertAuthorities(&cert_authorities)) { + return false; + } + std::vector<net::SSLClientCertType> cert_key_types; + if (!data.ReadCertKeyTypes(&cert_key_types)) { + return false; + } + + auto ssl_cert_request_info = base::MakeRefCounted<net::SSLCertRequestInfo>(); + ssl_cert_request_info->host_and_port = std::move(host_and_port); + ssl_cert_request_info->is_proxy = data.is_proxy(); + ssl_cert_request_info->cert_authorities = std::move(cert_authorities); + ssl_cert_request_info->cert_key_types = std::move(cert_key_types); + + *out = ssl_cert_request_info; + + return true; +} + } // namespace mojo
diff --git a/services/network/public/cpp/network_param_mojom_traits.h b/services/network/public/cpp/network_param_mojom_traits.h index 993b5cf7..ebfad9ab 100644 --- a/services/network/public/cpp/network_param_mojom_traits.h +++ b/services/network/public/cpp/network_param_mojom_traits.h
@@ -6,11 +6,15 @@ #define SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_MOJOM_TRAITS_H_ #include "base/component_export.h" +#include "base/memory/scoped_refptr.h" #include "mojo/public/cpp/bindings/struct_traits.h" #include "net/base/auth.h" #include "net/base/host_port_pair.h" +#include "net/base/proxy_server.h" #include "net/dns/public/resolve_error_info.h" #include "net/http/http_version.h" +#include "net/ssl/ssl_cert_request_info.h" +#include "net/ssl/ssl_client_cert_type.h" #include "services/network/public/mojom/network_param.mojom-shared.h" #include "url/mojom/scheme_host_port_mojom_traits.h" @@ -98,6 +102,74 @@ net::HostPortPair* out); }; +template <> +struct COMPONENT_EXPORT(NETWORK_CPP_NETWORK_PARAM) + EnumTraits<network::mojom::ProxyScheme, net::ProxyServer::Scheme> { + static network::mojom::ProxyScheme ToMojom(net::ProxyServer::Scheme scheme); + static bool FromMojom(network::mojom::ProxyScheme scheme, + net::ProxyServer::Scheme* out); +}; + +template <> +class COMPONENT_EXPORT(NETWORK_CPP_NETWORK_PARAM) + StructTraits<network::mojom::ProxyServerDataView, net::ProxyServer> { + public: + static net::ProxyServer::Scheme scheme(const net::ProxyServer& s) { + return s.scheme(); + } + + static absl::optional<net::HostPortPair> host_and_port( + const net::ProxyServer& s); + + static bool Read(network::mojom::ProxyServerDataView data, + net::ProxyServer* out); +}; + +template <> +struct COMPONENT_EXPORT(NETWORK_CPP_NETWORK_PARAM) + EnumTraits<network::mojom::SSLClientCertType, net::SSLClientCertType> { + static network::mojom::SSLClientCertType ToMojom( + net::SSLClientCertType scheme); + static bool FromMojom(network::mojom::SSLClientCertType scheme, + net::SSLClientCertType* out); +}; + +template <> +class COMPONENT_EXPORT(NETWORK_CPP_NETWORK_PARAM) + StructTraits<network::mojom::SSLCertRequestInfoDataView, + scoped_refptr<net::SSLCertRequestInfo>> { + public: + static bool IsNull(const scoped_refptr<net::SSLCertRequestInfo>& r) { + return !r; + } + + static void SetToNull(scoped_refptr<net::SSLCertRequestInfo>* output) { + *output = nullptr; + } + + static const net::HostPortPair& host_and_port( + const scoped_refptr<net::SSLCertRequestInfo>& s) { + return s->host_and_port; + } + + static bool is_proxy(const scoped_refptr<net::SSLCertRequestInfo>& s) { + return s->is_proxy; + } + + static const std::vector<std::string>& cert_authorities( + const scoped_refptr<net::SSLCertRequestInfo>& s) { + return s->cert_authorities; + } + + static const std::vector<net::SSLClientCertType>& cert_key_types( + const scoped_refptr<net::SSLCertRequestInfo>& s) { + return s->cert_key_types; + } + + static bool Read(network::mojom::SSLCertRequestInfoDataView data, + scoped_refptr<net::SSLCertRequestInfo>* out); +}; + } // namespace mojo #endif // SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_MOJOM_TRAITS_H_
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn index 496ccda..c77add61 100644 --- a/services/network/public/mojom/BUILD.gn +++ b/services/network/public/mojom/BUILD.gn
@@ -849,6 +849,10 @@ cpp = "::net::ProxyServer" }, { + mojom = "network.mojom.ProxyScheme" + cpp = "::net::ProxyServer::Scheme" + }, + { mojom = "network.mojom.ResolveErrorInfo" cpp = "::net::ResolveErrorInfo" },
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom index 67ec1324..915aa8ea 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom
@@ -120,12 +120,12 @@ // network error encountered, if any, and OK if the fallback was for a reason // other than a network error (e.g. the proxy service was explicitly directed // to skip a proxy). - OnFallback(proxy_resolver.mojom.ProxyServer bad_proxy, int32 net_error); + OnFallback(ProxyServer bad_proxy, int32 net_error); // Called when the response headers for the proxy tunnel request have been // received. OnTunnelHeadersReceived( - proxy_resolver.mojom.ProxyServer proxy_server, + ProxyServer proxy_server, HttpResponseHeaders response_headers); }; @@ -1472,7 +1472,7 @@ // specified as a case-insensitive string. Unlike server credentials, proxy // credentials are not keyed on NetworkAnonymizationKey. [EnableIf=is_chromeos_ash] - LookupProxyAuthCredentials(proxy_resolver.mojom.ProxyServer proxy_server, + LookupProxyAuthCredentials(ProxyServer proxy_server, string auth_scheme, string realm) => (AuthCredentials? credentials);
diff --git a/services/network/public/mojom/network_param.mojom b/services/network/public/mojom/network_param.mojom index 1ab7e7b9..f162a0a9 100644 --- a/services/network/public/mojom/network_param.mojom +++ b/services/network/public/mojom/network_param.mojom
@@ -43,8 +43,24 @@ uint16 port; }; -[Native] -struct ProxyServer; +// Mirror of net::ProxyServer::Scheme. +enum ProxyScheme { + kInvalid, + kDirect, + kHttp, + kSocks4, + kSocks5, + kHttps, + kQuic, +}; + +// Mirror of net::ProxyServer. +struct ProxyServer { + ProxyScheme scheme; + + // |host_and_port| field is set iff |scheme| is not INVALID or DIRECT. + HostPortPair? host_and_port; +}; // Host resolution error info. struct ResolveErrorInfo { @@ -58,8 +74,27 @@ bool is_secure_network_error = false; }; -[Native] -struct SSLCertRequestInfo; +// Mirror of net::SSLClientCertType. +enum SSLClientCertType { + kRsaSign = 1, + kEcdsaSign = 64, + kInvalid = 255, +}; + +// Mirror of net::SSLCertRequestInfo. +struct SSLCertRequestInfo { + // The host and port of the SSL server that requested client authentication. + HostPortPair host_and_port; + + // True if the server that issues this request was the HTTPS proxy used in + // the request. False, if the server was the origin server. + bool is_proxy = false; + + // List of DER-encoded X.509 DistinguishedName of certificate authorities + // allowed by the server. + array<string> cert_authorities; + array<SSLClientCertType> cert_key_types; +}; [Native] struct SSLInfo;
diff --git a/services/network/public/mojom/url_response_head.mojom b/services/network/public/mojom/url_response_head.mojom index f232e846..beab4de 100644 --- a/services/network/public/mojom/url_response_head.mojom +++ b/services/network/public/mojom/url_response_head.mojom
@@ -121,7 +121,7 @@ NavigationDeliveryType navigation_delivery_type = kDefault; // The proxy server used for this request, if any. - proxy_resolver.mojom.ProxyServer proxy_server; + ProxyServer proxy_server; // True if a service worker responded to the request. If the service worker // received a fetch event and did not call respondWith(), or was bypassed due
diff --git a/services/proxy_resolver/public/cpp/BUILD.gn b/services/proxy_resolver/public/cpp/BUILD.gn new file mode 100644 index 0000000..95eada0bd --- /dev/null +++ b/services/proxy_resolver/public/cpp/BUILD.gn
@@ -0,0 +1,19 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD - style license that can be +# found in the LICENSE file. + +component("proxy_resolver_mojom_support") { + sources = [ + "mojo_host_mojom_traits.cc", + "mojo_host_mojom_traits.h", + "proxy_resolver_mojom_traits.cc", + "proxy_resolver_mojom_traits.h", + ] + deps = [ + "//net", + "//services/network/public/mojom:mojom_network_param", + "//services/proxy_resolver/public/mojom:mojom_shared", + "//url/mojom:url_mojom_gurl", + ] + defines = [ "IS_PROXY_RESOLVER_CPP_IMPL" ] +}
diff --git a/services/proxy_resolver/public/cpp/mojo_host_mojom_traits.h b/services/proxy_resolver/public/cpp/mojo_host_mojom_traits.h index a8541a7..693d116 100644 --- a/services/proxy_resolver/public/cpp/mojo_host_mojom_traits.h +++ b/services/proxy_resolver/public/cpp/mojo_host_mojom_traits.h
@@ -5,6 +5,7 @@ #ifndef SERVICES_PROXY_RESOLVER_PUBLIC_CPP_MOJO_HOST_MOJOM_TRAITS_H_ #define SERVICES_PROXY_RESOLVER_PUBLIC_CPP_MOJO_HOST_MOJOM_TRAITS_H_ +#include "base/component_export.h" #include "base/strings/string_piece.h" #include "mojo/public/cpp/bindings/enum_traits.h" #include "net/proxy_resolution/proxy_resolve_dns_operation.h" @@ -13,8 +14,9 @@ namespace mojo { template <> -struct EnumTraits<proxy_resolver::mojom::HostResolveOperation, - net::ProxyResolveDnsOperation> { +struct COMPONENT_EXPORT(PROXY_RESOLVER_CPP) + EnumTraits<proxy_resolver::mojom::HostResolveOperation, + net::ProxyResolveDnsOperation> { static proxy_resolver::mojom::HostResolveOperation ToMojom( net::ProxyResolveDnsOperation input);
diff --git a/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.cc b/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.cc index 96a904a..601a13d 100644 --- a/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.cc +++ b/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.cc
@@ -4,119 +4,22 @@ #include "services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h" -#include "base/notreached.h" -#include "base/strings/string_piece.h" -#include "net/base/host_port_pair.h" #include "net/base/proxy_server.h" -#include "net/proxy_resolution/proxy_info.h" +#include "services/network/public/cpp/network_param_mojom_traits.h" namespace mojo { -proxy_resolver::mojom::ProxyScheme -EnumTraits<proxy_resolver::mojom::ProxyScheme, - net::ProxyServer::Scheme>::ToMojom(net::ProxyServer::Scheme scheme) { - using net::ProxyServer; - switch (scheme) { - case ProxyServer::SCHEME_INVALID: - return proxy_resolver::mojom::ProxyScheme::INVALID; - case ProxyServer::SCHEME_DIRECT: - return proxy_resolver::mojom::ProxyScheme::DIRECT; - case ProxyServer::SCHEME_HTTP: - return proxy_resolver::mojom::ProxyScheme::HTTP; - case ProxyServer::SCHEME_SOCKS4: - return proxy_resolver::mojom::ProxyScheme::SOCKS4; - case ProxyServer::SCHEME_SOCKS5: - return proxy_resolver::mojom::ProxyScheme::SOCKS5; - case ProxyServer::SCHEME_HTTPS: - return proxy_resolver::mojom::ProxyScheme::HTTPS; - case ProxyServer::SCHEME_QUIC: - return proxy_resolver::mojom::ProxyScheme::QUIC; - } - NOTREACHED(); - return proxy_resolver::mojom::ProxyScheme::INVALID; -} - -bool EnumTraits<proxy_resolver::mojom::ProxyScheme, net::ProxyServer::Scheme>:: - FromMojom(proxy_resolver::mojom::ProxyScheme scheme, - net::ProxyServer::Scheme* out) { - using net::ProxyServer; - switch (scheme) { - case proxy_resolver::mojom::ProxyScheme::INVALID: - *out = ProxyServer::SCHEME_INVALID; - return true; - case proxy_resolver::mojom::ProxyScheme::DIRECT: - *out = ProxyServer::SCHEME_DIRECT; - return true; - case proxy_resolver::mojom::ProxyScheme::HTTP: - *out = ProxyServer::SCHEME_HTTP; - return true; - case proxy_resolver::mojom::ProxyScheme::SOCKS4: - *out = ProxyServer::SCHEME_SOCKS4; - return true; - case proxy_resolver::mojom::ProxyScheme::SOCKS5: - *out = ProxyServer::SCHEME_SOCKS5; - return true; - case proxy_resolver::mojom::ProxyScheme::HTTPS: - *out = ProxyServer::SCHEME_HTTPS; - return true; - case proxy_resolver::mojom::ProxyScheme::QUIC: - *out = ProxyServer::SCHEME_QUIC; - return true; - } - return false; -} - -base::StringPiece -StructTraits<proxy_resolver::mojom::ProxyServerDataView, - net::ProxyServer>::host(const net::ProxyServer& s) { - if (s.scheme() == net::ProxyServer::SCHEME_DIRECT || - s.scheme() == net::ProxyServer::SCHEME_INVALID) { - return base::StringPiece(); - } - return s.host_port_pair().host(); -} - -uint16_t StructTraits<proxy_resolver::mojom::ProxyServerDataView, - net::ProxyServer>::port(const net::ProxyServer& s) { - if (s.scheme() == net::ProxyServer::SCHEME_DIRECT || - s.scheme() == net::ProxyServer::SCHEME_INVALID) { - return 0; - } - return s.host_port_pair().port(); -} - -bool StructTraits< - proxy_resolver::mojom::ProxyServerDataView, - net::ProxyServer>::Read(proxy_resolver::mojom::ProxyServerDataView data, - net::ProxyServer* out) { - net::ProxyServer::Scheme scheme; - if (!data.ReadScheme(&scheme)) - return false; - - base::StringPiece host; - if (!data.ReadHost(&host)) - return false; - - if ((scheme == net::ProxyServer::SCHEME_DIRECT || - scheme == net::ProxyServer::SCHEME_INVALID) && - (!host.empty() || data.port())) { - return false; - } - - *out = net::ProxyServer(scheme, - net::HostPortPair(std::string(host), data.port())); - return true; -} - bool StructTraits<proxy_resolver::mojom::ProxyInfoDataView, net::ProxyInfo>:: Read(proxy_resolver::mojom::ProxyInfoDataView data, net::ProxyInfo* out) { std::vector<net::ProxyServer> proxy_servers; - if (!data.ReadProxyServers(&proxy_servers)) + if (!data.ReadProxyServers(&proxy_servers)) { return false; + } net::ProxyList proxy_list; - for (const auto& server : proxy_servers) + for (const auto& server : proxy_servers) { proxy_list.AddProxyServer(server); + } out->UseProxyList(proxy_list); return true;
diff --git a/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h b/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h index 86b884d0..3b88f82 100644 --- a/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h +++ b/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h
@@ -5,47 +5,16 @@ #ifndef SERVICES_PROXY_RESOLVER_PUBLIC_CPP_PROXY_RESOLVER_MOJOM_TRAITS_H_ #define SERVICES_PROXY_RESOLVER_PUBLIC_CPP_PROXY_RESOLVER_MOJOM_TRAITS_H_ -#include "base/strings/string_piece.h" -#include "mojo/public/cpp/bindings/enum_traits.h" #include "mojo/public/cpp/bindings/struct_traits.h" -#include "net/base/host_port_pair.h" -#include "net/base/proxy_server.h" #include "net/proxy_resolution/proxy_info.h" #include "net/proxy_resolution/proxy_list.h" #include "services/proxy_resolver/public/mojom/proxy_resolver.mojom-shared.h" -namespace net { -class ProxyInfo; -class ProxyServer; -} // namespace net - namespace mojo { template <> -struct EnumTraits<proxy_resolver::mojom::ProxyScheme, - net::ProxyServer::Scheme> { - static proxy_resolver::mojom::ProxyScheme ToMojom( - net::ProxyServer::Scheme scheme); - static bool FromMojom(proxy_resolver::mojom::ProxyScheme scheme, - net::ProxyServer::Scheme* out); -}; - -template <> -struct StructTraits<proxy_resolver::mojom::ProxyServerDataView, - net::ProxyServer> { - static net::ProxyServer::Scheme scheme(const net::ProxyServer& s) { - return s.scheme(); - } - - static base::StringPiece host(const net::ProxyServer& s); - static uint16_t port(const net::ProxyServer& s); - - static bool Read(proxy_resolver::mojom::ProxyServerDataView data, - net::ProxyServer* out); -}; - -template <> -struct StructTraits<proxy_resolver::mojom::ProxyInfoDataView, net::ProxyInfo> { +struct COMPONENT_EXPORT(PROXY_RESOLVER_CPP) + StructTraits<proxy_resolver::mojom::ProxyInfoDataView, net::ProxyInfo> { static const std::vector<net::ProxyServer>& proxy_servers( const net::ProxyInfo& info) { return info.proxy_list().GetAll();
diff --git a/services/proxy_resolver/public/mojom/BUILD.gn b/services/proxy_resolver/public/mojom/BUILD.gn index 8bca51b..23d9c4a 100644 --- a/services/proxy_resolver/public/mojom/BUILD.gn +++ b/services/proxy_resolver/public/mojom/BUILD.gn
@@ -10,7 +10,7 @@ deps = [ "//services/network/public/mojom:mojom_ip_address", "//services/network/public/mojom:mojom_network_anonymization_key", - "//services/network/public/mojom:mojom_network_isolation_key", + "//services/network/public/mojom:mojom_network_param", "//url/mojom:url_mojom_gurl", ] public_deps = [ "//sandbox/policy/mojom" ] @@ -33,24 +33,13 @@ mojom = "proxy_resolver.mojom.ProxyInfo" cpp = "::net::ProxyInfo" }, - - { - mojom = "proxy_resolver.mojom.ProxyServer" - cpp = "::net::ProxyServer" - }, - - { - mojom = "proxy_resolver.mojom.ProxyServer::Scheme" - cpp = "::net::ProxyScheme" - }, ] traits_headers = [ "//services/proxy_resolver/public/cpp/mojo_host_mojom_traits.h", "//services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h", ] - traits_sources = [ - "//services/proxy_resolver/public/cpp/mojo_host_mojom_traits.cc", - "//services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.cc", + traits_public_deps = [ + "//services/proxy_resolver/public/cpp:proxy_resolver_mojom_support", ] }, ]
diff --git a/services/proxy_resolver/public/mojom/proxy_resolver.mojom b/services/proxy_resolver/public/mojom/proxy_resolver.mojom index d13f42e..d016703 100644 --- a/services/proxy_resolver/public/mojom/proxy_resolver.mojom +++ b/services/proxy_resolver/public/mojom/proxy_resolver.mojom
@@ -10,6 +10,7 @@ import "sandbox/policy/mojom/sandbox.mojom"; import "services/network/public/mojom/ip_address.mojom"; import "services/network/public/mojom/network_anonymization_key.mojom"; +import "services/network/public/mojom/network_param.mojom"; import "url/mojom/url.mojom"; // Mirror of net::ProxyResolveDnsOperation. @@ -27,28 +28,8 @@ ReportResult(int32 error, array<network.mojom.IPAddress> result); }; -// Mirror of net::ProxyServer::Scheme. -enum ProxyScheme { - INVALID, - DIRECT, - HTTP, - SOCKS4, - SOCKS5, - HTTPS, - QUIC, -}; - -// Mirror of net::ProxyServer. -struct ProxyServer { - ProxyScheme scheme; - - // |host| and |port| are only valid if |scheme| is not INVALID or DIRECT. - string host; - uint16 port; -}; - struct ProxyInfo { - array<ProxyServer> proxy_servers; + array<network.mojom.ProxyServer> proxy_servers; }; interface ProxyResolver {
diff --git a/testing/buildbot/OWNERS b/testing/buildbot/OWNERS index 3bba0306d..7e66cc0 100644 --- a/testing/buildbot/OWNERS +++ b/testing/buildbot/OWNERS
@@ -39,7 +39,7 @@ per-file *chromium.perf*.json=hypan@google.com # For OOBE-related test filters. -per-file *oobe*=file://chrome/browser/ui/webui/ash/login/OWNERS +per-file *oobe*=file://ash/login/OOBE_WEBUI_OWNERS # iOS Owners per-file chromium.clang.json=file://infra/config/groups/ios/OWNERS
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 737457d7..b5bf0b66 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -5618,9 +5618,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5631,8 +5631,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -5783,9 +5783,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5796,8 +5796,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -5930,9 +5930,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5943,8 +5943,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json index ed30e49a..d697c5b6 100644 --- a/testing/buildbot/chromium.coverage.json +++ b/testing/buildbot/chromium.coverage.json
@@ -25212,9 +25212,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -25225,8 +25225,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -25377,9 +25377,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -25390,8 +25390,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -25524,9 +25524,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -25537,8 +25537,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 1c26746..ffa5ac6 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -33946,9 +33946,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -33958,8 +33958,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -34111,9 +34111,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -34123,8 +34123,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -34258,9 +34258,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -34270,8 +34270,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -35698,9 +35698,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -35710,8 +35710,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -35863,9 +35863,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -35875,8 +35875,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -36010,9 +36010,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -36022,8 +36022,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -36739,9 +36739,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -36751,8 +36751,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index a10cad8..dddfaba 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -17723,12 +17723,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -17739,8 +17739,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -17908,12 +17908,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -17924,8 +17924,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [ @@ -18070,12 +18070,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 114.0.5711.3", + "description": "Run with ash-chrome version 114.0.5712.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -18086,8 +18086,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v114.0.5711.3", - "revision": "version:114.0.5711.3" + "location": "lacros_version_skew_tests_v114.0.5712.0", + "revision": "version:114.0.5712.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index bbcc5dc..d1da0f2c 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@ }, 'LACROS_VERSION_SKEW_CANARY': { 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5711.3/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5712.0/test_ash_chrome', ], - 'description': 'Run with ash-chrome version 114.0.5711.3', + 'description': 'Run with ash-chrome version 114.0.5712.0', 'identifier': 'Lacros version skew testing ash canary', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v114.0.5711.3', - 'revision': 'version:114.0.5711.3', + 'location': 'lacros_version_skew_tests_v114.0.5712.0', + 'revision': 'version:114.0.5712.0', }, ], },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 084619c..65b257eef 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -10247,12 +10247,14 @@ { "name": "Enabled_20230101", "enable_features": [ + "CrosPrivacyHub", "CrosPrivacyHubV0" ] }, { "name": "Enabled_20230101_Dogfood", "enable_features": [ + "CrosPrivacyHub", "CrosPrivacyHubV0" ] } @@ -12711,25 +12713,6 @@ ] } ], - "TangibleSyncOnDesktop": [ - { - "platforms": [ - "windows", - "mac", - "linux", - "chromeos_lacros", - "fuchsia" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "TangibleSync" - ] - } - ] - } - ], "TerminalTmuxRollout": [ { "platforms": [
diff --git a/third_party/.gitignore b/third_party/.gitignore index 06405f8..9978d8b 100644 --- a/third_party/.gitignore +++ b/third_party/.gitignore
@@ -251,6 +251,9 @@ /scons-2.0.1 /securemessage/src /shaka-player/dist/ +/siso/siso +/siso/siso.exe +/siso/.versions /skia /smhasher/src /snappy/src
diff --git a/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc b/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc index f7084e1..9f7d5e8 100644 --- a/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc +++ b/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc
@@ -94,12 +94,8 @@ bool OriginWithPossibleWildcards::DoesMatchOrigin( const url::Origin& match_origin) const { - // TODO(crbug.com/1418009): Add way to prevent CSP matching from allowing - // upgrades (http -> https) as permissions don't allow this. - return network::CheckCSPSource(csp_source, match_origin.GetURL(), - csp_source) && - csp_source.scheme == match_origin.scheme() && - csp_source.port == (match_origin.port() ?: url::PORT_UNSPECIFIED); + return network::CheckCSPSource(csp_source, match_origin.GetURL(), csp_source, + network::CSPSourceContext::PermissionsPolicy); } bool operator==(const OriginWithPossibleWildcards& lhs,
diff --git a/third_party/blink/renderer/core/fileapi/blob.cc b/third_party/blink/renderer/core/fileapi/blob.cc index 3ba1dfff..a84587a1 100644 --- a/third_party/blink/renderer/core/fileapi/blob.cc +++ b/third_party/blink/renderer/core/fileapi/blob.cc
@@ -41,8 +41,8 @@ #include "third_party/blink/renderer/core/fetch/blob_bytes_consumer.h" #include "third_party/blink/renderer/core/fetch/body_stream_buffer.h" #include "third_party/blink/renderer/core/fileapi/file_read_type.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" #include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/core/url/dom_url.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" @@ -65,18 +65,16 @@ // Helper class to asynchronously read from a Blob using a FileReaderLoader. // Each client is only good for one Blob read operation. -// Each instance owns itself and will delete itself in the callbacks. // This class is not thread-safe. class BlobFileReaderClient : public GarbageCollected<BlobFileReaderClient>, - public blink::FileReaderLoaderClient { + public FileReaderAccumulator { public: BlobFileReaderClient( const scoped_refptr<BlobDataHandle> blob_data_handle, const scoped_refptr<base::SingleThreadTaskRunner> task_runner, const FileReadType read_type, ScriptPromiseResolver* resolver) - : loader_(MakeGarbageCollected<FileReaderLoader>(read_type, - this, + : loader_(MakeGarbageCollected<FileReaderLoader>(this, std::move(task_runner))), resolver_(resolver), read_type_(read_type), @@ -87,19 +85,17 @@ void Trace(Visitor* visitor) const override { visitor->Trace(loader_); visitor->Trace(resolver_); - blink::FileReaderLoaderClient::Trace(visitor); + FileReaderAccumulator::Trace(visitor); } ~BlobFileReaderClient() override = default; - void DidStartLoading() override {} - void DidReceiveData() override {} void DidFail(FileErrorCode error_code) override { + FileReaderAccumulator::DidFail(error_code); resolver_->Reject(file_error::CreateDOMException(error_code)); - keep_alive_.Clear(); + Done(); } - void DidFinishLoading() override { - FileReaderData contents = loader_->TakeContents(); + void DidFinishLoading(FileReaderData contents) override { if (read_type_ == FileReadType::kReadAsText) { String result = std::move(contents).AsText("UTF-8"); resolver_->Resolve(result); @@ -109,10 +105,14 @@ } else { NOTREACHED() << "Unknown ReadType supplied to BlobFileReaderClient"; } - keep_alive_.Clear(); + Done(); } private: + void Done() { + keep_alive_.Clear(); + loader_ = nullptr; + } Member<FileReaderLoader> loader_; Member<ScriptPromiseResolver> resolver_; const FileReadType read_type_;
diff --git a/third_party/blink/renderer/core/fileapi/build.gni b/third_party/blink/renderer/core/fileapi/build.gni index 4ab90aa..ee57332b 100644 --- a/third_party/blink/renderer/core/fileapi/build.gni +++ b/third_party/blink/renderer/core/fileapi/build.gni
@@ -18,7 +18,8 @@ "file_reader_data.h", "file_reader_loader.cc", "file_reader_loader.h", - "file_reader_loader_client.h", + "file_reader_client.cc", + "file_reader_client.h", "file_reader_sync.cc", "file_reader_sync.h", "public_url_manager.cc",
diff --git a/third_party/blink/renderer/core/fileapi/file_read_type.h b/third_party/blink/renderer/core/fileapi/file_read_type.h index 661a6a62..21f8ecd2 100644 --- a/third_party/blink/renderer/core/fileapi/file_read_type.h +++ b/third_party/blink/renderer/core/fileapi/file_read_type.h
@@ -11,8 +11,7 @@ kReadAsArrayBuffer, kReadAsBinaryString, kReadAsText, - kReadAsDataURL, - kReadByClient + kReadAsDataURL }; } // namespace blink
diff --git a/third_party/blink/renderer/core/fileapi/file_reader.cc b/third_party/blink/renderer/core/fileapi/file_reader.cc index cd3c011d..17f54131 100644 --- a/third_party/blink/renderer/core/fileapi/file_reader.cc +++ b/third_party/blink/renderer/core/fileapi/file_reader.cc
@@ -318,8 +318,7 @@ loading_state_ = kLoadingStateLoading; loader_ = MakeGarbageCollected<FileReaderLoader>( - read_type_, this, - GetExecutionContext()->GetTaskRunner(TaskType::kFileReading)); + this, GetExecutionContext()->GetTaskRunner(TaskType::kFileReading)); loader_->Start(blob_data_handle_); blob_data_handle_ = nullptr; } @@ -381,12 +380,13 @@ loading_state_ = kLoadingStateNone; } -void FileReader::DidStartLoading() { +FileErrorCode FileReader::DidStartLoading() { base::AutoReset<bool> firing_events(&still_firing_events_, true); FireEvent(event_type_names::kLoadstart); + return FileErrorCode::kOK; } -void FileReader::DidReceiveData() { +FileErrorCode FileReader::DidReceiveData() { // Fire the progress event at least every 50ms. if (!last_progress_notification_time_) { last_progress_notification_time_ = base::ElapsedTimer(); @@ -396,21 +396,21 @@ FireEvent(event_type_names::kProgress); last_progress_notification_time_ = base::ElapsedTimer(); } + return FileErrorCode::kOK; } -void FileReader::DidFinishLoading() { +void FileReader::DidFinishLoading(FileReaderData contents) { if (loading_state_ == kLoadingStateAborted) return; DCHECK_EQ(loading_state_, kLoadingStateLoading); if (read_type_ == FileReadType::kReadAsArrayBuffer) { result_ = MakeGarbageCollected<V8UnionArrayBufferOrString>( - loader_->TakeContents().AsDOMArrayBuffer()); + std::move(contents).AsDOMArrayBuffer()); } else { result_ = MakeGarbageCollected<V8UnionArrayBufferOrString>( - loader_->TakeContents().AsString(read_type_, encoding_, blob_type_)); + std::move(contents).AsString(read_type_, encoding_, blob_type_)); } - // When we set m_state to DONE below, we still need to fire // the load and loadend events. To avoid GC to collect this FileReader, we // use this separate variable to keep the wrapper of this FileReader alive. @@ -442,6 +442,7 @@ } void FileReader::DidFail(FileErrorCode error_code) { + FileReaderAccumulator::DidFail(error_code); if (loading_state_ == kLoadingStateAborted) return; @@ -489,7 +490,7 @@ visitor->Trace(result_); EventTargetWithInlineData::Trace(visitor); ExecutionContextLifecycleObserver::Trace(visitor); - FileReaderLoaderClient::Trace(visitor); + FileReaderAccumulator::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/core/fileapi/file_reader.h b/third_party/blink/renderer/core/fileapi/file_reader.h index 79c598cc..205d1ce 100644 --- a/third_party/blink/renderer/core/fileapi/file_reader.h +++ b/third_party/blink/renderer/core/fileapi/file_reader.h
@@ -36,9 +36,10 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/events/event_target.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/fileapi/file_error.h" #include "third_party/blink/renderer/core/fileapi/file_read_type.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" #include "third_party/blink/renderer/core/probe/async_task_context.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/wtf/forward.h" @@ -54,7 +55,7 @@ class CORE_EXPORT FileReader final : public EventTargetWithInlineData, public ActiveScriptWrappable<FileReader>, public ExecutionContextLifecycleObserver, - public FileReaderLoaderClient { + public FileReaderAccumulator { DEFINE_WRAPPERTYPEINFO(); public: @@ -89,10 +90,10 @@ return ExecutionContextLifecycleObserver::GetExecutionContext(); } - // FileReaderLoaderClient - void DidStartLoading() override; - void DidReceiveData() override; - void DidFinishLoading() override; + // FileReaderClient + FileErrorCode DidStartLoading() override; + FileErrorCode DidReceiveData() override; + void DidFinishLoading(FileReaderData contents) override; void DidFail(FileErrorCode) override; DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart, kLoadstart)
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_client.cc b/third_party/blink/renderer/core/fileapi/file_reader_client.cc new file mode 100644 index 0000000..e87ea791 --- /dev/null +++ b/third_party/blink/renderer/core/fileapi/file_reader_client.cc
@@ -0,0 +1,69 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" +#include "third_party/blink/renderer/core/fileapi/file_read_type.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" +#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h" +#include "third_party/blink/renderer/platform/wtf/text/base64.h" +#include "third_party/blink/renderer/platform/wtf/text/string_builder.h" + +namespace blink { + +FileErrorCode FileReaderAccumulator::DidStartLoading(uint64_t size, + uint64_t total_bytes) { + bytes_loaded_ = 0; + raw_data_ = ArrayBufferContents(static_cast<unsigned>(total_bytes), 1, + ArrayBufferContents::kNotShared, + ArrayBufferContents::kDontInitialize); + if (!raw_data_.IsValid()) { + return FileErrorCode::kNotReadableErr; + } + return DidStartLoading(); +} + +FileErrorCode FileReaderAccumulator::DidReceiveData(const char* data, + unsigned data_length) { + // Fill out the buffer + if (bytes_loaded_ + data_length > raw_data_.DataLength()) { + raw_data_.Reset(); + bytes_loaded_ = 0; + return FileErrorCode::kNotReadableErr; + } + memcpy(static_cast<char*>(raw_data_.Data()) + bytes_loaded_, data, + data_length); + bytes_loaded_ += data_length; + return DidReceiveData(); +} + +void FileReaderAccumulator::DidFinishLoading() { + DCHECK_EQ(bytes_loaded_, raw_data_.DataLength()); + CHECK(raw_data_.IsValid()); + DidFinishLoading(FileReaderData(std::move(raw_data_))); +} + +void FileReaderAccumulator::DidFail(FileErrorCode) { + bytes_loaded_ = 0; + raw_data_.Reset(); +} + +std::pair<FileErrorCode, FileReaderData> SyncedFileReaderAccumulator::Load( + scoped_refptr<BlobDataHandle> handle, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + auto* client = MakeGarbageCollected<SyncedFileReaderAccumulator>(); + auto* file_reader = + MakeGarbageCollected<FileReaderLoader>(client, std::move(task_runner)); + + file_reader->StartSync(std::move(handle)); + return {client->error_code_, std::move(client->stored_)}; +} + +void SyncedFileReaderAccumulator::DidFail(FileErrorCode error_code) { + error_code_ = error_code; +} +void SyncedFileReaderAccumulator::DidFinishLoading(FileReaderData obj) { + stored_ = std::move(obj); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_client.h b/third_party/blink/renderer/core/fileapi/file_reader_client.h new file mode 100644 index 0000000..37850a03 --- /dev/null +++ b/third_party/blink/renderer/core/fileapi/file_reader_client.h
@@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_FILE_READER_CLIENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_FILE_READER_CLIENT_H_ + +#include "base/task/single_thread_task_runner.h" +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/fileapi/file_error.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_data.h" +#include "third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.h" +#include "third_party/blink/renderer/platform/blob/blob_data.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" + +namespace blink { + +enum class FileErrorCode; + +// FileReaderClient is used by the FileReaderLoader to read a given blob's raw +// data. For a more convenient way to read blobs that matches the different +// FileReadType's, see FileReaderAccumulator below. +// For more information on how to read Blobs in your specific situation, see: +// https://chromium.googlesource.com/chromium/src/+/HEAD/storage/browser/blob/README.md#how-to-use-blobs-blink-accessing-reading +class CORE_EXPORT FileReaderClient : public GarbageCollectedMixin { + public: + virtual ~FileReaderClient() = default; + + // Clients must implement this method to be informed about when the loading + // actually started. + // If an error occurred while processing the data, a FileErrorCode can be + // returned. In such case, the blob's processing will end a DidFail will be + // called with the returned error. + // Clients must not make re-entrant calls to the FileReaderLoader in this + // method. + virtual FileErrorCode DidStartLoading(uint64_t total_size, + uint64_t content_size) = 0; + // Clients must implement this method to receive the blob's data. + // If an error occurred while processing the data, a FileErrorCode can be + // returned. In such case, the blob's processing will end a DidFail will be + // called with the returned error. + // Clients must not make re-entrant calls to the FileReaderLoader in this + // method. + virtual FileErrorCode DidReceiveData(const char* data, + unsigned data_length) = 0; + // Clients must implement this method to be informed about when the loading + // ended. + virtual void DidFinishLoading() = 0; + // Clients must implement this method to be informed about any failures that + // occurred. + virtual void DidFail(FileErrorCode) = 0; + + void Trace(Visitor*) const override {} +}; + +// FileReaderAccumulator helps aggregating the data received from +// FileReaderLoader. This class implements a regular FileReaderClient and +// reads the file' chunks until completion. On completion, it provides a +// convenient way to convert the received data to the FileReadType types via +// the FileReaderData class helper. +class CORE_EXPORT FileReaderAccumulator : public FileReaderClient { + public: + // Clients might implement this method if they want to know when the loading + // process started. The client can also choose the loader behaviour by + // returning whether to continue or stop the loader. + virtual FileErrorCode DidStartLoading() { return FileErrorCode::kOK; } + // Clients might implement this method if they want to know when the loader + // received some data. The client can also choose the loader behaviour by + // returning whether to continue or stop the loader. + virtual FileErrorCode DidReceiveData() { return FileErrorCode::kOK; } + // Clients must implement this method to receive the aggregated file data. + virtual void DidFinishLoading(FileReaderData) = 0; + // Clients might implement this method to known whether the loading failed. + // If this method is implemented, it is recommended to call the parent + // implementation as well for early cleanup. + void DidFail(FileErrorCode) override; + void Trace(Visitor* visitor) const override { + FileReaderClient::Trace(visitor); + } + + private: + FileErrorCode DidStartLoading(uint64_t size, uint64_t total_bytes) final; + FileErrorCode DidReceiveData(const char* data, unsigned data_length) final; + void DidFinishLoading() final; + + uint64_t bytes_loaded_ = 0; + ArrayBufferContents raw_data_; +}; + +// The class acts similar to the FileReaderAccumulator, except that it +// works synchronously. This provides a few handy methods to help wait for the +// aggregated result. +class CORE_EXPORT SyncedFileReaderAccumulator + : public GarbageCollected<SyncedFileReaderAccumulator>, + public FileReaderAccumulator { + public: + static std::pair<FileErrorCode, FileReaderData> Load( + scoped_refptr<BlobDataHandle> handle, + scoped_refptr<base::SingleThreadTaskRunner>); + + void Trace(Visitor* visitor) const override { + FileReaderAccumulator::Trace(visitor); + } + + private: + void DidFail(FileErrorCode error_code) final; + void DidFinishLoading(FileReaderData obj) final; + + FileReaderData stored_; + FileErrorCode error_code_ = FileErrorCode::kOK; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_FILE_READER_CLIENT_H_
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc index deafb74d..dab1fbd 100644 --- a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc +++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
@@ -34,6 +34,7 @@ #include <memory> #include <utility> +#include "base/auto_reset.h" #include "base/memory/scoped_refptr.h" #include "base/numerics/safe_conversions.h" #include "base/task/single_thread_task_runner.h" @@ -42,7 +43,7 @@ #include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fileapi/blob.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/platform/blob/blob_url.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/functional.h" @@ -50,26 +51,37 @@ namespace blink { FileReaderLoader::FileReaderLoader( - FileReadType read_type, - FileReaderLoaderClient* client, + FileReaderClient* client, scoped_refptr<base::SingleThreadTaskRunner> task_runner) - : read_type_(read_type), - client_(client), + : client_(client), handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC, task_runner), task_runner_(std::move(task_runner)) { + CHECK(client); DCHECK(task_runner_); } FileReaderLoader::~FileReaderLoader() = default; void FileReaderLoader::Start(scoped_refptr<BlobDataHandle> blob_data) { + StartInternal(std::move(blob_data), /*is_sync=*/false); +} + +void FileReaderLoader::StartSync(scoped_refptr<BlobDataHandle> blob_data) { + StartInternal(std::move(blob_data), /*is_sync=*/true); +} + +void FileReaderLoader::StartInternal(scoped_refptr<BlobDataHandle> blob_data, + bool is_sync) { #if DCHECK_IS_ON() DCHECK(!started_loading_) << "FileReaderLoader can only be used once"; started_loading_ = true; #endif // DCHECK_IS_ON() + // This sets up the `IsSyncLoad` mechanism for the lifetime of this method. + base::AutoReset<bool> scoped_is_sync(&is_sync_, is_sync); + MojoCreateDataPipeOptions options; options.struct_size = sizeof(MojoCreateDataPipeOptions); options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE; @@ -111,25 +123,10 @@ Cleanup(); } -FileReaderData FileReaderLoader::TakeContents() { - // Let's prevent any API misusage here. Clients are definitely not supposed to - // extract some contents in case an error occurred. For partial contents, - // clients should be using FileReadType::kReadByClient. - CHECK(raw_data_.IsValid() && error_code_ == FileErrorCode::kOK && - finished_loading_); - - return FileReaderData(std::move(raw_data_)); -} - void FileReaderLoader::Cleanup() { handle_watcher_.Cancel(); consumer_handle_.reset(); receiver_.reset(); - - // If we get any error, we do not need to keep a buffer around. - if (error_code_ != FileErrorCode::kOK) { - raw_data_.Reset(); - } } void FileReaderLoader::Failed(FileErrorCode error_code) { @@ -138,92 +135,24 @@ return; error_code_ = error_code; Cleanup(); - if (client_) - client_->DidFail(error_code_); -} - -void FileReaderLoader::OnStartLoading(uint64_t total_bytes) { - total_bytes_ = total_bytes; - - DCHECK(!raw_data_.IsValid()); - - if (read_type_ != FileReadType::kReadByClient) { - // Check that we can cast to unsigned since we have to do - // so to call ArrayBuffer's create function. - // FIXME: Support reading more than the current size limit of ArrayBuffer. - if (total_bytes > std::numeric_limits<unsigned>::max()) { - Failed(FileErrorCode::kNotReadableErr); - return; - } - - raw_data_ = ArrayBufferContents(static_cast<unsigned>(total_bytes), 1, - ArrayBufferContents::kNotShared, - ArrayBufferContents::kDontInitialize); - if (!raw_data_.IsValid()) { - Failed(FileErrorCode::kNotReadableErr); - return; - } - } - - if (client_) - client_->DidStartLoading(); -} - -void FileReaderLoader::OnReceivedData(const char* data, unsigned data_length) { - DCHECK(data); - - // Bail out if we already encountered an error. - if (error_code_ != FileErrorCode::kOK) - return; - - if (read_type_ == FileReadType::kReadByClient) { - bytes_loaded_ += data_length; - - if (client_) - client_->DidReceiveDataForClient(data, data_length); - return; - } - - // Receiving more data than expected would indicate a bug in the - // implementation of the mojom Blob interface. However there is no guarantee - // that the Blob is actually backed by a "real" blob, so to - // defend against compromised renderer processes we still need to carefully - // validate anything received. So return an error if we received too much - // data. - if (bytes_loaded_ + data_length > raw_data_.DataLength()) { - raw_data_.Reset(); - bytes_loaded_ = 0; - Failed(FileErrorCode::kNotReadableErr); - return; - } - memcpy(static_cast<char*>(raw_data_.Data()) + bytes_loaded_, data, - data_length); - bytes_loaded_ += data_length; - - if (client_) - client_->DidReceiveData(); + client_->DidFail(error_code_); } void FileReaderLoader::OnFinishLoading() { - if (read_type_ != FileReadType::kReadByClient && raw_data_.IsValid()) { - DCHECK_EQ(bytes_loaded_, raw_data_.DataLength()); - } - finished_loading_ = true; - Cleanup(); - if (client_) - client_->DidFinishLoading(); + client_->DidFinishLoading(); } void FileReaderLoader::OnCalculatedSize(uint64_t total_size, uint64_t expected_content_size) { - auto weak_this = WrapWeakPersistent(this); - OnStartLoading(expected_content_size); - // OnStartLoading calls out to our client, which could delete |this|, so bail - // out if that happened. - if (!weak_this) + total_bytes_ = expected_content_size; + + if (auto err = client_->DidStartLoading(total_size, expected_content_size); + err != FileErrorCode::kOK) { + Failed(err); return; + } if (expected_content_size == 0) { received_all_data_ = true; @@ -291,12 +220,17 @@ return; } - auto weak_this = WrapWeakPersistent(this); - OnReceivedData(static_cast<const char*>(buffer), num_bytes); - // OnReceivedData calls out to our client, which could delete |this|, so - // bail out if that happened. - if (!weak_this) + const char* data = static_cast<const char*>(buffer); + DCHECK(data); + DCHECK_EQ(error_code_, FileErrorCode::kOK); + + bytes_loaded_ += num_bytes; + + if (auto err = client_->DidReceiveData(data, num_bytes); + err != FileErrorCode::kOK) { + Failed(err); return; + } consumer_handle_->EndReadData(num_bytes); if (BytesLoaded() >= total_bytes_) {
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.h b/third_party/blink/renderer/core/fileapi/file_reader_loader.h index e1284d9..8e2c0ed 100644 --- a/third_party/blink/renderer/core/fileapi/file_reader_loader.h +++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.h
@@ -39,9 +39,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fileapi/file_error.h" -#include "third_party/blink/renderer/core/fileapi/file_read_type.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_data.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/member.h" @@ -52,8 +50,7 @@ namespace blink { class BlobDataHandle; - -// Reads a Blob's content into memory. +// Reads a Blob's content and forwards it to the FileReaderClient. // // Blobs are typically stored on disk, and should be read asynchronously // whenever possible. Synchronous loading is implemented to support Web Platform @@ -67,16 +64,14 @@ public: // If client is given, do the loading asynchronously. Otherwise, load // synchronously. - FileReaderLoader(FileReadType, - FileReaderLoaderClient*, + FileReaderLoader(FileReaderClient*, scoped_refptr<base::SingleThreadTaskRunner>); ~FileReaderLoader() override; void Start(scoped_refptr<BlobDataHandle>); + void StartSync(scoped_refptr<BlobDataHandle>); void Cancel(); - FileReaderData TakeContents(); - // Returns the total bytes received. Bytes ignored by m_rawData won't be // counted. // @@ -97,14 +92,13 @@ void Trace(Visitor* visitor) const { visitor->Trace(client_); } private: + void StartInternal(scoped_refptr<BlobDataHandle>, bool is_sync); void Cleanup(); void Failed(FileErrorCode); - void OnStartLoading(uint64_t total_bytes); - void OnReceivedData(const char* data, unsigned data_length); - void OnFinishLoading(); + bool IsSyncLoad() { return is_sync_; } - bool IsSyncLoad() const { return !client_; } + void OnFinishLoading(); // BlobReaderClient: void OnCalculatedSize(uint64_t total_size, @@ -112,10 +106,7 @@ void OnComplete(int32_t status, uint64_t data_length) override; void OnDataPipeReadable(MojoResult); - FileReadType read_type_; - WeakMember<FileReaderLoaderClient> client_; - - ArrayBufferContents raw_data_; + Member<FileReaderClient> client_; bool finished_loading_ = false; uint64_t bytes_loaded_ = 0; @@ -137,6 +128,8 @@ bool started_loading_ = false; #endif // DCHECK_IS_ON() + bool is_sync_ = false; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; };
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader_client.h b/third_party/blink/renderer/core/fileapi/file_reader_loader_client.h deleted file mode 100644 index dfd6a80..0000000 --- a/third_party/blink/renderer/core/fileapi/file_reader_loader_client.h +++ /dev/null
@@ -1,65 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_FILE_READER_LOADER_CLIENT_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_FILE_READER_LOADER_CLIENT_H_ - -#include "base/notreached.h" -#include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/platform/heap/garbage_collected.h" - -namespace blink { - -enum class FileErrorCode; - -// For more information on how to read Blobs in your specific situation, see: -// https://chromium.googlesource.com/chromium/src/+/HEAD/storage/browser/blob/README.md#accessing-reading -class CORE_EXPORT FileReaderLoaderClient : public GarbageCollectedMixin { - public: - virtual ~FileReaderLoaderClient() = default; - - virtual void DidStartLoading() = 0; - // Clients must implement this method if they are using any ReadType except - // ReadByClient. - virtual void DidReceiveData() { NOTREACHED(); } - // Clients must implement this method if they are using the ReadByClient - // ReadType. - virtual void DidReceiveDataForClient(const char* data, unsigned data_length) { - NOTREACHED(); - } - virtual void DidFinishLoading() = 0; - virtual void DidFail(FileErrorCode) = 0; - - void Trace(Visitor*) const override {} -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_FILE_READER_LOADER_CLIENT_H_
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_sync.cc b/third_party/blink/renderer/core/fileapi/file_reader_sync.cc index f5755626..1925697 100644 --- a/third_party/blink/renderer/core/fileapi/file_reader_sync.cc +++ b/third_party/blink/renderer/core/fileapi/file_reader_sync.cc
@@ -35,9 +35,7 @@ #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fileapi/blob.h" #include "third_party/blink/renderer/core/fileapi/file_error.h" -#include "third_party/blink/renderer/core/fileapi/file_read_type.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" -#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" @@ -52,26 +50,19 @@ ExceptionState& exception_state) { DCHECK(blob); - FileReaderLoader* loader = MakeGarbageCollected<FileReaderLoader>( - FileReadType::kReadAsArrayBuffer, nullptr, task_runner_); - StartLoading(*loader, *blob, exception_state); - if (loader->GetErrorCode() != FileErrorCode::kOK) { - return nullptr; - } - return loader->TakeContents().AsDOMArrayBuffer(); + absl::optional<FileReaderData> res = Load(*blob, exception_state); + return !res ? nullptr : std::move(res).value().AsDOMArrayBuffer(); } String FileReaderSync::readAsBinaryString(Blob* blob, ExceptionState& exception_state) { DCHECK(blob); - FileReaderLoader* loader = MakeGarbageCollected<FileReaderLoader>( - FileReadType::kReadAsBinaryString, nullptr, task_runner_); - StartLoading(*loader, *blob, exception_state); - if (loader->GetErrorCode() != FileErrorCode::kOK) { + absl::optional<FileReaderData> res = Load(*blob, exception_state); + if (!res) { return ""; } - return loader->TakeContents().AsBinaryString(); + return std::move(res).value().AsBinaryString(); } String FileReaderSync::readAsText(Blob* blob, @@ -79,34 +70,34 @@ ExceptionState& exception_state) { DCHECK(blob); - FileReaderLoader* loader = MakeGarbageCollected<FileReaderLoader>( - FileReadType::kReadAsText, nullptr, task_runner_); - StartLoading(*loader, *blob, exception_state); - if (loader->GetErrorCode() != FileErrorCode::kOK) { + absl::optional<FileReaderData> res = Load(*blob, exception_state); + if (!res) { return ""; } - return loader->TakeContents().AsText(encoding); + return std::move(res).value().AsText(encoding); } String FileReaderSync::readAsDataURL(Blob* blob, ExceptionState& exception_state) { DCHECK(blob); - FileReaderLoader* loader = MakeGarbageCollected<FileReaderLoader>( - FileReadType::kReadAsDataURL, nullptr, task_runner_); - StartLoading(*loader, *blob, exception_state); - if (loader->GetErrorCode() != FileErrorCode::kOK) { + absl::optional<FileReaderData> res = Load(*blob, exception_state); + if (!res) { return ""; } - return loader->TakeContents().AsDataURL(blob->type()); + return std::move(res).value().AsDataURL(blob->type()); } -void FileReaderSync::StartLoading(FileReaderLoader& loader, - const Blob& blob, - ExceptionState& exception_state) { - loader.Start(blob.GetBlobDataHandle()); - if (loader.GetErrorCode() != FileErrorCode::kOK) - file_error::ThrowDOMException(exception_state, loader.GetErrorCode()); +absl::optional<FileReaderData> FileReaderSync::Load( + const Blob& blob, + ExceptionState& exception_state) { + auto res = + SyncedFileReaderAccumulator::Load(blob.GetBlobDataHandle(), task_runner_); + if (res.first != FileErrorCode::kOK) { + file_error::ThrowDOMException(exception_state, res.first); + return absl::nullopt; + } + return std::move(res.second); } } // namespace blink
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_sync.h b/third_party/blink/renderer/core/fileapi/file_reader_sync.h index 15712197..ff6f96c 100644 --- a/third_party/blink/renderer/core/fileapi/file_reader_sync.h +++ b/third_party/blink/renderer/core/fileapi/file_reader_sync.h
@@ -32,6 +32,9 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_FILEAPI_FILE_READER_SYNC_H_ #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_data.h" +#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -46,7 +49,6 @@ class DOMArrayBuffer; class ExceptionState; class ExecutionContext; -class FileReaderLoader; class FileReaderSync final : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); @@ -71,7 +73,7 @@ } private: - void StartLoading(FileReaderLoader&, const Blob&, ExceptionState&); + absl::optional<FileReaderData> Load(const Blob&, ExceptionState&); scoped_refptr<base::SingleThreadTaskRunner> task_runner_; };
diff --git a/third_party/blink/renderer/core/html/forms/date_time_field_element.cc b/third_party/blink/renderer/core/html/forms/date_time_field_element.cc index ae19caf..9b54afc 100644 --- a/third_party/blink/renderer/core/html/forms/date_time_field_element.cc +++ b/third_party/blink/renderer/core/html/forms/date_time_field_element.cc
@@ -55,7 +55,7 @@ float DateTimeFieldElement::ComputeTextWidth(const ComputedStyle& style, const String& text) { - return style.GetFont().Width(ConstructTextRun(style.GetFont(), text, style)); + return style.GetFont().Width(ConstructTextRun(text, style)); } void DateTimeFieldElement::DefaultEventHandler(Event& event) {
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc index c7f3a46..403a026 100644 --- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -59,9 +59,8 @@ #include "third_party/blink/renderer/bindings/core/v8/capture_source_location.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/scriptable_document_parser.h" -#include "third_party/blink/renderer/core/fileapi/file_read_type.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" @@ -192,7 +191,7 @@ class InspectorFileReaderLoaderClient final : public GarbageCollected<InspectorFileReaderLoaderClient>, - public FileReaderLoaderClient { + public FileReaderClient { public: InspectorFileReaderLoaderClient( scoped_refptr<BlobDataHandle> blob, @@ -200,10 +199,8 @@ base::OnceCallback<void(scoped_refptr<SharedBuffer>)> callback) : blob_(std::move(blob)), callback_(std::move(callback)), - loader_( - MakeGarbageCollected<FileReaderLoader>(FileReadType::kReadByClient, - this, - std::move(task_runner))), + loader_(MakeGarbageCollected<FileReaderLoader>(this, + std::move(task_runner))), keep_alive_(this) {} InspectorFileReaderLoaderClient(const InspectorFileReaderLoaderClient&) = @@ -218,13 +215,16 @@ loader_->Start(blob_); } - void DidStartLoading() override {} + FileErrorCode DidStartLoading(uint64_t, uint64_t) override { + return FileErrorCode::kOK; + } - void DidReceiveDataForClient(const char* data, + FileErrorCode DidReceiveData(const char* data, unsigned data_length) override { if (!data_length) - return; + return FileErrorCode::kOK; raw_data_->Append(data, data_length); + return FileErrorCode::kOK; } void DidFinishLoading() override { Done(raw_data_); } @@ -232,7 +232,7 @@ void DidFail(FileErrorCode) override { Done(nullptr); } void Trace(Visitor* visitor) const override { - FileReaderLoaderClient::Trace(visitor); + FileReaderClient::Trace(visitor); visitor->Trace(loader_); } @@ -240,6 +240,7 @@ void Done(scoped_refptr<SharedBuffer> output) { std::move(callback_).Run(output); keep_alive_.Clear(); + loader_ = nullptr; } scoped_refptr<BlobDataHandle> blob_;
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 62113f2..d1b81ac 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -257,13 +257,13 @@ const Font& font = box.StyleRef().GetFont(); const float min_default_label_width = kDefaultWidthNumChars * - font.Width(ConstructTextRun(font, character_as_string, box.StyleRef(), + font.Width(ConstructTextRun(character_as_string, box.StyleRef(), TextRun::kAllowTrailingExpansion)); const String label = input.GetLocale().QueryString(IDS_FORM_FILE_NO_FILE_LABEL); float default_label_width = font.Width(ConstructTextRun( - font, label, box.StyleRef(), TextRun::kAllowTrailingExpansion)); + label, box.StyleRef(), TextRun::kAllowTrailingExpansion)); if (HTMLInputElement* button = input.UploadButton()) { if (LayoutObject* button_layout_object = button->GetLayoutObject()) { default_label_width += @@ -332,7 +332,7 @@ style.ApplyTextTransform(&text); // We apply SELECT's style, not OPTION's style because max_option_width is // used to determine intrinsic width of the menulist box. - TextRun text_run = ConstructTextRun(style.GetFont(), text, style); + TextRun text_run = ConstructTextRun(text, style); max_option_width = std::max(max_option_width, style.GetFont().Width(text_run)); }
diff --git a/third_party/blink/renderer/core/layout/layout_text.h b/third_party/blink/renderer/core/layout/layout_text.h index 6aecf1c..7a56d43c 100644 --- a/third_party/blink/renderer/core/layout/layout_text.h +++ b/third_party/blink/renderer/core/layout/layout_text.h
@@ -267,8 +267,6 @@ has_abstract_inline_text_box_ = true; } - float HyphenWidth(const Font&, TextDirection); - PhysicalRect DebugRect() const override; void AutosizingMultiplerChanged() { @@ -531,13 +529,6 @@ return c; } -inline float LayoutText::HyphenWidth(const Font& font, - TextDirection direction) { - const ComputedStyle& style = StyleRef(); - return font.Width(ConstructTextRun(font, style.HyphenString().GetString(), - style, direction)); -} - inline void LayoutText::DetachAbstractInlineTextBoxesIfNeeded() { if (UNLIKELY(has_abstract_inline_text_box_)) DetachAbstractInlineTextBoxes();
diff --git a/third_party/blink/renderer/core/layout/layout_text_control.cc b/third_party/blink/renderer/core/layout/layout_text_control.cc index 24b568c..e3aca1d 100644 --- a/third_party/blink/renderer/core/layout/layout_text_control.cc +++ b/third_party/blink/renderer/core/layout/layout_text_control.cc
@@ -174,7 +174,7 @@ const UChar kCh = '0'; const String str = String(&kCh, 1u); TextRun text_run = - ConstructTextRun(font, str, style, TextRun::kAllowTrailingExpansion); + ConstructTextRun(str, style, TextRun::kAllowTrailingExpansion); return font.Width(text_run); }
diff --git a/third_party/blink/renderer/core/layout/text_run_constructor.cc b/third_party/blink/renderer/core/layout/text_run_constructor.cc index 99f32fc..5df350f 100644 --- a/third_party/blink/renderer/core/layout/text_run_constructor.cc +++ b/third_party/blink/renderer/core/layout/text_run_constructor.cc
@@ -36,22 +36,7 @@ namespace blink { template <typename CharacterType> -static inline TextRun ConstructTextRunInternal(const Font& font, - const CharacterType* characters, - int length, - const ComputedStyle& style, - TextDirection direction) { - TextRun::ExpansionBehavior expansion = - TextRun::kAllowTrailingExpansion | TextRun::kForbidLeadingExpansion; - bool directional_override = style.RtlOrdering() == EOrder::kVisual; - TextRun run(characters, length, 0, 0, expansion, direction, - directional_override); - return run; -} - -template <typename CharacterType> -static inline TextRun ConstructTextRunInternal(const Font& font, - const CharacterType* characters, +static inline TextRun ConstructTextRunInternal(const CharacterType* characters, int length, const ComputedStyle& style, TextDirection direction, @@ -72,65 +57,23 @@ return run; } -TextRun ConstructTextRun(const Font& font, - const LChar* characters, - int length, - const ComputedStyle& style, - TextDirection direction) { - return ConstructTextRunInternal(font, characters, length, style, direction); -} - -TextRun ConstructTextRun(const Font& font, - const UChar* characters, - int length, - const ComputedStyle& style, - TextDirection direction) { - return ConstructTextRunInternal(font, characters, length, style, direction); -} - -TextRun ConstructTextRun(const Font& font, - const LayoutText* text, - unsigned offset, - unsigned length, - const ComputedStyle& style, - TextDirection direction) { - DCHECK_LE(offset + length, text->TextLength()); - if (text->HasEmptyText()) - return ConstructTextRunInternal(font, static_cast<const LChar*>(nullptr), 0, - style, direction); - if (text->Is8Bit()) - return ConstructTextRunInternal(font, text->Characters8() + offset, length, - style, direction); - return ConstructTextRunInternal(font, text->Characters16() + offset, length, - style, direction); -} - -TextRun ConstructTextRun(const Font& font, - const String& string, - const ComputedStyle& style, - TextDirection direction, - TextRunFlags flags) { - unsigned length = string.length(); - if (!length) - return ConstructTextRunInternal(font, static_cast<const LChar*>(nullptr), - length, style, direction, flags); - if (string.Is8Bit()) - return ConstructTextRunInternal(font, string.Characters8(), length, style, - direction, flags); - return ConstructTextRunInternal(font, string.Characters16(), length, style, - direction, flags); -} - -TextRun ConstructTextRun(const Font& font, - const String& string, +TextRun ConstructTextRun(const String& string, const ComputedStyle& style, TextRunFlags flags) { - return ConstructTextRun( - font, string, style, + TextDirection direction = string.empty() || string.Is8Bit() ? TextDirection::kLtr - : BidiParagraph::BaseDirectionForStringOrLtr(string), - flags); + : BidiParagraph::BaseDirectionForStringOrLtr(string); + unsigned length = string.length(); + if (!length) { + return ConstructTextRunInternal(static_cast<const LChar*>(nullptr), length, + style, direction, flags); + } + if (string.Is8Bit()) + return ConstructTextRunInternal(string.Characters8(), length, style, + direction, flags); + return ConstructTextRunInternal(string.Characters16(), length, style, + direction, flags); } } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/text_run_constructor.h b/third_party/blink/renderer/core/layout/text_run_constructor.h index 6ebd1f38..d3ced3a0 100644 --- a/third_party/blink/renderer/core/layout/text_run_constructor.h +++ b/third_party/blink/renderer/core/layout/text_run_constructor.h
@@ -43,9 +43,7 @@ namespace blink { -class Font; class ComputedStyle; -class LayoutText; enum TextRunFlag { kDefaultTextRunFlags = 0, @@ -55,35 +53,13 @@ typedef unsigned TextRunFlags; -// Direction resolved from string value. -TextRun ConstructTextRun(const Font&, - const String&, +// TODO(1229581): All the calls to this function are bad. They are passing in +// TextRun::ExpansionBehaviour to flags instead of TextRunFlag above. +// Remove this function. +TextRun ConstructTextRun(const String&, const ComputedStyle&, TextRunFlags = kDefaultTextRunFlags); -// Explicit direction. -TextRun ConstructTextRun(const Font&, - const String&, - const ComputedStyle&, - TextDirection, - TextRunFlags = kDefaultTextRunFlags); -TextRun ConstructTextRun(const Font&, - const LayoutText*, - unsigned offset, - unsigned length, - const ComputedStyle&, - TextDirection); -TextRun ConstructTextRun(const Font&, - const LChar*, - int length, - const ComputedStyle&, - TextDirection); -TextRun ConstructTextRun(const Font&, - const UChar*, - int length, - const ComputedStyle&, - TextDirection); - } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_TEXT_RUN_CONSTRUCTOR_H_
diff --git a/third_party/blink/renderer/core/streams/build.gni b/third_party/blink/renderer/core/streams/build.gni index b129bd1..c1ca3f2 100644 --- a/third_party/blink/renderer/core/streams/build.gni +++ b/third_party/blink/renderer/core/streams/build.gni
@@ -11,6 +11,10 @@ "count_queuing_strategy.h", "miscellaneous_operations.cc", "miscellaneous_operations.h", + "pipe_options.cc", + "pipe_options.h", + "pipe_to_engine.cc", + "pipe_to_engine.h", "promise_handler.cc", "promise_handler.h", "queue_with_sizes.cc",
diff --git a/third_party/blink/renderer/core/streams/pipe_options.cc b/third_party/blink/renderer/core/streams/pipe_options.cc new file mode 100644 index 0000000..042389f --- /dev/null +++ b/third_party/blink/renderer/core/streams/pipe_options.cc
@@ -0,0 +1,26 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/streams/pipe_options.h" + +#include "third_party/blink/renderer/bindings/core/v8/v8_stream_pipe_options.h" +#include "third_party/blink/renderer/core/dom/abort_signal.h" +#include "third_party/blink/renderer/platform/bindings/v8_binding.h" + +namespace blink { + +PipeOptions::PipeOptions(const StreamPipeOptions* options) + : prevent_close_(options->hasPreventClose() ? options->preventClose() + : false), + prevent_abort_(options->hasPreventAbort() ? options->preventAbort() + : false), + prevent_cancel_(options->hasPreventCancel() ? options->preventCancel() + : false), + signal_(options->hasSignal() ? options->signal() : nullptr) {} + +void PipeOptions::Trace(Visitor* visitor) const { + visitor->Trace(signal_); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/streams/pipe_options.h b/third_party/blink/renderer/core/streams/pipe_options.h new file mode 100644 index 0000000..2588d1d2 --- /dev/null +++ b/third_party/blink/renderer/core/streams/pipe_options.h
@@ -0,0 +1,38 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_PIPE_OPTIONS_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_PIPE_OPTIONS_H_ + +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/member.h" +#include "third_party/blink/renderer/platform/heap/visitor.h" + +namespace blink { + +class AbortSignal; +class StreamPipeOptions; + +class PipeOptions : public GarbageCollected<PipeOptions> { + public: + PipeOptions() = default; + explicit PipeOptions(const StreamPipeOptions* options); + + bool PreventClose() const { return prevent_close_; } + bool PreventAbort() const { return prevent_abort_; } + bool PreventCancel() const { return prevent_cancel_; } + AbortSignal* Signal() const { return signal_; } + + void Trace(Visitor*) const; + + private: + bool prevent_close_ = false; + bool prevent_abort_ = false; + bool prevent_cancel_ = false; + Member<AbortSignal> signal_; +}; + +} // namespace blink + +#endif // LOCAL_GOOGLE_HOME_NIDHIJAJU_CHROMIUM_SRC_THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_PIPE_OPTIONS_H_
diff --git a/third_party/blink/renderer/core/streams/pipe_to_engine.cc b/third_party/blink/renderer/core/streams/pipe_to_engine.cc new file mode 100644 index 0000000..e30702e --- /dev/null +++ b/third_party/blink/renderer/core/streams/pipe_to_engine.cc
@@ -0,0 +1,610 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/streams/pipe_to_engine.h" + +#include "third_party/blink/renderer/bindings/core/v8/script_function.h" +#include "third_party/blink/renderer/core/dom/abort_signal.h" +#include "third_party/blink/renderer/core/execution_context/agent.h" +#include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/core/streams/miscellaneous_operations.h" +#include "third_party/blink/renderer/core/streams/pipe_options.h" +#include "third_party/blink/renderer/core/streams/promise_handler.h" +#include "third_party/blink/renderer/core/streams/read_request.h" +#include "third_party/blink/renderer/core/streams/readable_stream.h" +#include "third_party/blink/renderer/core/streams/readable_stream_byob_reader.h" +#include "third_party/blink/renderer/core/streams/stream_promise_resolver.h" +#include "third_party/blink/renderer/core/streams/writable_stream.h" +#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/bindings/script_state.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" + +namespace blink { + +class PipeToEngine::PipeToAbortAlgorithm final : public AbortSignal::Algorithm { + public: + PipeToAbortAlgorithm(PipeToEngine* engine, AbortSignal* signal) + : engine_(engine), signal_(signal) {} + ~PipeToAbortAlgorithm() override = default; + + void Run() override { engine_->AbortAlgorithm(signal_); } + + void Trace(Visitor* visitor) const override { + visitor->Trace(engine_); + visitor->Trace(signal_); + Algorithm::Trace(visitor); + } + + private: + Member<PipeToEngine> engine_; + Member<AbortSignal> signal_; +}; + +class PipeToEngine::PipeToReadRequest final : public ReadRequest { + public: + explicit PipeToReadRequest(PipeToEngine* instance) : instance_(instance) {} + + void ChunkSteps(ScriptState* script_state, + v8::Local<v8::Value> chunk) const override { + scoped_refptr<scheduler::EventLoop> event_loop = + ExecutionContext::From(script_state)->GetAgent()->event_loop(); + v8::Global<v8::Value> value(script_state->GetIsolate(), chunk); + event_loop->EnqueueMicrotask( + WTF::BindOnce(&PipeToEngine::ReadRequestChunkStepsBody, + WrapPersistent(instance_.Get()), + WrapPersistent(script_state), std::move(value))); + } + + void CloseSteps(ScriptState* script_state) const override { + instance_->ReadableClosed(); + } + + void ErrorSteps(ScriptState* script_state, + v8::Local<v8::Value> e) const override { + instance_->is_reading_ = false; + if (instance_->is_shutting_down_) { + // This function can be called during shutdown when the lock is + // released. Exit early in that case. + return; + } + instance_->ReadableError( + instance_->Readable()->GetStoredError(script_state->GetIsolate())); + } + + void Trace(Visitor* visitor) const override { + visitor->Trace(instance_); + ReadRequest::Trace(visitor); + } + + private: + Member<PipeToEngine> instance_; +}; + +class PipeToEngine::WrappedPromiseReaction final + : public PromiseHandlerWithValue { + public: + WrappedPromiseReaction(PipeToEngine* instance, PromiseReaction method) + : instance_(instance), method_(method) {} + + v8::Local<v8::Value> CallWithLocal(ScriptState* script_state, + v8::Local<v8::Value> value) override { + return (instance_->*method_)(value); + } + + void Trace(Visitor* visitor) const override { + visitor->Trace(instance_); + PromiseHandlerWithValue::Trace(visitor); + } + + private: + Member<PipeToEngine> instance_; + PromiseReaction method_; +}; + +ScriptPromise PipeToEngine::Start(ReadableStream* readable, + WritableStream* destination) { + // 1. Assert: source implements ReadableStream. + DCHECK(readable); + + // 2. Assert: dest implements WritableStream. + DCHECK(destination); + + // Not relevant to C++ implementation: + // 3. Assert: preventClose, preventAbort, and preventCancel are all + // booleans. + + // TODO(ricea): Implement |signal|. + // 4. If signal was not given, let signal be undefined. + // 5. Assert: either signal is undefined, or signal implements AbortSignal. + + // 6. Assert: ! IsReadableStreamLocked(source) is false. + DCHECK(!ReadableStream::IsLocked(readable)); + + // 7. Assert: ! IsWritableStreamLocked(dest) is false. + DCHECK(!WritableStream::IsLocked(destination)); + + auto* isolate = script_state_->GetIsolate(); + ExceptionState exception_state(isolate, ExceptionState::kUnknownContext, "", + ""); + + // 8. If source.[[controller]] implements ReadableByteStreamController, let + // reader be ! AcquireReadableStreamBYOBReader(source) or ! + // AcquireReadableStreamDefaultReader(source), at the user agent's + // discretion. + // 9. Otherwise, let reader be ! AcquireReadableStreamDefaultReader(source). + reader_ = ReadableStream::AcquireDefaultReader(script_state_, readable, + exception_state); + DCHECK(!exception_state.HadException()); + + // 10. Let writer be ! AcquireWritableStreamDefaultWriter(dest). + writer_ = WritableStream::AcquireDefaultWriter(script_state_, destination, + exception_state); + DCHECK(!exception_state.HadException()); + + // 11. Set source.[[disturbed]] to true. + + // 12. Let shuttingDown be false. + DCHECK(!is_shutting_down_); + + // 13. Let promise be a new promise. + promise_ = MakeGarbageCollected<StreamPromiseResolver>(script_state_); + + // 14. If signal is not undefined, + if (auto* signal = pipe_options_->Signal()) { + // b. If signal is aborted, perform abortAlgorithm and + // return promise. + if (signal->aborted()) { + AbortAlgorithm(signal); + return promise_->GetScriptPromise(script_state_); + } + + // c. Add abortAlgorithm to signal. + abort_handle_ = signal->AddAlgorithm( + MakeGarbageCollected<PipeToAbortAlgorithm>(this, signal)); + } + + // 15. In parallel ... + // The rest of the algorithm is described in terms of a series of + // constraints rather than as explicit steps. + if (CheckInitialState()) { + // Need to detect closing and error when we are not reading. This + // corresponds to the following conditions from the standard: + // 1. Errors must be propagated forward: if source.[[state]] is or + // becomes "errored", ... + // and + // 3. Closing must be propagated forward: if source.[[state]] is or + // becomes "closed", ... + ThenPromise(reader_->ClosedPromise()->V8Promise(isolate), + &PipeToEngine::OnReaderClosed, &PipeToEngine::ReadableError); + + // Need to detect error when we are not writing. This corresponds to this + // condition from the standard: + // 2. Errors must be propagated backward: if dest.[[state]] is or + // becomes "errored", ... + // We do not need to detect closure of the writable end of the pipe, + // because we have it locked and so it can only be closed by us. + ThenPromise(writer_->ClosedPromise()->V8Promise(isolate), nullptr, + &PipeToEngine::WritableError); + + // Start the main read / write loop. + HandleNextEvent(Undefined()); + } + + // 16. Return promise. + return promise_->GetScriptPromise(script_state_); +} + +bool PipeToEngine::CheckInitialState() { + auto* isolate = script_state_->GetIsolate(); + const auto state = Readable()->state_; + + // Both streams can be errored or closed. To perform the right action the + // order of the checks must match the standard: "the following conditions + // must be applied in order." This method only checks the initial state; + // detection of state changes elsewhere is done through checking promise + // reactions. + + // a. Errors must be propagated forward: if source.[[state]] is or + // becomes "errored", + if (state == ReadableStream::kErrored) { + ReadableError(Readable()->GetStoredError(isolate)); + return false; + } + + // 2. Errors must be propagated backward: if dest.[[state]] is or becomes + // "errored", + if (Destination()->IsErrored()) { + WritableError(Destination()->GetStoredError(isolate)); + return false; + } + + // 3. Closing must be propagated forward: if source.[[state]] is or + // becomes "closed", then + if (state == ReadableStream::kClosed) { + ReadableClosed(); + return false; + } + + // 4. Closing must be propagated backward: if ! + // WritableStreamCloseQueuedOrInFlight(dest) is true or dest.[[state]] + // is "closed", + if (Destination()->IsClosingOrClosed()) { + WritableStartedClosed(); + return false; + } + + return true; +} + +void PipeToEngine::AbortAlgorithm(AbortSignal* signal) { + // a. Let abortAlgorithm be the following steps: + // i. Let error be signal's abort reason. + v8::Local<v8::Value> error = + ToV8(signal->reason(script_state_), script_state_->GetContext()->Global(), + script_state_->GetIsolate()); + + // Steps ii. to iv. are implemented in AbortAlgorithmAction. + + // v. Shutdown with an action consisting of getting a promise to wait for + // all of the actions in actions, and with error. + ShutdownWithAction(&PipeToEngine::AbortAlgorithmAction, error); +} + +v8::Local<v8::Promise> PipeToEngine::AbortAlgorithmAction() { + v8::Local<v8::Value> error = shutdown_error_.Get(script_state_->GetIsolate()); + + // ii. Let actions be an empty ordered set. + HeapVector<ScriptPromise> actions; + + // This method runs later than the equivalent steps in the standard. This + // means that it is safe to do the checks of the state of the destination + // and source synchronously, simplifying the logic. + + // iii. If preventAbort is false, append the following action to actions: + // 1. If dest.[[state]] is "writable", return ! + // WritableStreamAbort(dest, error). + // 2. Otherwise, return a promise resolved with undefined. + if (!pipe_options_->PreventAbort() && Destination()->IsWritable()) { + actions.push_back(ScriptPromise( + script_state_, + WritableStream::Abort(script_state_, Destination(), error))); + } + + // iv. If preventCancel is false, append the following action action to + // actions: + // 1. If source.[[state]] is "readable", return ! + // ReadableStreamCancel(source, error). + // 2. Otherwise, return a promise resolved with undefined. + if (!pipe_options_->PreventCancel() && + ReadableStream::IsReadable(Readable())) { + actions.push_back(ScriptPromise( + script_state_, + ReadableStream::Cancel(script_state_, Readable(), error))); + } + + return ScriptPromise::All(script_state_, actions).V8Value().As<v8::Promise>(); +} + +v8::Local<v8::Value> PipeToEngine::HandleNextEvent(v8::Local<v8::Value>) { + DCHECK(!is_reading_); + if (is_shutting_down_) { + return Undefined(); + } + + absl::optional<double> desired_size = writer_->GetDesiredSizeInternal(); + if (!desired_size.has_value()) { + // This can happen if abort() is queued but not yet started when + // pipeTo() is called. In that case [[storedError]] is not set yet, and + // we need to wait until it is before we can cancel the pipe. Once + // [[storedError]] has been set, the rejection handler set on the writer + // closed promise above will detect it, so all we need to do here is + // nothing. + return Undefined(); + } + + if (desired_size.value() <= 0) { + // Need to wait for backpressure to go away. + ThenPromise(writer_->ReadyPromise()->V8Promise(script_state_->GetIsolate()), + &PipeToEngine::HandleNextEvent, &PipeToEngine::WritableError); + return Undefined(); + } + + is_reading_ = true; + auto* read_request = MakeGarbageCollected<PipeToReadRequest>(this); + ReadableStreamDefaultReader::Read(script_state_, reader_, read_request); + return Undefined(); +} + +void PipeToEngine::ReadRequestChunkStepsBody(ScriptState* script_state, + v8::Global<v8::Value> chunk) { + // This is needed because this method runs as an enqueued microtask, so the + // isolate needs a current context. + ScriptState::Scope scope(script_state); + is_reading_ = false; + const auto write = WritableStreamDefaultWriter::Write( + script_state, writer_, chunk.Get(script_state->GetIsolate())); + last_write_.Reset(script_state->GetIsolate(), write); + ThenPromise(write, nullptr, &PipeToEngine::WritableError); + HandleNextEvent(Undefined()); +} + +v8::Local<v8::Value> PipeToEngine::OnReaderClosed(v8::Local<v8::Value>) { + if (!is_reading_) { + ReadableClosed(); + } + return Undefined(); +} + +v8::Local<v8::Value> PipeToEngine::ReadableError(v8::Local<v8::Value> error) { + // This function can be called during shutdown when the lock is released. + // Exit early in that case. + if (is_shutting_down_) { + return Undefined(); + } + + // a. If preventAbort is false, shutdown with an action of ! + // WritableStreamAbort(dest, source.[[storedError]]) and with + // source.[[storedError]]. + DCHECK(error->SameValue( + Readable()->GetStoredError(script_state_->GetIsolate()))); + if (!pipe_options_->PreventAbort()) { + ShutdownWithAction(&PipeToEngine::WritableStreamAbortAction, error); + } else { + // b. Otherwise, shutdown with source.[[storedError]]. + Shutdown(error); + } + return Undefined(); +} + +v8::Local<v8::Value> PipeToEngine::WritableError(v8::Local<v8::Value> error) { + // This function can be called during shutdown when the lock is released. + // Exit early in that case. + if (is_shutting_down_) { + return Undefined(); + } + + // a. If preventCancel is false, shutdown with an action of ! + // ReadableStreamCancel(source, dest.[[storedError]]) and with + // dest.[[storedError]]. + DCHECK(error->SameValue( + Destination()->GetStoredError(script_state_->GetIsolate()))); + if (!pipe_options_->PreventCancel()) { + ShutdownWithAction(&PipeToEngine::ReadableStreamCancelAction, error); + } else { + // b. Otherwise, shutdown with dest.[[storedError]]. + Shutdown(error); + } + return Undefined(); +} + +void PipeToEngine::ReadableClosed() { + // a. If preventClose is false, shutdown with an action of ! + // WritableStreamDefaultWriterCloseWithErrorPropagation(writer). + if (!pipe_options_->PreventClose()) { + ShutdownWithAction( + &PipeToEngine:: + WritableStreamDefaultWriterCloseWithErrorPropagationAction, + v8::MaybeLocal<v8::Value>()); + } else { + // b. Otherwise, shutdown. + Shutdown(v8::MaybeLocal<v8::Value>()); + } +} + +void PipeToEngine::WritableStartedClosed() { + // a. Assert: no chunks have been read or written. + // This is trivially true because this method is only called from + // CheckInitialState(). + + // b. Let destClosed be a new TypeError. + const auto dest_closed = v8::Exception::TypeError( + V8String(script_state_->GetIsolate(), "Destination stream closed")); + + // c. If preventCancel is false, shutdown with an action of ! + // ReadableStreamCancel(source, destClosed) and with destClosed. + if (!pipe_options_->PreventCancel()) { + ShutdownWithAction(&PipeToEngine::ReadableStreamCancelAction, dest_closed); + } else { + // d. Otherwise, shutdown with destClosed. + Shutdown(dest_closed); + } +} + +void PipeToEngine::ShutdownWithAction( + Action action, + v8::MaybeLocal<v8::Value> original_error) { + // a. If shuttingDown is true, abort these substeps. + if (is_shutting_down_) { + return; + } + + // b. Set shuttingDown to true. + is_shutting_down_ = true; + + // Store the action in case we need to call it asynchronously. This is safe + // because the |is_shutting_down_| guard flag ensures that we can only reach + // this assignment once. + shutdown_action_ = action; + + // Store |original_error| as |shutdown_error_| if it was supplied. + v8::Local<v8::Value> original_error_local; + if (original_error.ToLocal(&original_error_local)) { + shutdown_error_.Reset(script_state_->GetIsolate(), original_error_local); + } + v8::Local<v8::Promise> p; + + // c. If dest.[[state]] is "writable" and ! + // WritableStreamCloseQueuedOrInFlight(dest) is false, + if (ShouldWriteQueuedChunks()) { + // i. If any chunks have been read but not yet written, write them to + // dest. + // ii. Wait until every chunk that has been read has been written + // (i.e. the corresponding promises have settled). + p = ThenPromise(WriteQueuedChunks(), &PipeToEngine::InvokeShutdownAction); + } else { + // d. Let p be the result of performing action. + p = InvokeShutdownAction(); + } + + // e. Upon fulfillment of p, finalize, passing along originalError if it + // was given. + // f. Upon rejection of p with reason newError, finalize with newError. + ThenPromise(p, &PipeToEngine::FinalizeWithOriginalErrorIfSet, + &PipeToEngine::FinalizeWithNewError); +} + +void PipeToEngine::Shutdown(v8::MaybeLocal<v8::Value> error_maybe) { + // a. If shuttingDown is true, abort these substeps. + if (is_shutting_down_) { + return; + } + + // b. Set shuttingDown to true. + is_shutting_down_ = true; + + // c. If dest.[[state]] is "writable" and ! + // WritableStreamCloseQueuedOrInFlight(dest) is false, + if (ShouldWriteQueuedChunks()) { + // Need to stash the value of |error_maybe| since we are calling + // Finalize() asynchronously. + v8::Local<v8::Value> error; + if (error_maybe.ToLocal(&error)) { + shutdown_error_.Reset(script_state_->GetIsolate(), error); + } + + // i. If any chunks have been read but not yet written, write them to + // dest. + // ii. Wait until every chunk that has been read has been written + // (i.e. the corresponding promises have settled). + // d. Finalize, passing along error if it was given. + ThenPromise(WriteQueuedChunks(), + &PipeToEngine::FinalizeWithOriginalErrorIfSet); + } else { + // d. Finalize, passing along error if it was given. + Finalize(error_maybe); + } +} + +v8::Local<v8::Value> PipeToEngine::FinalizeWithOriginalErrorIfSet( + v8::Local<v8::Value>) { + v8::MaybeLocal<v8::Value> error_maybe; + if (!shutdown_error_.IsEmpty()) { + error_maybe = shutdown_error_.Get(script_state_->GetIsolate()); + } + Finalize(error_maybe); + return Undefined(); +} + +v8::Local<v8::Value> PipeToEngine::FinalizeWithNewError( + v8::Local<v8::Value> new_error) { + Finalize(new_error); + return Undefined(); +} + +void PipeToEngine::Finalize(v8::MaybeLocal<v8::Value> error_maybe) { + // a. Perform ! WritableStreamDefaultWriterRelease(writer). + WritableStreamDefaultWriter::Release(script_state_, writer_); + + // b. If reader implements ReadableStreamBYOBReader, perform ! + // ReadableStreamBYOBReaderRelease(reader). + if (reader_->IsBYOBReader()) { + ReadableStreamGenericReader* reader = reader_; + ReadableStreamBYOBReader* byob_reader = + To<ReadableStreamBYOBReader>(reader); + ReadableStreamBYOBReader::Release(script_state_, byob_reader); + } else { + // c. Otherwise, perform ! ReadableStreamDefaultReaderRelease(reader). + DCHECK(reader_->IsDefaultReader()); + ReadableStreamGenericReader* reader = reader_; + ReadableStreamDefaultReader* default_reader = + To<ReadableStreamDefaultReader>(reader); + ReadableStreamDefaultReader::Release(script_state_, default_reader); + } + + // d. If signal is not undefined, remove abortAlgorithm from signal. + // + // An abort algorithm is only added if the signal provided to pipeTo is not + // undefined *and* not aborted, which means `abort_handle_` can be null if + // signal is not undefined. + if (abort_handle_) { + auto* signal = pipe_options_->Signal(); + DCHECK(signal); + signal->RemoveAlgorithm(abort_handle_); + } + + v8::Local<v8::Value> error; + if (error_maybe.ToLocal(&error)) { + // e. If error was given, reject promise with error. + promise_->Reject(script_state_, error); + } else { + // f. Otherwise, resolve promise with undefined. + promise_->ResolveWithUndefined(script_state_); + } +} + +bool PipeToEngine::ShouldWriteQueuedChunks() const { + // "If dest.[[state]] is "writable" and ! + // WritableStreamCloseQueuedOrInFlight(dest) is false" + return Destination()->IsWritable() && + !WritableStream::CloseQueuedOrInFlight(Destination()); +} + +v8::Local<v8::Promise> PipeToEngine::WriteQueuedChunks() { + if (!last_write_.IsEmpty()) { + // "Wait until every chunk that has been read has been written (i.e. + // the corresponding promises have settled)" + // This implies that we behave the same whether the promise fulfills or + // rejects. IgnoreErrors() will convert a rejection into a successful + // resolution. + return ThenPromise(last_write_.Get(script_state_->GetIsolate()), nullptr, + &PipeToEngine::IgnoreErrors); + } + return PromiseResolveWithUndefined(script_state_); +} + +v8::Local<v8::Promise> PipeToEngine::WritableStreamAbortAction() { + return WritableStream::Abort(script_state_, Destination(), ShutdownError()); +} + +v8::Local<v8::Promise> PipeToEngine::ReadableStreamCancelAction() { + return ReadableStream::Cancel(script_state_, Readable(), ShutdownError()); +} + +v8::Local<v8::Promise> +PipeToEngine::WritableStreamDefaultWriterCloseWithErrorPropagationAction() { + return WritableStreamDefaultWriter::CloseWithErrorPropagation(script_state_, + writer_); +} + +WritableStream* PipeToEngine::Destination() { + return writer_->OwnerWritableStream(); +} + +const WritableStream* PipeToEngine::Destination() const { + return writer_->OwnerWritableStream(); +} + +ReadableStream* PipeToEngine::Readable() { + return reader_->owner_readable_stream_; +} + +v8::Local<v8::Promise> PipeToEngine::ThenPromise(v8::Local<v8::Promise> promise, + PromiseReaction on_fulfilled, + PromiseReaction on_rejected) { + return StreamThenPromise( + script_state_->GetContext(), promise, + on_fulfilled + ? MakeGarbageCollected<ScriptFunction>( + script_state_, MakeGarbageCollected<WrappedPromiseReaction>( + this, on_fulfilled)) + : nullptr, + on_rejected + ? MakeGarbageCollected<ScriptFunction>( + script_state_, + MakeGarbageCollected<WrappedPromiseReaction>(this, on_rejected)) + : nullptr); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/streams/pipe_to_engine.h b/third_party/blink/renderer/core/streams/pipe_to_engine.h new file mode 100644 index 0000000..ef898565 --- /dev/null +++ b/third_party/blink/renderer/core/streams/pipe_to_engine.h
@@ -0,0 +1,200 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_PIPE_TO_ENGINE_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_PIPE_TO_ENGINE_H_ + +#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h" +#include "third_party/blink/renderer/core/dom/abort_signal.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/member.h" +#include "third_party/blink/renderer/platform/heap/visitor.h" +#include "v8/include/v8.h" + +namespace blink { + +class AbortSignal; +class PipeOptions; +class ReadableStream; +class ReadableStreamDefaultReader; +class ScriptState; +class StreamPromiseResolver; +class WritableStream; +class WritableStreamDefaultWriter; + +// PipeToEngine implements PipeTo(). All standard steps in this class come from +// https://streams.spec.whatwg.org/#readable-stream-pipe-to +// +// This implementation is simple but suboptimal because it uses V8 promises to +// drive its asynchronous state machine, allocating a lot of temporary V8 +// objects as a result. +// +// TODO(ricea): Create internal versions of ReadableStreamDefaultReader::Read() +// and WritableStreamDefaultWriter::Write() to bypass promise creation and so +// reduce the number of allocations on the hot path. +class PipeToEngine final : public GarbageCollected<PipeToEngine> { + public: + PipeToEngine(ScriptState* script_state, PipeOptions* pipe_options) + : script_state_(script_state), pipe_options_(pipe_options) {} + PipeToEngine(const PipeToEngine&) = delete; + PipeToEngine& operator=(const PipeToEngine&) = delete; + + // This is the main entrypoint for ReadableStreamPipeTo(). + ScriptPromise Start(ReadableStream* readable, WritableStream* destination); + + void Trace(Visitor* visitor) const { + visitor->Trace(script_state_); + visitor->Trace(pipe_options_); + visitor->Trace(reader_); + visitor->Trace(writer_); + visitor->Trace(promise_); + visitor->Trace(last_write_); + visitor->Trace(shutdown_error_); + visitor->Trace(abort_handle_); + } + + private: + // The implementation uses method pointers to maximise code reuse. + + class PipeToAbortAlgorithm; + class PipeToReadRequest; + class WrappedPromiseReaction; + + // |Action| represents an action that can be passed to the "Shutdown with an + // action" operation. Each Action is implemented as a method which delegates + // to some abstract operation, inferring the arguments from the state of + // |this|. + using Action = v8::Local<v8::Promise> (PipeToEngine::*)(); + + // This implementation uses ThenPromise() 7 times. Instead of creating a dozen + // separate subclasses of ScriptFunction, we use a single implementation and + // pass a method pointer at runtime to control the behaviour. Most + // PromiseReaction methods don't need to return a value, but because some do, + // the rest have to return undefined so that they can have the same method + // signature. Similarly, many of the methods ignore the argument that is + // passed to them. + using PromiseReaction = + v8::Local<v8::Value> (PipeToEngine::*)(v8::Local<v8::Value>); + + // Checks the state of the streams and executes the shutdown handlers if + // necessary. Returns true if piping can continue. + bool CheckInitialState(); + + void AbortAlgorithm(AbortSignal* signal); + + v8::Local<v8::Promise> AbortAlgorithmAction(); + + // HandleNextEvent() has an unused argument and return value because it is a + // PromiseReaction. HandleNextEvent() and ReadFulfilled() call each other + // asynchronously in a loop until the pipe completes. + v8::Local<v8::Value> HandleNextEvent(v8::Local<v8::Value>); + + void ReadRequestChunkStepsBody(ScriptState* script_state, + v8::Global<v8::Value> chunk); + + // If read() is in progress, then wait for it to tell us that the stream is + // closed so that we write all the data before shutdown. + v8::Local<v8::Value> OnReaderClosed(v8::Local<v8::Value>); + + // 1. Errors must be propagated forward: if source.[[state]] is or + // becomes "errored", then + v8::Local<v8::Value> ReadableError(v8::Local<v8::Value> error); + + // 2. Errors must be propagated backward: if dest.[[state]] is or becomes + // "errored", then + v8::Local<v8::Value> WritableError(v8::Local<v8::Value> error); + + // 3. Closing must be propagated forward: if source.[[state]] is or + // becomes "closed", then + void ReadableClosed(); + + // 4. Closing must be propagated backward: if ! + // WritableStreamCloseQueuedOrInFlight(dest) is true or dest.[[state]] is + // "closed", then + void WritableStartedClosed(); + + // * Shutdown with an action: if any of the above requirements ask to shutdown + // with an action |action|, optionally with an error |originalError|, then: + void ShutdownWithAction(Action action, + v8::MaybeLocal<v8::Value> original_error); + + // * Shutdown: if any of the above requirements or steps ask to shutdown, + // optionally with an error error, then: + void Shutdown(v8::MaybeLocal<v8::Value> error_maybe); + + // Calls Finalize(), using the stored shutdown error rather than the value + // that was passed. + v8::Local<v8::Value> FinalizeWithOriginalErrorIfSet(v8::Local<v8::Value>); + + // Calls Finalize(), using the value that was passed as the error. + v8::Local<v8::Value> FinalizeWithNewError(v8::Local<v8::Value> new_error); + + // * Finalize: both forms of shutdown will eventually ask to finalize, + // optionally with an error error, which means to perform the following + // steps: + void Finalize(v8::MaybeLocal<v8::Value> error_maybe); + + bool ShouldWriteQueuedChunks() const; + + v8::Local<v8::Promise> WriteQueuedChunks(); + + v8::Local<v8::Value> IgnoreErrors(v8::Local<v8::Value>) { + return Undefined(); + } + + // InvokeShutdownAction(), version for calling directly. + v8::Local<v8::Promise> InvokeShutdownAction() { + return (this->*shutdown_action_)(); + } + + // InvokeShutdownAction(), version for use as a PromiseReaction. + v8::Local<v8::Value> InvokeShutdownAction(v8::Local<v8::Value>) { + return InvokeShutdownAction(); + } + + v8::Local<v8::Value> ShutdownError() const { + DCHECK(!shutdown_error_.IsEmpty()); + return shutdown_error_.Get(script_state_->GetIsolate()); + } + + v8::Local<v8::Promise> WritableStreamAbortAction(); + + v8::Local<v8::Promise> ReadableStreamCancelAction(); + + v8::Local<v8::Promise> + WritableStreamDefaultWriterCloseWithErrorPropagationAction(); + + // Reduces the visual noise when we are returning an undefined value. + v8::Local<v8::Value> Undefined() { + return v8::Undefined(script_state_->GetIsolate()); + } + + WritableStream* Destination(); + + const WritableStream* Destination() const; + + ReadableStream* Readable(); + + // Performs promise.then(on_fulfilled, on_rejected). It behaves like + // StreamPromiseThen(). Only the types are different. + v8::Local<v8::Promise> ThenPromise(v8::Local<v8::Promise> promise, + PromiseReaction on_fulfilled, + PromiseReaction on_rejected = nullptr); + + Member<ScriptState> script_state_; + Member<PipeOptions> pipe_options_; + Member<ReadableStreamDefaultReader> reader_; + Member<WritableStreamDefaultWriter> writer_; + Member<StreamPromiseResolver> promise_; + Member<AbortSignal::AlgorithmHandle> abort_handle_; + TraceWrapperV8Reference<v8::Promise> last_write_; + Action shutdown_action_; + TraceWrapperV8Reference<v8::Value> shutdown_error_; + bool is_shutting_down_ = false; + bool is_reading_ = false; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_PIPE_TO_ENGINE_H_
diff --git a/third_party/blink/renderer/core/streams/readable_stream.cc b/third_party/blink/renderer/core/streams/readable_stream.cc index feeb485..a36a4c49 100644 --- a/third_party/blink/renderer/core/streams/readable_stream.cc +++ b/third_party/blink/renderer/core/streams/readable_stream.cc
@@ -7,21 +7,18 @@ #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/script_function.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_abort_signal.h" #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h" #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream_get_reader_options.h" #include "third_party/blink/renderer/bindings/core/v8/v8_readable_writable_pair.h" #include "third_party/blink/renderer/bindings/core/v8/v8_stream_pipe_options.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h" #include "third_party/blink/renderer/bindings/core/v8/v8_underlying_source.h" #include "third_party/blink/renderer/bindings/core/v8/v8_union_readablestreambyobreader_readablestreamdefaultreader.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h" -#include "third_party/blink/renderer/core/dom/abort_signal.h" -#include "third_party/blink/renderer/core/execution_context/agent.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/core/streams/byte_stream_tee_engine.h" #include "third_party/blink/renderer/core/streams/miscellaneous_operations.h" +#include "third_party/blink/renderer/core/streams/pipe_options.h" +#include "third_party/blink/renderer/core/streams/pipe_to_engine.h" #include "third_party/blink/renderer/core/streams/promise_handler.h" #include "third_party/blink/renderer/core/streams/read_into_request.h" #include "third_party/blink/renderer/core/streams/read_request.h" @@ -147,732 +144,6 @@ Member<UnderlyingByteSourceBase> underlying_byte_source_; }; -ReadableStream::PipeOptions::PipeOptions() - : prevent_close_(false), prevent_abort_(false), prevent_cancel_(false) {} - -ReadableStream::PipeOptions::PipeOptions(const StreamPipeOptions* options) - : prevent_close_(options->hasPreventClose() ? options->preventClose() - : false), - prevent_abort_(options->hasPreventAbort() ? options->preventAbort() - : false), - prevent_cancel_(options->hasPreventCancel() ? options->preventCancel() - : false), - signal_(options->hasSignal() ? options->signal() : nullptr) {} - -void ReadableStream::PipeOptions::Trace(Visitor* visitor) const { - visitor->Trace(signal_); -} - -bool ReadableStream::PipeOptions::GetBoolean(ScriptState* script_state, - v8::Local<v8::Object> dictionary, - const char* property_name, - ExceptionState& exception_state) { - auto* isolate = script_state->GetIsolate(); - v8::TryCatch block(isolate); - v8::Local<v8::Value> property_value; - if (!dictionary - ->Get(script_state->GetContext(), - V8AtomicString(isolate, property_name)) - .ToLocal(&property_value)) { - exception_state.RethrowV8Exception(block.Exception()); - return false; - } - return property_value->ToBoolean(isolate)->Value(); -} - -// PipeToEngine implements PipeTo(). All standard steps in this class come from -// https://streams.spec.whatwg.org/#readable-stream-pipe-to -// -// This implementation is simple but suboptimal because it uses V8 promises to -// drive its asynchronous state machine, allocating a lot of temporary V8 -// objects as a result. -// -// TODO(ricea): Create internal versions of ReadableStreamDefaultReader::Read() -// and WritableStreamDefaultWriter::Write() to bypass promise creation and so -// reduce the number of allocations on the hot path. -class ReadableStream::PipeToEngine final - : public GarbageCollected<PipeToEngine> { - public: - PipeToEngine(ScriptState* script_state, PipeOptions* pipe_options) - : script_state_(script_state), pipe_options_(pipe_options) {} - PipeToEngine(const PipeToEngine&) = delete; - PipeToEngine& operator=(const PipeToEngine&) = delete; - - // This is the main entrypoint for ReadableStreamPipeTo(). - ScriptPromise Start(ReadableStream* readable, WritableStream* destination) { - // 1. Assert: source implements ReadableStream. - DCHECK(readable); - - // 2. Assert: dest implements WritableStream. - DCHECK(destination); - - // Not relevant to C++ implementation: - // 3. Assert: preventClose, preventAbort, and preventCancel are all - // booleans. - - // TODO(ricea): Implement |signal|. - // 4. If signal was not given, let signal be undefined. - // 5. Assert: either signal is undefined, or signal implements AbortSignal. - - // 6. Assert: ! IsReadableStreamLocked(source) is false. - DCHECK(!ReadableStream::IsLocked(readable)); - - // 7. Assert: ! IsWritableStreamLocked(dest) is false. - DCHECK(!WritableStream::IsLocked(destination)); - - auto* isolate = script_state_->GetIsolate(); - ExceptionState exception_state(isolate, ExceptionState::kUnknownContext, "", - ""); - - // 8. If source.[[controller]] implements ReadableByteStreamController, let - // reader be ! AcquireReadableStreamBYOBReader(source) or ! - // AcquireReadableStreamDefaultReader(source), at the user agent's - // discretion. - // 9. Otherwise, let reader be ! AcquireReadableStreamDefaultReader(source). - reader_ = ReadableStream::AcquireDefaultReader(script_state_, readable, - exception_state); - DCHECK(!exception_state.HadException()); - - // 10. Let writer be ! AcquireWritableStreamDefaultWriter(dest). - writer_ = WritableStream::AcquireDefaultWriter(script_state_, destination, - exception_state); - DCHECK(!exception_state.HadException()); - - // 11. Set source.[[disturbed]] to true. - - // 12. Let shuttingDown be false. - DCHECK(!is_shutting_down_); - - // 13. Let promise be a new promise. - promise_ = MakeGarbageCollected<StreamPromiseResolver>(script_state_); - - // 14. If signal is not undefined, - if (auto* signal = pipe_options_->Signal()) { - // b. If signal is aborted, perform abortAlgorithm and - // return promise. - if (signal->aborted()) { - AbortAlgorithm(signal); - return promise_->GetScriptPromise(script_state_); - } - - // c. Add abortAlgorithm to signal. - abort_handle_ = signal->AddAlgorithm( - MakeGarbageCollected<PipeToAbortAlgorithm>(this, signal)); - } - - // 15. In parallel ... - // The rest of the algorithm is described in terms of a series of - // constraints rather than as explicit steps. - if (CheckInitialState()) { - // Need to detect closing and error when we are not reading. This - // corresponds to the following conditions from the standard: - // 1. Errors must be propagated forward: if source.[[state]] is or - // becomes "errored", ... - // and - // 3. Closing must be propagated forward: if source.[[state]] is or - // becomes "closed", ... - ThenPromise(reader_->ClosedPromise()->V8Promise(isolate), - &PipeToEngine::OnReaderClosed, &PipeToEngine::ReadableError); - - // Need to detect error when we are not writing. This corresponds to this - // condition from the standard: - // 2. Errors must be propagated backward: if dest.[[state]] is or - // becomes "errored", ... - // We do not need to detect closure of the writable end of the pipe, - // because we have it locked and so it can only be closed by us. - ThenPromise(writer_->ClosedPromise()->V8Promise(isolate), nullptr, - &PipeToEngine::WritableError); - - // Start the main read / write loop. - HandleNextEvent(Undefined()); - } - - // 16. Return promise. - return promise_->GetScriptPromise(script_state_); - } - - void Trace(Visitor* visitor) const { - visitor->Trace(script_state_); - visitor->Trace(pipe_options_); - visitor->Trace(reader_); - visitor->Trace(writer_); - visitor->Trace(promise_); - visitor->Trace(last_write_); - visitor->Trace(shutdown_error_); - visitor->Trace(abort_handle_); - } - - private: - // The implementation uses method pointers to maximise code reuse. - - class PipeToAbortAlgorithm final : public AbortSignal::Algorithm { - public: - PipeToAbortAlgorithm(PipeToEngine* engine, AbortSignal* signal) - : engine_(engine), signal_(signal) {} - ~PipeToAbortAlgorithm() override = default; - - void Run() override { engine_->AbortAlgorithm(signal_); } - - void Trace(Visitor* visitor) const override { - visitor->Trace(engine_); - visitor->Trace(signal_); - Algorithm::Trace(visitor); - } - - private: - Member<PipeToEngine> engine_; - Member<AbortSignal> signal_; - }; - - // |Action| represents an action that can be passed to the "Shutdown with an - // action" operation. Each Action is implemented as a method which delegates - // to some abstract operation, inferring the arguments from the state of - // |this|. - using Action = v8::Local<v8::Promise> (PipeToEngine::*)(); - - // This implementation uses ThenPromise() 7 times. Instead of creating a dozen - // separate subclasses of ScriptFunction, we use a single implementation and - // pass a method pointer at runtime to control the behaviour. Most - // PromiseReaction methods don't need to return a value, but because some do, - // the rest have to return undefined so that they can have the same method - // signature. Similarly, many of the methods ignore the argument that is - // passed to them. - using PromiseReaction = - v8::Local<v8::Value> (PipeToEngine::*)(v8::Local<v8::Value>); - - class WrappedPromiseReaction final : public PromiseHandlerWithValue { - public: - WrappedPromiseReaction(PipeToEngine* instance, PromiseReaction method) - : instance_(instance), method_(method) {} - - v8::Local<v8::Value> CallWithLocal(ScriptState* script_state, - v8::Local<v8::Value> value) override { - return (instance_->*method_)(value); - } - - void Trace(Visitor* visitor) const override { - visitor->Trace(instance_); - PromiseHandlerWithValue::Trace(visitor); - } - - private: - Member<PipeToEngine> instance_; - PromiseReaction method_; - }; - - // Checks the state of the streams and executes the shutdown handlers if - // necessary. Returns true if piping can continue. - bool CheckInitialState() { - auto* isolate = script_state_->GetIsolate(); - const auto state = Readable()->state_; - - // Both streams can be errored or closed. To perform the right action the - // order of the checks must match the standard: "the following conditions - // must be applied in order." This method only checks the initial state; - // detection of state changes elsewhere is done through checking promise - // reactions. - - // a. Errors must be propagated forward: if source.[[state]] is or - // becomes "errored", - if (state == kErrored) { - ReadableError(Readable()->GetStoredError(isolate)); - return false; - } - - // 2. Errors must be propagated backward: if dest.[[state]] is or becomes - // "errored", - if (Destination()->IsErrored()) { - WritableError(Destination()->GetStoredError(isolate)); - return false; - } - - // 3. Closing must be propagated forward: if source.[[state]] is or - // becomes "closed", then - if (state == kClosed) { - ReadableClosed(); - return false; - } - - // 4. Closing must be propagated backward: if ! - // WritableStreamCloseQueuedOrInFlight(dest) is true or dest.[[state]] - // is "closed", - if (Destination()->IsClosingOrClosed()) { - WritableStartedClosed(); - return false; - } - - return true; - } - - void AbortAlgorithm(AbortSignal* signal) { - // a. Let abortAlgorithm be the following steps: - // i. Let error be signal's abort reason. - v8::Local<v8::Value> error = ToV8(signal->reason(script_state_), - script_state_->GetContext()->Global(), - script_state_->GetIsolate()); - - // Steps ii. to iv. are implemented in AbortAlgorithmAction. - - // v. Shutdown with an action consisting of getting a promise to wait for - // all of the actions in actions, and with error. - ShutdownWithAction(&PipeToEngine::AbortAlgorithmAction, error); - } - - v8::Local<v8::Promise> AbortAlgorithmAction() { - v8::Local<v8::Value> error = - shutdown_error_.Get(script_state_->GetIsolate()); - - // ii. Let actions be an empty ordered set. - HeapVector<ScriptPromise> actions; - - // This method runs later than the equivalent steps in the standard. This - // means that it is safe to do the checks of the state of the destination - // and source synchronously, simplifying the logic. - - // iii. If preventAbort is false, append the following action to actions: - // 1. If dest.[[state]] is "writable", return ! - // WritableStreamAbort(dest, error). - // 2. Otherwise, return a promise resolved with undefined. - if (!pipe_options_->PreventAbort() && Destination()->IsWritable()) { - actions.push_back(ScriptPromise( - script_state_, - WritableStream::Abort(script_state_, Destination(), error))); - } - - // iv. If preventCancel is false, append the following action action to - // actions: - // 1. If source.[[state]] is "readable", return ! - // ReadableStreamCancel(source, error). - // 2. Otherwise, return a promise resolved with undefined. - if (!pipe_options_->PreventCancel() && IsReadable(Readable())) { - actions.push_back(ScriptPromise( - script_state_, - ReadableStream::Cancel(script_state_, Readable(), error))); - } - - return ScriptPromise::All(script_state_, actions) - .V8Value() - .As<v8::Promise>(); - } - - // HandleNextEvent() has an unused argument and return value because it is a - // PromiseReaction. HandleNextEvent() and ReadFulfilled() call each other - // asynchronously in a loop until the pipe completes. - v8::Local<v8::Value> HandleNextEvent(v8::Local<v8::Value>) { - DCHECK(!is_reading_); - if (is_shutting_down_) { - return Undefined(); - } - - absl::optional<double> desired_size = writer_->GetDesiredSizeInternal(); - if (!desired_size.has_value()) { - // This can happen if abort() is queued but not yet started when - // pipeTo() is called. In that case [[storedError]] is not set yet, and - // we need to wait until it is before we can cancel the pipe. Once - // [[storedError]] has been set, the rejection handler set on the writer - // closed promise above will detect it, so all we need to do here is - // nothing. - return Undefined(); - } - - if (desired_size.value() <= 0) { - // Need to wait for backpressure to go away. - ThenPromise( - writer_->ReadyPromise()->V8Promise(script_state_->GetIsolate()), - &PipeToEngine::HandleNextEvent, &PipeToEngine::WritableError); - return Undefined(); - } - - is_reading_ = true; - auto* read_request = MakeGarbageCollected<PipeToReadRequest>(this); - ReadableStreamDefaultReader::Read(script_state_, reader_, read_request); - return Undefined(); - } - - class PipeToReadRequest final : public ReadRequest { - public: - explicit PipeToReadRequest(PipeToEngine* instance) : instance_(instance) {} - - void ChunkSteps(ScriptState* script_state, - v8::Local<v8::Value> chunk) const override { - scoped_refptr<scheduler::EventLoop> event_loop = - ExecutionContext::From(script_state)->GetAgent()->event_loop(); - v8::Global<v8::Value> value(script_state->GetIsolate(), chunk); - event_loop->EnqueueMicrotask( - WTF::BindOnce(&PipeToEngine::ReadRequestChunkStepsBody, - WrapPersistent(instance_.Get()), - WrapPersistent(script_state), std::move(value))); - } - - void CloseSteps(ScriptState* script_state) const override { - instance_->ReadableClosed(); - } - - void ErrorSteps(ScriptState* script_state, - v8::Local<v8::Value> e) const override { - instance_->is_reading_ = false; - if (instance_->is_shutting_down_) { - // This function can be called during shutdown when the lock is - // released. Exit early in that case. - return; - } - instance_->ReadableError( - instance_->Readable()->GetStoredError(script_state->GetIsolate())); - } - - void Trace(Visitor* visitor) const override { - visitor->Trace(instance_); - ReadRequest::Trace(visitor); - } - - private: - Member<PipeToEngine> instance_; - }; - - void ReadRequestChunkStepsBody(ScriptState* script_state, - v8::Global<v8::Value> chunk) { - // This is needed because this method runs as an enqueued microtask, so the - // isolate needs a current context. - ScriptState::Scope scope(script_state); - is_reading_ = false; - const auto write = WritableStreamDefaultWriter::Write( - script_state, writer_, chunk.Get(script_state->GetIsolate())); - last_write_.Reset(script_state->GetIsolate(), write); - ThenPromise(write, nullptr, &PipeToEngine::WritableError); - HandleNextEvent(Undefined()); - } - - // If read() is in progress, then wait for it to tell us that the stream is - // closed so that we write all the data before shutdown. - v8::Local<v8::Value> OnReaderClosed(v8::Local<v8::Value>) { - if (!is_reading_) { - ReadableClosed(); - } - return Undefined(); - } - - // 1. Errors must be propagated forward: if source.[[state]] is or - // becomes "errored", then - v8::Local<v8::Value> ReadableError(v8::Local<v8::Value> error) { - // This function can be called during shutdown when the lock is released. - // Exit early in that case. - if (is_shutting_down_) { - return Undefined(); - } - - // a. If preventAbort is false, shutdown with an action of ! - // WritableStreamAbort(dest, source.[[storedError]]) and with - // source.[[storedError]]. - DCHECK(error->SameValue( - Readable()->GetStoredError(script_state_->GetIsolate()))); - if (!pipe_options_->PreventAbort()) { - ShutdownWithAction(&PipeToEngine::WritableStreamAbortAction, error); - } else { - // b. Otherwise, shutdown with source.[[storedError]]. - Shutdown(error); - } - return Undefined(); - } - - // 2. Errors must be propagated backward: if dest.[[state]] is or becomes - // "errored", then - v8::Local<v8::Value> WritableError(v8::Local<v8::Value> error) { - // This function can be called during shutdown when the lock is released. - // Exit early in that case. - if (is_shutting_down_) { - return Undefined(); - } - - // a. If preventCancel is false, shutdown with an action of ! - // ReadableStreamCancel(source, dest.[[storedError]]) and with - // dest.[[storedError]]. - DCHECK(error->SameValue( - Destination()->GetStoredError(script_state_->GetIsolate()))); - if (!pipe_options_->PreventCancel()) { - ShutdownWithAction(&PipeToEngine::ReadableStreamCancelAction, error); - } else { - // b. Otherwise, shutdown with dest.[[storedError]]. - Shutdown(error); - } - return Undefined(); - } - - // 3. Closing must be propagated forward: if source.[[state]] is or - // becomes "closed", then - void ReadableClosed() { - // a. If preventClose is false, shutdown with an action of ! - // WritableStreamDefaultWriterCloseWithErrorPropagation(writer). - if (!pipe_options_->PreventClose()) { - ShutdownWithAction( - &PipeToEngine:: - WritableStreamDefaultWriterCloseWithErrorPropagationAction, - v8::MaybeLocal<v8::Value>()); - } else { - // b. Otherwise, shutdown. - Shutdown(v8::MaybeLocal<v8::Value>()); - } - } - - // 4. Closing must be propagated backward: if ! - // WritableStreamCloseQueuedOrInFlight(dest) is true or dest.[[state]] is - // "closed", then - void WritableStartedClosed() { - // a. Assert: no chunks have been read or written. - // This is trivially true because this method is only called from - // CheckInitialState(). - - // b. Let destClosed be a new TypeError. - const auto dest_closed = v8::Exception::TypeError( - V8String(script_state_->GetIsolate(), "Destination stream closed")); - - // c. If preventCancel is false, shutdown with an action of ! - // ReadableStreamCancel(source, destClosed) and with destClosed. - if (!pipe_options_->PreventCancel()) { - ShutdownWithAction(&PipeToEngine::ReadableStreamCancelAction, - dest_closed); - } else { - // d. Otherwise, shutdown with destClosed. - Shutdown(dest_closed); - } - } - - // * Shutdown with an action: if any of the above requirements ask to shutdown - // with an action |action|, optionally with an error |originalError|, then: - void ShutdownWithAction(Action action, - v8::MaybeLocal<v8::Value> original_error) { - // a. If shuttingDown is true, abort these substeps. - if (is_shutting_down_) { - return; - } - - // b. Set shuttingDown to true. - is_shutting_down_ = true; - - // Store the action in case we need to call it asynchronously. This is safe - // because the |is_shutting_down_| guard flag ensures that we can only reach - // this assignment once. - shutdown_action_ = action; - - // Store |original_error| as |shutdown_error_| if it was supplied. - v8::Local<v8::Value> original_error_local; - if (original_error.ToLocal(&original_error_local)) { - shutdown_error_.Reset(script_state_->GetIsolate(), original_error_local); - } - v8::Local<v8::Promise> p; - - // c. If dest.[[state]] is "writable" and ! - // WritableStreamCloseQueuedOrInFlight(dest) is false, - if (ShouldWriteQueuedChunks()) { - // i. If any chunks have been read but not yet written, write them to - // dest. - // ii. Wait until every chunk that has been read has been written - // (i.e. the corresponding promises have settled). - p = ThenPromise(WriteQueuedChunks(), &PipeToEngine::InvokeShutdownAction); - } else { - // d. Let p be the result of performing action. - p = InvokeShutdownAction(); - } - - // e. Upon fulfillment of p, finalize, passing along originalError if it - // was given. - // f. Upon rejection of p with reason newError, finalize with newError. - ThenPromise(p, &PipeToEngine::FinalizeWithOriginalErrorIfSet, - &PipeToEngine::FinalizeWithNewError); - } - - // * Shutdown: if any of the above requirements or steps ask to shutdown, - // optionally with an error error, then: - void Shutdown(v8::MaybeLocal<v8::Value> error_maybe) { - // a. If shuttingDown is true, abort these substeps. - if (is_shutting_down_) { - return; - } - - // b. Set shuttingDown to true. - is_shutting_down_ = true; - - // c. If dest.[[state]] is "writable" and ! - // WritableStreamCloseQueuedOrInFlight(dest) is false, - if (ShouldWriteQueuedChunks()) { - // Need to stash the value of |error_maybe| since we are calling - // Finalize() asynchronously. - v8::Local<v8::Value> error; - if (error_maybe.ToLocal(&error)) { - shutdown_error_.Reset(script_state_->GetIsolate(), error); - } - - // i. If any chunks have been read but not yet written, write them to - // dest. - // ii. Wait until every chunk that has been read has been written - // (i.e. the corresponding promises have settled). - // d. Finalize, passing along error if it was given. - ThenPromise(WriteQueuedChunks(), - &PipeToEngine::FinalizeWithOriginalErrorIfSet); - } else { - // d. Finalize, passing along error if it was given. - Finalize(error_maybe); - } - } - - // Calls Finalize(), using the stored shutdown error rather than the value - // that was passed. - v8::Local<v8::Value> FinalizeWithOriginalErrorIfSet(v8::Local<v8::Value>) { - v8::MaybeLocal<v8::Value> error_maybe; - if (!shutdown_error_.IsEmpty()) { - error_maybe = shutdown_error_.Get(script_state_->GetIsolate()); - } - Finalize(error_maybe); - return Undefined(); - } - - // Calls Finalize(), using the value that was passed as the error. - v8::Local<v8::Value> FinalizeWithNewError(v8::Local<v8::Value> new_error) { - Finalize(new_error); - return Undefined(); - } - - // * Finalize: both forms of shutdown will eventually ask to finalize, - // optionally with an error error, which means to perform the following - // steps: - void Finalize(v8::MaybeLocal<v8::Value> error_maybe) { - // a. Perform ! WritableStreamDefaultWriterRelease(writer). - WritableStreamDefaultWriter::Release(script_state_, writer_); - - // b. If reader implements ReadableStreamBYOBReader, perform ! - // ReadableStreamBYOBReaderRelease(reader). - if (reader_->IsBYOBReader()) { - ReadableStreamGenericReader* reader = reader_; - ReadableStreamBYOBReader* byob_reader = - To<ReadableStreamBYOBReader>(reader); - ReadableStreamBYOBReader::Release(script_state_, byob_reader); - } else { - // c. Otherwise, perform ! ReadableStreamDefaultReaderRelease(reader). - DCHECK(reader_->IsDefaultReader()); - ReadableStreamGenericReader* reader = reader_; - ReadableStreamDefaultReader* default_reader = - To<ReadableStreamDefaultReader>(reader); - ReadableStreamDefaultReader::Release(script_state_, default_reader); - } - - // d. If signal is not undefined, remove abortAlgorithm from signal. - // - // An abort algorithm is only added if the signal provided to pipeTo is not - // undefined *and* not aborted, which means `abort_handle_` can be null if - // signal is not undefined. - if (abort_handle_) { - auto* signal = pipe_options_->Signal(); - DCHECK(signal); - signal->RemoveAlgorithm(abort_handle_); - } - - v8::Local<v8::Value> error; - if (error_maybe.ToLocal(&error)) { - // e. If error was given, reject promise with error. - promise_->Reject(script_state_, error); - } else { - // f. Otherwise, resolve promise with undefined. - promise_->ResolveWithUndefined(script_state_); - } - } - - bool ShouldWriteQueuedChunks() const { - // "If dest.[[state]] is "writable" and ! - // WritableStreamCloseQueuedOrInFlight(dest) is false" - return Destination()->IsWritable() && - !WritableStream::CloseQueuedOrInFlight(Destination()); - } - - v8::Local<v8::Promise> WriteQueuedChunks() { - if (!last_write_.IsEmpty()) { - // "Wait until every chunk that has been read has been written (i.e. - // the corresponding promises have settled)" - // This implies that we behave the same whether the promise fulfills or - // rejects. IgnoreErrors() will convert a rejection into a successful - // resolution. - return ThenPromise(last_write_.Get(script_state_->GetIsolate()), nullptr, - &PipeToEngine::IgnoreErrors); - } - return PromiseResolveWithUndefined(script_state_); - } - - v8::Local<v8::Value> IgnoreErrors(v8::Local<v8::Value>) { - return Undefined(); - } - - // InvokeShutdownAction(), version for calling directly. - v8::Local<v8::Promise> InvokeShutdownAction() { - return (this->*shutdown_action_)(); - } - - // InvokeShutdownAction(), version for use as a PromiseReaction. - v8::Local<v8::Value> InvokeShutdownAction(v8::Local<v8::Value>) { - return InvokeShutdownAction(); - } - - v8::Local<v8::Value> ShutdownError() const { - DCHECK(!shutdown_error_.IsEmpty()); - return shutdown_error_.Get(script_state_->GetIsolate()); - } - - v8::Local<v8::Promise> WritableStreamAbortAction() { - return WritableStream::Abort(script_state_, Destination(), ShutdownError()); - } - - v8::Local<v8::Promise> ReadableStreamCancelAction() { - return ReadableStream::Cancel(script_state_, Readable(), ShutdownError()); - } - - v8::Local<v8::Promise> - WritableStreamDefaultWriterCloseWithErrorPropagationAction() { - return WritableStreamDefaultWriter::CloseWithErrorPropagation(script_state_, - writer_); - } - - // Reduces the visual noise when we are returning an undefined value. - v8::Local<v8::Value> Undefined() { - return v8::Undefined(script_state_->GetIsolate()); - } - - WritableStream* Destination() { return writer_->OwnerWritableStream(); } - - const WritableStream* Destination() const { - return writer_->OwnerWritableStream(); - } - - ReadableStream* Readable() { return reader_->owner_readable_stream_; } - - // Performs promise.then(on_fulfilled, on_rejected). It behaves like - // StreamPromiseThen(). Only the types are different. - v8::Local<v8::Promise> ThenPromise(v8::Local<v8::Promise> promise, - PromiseReaction on_fulfilled, - PromiseReaction on_rejected = nullptr) { - return StreamThenPromise( - script_state_->GetContext(), promise, - on_fulfilled - ? MakeGarbageCollected<ScriptFunction>( - script_state_, MakeGarbageCollected<WrappedPromiseReaction>( - this, on_fulfilled)) - : nullptr, - on_rejected - ? MakeGarbageCollected<ScriptFunction>( - script_state_, MakeGarbageCollected<WrappedPromiseReaction>( - this, on_rejected)) - : nullptr); - } - - Member<ScriptState> script_state_; - Member<PipeOptions> pipe_options_; - Member<ReadableStreamDefaultReader> reader_; - Member<WritableStreamDefaultWriter> writer_; - Member<StreamPromiseResolver> promise_; - Member<AbortSignal::AlgorithmHandle> abort_handle_; - TraceWrapperV8Reference<v8::Promise> last_write_; - Action shutdown_action_; - TraceWrapperV8Reference<v8::Value> shutdown_error_; - bool is_shutting_down_ = false; - bool is_reading_ = false; -}; - ReadableStream* ReadableStream::Create(ScriptState* script_state, ExceptionState& exception_state) { return Create(script_state,
diff --git a/third_party/blink/renderer/core/streams/readable_stream.h b/third_party/blink/renderer/core/streams/readable_stream.h index e6eff2ca..47835fbd 100644 --- a/third_party/blink/renderer/core/streams/readable_stream.h +++ b/third_party/blink/renderer/core/streams/readable_stream.h
@@ -21,9 +21,9 @@ namespace blink { -class AbortSignal; class ExceptionState; class MessagePort; +class PipeOptions; class ReadableByteStreamController; class ReadableStreamBYOBReader; class ReadableStreamController; @@ -49,30 +49,6 @@ DEFINE_WRAPPERTYPEINFO(); public: - class PipeOptions : public GarbageCollected<PipeOptions> { - public: - PipeOptions(); - explicit PipeOptions(const StreamPipeOptions* options); - - bool PreventClose() const { return prevent_close_; } - bool PreventAbort() const { return prevent_abort_; } - bool PreventCancel() const { return prevent_cancel_; } - AbortSignal* Signal() const { return signal_; } - - void Trace(Visitor*) const; - - private: - bool GetBoolean(ScriptState* script_state, - v8::Local<v8::Object> dictionary, - const char* property_name, - ExceptionState& exception_state); - - bool prevent_close_ = false; - bool prevent_abort_ = false; - bool prevent_cancel_ = false; - Member<AbortSignal> signal_; - }; - enum State : uint8_t { kReadable, kClosed, kErrored }; // Zero-argument form of the constructor called from JavaScript. @@ -302,6 +278,7 @@ private: friend class ByteStreamTeeEngine; + friend class PipeToEngine; friend class ReadableByteStreamController; friend class ReadableStreamBYOBReader; friend class ReadableStreamDefaultController; @@ -311,7 +288,6 @@ class PullAlgorithm; class CancelAlgorithm; - class PipeToEngine; class ReadHandleImpl; // https://streams.spec.whatwg.org/#rs-constructor
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h index 8413603..28bfe9e 100644 --- a/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h +++ b/third_party/blink/renderer/core/streams/readable_stream_byob_reader.h
@@ -59,6 +59,7 @@ private: friend class ByteStreamTeeEngine; + friend class PipeToEngine; friend class ReadableByteStreamController; friend class ReadableStream;
diff --git a/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h b/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h index b9619db..19db1d1 100644 --- a/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h +++ b/third_party/blink/renderer/core/streams/readable_stream_generic_reader.h
@@ -57,6 +57,7 @@ void Trace(Visitor*) const override; private: + friend class PipeToEngine; friend class ReadableStreamDefaultController; Member<StreamPromiseResolver> closed_promise_;
diff --git a/third_party/blink/renderer/core/streams/writable_stream.cc b/third_party/blink/renderer/core/streams/writable_stream.cc index 9ae57fa..723ad5cf 100644 --- a/third_party/blink/renderer/core/streams/writable_stream.cc +++ b/third_party/blink/renderer/core/streams/writable_stream.cc
@@ -10,6 +10,7 @@ #include "third_party/blink/renderer/core/dom/abort_signal.h" #include "third_party/blink/renderer/core/streams/count_queuing_strategy.h" #include "third_party/blink/renderer/core/streams/miscellaneous_operations.h" +#include "third_party/blink/renderer/core/streams/pipe_options.h" #include "third_party/blink/renderer/core/streams/promise_handler.h" #include "third_party/blink/renderer/core/streams/readable_stream.h" #include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h" @@ -273,9 +274,8 @@ // 7. Let promise be ! ReadableStreamPipeTo(readable, value, false, false, // false). - auto promise = ReadableStream::PipeTo( - script_state, readable, this, - MakeGarbageCollected<ReadableStream::PipeOptions>()); + auto promise = ReadableStream::PipeTo(script_state, readable, this, + MakeGarbageCollected<PipeOptions>()); // 8. Set promise.[[PromiseIsHandled]] to true. promise.MarkAsHandled();
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc index ad2c9649..16f7796 100644 --- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc +++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -54,9 +54,8 @@ #include "third_party/blink/renderer/core/fetch/trust_token_to_mojom.h" #include "third_party/blink/renderer/core/fileapi/blob.h" #include "third_party/blink/renderer/core/fileapi/file.h" -#include "third_party/blink/renderer/core/fileapi/file_read_type.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" #include "third_party/blink/renderer/core/fileapi/public_url_manager.h" #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h" #include "third_party/blink/renderer/core/frame/deprecation/deprecation.h" @@ -244,23 +243,25 @@ class XMLHttpRequest::BlobLoader final : public GarbageCollected<XMLHttpRequest::BlobLoader>, - public FileReaderLoaderClient { + public FileReaderClient { public: BlobLoader(XMLHttpRequest* xhr, scoped_refptr<BlobDataHandle> handle) : xhr_(xhr), loader_(MakeGarbageCollected<FileReaderLoader>( - FileReadType::kReadByClient, this, xhr->GetExecutionContext()->GetTaskRunner( TaskType::kFileReading))) { loader_->Start(std::move(handle)); } - // FileReaderLoaderClient functions. - void DidStartLoading() override {} - void DidReceiveDataForClient(const char* data, unsigned length) override { + // FileReaderClient functions. + FileErrorCode DidStartLoading(uint64_t, uint64_t) override { + return FileErrorCode::kOK; + } + FileErrorCode DidReceiveData(const char* data, unsigned length) override { DCHECK_LE(length, static_cast<unsigned>(INT_MAX)); xhr_->DidReceiveData(data, length); + return FileErrorCode::kOK; } void DidFinishLoading() override { xhr_->DidFinishLoadingFromBlob(); } void DidFail(FileErrorCode error) override { xhr_->DidFailLoadingFromBlob(); } @@ -268,7 +269,7 @@ void Cancel() { loader_->Cancel(); } void Trace(Visitor* visitor) const override { - FileReaderLoaderClient::Trace(visitor); + FileReaderClient::Trace(visitor); visitor->Trace(xhr_); visitor->Trace(loader_); }
diff --git a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc index 28ae65a..aa6207d 100644 --- a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc +++ b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
@@ -20,9 +20,8 @@ #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/fileapi/file_read_type.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/inspector/inspected_frames.h" @@ -449,7 +448,7 @@ class CachedResponseFileReaderLoaderClient final : public GarbageCollected<CachedResponseFileReaderLoaderClient>, - public FileReaderLoaderClient { + public FileReaderClient { public: static void Load(scoped_refptr<base::SingleThreadTaskRunner> task_runner, scoped_refptr<BlobDataHandle> blob, @@ -463,7 +462,9 @@ CachedResponseFileReaderLoaderClient& operator=( const CachedResponseFileReaderLoaderClient&) = delete; - void DidStartLoading() override {} + FileErrorCode DidStartLoading(uint64_t, uint64_t) override { + return FileErrorCode::kOK; + } void DidFinishLoading() override { std::unique_ptr<CachedResponse> response = @@ -482,13 +483,14 @@ dispose(); } - void DidReceiveDataForClient(const char* data, + FileErrorCode DidReceiveData(const char* data, unsigned data_length) override { data_->Append(data, data_length); + return FileErrorCode::kOK; } void Trace(Visitor* visitor) const override { - FileReaderLoaderClient::Trace(visitor); + FileReaderClient::Trace(visitor); visitor->Trace(loader_); } @@ -496,10 +498,8 @@ scoped_refptr<base::SingleThreadTaskRunner> task_runner, scoped_refptr<BlobDataHandle>&& blob, std::unique_ptr<RequestCachedResponseCallback>&& callback) - : loader_( - MakeGarbageCollected<FileReaderLoader>(FileReadType::kReadByClient, - this, - std::move(task_runner))), + : loader_(MakeGarbageCollected<FileReaderLoader>(this, + std::move(task_runner))), callback_(std::move(callback)), data_(SharedBuffer::Create()), keep_alive_(this) { @@ -509,7 +509,10 @@ ~CachedResponseFileReaderLoaderClient() override = default; private: - void dispose() { keep_alive_.Clear(); } + void dispose() { + keep_alive_.Clear(); + loader_ = nullptr; + } Member<FileReaderLoader> loader_; std::unique_ptr<RequestCachedResponseCallback> callback_;
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc index 5ba91856..20d95536 100644 --- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc +++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
@@ -43,7 +43,6 @@ #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fileapi/blob.h" -#include "third_party/blink/renderer/core/fileapi/file_read_type.h" #include "third_party/blink/renderer/core/frame/deprecation/deprecation.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" @@ -278,7 +277,6 @@ const ImageBitmapOptions* options) : ExecutionContextLifecycleObserver(ExecutionContext::From(script_state)), loader_(MakeGarbageCollected<FileReaderLoader>( - FileReadType::kReadAsArrayBuffer, this, GetExecutionContext()->GetTaskRunner(TaskType::kFileReading))), factory_(&factory), @@ -339,8 +337,9 @@ } } -void ImageBitmapFactories::ImageBitmapLoader::DidFinishLoading() { - auto contents = loader_->TakeContents().AsArrayBufferContents(); +void ImageBitmapFactories::ImageBitmapLoader::DidFinishLoading( + FileReaderData data) { + auto contents = std::move(data).AsArrayBufferContents(); loader_.Clear(); if (!contents.IsValid()) { RejectPromise(kAllocationFailureImageBitmapRejectionReason); @@ -349,7 +348,9 @@ ScheduleAsyncImageBitmapDecoding(std::move(contents)); } -void ImageBitmapFactories::ImageBitmapLoader::DidFail(FileErrorCode) { +void ImageBitmapFactories::ImageBitmapLoader::DidFail( + FileErrorCode error_code) { + FileReaderAccumulator::DidFail(error_code); RejectPromise(kUndecodableImageBitmapRejectionReason); } @@ -428,7 +429,7 @@ void ImageBitmapFactories::ImageBitmapLoader::Trace(Visitor* visitor) const { ExecutionContextLifecycleObserver::Trace(visitor); - FileReaderLoaderClient::Trace(visitor); + FileReaderAccumulator::Trace(visitor); visitor->Trace(factory_); visitor->Trace(resolver_); visitor->Trace(options_);
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h index afad69f4..420db36 100644 --- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h +++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h
@@ -37,8 +37,8 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_typedefs.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/workers/worker_global_scope.h" #include "third_party/blink/renderer/modules/modules_export.h" @@ -144,7 +144,7 @@ class ImageBitmapLoader final : public GarbageCollected<ImageBitmapLoader>, public ExecutionContextLifecycleObserver, - public FileReaderLoaderClient { + public FileReaderAccumulator { public: static ImageBitmapLoader* Create(ImageBitmapFactories& factory, absl::optional<gfx::Rect> crop_rect, @@ -183,10 +183,8 @@ // ExecutionContextLifecycleObserver void ContextDestroyed() override; - // FileReaderLoaderClient - void DidStartLoading() override {} - void DidReceiveData() override {} - void DidFinishLoading() override; + // FileReaderClient + void DidFinishLoading(FileReaderData) override; void DidFail(FileErrorCode) override; Member<FileReaderLoader> loader_;
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc b/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc index 4132e20..1e5c40d 100644 --- a/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc +++ b/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
@@ -12,7 +12,6 @@ #include "third_party/blink/renderer/core/dom/document_fragment.h" #include "third_party/blink/renderer/core/editing/serializers/serialization.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/fileapi/file_read_type.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/web_feature.h" @@ -344,34 +343,31 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!file_reader_); file_reader_ = MakeGarbageCollected<FileReaderLoader>( - FileReadType::kReadAsArrayBuffer, this, - std::move(file_reading_task_runner_)); + this, std::move(file_reading_task_runner_)); file_reader_->Start(blob->GetBlobDataHandle()); } -// FileReaderLoaderClient implementation. - -void ClipboardWriter::DidStartLoading() {} -void ClipboardWriter::DidReceiveData() {} - -void ClipboardWriter::DidFinishLoading() { +// FileReaderClient implementation. +void ClipboardWriter::DidFinishLoading(FileReaderData contents) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DOMArrayBuffer* array_buffer = - file_reader_->TakeContents().AsDOMArrayBuffer(); + DOMArrayBuffer* array_buffer = std::move(contents).AsDOMArrayBuffer(); DCHECK(array_buffer); self_keep_alive_.Clear(); + file_reader_ = nullptr; StartWrite(array_buffer, clipboard_task_runner_); } void ClipboardWriter::DidFail(FileErrorCode error_code) { + FileReaderAccumulator::DidFail(error_code); self_keep_alive_.Clear(); + file_reader_ = nullptr; promise_->RejectFromReadOrDecodeFailure(); } void ClipboardWriter::Trace(Visitor* visitor) const { - FileReaderLoaderClient::Trace(visitor); + FileReaderAccumulator::Trace(visitor); visitor->Trace(promise_); visitor->Trace(system_clipboard_); visitor->Trace(file_reader_);
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_writer.h b/third_party/blink/renderer/modules/clipboard/clipboard_writer.h index 980255e..2d24f95c 100644 --- a/third_party/blink/renderer/modules/clipboard/clipboard_writer.h +++ b/third_party/blink/renderer/modules/clipboard/clipboard_writer.h
@@ -8,7 +8,7 @@ #include "base/sequence_checker.h" #include "base/task/single_thread_task_runner.h" #include "third_party/blink/renderer/core/fileapi/blob.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/modules/clipboard/clipboard_promise.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/self_keep_alive.h" @@ -52,7 +52,7 @@ // SelfKeepAlive, and keeps itself alive afterwards during cross-thread // operations by using WrapCrossThreadPersistent. class ClipboardWriter : public GarbageCollected<ClipboardWriter>, - public FileReaderLoaderClient { + public FileReaderAccumulator { public: // For writing sanitized and custom MIME types. // IsValidType() must return true on types passed into `mime_type`. @@ -74,10 +74,8 @@ // Begins the sequence of writing the Blob to the system clipbaord. void WriteToSystem(Blob* blob); - // FileReaderLoaderClient. - void DidStartLoading() override; - void DidReceiveData() override; - void DidFinishLoading() override; + // FileReaderClient. + void DidFinishLoading(FileReaderData) override; void DidFail(FileErrorCode) override; void Trace(Visitor*) const override; @@ -115,7 +113,6 @@ Member<FileReaderLoader> file_reader_; // Access to the global sanitized system clipboard. Member<SystemClipboard> system_clipboard_; - // Oilpan: ClipboardWriter must remain alive until Member<T>::Clear() is // called, to keep the FileReaderLoader alive and avoid unexpected UaPs. SelfKeepAlive<ClipboardWriter> self_keep_alive_{this};
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc b/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc index 6895e76..815ae37a 100644 --- a/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc +++ b/third_party/blink/renderer/modules/indexeddb/idb_request_loader.cc
@@ -9,7 +9,6 @@ #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/fileapi/file_read_type.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" #include "third_party/blink/renderer/modules/indexeddb/idb_request.h" #include "third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.h" @@ -28,9 +27,7 @@ DCHECK(IDBValueUnwrapper::IsWrapped(values_)); } -IDBRequestLoader::~IDBRequestLoader() { - // TODO(pwnall): Do we need to call loader_->Cancel() here? -} +IDBRequestLoader::~IDBRequestLoader() {} void IDBRequestLoader::Start() { #if DCHECK_IS_ON() @@ -87,19 +84,21 @@ file_reader_loading_ = true; #endif // DCHECK_IS_ON() loader_ = MakeGarbageCollected<FileReaderLoader>( - FileReadType::kReadByClient, this, - exection_context->GetTaskRunner(TaskType::kDatabaseAccess)); + this, exection_context->GetTaskRunner(TaskType::kDatabaseAccess)); loader_->Start(unwrapper.WrapperBlobHandle()); } -void IDBRequestLoader::DidStartLoading() {} +FileErrorCode IDBRequestLoader::DidStartLoading(uint64_t, uint64_t) { + return FileErrorCode::kOK; +} -void IDBRequestLoader::DidReceiveDataForClient(const char* data, +FileErrorCode IDBRequestLoader::DidReceiveData(const char* data, unsigned data_length) { DCHECK_LE(wrapped_data_.size() + data_length, wrapped_data_.capacity()) << "The reader returned more data than we were prepared for"; wrapped_data_.Append(data, data_length); + return FileErrorCode::kOK; } void IDBRequestLoader::DidFinishLoading() {
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_request_loader.h b/third_party/blink/renderer/modules/indexeddb/idb_request_loader.h index 44b571b..feb52f0 100644 --- a/third_party/blink/renderer/modules/indexeddb/idb_request_loader.h +++ b/third_party/blink/renderer/modules/indexeddb/idb_request_loader.h
@@ -8,8 +8,8 @@ #include <memory> #include "base/dcheck_is_on.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" @@ -31,7 +31,7 @@ // assumes that the overhead of creating and destroying a Vector is much smaller // than the IPC overhead required to load the Blob data into the renderer. class IDBRequestLoader : public GarbageCollected<IDBRequestLoader>, - public FileReaderLoaderClient { + public FileReaderClient { public: // Creates a loader that will unwrap IDBValues received by a IDBRequest. // @@ -50,13 +50,13 @@ // Halt the process of unwrapping values, if possible. void Cancel(); - // FileReaderLoaderClient implementaton. - void DidStartLoading() override; - void DidReceiveDataForClient(const char* data, unsigned data_length) override; + // FileReaderClient implementation. + FileErrorCode DidStartLoading(uint64_t, uint64_t) override; + FileErrorCode DidReceiveData(const char* data, unsigned data_length) override; void DidFinishLoading() override; void DidFail(FileErrorCode) override; void Trace(Visitor* visitor) const override { - FileReaderLoaderClient::Trace(visitor); + FileReaderClient::Trace(visitor); visitor->Trace(loader_); }
diff --git a/third_party/blink/renderer/modules/ml/BUILD.gn b/third_party/blink/renderer/modules/ml/BUILD.gn index 1db82594..e678743 100644 --- a/third_party/blink/renderer/modules/ml/BUILD.gn +++ b/third_party/blink/renderer/modules/ml/BUILD.gn
@@ -8,7 +8,10 @@ buildflag_header("buildflags") { header = "buildflags.h" - flags = [ "BUILD_WEBNN_WITH_XNNPACK=$build_webnn_with_xnnpack" ] + flags = [ + "BUILD_WEBNN_WITH_XNNPACK=$build_webnn_with_xnnpack", + "BUILD_WEBNN_ON_CROS=$build_webnn_on_cros", + ] } blink_modules_sources("ml") { @@ -50,6 +53,18 @@ deps += [ "//third_party/xnnpack" ] } + + if (build_webnn_on_cros) { + sources += [ + "webnn/ml_graph_cros.cc", + "webnn/ml_graph_cros.h", + ] + + deps += [ + "//third_party/flatbuffers:flatbuffers", + "//third_party/tflite:tflite_public_headers", + ] + } } source_set("unit_tests") { @@ -87,7 +102,7 @@ } if (is_chromeos && current_cpu == "x64") { - sources += [ "webnn/ml_graph_test_tflite.cc" ] + sources += [ "webnn/ml_graph_test_cros.cc" ] deps += [ "//third_party/tflite" ] } }
diff --git a/third_party/blink/renderer/modules/ml/ml_context.cc b/third_party/blink/renderer/modules/ml/ml_context.cc index 6ec2da8f..29786a7f7 100644 --- a/third_party/blink/renderer/modules/ml/ml_context.cc +++ b/third_party/blink/renderer/modules/ml/ml_context.cc
@@ -7,6 +7,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/modules/ml/ml.h" +#include "third_party/blink/renderer/modules/ml/ml_model_loader.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" namespace blink { @@ -54,8 +55,18 @@ return ml_.Get(); } +MLModelLoader* MLContext::GetModelLoaderForWebNN(ScriptState* script_state) { + if (!ml_model_loader_) { + ExecutionContext* execution_context = ExecutionContext::From(script_state); + ml_model_loader_ = + MakeGarbageCollected<MLModelLoader>(execution_context, this); + } + return ml_model_loader_; +} + void MLContext::Trace(Visitor* visitor) const { visitor->Trace(ml_); + visitor->Trace(ml_model_loader_); ScriptWrappable::Trace(visitor); }
diff --git a/third_party/blink/renderer/modules/ml/ml_context.h b/third_party/blink/renderer/modules/ml/ml_context.h index 63bf31e23..0abbd39 100644 --- a/third_party/blink/renderer/modules/ml/ml_context.h +++ b/third_party/blink/renderer/modules/ml/ml_context.h
@@ -18,6 +18,7 @@ namespace blink { class ML; +class MLModelLoader; class MODULES_EXPORT MLContext final : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); @@ -41,6 +42,9 @@ void LogConsoleWarning(const String& message); ML* GetML(); + // This method returns a MLModelLoader that's used and shared by WebNN APIs + // invoked on this MLContext. + MLModelLoader* GetModelLoaderForWebNN(ScriptState* script_state); void Trace(Visitor* visitor) const override; @@ -63,6 +67,8 @@ unsigned int num_threads_; Member<ML> ml_; + // WebNN uses this MLModelLoader to build a computational graph. + Member<MLModelLoader> ml_model_loader_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/ml_model_loader.cc b/third_party/blink/renderer/modules/ml/ml_model_loader.cc index 20b76879..3f1444b 100644 --- a/third_party/blink/renderer/modules/ml/ml_model_loader.cc +++ b/third_party/blink/renderer/modules/ml/ml_model_loader.cc
@@ -163,12 +163,30 @@ script_state, exception_state.GetContext()); ScriptPromise promise = resolver->Promise(); + auto* execution_context = ExecutionContext::From(script_state); + Load(script_state, buffer, + WTF::BindOnce(&OnRemoteModelLoad, WrapPersistent(execution_context), + WrapPersistent(resolver))); + + return promise; +} + +void MLModelLoader::Trace(Visitor* visitor) const { + visitor->Trace(ml_context_); + visitor->Trace(remote_loader_); + + ScriptWrappable::Trace(visitor); +} + +void MLModelLoader::Load(ScriptState* script_state, + DOMArrayBuffer* buffer, + ModelLoadedCallback callback) { if (ml_context_->GetML() == nullptr) { - resolver->Reject(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kInvalidStateError, "Internal error.")); + std::move(callback).Run(LoadModelResult::kUnknownError, mojo::NullRemote(), + nullptr); } else if (buffer == nullptr) { - resolver->Reject(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kConstraintError, "Invalid input arguments.")); + std::move(callback).Run(LoadModelResult::kInvalidModel, mojo::NullRemote(), + nullptr); } else { if (!remote_loader_.is_bound()) { // Needs to bootstrap the mojo connection first. @@ -184,44 +202,32 @@ script_state, std::move(options_mojo), WTF::BindOnce(&MLModelLoader::OnRemoteLoaderCreated, WrapPersistent(this), WrapPersistent(script_state), - WrapPersistent(resolver), WrapPersistent(buffer))); + WrapPersistent(buffer), std::move(callback))); } else { // Directly use `remote_loader_`. remote_loader_->Load( base::make_span(static_cast<const uint8_t*>(buffer->Data()), buffer->ByteLength()), - WTF::BindOnce(&OnRemoteModelLoad, - WrapPersistent(ExecutionContext::From(script_state)), - WrapPersistent(resolver))); + std::move(callback)); } } - - return promise; -} - -void MLModelLoader::Trace(Visitor* visitor) const { - visitor->Trace(ml_context_); - visitor->Trace(remote_loader_); - - ScriptWrappable::Trace(visitor); } void MLModelLoader::OnRemoteLoaderCreated( ScriptState* script_state, - ScriptPromiseResolver* resolver, DOMArrayBuffer* buffer, + ModelLoadedCallback callback, CreateModelLoaderResult result, mojo::PendingRemote<ModelLoader> pending_remote) { switch (result) { case CreateModelLoaderResult::kUnknownError: { - resolver->Reject(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kUnknownError, "Internal error.")); + std::move(callback).Run(LoadModelResult::kUnknownError, + mojo::NullRemote(), nullptr); return; } case CreateModelLoaderResult::kNotSupported: { - resolver->Reject(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kNotSupportedError, - "The context can not be supported.")); + std::move(callback).Run(LoadModelResult::kNotSupported, + mojo::NullRemote(), nullptr); return; } case CreateModelLoaderResult::kOk: { @@ -234,8 +240,7 @@ remote_loader_->Load( base::make_span(static_cast<const uint8_t*>(buffer->Data()), buffer->ByteLength()), - WTF::BindOnce(&OnRemoteModelLoad, WrapPersistent(execution_context), - WrapPersistent(resolver))); + std::move(callback)); return; } }
diff --git a/third_party/blink/renderer/modules/ml/ml_model_loader.h b/third_party/blink/renderer/modules/ml/ml_model_loader.h index ed9d575..65a8131 100644 --- a/third_party/blink/renderer/modules/ml/ml_model_loader.h +++ b/third_party/blink/renderer/modules/ml/ml_model_loader.h
@@ -47,11 +47,21 @@ void Trace(Visitor* visitor) const override; + // The callback of loading model is used to bind the pending remote of `Model` + // interface if the model is loaded successfully. + using ModelLoadedCallback = base::OnceCallback<void( + ml::model_loader::mojom::blink::LoadModelResult result, + mojo::PendingRemote<ml::model_loader::mojom::blink::Model> pending_remote, + ml::model_loader::mojom::blink::ModelInfoPtr model_info)>; + void Load(ScriptState* script_state, + DOMArrayBuffer* buffer, + ModelLoadedCallback callback); + private: void OnRemoteLoaderCreated( ScriptState* script_state, - ScriptPromiseResolver* resolver, DOMArrayBuffer* buffer, + ModelLoadedCallback callback, ml::model_loader::mojom::blink::CreateModelLoaderResult result, mojo::PendingRemote<ml::model_loader::mojom::blink::ModelLoader> pending_remote);
diff --git a/third_party/blink/renderer/modules/ml/webnn/features.gni b/third_party/blink/renderer/modules/ml/webnn/features.gni index ec24336..760689f9 100644 --- a/third_party/blink/renderer/modules/ml/webnn/features.gni +++ b/third_party/blink/renderer/modules/ml/webnn/features.gni
@@ -8,4 +8,8 @@ # Windows and Linux on x64 or x86. build_webnn_with_xnnpack = (is_linux || is_win) && (current_cpu == "x64" || current_cpu == "x86") + + # This build flag enables WebNN on ChromeOS platform to access hardware + # acceleration by using ModelLoader mojo interface. + build_webnn_on_cros = is_chromeos }
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc index 589f7e3..4dff6c0 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
@@ -30,6 +30,10 @@ #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.h" #endif +#if BUILDFLAG(BUILD_WEBNN_ON_CROS) +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_cros.h" +#endif + namespace blink { namespace { @@ -1917,6 +1921,15 @@ } #endif +#if BUILDFLAG(BUILD_WEBNN_ON_CROS) + // On ChromeOS, ML model inferencing is off-loaded to ModelLoader service. + if (ml_context_->GetDevicePreference() == V8MLDevicePreference::Enum::kAuto || + ml_context_->GetDevicePreference() == V8MLDevicePreference::Enum::kCpu) { + MLGraphCrOS::ValidateAndBuildAsync(ml_context_, named_outputs, resolver); + return promise; + } +#endif + resolver->Reject(MakeGarbageCollected<DOMException>( DOMExceptionCode::kNotSupportedError, "Not implemented")); return promise;
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_cros.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_cros.cc new file mode 100644 index 0000000..24cfa68 --- /dev/null +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_cros.cc
@@ -0,0 +1,131 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_cros.h" + +#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_compute_result.h" +#include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/modules/ml/ml.h" +#include "third_party/blink/renderer/modules/ml/ml_context.h" +#include "third_party/blink/renderer/modules/ml/ml_model_loader.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" + +namespace blink { + +namespace { + +flatbuffers::DetachedBuffer* g_flatbuffer_for_testing = nullptr; + +} // namespace + +// static +void MLGraphCrOS::ValidateAndBuildAsync(MLContext* ml_context, + const MLNamedOperands& named_outputs, + ScriptPromiseResolver* resolver) { + auto* script_state = resolver->GetScriptState(); + auto* execution_context = ExecutionContext::From(script_state); + auto* graph = + MakeGarbageCollected<MLGraphCrOS>(execution_context, ml_context); + graph->BuildAsync(named_outputs, resolver); +} + +MLGraphCrOS::MLGraphCrOS(ExecutionContext* execution_context, + MLContext* ml_context) + : MLGraph(ml_context), remote_model_(execution_context) {} + +MLGraphCrOS::~MLGraphCrOS() = default; + +void MLGraphCrOS::Trace(Visitor* visitor) const { + visitor->Trace(remote_model_); + MLGraph::Trace(visitor); +} + +void MLGraphCrOS::BuildAsyncImpl(const MLNamedOperands& outputs, + ScriptPromiseResolver* resolver) { + DOMArrayBuffer* buffer = nullptr; + if (g_flatbuffer_for_testing) { + buffer = DOMArrayBuffer::Create(g_flatbuffer_for_testing->data(), + g_flatbuffer_for_testing->size()); + } + // TODO(crbug.com/1273291): Convert WebNN graph to flatbuffer in the `buffer`. + auto* script_state = resolver->GetScriptState(); + auto* execution_context = ExecutionContext::From(script_state); + auto* ml_model_loader = ml_context_->GetModelLoaderForWebNN(script_state); + ml_model_loader->Load( + script_state, buffer, + WTF::BindOnce(&MLGraphCrOS::OnRemoteModelLoad, WrapPersistent(this), + WrapPersistent(execution_context), + WrapPersistent(resolver))); +} + +void MLGraphCrOS::OnRemoteModelLoad( + ExecutionContext* execution_context, + ScriptPromiseResolver* resolver, + ml::model_loader::mojom::blink::LoadModelResult result, + mojo::PendingRemote<ml::model_loader::mojom::blink::Model> pending_remote, + ml::model_loader::mojom::blink::ModelInfoPtr tensor_info) { + if (result != ml::model_loader::mojom::blink::LoadModelResult::kOk) { + resolver->Reject(MakeGarbageCollected<DOMException>( + DOMExceptionCode::kUnknownError, "Unknown error.")); + return; + } + remote_model_.Bind( + std::move(pending_remote), + execution_context->GetTaskRunner(TaskType::kInternalDefault)); + + // Stores input tensor information of loaded model to verify the input + // data by user including name and byte length. + input_tensor_name_to_info_ = std::move(tensor_info->input_tensor_info); + // Stores output tensor information of loaded model to verify the output + // data returned from `MLService` after computing. + output_tensor_name_to_info_ = std::move(tensor_info->output_tensor_info); + + resolver->Resolve(this); +} + +const HashMap<String, ml::model_loader::mojom::blink::TensorInfoPtr>& +MLGraphCrOS::GetInputTensorInfoMapForTesting() const { + return input_tensor_name_to_info_; +} + +const HashMap<String, ml::model_loader::mojom::blink::TensorInfoPtr>& +MLGraphCrOS::GetOutputTensorInfoMapForTesting() const { + return output_tensor_name_to_info_; +} + +// static +void MLGraphCrOS::SetFlatbufferForTesting( + flatbuffers::DetachedBuffer* flatbuffer) { + g_flatbuffer_for_testing = flatbuffer; +} + +MLGraph* MLGraphCrOS::BuildSyncImpl(const MLNamedOperands& named_outputs, + ExceptionState& exception_state) { + // TODO(crbug.com/1273291): Support sync build that is only exposed to + // dedicated worker. + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + "Not implemented."); + return nullptr; +} + +void MLGraphCrOS::ComputeAsyncImpl(const MLNamedArrayBufferViews& inputs, + const MLNamedArrayBufferViews& outputs, + ScriptPromiseResolver* resolver) { + // TODO(crbug.com/1273291): Support async compute. + resolver->Reject(MakeGarbageCollected<DOMException>( + DOMExceptionCode::kNotSupportedError, "Not implemented.")); +} + +void MLGraphCrOS::ComputeSyncImpl(const MLNamedArrayBufferViews& inputs, + const MLNamedArrayBufferViews& outputs, + ExceptionState& exception_state) { + // TODO(crbug.com/1273291): Support sync compute that is only exposed to + // dedicated worker. + exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, + "Not implemented."); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_cros.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_cros.h new file mode 100644 index 0000000..7a736f19 --- /dev/null +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_cros.h
@@ -0,0 +1,86 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_CROS_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_CROS_H_ + +#include "components/ml/mojom/web_platform_model.mojom-blink.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/platform/heap/member.h" +#include "third_party/blink/renderer/platform/heap/visitor.h" +#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h" +#include "third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h" + +namespace blink { + +class ScriptPromiseResolver; + +class MODULES_EXPORT MLGraphCrOS final : public MLGraph { + public: + // Create and build an MLGraphCrOS object. Resolve the promise with + // this concrete object if the underlying TF-Lite model converted from WebNN + // graph builds successfully. + static void ValidateAndBuildAsync(MLContext* context, + const MLNamedOperands& named_outputs, + ScriptPromiseResolver* resolver); + + // The constructor shouldn't be called directly, use ValidateAndBuildAsync() + // method instead, and the declaration must be public to be called by + // MakeGarbageCollected. + MLGraphCrOS(ExecutionContext* execution_context, MLContext* context); + ~MLGraphCrOS() override; + + void Trace(Visitor* visitor) const override; + + const HashMap<String, ml::model_loader::mojom::blink::TensorInfoPtr>& + GetInputTensorInfoMapForTesting() const; + const HashMap<String, ml::model_loader::mojom::blink::TensorInfoPtr>& + GetOutputTensorInfoMapForTesting() const; + + // The caller of this function is responsible to keep flatbuffer alive and + // unset it when it's no longer used. + static void SetFlatbufferForTesting(flatbuffers::DetachedBuffer* flatbuffer); + + private: + // The callback of loading tflite model, it will bind the `Model` pending + // remote if it's successful. + void OnRemoteModelLoad( + ExecutionContext* execution_context, + ScriptPromiseResolver* resolver, + ml::model_loader::mojom::blink::LoadModelResult result, + mojo::PendingRemote<ml::model_loader::mojom::blink::Model> pending_remote, + ml::model_loader::mojom::blink::ModelInfoPtr model_info); + + // Load a WebNN graph in `MLService` with `ModelLoader` message pipe, the + // operations of WebNN need to be converted into a TF-Lite model in + // FlatBuffers. + void BuildAsyncImpl(const MLNamedOperands& named_outputs, + ScriptPromiseResolver* resolver) override; + + // Load the converted model with synchronous call of `ModelLoader` interface. + MLGraph* BuildSyncImpl(const MLNamedOperands& named_outputs, + ExceptionState& exception_state) override; + + // Compute the converted model with asynchronous call of `Model` interface. + void ComputeAsyncImpl(const MLNamedArrayBufferViews& inputs, + const MLNamedArrayBufferViews& outputs, + ScriptPromiseResolver* resolver) override; + + // Compute the converted model with synchronous call of `Model` interface. + void ComputeSyncImpl(const MLNamedArrayBufferViews& inputs, + const MLNamedArrayBufferViews& outputs, + ExceptionState& exception_state) override; + + HeapMojoRemote<ml::model_loader::mojom::blink::Model> remote_model_; + HashMap<String, ml::model_loader::mojom::blink::TensorInfoPtr> + input_tensor_name_to_info_; + HashMap<String, ml::model_loader::mojom::blink::TensorInfoPtr> + output_tensor_name_to_info_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_CROS_H_
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc index 6a7cb04..f50c317 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc
@@ -33,6 +33,9 @@ case BackendType::kXnnpack: name += "Xnnpack_"; break; + case BackendType::kModelLoader: + name += "ModelLoader_"; + break; } switch (execution_mode) {
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h index 54bc04f0..1176798 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h
@@ -24,7 +24,7 @@ // The utility methods for graph test. enum ExecutionMode { kAsync, kSync }; // The backends share the unit tests in the MLGraphTest. -enum BackendType { kFake, kXnnpack }; +enum BackendType { kFake, kXnnpack, kModelLoader }; using TestVariety = std::tuple<BackendType, ExecutionMode>;
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_cros.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_cros.cc new file mode 100644 index 0000000..0b5646d --- /dev/null +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_cros.cc
@@ -0,0 +1,325 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/ml/mojom/ml_service.mojom-blink.h" +#include "components/ml/mojom/web_platform_model.mojom-blink.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" +#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_2d_options.h" +#include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/modules/ml/ml.h" +#include "third_party/blink/renderer/modules/ml/ml_context.h" +#include "third_party/blink/renderer/modules/ml/ml_model_loader_test_util.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_utils.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_cros.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h" +#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" +#include "third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h" +#include "third_party/tflite/src/tensorflow/lite/kernels/builtin_op_kernels.h" +#include "third_party/tflite/src/tensorflow/lite/model.h" +#include "third_party/tflite/src/tensorflow/lite/mutable_op_resolver.h" +#include "third_party/tflite/src/tensorflow/lite/schema/schema_generated.h" + +namespace blink { + +namespace blink_mojom = ml::model_loader::mojom::blink; + +namespace { + +// The version number of the Schema. Ideally all changes will be backward +// compatible. If that ever changes, we must ensure that version is the first +// entry in the new tflite root so that we can see that version is not 1. +#define TFLITE_SCHEMA_VERSION (3) + +Vector<int32_t> ConvertDimensions(const Vector<uint32_t>& dimensions) { + Vector<int32_t> new_dims; + for (auto dim : dimensions) { + new_dims.push_back(base::checked_cast<int32_t>(dim)); + } + return new_dims; +} + +blink_mojom::TensorInfoPtr ConvertToMojom(const TfLiteTensor* tensor) { + auto tensor_info = blink_mojom::TensorInfo::New(); + tensor_info->byte_size = base::checked_cast<uint32_t>(tensor->bytes); + WTF::Vector<uint32_t> dims; + dims.reserve(tensor->dims->size); + for (int32_t i = 0; i < tensor->dims->size; ++i) { + dims.push_back(tensor->dims->data[i]); + } + tensor_info->dimensions = std::move(dims); + return tensor_info; +} + +// This class maintains all the currently supported TFLite +// operations for the Chromium build of TFLite and registers them for use. +class TfLiteOpResolver : public tflite::MutableOpResolver { + public: + TfLiteOpResolver() { + AddBuiltin(tflite::BuiltinOperator_ADD, + tflite::ops::builtin::Register_ADD(), + /* min_version = */ 1, + /* max_version = */ 2); + } +}; + +class TfLiteRuntime { + public: + TfLiteRuntime() = default; + TfLiteRuntime(const TfLiteRuntime&) = delete; + TfLiteRuntime(TfLiteRuntime&&) = delete; + ~TfLiteRuntime() = default; + + TfLiteStatus Load(const mojo_base::BigBuffer& buffer, + blink_mojom::ModelInfoPtr& info) { + const tflite::Model* model = tflite::GetModel(buffer.data()); + EXPECT_NE(model, nullptr); + TfLiteOpResolver op_resolver; + EXPECT_EQ(tflite::InterpreterBuilder(model, op_resolver)(&interpreter_), + kTfLiteOk); + EXPECT_NE(interpreter_, nullptr); + EXPECT_EQ(interpreter_->AllocateTensors(), kTfLiteOk); + + for (auto index : interpreter_->inputs()) { + auto* tensor = interpreter_->tensor(index); + info->input_tensor_info.insert(WTF::String(tensor->name), + ConvertToMojom(tensor)); + } + + for (auto index : interpreter_->outputs()) { + auto* tensor = interpreter_->tensor(index); + info->output_tensor_info.insert(WTF::String(tensor->name), + ConvertToMojom(tensor)); + } + return kTfLiteOk; + } + + private: + std::unique_ptr<tflite::Interpreter> interpreter_; +}; + +} // namespace + +class FakeWebNNModel : public blink_mojom::Model { + public: + FakeWebNNModel() : runtime_(std::make_unique<TfLiteRuntime>()) {} + FakeWebNNModel(const FakeWebNNModel&) = delete; + FakeWebNNModel(FakeWebNNModel&&) = delete; + ~FakeWebNNModel() override = default; + + FakeMLModelLoader::LoadFn CreateFromThis() { + return WTF::BindOnce(&FakeWebNNModel::OnCreateModel, WTF::Unretained(this)); + } + + private: + void OnCreateModel(mojo_base::BigBuffer buffer, + blink_mojom::ModelLoader::LoadCallback callback) { + blink_mojom::ModelInfoPtr info = blink_mojom::ModelInfo::New(); + EXPECT_EQ(runtime_->Load(buffer, info), kTfLiteOk); + + receiver_.reset(); + std::move(callback).Run(blink_mojom::LoadModelResult::kOk, + receiver_.BindNewPipeAndPassRemote(), + std::move(info)); + } + + // Override methods from blink_mojom::Model. + void Compute(const WTF::HashMap<WTF::String, WTF::Vector<uint8_t>>& input, + blink_mojom::Model::ComputeCallback callback) override { + NOTIMPLEMENTED(); + } + + mojo::Receiver<blink_mojom::Model> receiver_{this}; + std::unique_ptr<TfLiteRuntime> runtime_; +}; + +class MLGraphTestCrOS : public MLGraphTestBase { + public: + ScopedSetMLServiceBinder SetUpMLService(V8TestingScope& scope) { + service_.SetCreateModelLoader(loader_.CreateFromThis()); + loader_.SetLoad(model_.CreateFromThis()); + + return ScopedSetMLServiceBinder(&service_, scope); + } + + private: + FakeMLService service_; + FakeMLModelLoader loader_; + FakeWebNNModel model_; +}; + +template <typename T> +struct ElementWiseAddTester { + OperandInfo<T> lhs; + OperandInfo<T> rhs; + OperandInfo<T> expected; + + ~ElementWiseAddTester() { MLGraphCrOS::SetFlatbufferForTesting(nullptr); } + + void Test(MLGraphTestCrOS& helper, V8TestingScope& scope) { + // Setup binder for MLService + ScopedSetMLServiceBinder scoped_setup_binder = helper.SetUpMLService(scope); + // Set the flatbuffer of tflite model converted from the WebNN graph. + flatbuffers::DetachedBuffer flatbuffer = GetFlatBuffer(); + MLGraphCrOS::SetFlatbufferForTesting(&flatbuffer); + + // Test building graph for the operands in the following topology: + // [input] [constant] + // \ / + // add + // | + // [output] + auto* builder = CreateMLGraphBuilder(scope.GetExecutionContext()); + auto* input = BuildInput(builder, "input", lhs.dimensions, lhs.type, + scope.GetExceptionState()); + auto* constant = BuildConstant(builder, rhs.dimensions, rhs.type, + rhs.values, scope.GetExceptionState()); + auto* output = BuildElementWiseBinary( + scope, builder, ElementWiseBinaryKind::kAdd, input, constant); + EXPECT_EQ(output->Type(), expected.type); + auto [graph, exception] = + helper.BuildGraph(scope, builder, {{"output", output}}); + EXPECT_NE(graph, nullptr); + MLGraphCrOS* cros_graph = static_cast<MLGraphCrOS*>(graph.Get()); + const auto& input_tensor_info = + cros_graph->GetInputTensorInfoMapForTesting(); + EXPECT_EQ(input_tensor_info.size(), 1u); + EXPECT_EQ(input_tensor_info.Contains("input"), true); + EXPECT_EQ(input_tensor_info.find("input")->value->dimensions, + lhs.dimensions); + const auto& output_tensor_info = + cros_graph->GetOutputTensorInfoMapForTesting(); + EXPECT_EQ(output_tensor_info.size(), 1u); + EXPECT_EQ(output_tensor_info.Contains("output"), true); + EXPECT_EQ(output_tensor_info.find("output")->value->dimensions, + expected.dimensions); + } + + private: + // Build tflite model for the element-wise graph in the flatbuffer. + flatbuffers::DetachedBuffer GetFlatBuffer() { + // Tflite model parameters information. + const char* kModelDescription = "ElementWise binary model for testing"; + const tflite::TensorType type = tflite::TensorType_FLOAT32; + + flatbuffers::FlatBufferBuilder builder; + // It is required that the first entry in the buffers of model is always an + // empty buffer. This is so that the default buffer index of zero in Tensor + // will always refer to a valid empty buffer. + Vector<flatbuffers::Offset<tflite::Buffer>> buffers = { + tflite::CreateBuffer(builder, builder.CreateVector({})), + }; + // Create tflite |Buffer| for constant tensor. + buffers.push_back(tflite::CreateBuffer( + builder, builder.CreateVector( + reinterpret_cast<const uint8_t*>(rhs.values.data()), + sizeof(T) * rhs.values.size()))); + + // A list of all tflite |Tensor| used in this model. + Vector<flatbuffers::Offset<tflite::Tensor>> tensors; + // Create tflite |Tensor| for constant tensor. + CHECK(lhs.type == V8MLOperandType::Enum::kFloat32); + uint32_t lhs_buffer_index = 0; + tensors.emplace_back(tflite::CreateTensor( + builder, + builder.CreateVector<int32_t>(ConvertDimensions(lhs.dimensions)), type, + lhs_buffer_index, builder.CreateString("input"))); + // Create tflite |Tensor| for input tensor. + CHECK(rhs.type == V8MLOperandType::Enum::kFloat32); + uint32_t rhs_buffer_index = 1; + tensors.emplace_back(tflite::CreateTensor( + builder, + builder.CreateVector<int32_t>(ConvertDimensions(rhs.dimensions)), type, + rhs_buffer_index)); + // Create tflite |Tensor| for output tensor. + uint32_t output_buffer_index = 0; + tensors.emplace_back(tflite::CreateTensor( + builder, + builder.CreateVector<int32_t>(ConvertDimensions(expected.dimensions)), + type, output_buffer_index, builder.CreateString("output"))); + + // A list of all tflite |Operator| used in this model. + Vector<flatbuffers::Offset<tflite::Operator>> operators; + int32_t lhs_tensor_index = 0, rhs_tensor_index = 1, output_tensor_index = 2; + Vector<int32_t> op_inputs = {lhs_tensor_index, rhs_tensor_index}; + Vector<int32_t> op_outputs = {output_tensor_index}; + operators.emplace_back(tflite::CreateOperator( + builder, 0, builder.CreateVector<int32_t>(op_inputs), + builder.CreateVector<int32_t>(op_outputs))); + + // Create subgraph in the model. + Vector<int32_t> subgraph_inputs = {lhs_tensor_index}; + Vector<int32_t> subgraph_outputs = {output_tensor_index}; + flatbuffers::Offset<tflite::SubGraph> subgraph = tflite::CreateSubGraph( + builder, builder.CreateVector(tensors.data(), tensors.size()), + builder.CreateVector<int32_t>(subgraph_inputs), + builder.CreateVector<int32_t>(subgraph_outputs), + builder.CreateVector(operators.data(), operators.size())); + + flatbuffers::Offset<flatbuffers::String> description = + builder.CreateString(kModelDescription); + + Vector<flatbuffers::Offset<tflite::OperatorCode>> operator_codes = { + {tflite::CreateOperatorCode(builder, tflite::BuiltinOperator_ADD)}}; + flatbuffers::Offset<tflite::Model> model_buffer = tflite::CreateModel( + builder, TFLITE_SCHEMA_VERSION, + builder.CreateVector(operator_codes.data(), operator_codes.size()), + builder.CreateVector(&subgraph, 1), description, + builder.CreateVector(buffers.data(), buffers.size())); + + tflite::FinishModelBuffer(builder, model_buffer); + + return builder.Release(); + } +}; + +TEST_P(MLGraphTestCrOS, BuildGraphWithTfliteModel) { + V8TestingScope scope; + + { + // Test element-wise add operator for two 1-D tensors. + ElementWiseAddTester<float>{ + .lhs = {.type = V8MLOperandType::Enum::kFloat32, + .dimensions = {2}, + .values = {1.0, 2.0}}, + .rhs = {.type = V8MLOperandType::Enum::kFloat32, + .dimensions = {2}, + .values = {3.0, 4.0}}, + .expected = {.type = V8MLOperandType::Enum::kFloat32, + .dimensions = {2}}} + .Test(*this, scope); + } + { + // Test element-wise add operator for 1-D tensor broadcasting to 2-D + // tensor. + ElementWiseAddTester<float>{ + .lhs = {.type = V8MLOperandType::Enum::kFloat32, + .dimensions = {2, 2}, + .values = {1.0, 2.0, 3.0, 4.0}}, + .rhs = {.type = V8MLOperandType::Enum::kFloat32, + .dimensions = {2}, + .values = {5.0, 6.0}}, + .expected = {.type = V8MLOperandType::Enum::kFloat32, + .dimensions = {2, 2}}} + .Test(*this, scope); + } +} + +INSTANTIATE_TEST_SUITE_P( + All, + MLGraphTestCrOS, + testing::Combine(::testing::Values(BackendType::kModelLoader), + ::testing::Values(ExecutionMode::kAsync)), + TestVarietyToString); + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_tflite.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_tflite.cc deleted file mode 100644 index 3826c42..0000000 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_tflite.cc +++ /dev/null
@@ -1,164 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/renderer/platform/wtf/vector.h" -#include "third_party/tflite/src/tensorflow/lite/kernels/builtin_op_kernels.h" -#include "third_party/tflite/src/tensorflow/lite/model.h" -#include "third_party/tflite/src/tensorflow/lite/mutable_op_resolver.h" -#include "third_party/tflite/src/tensorflow/lite/schema/schema_generated.h" - -namespace blink { - -// The version number of the Schema. Ideally all changes will be backward -// compatible. If that ever changes, we must ensure that version is the first -// entry in the new tflite root so that we can see that version is not 1. -#define TFLITE_SCHEMA_VERSION (3) - -// This class maintains all the currently supported TFLite -// operations for the Chromium build of TFLite and registers them for use. -class TFLiteOpResolver : public tflite::MutableOpResolver { - public: - TFLiteOpResolver() { - AddBuiltin(tflite::BuiltinOperator_ADD, - tflite::ops::builtin::Register_ADD(), - /* min_version = */ 1, - /* max_version = */ 2); - } -}; - -// Helper function to get the data of result into a vector. -template <typename T> -Vector<T> GetResult(const WTF::Vector<uint8_t>& result) { - Vector<T> values(base::checked_cast<wtf_size_t>(result.size() / sizeof(T))); - memcpy(values.data(), result.data(), result.size()); - return values; -} - -template <typename T> -struct OperandInfo { - tflite::TensorType type; - Vector<int32_t> dimensions; - Vector<T> values; -}; - -template <typename T> -struct ElementWiseBinaryTester { - tflite::BuiltinOperator kind; - OperandInfo<T> lhs; - OperandInfo<T> rhs; - Vector<T> expected; - - void Test() { - flatbuffers::FlatBufferBuilder builder; - // It is required that the first entry in the buffers of model is always an - // empty buffer. This is so that the default buffer index of zero in Tensor - // will always refer to a valid empty buffer. - Vector<flatbuffers::Offset<tflite::Buffer>> buffers = { - tflite::CreateBuffer(builder, builder.CreateVector({})), - }; - // Create tflite |Buffer| for first input tensor. - buffers.push_back(tflite::CreateBuffer( - builder, builder.CreateVector( - reinterpret_cast<const uint8_t*>(lhs.values.data()), - sizeof(T) * lhs.values.size()))); - // Create tflite |Buffer| for second input tensor. - buffers.push_back(tflite::CreateBuffer( - builder, builder.CreateVector( - reinterpret_cast<const uint8_t*>(rhs.values.data()), - sizeof(T) * rhs.values.size()))); - - // A list of all tflite |Tensor| used in this model. - Vector<flatbuffers::Offset<tflite::Tensor>> tensors; - // Create tflite |Tensor| for first input tensor. - uint32_t lhs_buffer_index = 1; - tensors.emplace_back(tflite::CreateTensor( - builder, builder.CreateVector<int32_t>(lhs.dimensions), lhs.type, - lhs_buffer_index)); - // Create tflite |Tensor| for second input tensor. - uint32_t rhs_buffer_index = 2; - tensors.emplace_back(tflite::CreateTensor( - builder, builder.CreateVector<int32_t>(rhs.dimensions), rhs.type, - rhs_buffer_index)); - // Create tflite |Tensor| for output tensor. - DCHECK(lhs.dimensions == rhs.dimensions); - tensors.emplace_back(tflite::CreateTensor( - builder, builder.CreateVector<int32_t>(lhs.dimensions), lhs.type)); - - // A list of all tflite |Operator| used in this model. - Vector<flatbuffers::Offset<tflite::Operator>> operators; - int32_t lhs_tensor_index = 0, rhs_tensor_index = 1, output_tensor_index = 2; - Vector<int32_t> op_inputs = {lhs_tensor_index, rhs_tensor_index}; - Vector<int32_t> op_outputs = {output_tensor_index}; - operators.emplace_back(tflite::CreateOperator( - builder, 0, builder.CreateVector<int32_t>(op_inputs), - builder.CreateVector<int32_t>(op_outputs))); - - // Create subgraph in the model. - Vector<int32_t> subgraph_outputs = {output_tensor_index}; - flatbuffers::Offset<tflite::SubGraph> subgraph = tflite::CreateSubGraph( - builder, builder.CreateVector(tensors.data(), tensors.size()), - builder.CreateVector<int32_t>({}), - builder.CreateVector<int32_t>(subgraph_outputs), - builder.CreateVector(operators.data(), operators.size())); - - flatbuffers::Offset<flatbuffers::String> description = - builder.CreateString("ElementWise Binary model"); - - Vector<flatbuffers::Offset<tflite::OperatorCode>> operator_codes = { - {tflite::CreateOperatorCode(builder, kind)}}; - flatbuffers::Offset<tflite::Model> model_buffer = tflite::CreateModel( - builder, TFLITE_SCHEMA_VERSION, - builder.CreateVector(operator_codes.data(), operator_codes.size()), - builder.CreateVector(&subgraph, 1), description, - builder.CreateVector(buffers.data(), buffers.size())); - - tflite::FinishModelBuffer(builder, model_buffer); - - // Compute the graph. - std::unique_ptr<tflite::Interpreter> interpreter; - const tflite::Model* model = tflite::GetModel(builder.GetBufferPointer()); - EXPECT_NE(model, nullptr); - TFLiteOpResolver op_resolver; - EXPECT_EQ(tflite::InterpreterBuilder(model, op_resolver)(&interpreter), - kTfLiteOk); - EXPECT_NE(interpreter, nullptr); - EXPECT_EQ(interpreter->AllocateTensors(), kTfLiteOk); - - EXPECT_EQ(interpreter->Invoke(), kTfLiteOk); - - // Get output data after computing the model. - EXPECT_EQ(interpreter->outputs().size(), 1u); - auto* tensor = interpreter->tensor(output_tensor_index); - WTF::Vector<uint8_t> output_data(static_cast<wtf_size_t>(tensor->bytes)); - memcpy(output_data.data(), tensor->data.raw, tensor->bytes); - auto results = GetResult<T>(output_data); - EXPECT_EQ(results, expected); - } -}; - -class MLGraphTestTfLite : public testing::Test { - public: - MLGraphTestTfLite() = default; - ~MLGraphTestTfLite() override = default; -}; - -TEST_F(MLGraphTestTfLite, ElementWiseAddTest) { - { - // Test element-wise add operator for two 1-D tensors. - // The expected results should be the sum of the values of the two input - // tensors, element-wise. - ElementWiseBinaryTester<float>{.kind = tflite::BuiltinOperator_ADD, - .lhs = {.type = tflite::TensorType_FLOAT32, - .dimensions = {2}, - .values = {1.0, 2.0}}, - .rhs = {.type = tflite::TensorType_FLOAT32, - .dimensions = {2}, - .values = {3.0, 4.0}}, - .expected = {4.0, 6.0}} - .Test(); - } -} - -} // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc index f4dc631c4f..b6e5666 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc
@@ -47,8 +47,8 @@ // Use `const void*` here because this HashMap might be used in a worker thread // that doesn't support GC. // -// This map is only used in CreateXnnSubgraphAndRuntime(), who owns references -// to MLOperands, so it's safe to use raw pointers here. +// This map is only used in CreateXnnSubgraph(), who owns references to +// MLOperands, so it's safe to use raw pointers here. // // TODO(crbug.com/1273291): Consider getting GC support in worker threads, so // the safer `HeapHashMap<Member<MLOperand>, uint32_t>` could be used instead. @@ -1206,6 +1206,25 @@ return xnn_status_success; } +// Creates an XNNPACK Runtime object from the Subgraph object. The Runtime +// object is a combination of an execution plan for Subgraph Nodes and a +// memory manager for Subgraph Values and will be used for the accelerated +// executions. This method can run either in a background thread for +// asynchronous graph building or in the caller's thread for synchronous graph +// building. +xnn_status CreateXnnRuntime(const XnnSubgraphPtr& subgraph, + XnnRuntimePtr& out_runtime, + String& error_message) { + TRACE_EVENT("blink", "CreateXnnRuntime"); + CHECK(subgraph); + xnn_runtime_t runtime_ptr = nullptr; + XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE( + xnn_create_runtime(subgraph.get(), &runtime_ptr)); + CHECK(runtime_ptr); + out_runtime.reset(runtime_ptr); + return xnn_status_success; +} + } // namespace // static @@ -1259,73 +1278,117 @@ void MLGraphXnnpack::BuildAsyncImpl(const MLNamedOperands& named_outputs, ScriptPromiseResolver* resolver) { - // The current implementation is not safe to be called in a Web worker thread. - // This is because the `CrossThreadPersistent` doesn't protect the heap owning - // an object from terminating. This would cause UAF (use-after-free) issue, - // when the calling Web worker thread terminates, e.g. user code calls - // `worker.terminate()`, `BuildOnBackgroundThread()` running worker pool - // thread will access these freed objects wrapped in `CrossThreadPersistent`. - // - // TODO(crbug.com/1425370): Fix this issue by avoiding wrapping the GC objects - // by `CrossThreadPersistent` and accessing them on the worker pool thread. CHECK(IsMainThread()); - - // TODO(crbug.com/1273291): Revisit whether the topological sorting should run - // in the worker thread. - auto* toposorted_operators = GetOperatorsInTopologicalOrder(named_outputs); + CHECK(!xnn_context_); worker_pool::PostTask( - FROM_HERE, - CrossThreadBindOnce( - &BuildOnBackgroundThread, WrapCrossThreadPersistent(this), - WrapCrossThreadPersistent( - MakeGarbageCollected<MLNamedOperands>(named_outputs)), - WrapCrossThreadPersistent(toposorted_operators), - WrapCrossThreadPersistent(resolver), resolver_task_runner_)); + FROM_HERE, CrossThreadBindOnce( + &GetSharedXnnpackContextOnBackgroundThread, + MakeCrossThreadHandle(this), + MakeCrossThreadHandle( + MakeGarbageCollected<MLNamedOperands>(named_outputs)), + MakeCrossThreadHandle(resolver), resolver_task_runner_)); } // static -void MLGraphXnnpack::BuildOnBackgroundThread( - CrossThreadPersistent<MLGraphXnnpack> graph, - CrossThreadPersistent<MLNamedOperands> named_outputs, - CrossThreadPersistent<HeapVector<Member<const MLOperator>>> - toposorted_operators, - CrossThreadPersistent<ScriptPromiseResolver> resolver, +void MLGraphXnnpack::GetSharedXnnpackContextOnBackgroundThread( + CrossThreadHandle<MLGraphXnnpack> graph, + CrossThreadHandle<MLNamedOperands> named_outputs, + CrossThreadHandle<ScriptPromiseResolver> resolver, scoped_refptr<base::SequencedTaskRunner> resolver_task_runner) { - DCHECK(!IsMainThread()); - DCHECK(!graph->xnn_context_); - + CHECK(!IsMainThread()); // Get or create the SharedXnnpackContext. String error_message; - xnn_status status = xnn_status_success; - graph->xnn_context_ = SharedXnnpackContext::GetInstance(error_message); - if (!graph->xnn_context_) { - status = xnn_status_uninitialized; - } else { - status = graph->CreateXnnSubgraphAndRuntime( - *named_outputs, *toposorted_operators, error_message); - } - - PostCrossThreadTask(*resolver_task_runner, FROM_HERE, - CrossThreadBindOnce(&MLGraphXnnpack::OnBuildFinished, - std::move(graph), std::move(resolver), - status, std::move(error_message))); + auto xnn_context = SharedXnnpackContext::GetInstance(error_message); + PostCrossThreadTask( + *resolver_task_runner, FROM_HERE, + CrossThreadBindOnce( + &MLGraphXnnpack::OnDidGetSharedXnnpackContext, + MakeUnwrappingCrossThreadHandle(std::move(graph)), + std::move(xnn_context), + MakeUnwrappingCrossThreadHandle(std::move(named_outputs)), + MakeUnwrappingCrossThreadHandle(std::move(resolver)), + std::move(error_message))); } -void MLGraphXnnpack::OnBuildFinished( - CrossThreadPersistent<ScriptPromiseResolver> resolver, - xnn_status status, +void MLGraphXnnpack::OnDidGetSharedXnnpackContext( + scoped_refptr<SharedXnnpackContext> xnn_context, + MLNamedOperands* named_outputs, + ScriptPromiseResolver* resolver, String error_message) { + CHECK(IsMainThread()); + if (!xnn_context) { + resolver->Reject(MakeGarbageCollected<DOMException>( + XnnStatusToDOMExceptionCode(xnn_status_uninitialized), error_message)); + return; + } + + Vector<DataBufferPtr> static_data_buffers; + XnnSubgraphPtr subgraph(nullptr, &xnn_delete_subgraph); + xnn_status status = CreateXnnSubgraph(*named_outputs, subgraph, + static_data_buffers, error_message); if (status != xnn_status_success) { resolver->Reject(MakeGarbageCollected<DOMException>( XnnStatusToDOMExceptionCode(status), error_message)); return; } + // Pass `xnn_context` and `static_data_buffers` forward for XNNPACK Runtime + // creation. If it succeeds, they will be kept by this `MLGraphXnnpack` object + // together with the created Runtime object. + worker_pool::PostTask( + FROM_HERE, CrossThreadBindOnce( + &CreateXnnRuntimeOnBackgroundThread, std::move(subgraph), + std::move(xnn_context), std::move(static_data_buffers), + MakeCrossThreadHandle(this), + MakeCrossThreadHandle(resolver), resolver_task_runner_)); +} + +// static +void MLGraphXnnpack::CreateXnnRuntimeOnBackgroundThread( + XnnSubgraphPtr subgraph, + scoped_refptr<SharedXnnpackContext> xnn_context, + Vector<DataBufferPtr> static_data_buffers, + CrossThreadHandle<MLGraphXnnpack> graph, + CrossThreadHandle<ScriptPromiseResolver> resolver, + scoped_refptr<base::SequencedTaskRunner> resolver_task_runner) { + CHECK(!IsMainThread()); + String error_message; + XnnRuntimePtr runtime(nullptr, &xnn_delete_runtime); + xnn_status status = CreateXnnRuntime(subgraph, runtime, error_message); + PostCrossThreadTask( + *resolver_task_runner, FROM_HERE, + CrossThreadBindOnce(&MLGraphXnnpack::OnDidCreateXnnRuntime, + MakeUnwrappingCrossThreadHandle(std::move(graph)), + status, std::move(runtime), std::move(xnn_context), + std::move(static_data_buffers), + MakeUnwrappingCrossThreadHandle(std::move(resolver)), + std::move(error_message))); +} + +void MLGraphXnnpack::OnDidCreateXnnRuntime( + xnn_status status, + XnnRuntimePtr runtime, + scoped_refptr<SharedXnnpackContext> xnn_context, + Vector<DataBufferPtr> static_data_buffers, + ScriptPromiseResolver* resolver, + String error_message) { + CHECK(IsMainThread()); + if (status != xnn_status_success) { + resolver->Reject(MakeGarbageCollected<DOMException>( + XnnStatusToDOMExceptionCode(status), error_message)); + return; + } + // Transfer the ownership of `runtime`, `xnn_context` and + // `static_data_buffers` to this `MLGraphXnnpack` object for following XNNPACK + // Runtime invocations. + xnn_runtime_ = std::move(runtime); + xnn_context_ = std::move(xnn_context); + static_data_buffers_ = std::move(static_data_buffers); resolver->Resolve(this); } MLGraph* MLGraphXnnpack::BuildSyncImpl(const MLNamedOperands& named_outputs, ExceptionState& exception_state) { - DCHECK(!xnn_context_); + CHECK(!xnn_context_); String error_message; xnn_context_ = SharedXnnpackContext::GetInstance(error_message); if (!xnn_context_) { @@ -1334,9 +1397,16 @@ return nullptr; } - auto* toposorted_operators = GetOperatorsInTopologicalOrder(named_outputs); - xnn_status status = CreateXnnSubgraphAndRuntime( - named_outputs, *toposorted_operators, error_message); + XnnSubgraphPtr subgraph(nullptr, &xnn_delete_subgraph); + xnn_status status = CreateXnnSubgraph(named_outputs, subgraph, + static_data_buffers_, error_message); + if (status != xnn_status_success) { + exception_state.ThrowDOMException(XnnStatusToDOMExceptionCode(status), + error_message); + return nullptr; + } + + status = CreateXnnRuntime(subgraph, xnn_runtime_, error_message); if (status != xnn_status_success) { exception_state.ThrowDOMException(XnnStatusToDOMExceptionCode(status), error_message); @@ -1416,11 +1486,12 @@ } } -xnn_status MLGraphXnnpack::CreateXnnSubgraphAndRuntime( +xnn_status MLGraphXnnpack::CreateXnnSubgraph( const MLNamedOperands& named_outputs, - const HeapVector<Member<const MLOperator>>& toposorted_operators, + XnnSubgraphPtr& out_subgraph, + Vector<DataBufferPtr>& out_static_data_buffers, String& error_message) { - TRACE_EVENT("blink", "MLGraphXnnpack::CreateXnnSubgraphAndRuntime"); + TRACE_EVENT("blink", "MLGraphXnnpack::CreateXnnSubgraph"); // The number of external value IDs that is reserved by XNNPACK Subgraph. Set // its value to the number of graph input and output resources. @@ -1434,17 +1505,11 @@ xnn_subgraph_t subgraph_ptr = nullptr; XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE( xnn_create_subgraph(external_value_ids_num, 0, &subgraph_ptr)); - DCHECK_NE(subgraph_ptr, nullptr); + CHECK(subgraph_ptr); + XnnSubgraphPtr subgraph(subgraph_ptr, &xnn_delete_subgraph); - // XNNPACK Subgraph is an abstract representation of a neural network model. - // The Subgraph Values and Nodes will be defined for the operands and - // operators of a WebNN graph. An XNNPACK Runtime object will be created from - // the Subgraph object. Once constructed, the Runtime object is independent of - // the Subgraph object. The Runtime object is kept for the accelerated - // executions and the Subgraph object will be deleted. - std::unique_ptr<xnn_subgraph, decltype(&xnn_delete_subgraph)> subgraph( - subgraph_ptr, &xnn_delete_subgraph); - + // Holds the static data of XNNPACK Values for MLGraph's constant operands. + Vector<DataBufferPtr> static_data_buffers; // Map the operand to its XNNPACK Value ID. OperandValueIdMap operand_value_id_map; // The ID is used to define an external XNNPACK Value. It should be increased @@ -1469,9 +1534,14 @@ output_external_value_id_map_.insert(name, value_id); } + // TODO(crbug.com/1273291): Revisit whether the topological sorting should run + // in the worker thread. + auto* toposorted_operators = GetOperatorsInTopologicalOrder(named_outputs); + CHECK(toposorted_operators); + // Visit the operators in topological order. For each operator, define XNNPACK // Values for its input and output operands. - for (const auto current_operator : toposorted_operators) { + for (const auto current_operator : *toposorted_operators) { for (const auto& operand : current_operator->Inputs()) { if (operand_value_id_map.Contains(operand.Get())) { // The XNNPACK Value is already defined for this operand, skip it. @@ -1514,7 +1584,7 @@ XNN_CHECK_STATUS(DefineStaticXnnValue(subgraph.get(), operand, data, value_id, error_message)); operand_value_id_map.insert(operand.Get(), value_id); - static_data_buffers_.push_back(std::move(data)); + static_data_buffers.push_back(std::move(data)); break; } case MLOperand::OperandKind::kOutput: @@ -1544,11 +1614,9 @@ operand_value_id_map, error_message)); } - xnn_runtime_t runtime_ptr = nullptr; - XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE( - xnn_create_runtime(subgraph.get(), &runtime_ptr)); - DCHECK_NE(runtime_ptr, nullptr); - xnn_runtime_.reset(runtime_ptr); + // Return the XNNPACK Subgraph and static data buffers if there are no errors. + out_subgraph = std::move(subgraph); + out_static_data_buffers = std::move(static_data_buffers); return xnn_status_success; }
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.h index e9066ea72..a1242e6 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.h +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.h
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/modules/ml/webnn/ml_graph.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h" +#include "third_party/blink/renderer/platform/heap/cross_thread_handle.h" #include "third_party/blink/renderer/platform/heap/cross_thread_persistent.h" #include "third_party/xnnpack/src/include/xnnpack.h" @@ -25,6 +26,11 @@ using DataBufferPtr = std::unique_ptr<uint8_t[]>; +using XnnSubgraphPtr = + std::unique_ptr<xnn_subgraph, decltype(&xnn_delete_subgraph)>; +using XnnRuntimePtr = + std::unique_ptr<xnn_runtime, decltype(&xnn_delete_runtime)>; + class MODULES_EXPORT MLGraphXnnpack final : public MLGraph { public: // Create and build an MLGraphXnnpack object. Resolve the promise with @@ -52,29 +58,66 @@ const Vector<xnn_external_value>& GetXnnExternalValuesTesting() const; private: - // Post the XNNPACK Subgraph and Runtime building to a background thread. + // Build the XNNPACK Subgraph and Runtime asynchronously on a background + // thread. It would execute the following four steps: + // 1) Running `GetSharedXnnpackContextOnBackgroundThread()` on a background + // thread. It may initialize the XNNPACK library, which can be time-consuming. + // 2) Running `OnDidGetSharedXnnpackContext()` on the caller's thread. It + // creates an XNNPACK Subgraph and defines its Nodes by traversing the + // `MLOperator`s and `MLOperand`s of a WebNN graph that are allocated in the + // heap of the caller's thread. + // 3) Running `CreateXnnRuntimeOnBackgroundThread()` on a background thread. + // The creation of XNNPACK Runtime includes graph optimization, operator + // kernel creation and memory allocation and packing that can be + // time-consuming. + // 4) Running `OnDidCreateXnnRuntime()` on the calling thread. It resolves the + // promise with this `MLGraphXnnpack` object if there are no errors. + // + // The sequence of above steps can be illustrated as the following diagram: + // Calling thread background thread + // `BuildAsyncImpl()` + // | + // post task -------> `GetSharedXnnpackContextOnBackgroundThread()` + // | + // `OnDidGetSharedXnnpackContext()` <----------post task + // | + // post task ------------> `CreateXnnRuntimeOnBackgroundThread()` + // | + // `OnDidCreateXnnRuntime() <-----------------post task void BuildAsyncImpl(const MLNamedOperands& named_outputs, ScriptPromiseResolver* resolver) override; - // Build the XNNPACK Subgraph and Runtime off the main thread. - static void BuildOnBackgroundThread( - CrossThreadPersistent<MLGraphXnnpack> graph, - CrossThreadPersistent<MLNamedOperands> named_outputs, - CrossThreadPersistent<HeapVector<Member<const MLOperator>>> - toposorted_operators, - CrossThreadPersistent<ScriptPromiseResolver> resolver, + static void GetSharedXnnpackContextOnBackgroundThread( + CrossThreadHandle<MLGraphXnnpack> graph, + CrossThreadHandle<MLNamedOperands> named_outputs, + CrossThreadHandle<ScriptPromiseResolver> resolver, scoped_refptr<base::SequencedTaskRunner> resolver_task_runner); - // Resolve the promise on the main thread after finish building the XNNPACK - // Subgraph and Runtime. - void OnBuildFinished(CrossThreadPersistent<ScriptPromiseResolver> resolver, - xnn_status status, - String error_message = String()); + void OnDidGetSharedXnnpackContext( + scoped_refptr<SharedXnnpackContext> xnn_context, + MLNamedOperands* named_outputs, + ScriptPromiseResolver* resolver, + String error_message = String()); - // Build the XNNPACK Subgraph synchronously in the caller's thread. If the - // XNNPACK Subgraph builds successfully, it should return this MLGraphXnnpack - // object. Otherwise, it returns a nullptr and throw a DOMException - // accordingly. + static void CreateXnnRuntimeOnBackgroundThread( + XnnSubgraphPtr subgraph, + scoped_refptr<SharedXnnpackContext> xnn_context, + Vector<DataBufferPtr> static_data_buffers, + CrossThreadHandle<MLGraphXnnpack> graph, + CrossThreadHandle<ScriptPromiseResolver> resolver, + scoped_refptr<base::SequencedTaskRunner> resolver_task_runner); + + void OnDidCreateXnnRuntime(xnn_status status, + XnnRuntimePtr runtime, + scoped_refptr<SharedXnnpackContext> xnn_context, + Vector<DataBufferPtr> static_data_buffers, + ScriptPromiseResolver* resolver, + String error_message = String()); + + // Build the XNNPACK Subgraph and Runtime synchronously in the caller's + // thread. If the XNNPACK Subgraph and Runtime build successfully, it should + // return this `MLGraphXnnpack` object. Otherwise, it returns a nullptr and + // throw a DOMException accordingly. MLGraph* BuildSyncImpl(const MLNamedOperands& named_outputs, ExceptionState& exception_state) override; @@ -105,18 +148,19 @@ const MLNamedArrayBufferViews& outputs, ExceptionState& exception_state) override; - // This method firstly creates an XNNPACK Subgraph object and defines Subgraph - // Nodes and Values for the operators and operands of a WebNN graph. Then it - // creates an XNNPACK Runtime object from the Subgraph object. The Runtime - // object is a combination of an execution plan for Subgraph Nodes and a - // memory manager for Subgraph Values and will be used for the accelerated - // executions. This method can run either in a background thread for - // asynchronous graph building or in the caller's thread for synchronous graph - // building. - xnn_status CreateXnnSubgraphAndRuntime( - const MLNamedOperands& named_outputs, - const HeapVector<Member<const MLOperator>>& toposorted_operators, - String& error_message); + // XNNPACK Subgraph is an abstract representation of a neural network model. + // This method first sorts the MLOperators by searching from `named_outputs` + // and then creates an XNNPACK Subgraph object and defines Subgraph Nodes and + // Values from the sorted operators. The output XNNPACK Subgraph + // `out_subgraph` will be used to create an XNNPACK Runtime. Because the + // static data buffers of XNNPACK Values should outlive Subgraph and Runtime + // using them, they are returned in `out_static_data_buffers`. This method + // must be called on the thread owning this `MLGraphXnnpack` and + // `named_outputs`. + xnn_status CreateXnnSubgraph(const MLNamedOperands& named_outputs, + XnnSubgraphPtr& out_subgraph, + Vector<DataBufferPtr>& out_static_data_buffers, + String& error_message); // This method creates the xnn_external_value vector from named input and // output array buffer views. The xnn_external_value vector is used to set up @@ -173,8 +217,7 @@ Vector<xnn_external_value> xnn_external_values_; // The XNNPACK Runtime object for the accelerated executions. - std::unique_ptr<xnn_runtime, decltype(&xnn_delete_runtime)> xnn_runtime_{ - nullptr, &xnn_delete_runtime}; + XnnRuntimePtr xnn_runtime_{nullptr, &xnn_delete_runtime}; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/presentation/presentation_connection.cc b/third_party/blink/renderer/modules/presentation/presentation_connection.cc index e721ab4d..28480f95 100644 --- a/third_party/blink/renderer/modules/presentation/presentation_connection.cc +++ b/third_party/blink/renderer/modules/presentation/presentation_connection.cc
@@ -12,9 +12,8 @@ #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/events/message_event.h" #include "third_party/blink/renderer/core/fileapi/file_error.h" -#include "third_party/blink/renderer/core/fileapi/file_read_type.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h" @@ -119,35 +118,33 @@ class PresentationConnection::BlobLoader final : public GarbageCollected<PresentationConnection::BlobLoader>, - public FileReaderLoaderClient { + public FileReaderAccumulator { public: BlobLoader(scoped_refptr<BlobDataHandle> blob_data_handle, PresentationConnection* presentation_connection, scoped_refptr<base::SingleThreadTaskRunner> task_runner) : presentation_connection_(presentation_connection), - loader_(MakeGarbageCollected<FileReaderLoader>( - FileReadType::kReadAsArrayBuffer, - this, - std::move(task_runner))) { + loader_( + MakeGarbageCollected<FileReaderLoader>(this, + std::move(task_runner))) { loader_->Start(std::move(blob_data_handle)); } ~BlobLoader() override = default; - // FileReaderLoaderClient functions. - void DidStartLoading() override {} - void DidReceiveData() override {} - void DidFinishLoading() override { - presentation_connection_->DidFinishLoadingBlob( - loader_->TakeContents().AsDOMArrayBuffer()); + // FileReaderAccumulator functions. + void DidFinishLoading(FileReaderData contents) override { + auto* buffer = std::move(contents).AsDOMArrayBuffer(); + presentation_connection_->DidFinishLoadingBlob(buffer); } void DidFail(FileErrorCode error_code) override { + FileReaderAccumulator::DidFail(error_code); presentation_connection_->DidFailLoadingBlob(error_code); } void Cancel() { loader_->Cancel(); } void Trace(Visitor* visitor) const override { - FileReaderLoaderClient::Trace(visitor); + FileReaderAccumulator::Trace(visitor); visitor->Trace(presentation_connection_); visitor->Trace(loader_); }
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc index a99ca90..7a543d0 100644 --- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc +++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
@@ -52,9 +52,8 @@ #include "third_party/blink/renderer/bindings/core/v8/capture_source_location.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fileapi/file_error.h" -#include "third_party/blink/renderer/core/fileapi/file_read_type.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_client.h" #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" -#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/loader/base_fetch_context.h" @@ -130,7 +129,7 @@ class WebSocketChannelImpl::BlobLoader final : public GarbageCollected<WebSocketChannelImpl::BlobLoader>, - public FileReaderLoaderClient { + public FileReaderClient { public: BlobLoader(scoped_refptr<BlobDataHandle>, WebSocketChannelImpl*, @@ -139,14 +138,14 @@ void Cancel(); - // FileReaderLoaderClient functions. - void DidStartLoading() override; - void DidReceiveDataForClient(const char* data, unsigned data_length) override; + // FileReaderClient functions. + FileErrorCode DidStartLoading(uint64_t, uint64_t) override; + FileErrorCode DidReceiveData(const char* data, unsigned data_length) override; void DidFinishLoading() override; void DidFail(FileErrorCode) override; void Trace(Visitor* visitor) const override { - FileReaderLoaderClient::Trace(visitor); + FileReaderClient::Trace(visitor); visitor->Trace(channel_); visitor->Trace(loader_); } @@ -159,6 +158,8 @@ MessageData data_; size_t size_ = 0; size_t offset_ = 0; + + bool blob_too_large_ = false; }; WebSocketChannelImpl::BlobLoader::BlobLoader( @@ -166,10 +167,8 @@ WebSocketChannelImpl* channel, scoped_refptr<base::SingleThreadTaskRunner> task_runner) : channel_(channel), - loader_( - MakeGarbageCollected<FileReaderLoader>(FileReadType::kReadByClient, - this, - std::move(task_runner))) { + loader_(MakeGarbageCollected<FileReaderLoader>(this, + std::move(task_runner))) { loader_->Start(std::move(blob_data_handle)); } @@ -179,29 +178,30 @@ data_ = nullptr; } -void WebSocketChannelImpl::BlobLoader::DidStartLoading() { +FileErrorCode WebSocketChannelImpl::BlobLoader::DidStartLoading(uint64_t, + uint64_t) { const absl::optional<uint64_t> size = loader_->TotalBytes(); DCHECK(size); if (size.value() > std::numeric_limits<size_t>::max()) { - loader_->Cancel(); - loader_ = nullptr; - channel_->BlobTooLarge(); - return; + blob_too_large_ = true; + return FileErrorCode::kAbortErr; } size_ = static_cast<size_t>(size.value()); data_ = WebSocketChannelImpl::CreateMessageData( channel_->execution_context_->GetIsolate(), size_); + return FileErrorCode::kOK; } -void WebSocketChannelImpl::BlobLoader::DidReceiveDataForClient( +FileErrorCode WebSocketChannelImpl::BlobLoader::DidReceiveData( const char* data, unsigned data_length) { const size_t data_to_copy = std::min(size_ - offset_, static_cast<size_t>(data_length)); if (!data_to_copy) - return; + return FileErrorCode::kOK; memcpy(data_.get() + offset_, data, data_to_copy); offset_ += data_to_copy; + return FileErrorCode::kOK; } void WebSocketChannelImpl::BlobLoader::DidFinishLoading() { @@ -212,6 +212,10 @@ } void WebSocketChannelImpl::BlobLoader::DidFail(FileErrorCode error_code) { + if (error_code == FileErrorCode::kAbortErr && blob_too_large_) { + blob_too_large_ = false; + channel_->BlobTooLarge(); + } channel_->DidFailLoadingBlob(error_code); loader_ = nullptr; data_ = nullptr;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index 99cc14a..7c7e303 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -2100,21 +2100,17 @@ ++subresource_load_metrics_ .number_of_subresource_loads_handled_by_service_worker; } - - if (IsControlledByServiceWorker() == - mojom::blink::ControllerServiceWorkerMode::kControlled) { - if (resource->GetResponse().WasFetchedViaServiceWorker()) { - base::UmaHistogramEnumeration("ServiceWorker.Subresource.Handled.Type", - resource->GetType()); - } else { - base::UmaHistogramEnumeration( - "ServiceWorker.Subresource.Fallbacked.Type", resource->GetType()); - } - } } if (IsControlledByServiceWorker() == mojom::blink::ControllerServiceWorkerMode::kControlled) { + if (resource->GetResponse().WasFetchedViaServiceWorker()) { + base::UmaHistogramEnumeration("ServiceWorker.Subresource.Handled.Type2", + resource->GetType()); + } else { + base::UmaHistogramEnumeration( + "ServiceWorker.Subresource.Fallbacked.Type2", resource->GetType()); + } UpdateServiceWorkerSubresourceMetrics( resource->GetType(), resource->GetResponse().WasFetchedViaServiceWorker());
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index 269f1ba..dfee0b6 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -1173,8 +1173,6 @@ 'media::VideoFrame', 'viz::RasterContextProvider', 'viz::ReleaseCallback', - 'viz::ResourceFormat', - 'viz::ResourceFormatToClosestSkColorType', 'viz::SinglePlaneFormat', 'viz::ToClosestSkColorType', 'viz::TransferableResource', @@ -1407,7 +1405,6 @@ 'gpu::SyncToken', 'viz::RasterContextProvider', 'viz::ReleaseCallback', - 'viz::ResourceFormat', 'media::.+', 'libyuv::.+', ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 0536829..99e4cb5 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -858,6 +858,7 @@ crbug.com/1044742 external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-filter.html [ Failure ] crbug.com/1044742 external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-stacking-context-001.html [ Failure ] crbug.com/1044742 [ Mac10.13 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure ] +crbug.com/1044742 [ Mac10.14 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure Crash ] crbug.com/1044742 [ Mac10.15 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure ] crbug.com/1044742 [ Mac11 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure ] crbug.com/1044742 [ Mac11-arm64 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Failure ] @@ -1191,6 +1192,10 @@ crbug.com/807497 external/wpt/css/css-flexbox/anonymous-flex-item-005.html [ Failure ] crbug.com/1311206 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-038.html [ Failure ] +crbug.com/1228023 external/wpt/css/css-flexbox/justify-content-007.html [ Failure ] +crbug.com/1306037 external/wpt/css/css-flexbox/abspos/dynamic-align-self-001.html [ Failure ] + + crbug.com/1299946 [ Mac10.14 Release ] external/wpt/css/css-sizing/min-content-negative-margin-crash.html [ Pass Timeout ] crbug.com/1299946 [ Mac10.15 Release ] external/wpt/css/css-sizing/min-content-negative-margin-crash.html [ Pass Timeout ] crbug.com/1299946 [ Mac11 Release ] external/wpt/css/css-sizing/min-content-negative-margin-crash.html [ Pass Timeout ] @@ -2718,6 +2723,7 @@ crbug.com/1088475 [ Fuchsia ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] crbug.com/1088475 [ Linux ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] crbug.com/1088475 [ Mac10.13 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] +crbug.com/1088475 [ Mac10.14 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Crash ] crbug.com/1088475 [ Mac10.15 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] crbug.com/1088475 [ Mac11 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] crbug.com/1088475 [ Mac11-arm64 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Failure Pass Timeout ] @@ -2961,7 +2967,6 @@ crbug.com/626703 [ Linux ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries.html [ Failure ] crbug.com/626703 [ Mac10.14 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries.html [ Failure ] crbug.com/626703 [ Mac10.14 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video-sibling.html [ Crash ] -crbug.com/626703 [ Mac10.14 ] external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-video.html [ Crash ] crbug.com/626703 [ Mac10.14 ] external/wpt/html/cross-origin-opener-policy/resource-popup.https.html [ Crash ] crbug.com/626703 [ Mac10.14 ] external/wpt/html/semantics/embedded-content/media-elements/preserves-pitch.html [ Crash Timeout ] crbug.com/1232504 [ Mac10.14 ] external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay-hidden.optional.html [ Crash Timeout ] @@ -3027,7 +3032,6 @@ crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/simplecall.https.html [ Crash ] crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/simulcast/vp8.https.html [ Crash ] crbug.com/626703 [ Mac10.14 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/audio_has_no_subtitles.html [ Crash ] -crbug.com/626703 [ Mac10.14 ] external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html [ Crash ] crbug.com/626703 [ Mac10.14 ] virtual/feature-policy-permissions/external/wpt/mediacapture-streams/MediaStream-finished-add.https.html [ Crash ] crbug.com/626703 [ Mac10.14 ] wpt_internal/webcodecs/annexb_decoding.https.any.html [ Crash ] crbug.com/626703 [ Mac10.14 ] wpt_internal/webcodecs/annexb_decoding.https.any.worker.html [ Crash ] @@ -6856,8 +6860,12 @@ # Fails on newer Ubuntu versions. crbug.com/1432272 [ Linux ] virtual/unsafe_webgpu/regress/regress-1104580.html [ Crash Pass ] +# TODO(crbug.com/1432448, crbug.com/1273291): Re-enable or move off waterfall. +crbug.com/1432448 external/wpt/webnn/* [ Failure ] + # Sheriff 2023-04-12 crbug.com/1432666 [ Mac ] external/wpt/mediacapture-record/passthrough/MediaRecorder-passthrough.https.html [ Failure Pass ] # Sheriff 2023-04-13 crbug.com/1432763 [ Linux ] external/wpt/fetch/metadata/generated/element-picture.https.sub.html [ Pass Timeout ] +crbug.com/1432812 [ Win11 ] fast/backgrounds/repeat/negative-offset-repeat-transformed.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/abspos/dynamic-align-self-001.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/abspos/dynamic-align-self-001.html new file mode 100644 index 0000000..208c006d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/abspos/dynamic-align-self-001.html
@@ -0,0 +1,46 @@ +<!DOCTYPE html> +<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org"> +<link rel="help" href="https://crbug.com/1306037"> +<link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> +<meta name="assert" + content="Abspos child of a flexbox moves after script changes its alignment."> +<style> + #reference-overlapped-red { + position: absolute; + background-color: red; + width: 100px; + height: 100px; + z-index: -1; + } + + #parent { + position: relative; + display: flex; + width: 200px; + height: 200px; + } + + #child { + display: flex; + position: absolute; + width: 100px; + height: 100px; + background-color: green; + align-self: end; + } + +</style> + +<p>Test passes if there is a filled green square and <strong>no red</strong>. +</p> + +<div id=reference-overlapped-red></div> + +<div id="parent"> + <div id="child"></div> +</div> + +<script> + document.body.offsetTop; + child.style.alignSelf = 'start'; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/fieldset-as-container-justify-center.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/fieldset-as-container-justify-center.tentative.html new file mode 100644 index 0000000..a1d7564 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/fieldset-as-container-justify-center.tentative.html
@@ -0,0 +1,46 @@ +<!DOCTYPE html> +<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org"> +<link rel="help" href="https://crbug.com/1229458"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/8690"> +<link rel="help" href="https://github.com/whatwg/html/issues/9123"> +<link rel="help" + href="https://html.spec.whatwg.org/multipage/rendering.html#anonymous-fieldset-content-box"> +<meta name="assert" + content="justify-content: center is ignored in a column flexbox fieldset when the anonymous fieldset content box has no height or min-height."> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<style> + fieldset { + display: flex; + flex-flow: column; + justify-content: center; + align-items: center; + width: 200px; + min-height: 200px; + padding: 0px; + border: 1px solid; + position: relative; + } + + .item { + height: 100px; + width: 100px; + background: orange; + } + +</style> +<p>Pass Condition: orange square is at top of black square.<br> + Safari 16.4 and Firefox 111 fail -- orange box is vertically centered as if + the anonymous fieldset content box and the fieldset were the same box. +</p> + +<fieldset> + <div class="item" data-offset-y="0"></div> +</fieldset> + +<script> + checkLayout('.item'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-aspect-ratio-img-row-017.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-aspect-ratio-img-row-017.html new file mode 100644 index 0000000..b2408159 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-aspect-ratio-img-row-017.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1700474"> +<link rel="help" href="https://crbug.com/1337056"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht" /> +<meta name="assert" + content="specified size suggestion obeys item's resolvable % main size"> + +<style> + #reference-overlapped-red { + position: absolute; + background-color: red; + width: 100px; + height: 100px; + z-index: -1; + } + +</style> + +<p>Test passes if there is a filled green square and <strong>no red</strong>. +</p> + +<div id="reference-overlapped-red"></div> + +<div style="display: flex; width: 100px;"> + <img src="support/100x100-green.png" style="width: 100%; flex: 0 0 10px;"> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/grandchild-span-height.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/grandchild-span-height.html new file mode 100644 index 0000000..c087edb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/grandchild-span-height.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta name="flags" content="asis" /> +<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1601626"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> + +<style> + #reference-overlapped-red { + position: absolute; + background-color: red; + width: 100px; + height: 100px; + z-index: -1; + } + +</style> +<p>Test passes if there is a filled green square and <strong>no red</strong>. +</p> + +<div id=reference-overlapped-red></div> + +<!-- Firefox 111 gives the green square too much height. 111px on my system. --> + +<div style="display: flex;"> + <div style="background-color: green; line-height: 10px;"> + <span style="margin-left: 1px"> + <div style="display:inline-block; width: 99px; height: 100px"></div> + <!-- the html comments are necessary to trigger the bug --> + <!-- --> + </span> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/grid-flex-item-007.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/grid-flex-item-007.html new file mode 100644 index 0000000..bdea17d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/grid-flex-item-007.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org"> +<link rel="help" + href="https://drafts.csswg.org/css-flexbox-1/#valdef-flex-direction-column"> +<link rel="help" href="https://webkit.org/b/226522"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<meta name="assert" + content="Column flexboxes with indefinite heights don't mess up positioning of descendant grid items."> + +<style> + #reference-overlapped-red { + position: absolute; + background-color: red; + width: 100px; + height: 100px; + z-index: -1; + } + +</style> +<p>Test passes if there is a filled green square and <strong>no red</strong>. +</p> +<div id=reference-overlapped-red></div> + +<body style="height: 400px;"> + <div style="display: flex; flex-direction: column;"> + <div style="display: grid; align-items: center; height: 100%;"> + <div style="width:100px; height: 100px; background: green;"></div> + </div> + </div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/justify-content-007.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/justify-content-007.html new file mode 100644 index 0000000..2ce9177 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/justify-content-007.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org"> +<link rel="help" + href="https://drafts.csswg.org/css-flexbox/#justify-content-property"> +<link rel="help" href="https://crbug.com/1228023"> +<meta name="assert" + content="Wrapped item obeys justify-content:center when the item wraps because the container has max-height."> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> + +<style> + .flexitem { + width: 100px; + } + +</style> + +Pass condition: orange square is vertically centered in the black box.<br> +Chrome 112 and Safari 16.4 fail. Firefox 111 passes. +<div + style="display: flex; flex-flow: column wrap; max-height: 200px; justify-content: center; align-content: start; border: 2px solid; position: relative;"> + <div class=flexitem style="background: blue; height: 200px;"></div> + <div class=flexitem style="background: orange; height: 100px;" + data-offset-y=50></div> +</div> + +<script> + checkLayout('.flexitem + .flexitem'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/table-as-flex-item-max-content.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/table-as-flex-item-max-content.html new file mode 100644 index 0000000..c7316aa --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/table-as-flex-item-max-content.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org"> +<link rel="help" + href="https://drafts.csswg.org/css-flexbox/#intrinsic-cross-sizes"> +<link rel="help" href="https://webkit.org/b/253922"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<meta name="assert" + content="A table's max-content width is used for its parent flexbox's max-content calculation. Safari 16.4 uses min-content width."> + +<style> + #reference-overlapped-red { + position: absolute; + background-color: red; + width: 100px; + height: 100px; + z-index: -1; + } + + .inline-block { + float: left; + width: 50px; + } + +</style> +<p>Test passes if there is a filled green square and <strong>no red</strong>. +</p> + +<div id=reference-overlapped-red></div> +<div + style="display: flex; flex-direction: column; height: 100px; width: max-content; background-color: green;"> + <div style="display: table"> + <div style="display: table-cell"> + <div class="inline-block"></div> + <div class="inline-block"></div> + </div> + </div> +</div>
diff --git a/third_party/eigen3/README.chromium b/third_party/eigen3/README.chromium index b2d088f..8857ef0 100644 --- a/third_party/eigen3/README.chromium +++ b/third_party/eigen3/README.chromium
@@ -1,8 +1,8 @@ Name: Eigen Short Name: eigen3 URL: http://eigen.tuxfamily.org/ -Version: 33e206f714d16f03cd31fd7bf1aa9d3a0ef66a5e -Date: 2023/03/31 +Version: b0eded878d5d162d61583a286c0d8a45406ad1bc +Date: 2023/04/12 License: MPL 2 License File: LICENSE Security Critical: Yes
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium index 762386b..01c0de0d 100644 --- a/third_party/nearby/README.chromium +++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@ Name: Nearby Connections Library Short Name: Nearby URL: https://github.com/google/nearby -Version: 28f7498580d586ccd0855deaf45057f0498cf5a3 +Version: 37225fab5abf6d897e16c43082b64ed7bdd0fc3c License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/opus/README.chromium b/third_party/opus/README.chromium index bc9622b3..2412031 100644 --- a/third_party/opus/README.chromium +++ b/third_party/opus/README.chromium
@@ -1,6 +1,6 @@ Name: opus URL: https://gitlab.xiph.org/xiph/opus -Version: ab04fbb1 +Version: 8cf872a1 License: BSD License File: src/COPYING Security Critical: yes
diff --git a/third_party/opus/src/celt/kiss_fft.h b/third_party/opus/src/celt/kiss_fft.h index bffa2bf..1cd9d6f 100644 --- a/third_party/opus/src/celt/kiss_fft.h +++ b/third_party/opus/src/celt/kiss_fft.h
@@ -52,6 +52,10 @@ # define kiss_fft_scalar opus_int32 # define kiss_twiddle_scalar opus_int16 +/* Some 32-bit CPUs would load/store a kiss_twiddle_cpx with a single memory + * access, and could benefit from additional alignment. + */ +#define KISS_TWIDDLE_CPX_ALIGNMENT (sizeof(opus_int32)) #else # ifndef kiss_fft_scalar @@ -62,6 +66,13 @@ # endif #endif +#if defined(__GNUC__) && defined(KISS_TWIDDLE_CPX_ALIGNMENT) +#define KISS_TWIDDLE_CPX_ALIGNED \ + __attribute__((aligned(KISS_TWIDDLE_CPX_ALIGNMENT))) +#else +#define KISS_TWIDDLE_CPX_ALIGNED +#endif + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; @@ -70,7 +81,7 @@ typedef struct { kiss_twiddle_scalar r; kiss_twiddle_scalar i; -}kiss_twiddle_cpx; +} KISS_TWIDDLE_CPX_ALIGNED kiss_twiddle_cpx; #define MAXFACTORS 8 /* e.g. an fft of length 128 has 4 factors
diff --git a/third_party/opus/src/opus.m4 b/third_party/opus/src/opus.m4 index 47f5ec4..263470d 100644 --- a/third_party/opus/src/opus.m4 +++ b/third_party/opus/src/opus.m4
@@ -63,7 +63,7 @@ #include <string.h> #include <opus.h> -int main () +int main (void) { system("touch conf.opustest"); return 0;
diff --git a/third_party/opus/src/silk/MacroDebug.h b/third_party/opus/src/silk/MacroDebug.h index aceeef7e..3110da9a 100644 --- a/third_party/opus/src/silk/MacroDebug.h +++ b/third_party/opus/src/silk/MacroDebug.h
@@ -829,7 +829,7 @@ static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND_(opus_int32 a, opus_int32 shift, char *file, int line){ opus_int32 ret; ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; - /* the marco definition can't handle a shift of zero */ + /* the macro definition can't handle a shift of zero */ if ( (shift <= 0) || (shift>31) || ((opus_int64)ret != ((opus_int64)a + ((opus_int64)1 << (shift - 1))) >> shift) ) { fprintf (stderr, "silk_RSHIFT_ROUND(%d, %d) in %s: line %d\n", a, shift, file, line); @@ -844,7 +844,7 @@ #define silk_RSHIFT_ROUND64(a,b) silk_RSHIFT_ROUND64_((a), (b), __FILE__, __LINE__) static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64_(opus_int64 a, opus_int32 shift, char *file, int line){ opus_int64 ret; - /* the marco definition can't handle a shift of zero */ + /* the macro definition can't handle a shift of zero */ if ( (shift <= 0) || (shift>=64) ) { fprintf (stderr, "silk_RSHIFT_ROUND64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line);
diff --git a/third_party/opus/src/silk/fixed/LTP_scale_ctrl_FIX.c b/third_party/opus/src/silk/fixed/LTP_scale_ctrl_FIX.c index b3afb70..db1016e 100644 --- a/third_party/opus/src/silk/fixed/LTP_scale_ctrl_FIX.c +++ b/third_party/opus/src/silk/fixed/LTP_scale_ctrl_FIX.c
@@ -42,7 +42,7 @@ if( condCoding == CODE_INDEPENDENTLY ) { /* Only scale if first frame in packet */ - round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + round_loss = psEnc->sCmn.PacketLoss_perc * psEnc->sCmn.nFramesPerPacket; if ( psEnc->sCmn.LBRR_flag ) { /* LBRR reduces the effective loss. In practice, it does not square the loss because losses aren't independent, but that still seems to work best. We also never go below 2%. */
diff --git a/third_party/opus/src/silk/float/LTP_scale_ctrl_FLP.c b/third_party/opus/src/silk/float/LTP_scale_ctrl_FLP.c index 1fed099..6f30ff0 100644 --- a/third_party/opus/src/silk/float/LTP_scale_ctrl_FLP.c +++ b/third_party/opus/src/silk/float/LTP_scale_ctrl_FLP.c
@@ -41,7 +41,7 @@ if( condCoding == CODE_INDEPENDENTLY ) { /* Only scale if first frame in packet */ - round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + round_loss = psEnc->sCmn.PacketLoss_perc * psEnc->sCmn.nFramesPerPacket; if ( psEnc->sCmn.LBRR_flag ) { /* LBRR reduces the effective loss. In practice, it does not square the loss because losses aren't independent, but that still seems to work best. We also never go below 2%. */
diff --git a/third_party/opus/src/win32/genversion.bat b/third_party/opus/src/win32/genversion.bat index aea5573..1def746 100755 --- a/third_party/opus/src/win32/genversion.bat +++ b/third_party/opus/src/win32/genversion.bat
@@ -1,37 +1,37 @@ -@echo off - -setlocal enableextensions enabledelayedexpansion - -for /f %%v in ('cd "%~dp0.." ^&^& git status ^>NUL 2^>NUL ^&^& git describe --tags --match "v*" --dirty 2^>NUL') do set version=%%v - -if not "%version%"=="" set version=!version:~1! && goto :gotversion - -if exist "%~dp0..\package_version" goto :getversion - -echo Git cannot be found, nor can package_version. Generating unknown version. - -set version=unknown - -goto :gotversion - -:getversion - -for /f "delims== tokens=2" %%v in (%~dps0..\package_version) do set version=%%v -set version=!version:"=! - -:gotversion - -set version=!version: =! -set version_out=#define %~2 "%version%" - -echo %version_out%> "%~1_temp" - -echo n | comp "%~1_temp" "%~1" > NUL 2> NUL - -if not errorlevel 1 goto exit - -copy /y "%~1_temp" "%~1" - -:exit - -del "%~1_temp" +@echo off + +setlocal enableextensions enabledelayedexpansion + +for /f %%v in ('cd "%~dp0.." ^&^& git status ^>NUL 2^>NUL ^&^& git describe --tags --match "v*" --dirty 2^>NUL') do set version=%%v + +if not "%version%"=="" set version=!version:~1! && goto :gotversion + +if exist "%~dp0..\package_version" goto :getversion + +echo Git cannot be found, nor can package_version. Generating unknown version. + +set version=unknown + +goto :gotversion + +:getversion + +for /f "delims== tokens=2" %%v in (%~dps0..\package_version) do set version=%%v +set version=!version:"=! + +:gotversion + +set version=!version: =! +set version_out=#define %~2 "%version%" + +echo %version_out%> "%~1_temp" + +echo n | comp "%~1_temp" "%~1" > NUL 2> NUL + +if not errorlevel 1 goto exit + +copy /y "%~1_temp" "%~1" + +:exit + +del "%~1_temp"
diff --git a/third_party/tflite/README.chromium b/third_party/tflite/README.chromium index c0f802df..81afe07 100644 --- a/third_party/tflite/README.chromium +++ b/third_party/tflite/README.chromium
@@ -1,8 +1,8 @@ Name: TensorFlow Lite Short Name: tflite URL: https://github.com/tensorflow/tensorflow -Version: 364fd6c6121aa3fef8d5ba1909a16664db5fe4c7 -Date: 2023/03/31 +Version: ca3bc50b524364bb4d5e587f9de6e339f8fcc485 +Date: 2023/04/12 License: Apache 2.0 License File: LICENSE Security Critical: Yes
diff --git a/third_party/xnnpack/BUILD.gn b/third_party/xnnpack/BUILD.gn index 738292c08..623c47b 100644 --- a/third_party/xnnpack/BUILD.gn +++ b/third_party/xnnpack/BUILD.gn
@@ -50,12 +50,24 @@ sources = [ "src/src/allocator.c", + "src/src/argmaxpool-config.c", + "src/src/avgpool-config.c", "src/src/binary-elementwise-config.c", "src/src/cache.c", + "src/src/conv-hwc2chw-config.c", + "src/src/dwconv-config.c", + "src/src/dwconv2d-chw-config.c", + "src/src/gavgpool-config.c", + "src/src/gavgpool-cw-config.c", + "src/src/gemm-config.c", "src/src/hardware-config.c", + "src/src/ibilinear-chw-config.c", + "src/src/ibilinear-config.c", "src/src/indirection.c", "src/src/init.c", "src/src/log.c", + "src/src/lut32norm-config.c", + "src/src/maxpool-config.c", "src/src/memory-planner.c", "src/src/memory.c", "src/src/microkernel-utils.c", @@ -67,14 +79,22 @@ "src/src/operator-utils.c", "src/src/packing.c", "src/src/params.c", + "src/src/pavgpool-config.c", + "src/src/prelu-config.c", + "src/src/raddstoreexpminusmax-config.c", + "src/src/rmax-config.c", "src/src/runtime.c", + "src/src/spmm-config.c", "src/src/subgraph.c", "src/src/tensor.c", "src/src/transpose-config.c", "src/src/unary-elementwise-config.c", + "src/src/unpool-config.c", + "src/src/vmulcaddc-config.c", "src/src/x8-lut-config.c", "src/src/xx-fill-config.c", "src/src/xx-pad-config.c", + "src/src/zip-config.c", ] deps = [ @@ -414,6 +434,7 @@ "src/src/operators/convolution-nchw.c", "src/src/operators/convolution-nhwc.c", "src/src/operators/deconvolution-nhwc.c", + "src/src/operators/dynamic-fully-connected-nc.c", "src/src/operators/fully-connected-nc.c", "src/src/operators/global-average-pooling-ncw.c", "src/src/operators/global-average-pooling-nwc.c",
diff --git a/third_party/xnnpack/README.chromium b/third_party/xnnpack/README.chromium index ac5d3d0..88107538 100644 --- a/third_party/xnnpack/README.chromium +++ b/third_party/xnnpack/README.chromium
@@ -1,8 +1,8 @@ Name: XNNPACK Short Name: xnnpack URL: https://github.com/google/xnnpack -Version: 7adae8e6ded8fff33d92212ca1028d2419cd34d4 -Date: 2023/03/31 +Version: b9d4073a6913891ce9cbd8965c8d506075d2a45a +Date: 2023/04/12 License: BSD License File: src/LICENSE Security Critical: Yes
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 8e11367..c5544856 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -403,12 +403,15 @@ 'android-backuprefptr-arm64-fyi-rel': 'release_trybot_backuprefptr_arm64_reclient', 'android-fieldtrial-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_reclient', 'android-perfetto-rel': 'perfetto_release_bot_reclient_android', - # Keep in sync with android-pie-arm64-rel, but with reclient. - 'build-perf-android': 'android_release_trybot_arm64_webview_monochrome_expectations_fastbuild_reclient', - # Keep in sync with linux-rel, but with reclient. + # Keep in sync with android-pie-arm64-rel + 'build-perf-android': 'android_release_bot_minimal_symbols_arm64_webview_monochrome_reclient', + 'build-perf-android-siso': 'android_release_bot_minimal_symbols_arm64_webview_monochrome_siso', + # Keep in sync with linux-rel 'build-perf-linux': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_code_coverage_do_typecheck_reclient', - # Keep in sync with win10_chromium_x64_rel_ng, but with reclient. + 'build-perf-linux-siso': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_code_coverage_do_typecheck_siso', + # Keep in sync with win10_chromium_x64_rel_ng 'build-perf-windows': 'gpu_tests_release_trybot_resource_allowlisting_code_coverage_reclient', + 'build-perf-windows-siso': 'gpu_tests_release_trybot_resource_allowlisting_code_coverage_siso', # TODO(crbug.com/1235218): remove after the migration. 'chromeos-amd64-generic-rel (reclient compare)': 'chromeos_amd64-generic-vm_use_fake_dbus_clients_reclient', 'chromeos-amd64-generic-rel (reclient)': 'chromeos_amd64-generic-vm_use_fake_dbus_clients_reclient', @@ -883,19 +886,6 @@ 'linux-finch-smoke-chrome': 'official_reclient', 'lorenz-graph-dbg': 'android_debug_bot_reclient_external_fastbuild', 'mac-arm64-finch-smoke-chrome': 'official_reclient_mac_arm', - # b/248132996: for siso experiments. - 'siso-comparison-android': { - 'reclient': 'android_release_trybot_arm64_webview_monochrome_expectations_fastbuild_reclient', - 'siso': 'android_release_trybot_arm64_webview_monochrome_expectations_fastbuild_siso', - }, - 'siso-comparison-linux': { - 'reclient': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_do_typecheck_reclient', - 'siso': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_do_typecheck_siso', - }, - 'siso-comparison-win10': { - 'reclient': 'gpu_tests_release_trybot_resource_allowlisting_no_precompiled_headers_reclient', - 'siso': 'gpu_tests_release_trybot_resource_allowlisting_no_precompiled_headers_siso', - }, 'win-arm64-dbg': 'chrome_branded_arm64_debug_reclient', 'win-arm64-rel': 'chrome_branded_arm64_release_reclient', 'win-celab-rel': 'official_celab_release_bot_reclient', @@ -1698,6 +1688,11 @@ 'strip_debug_info', 'webview_monochrome', ], + 'android_release_bot_minimal_symbols_arm64_webview_monochrome_siso': [ + 'android', 'release_bot', 'minimal_symbols', 'arm64', + 'strip_debug_info', 'webview_monochrome', 'no_goma', 'no_reclient', + ], + 'android_release_bot_minimal_symbols_reclient': [ 'android', 'release_bot_reclient', 'minimal_symbols', 'strip_debug_info', ], @@ -1755,18 +1750,6 @@ 'no_secondary_abi', 'use_clang_coverage', 'partial_code_coverage_instrumentation', ], - 'android_release_trybot_arm64_webview_monochrome_expectations_fastbuild_reclient': [ - 'android', 'release_trybot_reclient', 'arm64', 'strip_debug_info', - 'android_fastbuild', 'webview_monochrome', 'fail_on_android_expectations', - 'no_secondary_abi', - ], - - 'android_release_trybot_arm64_webview_monochrome_expectations_fastbuild_siso': [ - 'android', 'release_trybot', 'arm64', 'strip_debug_info', - 'android_fastbuild', 'webview_monochrome', 'fail_on_android_expectations', - 'no_secondary_abi', 'no_goma', 'no_reclient', - ], - 'android_release_trybot_arm64_webview_monochrome_reclient': [ 'android', 'release_trybot_reclient', 'arm64', 'strip_debug_info', 'webview_monochrome', @@ -2846,6 +2829,14 @@ "enable_backup_ref_ptr_feature_flag", ], + 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_code_coverage_do_typecheck_siso': [ + 'gpu_tests', 'release_trybot', 'no_symbols', 'use_dummy_lastchange', + 'use_clang_coverage', 'partial_code_coverage_instrumentation', 'devtools_do_typecheck', + 'enable_dangling_raw_ptr_feature_flag', + "enable_backup_ref_ptr_feature_flag", + "no_goma", "no_reclient", + ], + 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_do_typecheck_chrome_for_testing_reclient': [ 'gpu_tests', 'release_trybot_reclient', 'no_symbols', 'use_dummy_lastchange', 'devtools_do_typecheck', 'chrome_for_testing', @@ -2855,10 +2846,6 @@ 'gpu_tests', 'release_trybot_reclient', 'no_symbols', 'use_dummy_lastchange', 'devtools_do_typecheck', ], - 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_do_typecheck_siso': [ - 'gpu_tests', 'release_trybot', 'no_symbols', 'use_dummy_lastchange', - 'devtools_do_typecheck', 'no_goma', 'no_reclient', - ], 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_invert_fieldtrials_reclient': [ 'gpu_tests', 'release_trybot_reclient', 'no_symbols', 'use_dummy_lastchange', @@ -2892,19 +2879,17 @@ 'enable_dangling_raw_ptr_feature_flag', ], + 'gpu_tests_release_trybot_resource_allowlisting_code_coverage_siso': [ + 'gpu_tests', 'release_trybot', 'no_resource_allowlisting', + 'use_clang_coverage', 'partial_code_coverage_instrumentation', + 'enable_dangling_raw_ptr_feature_flag', + 'no_goma', 'no_reclient', + ], + 'gpu_tests_release_trybot_resource_allowlisting_invert_fieldtrials': [ 'gpu_tests', 'release_trybot_reclient', 'resource_allowlisting', 'invert_fieldtrials', ], - 'gpu_tests_release_trybot_resource_allowlisting_no_precompiled_headers_reclient': [ - 'gpu_tests', 'release_trybot_reclient', 'no_resource_allowlisting', 'no_precompiled_headers', - ], - - 'gpu_tests_release_trybot_resource_allowlisting_no_precompiled_headers_siso': [ - 'gpu_tests', 'release_trybot', 'no_resource_allowlisting', 'no_precompiled_headers', - 'no_goma', 'no_reclient', - ], - 'gpu_tests_release_trybot_resource_allowlisting_reclient': [ 'gpu_tests', 'release_trybot_reclient', 'resource_allowlisting', ], @@ -4523,10 +4508,6 @@ 'gn_args': 'use_lld=false', }, - 'no_precompiled_headers': { - 'gn_args': 'enable_precompiled_headers=false', - }, - 'no_reclient': { 'gn_args': 'use_remoteexec=false', },
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json index c119b9b18..83745eee8 100644 --- a/tools/mb/mb_config_expectations/chromium.fyi.json +++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -444,23 +444,37 @@ }, "build-perf-android": { "gn_args": { - "android_static_analysis": "off", - "dcheck_always_on": true, + "dcheck_always_on": false, "debuggable_apks": false, - "fail_on_android_expectations": true, "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, "proprietary_codecs": true, - "skip_secondary_abi_for_cq": true, "strip_debug_info": true, - "symbol_level": 0, + "symbol_level": 1, "system_webview_package_name": "com.google.android.apps.chrome", "target_cpu": "arm64", "target_os": "android", "use_remoteexec": true } }, + "build-perf-android-siso": { + "gn_args": { + "dcheck_always_on": false, + "debuggable_apks": false, + "ffmpeg_branding": "Chrome", + "is_component_build": false, + "is_debug": false, + "proprietary_codecs": true, + "strip_debug_info": true, + "symbol_level": 1, + "system_webview_package_name": "com.google.android.apps.chrome", + "target_cpu": "arm64", + "target_os": "android", + "use_goma": false, + "use_remoteexec": false + } + }, "build-perf-linux": { "gn_args": { "coverage_instrumentation_input_file": "//.code-coverage/files_to_instrument.txt", @@ -479,6 +493,25 @@ "use_remoteexec": true } }, + "build-perf-linux-siso": { + "gn_args": { + "coverage_instrumentation_input_file": "//.code-coverage/files_to_instrument.txt", + "dcheck_always_on": true, + "devtools_skip_typecheck": false, + "enable_backup_ref_ptr_feature_flag": true, + "enable_dangling_raw_ptr_checks": true, + "enable_dangling_raw_ptr_feature_flag": true, + "ffmpeg_branding": "Chrome", + "is_component_build": false, + "is_debug": false, + "proprietary_codecs": true, + "symbol_level": 0, + "use_clang_coverage": true, + "use_dummy_lastchange": true, + "use_goma": false, + "use_remoteexec": false + } + }, "build-perf-windows": { "gn_args": { "coverage_instrumentation_input_file": "//.code-coverage/files_to_instrument.txt", @@ -495,6 +528,23 @@ "use_remoteexec": true } }, + "build-perf-windows-siso": { + "gn_args": { + "coverage_instrumentation_input_file": "//.code-coverage/files_to_instrument.txt", + "dcheck_always_on": true, + "enable_dangling_raw_ptr_checks": true, + "enable_dangling_raw_ptr_feature_flag": true, + "enable_resource_allowlist_generation": false, + "ffmpeg_branding": "Chrome", + "is_component_build": false, + "is_debug": false, + "proprietary_codecs": true, + "symbol_level": 0, + "use_clang_coverage": true, + "use_goma": false, + "use_remoteexec": false + } + }, "chromeos-amd64-generic-rel (reclient compare)": { "args_file": "//build/args/chromeos/amd64-generic-vm.gni", "gn_args": {
diff --git a/tools/mb/mb_config_expectations/internal.chrome.fyi.json b/tools/mb/mb_config_expectations/internal.chrome.fyi.json index 215e3d3..25cd03b 100644 --- a/tools/mb/mb_config_expectations/internal.chrome.fyi.json +++ b/tools/mb/mb_config_expectations/internal.chrome.fyi.json
@@ -74,105 +74,6 @@ "use_remoteexec": true } }, - "siso-comparison-android": { - "reclient": { - "gn_args": { - "android_static_analysis": "off", - "dcheck_always_on": true, - "debuggable_apks": false, - "fail_on_android_expectations": true, - "ffmpeg_branding": "Chrome", - "is_component_build": false, - "is_debug": false, - "proprietary_codecs": true, - "skip_secondary_abi_for_cq": true, - "strip_debug_info": true, - "symbol_level": 0, - "system_webview_package_name": "com.google.android.apps.chrome", - "target_cpu": "arm64", - "target_os": "android", - "use_remoteexec": true - } - }, - "siso": { - "gn_args": { - "android_static_analysis": "off", - "dcheck_always_on": true, - "debuggable_apks": false, - "fail_on_android_expectations": true, - "ffmpeg_branding": "Chrome", - "is_component_build": false, - "is_debug": false, - "proprietary_codecs": true, - "skip_secondary_abi_for_cq": true, - "strip_debug_info": true, - "symbol_level": 0, - "system_webview_package_name": "com.google.android.apps.chrome", - "target_cpu": "arm64", - "target_os": "android", - "use_goma": false, - "use_remoteexec": false - } - } - }, - "siso-comparison-linux": { - "reclient": { - "gn_args": { - "dcheck_always_on": true, - "devtools_skip_typecheck": false, - "ffmpeg_branding": "Chrome", - "is_component_build": false, - "is_debug": false, - "proprietary_codecs": true, - "symbol_level": 0, - "use_dummy_lastchange": true, - "use_remoteexec": true - } - }, - "siso": { - "gn_args": { - "dcheck_always_on": true, - "devtools_skip_typecheck": false, - "ffmpeg_branding": "Chrome", - "is_component_build": false, - "is_debug": false, - "proprietary_codecs": true, - "symbol_level": 0, - "use_dummy_lastchange": true, - "use_goma": false, - "use_remoteexec": false - } - } - }, - "siso-comparison-win10": { - "reclient": { - "gn_args": { - "dcheck_always_on": true, - "enable_precompiled_headers": false, - "enable_resource_allowlist_generation": false, - "ffmpeg_branding": "Chrome", - "is_component_build": false, - "is_debug": false, - "proprietary_codecs": true, - "symbol_level": 0, - "use_remoteexec": true - } - }, - "siso": { - "gn_args": { - "dcheck_always_on": true, - "enable_precompiled_headers": false, - "enable_resource_allowlist_generation": false, - "ffmpeg_branding": "Chrome", - "is_component_build": false, - "is_debug": false, - "proprietary_codecs": true, - "symbol_level": 0, - "use_goma": false, - "use_remoteexec": false - } - } - }, "win-arm64-dbg": { "gn_args": { "ffmpeg_branding": "Chrome",
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 22af686c..1c86ddb 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -16773,6 +16773,7 @@ </action> <action name="ManagedUsers_OpenProfile"> + <obsolete>Deprecated as of 04/2023.</obsolete> <owner>pam@chromium.org</owner> <owner>treib@chromium.org</owner> <description>Supervised user profile activated.</description> @@ -16785,6 +16786,7 @@ </action> <action name="ManagedUsers_SwitchProfile"> + <obsolete>Deprecated as of 04/2023.</obsolete> <owner>pam@chromium.org</owner> <owner>treib@chromium.org</owner> <description>Supervised user switched to another profile.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index c9b0cf94..07cdd29d 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -42350,6 +42350,7 @@ <int value="4" label="kContributed"/> <int value="5" label="kRejected"/> <int value="6" label="kTaskFailedUnknownError"/> + <int value="7" label="kTaskTimeoutAbort"/> </enum> <enum name="FederatedServiceEvent"> @@ -44420,6 +44421,13 @@ </int> </enum> +<enum name="FirstRunEntryPoint"> + <int value="0" label="Other"/> + <int value="1" label="Process startup"/> + <int value="2" label="Web app launch"/> + <int value="3" label="Web app context menu command"/> +</enum> + <enum name="FirstRunExitStatus"> <summary> Status code indicating how the first run experience was exited. @@ -44439,6 +44447,14 @@ window etc..), experience is considered 'finished'"/> </enum> +<enum name="FirstRunFinishReason"> + <int value="0" label="ExperimentCounterfactual (feature is disabled)"/> + <int value="1" label="FinishedFlow (happy path)"/> + <int value="2" + label="ProfileAlreadySetUp (syncing on Lacros or signed in on Dice)"/> + <int value="3" label="SkippedByPolicies"/> +</enum> + <enum name="FirstRunLaunchSource"> <summary> External applications/promotions that triggered Chrome launch and First Run. @@ -55395,13 +55411,6 @@ <int value="8" label="Ahnmatae"/> </enum> -<enum name="LacrosFirstRunEntryPoint"> - <int value="0" label="Other"/> - <int value="1" label="Lacros process startup"/> - <int value="2" label="Web app launch"/> - <int value="3" label="Web app context menu command"/> -</enum> - <enum name="LacrosLaunchMode"> <int value="0" label="Only Ash browser"/> <int value="1" label="Ash and Lacros browser available"/> @@ -61188,6 +61197,7 @@ <int value="-431553693" label="ChangePasswordAffiliationInfo:disabled"/> <int value="-430369215" label="AssistPersonalInfo:disabled"/> <int value="-430360431" label="disable-password-generation"/> + <int value="-429580313" label="OmniboxActionsInSuggest:disabled"/> <int value="-429425707" label="StartSurfaceOnTablet:enabled"/> <int value="-428599163" label="NTPDownloadSuggestions:enabled"/> <int value="-428556995" label="DesktopPWAsTabStripSettings:enabled"/> @@ -62784,6 +62794,7 @@ <int value="430776375" label="TextureLayerSkipWaitForActivation:disabled"/> <int value="430959979" label="SyncStandaloneTransport:disabled"/> <int value="431691805" label="MediaDocumentDownloadButton:enabled"/> + <int value="432920820" label="OmniboxActionsInSuggest:enabled"/> <int value="434033638" label="PwaPersistentNotification:disabled"/> <int value="434333410" label="DefaultMeetWebApp:disabled"/> <int value="434530296" @@ -74448,13 +74459,6 @@ <int value="2" label="Enabled">NPAPI is enabled</int> </enum> -<enum name="NQE.ConnectivityMonitor.NetworkChangeType"> - <int value="0" label="NoEarlyActivation"/> - <int value="1" label="EarlyActivationOfUnknownNetwork"/> - <int value="2" label="EarlyActivationOfDifferentNetwork"/> - <int value="3" label="EarlyActivationOfSameNetwork"/> -</enum> - <enum name="NQEEffectiveConnectionType"> <int value="0" label="Unknown"/> <int value="1" label="Offline"/>
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml index a78700d8..364ff68 100644 --- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -3166,12 +3166,6 @@ label="Observed metric was greater than 5100 (inclusive) units"/> </histogram_suffixes> -<histogram_suffixes name="NQE_SignalStrengthQueried" separator="."> - <suffix name="Cellular" label="On cellular network."/> - <suffix name="WiFi" label="On WiFi network."/> - <affected-histogram name="NQE.SignalStrengthQueried"/> -</histogram_suffixes> - <histogram_suffixes name="OfflinePagesArchiveDirectoryType" separator="."> <suffix name="Persistent" label="Persistent archive directory"/> <suffix name="Temporary" label="Temporary archive directory"/>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index d085f633..489f736 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -3619,7 +3619,7 @@ </histogram> <histogram name="Media.MediaStreamManager.DesktopVideoDeviceUpdate" - enum="MediaStreamRequestResult2" expires_after="2023-04-16"> + enum="MediaStreamRequestResult2" expires_after="2023-07-16"> <owner>eladalon@chromium.org</owner> <owner>tovep@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index afd5b717..3066bc0 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -8526,122 +8526,6 @@ </summary> </histogram> -<histogram name="NQE.CachedNetworkQualityAvailable" enum="BooleanAvailable" - expires_after="2021-10-10"> - <owner>tbansal@chromium.org</owner> - <owner>bengr@chromium.org</owner> - <summary> - Records if the cached network quality (from memory or from a persistent - source) was available. Recorded right after connection change event. - </summary> -</histogram> - -<histogram name="NQE.CellularSignalStrength.ECTReduction" - units="ECT level reduction" expires_after="2021-10-10"> - <obsolete> - Obsoleted July 2021. - </obsolete> - <owner>tbansal@chromium.org</owner> - <summary> - Number of buckets by which effective connection type was reduced or capped - due to low cellular signal strength. Recorded only on cellular networks, and - only when the value of the effective connection typed is capped. - </summary> -</histogram> - -<histogram name="NQE.CellularSignalStrength.LevelAvailable" - enum="BooleanAvailable" expires_after="2021-10-10"> - <owner>tbansal@chromium.org</owner> - <owner>bengr@chromium.org</owner> - <summary> - Whether the signal strength for the cellular network was available or not. - Recorded right before a connection change event. Recorded only on cellular - connections on Android platform. - </summary> -</histogram> - -<histogram name="NQE.ConnectivityMonitor.NetworkChangeEvent" - enum="NQE.ConnectivityMonitor.NetworkChangeType" expires_after="2021-08-29"> - <obsolete> - Removed January 2022. - </obsolete> - <owner>rockot@google.com</owner> - <owner>zhongyi@chromium.org</owner> - <summary> - When ConnectivityMonitor establishes that the current default network may be - failing and is Wi-Fi, it asks the operating system to activate a mobile - network for subsequent use. Whenever the system's default network changes, - this logs the relationship between the new default network and the network - preemptively activated by ConnectivityMonitor, if any. - </summary> -</histogram> - -<histogram name="NQE.ConnectivityMonitor.TimeToSwitchNetworks" units="ms" - expires_after="2022-01-02"> - <owner>rockot@google.com</owner> - <owner>zhongyi@chromium.org</owner> - <summary> - The Network Quality Estimator (NQE) observes network activity to look for - connectivity issues. If it begins to observe failures on a previously - functioning network, it tracks the time at which the failures were first - observed. If the device subsequently switches its default network to - different network (or offline), this histogram logs the number of - milliseconds elapsed since the original failures were observed. - </summary> -</histogram> - -<histogram name="NQE.EffectiveConnectionType.OnECTComputation" - enum="NQEEffectiveConnectionType" expires_after="2022-05-01"> - <owner>tbansal@chromium.org</owner> - <owner>src/net/nqe/OWNERS</owner> - <summary> - Effective connection type estimated by the network quality estimator. - Recorded every time the effective connection type is computed. - </summary> -</histogram> - -<histogram name="NQE.EndToEndRTT.OnECTComputation" units="ms" - expires_after="2021-10-10"> - <owner>tbansal@chromium.org</owner> - <owner>src/net/nqe/OWNERS</owner> - <summary> - Rough estimate of the computed end-to-end round trip time. Recorded by the - network quality estimator every time the effective connection type is - computed. - </summary> -</histogram> - -<histogram name="NQE.HttpRttReduction.BasedOnRTTCounts" units="ms" - expires_after="2021-10-01"> - <owner>tbansal@chromium.org</owner> - <owner>bengr@chromium.org</owner> - <summary> - Duration by which HTTP RTT was reduced because of low confidence. - </summary> -</histogram> - -<histogram name="NQE.Kbps.OnECTComputation" units="Kbps" - expires_after="2021-11-21"> - <owner>bengr@chromium.org</owner> - <owner>tbansal@chromium.org</owner> - <summary> - Rough estimate of the downstream peak throughput (in kilobits per second). - Recorded by the network quality estimator every time the effective - connection type is computed. - </summary> -</histogram> - -<histogram name="NQE.NetworkIdAvailable" enum="BooleanAvailable" - expires_after="2021-07-22"> - <owner>tbansal@chromium.org</owner> - <owner>bengr@chromium.org</owner> - <summary> - Whether the NetworkID (SSID of the Wi-Fi network, or the MCC/MNC operator of - the cellular network) was available or not. Recorded only on Wi-Fi and - cellular networks. Recorded right after the connection type changes. - </summary> -</histogram> - <histogram name="NQE.Prefs.ReadCount" units="count" expires_after="2021-10-10"> <owner>tbansal@chromium.org</owner> <owner>bengr@chromium.org</owner> @@ -8691,40 +8575,6 @@ </summary> </histogram> -<histogram base="true" name="NQE.SignalStrengthQueried" enum="Boolean" - expires_after="2021-11-14"> - <obsolete> - Obsleted July 2021. - </obsolete> - <owner>tbansal@chromium.org</owner> - <owner>mcrouse@chromium.org</owner> - <summary> - Recorded as true when the signal strength of the current network is queried. - </summary> -</histogram> - -<histogram name="NQE.TransportRTT.OnECTComputation" units="ms" - expires_after="2022-06-26"> - <owner>bengr@chromium.org</owner> - <owner>tbansal@chromium.org</owner> - <summary> - Rough estimate of the computed round trip time at the transport layer. - Recorded by the network quality estimator every time the effective - connection type is computed. - </summary> -</histogram> - -<histogram name="NQE.WifiSignalStrength.LevelAvailable" enum="BooleanAvailable" - expires_after="2020-07-06"> - <owner>tbansal@chromium.org</owner> - <owner>bengr@chromium.org</owner> - <summary> - Whether the signal strength for the Wifi network was available or not. - Recorded right before a connection change event. Recorded only on Wifi - connections on Android platform. - </summary> -</histogram> - <histogram name="OAuth2Login.MergeSessionFailure" enum="GoogleServiceAuthError" expires_after="2023-09-10"> <owner>droger@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/profile/histograms.xml b/tools/metrics/histograms/metadata/profile/histograms.xml index 4c440d89..49bc392 100644 --- a/tools/metrics/histograms/metadata/profile/histograms.xml +++ b/tools/metrics/histograms/metadata/profile/histograms.xml
@@ -333,7 +333,7 @@ </histogram> <histogram name="Profile.LacrosPrimaryProfileFirstRunEntryPoint" - enum="LacrosFirstRunEntryPoint" expires_after="M120"> + enum="FirstRunEntryPoint" expires_after="M120"> <owner>dgn@chromium.org</owner> <owner>droger@chromium.org</owner> <summary> @@ -765,6 +765,23 @@ </summary> </histogram> +<histogram name="ProfilePicker.FirstRun.EntryPoint" enum="FirstRunEntryPoint" + expires_after="2023-12-19"> + <owner>dgn@chromium.org</owner> + <owner>for-you-fre@google.com</owner> + <summary> + Records the entry point that triggered the first run experience. This is + recorded right before the first run is shown. If the FRE is skipped, this is + never recorded. If the FRE is exited early and needs to be shown again + (relevant only on Lacros where we support showing the FRE more than once), + or if the user re-triggers the FRE while it is already shown, there would be + more than one record for that install. + + Note: Profile.LacrosPrimaryProfileFirstRunEntryPoint on Lacros records the + same data. + </summary> +</histogram> + <histogram name="ProfilePicker.FirstRun.ExitStatus" enum="FirstRunExitStatus" expires_after="2023-12-19"> <owner>dgn@chromium.org</owner> @@ -776,6 +793,18 @@ </summary> </histogram> +<histogram name="ProfilePicker.FirstRun.FinishReason" + enum="FirstRunFinishReason" expires_after="2023-12-19"> + <owner>dgn@chromium.org</owner> + <owner>for-you-fre@google.com</owner> + <summary> + Records the reason why the first run experience was marked finished. This + aims at tracking how often policies or some pre-existing state suppresses + the first run experience. It is tracked by the first run service itself, + when the flow completes (or is suppressed). + </summary> +</histogram> + <histogram name="ProfilePicker.FirstRun.OrganizationAvailableTiming" units="ms" expires_after="2023-07-25"> <owner>dgn@chromium.org</owner> @@ -803,6 +832,19 @@ </summary> </histogram> +<histogram name="ProfilePicker.FirstRun.ServiceCreated" enum="BooleanCreated" + expires_after="2023-12-19"> + <owner>dgn@chromium.org</owner> + <owner>for-you-fre@google.com</owner> + <summary> + Records first run service creations in this current profile. true is + recorded if the service was successfully created, and false is recorded if + it was suppressed because the feature is disabled. If this is not the first + run or the profile is not able to display the first run experience, nothing + will be recorded. + </summary> +</histogram> + <histogram name="ProfilePicker.Shown" enum="ProfilePickerEntryPoint" expires_after="2023-10-08"> <owner>msalama@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/service/histograms.xml b/tools/metrics/histograms/metadata/service/histograms.xml index 42daba7..b64d1e16 100644 --- a/tools/metrics/histograms/metadata/service/histograms.xml +++ b/tools/metrics/histograms/metadata/service/histograms.xml
@@ -1382,8 +1382,8 @@ </summary> </histogram> -<histogram name="ServiceWorker.Subresource.Fallbacked.Type" enum="ResourceType" - expires_after="2023-10-01"> +<histogram name="ServiceWorker.Subresource.Fallbacked.Type2" + enum="ResourceType" expires_after="2023-10-01"> <owner>yyanagisawa@google.com</owner> <owner>chrome-worker@google.com</owner> <summary> @@ -1392,13 +1392,10 @@ metric is taken every time a subresource load finishes. See ServiceWorker.Subresource.Handled.Type for handled cases. - - Warning: an unexpected reorder happened in Apr 2021 - (https://crrev.com/c/2798954). Please do not trust older reports. </summary> </histogram> -<histogram name="ServiceWorker.Subresource.Handled.Type" enum="ResourceType" +<histogram name="ServiceWorker.Subresource.Handled.Type2" enum="ResourceType" expires_after="2023-10-01"> <owner>yyanagisawa@google.com</owner> <owner>chrome-worker@google.com</owner> @@ -1408,9 +1405,6 @@ every time a subresource load finishes. See ServiceWorker.Subresource.Fallbacked.Type for fallbacked cases. - - Warning: an unexpected reorder happened in Apr 2021 - (https://crrev.com/c/2798954). Please do not trust older reports. </summary> </histogram>
diff --git a/tools/style_variable_generator/base_generator.py b/tools/style_variable_generator/base_generator.py index 142c6795..4eaa38b 100644 --- a/tools/style_variable_generator/base_generator.py +++ b/tools/style_variable_generator/base_generator.py
@@ -94,6 +94,9 @@ for name, value in data.get('opacities', {}).items(): self.model.Add(VariableType.OPACITY, name, value, context) + for name, value in data.get('legacy_mappings', {}).items(): + self.model.Add(VariableType.LEGACY_MAPPING, name, value, context) + typography = data.get('typography') if typography: for name, value in typography['font_families'].items():
diff --git a/tools/style_variable_generator/css_generator.py b/tools/style_variable_generator/css_generator.py index eb55307c..9be65dcf 100644 --- a/tools/style_variable_generator/css_generator.py +++ b/tools/style_variable_generator/css_generator.py
@@ -39,11 +39,13 @@ 'typefaces': self.model.typefaces, 'font_families': self.model.font_families, 'untyped_css': self.model.untyped_css, + 'legacy_mappings': self.model.legacy_mappings, } def GetFilters(self): return { 'to_css_var_name': self.ToCSSVarName, + 'to_css_var_name_unscoped': self.ToCSSVarNameUnscoped, 'css_opacity': self._CSSOpacity, 'css_color_rgb': self.CSSColorRGB, 'process_simple_ref': self.ProcessSimpleRef, @@ -127,6 +129,9 @@ return '--%s%s' % (self._GetCSSVarPrefix(name), var_name) + def ToCSSVarNameUnscoped(self, name): + return f'--{name}' + def _CSSOpacity(self, opacity): if opacity.var: return 'var(%s)' % self.ToCSSVarName(opacity.var)
diff --git a/tools/style_variable_generator/model.py b/tools/style_variable_generator/model.py index 425d8803..a6e11b5 100644 --- a/tools/style_variable_generator/model.py +++ b/tools/style_variable_generator/model.py
@@ -26,6 +26,7 @@ UNTYPED_CSS = 'untyped_css' TYPEFACE = 'typeface' FONT_FAMILY = 'font_family' + LEGACY_MAPPING = 'legacy_mappings' class StyleVariable(object): @@ -307,6 +308,9 @@ self.untyped_css = SimpleModel(VariableType.UNTYPED_CSS) self.submodels[VariableType.UNTYPED_CSS] = self.untyped_css + self.legacy_mappings = SimpleModel(VariableType.LEGACY_MAPPING) + self.submodels[VariableType.LEGACY_MAPPING] = self.legacy_mappings + def CheckTypeFace(name, value_obj, context): assert value_obj['font_family'] assert value_obj['font_size']
diff --git a/tools/style_variable_generator/templates/css_generator.tmpl b/tools/style_variable_generator/templates/css_generator.tmpl index 4347186..8ac96244 100644 --- a/tools/style_variable_generator/templates/css_generator.tmpl +++ b/tools/style_variable_generator/templates/css_generator.tmpl
@@ -33,6 +33,9 @@ html:not(body) { {{- render_variables_for_mode(Modes.DEFAULT) -}} +{%- for name, value in legacy_mappings.items() %} + {{name | to_css_var_name_unscoped}}: {{value | process_simple_ref}}; +{% endfor -%} }
diff --git a/tools/style_variable_generator/templates/ts_generator.tmpl b/tools/style_variable_generator/templates/ts_generator.tmpl index ac773a8..a170701 100644 --- a/tools/style_variable_generator/templates/ts_generator.tmpl +++ b/tools/style_variable_generator/templates/ts_generator.tmpl
@@ -31,6 +31,7 @@ * mode values and ignores the documents prefers-color-scheme. */ lockTheme?: 'light' | 'dark'; + useDynamicColors?: boolean; } // Use a ternary expression that can only be evaluated at runtime here to force @@ -72,6 +73,14 @@ {% endif -%} ` : ''; +const LEGACY_MAPPINGS_CSS = window ? ` +{%- if legacy_mappings %} +{%- for name, value in legacy_mappings.items() %} + {{name | to_css_var_name_unscoped}}: {{value | process_simple_ref}}; +{% endfor -%} +{% endif -%} +` : ''; + /** * Returns a string containing all semantic colors exported in this file as * css variables. This string an be used to construct a stylesheet which can be @@ -81,6 +90,8 @@ * that all TS constant references resolve correctly. */ export function getColorsCSS(options?: GetColorsCSSOptions) { + const legacyMappings = options?.useDynamicColors ? LEGACY_MAPPINGS_CSS : ''; + let cssString; if (options?.lockTheme === 'light') { // Tag strings which are safe with a special comment so copybara can add @@ -90,6 +101,7 @@ ${DEFAULT_CSS} ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DARK_MODE_OVERRIDES_CSS} @@ -102,6 +114,7 @@ ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} ${DARK_MODE_OVERRIDES_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DEFAULT_CSS} @@ -113,6 +126,7 @@ ${DEFAULT_CSS} ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DARK_MODE_OVERRIDES_CSS}
diff --git a/tools/style_variable_generator/tests/base_generator_test.py b/tools/style_variable_generator/tests/base_generator_test.py index 0842913..81c5438 100755 --- a/tools/style_variable_generator/tests/base_generator_test.py +++ b/tools/style_variable_generator/tests/base_generator_test.py
@@ -316,6 +316,17 @@ self.assertEqual(self.ResolveRGBA('alert_debug'), 'rgba(0, 0, 0, 1)') self.assertEqual(self.ResolveRGBA('alert'), 'rgba(255, 255, 255, 1)') + def testAlias(self): + self.generator.AddJSONToModel(''' + { + aliases: { + legacy: "$white", + }, + } + ''') + self.assertEqual(self.generator.model.aliases['legacy'], '$white') + self.generator.model.Validate() + if __name__ == '__main__': unittest.main()
diff --git a/tools/style_variable_generator/tests/colors_test.json5 b/tools/style_variable_generator/tests/colors_test.json5 index c5882f6..f86d21c 100644 --- a/tools/style_variable_generator/tests/colors_test.json5 +++ b/tools/style_variable_generator/tests/colors_test.json5
@@ -8,6 +8,9 @@ field_id: 2, }, }, + legacy_mappings: { + legacy_color: '$text_color_primary', + }, colors: { text_color_primary: { light: "$google_grey_900",
diff --git a/tools/style_variable_generator/tests/goldens/colors_test_custom_dark_toggle_expected.css b/tools/style_variable_generator/tests/goldens/colors_test_custom_dark_toggle_expected.css index 8204029..41fa6996 100644 --- a/tools/style_variable_generator/tests/goldens/colors_test_custom_dark_toggle_expected.css +++ b/tools/style_variable_generator/tests/goldens/colors_test_custom_dark_toggle_expected.css
@@ -26,6 +26,8 @@ --cros-disabled-opacity: 0.38; --cros-reference-opacity: var(--cros-disabled-opacity); + + --legacy_color: var(--cros-text-color-primary); } html[dark]:not(body) {
diff --git a/tools/style_variable_generator/tests/goldens/colors_test_dark_only_expected.css b/tools/style_variable_generator/tests/goldens/colors_test_dark_only_expected.css index 3777c38..2205c1b3 100644 --- a/tools/style_variable_generator/tests/goldens/colors_test_dark_only_expected.css +++ b/tools/style_variable_generator/tests/goldens/colors_test_dark_only_expected.css
@@ -25,4 +25,6 @@ --cros-disabled-opacity: 0.38; --cros-reference-opacity: 1; + + --legacy_color: var(--cros-text-color-primary); }
diff --git a/tools/style_variable_generator/tests/goldens/colors_test_expected.css b/tools/style_variable_generator/tests/goldens/colors_test_expected.css index faad3cd..508fc15 100644 --- a/tools/style_variable_generator/tests/goldens/colors_test_expected.css +++ b/tools/style_variable_generator/tests/goldens/colors_test_expected.css
@@ -26,6 +26,8 @@ --cros-disabled-opacity: 0.38; --cros-reference-opacity: var(--cros-disabled-opacity); + + --legacy_color: var(--cros-text-color-primary); } @media (prefers-color-scheme: dark) {
diff --git a/tools/style_variable_generator/tests/goldens/colors_test_include_style_sheet_expected.ts b/tools/style_variable_generator/tests/goldens/colors_test_include_style_sheet_expected.ts index 2ea858466..9640361 100644 --- a/tools/style_variable_generator/tests/goldens/colors_test_include_style_sheet_expected.ts +++ b/tools/style_variable_generator/tests/goldens/colors_test_include_style_sheet_expected.ts
@@ -16,6 +16,7 @@ * mode values and ignores the documents prefers-color-scheme. */ lockTheme?: 'light' | 'dark'; + useDynamicColors?: boolean; } // Use a ternary expression that can only be evaluated at runtime here to force @@ -56,6 +57,10 @@ const TYPOGRAPHY_CSS = window ? `` : ''; +const LEGACY_MAPPINGS_CSS = window ? ` + --legacy_color: var(--cros-text-color-primary); +` : ''; + /** * Returns a string containing all semantic colors exported in this file as * css variables. This string an be used to construct a stylesheet which can be @@ -65,6 +70,8 @@ * that all TS constant references resolve correctly. */ export function getColorsCSS(options?: GetColorsCSSOptions) { + const legacyMappings = options?.useDynamicColors ? LEGACY_MAPPINGS_CSS : ''; + let cssString; if (options?.lockTheme === 'light') { // Tag strings which are safe with a special comment so copybara can add @@ -74,6 +81,7 @@ ${DEFAULT_CSS} ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DARK_MODE_OVERRIDES_CSS} @@ -86,6 +94,7 @@ ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} ${DARK_MODE_OVERRIDES_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DEFAULT_CSS} @@ -97,6 +106,7 @@ ${DEFAULT_CSS} ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DARK_MODE_OVERRIDES_CSS}
diff --git a/tools/style_variable_generator/tests/goldens/colors_test_typography_and_untyped_css_expected.ts b/tools/style_variable_generator/tests/goldens/colors_test_typography_and_untyped_css_expected.ts index 987b229..f8398cd 100644 --- a/tools/style_variable_generator/tests/goldens/colors_test_typography_and_untyped_css_expected.ts +++ b/tools/style_variable_generator/tests/goldens/colors_test_typography_and_untyped_css_expected.ts
@@ -18,6 +18,7 @@ * mode values and ignores the documents prefers-color-scheme. */ lockTheme?: 'light' | 'dark'; + useDynamicColors?: boolean; } // Use a ternary expression that can only be evaluated at runtime here to force @@ -73,6 +74,10 @@ --cros-headline-1-line-height: 22px; ` : ''; +const LEGACY_MAPPINGS_CSS = window ? ` + --legacy_color: var(--cros-text-color-primary); +` : ''; + /** * Returns a string containing all semantic colors exported in this file as * css variables. This string an be used to construct a stylesheet which can be @@ -82,6 +87,8 @@ * that all TS constant references resolve correctly. */ export function getColorsCSS(options?: GetColorsCSSOptions) { + const legacyMappings = options?.useDynamicColors ? LEGACY_MAPPINGS_CSS : ''; + let cssString; if (options?.lockTheme === 'light') { // Tag strings which are safe with a special comment so copybara can add @@ -91,6 +98,7 @@ ${DEFAULT_CSS} ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DARK_MODE_OVERRIDES_CSS} @@ -103,6 +111,7 @@ ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} ${DARK_MODE_OVERRIDES_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DEFAULT_CSS} @@ -114,6 +123,7 @@ ${DEFAULT_CSS} ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DARK_MODE_OVERRIDES_CSS}
diff --git a/tools/style_variable_generator/tests/goldens/colors_test_typography_expected.ts b/tools/style_variable_generator/tests/goldens/colors_test_typography_expected.ts index c7202de..05ec671 100644 --- a/tools/style_variable_generator/tests/goldens/colors_test_typography_expected.ts +++ b/tools/style_variable_generator/tests/goldens/colors_test_typography_expected.ts
@@ -17,6 +17,7 @@ * mode values and ignores the documents prefers-color-scheme. */ lockTheme?: 'light' | 'dark'; + useDynamicColors?: boolean; } // Use a ternary expression that can only be evaluated at runtime here to force @@ -68,6 +69,10 @@ --cros-headline-1-line-height: 22px; ` : ''; +const LEGACY_MAPPINGS_CSS = window ? ` + --legacy_color: var(--cros-text-color-primary); +` : ''; + /** * Returns a string containing all semantic colors exported in this file as * css variables. This string an be used to construct a stylesheet which can be @@ -77,6 +82,8 @@ * that all TS constant references resolve correctly. */ export function getColorsCSS(options?: GetColorsCSSOptions) { + const legacyMappings = options?.useDynamicColors ? LEGACY_MAPPINGS_CSS : ''; + let cssString; if (options?.lockTheme === 'light') { // Tag strings which are safe with a special comment so copybara can add @@ -86,6 +93,7 @@ ${DEFAULT_CSS} ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DARK_MODE_OVERRIDES_CSS} @@ -98,6 +106,7 @@ ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} ${DARK_MODE_OVERRIDES_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DEFAULT_CSS} @@ -109,6 +118,7 @@ ${DEFAULT_CSS} ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DARK_MODE_OVERRIDES_CSS}
diff --git a/tools/style_variable_generator/tests/goldens/colors_test_untyped_css_expected.ts b/tools/style_variable_generator/tests/goldens/colors_test_untyped_css_expected.ts index 5f1667a..6468915 100644 --- a/tools/style_variable_generator/tests/goldens/colors_test_untyped_css_expected.ts +++ b/tools/style_variable_generator/tests/goldens/colors_test_untyped_css_expected.ts
@@ -17,6 +17,7 @@ * mode values and ignores the documents prefers-color-scheme. */ lockTheme?: 'light' | 'dark'; + useDynamicColors?: boolean; } // Use a ternary expression that can only be evaluated at runtime here to force @@ -61,6 +62,10 @@ const TYPOGRAPHY_CSS = window ? `` : ''; +const LEGACY_MAPPINGS_CSS = window ? ` + --legacy_color: var(--cros-text-color-primary); +` : ''; + /** * Returns a string containing all semantic colors exported in this file as * css variables. This string an be used to construct a stylesheet which can be @@ -70,6 +75,8 @@ * that all TS constant references resolve correctly. */ export function getColorsCSS(options?: GetColorsCSSOptions) { + const legacyMappings = options?.useDynamicColors ? LEGACY_MAPPINGS_CSS : ''; + let cssString; if (options?.lockTheme === 'light') { // Tag strings which are safe with a special comment so copybara can add @@ -79,6 +86,7 @@ ${DEFAULT_CSS} ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DARK_MODE_OVERRIDES_CSS} @@ -91,6 +99,7 @@ ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} ${DARK_MODE_OVERRIDES_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DEFAULT_CSS} @@ -102,6 +111,7 @@ ${DEFAULT_CSS} ${UNTYPED_CSS} ${TYPOGRAPHY_CSS} + ${legacyMappings} } :host([inverted-colors]) { ${DARK_MODE_OVERRIDES_CSS}
diff --git a/tools/style_variable_generator/tests/goldens/suppress_sources_comment_test_expected.css b/tools/style_variable_generator/tests/goldens/suppress_sources_comment_test_expected.css index 768d284..41dbb0a 100644 --- a/tools/style_variable_generator/tests/goldens/suppress_sources_comment_test_expected.css +++ b/tools/style_variable_generator/tests/goldens/suppress_sources_comment_test_expected.css
@@ -21,6 +21,8 @@ --cros-disabled-opacity: 0.38; --cros-reference-opacity: var(--cros-disabled-opacity); + + --legacy_color: var(--cros-text-color-primary); } @media (prefers-color-scheme: dark) {
diff --git a/tools/style_variable_generator/tests/style_variable_generator_test.py b/tools/style_variable_generator/tests/style_variable_generator_test.py index 5efc291dd..284de8c5a 100755 --- a/tools/style_variable_generator/tests/style_variable_generator_test.py +++ b/tools/style_variable_generator/tests/style_variable_generator_test.py
@@ -27,7 +27,7 @@ path = os.path.join(os.path.dirname(__file__), 'goldens', filename) with open(path, 'r') as f: self.maxDiff = None - self.assertEqual(value, f.read()) + self.assertEqual(value, f.read(), f'Did not match golden: {path}') def AddJSONFilesToModel(self, files): relpaths_from_cwd = [
diff --git a/ui/base/ime/surrounding_text_tracker.cc b/ui/base/ime/surrounding_text_tracker.cc index 35127351..75e051f67 100644 --- a/ui/base/ime/surrounding_text_tracker.cc +++ b/ui/base/ime/surrounding_text_tracker.cc
@@ -11,14 +11,26 @@ namespace ui { -SurroundingTextTracker::SurroundingTextTracker() - : predicted_state_{u"", gfx::Range(0), gfx::Range()} {} +SurroundingTextTracker::Entry::Entry(State state, + base::RepeatingClosure command) + : state(std::move(state)), command(std::move(command)) {} + +SurroundingTextTracker::Entry::Entry(const Entry&) = default; +SurroundingTextTracker::Entry::Entry(Entry&&) = default; +SurroundingTextTracker::Entry& SurroundingTextTracker::Entry::operator=( + const Entry&) = default; +SurroundingTextTracker::Entry& SurroundingTextTracker::Entry::operator=( + Entry&&) = default; +SurroundingTextTracker::Entry::~Entry() = default; + +SurroundingTextTracker::SurroundingTextTracker() { + ResetInternal(u"", gfx::Range(0)); +} SurroundingTextTracker::~SurroundingTextTracker() = default; void SurroundingTextTracker::Reset() { - predicted_state_ = State{u"", gfx::Range(0), gfx::Range()}; - expected_updates_.clear(); + ResetInternal(u"", gfx::Range(0)); } SurroundingTextTracker::UpdateResult SurroundingTextTracker::Update( @@ -26,8 +38,8 @@ const gfx::Range& selection) { for (auto it = expected_updates_.begin(); it != expected_updates_.end(); ++it) { - if (it->surrounding_text == surrounding_text && - it->selection == selection) { + if (it->state.surrounding_text == surrounding_text && + it->state.selection == selection) { // Found the target state. Remove the older histories. // Keep the last entry, because sometimes it is notified multiple times // by client apps. @@ -37,17 +49,17 @@ } VLOG(1) << "Unknown surrounding text update is found"; - predicted_state_ = - State{std::u16string(surrounding_text), selection, gfx::Range()}; - expected_updates_.clear(); - expected_updates_.push_back(predicted_state_); + ResetInternal(surrounding_text, selection); return UpdateResult::kReset; } void SurroundingTextTracker::OnSetEditableSelectionRange( const gfx::Range& range) { predicted_state_.selection = range; - expected_updates_.push_back(predicted_state_); + expected_updates_.emplace_back( + predicted_state_, + base::BindRepeating(&SurroundingTextTracker::OnSetEditableSelectionRange, + base::Unretained(this), range)); } void SurroundingTextTracker::OnSetCompositionText( @@ -65,37 +77,50 @@ composition_begin + composition.selection.end()); predicted_state_.composition = gfx::Range( composition_begin, composition_begin + composition.text.length()); - expected_updates_.push_back(predicted_state_); + expected_updates_.emplace_back( + predicted_state_, + base::BindRepeating(&SurroundingTextTracker::OnSetCompositionText, + base::Unretained(this), composition)); } void SurroundingTextTracker::OnSetCompositionFromExistingText( const gfx::Range& range) { predicted_state_.composition = range; - expected_updates_.push_back(predicted_state_); + expected_updates_.emplace_back( + predicted_state_, + base::BindRepeating( + &SurroundingTextTracker::OnSetCompositionFromExistingText, + base::Unretained(this), range)); } void SurroundingTextTracker::OnConfirmCompositionText(bool keep_selection) { - if (predicted_state_.composition.is_empty()) - return; - - if (!keep_selection && !predicted_state_.composition.is_empty()) - predicted_state_.selection = gfx::Range(predicted_state_.composition.end()); - predicted_state_.composition = gfx::Range(); - expected_updates_.push_back(predicted_state_); + if (!predicted_state_.composition.is_empty()) { + if (!keep_selection && !predicted_state_.composition.is_empty()) { + predicted_state_.selection = + gfx::Range(predicted_state_.composition.end()); + } + predicted_state_.composition = gfx::Range(); + } + expected_updates_.emplace_back( + predicted_state_, + base::BindRepeating(&SurroundingTextTracker::OnConfirmCompositionText, + base::Unretained(this), keep_selection)); } void SurroundingTextTracker::OnClearCompositionText() { - if (predicted_state_.composition.is_empty()) - return; - - predicted_state_.surrounding_text.erase( - predicted_state_.composition.GetMin(), - predicted_state_.composition.length()); - // Set selection to the position where composition existed. - predicted_state_.selection = - gfx::Range(predicted_state_.composition.GetMin()); - predicted_state_.composition = gfx::Range(); - expected_updates_.push_back(predicted_state_); + if (!predicted_state_.composition.is_empty()) { + predicted_state_.surrounding_text.erase( + predicted_state_.composition.GetMin(), + predicted_state_.composition.length()); + // Set selection to the position where composition existed. + predicted_state_.selection = + gfx::Range(predicted_state_.composition.GetMin()); + predicted_state_.composition = gfx::Range(); + } + expected_updates_.emplace_back( + predicted_state_, + base::BindRepeating(&SurroundingTextTracker::OnClearCompositionText, + base::Unretained(this))); } void SurroundingTextTracker::OnInsertText( @@ -134,50 +159,63 @@ ? gfx::Range(rewritten_range.GetMin() + text.length()) : gfx::Range(rewritten_range.GetMin()); predicted_state_.composition = gfx::Range(); - expected_updates_.push_back(predicted_state_); + expected_updates_.emplace_back( + predicted_state_, + base::BindRepeating(&SurroundingTextTracker::OnInsertText, + base::Unretained(this), text, cursor_behavior)); } void SurroundingTextTracker::OnExtendSelectionAndDelete(size_t before, size_t after) { - if (before == 0 && after == 0 && predicted_state_.selection.is_empty() && - predicted_state_.composition.is_empty()) { - // Nothing happens for null deletion. - return; - } - - gfx::Range delete_range( - predicted_state_.selection.GetMin() - - std::min(before, predicted_state_.selection.GetMin()), - std::min(predicted_state_.selection.GetMax() + after, - predicted_state_.surrounding_text.length())); - if (!predicted_state_.composition.is_empty()) { - // Cancel the current composition. - if (predicted_state_.composition.Intersects(delete_range)) { - // Expand the delete_range to include the whole composition range, - // if there's some overlap. - delete_range = gfx::Range(std::min(predicted_state_.composition.GetMin(), - delete_range.GetMin()), - std::max(predicted_state_.composition.GetMax(), - delete_range.GetMax())); - } else { - // Otherwise, remove the composition here. If the composition appears - // before the delete_range, the offset needs to be updated. - predicted_state_.surrounding_text.erase( - predicted_state_.composition.GetMin(), - predicted_state_.composition.length()); - if (delete_range.GetMin() > predicted_state_.composition.GetMin()) { - delete_range = gfx::Range( - delete_range.start() - predicted_state_.composition.length(), - delete_range.end() - predicted_state_.composition.length()); + if (before != 0 || after != 0 || !predicted_state_.selection.is_empty() || + !predicted_state_.composition.is_empty()) { + gfx::Range delete_range( + predicted_state_.selection.GetMin() - + std::min(before, predicted_state_.selection.GetMin()), + std::min(predicted_state_.selection.GetMax() + after, + predicted_state_.surrounding_text.length())); + if (!predicted_state_.composition.is_empty()) { + // Cancel the current composition. + if (predicted_state_.composition.Intersects(delete_range)) { + // Expand the delete_range to include the whole composition range, + // if there's some overlap. + delete_range = + gfx::Range(std::min(predicted_state_.composition.GetMin(), + delete_range.GetMin()), + std::max(predicted_state_.composition.GetMax(), + delete_range.GetMax())); + } else { + // Otherwise, remove the composition here. If the composition appears + // before the delete_range, the offset needs to be updated. + predicted_state_.surrounding_text.erase( + predicted_state_.composition.GetMin(), + predicted_state_.composition.length()); + if (delete_range.GetMin() > predicted_state_.composition.GetMin()) { + delete_range = gfx::Range( + delete_range.start() - predicted_state_.composition.length(), + delete_range.end() - predicted_state_.composition.length()); + } } } + + predicted_state_.surrounding_text.erase(delete_range.GetMin(), + delete_range.length()); + predicted_state_.selection = gfx::Range(delete_range.GetMin()); + predicted_state_.composition = gfx::Range(); } - predicted_state_.surrounding_text.erase(delete_range.GetMin(), - delete_range.length()); - predicted_state_.selection = gfx::Range(delete_range.GetMin()); - predicted_state_.composition = gfx::Range(); - expected_updates_.push_back(predicted_state_); + expected_updates_.emplace_back( + predicted_state_, + base::BindRepeating(&SurroundingTextTracker::OnExtendSelectionAndDelete, + base::Unretained(this), before, after)); +} + +void SurroundingTextTracker::ResetInternal(base::StringPiece16 surrounding_text, + const gfx::Range& selection) { + predicted_state_ = + State{std::u16string(surrounding_text), selection, gfx::Range()}; + expected_updates_.clear(); + expected_updates_.emplace_back(predicted_state_, base::RepeatingClosure()); } } // namespace ui
diff --git a/ui/base/ime/surrounding_text_tracker.h b/ui/base/ime/surrounding_text_tracker.h index 3dab060..f78345a 100644 --- a/ui/base/ime/surrounding_text_tracker.h +++ b/ui/base/ime/surrounding_text_tracker.h
@@ -9,7 +9,9 @@ #include <string> #include "base/component_export.h" +#include "base/functional/callback.h" #include "base/strings/string_piece.h" +#include "third_party/abseil-cpp/absl/types/variant.h" #include "ui/base/ime/text_input_client.h" #include "ui/gfx/range/range.h" @@ -75,8 +77,28 @@ void OnExtendSelectionAndDelete(size_t before, size_t after); private: + // History of events and their expected states. + struct Entry { + State state; + base::RepeatingClosure command; + + Entry(State state, base::RepeatingClosure command); + + // Copy/Move-able. + Entry(const Entry&); + Entry(Entry&& entry); + Entry& operator=(const Entry&); + Entry& operator=(Entry&&); + + ~Entry(); + }; + + void ResetInternal(base::StringPiece16 surrounding_text, + const gfx::Range& selection); + + // The latest known state. State predicted_state_; - std::deque<State> expected_updates_; + std::deque<Entry> expected_updates_; }; } // namespace ui
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_match.html b/ui/webui/resources/cr_components/omnibox/realbox_match.html index 42129ed6..4befcb8e 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_match.html +++ b/ui/webui/resources/cr_components/omnibox/realbox_match.html
@@ -187,6 +187,12 @@ font-size: 12px; line-height: 16px; } + + + :host([side-type-class_='secondary-side'][is-entity-suggestion][has-image]) + #remove { + display: none; + } </style> <div class="container" aria-hidden="true"> <div id="focus-indicator"></div>