diff --git a/DEPS b/DEPS index 785ade9de..f32f78c 100644 --- a/DEPS +++ b/DEPS
@@ -305,15 +305,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': 'ef57c474c8b10b4c97ac88154e490993d142619d', + 'skia_revision': '61da282a10bc855b0dd2944ad7923a3a1c76fea5', # 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': '667602785ee1a57e97fd126bd1addd9d90b9583f', + 'v8_revision': 'fb5540cbafa376d24341b9b05a86e7ba1355f590', # 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': 'dbd34ba86494db895d386c17c7d57ea92e318dc4', + 'angle_revision': 'c8a87b37d5fc3c4bcfa19382486198bd5bafe8d5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -332,7 +332,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:9.20220913.3.1', + 'fuchsia_version': 'version:9.20220914.1.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. @@ -384,7 +384,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': 'e6ab1b4d2046d4ac7ac9c997ecafdcc8395e708c', + 'devtools_frontend_revision': '6a3cd17dd1ce1929aa2cfe5c03dee6d438b60a33', # 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. @@ -420,7 +420,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': 'a0b64c7e642ba3742c1faded2b29b957a970ec6c', + 'dawn_revision': 'b74ca3f8e071c5e88fdc74ee04a9f240c6a12ca8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -1209,7 +1209,7 @@ Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '8a88a361916c410324526b1f1c5f8a9d61e96615', + 'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + 'd024440bf25d16b1531b5c88a291381455b60f20', 'condition': 'checkout_src_internal', }, @@ -1597,7 +1597,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'b910084bb46109fc40ac3eb3719d455bc53e9611', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'a8b5c6144dd79c1ccf2f7e3d9f4b9d6029f60dae', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1651,7 +1651,7 @@ 'packages': [ { 'package': 'chromium/third_party/r8', - 'version': 'DbVJ-oYhMQRvNqZYr37TP1-U_0vkeVNii078zhzdUmUC', + 'version': 'M3EMkYB8eJSrmuVBALj8iJw_ysvzFKniQRYFZ7d61XkC', }, ], 'condition': 'checkout_android', @@ -1778,10 +1778,10 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '399c52a625bd3074849527d66879283dded9a31b', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '3729857192afbb868e3aa46d62638bf57c7ce54d', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '41263fab8f7d36130b9b26fa4b0b84b4259a2e62', + Var('webrtc_git') + '/src.git' + '@' + '6fa8a759b4c0c36aed1fdf4bd3442efc7562311a', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1873,7 +1873,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/eche_app/app', - 'version': 'uGTtvjRo_LUHdOEk7jtWDiS3G7BU8gyjitLSRz5VJJYC', + 'version': 'Ogm1R0DYIBfiOnmn4JGWi5dKm9oZ8t36ukBVWlXFp18C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1906,7 +1906,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/projector_app/app', - 'version': 'UpPBxF3SYJWFpc7u4AHK8UdtP5AX9mNk28_8s7Tls6oC', + 'version': 'ttP4D8aZS7d73xx-7XhG7Jg_E2qEaw7bCci7qcJk3moC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 42a7f1c..6ad8be3 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -5089,7 +5089,7 @@ # don't match the chromium style guide, but new files should # get it right. if guard_name != expected_guard: - if not f.OldContents(): + if f.Action() == 'A': # If file was just 'A'dded errors.append( output_api.PresubmitPromptWarning( 'Header using the wrong include guard name %s'
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py index 9bfb045..af18e22 100755 --- a/PRESUBMIT_test.py +++ b/PRESUBMIT_test.py
@@ -799,7 +799,7 @@ '#ifndef CHROME_ODL_H_', '#define CHROME_ODL_H_', '#endif // CHROME_ODL_H_', - ]), + ], action='M'), # Using a Blink style include guard outside Blink is wrong. MockAffectedFile('content/NotInBlink.h', [ '#ifndef NotInBlink_h', @@ -821,8 +821,9 @@ 'struct McBoatFace;', '#endif // WrongInBlink_h', ]), - # Using a bad include guard in Blink is not accepted even if - # it's an old file. + # Using a bad include guard in Blink is not supposed to be accepted even + # if it's an old file. However the current presubmit has accepted this + # for a while. MockAffectedFile('third_party/blink/StillInBlink.h', [ '// New contents', '#ifndef AcceptedInBlink_h', @@ -835,7 +836,7 @@ '#define AcceptedInBlink_h', 'struct McBoatFace;', '#endif // AcceptedInBlink_h', - ]), + ], action='M'), # Using a non-Chromium include guard in third_party # (outside blink) is accepted. MockAffectedFile('third_party/foo/some_file.h', [
diff --git a/ash/clipboard/clipboard_history_controller_impl.cc b/ash/clipboard/clipboard_history_controller_impl.cc index ec8eb5d6c..728be2a 100644 --- a/ash/clipboard/clipboard_history_controller_impl.cc +++ b/ash/clipboard/clipboard_history_controller_impl.cc
@@ -359,7 +359,7 @@ weak_ptr_factory_.GetWeakPtr())); for (auto& observer : observers_) - observer.OnClipboardHistoryMenuShown(show_source); + observer.OnClipboardHistoryMenuShown(); } gfx::Rect ClipboardHistoryControllerImpl::GetMenuBoundsInScreenForTest() const { @@ -382,15 +382,6 @@ get_history_values_blocker_for_test_->Signal(); } -bool ClipboardHistoryControllerImpl::ShouldShowNewFeatureBadge() const { - return chromeos::features::IsClipboardHistoryContextMenuNudgeEnabled() && - nudge_controller_->ShouldShowNewFeatureBadge(); -} - -void ClipboardHistoryControllerImpl::MarkNewFeatureBadgeShown() { - nudge_controller_->MarkNewFeatureBadgeShown(); -} - void ClipboardHistoryControllerImpl::OnScreenshotNotificationCreated() { nudge_controller_->MarkScreenshotNotificationShown(); }
diff --git a/ash/clipboard/clipboard_history_controller_impl.h b/ash/clipboard/clipboard_history_controller_impl.h index de4e1f4..946f0b4 100644 --- a/ash/clipboard/clipboard_history_controller_impl.h +++ b/ash/clipboard/clipboard_history_controller_impl.h
@@ -146,8 +146,6 @@ // ClipboardHistoryController: bool CanShowMenu() const override; - bool ShouldShowNewFeatureBadge() const override; - void MarkNewFeatureBadgeShown() override; void OnScreenshotNotificationCreated() override; std::unique_ptr<ScopedClipboardHistoryPause> CreateScopedPause() override; void GetHistoryValues(const std::set<std::string>& item_id_filter,
diff --git a/ash/clipboard/clipboard_nudge_constants.h b/ash/clipboard/clipboard_nudge_constants.h index 8377adcf..f7d766c 100644 --- a/ash/clipboard/clipboard_nudge_constants.h +++ b/ash/clipboard/clipboard_nudge_constants.h
@@ -16,11 +16,9 @@ // Shows when the keyboard shortcut for clipboard is pressed with no items // in the history. kZeroStateNudge = 1, - // Blue new feature badge for clipboard history's context menu option. - kNewFeatureBadge = 2, // Shows the keyboard shortcut for clipboard history in the screenshot // notification nudge. - kScreenshotNotificationNudge = 3, + kScreenshotNotificationNudge = 2, }; const char kOnboardingNudge_ShowCount[] = @@ -35,12 +33,6 @@ "Ash.ClipboardHistory.Nudges.ZeroStateNudge.ToFeatureOpenTime"; const char kZeroStateNudge_PasteTime[] = "Ash.ClipboardHistory.Nudges.ZeroStateNudge.ToFeaturePasteTime"; -const char kNewBadge_ShowCount[] = - "Ash.ClipboardHistory.Nudges.NewFeatureBadge.ShownCount"; -const char kNewBadge_OpenTime[] = - "Ash.ClipboardHistory.Nudges.NewFeatureBadge.ToFeatureOpenTime"; -const char kNewBadge_PasteTime[] = - "Ash.ClipboardHistory.Nudges.NewFeatureBadge.ToFeaturePasteTime"; const char kScreenshotNotification_ShowCount[] = "Ash.ClipboardHistory.Nudges.ScreenshotNotificationNudge.ShownCount"; const char kScreenshotNotification_OpenTime[] =
diff --git a/ash/clipboard/clipboard_nudge_controller.cc b/ash/clipboard/clipboard_nudge_controller.cc index d4c50d8..8406d1a 100644 --- a/ash/clipboard/clipboard_nudge_controller.cc +++ b/ash/clipboard/clipboard_nudge_controller.cc
@@ -24,7 +24,6 @@ // Keys for tooltip sub-preferences for shown count and last time shown. constexpr char kShownCount[] = "shown_count"; constexpr char kLastTimeShown[] = "last_time_shown"; -constexpr char kNewFeatureBadgeCount[] = "new_feature_shown_count"; // The maximum number of 1 second buckets used to record the time between // showing the nudge and recording the feature being opened/used. @@ -116,25 +115,6 @@ } } -void ClipboardNudgeController::MarkNewFeatureBadgeShown() { - PrefService* prefs = - Shell::Get()->session_controller()->GetLastActiveUserPrefService(); - if (!prefs) - return; - const int shown_count = GetNewFeatureBadgeShownCount(prefs); - DictionaryPrefUpdate update(prefs, prefs::kMultipasteNudges); - update->SetIntPath(kNewFeatureBadgeCount, shown_count + 1); - base::UmaHistogramBoolean(kNewBadge_ShowCount, true); - if (new_feature_last_shown_time_.ShouldLogFeatureOpenTime()) { - base::UmaHistogramExactLinear(kNewBadge_OpenTime, kMaxSeconds, kMaxSeconds); - } - if (new_feature_last_shown_time_.ShouldLogFeatureUsedTime()) { - base::UmaHistogramExactLinear(kNewBadge_PasteTime, kMaxSeconds, - kMaxSeconds); - } - new_feature_last_shown_time_.ResetTime(); -} - void ClipboardNudgeController::MarkScreenshotNotificationShown() { base::UmaHistogramBoolean(kScreenshotNotification_ShowCount, true); if (screenshot_notification_last_shown_time_.ShouldLogFeatureOpenTime()) { @@ -148,16 +128,6 @@ screenshot_notification_last_shown_time_.ResetTime(); } -bool ClipboardNudgeController::ShouldShowNewFeatureBadge() { - PrefService* prefs = - Shell::Get()->session_controller()->GetLastActiveUserPrefService(); - if (!prefs) - return false; - int badge_shown_count = GetNewFeatureBadgeShownCount(prefs); - // We should not show more nudges after hitting the limit. - return badge_shown_count < kContextMenuBadgeShowLimit; -} - void ClipboardNudgeController::OnClipboardDataRead() { PrefService* prefs = Shell::Get()->session_controller()->GetLastActiveUserPrefService(); @@ -197,12 +167,9 @@ DictionaryPrefUpdate update(prefs, prefs::kMultipasteNudges); update->SetIntPath(kShownCount, 0); update->SetPath(kLastTimeShown, base::TimeToValue(base::Time())); - update->SetIntPath(kNewFeatureBadgeCount, 0); } void ClipboardNudgeController::ShowNudge(ClipboardNudgeType nudge_type) { - DCHECK_NE(nudge_type, ClipboardNudgeType::kNewFeatureBadge); - current_nudge_type_ = nudge_type; SystemNudgeController::ShowNudge(); @@ -251,22 +218,9 @@ update->SetPath(kLastTimeShown, base::TimeToValue(GetTime())); } -void ClipboardNudgeController::OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource show_source) { +void ClipboardNudgeController::OnClipboardHistoryMenuShown() { if (LogFeatureOpenTime(last_shown_time_, kOnboardingNudge_OpenTime)) last_shown_time_.set_was_logged_as_opened(); - switch (show_source) { - case crosapi::mojom::ClipboardHistoryControllerShowSource::kAccelerator: - case crosapi::mojom::ClipboardHistoryControllerShowSource::kVirtualKeyboard: - case crosapi::mojom::ClipboardHistoryControllerShowSource::kUnknown: - break; - case crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu: - case crosapi::mojom::ClipboardHistoryControllerShowSource:: - kTextfieldContextMenu: - if (LogFeatureOpenTime(new_feature_last_shown_time_, kNewBadge_OpenTime)) - new_feature_last_shown_time_.set_was_logged_as_opened(); - } if (LogFeatureOpenTime(zero_state_last_shown_time_, kZeroStateNudge_OpenTime)) zero_state_last_shown_time_.set_was_logged_as_opened(); if (LogFeatureOpenTime(screenshot_notification_last_shown_time_, @@ -278,8 +232,6 @@ void ClipboardNudgeController::OnClipboardHistoryPasted() { if (LogFeatureUsedTime(last_shown_time_, kOnboardingNudge_PasteTime)) last_shown_time_.set_was_logged_as_used(); - if (LogFeatureUsedTime(new_feature_last_shown_time_, kNewBadge_PasteTime)) - new_feature_last_shown_time_.set_was_logged_as_used(); if (LogFeatureUsedTime(zero_state_last_shown_time_, kZeroStateNudge_PasteTime)) { zero_state_last_shown_time_.set_was_logged_as_used(); @@ -315,12 +267,6 @@ return dictionary.FindInt(kShownCount).value_or(0); } -int ClipboardNudgeController::GetNewFeatureBadgeShownCount(PrefService* prefs) { - const base::Value::Dict& dictionary = - prefs->GetDict(prefs::kMultipasteNudges); - return dictionary.FindInt(kNewFeatureBadgeCount).value_or(0); -} - base::Time ClipboardNudgeController::GetLastShownTime(PrefService* prefs) { const base::Value::Dict& dictionary = prefs->GetDict(prefs::kMultipasteNudges);
diff --git a/ash/clipboard/clipboard_nudge_controller.h b/ash/clipboard/clipboard_nudge_controller.h index 8482cf7..ddcef6e 100644 --- a/ash/clipboard/clipboard_nudge_controller.h +++ b/ash/clipboard/clipboard_nudge_controller.h
@@ -84,19 +84,11 @@ // Resets nudge state and show nudge timer. void HandleNudgeShown(); - // Checks whether we should show the context menu 'new' badge. - bool ShouldShowNewFeatureBadge(); - - // Increment the 'new' feature badge shown count. - void MarkNewFeatureBadgeShown(); - // Increment the screenshot notification shown count. void MarkScreenshotNotificationShown(); // ClipboardHistoryControllerImpl: - void OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource show_source) - override; + void OnClipboardHistoryMenuShown() override; void OnClipboardHistoryPasted() override; // Shows the nudge widget. @@ -117,8 +109,6 @@ int GetShownCount(PrefService* prefs); // Gets the last time the nudge was shown. base::Time GetLastShownTime(PrefService* prefs); - // Gets the number of times the context menu 'new' badge has been shown. - int GetNewFeatureBadgeShownCount(PrefService* prefs); // Checks whether another nudge can be shown. bool ShouldShowNudge(PrefService* prefs); // Gets the current time. Can be overridden for testing. @@ -130,9 +120,6 @@ // Time the zero state nudge was last shown. TimeMetricHelper zero_state_last_shown_time_; - // Time the new feature badge was last shown. - TimeMetricHelper new_feature_last_shown_time_; - // Time the screenshot notification nudge was last shown. TimeMetricHelper screenshot_notification_last_shown_time_;
diff --git a/ash/clipboard/clipboard_nudge_controller_unittest.cc b/ash/clipboard/clipboard_nudge_controller_unittest.cc index 992c603..ba3e2427 100644 --- a/ash/clipboard/clipboard_nudge_controller_unittest.cc +++ b/ash/clipboard/clipboard_nudge_controller_unittest.cc
@@ -8,13 +8,11 @@ #include "ash/clipboard/clipboard_history_controller_impl.h" #include "ash/clipboard/clipboard_nudge.h" #include "ash/clipboard/clipboard_nudge_constants.h" -#include "ash/constants/ash_features.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "base/strings/string_number_conversions.h" #include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "chromeos/crosapi/mojom/clipboard_history.mojom.h" #include "ui/base/clipboard/clipboard_data.h" @@ -38,8 +36,6 @@ // AshTestBase: void SetUp() override { - scoped_feature_list_.InitAndEnableFeature( - chromeos::features::kClipboardHistoryContextMenuNudge); AshTestBase::SetUp(); nudge_controller_ = Shell::Get()->clipboard_history_controller()->nudge_controller(); @@ -61,9 +57,6 @@ case ClipboardNudgeType::kZeroStateNudge: nudge_controller_->ShowNudge(nudge_type); return; - case ClipboardNudgeType::kNewFeatureBadge: - nudge_controller_->MarkNewFeatureBadgeShown(); - return; case ClipboardNudgeType::kScreenshotNotificationNudge: nudge_controller_->MarkScreenshotNotificationShown(); return; @@ -73,7 +66,6 @@ base::HistogramTester& histograms() { return histograms_; } private: - base::test::ScopedFeatureList scoped_feature_list_; base::SimpleTestClock test_clock_; // Histogram value verifier. base::HistogramTester histograms_; @@ -213,23 +205,6 @@ nudge_controller_->GetClipboardStateForTesting()); } -// Verifies that the context menu new feature badge for the clipboard option -// only shows |kContextMenuBadgeShowLimit| times. -TEST_F(ClipboardNudgeControllerTest, ShowNewFeatureNudge) { - ASSERT_TRUE(nudge_controller_->ShouldShowNewFeatureBadge()); - - // Mark the badge shown |kContextMenuBadgeShowLimit| - 1 times. - // Should expect to keep showing the badge - for (int i = 0; i < kContextMenuBadgeShowLimit - 1; ++i) { - nudge_controller_->MarkNewFeatureBadgeShown(); - EXPECT_TRUE(nudge_controller_->ShouldShowNewFeatureBadge()); - } - // Marking the badge as shown |kContextMenuBadgeShowLimit| times should not - // expect to show the badge the next time. - nudge_controller_->MarkNewFeatureBadgeShown(); - EXPECT_FALSE(nudge_controller_->ShouldShowNewFeatureBadge()); -} - // Verifies that controller cleans up and closes an old nudge before displaying // another one. TEST_F(ClipboardNudgeControllerTest, ShowZeroStateNudgeAfterOngoingNudge) { @@ -280,8 +255,6 @@ histograms().ExpectTotalCount(kOnboardingNudge_PasteTime, 0); histograms().ExpectTotalCount(kZeroStateNudge_OpenTime, 0); histograms().ExpectTotalCount(kZeroStateNudge_PasteTime, 0); - histograms().ExpectTotalCount(kNewBadge_OpenTime, 0); - histograms().ExpectTotalCount(kNewBadge_PasteTime, 0); histograms().ExpectTotalCount(kScreenshotNotification_OpenTime, 0); histograms().ExpectTotalCount(kScreenshotNotification_PasteTime, 0); } @@ -292,19 +265,14 @@ TEST_F(ClipboardNudgeControllerTest, ShowMenuAfterNudges_LogsOpenNudgeMetrics) { ShowNudgeForType(ClipboardNudgeType::kOnboardingNudge); ShowNudgeForType(ClipboardNudgeType::kZeroStateNudge); - ShowNudgeForType(ClipboardNudgeType::kNewFeatureBadge); ShowNudgeForType(ClipboardNudgeType::kScreenshotNotificationNudge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu); + nudge_controller_->OnClipboardHistoryMenuShown(); histograms().ExpectTotalCount(kOnboardingNudge_OpenTime, 1); histograms().ExpectTotalCount(kZeroStateNudge_OpenTime, 1); - histograms().ExpectTotalCount(kNewBadge_OpenTime, 1); histograms().ExpectTotalCount(kScreenshotNotification_OpenTime, 1); histograms().ExpectTotalCount(kOnboardingNudge_PasteTime, 0); histograms().ExpectTotalCount(kZeroStateNudge_PasteTime, 0); - histograms().ExpectTotalCount(kNewBadge_PasteTime, 0); histograms().ExpectTotalCount(kScreenshotNotification_PasteTime, 0); } @@ -314,20 +282,15 @@ TEST_F(ClipboardNudgeControllerTest, PasteAfterNudges_LogsPasteNudgeMetrics) { ShowNudgeForType(ClipboardNudgeType::kOnboardingNudge); ShowNudgeForType(ClipboardNudgeType::kZeroStateNudge); - ShowNudgeForType(ClipboardNudgeType::kNewFeatureBadge); ShowNudgeForType(ClipboardNudgeType::kScreenshotNotificationNudge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu); + nudge_controller_->OnClipboardHistoryMenuShown(); nudge_controller_->OnClipboardHistoryPasted(); histograms().ExpectTotalCount(kOnboardingNudge_OpenTime, 1); histograms().ExpectTotalCount(kZeroStateNudge_OpenTime, 1); - histograms().ExpectTotalCount(kNewBadge_OpenTime, 1); histograms().ExpectTotalCount(kScreenshotNotification_OpenTime, 1); histograms().ExpectTotalCount(kOnboardingNudge_PasteTime, 1); histograms().ExpectTotalCount(kZeroStateNudge_PasteTime, 1); - histograms().ExpectTotalCount(kNewBadge_PasteTime, 1); histograms().ExpectTotalCount(kScreenshotNotification_PasteTime, 1); } @@ -335,18 +298,14 @@ // onboarding nudge histograms, TEST_F(ClipboardNudgeControllerTest, OnboardingNudge_DoesNotLogOtherMetrics) { ShowNudgeForType(ClipboardNudgeType::kOnboardingNudge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu); + nudge_controller_->OnClipboardHistoryMenuShown(); nudge_controller_->OnClipboardHistoryPasted(); histograms().ExpectTotalCount(kOnboardingNudge_OpenTime, 1); histograms().ExpectTotalCount(kZeroStateNudge_OpenTime, 0); - histograms().ExpectTotalCount(kNewBadge_OpenTime, 0); histograms().ExpectTotalCount(kScreenshotNotification_OpenTime, 0); histograms().ExpectTotalCount(kOnboardingNudge_PasteTime, 1); histograms().ExpectTotalCount(kZeroStateNudge_PasteTime, 0); - histograms().ExpectTotalCount(kNewBadge_PasteTime, 0); histograms().ExpectTotalCount(kScreenshotNotification_PasteTime, 0); } @@ -354,37 +313,14 @@ // state nudge histograms, TEST_F(ClipboardNudgeControllerTest, ZeroStateNudge_DoesNotLogOtherMetrics) { ShowNudgeForType(ClipboardNudgeType::kZeroStateNudge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu); + nudge_controller_->OnClipboardHistoryMenuShown(); nudge_controller_->OnClipboardHistoryPasted(); histograms().ExpectTotalCount(kOnboardingNudge_OpenTime, 0); histograms().ExpectTotalCount(kZeroStateNudge_OpenTime, 1); - histograms().ExpectTotalCount(kNewBadge_OpenTime, 0); histograms().ExpectTotalCount(kScreenshotNotification_OpenTime, 0); histograms().ExpectTotalCount(kOnboardingNudge_PasteTime, 0); histograms().ExpectTotalCount(kZeroStateNudge_PasteTime, 1); - histograms().ExpectTotalCount(kNewBadge_PasteTime, 0); - histograms().ExpectTotalCount(kScreenshotNotification_PasteTime, 0); -} - -// Test that the new feature badge being shown only logs the metrics for the new -// feature badge histograms, -TEST_F(ClipboardNudgeControllerTest, NewFeatureBadge_DoesNotLogOtherMetrics) { - ShowNudgeForType(ClipboardNudgeType::kNewFeatureBadge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu); - nudge_controller_->OnClipboardHistoryPasted(); - - histograms().ExpectTotalCount(kOnboardingNudge_OpenTime, 0); - histograms().ExpectTotalCount(kZeroStateNudge_OpenTime, 0); - histograms().ExpectTotalCount(kNewBadge_OpenTime, 1); - histograms().ExpectTotalCount(kScreenshotNotification_OpenTime, 0); - histograms().ExpectTotalCount(kOnboardingNudge_PasteTime, 0); - histograms().ExpectTotalCount(kZeroStateNudge_PasteTime, 0); - histograms().ExpectTotalCount(kNewBadge_PasteTime, 1); histograms().ExpectTotalCount(kScreenshotNotification_PasteTime, 0); } @@ -393,18 +329,14 @@ TEST_F(ClipboardNudgeControllerTest, ScreenshotNotification_DoesNotLogOtherMetrics) { ShowNudgeForType(ClipboardNudgeType::kScreenshotNotificationNudge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu); + nudge_controller_->OnClipboardHistoryMenuShown(); nudge_controller_->OnClipboardHistoryPasted(); histograms().ExpectTotalCount(kOnboardingNudge_OpenTime, 0); histograms().ExpectTotalCount(kZeroStateNudge_OpenTime, 0); - histograms().ExpectTotalCount(kNewBadge_OpenTime, 0); histograms().ExpectTotalCount(kScreenshotNotification_OpenTime, 1); histograms().ExpectTotalCount(kOnboardingNudge_PasteTime, 0); histograms().ExpectTotalCount(kZeroStateNudge_PasteTime, 0); - histograms().ExpectTotalCount(kNewBadge_PasteTime, 0); histograms().ExpectTotalCount(kScreenshotNotification_PasteTime, 1); } @@ -413,24 +345,17 @@ TEST_F(ClipboardNudgeControllerTest, SecondTimeAction_DoesNotLogNudgeMetrics) { ShowNudgeForType(ClipboardNudgeType::kOnboardingNudge); ShowNudgeForType(ClipboardNudgeType::kZeroStateNudge); - ShowNudgeForType(ClipboardNudgeType::kNewFeatureBadge); ShowNudgeForType(ClipboardNudgeType::kScreenshotNotificationNudge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu); + nudge_controller_->OnClipboardHistoryMenuShown(); nudge_controller_->OnClipboardHistoryPasted(); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu); + nudge_controller_->OnClipboardHistoryMenuShown(); nudge_controller_->OnClipboardHistoryPasted(); histograms().ExpectTotalCount(kOnboardingNudge_OpenTime, 1); histograms().ExpectTotalCount(kZeroStateNudge_OpenTime, 1); - histograms().ExpectTotalCount(kNewBadge_OpenTime, 1); histograms().ExpectTotalCount(kScreenshotNotification_OpenTime, 1); histograms().ExpectTotalCount(kOnboardingNudge_PasteTime, 1); histograms().ExpectTotalCount(kZeroStateNudge_PasteTime, 1); - histograms().ExpectTotalCount(kNewBadge_PasteTime, 1); histograms().ExpectTotalCount(kScreenshotNotification_PasteTime, 1); } @@ -438,56 +363,21 @@ TEST_F(ClipboardNudgeControllerTest, ShowNudgeTwice_LogsMetricsTwoTimes) { ShowNudgeForType(ClipboardNudgeType::kOnboardingNudge); ShowNudgeForType(ClipboardNudgeType::kZeroStateNudge); - ShowNudgeForType(ClipboardNudgeType::kNewFeatureBadge); ShowNudgeForType(ClipboardNudgeType::kScreenshotNotificationNudge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu); + nudge_controller_->OnClipboardHistoryMenuShown(); nudge_controller_->OnClipboardHistoryPasted(); ShowNudgeForType(ClipboardNudgeType::kOnboardingNudge); ShowNudgeForType(ClipboardNudgeType::kZeroStateNudge); - ShowNudgeForType(ClipboardNudgeType::kNewFeatureBadge); ShowNudgeForType(ClipboardNudgeType::kScreenshotNotificationNudge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu); + nudge_controller_->OnClipboardHistoryMenuShown(); nudge_controller_->OnClipboardHistoryPasted(); histograms().ExpectTotalCount(kOnboardingNudge_OpenTime, 2); histograms().ExpectTotalCount(kZeroStateNudge_OpenTime, 2); - histograms().ExpectTotalCount(kNewBadge_OpenTime, 2); histograms().ExpectTotalCount(kScreenshotNotification_OpenTime, 2); histograms().ExpectTotalCount(kOnboardingNudge_PasteTime, 2); histograms().ExpectTotalCount(kZeroStateNudge_PasteTime, 2); - histograms().ExpectTotalCount(kNewBadge_PasteTime, 2); histograms().ExpectTotalCount(kScreenshotNotification_PasteTime, 2); } -// For the new feature badge, metrics should only log for opening a menu by a -// context menu source. -TEST_F(ClipboardNudgeControllerTest, - NewFeatureBadgeOpen_LogsByWithContextMenuSource) { - ShowNudgeForType(ClipboardNudgeType::kNewFeatureBadge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kRenderViewContextMenu); - ShowNudgeForType(ClipboardNudgeType::kNewFeatureBadge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource:: - kTextfieldContextMenu); - - histograms().ExpectTotalCount(kNewBadge_OpenTime, 2); -} - -TEST_F(ClipboardNudgeControllerTest, - NewFeatureBadgeOpen_DoesNotLogsWithNotContextMenuSource) { - ShowNudgeForType(ClipboardNudgeType::kNewFeatureBadge); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource::kAccelerator); - nudge_controller_->OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource::kVirtualKeyboard); - - histograms().ExpectTotalCount(kNewBadge_OpenTime, 0); -} - } // namespace ash
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 5a8cfd4..baf24564 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -346,11 +346,6 @@ const base::Feature kCheckPasswordsAgainstCryptohomeHelper{ "CheckPasswordsAgainstCryptohomeHelper", base::FEATURE_DISABLED_BY_DEFAULT}; -// If enabled, a blue new nudge will show on the context menu option for -// clipboard history. -const base::Feature kClipboardHistoryContextMenuNudge{ - "ClipboardHistoryContextMenuNudge", base::FEATURE_DISABLED_BY_DEFAULT}; - // If enabled, the clipboard nudge shown prefs will be reset at the start of // each new user session. const base::Feature kClipboardHistoryNudgeSessionReset{ @@ -1920,10 +1915,6 @@ return base::FeatureList::IsEnabled(kCheckPasswordsAgainstCryptohomeHelper); } -bool IsClipboardHistoryContextMenuNudgeEnabled() { - return base::FeatureList::IsEnabled(kClipboardHistoryContextMenuNudge); -} - bool IsClipboardHistoryNudgeSessionResetEnabled() { return base::FeatureList::IsEnabled(kClipboardHistoryNudgeSessionReset); }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 9a3ee2db..ce02fa9 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -153,8 +153,6 @@ COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kCheckPasswordsAgainstCryptohomeHelper; COMPONENT_EXPORT(ASH_CONSTANTS) -extern const base::Feature kClipboardHistoryContextMenuNudge; -COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kClipboardHistoryNudgeSessionReset; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kClipboardHistoryReorder; @@ -746,8 +744,6 @@ bool IsCheckPasswordsAgainstCryptohomeHelperEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsLauncherItemColorSyncEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) -bool IsClipboardHistoryContextMenuNudgeEnabled(); -COMPONENT_EXPORT(ASH_CONSTANTS) bool IsClipboardHistoryNudgeSessionResetEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsClipboardHistoryReorderEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsConsumerAutoUpdateToggleAllowed();
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn index 5b2bbb6..66c1372 100644 --- a/ash/public/cpp/BUILD.gn +++ b/ash/public/cpp/BUILD.gn
@@ -238,6 +238,7 @@ "power_utils.h", "presentation_time_recorder.cc", "presentation_time_recorder.h", + "privacy_hub_delegate.h", "privacy_screen_dlp_helper.cc", "privacy_screen_dlp_helper.h", "projector/annotator_tool.cc",
diff --git a/ash/public/cpp/clipboard_history_controller.h b/ash/public/cpp/clipboard_history_controller.h index f63099a..0c10ca0 100644 --- a/ash/public/cpp/clipboard_history_controller.h +++ b/ash/public/cpp/clipboard_history_controller.h
@@ -36,8 +36,7 @@ class Observer : public base::CheckedObserver { public: // Called when the clipboard history menu is shown. - virtual void OnClipboardHistoryMenuShown( - crosapi::mojom::ClipboardHistoryControllerShowSource show_source) {} + virtual void OnClipboardHistoryMenuShown() {} // Called when the user pastes from the clipboard history menu. virtual void OnClipboardHistoryPasted() {} // Called when the clipboard history changes. @@ -64,11 +63,6 @@ ui::MenuSourceType source_type, crosapi::mojom::ClipboardHistoryControllerShowSource show_source) = 0; - // Whether 'new' feature badge should be applied to clipboard menu. - virtual bool ShouldShowNewFeatureBadge() const = 0; - // Increment the 'new' feature badge shown count. - virtual void MarkNewFeatureBadgeShown() = 0; - // Notify the clipboard history that a screenshot notification was created. virtual void OnScreenshotNotificationCreated() = 0;
diff --git a/ash/public/cpp/holding_space/holding_space_constants.h b/ash/public/cpp/holding_space/holding_space_constants.h index eeb2cbe..cf61be918 100644 --- a/ash/public/cpp/holding_space/holding_space_constants.h +++ b/ash/public/cpp/holding_space/holding_space_constants.h
@@ -93,6 +93,10 @@ // The maximum allowed number of suggestions to display in holding space UI. constexpr size_t kMaxSuggestions = 4u; +// The maximum number of items to store in the `HoldingSpaceModel` for screen +// captures and downloads. +constexpr size_t kMaxItemsPerSection = 50; + // Mime type with wildcard which matches all image types. constexpr char kMimeTypeImage[] = "image/*";
diff --git a/ash/public/cpp/holding_space/holding_space_model.cc b/ash/public/cpp/holding_space/holding_space_model.cc index 3754ef6..4e937be1 100644 --- a/ash/public/cpp/holding_space/holding_space_model.cc +++ b/ash/public/cpp/holding_space/holding_space_model.cc
@@ -4,6 +4,11 @@ #include "ash/public/cpp/holding_space/holding_space_model.h" +#include <numeric> + +#include "ash/constants/ash_features.h" +#include "ash/public/cpp/holding_space/holding_space_constants.h" +#include "ash/public/cpp/holding_space/holding_space_item.h" #include "ash/public/cpp/holding_space/holding_space_model_observer.h" #include "ash/public/cpp/holding_space/holding_space_util.h" #include "base/bind.h" @@ -14,6 +19,23 @@ namespace ash { +namespace { + +// Helpers --------------------------------------------------------------------- + +// Maps a `HoldingSpaceItem::Type` to a `HoldingSpaceModel::Section`. +HoldingSpaceModel::Section ToSection(HoldingSpaceItem::Type type) { + if (holding_space_util::IsDownloadType(type)) + return HoldingSpaceModel::Section::kDownload; + + if (holding_space_util::IsScreenCaptureType(type)) + return HoldingSpaceModel::Section::kScreenCapture; + + return HoldingSpaceModel::Section::kNone; +} + +} // namespace + // HoldingSpaceModel::ScopedItemUpdate ----------------------------------------- HoldingSpaceModel::ScopedItemUpdate::~ScopedItemUpdate() { @@ -183,8 +205,12 @@ item_ptrs.push_back(item.get()); items_.push_back(std::move(item)); } + for (auto& observer : observers_) observer.OnHoldingSpaceItemsAdded(item_ptrs); + + if (features::IsHoldingSpacePredictabilityEnabled()) + TrimToMaxItemsPerSection(); } void HoldingSpaceModel::RemoveItem(const std::string& id) { @@ -316,4 +342,22 @@ observers_.RemoveObserver(observer); } +// Removes any items that exceed the `kMaxItemsPerSection` of that +// `HoldingSpaceItem::Type`. Types are bucketed into screen_captures and +// downloads. For example if `kMaxItemsPerSection` is 10 and after adding 2 +// new download items the user has a total of 12 items in the downloads +// bucket, then we remove the 2 oldest (i.e. first we find in the vector) +// downloads from holding space `items_`, leaving the 10 newest remaining. +// If it's not a download or screen capture then no limit is applied. +void HoldingSpaceModel::TrimToMaxItemsPerSection() { + RemoveIf(base::BindRepeating( + [](std::map<Section, size_t>& items_per_section, + const HoldingSpaceItem* item) { + auto section = ToSection(item->type()); + return ++items_per_section[section] > kMaxItemsPerSection && + section != HoldingSpaceModel::Section::kNone; + }, + base::OwnedRef(std::map<Section, size_t>()))); +} + } // namespace ash
diff --git a/ash/public/cpp/holding_space/holding_space_model.h b/ash/public/cpp/holding_space/holding_space_model.h index ade57db..0f5a374 100644 --- a/ash/public/cpp/holding_space/holding_space_model.h +++ b/ash/public/cpp/holding_space/holding_space_model.h
@@ -110,6 +110,8 @@ bool invalidate_image_ = false; }; + enum class Section { kDownload, kScreenCapture, kNone }; + HoldingSpaceModel(); HoldingSpaceModel(const HoldingSpaceModel& other) = delete; HoldingSpaceModel& operator=(const HoldingSpaceModel& other) = delete; @@ -174,6 +176,9 @@ void RemoveObserver(HoldingSpaceModelObserver* observer); private: + // Removes any items that exceed the `kMaxItemsPerSection` of that section. + void TrimToMaxItemsPerSection(); + // The list of items added to the model in the order they have been added to // the model. ItemList items_;
diff --git a/ash/public/cpp/holding_space/holding_space_model_unittest.cc b/ash/public/cpp/holding_space/holding_space_model_unittest.cc index 6e577f9..c0fb7ab 100644 --- a/ash/public/cpp/holding_space/holding_space_model_unittest.cc +++ b/ash/public/cpp/holding_space/holding_space_model_unittest.cc
@@ -7,6 +7,8 @@ #include <memory> #include <vector> +#include "ash/constants/ash_features.h" +#include "ash/public/cpp/holding_space/holding_space_constants.h" #include "ash/public/cpp/holding_space/holding_space_image.h" #include "ash/public/cpp/holding_space/holding_space_item.h" #include "ash/public/cpp/holding_space/holding_space_model_observer.h" @@ -14,6 +16,8 @@ #include "ash/public/cpp/holding_space/holding_space_util.h" #include "base/bind.h" #include "base/scoped_observation.h" +#include "base/test/scoped_feature_list.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/chromeos/styles/cros_styles.h" #include "ui/gfx/paint_vector_icon.h" @@ -35,7 +39,7 @@ std::vector<HoldingSpaceItem::Type> GetHoldingSpaceItemTypes() { std::vector<HoldingSpaceItem::Type> types; for (int i = 0; i <= static_cast<int>(HoldingSpaceItem::Type::kMaxValue); ++i) - types.push_back(static_cast<HoldingSpaceItem::Type>(i)); + types.emplace_back(static_cast<HoldingSpaceItem::Type>(i)); return types; } @@ -47,6 +51,13 @@ /*async_bitmap_resolver=*/base::DoNothing()); } +std::unique_ptr<HoldingSpaceItem> CreateItem(HoldingSpaceItem::Type type) { + return HoldingSpaceItem::CreateFileBackedItem( + /*type=*/type, base::FilePath("file_path"), + GURL("filesystem::file_system_url"), + /*image_resolver=*/base::BindOnce(&CreateFakeHoldingSpaceImage)); +} + // ScopedModelObservation ------------------------------------------------------ // A class which observes a `HoldingSpaceModel` within its lifetime. Note that @@ -85,6 +96,14 @@ return result; } + // Returns the id's of `HoldingSpaceItem`s for which + // `OnHoldingSpaceItemRemoved()` was called. Also clears the cached values. + std::vector<std::string> TakeRemovedItems() { + std::vector<std::string> result; + result.swap(removed_item_ids_); + return result; + } + private: // HoldingSpaceModel::Observer: void OnHoldingSpaceItemUpdated(const HoldingSpaceItem* item, @@ -94,6 +113,12 @@ ++updated_item_count_; } + void OnHoldingSpaceItemsRemoved( + const std::vector<const HoldingSpaceItem*>& items) override { + for (const HoldingSpaceItem* item : items) + removed_item_ids_.push_back(item->id()); + } + // The last `HoldingSpaceItem` for which `OnHoldingSpaceItemUpdated()` was // called. May be `nullptr` prior to an update event or following a call to // `TakeLastUpdatedItem()`. @@ -108,29 +133,54 @@ // be reset following a call to `TakeUpdatedItemCount()`. int updated_item_count_ = 0; + // A vector of item id's that have been removed. + std::vector<std::string> removed_item_ids_; + base::ScopedObservation<HoldingSpaceModel, HoldingSpaceModelObserver> observation_{this}; }; } // namespace +// Print out the `HoldingSpaceItem::Type` in the test output. +std::ostream& operator<<(std::ostream& os, const HoldingSpaceItem::Type type) { + return os << holding_space_util::ToString(type); +} + // HoldingSpaceModelTest ------------------------------------------------------- // Base class for `HoldingSpaceModel` tests, parameterized by the set of all // holding space item types. class HoldingSpaceModelTest - : public testing::TestWithParam<HoldingSpaceItem::Type> { + : public testing::TestWithParam<std::tuple<HoldingSpaceItem::Type, bool>> { public: + HoldingSpaceModelTest() { + scoped_feature_list_.InitWithFeatureState( + features::kHoldingSpacePredictability, + IsHoldingSpacePredictabilityEnabled()); + } + // Returns the `HoldingSpaceModel` under test. HoldingSpaceModel& model() { return model_; } + bool IsHoldingSpacePredictabilityEnabled() const { + return std::get<1>(GetParam()); + } + + HoldingSpaceItem::Type GetHoldingSpaceItemType() { + return std::get<0>(GetParam()); + } + private: HoldingSpaceModel model_; + base::test::ScopedFeatureList scoped_feature_list_; }; -INSTANTIATE_TEST_SUITE_P(All, - HoldingSpaceModelTest, - testing::ValuesIn(GetHoldingSpaceItemTypes())); +INSTANTIATE_TEST_SUITE_P( + All, + HoldingSpaceModelTest, + testing::Combine(testing::ValuesIn(GetHoldingSpaceItemTypes()), + testing::Bool())); // Tests ----------------------------------------------------------------------- @@ -143,7 +193,7 @@ // Create a holding space `item`. auto item = HoldingSpaceItem::CreateFileBackedItem( - /*type=*/GetParam(), base::FilePath("file_path"), + /*type=*/GetHoldingSpaceItemType(), base::FilePath("file_path"), GURL("filesystem::file_system_url"), HoldingSpaceProgress(/*current_bytes=*/0, /*total_bytes=*/100), /*image_resolver=*/base::BindOnce(&CreateFakeHoldingSpaceImage)); @@ -220,7 +270,7 @@ // Create a holding space `item`. auto item = HoldingSpaceItem::CreateFileBackedItem( - /*type=*/GetParam(), base::FilePath("file_path"), + /*type=*/GetHoldingSpaceItemType(), base::FilePath("file_path"), GURL("filesystem::file_system_url"), HoldingSpaceProgress(/*current_bytes=*/0, /*total_bytes=*/100), /*image_resolver=*/base::BindOnce(&CreateFakeHoldingSpaceImage)); @@ -340,7 +390,7 @@ // Create a holding space `item`. auto item = HoldingSpaceItem::CreateFileBackedItem( - /*type=*/GetParam(), base::FilePath("file_path"), + /*type=*/GetHoldingSpaceItemType(), base::FilePath("file_path"), GURL("filesystem::file_system_url"), HoldingSpaceProgress(), /*image_resolver=*/base::BindOnce(&CreateFakeHoldingSpaceImage)); auto* item_ptr = item.get(); @@ -376,7 +426,7 @@ // Create an in-progress holding space `item`. auto item = HoldingSpaceItem::CreateFileBackedItem( - /*type=*/GetParam(), base::FilePath("file_path"), + /*type=*/GetHoldingSpaceItemType(), base::FilePath("file_path"), GURL("filesystem::file_system_url"), HoldingSpaceProgress(/*current_bytes=*/0, /*total_bytes=*/100), /*image_resolver=*/base::BindOnce(&CreateFakeHoldingSpaceImage)); @@ -452,7 +502,7 @@ // Create a holding space `item`. auto item = HoldingSpaceItem::CreateFileBackedItem( - /*type=*/GetParam(), base::FilePath("file_path"), + /*type=*/GetHoldingSpaceItemType(), base::FilePath("file_path"), GURL("filesystem::file_system_url"), HoldingSpaceProgress(/*current_bytes=*/absl::nullopt, /*total_bytes=*/100), @@ -514,4 +564,54 @@ EXPECT_TRUE(item_ptr->progress().IsComplete()); } +TEST_P(HoldingSpaceModelTest, + AddingItemsPushesOutOldestItemsWhenMaxItemsPerSectionReached) { + ScopedModelObservation observation(&model()); + + // Verify the `model()` is initially empty. + EXPECT_EQ(model().items().size(), 0u); + + // Add 2 items and store their id's to assert that they were deleted later. + auto first_item = CreateItem(GetHoldingSpaceItemType()); + std::string first_item_id = first_item.get()->id(); + model().AddItem(std::move(first_item)); + auto second_item = CreateItem(GetHoldingSpaceItemType()); + std::string second_item_id = second_item.get()->id(); + model().AddItem(std::move(second_item)); + + // Starting at index 2, add more items up to `kMaxItemsPerSection`. + for (size_t i = 2; i < kMaxItemsPerSection; ++i) { + // Add `item` to the `model()`. + model().AddItem(CreateItem(GetHoldingSpaceItemType())); + } + // Verify we've reached the limit of `items` in the model. + EXPECT_EQ(model().items().size(), kMaxItemsPerSection); + + // Add 2 more `item`s which takes us to `kMaxItemsPerSection` + 2. + constexpr int kExtraItems = 2; + for (int i = 0; i < kExtraItems; ++i) + model().AddItem(CreateItem(GetHoldingSpaceItemType())); + + // If the `type` is contained inside the screen capture or downloads + // sections and the feature flag is enabled, then assert that we have no more + // than the `kMaxItemsPerSection` and that the oldest item(s) were deleted. + if (IsHoldingSpacePredictabilityEnabled() && + (holding_space_util::IsDownloadType(GetHoldingSpaceItemType()) || + holding_space_util::IsScreenCaptureType(GetHoldingSpaceItemType()))) { + EXPECT_EQ(model().items().size(), kMaxItemsPerSection); + EXPECT_EQ(model().GetItem(first_item_id), nullptr); + EXPECT_EQ(model().GetItem(second_item_id), nullptr); + EXPECT_THAT(observation.TakeRemovedItems(), + testing::ElementsAre(first_item_id, second_item_id)); + } else { + // If the `type` is not contained inside the screen capture or downloads + // section buckets or the feature flag is disabled then we expect to exceed + // the `kMaxItemsPerSection` and not delete anything. + EXPECT_EQ(model().items().size(), kMaxItemsPerSection + kExtraItems); + EXPECT_TRUE(model().GetItem(first_item_id)); + EXPECT_TRUE(model().GetItem(second_item_id)); + EXPECT_TRUE(observation.TakeRemovedItems().empty()); + } +} + } // namespace ash
diff --git a/ash/public/cpp/holding_space/holding_space_util.cc b/ash/public/cpp/holding_space/holding_space_util.cc index 0401d7a..63b69ed 100644 --- a/ash/public/cpp/holding_space/holding_space_util.cc +++ b/ash/public/cpp/holding_space/holding_space_util.cc
@@ -101,4 +101,28 @@ } } +std::set<HoldingSpaceItem::Type> DownloadSupportedTypes() { + return {HoldingSpaceItem::Type::kArcDownload, + HoldingSpaceItem::Type::kDiagnosticsLog, + HoldingSpaceItem::Type::kDownload, + HoldingSpaceItem::Type::kLacrosDownload, + HoldingSpaceItem::Type::kNearbyShare, + HoldingSpaceItem::Type::kPrintedPdf, + HoldingSpaceItem::Type::kScan, + HoldingSpaceItem::Type::kPhoneHubCameraRoll}; +} + +std::set<HoldingSpaceItem::Type> ScreenCaptureSupportedTypes() { + return {HoldingSpaceItem::Type::kScreenshot, + HoldingSpaceItem::Type::kScreenRecording}; +} + +bool IsDownloadType(HoldingSpaceItem::Type item_type) { + return base::Contains(DownloadSupportedTypes(), item_type); +} + +bool IsScreenCaptureType(HoldingSpaceItem::Type item_type) { + return base::Contains(ScreenCaptureSupportedTypes(), item_type); +} + } // namespace ash::holding_space_util
diff --git a/ash/public/cpp/holding_space/holding_space_util.h b/ash/public/cpp/holding_space/holding_space_util.h index 6b73f2994..2ee55f7 100644 --- a/ash/public/cpp/holding_space/holding_space_util.h +++ b/ash/public/cpp/holding_space/holding_space_util.h
@@ -5,6 +5,7 @@ #ifndef ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_UTIL_H_ #define ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_UTIL_H_ +#include <set> #include <string> #include "ash/public/cpp/ash_public_export.h" @@ -39,6 +40,15 @@ // Returns the string representation of the specified holding space item `type`. ASH_PUBLIC_EXPORT std::string ToString(HoldingSpaceItem::Type type); +ASH_PUBLIC_EXPORT std::set<HoldingSpaceItem::Type> DownloadSupportedTypes(); + +ASH_PUBLIC_EXPORT std::set<HoldingSpaceItem::Type> +ScreenCaptureSupportedTypes(); + +ASH_PUBLIC_EXPORT bool IsDownloadType(HoldingSpaceItem::Type item_type); + +ASH_PUBLIC_EXPORT bool IsScreenCaptureType(HoldingSpaceItem::Type item_type); + } // namespace holding_space_util } // namespace ash
diff --git a/ash/public/cpp/privacy_hub_delegate.h b/ash/public/cpp/privacy_hub_delegate.h new file mode 100644 index 0000000..b0893b8e --- /dev/null +++ b/ash/public/cpp/privacy_hub_delegate.h
@@ -0,0 +1,32 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_PUBLIC_CPP_PRIVACY_HUB_DELEGATE_H_ +#define ASH_PUBLIC_CPP_PRIVACY_HUB_DELEGATE_H_ + +#include "base/values.h" + +namespace cros::mojom { +enum class CameraPrivacySwitchState : int32_t; +} + +namespace ash { + +// This class serves as a callback into webui for Privacy Hub backend in +// //ash/system. +class PrivacyHubDelegate { + public: + // Signals that the availability of microphone changed + virtual void AvailabilityOfMicrophoneChanged( + bool has_active_input_device) = 0; + // Signals that the state of the microphone hardware toggle changed + virtual void MicrophoneHardwareToggleChanged(bool muted) = 0; + // Signals that the state of the camera hardware toggle changed + virtual void CameraHardwareToggleChanged( + cros::mojom::CameraPrivacySwitchState state) = 0; +}; + +} // namespace ash + +#endif // ASH_PUBLIC_CPP_PRIVACY_HUB_DELEGATE_H_
diff --git a/ash/public/cpp/views_text_services_context_menu_impl.cc b/ash/public/cpp/views_text_services_context_menu_impl.cc index ac4ff373..74e87ca 100644 --- a/ash/public/cpp/views_text_services_context_menu_impl.cc +++ b/ash/public/cpp/views_text_services_context_menu_impl.cc
@@ -94,10 +94,6 @@ const size_t target_index = index_of_paste.value() + 1; menu->InsertItemAt(target_index, IDS_APP_SHOW_CLIPBOARD_HISTORY, l10n_util::GetStringUTF16(IDS_APP_SHOW_CLIPBOARD_HISTORY)); - if (ClipboardHistoryController::Get()->ShouldShowNewFeatureBadge()) { - menu->SetIsNewFeatureAt(target_index, true); - ClipboardHistoryController::Get()->MarkNewFeatureBadgeShown(); - } } } // namespace ash
diff --git a/ash/services/ime/public/cpp/BUILD.gn b/ash/services/ime/public/cpp/BUILD.gn index 41c40a4..8d84679 100644 --- a/ash/services/ime/public/cpp/BUILD.gn +++ b/ash/services/ime/public/cpp/BUILD.gn
@@ -31,6 +31,8 @@ "rulebased/def/fa.h", "rulebased/def/gu_phone.cc", "rulebased/def/gu_phone.h", + "rulebased/def/hi_inscript.cc", + "rulebased/def/hi_inscript.h", "rulebased/def/km.cc", "rulebased/def/km.h", "rulebased/def/kn_phone.cc",
diff --git a/ash/services/ime/public/cpp/rulebased/def/hi_inscript.cc b/ash/services/ime/public/cpp/rulebased/def/hi_inscript.cc new file mode 100644 index 0000000..59d827e6 --- /dev/null +++ b/ash/services/ime/public/cpp/rulebased/def/hi_inscript.cc
@@ -0,0 +1,278 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/services/ime/public/cpp/rulebased/def/hi_inscript.h" + +namespace hi_inscript { + +const char* kId = "hi_inscript"; +bool kIs102 = false; + +const char* kNormal[] = { + "\u094a", // BackQuote : ॊ + "1", // Digit1 + "2", // Digit2 + "3", // Digit3 + "4", // Digit4 + "5", // Digit5 + "6", // Digit6 + "7", // Digit7 + "8", // Digit8 + "9", // Digit9 + "0", // Digit0 + "-", // Minus + "\u0943", // Equal : ृ + "\u094c", // KeyQ : ौ + "\u0948", // KeyW : ै + "\u093e", // KeyE : ा + "\u0940", // KeyR : ी + "\u0942", // KeyT : ू + "\u092c", // KeyY : ब + "\u0939", // KeyU : ह + "\u0917", // KeyI : ग + "\u0926", // KeyO : द + "\u091c", // KeyP : ज + "\u0921", // BracketLeft : ड + "\u093c", // BracketRight : ़ + "\u0949", // Backslash : ॉ + "\u094b", // KeyA : ो + "\u0947", // KeyS : े + "\u094d", // KeyD : ् + "\u093f", // KeyF : ि + "\u0941", // KeyG : ु + "\u092a", // KeyH : प + "\u0930", // KeyJ : र + "\u0915", // KeyK : क + "\u0924", // KeyL : त + "\u091a", // Semicolon : च + "\u091f", // Quote : ट + "\u0946", // KeyZ : ॆ + "\u0902", // KeyX : ं + "\u092e", // KeyC : म + "\u0928", // KeyV : न + "\u0935", // KeyB : व + "\u0932", // KeyN : ल + "\u0938", // KeyM : स + ",", // Comma + ".", // Period + "\u092f", // Slash : य + "\u0020", // Space +}; + +const char* kShift[] = { + "\u0912", // BackQuote : ऒ + "\u090d", // Digit1 : ऍ + "\u0945", // Digit2 : ॅ + "\u094d\u0930", // Digit3 : ्र + "\u0930\u094d", // Digit4 : र् + "\u091c\u094d\u091e", // Digit5 : ज्ञ + "\u0924\u094d\u0930", // Digit6 : त्र + "\u0915\u094d\u0937", // Digit7 : क्ष + "\u0936\u094d\u0930", // Digit8 : श्र + "(", // Digit9 + ")", // Digit0 + "\u0903", // Minus : ः + "\u090b", // Equal : ऋ + "\u0914", // KeyQ : औ + "\u0910", // KeyW : ऐ + "\u0906", // KeyE : आ + "\u0908", // KeyR : ई + "\u090a", // KeyT : ऊ + "\u092d", // KeyY : भ + "\u0919", // KeyU : ङ + "\u0918", // KeyI : घ + "\u0927", // KeyO : ध + "\u091d", // KeyP : झ + "\u0922", // BracketLeft : ढ + "\u091e", // BracketRight : ञ + "\u0911", // Backslash : ऑ + "\u0913", // KeyA : ओ + "\u090f", // KeyS : ए + "\u0905", // KeyD : अ + "\u0907", // KeyF : इ + "\u0909", // KeyG : उ + "\u092b", // KeyH : फ + "\u0931", // KeyJ : ऱ + "\u0916", // KeyK : ख + "\u0925", // KeyL : थ + "\u091b", // Semicolon : छ + "\u0920", // Quote : ठ + "\u090e", // KeyZ : ऎ + "\u0901", // KeyX : ँ + "\u0923", // KeyC : ण + "\u0929", // KeyV : ऩ + "\u0934", // KeyB : ऴ + "\u0933", // KeyN : ळ + "\u0936", // KeyM : श + "\u0937", // Comma : ष + "\u0964", // Period : । + "\u095f", // Slash : य़ = <U+092F, U+093C> + "\u0020", // Space +}; + +// For some keys, AltGr+Key combinations do not work when they're 'hijacked' by +// OS shortcuts (Alt+Key). For instance, AltGr+F is treated as Alt+F and +// the file browser opens instead of producing U+0962. +// See crbug.com/1354988 (b/243243592) +const char* kAltGr[] = { + "", // BackQuote + "\u200d", // Digit1 : ZWJ + "\u200c", // Digit2 : ZWNJ + "", // Digit3 + "\u20b9", // Digit4 : ₹(Rupee sign) + "", // Digit5 + "", // Digit6 + "", // Digit7 + "", // Digit8 + "", // Digit9 + "", // Digit0 + "", // Minus + "\u0944", // Equal : ॄ + "", // KeyQ + "", // KeyW + "", // KeyE + "\u0963", // KeyR : ॣ + "", // KeyT + "", // KeyY + "", // KeyU + "\u095a", // KeyI : ग़ = <U+0917, U+093C> + "", // KeyO + "\u095b", // KeyP : ज़ = <U+091C, U+093C> + "\u095c", // BracketLeft : ड़ = <U+0921, U+093C> + "", // BracketRight + "", // Backslash + "", // KeyA + "", // KeyS + "", // KeyD + "\u0962", // KeyF : ॢ + "", // KeyG + "", // KeyH + "", // KeyJ + "\u0958", // KeyK : क़ = <U+0915, U+093C> + "", // KeyL + "", // Semicolon + "", // Quote + "", // KeyZ + "", // KeyX + "", // KeyC + "", // KeyV + "", // KeyB + "", // KeyN + "", // KeyM + "\u0970", // Comma : ॰ + "\u0965", // Period : ॥ + "", // Slash + "", // Space +}; + +const char* kShiftAltGr[] = { + "", // BackQuote + "", // Digit1 + "", // Digit2 + "", // Digit3 + "", // Digit4 + "", // Digit5 + "", // Digit6 + "", // Digit7 + "", // Digit8 + "", // Digit9 + "", // Digit0 + "", // Minus + "\u0960", // Equal : ॠ + "", // KeyQ + "", // KeyW + "", // KeyE + "\u0961", // KeyR : ॡ + "", // KeyT + "", // KeyY + "", // KeyU + "", // KeyI + "", // KeyO + "", // KeyP + "\u095d", // BracketLeft : ढ़ = <U+0922, U+093C> + "", // BracketRight + "", // Backslash + "", // KeyA + "", // KeyS + "", // KeyD + "\u090c", // KeyF : ऌ + "", // KeyG + "\u095e", // KeyH : फ़ = <U+092B, U+093C> + "", // KeyJ + "\u0959", // KeyK : ख़ = <U+0916, U+093C> + "", // KeyL + "", // Semicolon + "", // Quote + "", // KeyZ + "\u0950", // KeyX : ॐ + "", // KeyC + "", // KeyV + "", // KeyB + "", // KeyN + "", // KeyM + "", // Comma + "\u093d", // Period : ऽ + "", // Slash + "", // Space +}; + +// Capslock is identical to Normal (no modifier state) except that it +// is used to type Devanagari digits, U+0966 - U+096f. +const char* kCapslock[] = { + "\u094a", // BackQuote : ॊ + "\u0967", // Digit1 : १ + "\u0968", // Digit2 : २ + "\u0969", // Digit3 : ३ + "\u096a", // Digit4 : ४ + "\u096b", // Digit5 : ५ + "\u096c", // Digit6 : ६ + "\u096d", // Digit7 : ७ + "\u096e", // Digit8 : ८ + "\u096f", // Digit9 : ९ + "\u0966", // Digit0 : ० + "-", // Minus + "\u0943", // Equal : ृ + "\u094c", // KeyQ : ौ + "\u0948", // KeyW : ै + "\u093e", // KeyE : ा + "\u0940", // KeyR : ी + "\u0942", // KeyT : ू + "\u092c", // KeyY : ब + "\u0939", // KeyU : ह + "\u0917", // KeyI : ग + "\u0926", // KeyO : द + "\u091c", // KeyP : ज + "\u0921", // BracketLeft : ड + "\u093c", // BracketRight : ़ + "\u0949", // Backslash : ॉ + "\u094b", // KeyA : ो + "\u0947", // KeyS : े + "\u094d", // KeyD : ् + "\u093f", // KeyF : ि + "\u0941", // KeyG : ु + "\u092a", // KeyH : प + "\u0930", // KeyJ : र + "\u0915", // KeyK : क + "\u0924", // KeyL : त + "\u091a", // Semicolon : च + "\u091f", // Quote : ट + "\u0946", // KeyZ : ॆ + "\u0902", // KeyX : ं + "\u092e", // KeyC : म + "\u0928", // KeyV : न + "\u0935", // KeyB : व + "\u0932", // KeyN : ल + "\u0938", // KeyM : स + ",", // Comma + ".", // Period + "\u092f", // Slash : य + "\u0020", // Space +}; + +// Note that Capslock + {Shift, AltGr, Shift+AltGr} are identical to those +// without Capslock. +const char** kKeyMap[8] = {kNormal, kShift, kAltGr, kShiftAltGr, + kCapslock, kShift, kAltGr, kShiftAltGr}; + +} // namespace hi_inscript
diff --git a/ash/services/ime/public/cpp/rulebased/def/hi_inscript.h b/ash/services/ime/public/cpp/rulebased/def/hi_inscript.h new file mode 100644 index 0000000..b883492 --- /dev/null +++ b/ash/services/ime/public/cpp/rulebased/def/hi_inscript.h
@@ -0,0 +1,21 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_HI_INSCRIPT_H_ +#define ASH_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_HI_INSCRIPT_H_ + +namespace hi_inscript { + +// The id of this IME/keyboard. +extern const char* kId; + +// Whether this keyboard layout is a 102 or 101 keyboard. +extern bool kIs102; + +// The key mapping definitions under various modifier states. +extern const char** kKeyMap[8]; + +} // namespace hi_inscript + +#endif // ASH_SERVICES_IME_PUBLIC_CPP_RULEBASED_DEF_HI_INSCRIPT_H_
diff --git a/ash/services/ime/public/cpp/rulebased/rules_data.cc b/ash/services/ime/public/cpp/rulebased/rules_data.cc index e9eb066..981c757 100644 --- a/ash/services/ime/public/cpp/rulebased/rules_data.cc +++ b/ash/services/ime/public/cpp/rulebased/rules_data.cc
@@ -12,6 +12,7 @@ #include "ash/services/ime/public/cpp/rulebased/def/ethi.h" #include "ash/services/ime/public/cpp/rulebased/def/fa.h" #include "ash/services/ime/public/cpp/rulebased/def/gu_phone.h" +#include "ash/services/ime/public/cpp/rulebased/def/hi_inscript.h" #include "ash/services/ime/public/cpp/rulebased/def/km.h" #include "ash/services/ime/public/cpp/rulebased/def/kn_phone.h" #include "ash/services/ime/public/cpp/rulebased/def/lo.h" @@ -87,6 +88,8 @@ {gu_phone::kId, RawDataEntry(gu_phone::kKeyMap, gu_phone::kIs102, gu_phone::kTransforms, gu_phone::kTransformsLen, gu_phone::kHistoryPrune)}, + {hi_inscript::kId, + RawDataEntry(hi_inscript::kKeyMap, hi_inscript::kIs102)}, {km::kId, RawDataEntry(km::kKeyMap, km::kIs102)}, {kn_phone::kId, RawDataEntry(us::kKeyMap, us::kIs102, kn_phone::kTransforms,
diff --git a/ash/system/holding_space/downloads_section.cc b/ash/system/holding_space/downloads_section.cc index f18d45e..ef1da8d7 100644 --- a/ash/system/holding_space/downloads_section.cc +++ b/ash/system/holding_space/downloads_section.cc
@@ -10,6 +10,7 @@ #include "ash/public/cpp/holding_space/holding_space_constants.h" #include "ash/public/cpp/holding_space/holding_space_controller.h" #include "ash/public/cpp/holding_space/holding_space_metrics.h" +#include "ash/public/cpp/holding_space/holding_space_util.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_provider.h" @@ -109,17 +110,9 @@ // DownloadsSection ------------------------------------------------------------ DownloadsSection::DownloadsSection(HoldingSpaceViewDelegate* delegate) - : HoldingSpaceItemViewsSection( - delegate, - /*supported_types=*/ - {HoldingSpaceItem::Type::kArcDownload, - HoldingSpaceItem::Type::kDiagnosticsLog, - HoldingSpaceItem::Type::kDownload, - HoldingSpaceItem::Type::kLacrosDownload, - HoldingSpaceItem::Type::kNearbyShare, - HoldingSpaceItem::Type::kPrintedPdf, HoldingSpaceItem::Type::kScan, - HoldingSpaceItem::Type::kPhoneHubCameraRoll}, - /*max_count=*/kMaxDownloads) {} + : HoldingSpaceItemViewsSection(delegate, + holding_space_util::DownloadSupportedTypes(), + /*max_count=*/kMaxDownloads) {} DownloadsSection::~DownloadsSection() = default;
diff --git a/ash/system/holding_space/screen_captures_section.cc b/ash/system/holding_space/screen_captures_section.cc index 97185c44..d27cdc2 100644 --- a/ash/system/holding_space/screen_captures_section.cc +++ b/ash/system/holding_space/screen_captures_section.cc
@@ -7,6 +7,7 @@ #include "ash/bubble/bubble_utils.h" #include "ash/public/cpp/holding_space/holding_space_constants.h" #include "ash/public/cpp/holding_space/holding_space_item.h" +#include "ash/public/cpp/holding_space/holding_space_util.h" #include "ash/strings/grit/ash_strings.h" #include "ash/system/holding_space/holding_space_item_screen_capture_view.h" #include "ui/base/l10n/l10n_util.h" @@ -19,11 +20,10 @@ namespace ash { ScreenCapturesSection::ScreenCapturesSection(HoldingSpaceViewDelegate* delegate) - : HoldingSpaceItemViewsSection(delegate, - /*supported_types=*/ - {HoldingSpaceItem::Type::kScreenshot, - HoldingSpaceItem::Type::kScreenRecording}, - /*max_count=*/kMaxScreenCaptures) {} + : HoldingSpaceItemViewsSection( + delegate, + holding_space_util::ScreenCaptureSupportedTypes(), + /*max_count=*/kMaxScreenCaptures) {} ScreenCapturesSection::~ScreenCapturesSection() = default;
diff --git a/ash/system/holding_space/screen_captures_section.h b/ash/system/holding_space/screen_captures_section.h index 2b47e85..9038efd88 100644 --- a/ash/system/holding_space/screen_captures_section.h +++ b/ash/system/holding_space/screen_captures_section.h
@@ -7,6 +7,7 @@ #include <memory> +#include "ash/public/cpp/holding_space/holding_space_item.h" #include "ash/system/holding_space/holding_space_item_views_section.h" namespace ash {
diff --git a/ash/system/privacy_hub/camera_privacy_switch_controller.cc b/ash/system/privacy_hub/camera_privacy_switch_controller.cc index 057c7c0..1318d818 100644 --- a/ash/system/privacy_hub/camera_privacy_switch_controller.cc +++ b/ash/system/privacy_hub/camera_privacy_switch_controller.cc
@@ -10,6 +10,7 @@ #include "ash/public/cpp/session/session_observer.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" +#include "ash/system/privacy_hub/privacy_hub_controller.h" #include "base/bind.h" #include "base/check.h" #include "components/prefs/pref_service.h" @@ -49,12 +50,18 @@ } // namespace CameraPrivacySwitchController::CameraPrivacySwitchController() - : switch_api_(std::make_unique<VCDPrivacyAdapter>()) { + : switch_api_(std::make_unique<VCDPrivacyAdapter>()), + camera_privacy_switch_state_(media::CameraHalDispatcherImpl::GetInstance() + ->AddCameraPrivacySwitchObserver(this)) + +{ Shell::Get()->session_controller()->AddObserver(this); } CameraPrivacySwitchController::~CameraPrivacySwitchController() { Shell::Get()->session_controller()->RemoveObserver(this); + media::CameraHalDispatcherImpl::GetInstance() + ->RemoveCameraPrivacySwitchObserver(this); } void CameraPrivacySwitchController::OnActiveUserPrefServiceChanged( @@ -91,4 +98,19 @@ switch_api_ = std::move(switch_api); } +void CameraPrivacySwitchController::OnCameraHWPrivacySwitchStatusChanged( + int32_t camera_id, + cros::mojom::CameraPrivacySwitchState state) { + camera_privacy_switch_state_ = state; + Shell::Get() + ->privacy_hub_controller() + ->frontend() + .CameraHardwareToggleChanged(state); +} + +cros::mojom::CameraPrivacySwitchState +CameraPrivacySwitchController::HWSwitchState() const { + return camera_privacy_switch_state_; +} + } // namespace ash
diff --git a/ash/system/privacy_hub/camera_privacy_switch_controller.h b/ash/system/privacy_hub/camera_privacy_switch_controller.h index 5eabc22..0ac414e 100644 --- a/ash/system/privacy_hub/camera_privacy_switch_controller.h +++ b/ash/system/privacy_hub/camera_privacy_switch_controller.h
@@ -11,6 +11,7 @@ #include "ash/ash_export.h" #include "ash/public/cpp/session/session_observer.h" #include "components/prefs/pref_change_registrar.h" +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" namespace ash { @@ -30,7 +31,9 @@ // It listens on both ends and changes UI to reflect changes in // the backend and notifies the backend of changes in the user // preference setting. -class ASH_EXPORT CameraPrivacySwitchController : public SessionObserver { +class ASH_EXPORT CameraPrivacySwitchController + : public SessionObserver, + public media::CameraPrivacySwitchObserver { public: CameraPrivacySwitchController(); @@ -43,9 +46,18 @@ // SessionObserver: void OnActiveUserPrefServiceChanged(PrefService* pref_service) override; + // media::CameraPrivacySwitchObserver + void OnCameraHWPrivacySwitchStatusChanged( + int32_t camera_id, + cros::mojom::CameraPrivacySwitchState state) override; + // Handles user toggling the camera switch on Privacy Hub UI. void OnPreferenceChanged(const std::string& pref_name); + // Returns the last observed HW switch state for the camera. + cros::mojom::CameraPrivacySwitchState HWSwitchState() const; + + // Sets Privacy switch API for testing void SetCameraPrivacySwitchAPIForTest( std::unique_ptr<CameraPrivacySwitchAPI> switch_api); @@ -55,6 +67,7 @@ std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; std::unique_ptr<CameraPrivacySwitchAPI> switch_api_; + cros::mojom::CameraPrivacySwitchState camera_privacy_switch_state_; }; } // namespace ash
diff --git a/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc b/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc index 8f9ad28..a3f18b5 100644 --- a/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc +++ b/ash/system/privacy_hub/camera_privacy_switch_controller_unittest.cc
@@ -22,6 +22,8 @@ namespace ash { +namespace { + class MockSwitchAPI : public CameraPrivacySwitchAPI { public: MOCK_METHOD(void, @@ -30,6 +32,18 @@ (override)); }; +class MockFrontendAPI : public PrivacyHubDelegate { + public: + MOCK_METHOD(void, + CameraHardwareToggleChanged, + (cros::mojom::CameraPrivacySwitchState state), + (override)); + void AvailabilityOfMicrophoneChanged(bool) override {} + void MicrophoneHardwareToggleChanged(bool) override {} +}; + +} // namespace + class PrivacyHubCameraControllerTests : public AshTestBase { protected: PrivacyHubCameraControllerTests() { @@ -48,11 +62,12 @@ auto mock_switch = std::make_unique<::testing::NiceMock<MockSwitchAPI>>(); mock_switch_ = mock_switch.get(); - controller_ = - Shell::Get()->privacy_hub_controller()->CameraControllerForTest(); + Shell::Get()->privacy_hub_controller()->set_frontend(&mock_frontend_); + controller_ = &Shell::Get()->privacy_hub_controller()->camera_controller(); controller_->SetCameraPrivacySwitchAPIForTest(std::move(mock_switch)); } + ::testing::NiceMock<MockFrontendAPI> mock_frontend_; ::testing::NiceMock<MockSwitchAPI>* mock_switch_; CameraPrivacySwitchController* controller_; base::test::ScopedFeatureList scoped_feature_list_; @@ -88,4 +103,15 @@ } } +TEST_F(PrivacyHubCameraControllerTests, OnCameraHardwarePrivacySwitchChanged) { + EXPECT_CALL(mock_frontend_, CameraHardwareToggleChanged( + cros::mojom::CameraPrivacySwitchState::OFF)); + CameraPrivacySwitchController& controller = + Shell::Get()->privacy_hub_controller()->camera_controller(); + controller.OnCameraHWPrivacySwitchStatusChanged( + 0, cros::mojom::CameraPrivacySwitchState::OFF); + EXPECT_EQ(cros::mojom::CameraPrivacySwitchState::OFF, + controller.HWSwitchState()); +} + } // namespace ash
diff --git a/ash/system/privacy_hub/microphone_privacy_switch_controller.cc b/ash/system/privacy_hub/microphone_privacy_switch_controller.cc index 46b6b74..7408307e 100644 --- a/ash/system/privacy_hub/microphone_privacy_switch_controller.cc +++ b/ash/system/privacy_hub/microphone_privacy_switch_controller.cc
@@ -10,6 +10,7 @@ #include "ash/public/cpp/session/session_observer.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" +#include "ash/system/privacy_hub/privacy_hub_controller.h" #include "base/bind.h" #include "chromeos/ash/components/audio/cras_audio_handler.h" #include "components/prefs/pref_service.h" @@ -18,11 +19,13 @@ MicrophonePrivacySwitchController::MicrophonePrivacySwitchController() { Shell::Get()->session_controller()->AddObserver(this); + ui::MicrophoneMuteSwitchMonitor::Get()->AddObserver(this); CrasAudioHandler::Get()->AddAudioObserver(this); } MicrophonePrivacySwitchController::~MicrophonePrivacySwitchController() { Shell::Get()->session_controller()->RemoveObserver(this); + ui::MicrophoneMuteSwitchMonitor::Get()->RemoveObserver(this); CrasAudioHandler::Get()->RemoveAudioObserver(this); } @@ -72,4 +75,20 @@ } } +void MicrophonePrivacySwitchController::OnAudioNodesChanged() { + Shell::Get() + ->privacy_hub_controller() + ->frontend() + .AvailabilityOfMicrophoneChanged( + CrasAudioHandler::Get()->HasActiveInputDeviceForSimpleUsage()); +} + +void MicrophonePrivacySwitchController::OnMicrophoneMuteSwitchValueChanged( + bool muted) { + Shell::Get() + ->privacy_hub_controller() + ->frontend() + .MicrophoneHardwareToggleChanged(muted); +} + } // namespace ash
diff --git a/ash/system/privacy_hub/microphone_privacy_switch_controller.h b/ash/system/privacy_hub/microphone_privacy_switch_controller.h index 1cdb784..ec674a79 100644 --- a/ash/system/privacy_hub/microphone_privacy_switch_controller.h +++ b/ash/system/privacy_hub/microphone_privacy_switch_controller.h
@@ -11,13 +11,15 @@ #include "ash/public/cpp/session/session_observer.h" #include "chromeos/ash/components/audio/cras_audio_handler.h" #include "components/prefs/pref_change_registrar.h" +#include "ui/events/devices/microphone_mute_switch_monitor.h" namespace ash { // This controller keeps the KUserMicrophoneAllowed preference and the state of // the system input mute in sync. class ASH_EXPORT MicrophonePrivacySwitchController - : public CrasAudioHandler::AudioObserver, + : public ui::MicrophoneMuteSwitchMonitor::Observer, + public CrasAudioHandler::AudioObserver, public SessionObserver { public: MicrophonePrivacySwitchController(); @@ -28,12 +30,18 @@ MicrophonePrivacySwitchController& operator=( const MicrophonePrivacySwitchController&) = delete; - // SessionObserver: + // SessionObserver void OnActiveUserPrefServiceChanged(PrefService* pref_service) override; - // CrasAudioHandler::AudioObserver: + // CrasAudioHandler::AudioObserver void OnInputMuteChanged(bool mute_on) override; + // CrasAudioHandler::AudioObserver + void OnAudioNodesChanged() override; + + // ui::MicrophoneMuteSwitchMonitor::Observer + void OnMicrophoneMuteSwitchValueChanged(bool muted) override; + private: // A callback that is invoked when the user changes KUserMicrophoneAllowed // preference from the Privacy Hub UI.
diff --git a/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc b/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc index 621a5cf..cbf476c 100644 --- a/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc +++ b/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc
@@ -6,15 +6,21 @@ #include "ash/constants/ash_pref_names.h" #include "ash/public/cpp/microphone_mute_notification_delegate.h" +#include "ash/public/cpp/privacy_hub_delegate.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" +#include "ash/system/privacy_hub/privacy_hub_controller.h" #include "ash/test/ash_test_base.h" #include "base/test/scoped_feature_list.h" #include "chromeos/ash/components/audio/cras_audio_handler.h" #include "components/account_id/account_id.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" namespace ash { +using testing::_; + namespace { class FakeMicrophoneMuteNotificationDelegate @@ -25,14 +31,22 @@ } }; +class MockFrontendAPI : public PrivacyHubDelegate { + public: + MOCK_METHOD(void, AvailabilityOfMicrophoneChanged, (bool), (override)); + MOCK_METHOD(void, MicrophoneHardwareToggleChanged, (bool), (override)); + void CameraHardwareToggleChanged( + cros::mojom::CameraPrivacySwitchState state) override {} +}; + } // namespace -class MicrophonePrivacySwitchControllerTest : public AshTestBase { +class PrivacyHubMicrophoneControllerTest : public AshTestBase { public: - MicrophonePrivacySwitchControllerTest() { + PrivacyHubMicrophoneControllerTest() { scoped_feature_list_.InitAndEnableFeature(ash::features::kCrosPrivacyHub); } - ~MicrophonePrivacySwitchControllerTest() override = default; + ~PrivacyHubMicrophoneControllerTest() override = default; // AshTestBase: void SetUp() override { @@ -41,6 +55,7 @@ // This makes sure a global instance of MicrophoneMuteNotificationDelegate // is created before running tests. delegate_ = std::make_unique<FakeMicrophoneMuteNotificationDelegate>(); + Shell::Get()->privacy_hub_controller()->set_frontend(&mock_frontend_); } protected: @@ -56,12 +71,14 @@ ->GetBoolean(prefs::kUserMicrophoneAllowed); } + ::testing::NiceMock<MockFrontendAPI> mock_frontend_; + private: std::unique_ptr<FakeMicrophoneMuteNotificationDelegate> delegate_; base::test::ScopedFeatureList scoped_feature_list_; }; -TEST_F(MicrophonePrivacySwitchControllerTest, SetSystemMuteOnLogin) { +TEST_F(PrivacyHubMicrophoneControllerTest, SetSystemMuteOnLogin) { for (bool microphone_allowed : {false, true, false}) { const bool microphone_muted = !microphone_allowed; SetUserPref(microphone_allowed); @@ -78,14 +95,14 @@ } } -TEST_F(MicrophonePrivacySwitchControllerTest, OnPreferenceChanged) { +TEST_F(PrivacyHubMicrophoneControllerTest, OnPreferenceChanged) { for (bool microphone_allowed : {false, true, false}) { SetUserPref(microphone_allowed); EXPECT_EQ(CrasAudioHandler::Get()->IsInputMuted(), !microphone_allowed); } } -TEST_F(MicrophonePrivacySwitchControllerTest, OnInputMuteChanged) { +TEST_F(PrivacyHubMicrophoneControllerTest, OnInputMuteChanged) { for (bool microphone_muted : {false, true, false}) { const bool microphone_allowed = !microphone_muted; @@ -94,4 +111,20 @@ } } +TEST_F(PrivacyHubMicrophoneControllerTest, OnAudioNodesChanged) { + EXPECT_CALL(mock_frontend_, AvailabilityOfMicrophoneChanged(_)); + Shell::Get() + ->privacy_hub_controller() + ->microphone_controller() + .OnAudioNodesChanged(); +} + +TEST_F(PrivacyHubMicrophoneControllerTest, OnMicrophoneMuteSwitchValueChanged) { + EXPECT_CALL(mock_frontend_, MicrophoneHardwareToggleChanged(_)); + Shell::Get() + ->privacy_hub_controller() + ->microphone_controller() + .OnMicrophoneMuteSwitchValueChanged(true); +} + } // namespace ash
diff --git a/ash/system/privacy_hub/privacy_hub_controller.h b/ash/system/privacy_hub/privacy_hub_controller.h index 61788c9c..daa173f02 100644 --- a/ash/system/privacy_hub/privacy_hub_controller.h +++ b/ash/system/privacy_hub/privacy_hub_controller.h
@@ -6,8 +6,11 @@ #define ASH_SYSTEM_PRIVACY_HUB_PRIVACY_HUB_CONTROLLER_H_ #include "ash/ash_export.h" +#include "ash/public/cpp/privacy_hub_delegate.h" #include "ash/system/privacy_hub/camera_privacy_switch_controller.h" #include "ash/system/privacy_hub/microphone_privacy_switch_controller.h" +#include "base/memory/raw_ptr.h" +#include "base/values.h" class PrefRegistrySimple; @@ -22,15 +25,25 @@ ~PrivacyHubController(); - CameraPrivacySwitchController* CameraControllerForTest() { - return &camera_controller_; + CameraPrivacySwitchController& camera_controller() { + return camera_controller_; + } + MicrophonePrivacySwitchController& microphone_controller() { + return microphone_controller_; } static void RegisterProfilePrefs(PrefRegistrySimple* registry); + // Sets the frontend adapter (to be used from webui) + void set_frontend(PrivacyHubDelegate* ptr) { frontend_ = ptr; } + + // Returns the adapter that can be used to modify the frontend + PrivacyHubDelegate& frontend() { return *frontend_; } + private: CameraPrivacySwitchController camera_controller_; MicrophonePrivacySwitchController microphone_controller_; + raw_ptr<PrivacyHubDelegate> frontend_; }; } // namespace ash
diff --git a/base/android/java/src/org/chromium/base/TraceEvent.java b/base/android/java/src/org/chromium/base/TraceEvent.java index b0655cc..7f449ad 100644 --- a/base/android/java/src/org/chromium/base/TraceEvent.java +++ b/base/android/java/src/org/chromium/base/TraceEvent.java
@@ -741,6 +741,18 @@ } /** + * Triggers a 'instant' native "AndroidToolbar" event. + * @param blockReason the enum TopToolbarBlockCapture (-1 if not blocked). + * @param allowReason the enum TopToolbarAllowCapture (-1 if not allowed). + * @param snapshotDiff the enum ToolbarSnapshotDifference (-1 if no diff). + */ + public static void instantAndroidToolbar(int blockReason, int allowReason, int snapshotDiff) { + if (sEnabled) { + TraceEventJni.get().instantAndroidToolbar(blockReason, allowReason, snapshotDiff); + } + } + + /** * Snapshots the view hierarchy state on the main thread and then finishes emitting a trace * event on the threadpool. */ @@ -886,6 +898,7 @@ void addViewDump(int id, int parentId, boolean isShown, boolean isDirty, String className, String resourceName, long activityProtoPtr); void instantAndroidIPC(String name, long durMs); + void instantAndroidToolbar(int blockReason, int allowReason, int snapshotDiff); } /**
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java index 975f6bb..cf4a325 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java +++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java
@@ -1040,6 +1040,18 @@ } /** + * @return the current connection binding state. + */ + public @ChildBindingState int bindingStateCurrent() { + // WARNING: this method can be called from a thread other than the launcher thread. + // Note that it returns the current waived bound only state and is racy. This not really + // preventable without changing the caller's API, short of blocking. + synchronized (mBindingStateLock) { + return mBindingState; + } + } + + /** * @return true if the connection is bound and only bound with the waived binding or if the * connection is unbound and was only bound with the waived binding when it disconnected. */
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java index 26ad9ab..4eeae78 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java +++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java
@@ -99,8 +99,9 @@ // The IBinder interfaces provided to the created service. private final List<IBinder> mClientInterfaces; - // The actual service connection. Set once we have connected to the service. - private ChildProcessConnection mConnection; + // The actual service connection. Set once we have connected to the service. Volatile as it is + // accessed from threads other than the Launcher thread. + private volatile ChildProcessConnection mConnection; /** * Constructor.
diff --git a/base/android/trace_event_binding.cc b/base/android/trace_event_binding.cc index a918552..0865931 100644 --- a/base/android/trace_event_binding.cc +++ b/base/android/trace_event_binding.cc
@@ -237,6 +237,31 @@ }); } +static void JNI_TraceEvent_InstantAndroidToolbar(JNIEnv* env, + jint block_reason, + jint allow_reason, + jint snapshot_diff) { + using AndroidToolbar = perfetto::protos::pbzero::AndroidToolbar; + TRACE_EVENT_INSTANT( + internal::kJavaTraceCategory, "AndroidToolbar", + [&](perfetto::EventContext ctx) { + auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>(); + auto* android_toolbar = event->set_android_toolbar(); + if (block_reason >= 0) { + android_toolbar->set_block_capture_reason( + static_cast<AndroidToolbar::BlockCaptureReason>(block_reason)); + } + if (allow_reason >= 0) { + android_toolbar->set_allow_capture_reason( + static_cast<AndroidToolbar::AllowCaptureReason>(allow_reason)); + } + if (snapshot_diff >= 0) { + android_toolbar->set_snapshot_difference( + static_cast<AndroidToolbar::SnapshotDifference>(snapshot_diff)); + } + }); +} + static void JNI_TraceEvent_Begin(JNIEnv* env, const JavaParamRef<jstring>& jname, const JavaParamRef<jstring>& jarg) {
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc index 093177a8..b40589d 100644 --- a/base/trace_event/trace_event_unittest.cc +++ b/base/trace_event/trace_event_unittest.cc
@@ -2571,8 +2571,8 @@ Clear(); } -// Flaky on iOS device, see crbug.com/908002 -#if BUILDFLAG(IS_IOS) && !(TARGET_OS_SIMULATOR) +// Flaky on iOS device, see crbug.com/908002, crbug.com/1363545 +#if BUILDFLAG(IS_IOS) #define MAYBE_EventFiltering DISABLED_EventFiltering #else #define MAYBE_EventFiltering EventFiltering
diff --git a/base/tracing/protos/chrome_track_event.proto b/base/tracing/protos/chrome_track_event.proto index 95c5250..3d21d2ac 100644 --- a/base/tracing/protos/chrome_track_event.proto +++ b/base/tracing/protos/chrome_track_event.proto
@@ -828,9 +828,50 @@ optional Priority priority = 1; } +message AndroidToolbar { + enum BlockCaptureReason { + BLOCKED_UNKNOWN = 0; + BLOCKED_TOOLBAR_OR_RESULT_NULL = 1; + BLOCKED_VIEW_NOT_DIRTY = 2; + BLOCKED_SNAPSHOT_SAME = 3; + BLOCKED_URL_BAR_HAS_FOCUS = 4; + BLOCKED_URL_BAR_FOCUS_IN_PROGRESS = 5; + BLOCKED_OPTIONAL_BUTTON_ANIMATION_IN_PROGRESS = 6; + BLOCKED_STATUS_ICON_ANIMATION_IN_PROGRESS = 7; + BLOCKED_SCROLL_ABLATION = 8; + BLOCKED_BROWSER_CONTROLS_LOCKED = 9; + // TODO(https://crbug.com/1324678): SCROLL_IN_PROGRESS. + // TODO(https://crbug.com/1324678): NATIVE_PAGE. + } + enum AllowCaptureReason { + ALLOWED_UNKNOWN = 0; + ALLOWED_FORCE_CAPTURE = 1; + ALLOWED_SNAPSHOT_DIFFERENCE = 2; + } + enum SnapshotDifference { + DIFF_NONE = 0; + DIFF_NULL = 1; + DIFF_TINT = 2; + DIFF_TAB_COUNT = 3; + DIFF_OPTIONAL_BUTTON_DATA = 4; + DIFF_VISUAL_STATE = 5; + DIFF_SECURITY_ICON = 6; + DIFF_SHOWING_UPDATE_BADGE = 7; + DIFF_PAINT_PREVIEW = 8; + DIFF_PROGRESS = 9; + DIFF_LOCATION_BAR_WIDTH = 10; + DIFF_URL_TEXT = 11; + DIFF_HOME_BUTTON_COLOR = 12; + } + + optional BlockCaptureReason block_capture_reason = 1; + optional AllowCaptureReason allow_capture_reason = 2; + optional SnapshotDifference snapshot_difference = 3; +} + message ChromeTrackEvent { // Extension range for Chrome: 1000-1999 - // Next ID: 1041 + // Next ID: 1042 extend TrackEvent { optional ChromeAppState chrome_app_state = 1000; @@ -918,5 +959,7 @@ optional ChromeSqlDiagnostics sql_diagnostics = 1039; optional SequenceManagerTask sequence_manager_task = 1040; + + optional AndroidToolbar android_toolbar = 1041; } }
diff --git a/build/rust/cargo_crate.gni b/build/rust/cargo_crate.gni index 5724290d..de65a05 100644 --- a/build/rust/cargo_crate.gni +++ b/build/rust/cargo_crate.gni
@@ -291,6 +291,7 @@ if (defined(invoker.build_deps)) { deps = invoker.build_deps } + rustenv = _rustenv forward_variables_from(invoker, [ "features",
diff --git a/build/rust/tests/test_bin_crate/BUILD.gn b/build/rust/tests/test_bin_crate/BUILD.gn index e633e65..ac47ee0 100644 --- a/build/rust/tests/test_bin_crate/BUILD.gn +++ b/build/rust/tests/test_bin_crate/BUILD.gn
@@ -10,4 +10,6 @@ sources = [ "crate/src/main.rs" ] build_sources = [ "crate/build.rs" ] build_root = "crate/build.rs" + + rustenv = [ "BUILD_SCRIPT_TEST_VARIABLE=123" ] }
diff --git a/build/rust/tests/test_bin_crate/crate/build.rs b/build/rust/tests/test_bin_crate/crate/build.rs index fcd3290..a1051eb 100644 --- a/build/rust/tests/test_bin_crate/crate/build.rs +++ b/build/rust/tests/test_bin_crate/crate/build.rs
@@ -27,6 +27,9 @@ if target.contains("darwin") { println!("cargo:rustc-cfg=is_mac"); } + + // Check that we can get a `rustenv` variable from the build script. + let _ = env!("BUILD_SCRIPT_TEST_VARIABLE"); } fn rustc_minor_version() -> Option<u32> {
diff --git a/chrome/VERSION b/chrome/VERSION index 94e36c78..8d929c7 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=107 MINOR=0 -BUILD=5301 +BUILD=5302 PATCH=0
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/InCctTriggeringFromGsaTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/InCctTriggeringFromGsaTest.java index bcf8463..50e7500 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/InCctTriggeringFromGsaTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/InCctTriggeringFromGsaTest.java
@@ -19,12 +19,14 @@ import android.support.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; +import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.autofill_assistant.proto.GetTriggerScriptsResponseProto; @@ -39,11 +41,14 @@ import org.chromium.components.autofill_assistant.AutofillAssistantPreferencesUtil; import org.chromium.content_public.browser.test.util.TestThreadUtils; +import java.util.concurrent.TimeoutException; + /** * Tests for heuristics-based triggering in tabs created by GSA. */ @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) @RunWith(ChromeJUnit4ClassRunner.class) +@Batch(Batch.PER_CLASS) public class InCctTriggeringFromGsaTest { private static final String HTML_DIRECTORY = "/components/test/data/autofill_assistant/html/"; private static final String TEST_PAGE_UNSUPPORTED = "autofill_assistant_target_website.html"; @@ -153,6 +158,48 @@ waitUntilViewMatchesCondition(withText("TriggerScript"), isDisplayed()); } /** + * Tests a simple trigger heuristic that checks URLs for the appearance of 'cart' using + * javascript navigation. + * + * { + * "heuristics":[ + * { + * "intent":"SHOPPING_ASSISTED_CHECKOUT", + * "conditionSet":{ + * "urlMatches":".*cart.*" + * } + * } + * ] + * } + */ + @Test + @SmallTest + // clang-format off + @CommandLineFlags. + Add({"enable-features=AutofillAssistantInCctTriggering<FakeStudyName," + +"AutofillAssistantUrlHeuristics<FakeStudyName", + "force-fieldtrials=FakeStudyName/Enabled", + "force-fieldtrial-params=FakeStudyName.Enabled:json_parameters/" + +"%7B%22heuristics%22%3A%5B%7B%22intent%22%3A%22SHOPPING_ASSISTED_CHECKOUT" + +"%22%2C%22conditionSet%22%3A%7B%22urlMatches%22%3A%22.*cart.*%22%7D%7D%5D%7D"}) + // clang-format on + public void + triggerImplicitlyOnJSNavigation() throws TimeoutException { + AutofillAssistantTestServiceRequestSender testServiceRequestSender = + new AutofillAssistantTestServiceRequestSender(); + testServiceRequestSender.setNextResponse( + /* httpStatus = */ 200, createDefaultTriggerScriptResponse("TriggerScript")); + testServiceRequestSender.scheduleForInjection(); + + mTestRule.loadUrl(getTargetWebsiteUrl(TEST_PAGE_UNSUPPORTED)); + onView(withText("TriggerScript")).check(doesNotExist()); + mTestRule.runJavaScriptCodeInCurrentTab( + "window.history.pushState(\"\", \"\", window.location.href + 'cart');"); + // Note: allow for some extra time here to account for the start. + waitUntilViewMatchesCondition( + withText("TriggerScript"), isDisplayed(), DEFAULT_MAX_TIME_TO_POLL); + } + /** * Tests a simple trigger heuristic that checks URL for the appearance of cart. * * {
diff --git a/chrome/android/features/keyboard_accessory/BUILD.gn b/chrome/android/features/keyboard_accessory/BUILD.gn index 59eb9cae..422c816f 100644 --- a/chrome/android/features/keyboard_accessory/BUILD.gn +++ b/chrome/android/features/keyboard_accessory/BUILD.gn
@@ -76,6 +76,7 @@ ] deps = [ + ":test_resources", "internal:internal_java", "public:public_java", "//base:base_java", @@ -121,6 +122,16 @@ "//ui/android:ui_utils_java", "//url:gurl_java", ] + + resources_package = "org.chromium.chrome.browser.keyboard_accessory" +} + +android_resources("test_resources") { + testonly = true + + sources = [ "javatests/res/layout/test_main.xml" ] + + deps = [ "internal:java_resources" ] } robolectric_binary("keyboard_accessory_junit_tests") {
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet.xml index 9e34431..5c43dd2 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet.xml +++ b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet.xml
@@ -7,6 +7,7 @@ <org.chromium.chrome.browser.keyboard_accessory.sheet_component.AccessorySheetView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/keyboard_accessory_sheet_container" android:fillViewport="true" android:paddingTop="0dp" android:layout_gravity="start|top"
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java index a493b5a..64eea72 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.keyboard_accessory; +import static org.chromium.base.ThreadUtils.assertOnUiThread; + import android.app.Activity; import android.util.SparseArray; @@ -63,6 +65,7 @@ @CalledByNative private void onItemsAvailable(Object objAccessorySheetData) { + assertOnUiThread(); AccessorySheetData accessorySheetData = (AccessorySheetData) objAccessorySheetData; PropertyProvider<AccessorySheetData> provider = getOrCreateProvider(accessorySheetData.getSheetType());
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java index c415ca0f..69d5cdf 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.keyboard_accessory; import android.view.View; -import android.view.ViewStub; import androidx.annotation.VisibleForTesting; @@ -22,6 +21,7 @@ import org.chromium.components.autofill.AutofillSuggestion; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.content_public.browser.WebContents; +import org.chromium.ui.AsyncViewStub; import org.chromium.ui.DropdownPopupWindow; import org.chromium.ui.base.WindowAndroid; @@ -42,14 +42,15 @@ @Override public void initialize(WindowAndroid windowAndroid, BottomSheetController sheetController, SoftKeyboardDelegate keyboardDelegate, BackPressManager backPressManager, - ViewStub sheetStub, ViewStub barStub) { + AsyncViewStub sheetStub, AsyncViewStub barStub) { if (barStub == null || sheetStub == null) return; // The manual filling isn't needed. - if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)) { - barStub.setLayoutResource(R.layout.keyboard_accessory_modern); - } else { - barStub.setLayoutResource(R.layout.keyboard_accessory); - } + barStub.setLayoutResource( + ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY) + ? R.layout.keyboard_accessory_modern + : R.layout.keyboard_accessory); sheetStub.setLayoutResource(R.layout.keyboard_accessory_sheet); + barStub.setShouldInflateOnBackgroundThread(true); + sheetStub.setShouldInflateOnBackgroundThread(true); initialize(windowAndroid, new KeyboardAccessoryCoordinator(mMediator, barStub), new AccessorySheetCoordinator(sheetStub), sheetController, backPressManager, keyboardDelegate, new ConfirmationDialogHelper(windowAndroid.getContext()));
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java index f53a54d..2b2ea56f 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
@@ -7,8 +7,6 @@ import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SKIP_CLOSING_ANIMATION; import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.VISIBLE; -import android.view.ViewStub; - import androidx.annotation.Nullable; import androidx.annotation.Px; import androidx.annotation.VisibleForTesting; @@ -17,6 +15,7 @@ import org.chromium.base.TraceEvent; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.keyboard_accessory.AccessoryTabType; +import org.chromium.chrome.browser.keyboard_accessory.R; import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BarItem; import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryViewBinder.BarItemViewHolder; import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData; @@ -24,7 +23,8 @@ import org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabLayoutCoordinator; import org.chromium.components.autofill.AutofillDelegate; import org.chromium.components.autofill.AutofillSuggestion; -import org.chromium.ui.DeferredViewStubInflationProvider; +import org.chromium.ui.AsyncViewProvider; +import org.chromium.ui.AsyncViewStub; import org.chromium.ui.ViewProvider; import org.chromium.ui.modelutil.LazyConstructionPropertyMcp; import org.chromium.ui.modelutil.ListModel; @@ -117,15 +117,16 @@ /** * Initializes the component as soon as the native library is loaded by e.g. starting to listen * to keyboard visibility events. - * @param barStub A {@link ViewStub} for the accessory bar layout. + * @param barStub A {@link AsyncViewStub} for the accessory bar layout. */ - public KeyboardAccessoryCoordinator(VisibilityDelegate visibilityDelegate, ViewStub barStub) { + public KeyboardAccessoryCoordinator( + VisibilityDelegate visibilityDelegate, AsyncViewStub barStub) { this(new KeyboardAccessoryTabLayoutCoordinator(), visibilityDelegate, - new DeferredViewStubInflationProvider<>(barStub)); + AsyncViewProvider.of(barStub, R.id.keyboard_accessory)); } /** - * Constructor that allows to mock the {@link DeferredViewStubInflationProvider}. + * Constructor that allows to mock the {@link AsyncViewProvider}. * @param viewProvider A provider for the accessory. */ @VisibleForTesting
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernView.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernView.java index 67b52fe2..737a5b3 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernView.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernView.java
@@ -125,7 +125,6 @@ @Override protected void onFinishInflate() { - TraceEvent.begin("KeyboardAccessoryModernView#onFinishInflate"); super.onFinishInflate(); mSheetTitle = findViewById(R.id.sheet_title); mKeyboardToggle = findViewById(R.id.show_keyboard); @@ -139,7 +138,6 @@ // Remove any paddings that might be inherited since this messes up the fading edge. ViewCompat.setPaddingRelative(mBarItemsView, 0, 0, 0, 0); - TraceEvent.end("KeyboardAccessoryModernView#onFinishInflate"); } @Override
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetCoordinator.java index cbe0150..13406d08 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetCoordinator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetCoordinator.java
@@ -12,8 +12,6 @@ import static org.chromium.chrome.browser.keyboard_accessory.sheet_component.AccessorySheetProperties.TOP_SHADOW_VISIBLE; import static org.chromium.chrome.browser.keyboard_accessory.sheet_component.AccessorySheetProperties.VISIBLE; -import android.view.ViewStub; - import androidx.annotation.Nullable; import androidx.annotation.Px; import androidx.annotation.VisibleForTesting; @@ -22,8 +20,10 @@ import androidx.viewpager.widget.ViewPager; import org.chromium.base.TraceEvent; +import org.chromium.chrome.browser.keyboard_accessory.R; import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData; -import org.chromium.ui.DeferredViewStubInflationProvider; +import org.chromium.ui.AsyncViewProvider; +import org.chromium.ui.AsyncViewStub; import org.chromium.ui.ViewProvider; import org.chromium.ui.modelutil.LazyConstructionPropertyMcp; import org.chromium.ui.modelutil.ListModel; @@ -42,14 +42,14 @@ /** * Creates the sheet component by instantiating Model, View and Controller before wiring these * parts up. - * @param sheetStub A {@link ViewStub} for the accessory sheet layout. + * @param sheetStub A {@link AsyncViewStub} for the accessory sheet layout. */ - public AccessorySheetCoordinator(ViewStub sheetStub) { - this(new DeferredViewStubInflationProvider<>(sheetStub)); + public AccessorySheetCoordinator(AsyncViewStub sheetStub) { + this(AsyncViewProvider.of(sheetStub, R.id.keyboard_accessory_sheet_container)); } /** - * Constructor that allows to mock the {@link DeferredViewStubInflationProvider}. + * Constructor that allows to mock the {@link AsyncViewProvider}. * @param viewProvider A provider for the accessory. */ @VisibleForTesting
diff --git a/chrome/android/features/keyboard_accessory/javatests/res/layout/test_main.xml b/chrome/android/features/keyboard_accessory/javatests/res/layout/test_main.xml new file mode 100644 index 0000000..b01ae3f --- /dev/null +++ b/chrome/android/features/keyboard_accessory/javatests/res/layout/test_main.xml
@@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2022 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <org.chromium.ui.AsyncViewStub + android:id="@+id/keyboard_accessory_stub" + android:inflatedId="@+id/keyboard_accessory" + android:layout_height="@dimen/keyboard_accessory_height_with_shadow" + android:layout_width="match_parent" + android:layout_gravity="start|bottom"/> + + <org.chromium.ui.AsyncViewStub + android:id="@+id/keyboard_accessory_sheet_stub" + android:inflatedId="@+id/keyboard_accessory_sheet_container" + android:layout_height="@dimen/keyboard_accessory_sheet_height" + android:layout_width="match_parent" + android:layout_gravity="start|bottom"/> +</FrameLayout>
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java index f60ecc1..2b9bbfb7 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java
@@ -27,6 +27,7 @@ import android.view.ViewGroup; import android.widget.TextView; +import androidx.annotation.StringRes; import androidx.recyclerview.widget.RecyclerView; import androidx.test.espresso.PerformException; import androidx.test.espresso.UiController; @@ -416,6 +417,41 @@ } /** + * Use in a |onView().perform| action to select the tab at |tabIndex| for the found tab layout. + * @param tabIndex The index to be selected. + * @return The action executed by |perform|. + */ + public static ViewAction selectTabWithDescription(@StringRes int descriptionResId) { + return new ViewAction() { + @Override + public Matcher<View> getConstraints() { + return allOf(isDisplayed(), isAssignableFrom(TabLayout.class)); + } + + @Override + public String getDescription() { + return "with tab with matching description."; + } + + @Override + public void perform(UiController uiController, View view) { + String descriptionToMatch = view.getContext().getString(descriptionResId); + TabLayout tabLayout = (TabLayout) view; + for (int tabIndex = 0; tabIndex < tabLayout.getTabCount(); tabIndex++) { + final TabLayout.Tab tab = tabLayout.getTabAt(tabIndex); + if (descriptionToMatch.equals(tab.getContentDescription())) { + PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, tab::select); + return; + } + } + throw new PerformException.Builder() + .withCause(new Throwable("No tab with description: " + descriptionToMatch)) + .build(); + } + }; + } + + /** * Use in a |onView().perform| action to scroll to the end of a {@link RecyclerView}. * @return The action executed by |perform|. */
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java index fab1b019..08b031c 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
@@ -43,7 +43,6 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.view.View; -import android.view.ViewStub; import androidx.annotation.Nullable; import androidx.test.espresso.ViewInteraction; @@ -88,7 +87,8 @@ import org.chromium.components.feature_engagement.TriggerState; import org.chromium.content_public.browser.test.util.JavaScriptUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.DeferredViewStubInflationProvider; +import org.chromium.ui.AsyncViewProvider; +import org.chromium.ui.AsyncViewStub; import org.chromium.ui.DropdownItem; import org.chromium.ui.ViewProvider; import org.chromium.ui.modelutil.LazyConstructionPropertyMcp; @@ -230,12 +230,12 @@ .with(OBFUSCATED_CHILD_AT_CALLBACK, unused -> {}) .with(SHOW_SWIPING_IPH, false) .build(); - ViewStub viewStub = + AsyncViewStub viewStub = mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory_stub); mKeyboardAccessoryView = new ArrayBlockingQueue<>(1); ViewProvider<KeyboardAccessoryModernView> provider = - new DeferredViewStubInflationProvider<>(viewStub); + AsyncViewProvider.of(viewStub, R.id.keyboard_accessory); LazyConstructionPropertyMcp.create( mModel, VISIBLE, provider, KeyboardAccessoryModernViewBinder::bind); provider.whenLoaded(mKeyboardAccessoryView::add);
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java index 5f78ebb..5d6917b 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java
@@ -30,7 +30,6 @@ import static org.chromium.ui.test.util.ViewUtils.waitForView; import android.view.View; -import android.view.ViewStub; import androidx.test.filters.MediumTest; @@ -53,7 +52,8 @@ import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.DeferredViewStubInflationProvider; +import org.chromium.ui.AsyncViewProvider; +import org.chromium.ui.AsyncViewStub; import org.chromium.ui.ViewProvider; import org.chromium.ui.modelutil.LazyConstructionPropertyMcp; import org.chromium.ui.modelutil.PropertyModel; @@ -94,12 +94,12 @@ })) .with(DISABLE_ANIMATIONS_FOR_TESTING, true) .build(); - ViewStub viewStub = + AsyncViewStub viewStub = mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory_stub); mKeyboardAccessoryView = new ArrayBlockingQueue<>(1); ViewProvider<KeyboardAccessoryView> provider = - new DeferredViewStubInflationProvider<>(viewStub); + AsyncViewProvider.of(viewStub, R.id.keyboard_accessory); LazyConstructionPropertyMcp.create( mModel, VISIBLE, provider, KeyboardAccessoryViewBinder::bind); provider.whenLoaded(mKeyboardAccessoryView::add);
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetRenderTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetRenderTest.java index e52569f5..505dee6 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetRenderTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetRenderTest.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.keyboard_accessory.sheet_component; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static androidx.test.espresso.matcher.ViewMatchers.withId; @@ -20,14 +19,10 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.view.Gravity; -import android.view.ViewStub; +import android.view.LayoutInflater; import android.widget.FrameLayout; import android.widget.LinearLayout; -import androidx.annotation.DimenRes; -import androidx.annotation.IdRes; -import androidx.annotation.LayoutRes; -import androidx.annotation.Nullable; import androidx.test.filters.MediumTest; import org.junit.After; @@ -63,7 +58,8 @@ import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.content_public.browser.test.NativeLibraryTestUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.DeferredViewStubInflationProvider; +import org.chromium.ui.AsyncViewProvider; +import org.chromium.ui.AsyncViewStub; import org.chromium.ui.modelutil.LazyConstructionPropertyMcp; import org.chromium.ui.modelutil.ListModel; import org.chromium.ui.modelutil.PropertyModel; @@ -133,14 +129,14 @@ // and won't apply the theme. mActivityTestRule.getActivity().setTheme(R.style.ColorOverlay_ChromiumAndroid); TestThreadUtils.runOnUiThreadBlocking(() -> { - ViewStub sheetStub = initializeContentViewWithSheetStub(); + AsyncViewStub sheetStub = initializeContentViewWithSheetStub(); mSheetModel = createSheetModel( mActivityTestRule.getActivity().getResources().getDimensionPixelSize( R.dimen.keyboard_accessory_sheet_height)); LazyConstructionPropertyMcp.create(mSheetModel, VISIBLE, - new DeferredViewStubInflationProvider<>(sheetStub), + AsyncViewProvider.of(sheetStub, R.id.keyboard_accessory_sheet_container), AccessorySheetViewBinder::bind); }); } @@ -258,27 +254,20 @@ mRenderTestRule.render(mContentView, "Addresses"); } - private ViewStub initializeContentViewWithSheetStub() { - mContentView = new FrameLayout(mActivityTestRule.getActivity()); - mActivityTestRule.getActivity().setContentView(mContentView); - - ViewStub sheetStub = createViewStub(R.id.keyboard_accessory_sheet_stub, - R.layout.keyboard_accessory_sheet, null, R.dimen.keyboard_accessory_sheet_height); - mContentView.addView(sheetStub, MATCH_PARENT, WRAP_CONTENT); - return sheetStub; - } - - private ViewStub createViewStub(@IdRes int id, @LayoutRes int layout, - @Nullable @IdRes Integer inflatedId, @DimenRes int layoutHeight) { - ViewStub stub = new ViewStub(mActivityTestRule.getActivity()); - stub.setId(id); - stub.setLayoutResource(layout); - if (inflatedId != null) stub.setInflatedId(inflatedId); + private AsyncViewStub initializeContentViewWithSheetStub() { + mContentView = (FrameLayout) LayoutInflater.from(mActivityTestRule.getActivity()) + .inflate(R.layout.test_main, null); + AsyncViewStub sheetStub = mContentView.findViewById(R.id.keyboard_accessory_sheet_stub); + sheetStub.setLayoutResource(R.layout.keyboard_accessory_sheet); + sheetStub.setShouldInflateOnBackgroundThread(true); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(MATCH_PARENT, - mActivityTestRule.getActivity().getResources().getDimensionPixelSize(layoutHeight)); + mActivityTestRule.getActivity().getResources().getDimensionPixelSize( + R.dimen.keyboard_accessory_sheet_height)); layoutParams.gravity = Gravity.START | Gravity.BOTTOM; - stub.setLayoutParams(layoutParams); - return stub; + sheetStub.setLayoutParams(layoutParams); + + mActivityTestRule.getActivity().setContentView(mContentView); + return sheetStub; } private static PropertyModel createSheetModel(int height) {
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetViewTest.java index 08c5db5..e978c93 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetViewTest.java
@@ -29,7 +29,6 @@ import android.view.View; import android.view.ViewGroup; -import android.view.ViewStub; import android.widget.LinearLayout; import android.widget.TextView; @@ -48,7 +47,8 @@ import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.DeferredViewStubInflationProvider; +import org.chromium.ui.AsyncViewProvider; +import org.chromium.ui.AsyncViewStub; import org.chromium.ui.ViewProvider; import org.chromium.ui.modelutil.LazyConstructionPropertyMcp; import org.chromium.ui.modelutil.ListModel; @@ -74,7 +74,7 @@ public void setUp() throws InterruptedException { mActivityTestRule.startMainActivityOnBlankPage(); TestThreadUtils.runOnUiThreadBlocking(() -> { - ViewStub viewStub = mActivityTestRule.getActivity().findViewById( + AsyncViewStub viewStub = mActivityTestRule.getActivity().findViewById( R.id.keyboard_accessory_sheet_stub); int height = mActivityTestRule.getActivity().getResources().getDimensionPixelSize( R.dimen.keyboard_accessory_sheet_height); @@ -87,7 +87,7 @@ .with(TOP_SHADOW_VISIBLE, false) .build(); ViewProvider<AccessorySheetView> provider = - new DeferredViewStubInflationProvider<>(viewStub); + AsyncViewProvider.of(viewStub, R.id.keyboard_accessory_sheet_container); mViewPager = new ArrayBlockingQueue<>(1); LazyConstructionPropertyMcp.create( mModel, VISIBLE, provider, AccessorySheetViewBinder::bind); @@ -155,7 +155,7 @@ mModel.set(VISIBLE, true); }); // Render view. - onView(withText(kFirstTab)).check(matches(isDisplayed())); + onViewWaiting(withText(kFirstTab)).check(matches(isDisplayed())); TestThreadUtils.runOnUiThreadBlocking(() -> mModel.set(ACTIVE_TAB_INDEX, 1)); @@ -174,7 +174,7 @@ mModel.set(VISIBLE, true); }); // Render view. - onView(withText(kFirstTab)).check(matches(isDisplayed())); + onViewWaiting(withText(kFirstTab)).check(matches(isDisplayed())); TestThreadUtils.runOnUiThreadBlocking( () -> mModel.get(TABS).remove(mModel.get(TABS).get(0))); @@ -193,7 +193,7 @@ }); // Render view. // Remove the last tab. - onView(withText(kFirstTab)).check(matches(isDisplayed())); + onViewWaiting(withText(kFirstTab)).check(matches(isDisplayed())); TestThreadUtils.runOnUiThreadBlocking( () -> { mModel.get(TABS).remove(mModel.get(TABS).get(0)); }); onView(withText(kFirstTab)).check(doesNotExist());
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java index 7e1badd..3625cc91 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java
@@ -19,7 +19,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.not; -import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabAtPosition; +import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabWithDescription; import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.whenDisplayed; import static org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabTestHelper.isKeyboardAccessoryTabLayout; @@ -132,7 +132,8 @@ // Scroll to last element and click the second icon: whenDisplayed(withId(R.id.bar_items_view)) .perform(scrollTo(isKeyboardAccessoryTabLayout()), - actionOnItem(isKeyboardAccessoryTabLayout(), selectTabAtPosition(1))); + actionOnItem(isKeyboardAccessoryTabLayout(), + selectTabWithDescription(R.string.address_accessory_sheet_toggle))); // Wait for the sheet to come up and be stable. whenDisplayed(withId(R.id.addresses_sheet));
diff --git a/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java b/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java index 824aebb..8179f00f5 100644 --- a/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java +++ b/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java
@@ -7,7 +7,6 @@ import android.content.Context; import android.view.View; import android.view.ViewGroup; -import android.view.ViewStub; import androidx.annotation.Px; @@ -20,6 +19,7 @@ import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.widget.gesture.BackPressHandler; import org.chromium.content_public.browser.WebContents; +import org.chromium.ui.AsyncViewStub; import org.chromium.ui.DropdownPopupWindow; import org.chromium.ui.base.WindowAndroid; @@ -94,12 +94,11 @@ * @param sheetController A {@link BottomSheetController} to show the UI in. * @param keyboardDelegate A {@link SoftKeyboardDelegate} to control only the system keyboard. * @param backPressManager A {@link BackPressManager} to register {@link BackPressHandler}. - * @param sheetStub The {@link ViewStub} used to inflate the keyboard accessory bottom - * @param barStub The {@link ViewStub} used to inflate the keyboard accessory bar. + * @param barStub The {@link AsyncViewStub} used to inflate the keyboard accessory bar. */ void initialize(WindowAndroid windowAndroid, BottomSheetController sheetController, SoftKeyboardDelegate keyboardDelegate, BackPressManager backPressManager, - ViewStub sheetStub, ViewStub barStub); + AsyncViewStub sheetStub, AsyncViewStub barStub); /** * Cleans up the manual UI by destroying the accessory bar and its bottom sheet.
diff --git a/chrome/android/java/res_app/layout/main.xml b/chrome/android/java/res_app/layout/main.xml index 30cccd4..d38e04e 100644 --- a/chrome/android/java/res_app/layout/main.xml +++ b/chrome/android/java/res_app/layout/main.xml
@@ -61,15 +61,16 @@ android:layout_height="wrap_content" android:layout_gravity="start|bottom" /> - <ViewStub + <org.chromium.ui.AsyncViewStub android:id="@+id/keyboard_accessory_stub" android:inflatedId="@+id/keyboard_accessory" android:layout_height="@dimen/keyboard_accessory_height_with_shadow" android:layout_width="match_parent" android:layout_gravity="start|bottom"/> - <ViewStub + <org.chromium.ui.AsyncViewStub android:id="@+id/keyboard_accessory_sheet_stub" + android:inflatedId="@+id/keyboard_accessory_sheet_container" android:layout_height="@dimen/keyboard_accessory_sheet_height" android:layout_width="match_parent" android:layout_gravity="start|bottom"/>
diff --git a/chrome/app/theme/chrome_unscaled_resources.grd b/chrome/app/theme/chrome_unscaled_resources.grd index ca2c9919..431df86c 100644 --- a/chrome/app/theme/chrome_unscaled_resources.grd +++ b/chrome/app/theme/chrome_unscaled_resources.grd
@@ -17,18 +17,39 @@ <if expr="_google_chrome"> <then> <include name="IDR_ASSISTANT_LOGO_MONOCHROME" file="google_chrome/google_assistant.svg" type="BINDATA" /> - <if expr="is_linux"> + <if expr="_google_chrome_for_testing"> <then> - <include name="IDR_PRODUCT_LOGO_64" file="google_chrome/linux/product_logo_64.png" type="BINDATA" /> - <include name="IDR_PRODUCT_LOGO_128" file="google_chrome/linux/product_logo_128.png" type="BINDATA" /> - <include name="IDR_PRODUCT_LOGO_128_BETA" file="google_chrome/linux/product_logo_128_beta.png" type="BINDATA" /> - <include name="IDR_PRODUCT_LOGO_128_DEV" file="google_chrome/linux/product_logo_128_dev.png" type="BINDATA" /> - <include name="IDR_PRODUCT_LOGO_256" file="google_chrome/linux/product_logo_256.png" type="BINDATA" /> + <if expr="is_linux"> + <then> + <include name="IDR_PRODUCT_LOGO_64" file="google_chrome/google_chrome_for_testing/linux/product_logo_64.png" type="BINDATA" /> + <include name="IDR_PRODUCT_LOGO_128" file="google_chrome/google_chrome_for_testing/linux/product_logo_128.png" type="BINDATA" /> + <!-- Beta and Dev use the same logo as stable because channels are not a relevant concept for CfT. --> + <include name="IDR_PRODUCT_LOGO_128_BETA" file="google_chrome/google_chrome_for_testing/linux/product_logo_128.png" type="BINDATA" /> + <include name="IDR_PRODUCT_LOGO_128_DEV" file="google_chrome/google_chrome_for_testing/linux/product_logo_128.png" type="BINDATA" /> + <include name="IDR_PRODUCT_LOGO_256" file="google_chrome/google_chrome_for_testing/linux/product_logo_256.png" type="BINDATA" /> + </then> + <else> + <include name="IDR_PRODUCT_LOGO_64" file="google_chrome/google_chrome_for_testing/product_logo_64.png" type="BINDATA" /> + <include name="IDR_PRODUCT_LOGO_128" file="google_chrome/google_chrome_for_testing/product_logo_128.png" type="BINDATA" /> + <include name="IDR_PRODUCT_LOGO_256" file="google_chrome/google_chrome_for_testing/product_logo_256.png" type="BINDATA" /> + </else> + </if> </then> - <else> - <include name="IDR_PRODUCT_LOGO_64" file="google_chrome/product_logo_64.png" type="BINDATA" /> - <include name="IDR_PRODUCT_LOGO_128" file="google_chrome/product_logo_128.png" type="BINDATA" /> - <include name="IDR_PRODUCT_LOGO_256" file="google_chrome/product_logo_256.png" type="BINDATA" /> + <else> <!-- not _google_chrome_for_testing --> + <if expr="is_linux"> + <then> + <include name="IDR_PRODUCT_LOGO_64" file="google_chrome/linux/product_logo_64.png" type="BINDATA" /> + <include name="IDR_PRODUCT_LOGO_128" file="google_chrome/linux/product_logo_128.png" type="BINDATA" /> + <include name="IDR_PRODUCT_LOGO_128_BETA" file="google_chrome/linux/product_logo_128_beta.png" type="BINDATA" /> + <include name="IDR_PRODUCT_LOGO_128_DEV" file="google_chrome/linux/product_logo_128_dev.png" type="BINDATA" /> + <include name="IDR_PRODUCT_LOGO_256" file="google_chrome/linux/product_logo_256.png" type="BINDATA" /> + </then> + <else> + <include name="IDR_PRODUCT_LOGO_64" file="google_chrome/product_logo_64.png" type="BINDATA" /> + <include name="IDR_PRODUCT_LOGO_128" file="google_chrome/product_logo_128.png" type="BINDATA" /> + <include name="IDR_PRODUCT_LOGO_256" file="google_chrome/product_logo_256.png" type="BINDATA" /> + </else> + </if> </else> </if> <include name="IDR_PRODUCT_LOGO_24PX_1X" file="google_chrome/chrome_24px_1x.svg" type="BINDATA" />
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index 148800e77..3a88503 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -137,8 +137,8 @@ <then> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_16" file="google_chrome/google_chrome_for_testing/linux/product_logo_16.png" /> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32" file="google_chrome/google_chrome_for_testing/linux/product_logo_32.png" /> - <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32_BETA" file="google_chrome/google_chrome_for_testing/linux/product_logo_32_beta.png" /> - <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32_DEV" file="google_chrome/google_chrome_for_testing/linux/product_logo_32_dev.png" /> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32_BETA" file="google_chrome/google_chrome_for_testing/linux/product_logo_32.png" /> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32_DEV" file="google_chrome/google_chrome_for_testing/linux/product_logo_32.png" /> </then> <else> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_16" file="google_chrome/linux/product_logo_16.png" /> @@ -163,8 +163,8 @@ </if> <!-- not is_android --> <if expr="_google_chrome_for_testing"> <then> - <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32_BETA" file="google_chrome/google_chrome_for_testing/product_logo_32_beta.png" /> - <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32_DEV" file="google_chrome/google_chrome_for_testing/product_logo_32_dev.png" /> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32_BETA" file="google_chrome/google_chrome_for_testing/product_logo_32.png" /> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32_DEV" file="google_chrome/google_chrome_for_testing/product_logo_32.png" /> </then> <else> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_32_BETA" file="google_chrome/product_logo_32_beta.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 3c86fbf6..bc4ce9e 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -631,9 +631,13 @@ "interstitials/enterprise_util.h", "invalidation/profile_invalidation_provider_factory.cc", "invalidation/profile_invalidation_provider_factory.h", + "k_anonymity_service/k_anonymity_service_client.cc", + "k_anonymity_service/k_anonymity_service_client.h", "k_anonymity_service/k_anonymity_service_urls.h", "k_anonymity_service/k_anonymity_trust_token_getter.cc", "k_anonymity_service/k_anonymity_trust_token_getter.h", + "k_anonymity_service/remote_trust_token_query_answerer.cc", + "k_anonymity_service/remote_trust_token_query_answerer.h", "language/accept_languages_service_factory.cc", "language/accept_languages_service_factory.h", "language/language_model_manager_factory.cc", @@ -3036,6 +3040,8 @@ "fast_checkout/fast_checkout_client_impl.h", "fast_checkout/fast_checkout_external_action_delegate.cc", "fast_checkout/fast_checkout_external_action_delegate.h", + "fast_checkout/fast_checkout_tab_helper.cc", + "fast_checkout/fast_checkout_tab_helper.h", "fast_checkout/fast_checkout_util.cc", "fast_checkout/fast_checkout_util.h", "feature_guide/notifications/android/feature_notification_guide_bridge.cc", @@ -3394,6 +3400,7 @@ "//components/cdm/browser", "//components/commerce/core:commerce_subscription_db_content_proto", "//components/commerce/core:feature_list", + "//components/commerce/core:heuristics_provider", "//components/commerce/core:merchant_signal_db_proto", "//components/commerce/core:proto", "//components/component_updater/android:native_background_task_update_scheduler", @@ -5653,6 +5660,7 @@ "//components/arc/common", "//components/reporting/metrics:metrics_data_collection", "//extensions/browser/updater", + "//ui/chromeos/strings:strings_grit", "//ui/chromeos/styles:cros_styles_views", "//ui/platform_window", ] @@ -8229,6 +8237,8 @@ "autofill/mock_password_accessory_controller.h", "download/android/mock_download_controller.cc", "download/android/mock_download_controller.h", + "fast_checkout/mock_fast_checkout_capabilities_fetcher.cc", + "fast_checkout/mock_fast_checkout_capabilities_fetcher.h", ] deps += [ "//chrome/android:test_support_jni_headers" ] } else {
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc b/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc index db2799b..63674b8 100644 --- a/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc +++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc
@@ -400,11 +400,11 @@ TestingProfile profile; auto* proxy = AppServiceProxyFactory::GetForProfile(&profile); - std::string test_arc_app = "test_arc_app_id"; - std::string test_web_app = "test_web_app_id"; - UpdateAppReadiness(proxy, "app1", test_arc_app, apps::AppType::kArc, + std::string skype_arc_app_id = "com.skype.raider"; + std::string skype_web_app_id = "https://web.skype.com/"; + UpdateAppReadiness(proxy, "app1", skype_arc_app_id, apps::AppType::kArc, Readiness::kReady); - UpdateAppReadiness(proxy, "app2", test_web_app, apps::AppType::kWeb, + UpdateAppReadiness(proxy, "app2", skype_web_app_id, apps::AppType::kWeb, Readiness::kReady); ASSERT_TRUE(AppDeduplicationServiceFactory:: @@ -412,25 +412,32 @@ auto* service = AppDeduplicationServiceFactory::GetForProfile(&profile); EXPECT_NE(nullptr, service); - std::string binary_pb = ""; + std::string app_with_locale_pb = ""; base::FilePath install_dir("/"); - // TODO(b/238394602): Move the fake data population to test only when real - // data feeds in. + base::FilePath path; + EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &path)); + path = path.AppendASCII("app_deduplication_service/binary_test_data.pb"); + std::string dedupe_pb; + ASSERT_TRUE(base::ReadFileToString(path, &dedupe_pb)); + + ComponentFileContents component_files = {app_with_locale_pb, dedupe_pb}; apps::AppProvisioningDataManager::Get()->PopulateFromDynamicUpdate( - binary_pb, install_dir); + component_files, install_dir); - EntryId arc_entry_id("test_arc_app_id", apps::AppType::kArc); - EntryId web_entry_id("test_web_app_id", apps::AppType::kWeb); + EntryId skype_arc_entry_id(skype_arc_app_id, apps::AppType::kArc); + EntryId skype_web_entry_id(skype_web_app_id, apps::AppType::kWeb); + EntryId skype_phonehub_entry_id("com.skype.raider"); - EXPECT_THAT(service->GetDuplicates(arc_entry_id), - ElementsAre(Entry(arc_entry_id), Entry(web_entry_id))); - EXPECT_THAT(service->GetDuplicates(web_entry_id), - ElementsAre(Entry(arc_entry_id), Entry(web_entry_id))); - EXPECT_TRUE(service->AreDuplicates(arc_entry_id, web_entry_id)); + EXPECT_THAT( + service->GetDuplicates(skype_arc_entry_id), + ElementsAre(Entry(skype_phonehub_entry_id), Entry(skype_arc_entry_id), + Entry(skype_web_entry_id))); + EXPECT_TRUE(service->AreDuplicates(skype_arc_entry_id, skype_web_entry_id)); EntryId not_duplicate_app_id("not_duplicate_app_id", apps::AppType::kWeb); EXPECT_TRUE(service->GetDuplicates(not_duplicate_app_id).empty()); - EXPECT_FALSE(service->AreDuplicates(not_duplicate_app_id, web_entry_id)); + EXPECT_FALSE( + service->AreDuplicates(not_duplicate_app_id, skype_web_entry_id)); } } // namespace apps::deduplication
diff --git a/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.cc b/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.cc index 861b694..425d0f7 100644 --- a/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.cc +++ b/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.cc
@@ -14,22 +14,20 @@ namespace apps { namespace { -// TODO(b/238394602): Use fake data for now. Update to generate from real data -// when real data is ready. -std::unique_ptr<proto::DuplicatedGroupList> PopulateDuplicatedGroupList() { +std::unique_ptr<proto::DuplicatedGroupList> PopulateDuplicatedGroupList( + const std::string& binary_pb) { + // Parse the proto and do some validation on it. + if (binary_pb.empty()) { + LOG(ERROR) << "Binary is empty"; + return nullptr; + } + std::unique_ptr<proto::DuplicatedGroupList> duplicated_group_list = std::make_unique<proto::DuplicatedGroupList>(); - auto* add_group = duplicated_group_list->add_duplicate_group(); - proto::DuplicateGroup duplicate_group; - auto* arc_app = duplicate_group.add_app(); - arc_app->set_app_id_for_platform("test_arc_app_id"); - arc_app->set_source_name("arc"); - - auto* web_app = duplicate_group.add_app(); - web_app->set_app_id_for_platform("test_web_app_id"); - web_app->set_source_name("web"); - - *add_group = duplicate_group; + if (!duplicated_group_list->ParseFromString(binary_pb)) { + LOG(ERROR) << "Failed to parse protobuf"; + return nullptr; + } return duplicated_group_list; } @@ -63,12 +61,14 @@ AppProvisioningDataManager::~AppProvisioningDataManager() = default; void AppProvisioningDataManager::PopulateFromDynamicUpdate( - const std::string& binary_pb, + const ComponentFileContents& component_files, const base::FilePath& install_dir) { // TODO(melzhang) : Add check that version of |app_with_locale_list| is newer. - app_with_locale_list_ = PopulateAppWithLocaleList(binary_pb); + app_with_locale_list_ = + PopulateAppWithLocaleList(component_files.app_with_locale_pb); if (base::FeatureList::IsEnabled(features::kAppDeduplicationService)) { - duplicated_group_list_ = PopulateDuplicatedGroupList(); + duplicated_group_list_ = + PopulateDuplicatedGroupList(component_files.deduplication_pb); } data_dir_ = install_dir; OnAppDataUpdated();
diff --git a/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.h b/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.h index 324d24d..572c320f 100644 --- a/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.h +++ b/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.h
@@ -15,6 +15,11 @@ namespace apps { +struct ComponentFileContents { + std::string app_with_locale_pb; + std::string deduplication_pb; +}; + // The AppProvisioningDataManager parses the updates received from the Component // Updater and forwards the data in the desired format to the relevant service. // E.g. Component Updater sends through new discovery app data, after parsing @@ -41,11 +46,12 @@ static AppProvisioningDataManager* GetInstance(); // Singleton - // Update the internal list from a binary proto fetched from the network. + // Update the internal list from the binary proto files fetched from the + // network. // Same integrity checks apply. This can be called multiple times with new // protos. - void PopulateFromDynamicUpdate(const std::string& binary_pb, - const base::FilePath& data_dir); + void PopulateFromDynamicUpdate(const ComponentFileContents& component_files, + const base::FilePath& install_dir); const base::FilePath& GetDataFilePath();
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc index b601231..331f843e 100644 --- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -119,7 +119,7 @@ class WebViewInteractiveTest : public extensions::PlatformAppBrowserTest { public: WebViewInteractiveTest() - : guest_web_contents_(nullptr), + : guest_view_(nullptr), embedder_web_contents_(nullptr), corner_(gfx::Point()), mouse_click_result_(false), @@ -300,8 +300,7 @@ ASSERT_TRUE(done_listener->WaitUntilSatisfied()); embedder_web_contents_ = embedder_web_contents; - guest_web_contents_ = - GetGuestViewManager()->DeprecatedWaitForSingleGuestCreated(); + guest_view_ = GetGuestViewManager()->WaitForSingleGuestViewCreated(); } void SendMessageToEmbedder(const std::string& message) { @@ -313,36 +312,27 @@ void SetupTest(const std::string& app_name, const std::string& guest_url_spec) { ASSERT_TRUE(StartEmbeddedTestServer()); - GURL::Replacements replace_host; - replace_host.SetHostStr("localhost"); - - GURL guest_url = embedded_test_server()->GetURL(guest_url_spec); - guest_url = guest_url.ReplaceComponents(replace_host); - - ui_test_utils::UrlLoadObserver guest_observer( - guest_url, content::NotificationService::AllSources()); LoadAndLaunchPlatformApp(app_name.c_str(), "connected"); - guest_observer.Wait(); - content::Source<content::NavigationController> source = - guest_observer.source(); - EXPECT_TRUE(source->DeprecatedGetWebContents() - ->GetPrimaryMainFrame() - ->GetProcess() - ->IsForGuestsOnly()); + guest_view_ = GetGuestViewManager()->WaitForSingleGuestViewCreated(); + ASSERT_TRUE( + guest_view_->GetGuestMainFrame()->GetProcess()->IsForGuestsOnly()); - guest_web_contents_ = source->DeprecatedGetWebContents(); - embedder_web_contents_ = - GuestViewBase::FromWebContents(guest_web_contents_)-> - embedder_web_contents(); + embedder_web_contents_ = guest_view_->embedder_web_contents(); gfx::Rect offset = embedder_web_contents_->GetContainerBounds(); corner_ = offset.origin(); } - content::WebContents* guest_web_contents() { - return guest_web_contents_; + content::WebContents* DeprecatedGuestWebContents() { + return guest_view_->web_contents(); + } + + guest_view::GuestViewBase* GetGuestView() { return guest_view_; } + + content::RenderFrameHost* GetGuestRenderFrameHost() { + return guest_view_->GetGuestMainFrame(); } content::WebContents* embedder_web_contents() { @@ -444,9 +434,9 @@ popup_observer.Init(); // Press alt+DOWN to open popup. bool alt = true; - content::SimulateKeyPress(guest_web_contents(), ui::DomKey::ARROW_DOWN, - ui::DomCode::ARROW_DOWN, ui::VKEY_DOWN, false, - false, alt, false); + content::SimulateKeyPress(DeprecatedGuestWebContents(), + ui::DomKey::ARROW_DOWN, ui::DomCode::ARROW_DOWN, + ui::VKEY_DOWN, false, false, alt, false); popup_observer.Wait(); content::RenderWidgetHost* popup_rwh = @@ -473,7 +463,7 @@ EXPECT_LE(std::abs(diff.y() - top_spacing), threshold_px); // Close the popup. - content::SimulateKeyPress(guest_web_contents(), ui::DomKey::ESCAPE, + content::SimulateKeyPress(DeprecatedGuestWebContents(), ui::DomKey::ESCAPE, ui::DomCode::ESCAPE, ui::VKEY_ESCAPE, false, false, false, false); } @@ -484,11 +474,11 @@ content::WebContents* embedder_web_contents = GetFirstAppWindowWebContents(); ASSERT_TRUE(embedder_web_contents); - ASSERT_TRUE(guest_web_contents()); + ASSERT_TRUE(DeprecatedGuestWebContents()); // Click the guest to request fullscreen. ExtensionTestMessageListener passed_listener("FULLSCREEN_STEP_PASSED"); passed_listener.set_failure_message("TEST_FAILED"); - content::SimulateMouseClickAt(guest_web_contents(), 0, + content::SimulateMouseClickAt(DeprecatedGuestWebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(20, 20)); ASSERT_TRUE(passed_listener.WaitUntilSatisfied()); @@ -496,8 +486,10 @@ protected: TestGuestViewManagerFactory factory_; - raw_ptr<content::WebContents> guest_web_contents_; + // Only set if `SetupTest` or `TestHelper` are called. + raw_ptr<guest_view::GuestViewBase> guest_view_; raw_ptr<content::WebContents> embedder_web_contents_; + gfx::Point corner_; bool mouse_click_result_; bool first_click_; @@ -696,7 +688,7 @@ ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED"); next_step_listener.set_failure_message("TEST_STEP_FAILED"); - content::SimulateMouseClickAt(guest_web_contents(), 0, + content::SimulateMouseClickAt(DeprecatedGuestWebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(clickX, clickY)); ASSERT_TRUE(next_step_listener.WaitUntilSatisfied()); @@ -923,7 +915,7 @@ IN_PROC_BROWSER_TEST_F(DISABLED_WebViewPopupInteractiveTest, PopupPositioningBasic) { TestHelper("testBasic", "web_view/popup_positioning", NO_TEST_SERVER); - ASSERT_TRUE(guest_web_contents()); + ASSERT_TRUE(DeprecatedGuestWebContents()); PopupTestHelper(gfx::Point()); // TODO(lazyboy): Move the embedder window to a random location and @@ -938,7 +930,7 @@ IN_PROC_BROWSER_TEST_F(DISABLED_WebViewPopupInteractiveTest, PopupPositioningMoved) { TestHelper("testMoved", "web_view/popup_positioning", NO_TEST_SERVER); - ASSERT_TRUE(guest_web_contents()); + ASSERT_TRUE(DeprecatedGuestWebContents()); PopupTestHelper(gfx::Point(20, 0)); } @@ -1060,13 +1052,13 @@ TestHelper("testFocusRestored", "web_view/focus", NO_TEST_SERVER); content::WebContents* embedder_web_contents = GetFirstAppWindowWebContents(); ASSERT_TRUE(embedder_web_contents); - ASSERT_TRUE(guest_web_contents()); + ASSERT_TRUE(DeprecatedGuestWebContents()); // 1) We click on the guest so that we get a focus event. ExtensionTestMessageListener next_step_listener("TEST_STEP_PASSED"); next_step_listener.set_failure_message("TEST_STEP_FAILED"); { - content::SimulateMouseClickAt(guest_web_contents(), 0, + content::SimulateMouseClickAt(DeprecatedGuestWebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(10, 10)); EXPECT_TRUE(content::ExecuteScript( @@ -1094,7 +1086,7 @@ // input element, then we ensure text_input_type is properly set. next_step_listener.Reset(); { - content::SimulateMouseClickAt(guest_web_contents(), 0, + content::SimulateMouseClickAt(DeprecatedGuestWebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(10, 10)); EXPECT_TRUE(content::ExecuteScript( @@ -1211,7 +1203,7 @@ IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, MAYBE_LongPressSelection) { SetupTest("web_view/text_selection", "/extensions/platform_apps/web_view/text_selection/guest.html"); - ASSERT_TRUE(guest_web_contents()); + ASSERT_TRUE(DeprecatedGuestWebContents()); ASSERT_TRUE(embedder_web_contents()); ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow())); @@ -1221,7 +1213,9 @@ context_menu_gesture_event_type = blink::WebInputEvent::Type::kGestureLongTap; #endif auto filter = std::make_unique<content::InputMsgWatcher>( - guest_web_contents()->GetRenderWidgetHostView()->GetRenderWidgetHost(), + DeprecatedGuestWebContents() + ->GetRenderWidgetHostView() + ->GetRenderWidgetHost(), context_menu_gesture_event_type); // Wait for guest to load (without this the events never reach the guest). @@ -1231,7 +1225,7 @@ FROM_HERE, message_loop_runner->QuitClosure(), base::Milliseconds(200)); message_loop_runner->Run(); - gfx::Rect guest_rect = guest_web_contents()->GetContainerBounds(); + gfx::Rect guest_rect = DeprecatedGuestWebContents()->GetContainerBounds(); gfx::Point embedder_origin = embedder_web_contents()->GetContainerBounds().origin(); guest_rect.Offset(-embedder_origin.x(), -embedder_origin.y()); @@ -1256,7 +1250,7 @@ EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); #endif - EXPECT_FALSE(guest_web_contents()->IsShowingContextMenu()); + EXPECT_FALSE(DeprecatedGuestWebContents()->IsShowingContextMenu()); } #endif @@ -1264,21 +1258,22 @@ IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, TextSelection) { SetupTest("web_view/text_selection", "/extensions/platform_apps/web_view/text_selection/guest.html"); - ASSERT_TRUE(guest_web_contents()); + ASSERT_TRUE(DeprecatedGuestWebContents()); ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow( GetPlatformAppWindow())); // Wait until guest sees a context menu. ExtensionTestMessageListener ctx_listener("MSG_CONTEXTMENU"); ContextMenuWaiter menu_observer; - SimulateRWHMouseClick(guest_web_contents()->GetRenderViewHost()->GetWidget(), - blink::WebMouseEvent::Button::kRight, 20, 20); + SimulateRWHMouseClick( + DeprecatedGuestWebContents()->GetRenderViewHost()->GetWidget(), + blink::WebMouseEvent::Button::kRight, 20, 20); menu_observer.WaitForMenuOpenAndClose(); ASSERT_TRUE(ctx_listener.WaitUntilSatisfied()); // Now verify that the selection text propagates properly to RWHV. content::RenderWidgetHostView* guest_rwhv = - guest_web_contents()->GetRenderWidgetHostView(); + DeprecatedGuestWebContents()->GetRenderWidgetHostView(); ASSERT_TRUE(guest_rwhv); std::string selected_text = base::UTF16ToUTF8(guest_rwhv->GetSelectedText()); ASSERT_GE(selected_text.size(), 10u); @@ -1290,18 +1285,20 @@ IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, WordLookup) { SetupTest("web_view/text_selection", "/extensions/platform_apps/web_view/text_selection/guest.html"); - ASSERT_TRUE(guest_web_contents()); + ASSERT_TRUE(DeprecatedGuestWebContents()); ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow())); content::TextInputTestLocalFrame text_input_local_frame; - text_input_local_frame.SetUp(guest_web_contents()->GetPrimaryMainFrame()); + text_input_local_frame.SetUp( + DeprecatedGuestWebContents()->GetPrimaryMainFrame()); // Lookup some string through context menu. ContextMenuNotificationObserver menu_observer(IDC_CONTENT_CONTEXT_LOOK_UP); // Simulating a mouse click at a position to highlight text in guest and // showing the context menu. - SimulateRWHMouseClick(guest_web_contents()->GetRenderViewHost()->GetWidget(), - blink::WebMouseEvent::Button::kRight, 20, 20); + SimulateRWHMouseClick( + DeprecatedGuestWebContents()->GetRenderViewHost()->GetWidget(), + blink::WebMouseEvent::Button::kRight, 20, 20); // Wait for the response form the guest renderer. text_input_local_frame.WaitForGetStringForRange(); @@ -1647,13 +1644,13 @@ IN_PROC_BROWSER_TEST_F(WebViewFocusInteractiveTest, DropDownPopupInCorrectPosition) { TestHelper("testSelectPopupPositionInMac", "web_view/shim", NO_TEST_SERVER); - ASSERT_TRUE(guest_web_contents_); + ASSERT_TRUE(DeprecatedGuestWebContents()); // This is set in javascript. const float distance_from_root_view_origin = 250.0; // Verify that the view is offset inside root view as expected. content::RenderWidgetHostView* guest_rwhv = - guest_web_contents_->GetRenderWidgetHostView(); + DeprecatedGuestWebContents()->GetRenderWidgetHostView(); while (guest_rwhv->TransformPointToRootCoordSpace(gfx::Point()) .OffsetFromOrigin() .Length() < distance_from_root_view_origin) {
diff --git a/chrome/browser/apps/platform_apps/DIR_METADATA b/chrome/browser/apps/platform_apps/DIR_METADATA new file mode 100644 index 0000000..9bf2d2f --- /dev/null +++ b/chrome/browser/apps/platform_apps/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail: { + component: "Platform>Apps" +}
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn index ed0899d..2aca611 100644 --- a/chrome/browser/ash/BUILD.gn +++ b/chrome/browser/ash/BUILD.gn
@@ -2139,6 +2139,8 @@ "printing/usb_printer_util.h", "printing/zeroconf_printer_detector.cc", "printing/zeroconf_printer_detector.h", + "privacy_hub/privacy_hub_util.cc", + "privacy_hub/privacy_hub_util.h", "process_snapshot_server.cc", "process_snapshot_server.h", "profiles/browser_context_helper_delegate_impl.cc",
diff --git a/chrome/browser/ash/crosapi/browser_manager.cc b/chrome/browser/ash/crosapi/browser_manager.cc index c5cccc07..c526fbe 100644 --- a/chrome/browser/ash/crosapi/browser_manager.cc +++ b/chrome/browser/ash/crosapi/browser_manager.cc
@@ -808,7 +808,7 @@ // Paths are UTF-8 safe on Chrome OS. std::string user_data_dir = browser_util::GetUserDataDir().AsUTF8Unsafe(); std::string crash_dir = - browser_util::GetUserDataDir().Append("crash_dumps").AsUTF8Unsafe(); + browser_util::GetUserDataDir().Append("Crash Reports").AsUTF8Unsafe(); // Pass the locale via command line instead of via LacrosInitParams because // the Lacros browser process needs it early in startup, before zygote fork.
diff --git a/chrome/browser/ash/file_manager/file_manager_jstest.cc b/chrome/browser/ash/file_manager/file_manager_jstest.cc index 7cce203..5f4e1e1 100644 --- a/chrome/browser/ash/file_manager/file_manager_jstest.cc +++ b/chrome/browser/ash/file_manager/file_manager_jstest.cc
@@ -326,3 +326,7 @@ IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ReducerAllEntries) { RunTestURL("state/reducers/all_entries_unittest.js"); } + +IN_PROC_BROWSER_TEST_F(FileManagerJsTest, XfDlpRestrictionDetailsDialog) { + RunTestURL("widgets/xf_dlp_restriction_details_dialog_unittest.js"); +}
diff --git a/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc b/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc index 9c58133e..04a7c5f9 100644 --- a/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc +++ b/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc
@@ -427,6 +427,11 @@ continue; } + if (engine.engine_id == "vkd_hi_inscript" && + !base::FeatureList::IsEnabled(features::kHindiInscriptLayout)) { + continue; + } + component_ime.engines.push_back(engine); } out_imes->push_back(component_ime);
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_target_device_connection_broker.cc b/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_target_device_connection_broker.cc index e26ad92..c45ddbb 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_target_device_connection_broker.cc +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_target_device_connection_broker.cc
@@ -68,4 +68,14 @@ fake_connection_ = std::move(fake_authenticated_connection); } +void FakeTargetDeviceConnectionBroker::RejectConnection( + const std::string& source_device_id) { + connection_lifecycle_listener_->OnConnectionRejected(source_device_id); +} + +void FakeTargetDeviceConnectionBroker::CloseConnection( + const std::string& source_device_id) { + connection_lifecycle_listener_->OnConnectionClosed(source_device_id); +} + } // namespace ash::quick_start
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_target_device_connection_broker.h b/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_target_device_connection_broker.h index 28e60d02..9cd808f 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_target_device_connection_broker.h +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/fake_target_device_connection_broker.h
@@ -74,6 +74,8 @@ void StopAdvertising(base::OnceClosure on_stop_advertising_callback) override; void InitiateConnection(const std::string& source_device_id); void AuthenticateConnection(const std::string& source_device_id); + void RejectConnection(const std::string& source_device_id); + void CloseConnection(const std::string& source_device_id); void set_feature_support_status(FeatureSupportStatus feature_support_status) { feature_support_status_ = feature_support_status;
diff --git a/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.cc b/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.cc index 2c95335..3f542e7d 100644 --- a/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.cc +++ b/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.cc
@@ -99,6 +99,7 @@ // New connection came. It should be a different device. DCHECK_NE(source_device_id_, source_device_id); } + source_device_id_ = source_device_id; incoming_connection_ = std::move(connection); auto qr_code = GenerateQRCode(incoming_connection_->GetQrCodeData()); status_.step = Step::QR_CODE_VERIFICATION; @@ -109,6 +110,7 @@ void TargetDeviceBootstrapController::OnConnectionAuthenticated( const std::string& source_device_id, base::WeakPtr<AuthenticatedConnection> connection) { + DCHECK_EQ(source_device_id_, source_device_id); constexpr Step kPossibleSteps[] = {Step::QR_CODE_VERIFICATION}; DCHECK(base::Contains(kPossibleSteps, status_.step)); DCHECK(incoming_connection_.WasInvalidated()); @@ -120,14 +122,18 @@ void TargetDeviceBootstrapController::OnConnectionRejected( const std::string& source_device_id) { - // TODO(b/239855593): Implement - NOTIMPLEMENTED(); + DCHECK_EQ(source_device_id_, source_device_id); + status_.step = Step::ERROR; + status_.payload = ErrorCode::CONNECTION_REJECTED; + NotifyObservers(); } void TargetDeviceBootstrapController::OnConnectionClosed( const std::string& source_device_id) { - // TODO(b/239855593): Implement - NOTIMPLEMENTED(); + DCHECK_EQ(source_device_id_, source_device_id); + status_.step = Step::ERROR; + status_.payload = ErrorCode::CONNECTION_CLOSED; + NotifyObservers(); } void TargetDeviceBootstrapController::NotifyObservers() {
diff --git a/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.h b/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.h index 31ba9b8b..2fdd34d 100644 --- a/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.h +++ b/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.h
@@ -37,6 +37,8 @@ enum class ErrorCode { START_ADVERTISING_FAILED, + CONNECTION_REJECTED, + CONNECTION_CLOSED, }; using QRCodePixelData = std::vector<uint8_t>;
diff --git a/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller_unittest.cc b/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller_unittest.cc index 9c035c6..ac5a69de 100644 --- a/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller_unittest.cc +++ b/chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller_unittest.cc
@@ -162,3 +162,31 @@ ash::quick_start::FakeTargetDeviceConnectionBroker:: FeatureSupportStatus::kNotSupported); } + +TEST_F(TargetDeviceBootstrapControllerTest, RejectConnection) { + bootstrap_controller_->StartAdvertising(); + connection_broker()->on_start_advertising_callback().Run(/*success=*/true); + connection_broker()->InitiateConnection(kSourceDeviceId); + + connection_broker()->RejectConnection(kSourceDeviceId); + + EXPECT_EQ(fake_observer_->last_status.step, Step::ERROR); + ASSERT_TRUE( + absl::holds_alternative<ErrorCode>(fake_observer_->last_status.payload)); + EXPECT_EQ(absl::get<ErrorCode>(fake_observer_->last_status.payload), + ErrorCode::CONNECTION_REJECTED); +} + +TEST_F(TargetDeviceBootstrapControllerTest, CloseConnection) { + bootstrap_controller_->StartAdvertising(); + connection_broker()->on_start_advertising_callback().Run(/*success=*/true); + connection_broker()->InitiateConnection(kSourceDeviceId); + + connection_broker()->CloseConnection(kSourceDeviceId); + + EXPECT_EQ(fake_observer_->last_status.step, Step::ERROR); + ASSERT_TRUE( + absl::holds_alternative<ErrorCode>(fake_observer_->last_status.payload)); + EXPECT_EQ(absl::get<ErrorCode>(fake_observer_->last_status.payload), + ErrorCode::CONNECTION_CLOSED); +}
diff --git a/chrome/browser/ash/login/screens/quick_start_screen.cc b/chrome/browser/ash/login/screens/quick_start_screen.cc index e9ee7c4..6f709f8 100644 --- a/chrome/browser/ash/login/screens/quick_start_screen.cc +++ b/chrome/browser/ash/login/screens/quick_start_screen.cc
@@ -3,18 +3,18 @@ // found in the LICENSE file. #include "chrome/browser/ash/login/screens/quick_start_screen.h" +#include <memory> -#include "base/bind.h" #include "base/i18n/time_formatting.h" #include "base/memory/weak_ptr.h" #include "base/notreached.h" #include "base/strings/utf_string_conversions.h" -#include "base/threading/sequenced_task_runner_handle.h" #include "base/time/time.h" #include "chrome/browser/ash/login/oobe_quick_start/target_device_bootstrap_controller.h" #include "chrome/browser/ash/login/oobe_quick_start/verification_shapes.h" #include "chrome/browser/ash/login/ui/login_display_host.h" #include "chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.h" +#include "third_party/abseil-cpp/absl/types/variant.h" namespace ash { @@ -49,12 +49,6 @@ LoginDisplayHost::default_host()->GetQuickStartBootstrapController(); bootstrap_controller_->AddObserver(this); bootstrap_controller_->StartAdvertising(); - - base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&QuickStartScreen::SendRandomFiguresForTesting, // IN-TEST - base::Unretained(this)), - base::Seconds(1)); } void QuickStartScreen::HideImpl() { @@ -64,13 +58,33 @@ UnbindFromBootstrapController(); } -void QuickStartScreen::OnUserAction(const base::Value::List& args) { - SendRandomFiguresForTesting(); // IN-TEST -} +void QuickStartScreen::OnUserAction(const base::Value::List& args) {} void QuickStartScreen::OnStatusChanged( const quick_start::TargetDeviceBootstrapController::Status& status) { - NOTIMPLEMENTED(); + using Step = quick_start::TargetDeviceBootstrapController::Step; + using QRCodePixelData = + quick_start::TargetDeviceBootstrapController::QRCodePixelData; + + switch (status.step) { + case Step::QR_CODE_VERIFICATION: { + CHECK(absl::holds_alternative<QRCodePixelData>(status.payload)); + if (!view_) + return; + const auto& code = absl::get<QRCodePixelData>(status.payload); + base::Value::List qr_code_list; + for (const auto& it : code) { + qr_code_list.Append(base::Value(static_cast<bool>(it & 1))); + } + view_->SetQRCode(std::move(qr_code_list)); + return; + } + case Step::NONE: + case Step::ERROR: + case Step::ADVERTISING: + case Step::CONNECTED: + NOTIMPLEMENTED(); + } } void QuickStartScreen::UnbindFromBootstrapController() {
diff --git a/chrome/browser/ash/login/screens/quick_start_screen_browsertest.cc b/chrome/browser/ash/login/screens/quick_start_screen_browsertest.cc index 89a565da..30064f8 100644 --- a/chrome/browser/ash/login/screens/quick_start_screen_browsertest.cc +++ b/chrome/browser/ash/login/screens/quick_start_screen_browsertest.cc
@@ -3,12 +3,15 @@ // found in the LICENSE file. #include "ash/constants/ash_features.h" +#include "base/run_loop.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/ash/login/oobe_quick_start/connectivity/fake_target_device_connection_broker.h" #include "chrome/browser/ash/login/oobe_quick_start/connectivity/target_device_connection_broker.h" +#include "chrome/browser/ash/login/screens/quick_start_screen.h" #include "chrome/browser/ash/login/test/js_checker.h" #include "chrome/browser/ash/login/test/oobe_base_test.h" #include "chrome/browser/ash/login/test/oobe_screen_waiter.h" +#include "chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h" #include "content/public/test/browser_test.h" @@ -30,9 +33,6 @@ void SetUpInProcessBrowserTestFixture() override { OobeBaseTest::SetUpInProcessBrowserTestFixture(); - connection_broker_factory_.set_initial_feature_support_status( - quick_start::TargetDeviceConnectionBroker::FeatureSupportStatus:: - kUndetermined); quick_start::TargetDeviceConnectionBrokerFactory::SetFactoryForTesting( &connection_broker_factory_); } @@ -51,7 +51,17 @@ base::test::ScopedFeatureList feature_list_; }; -IN_PROC_BROWSER_TEST_F(QuickStartBrowserTest, ButtonVisibleOnWelcomeScreen) { +class QuickStartNotDeterminedBrowserTest : public QuickStartBrowserTest { + public: + QuickStartNotDeterminedBrowserTest() { + connection_broker_factory_.set_initial_feature_support_status( + quick_start::TargetDeviceConnectionBroker::FeatureSupportStatus:: + kUndetermined); + } +}; + +IN_PROC_BROWSER_TEST_F(QuickStartNotDeterminedBrowserTest, + ButtonVisibleOnWelcomeScreen) { OobeScreenWaiter(chromeos::WelcomeView::kScreenId).Wait(); test::OobeJS().ExpectHiddenPath(kQuickStartButtonPath); @@ -64,4 +74,23 @@ ->Wait(); } +IN_PROC_BROWSER_TEST_F(QuickStartBrowserTest, QRCode) { + OobeScreenWaiter(chromeos::WelcomeView::kScreenId).Wait(); + test::OobeJS().ExpectVisiblePath(kQuickStartButtonPath); + + test::OobeJS().ClickOnPath(kQuickStartButtonPath); + + OobeScreenWaiter(chromeos::QuickStartView::kScreenId).Wait(); + connection_broker_factory_.instances().front()->InitiateConnection( + "fake_device_id"); + + test::OobeJS() + .CreateWaiter( + test::GetOobeElementPath({chromeos::QuickStartView::kScreenId.name}) + + ".uiStep === 'verification'") + ->Wait(); + test::OobeJS().ExpectAttributeEQ( + "canvasSize_", {chromeos::QuickStartView::kScreenId.name}, 225); +} + } // namespace ash
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller.cc index dae44d7..faa3887a7 100644 --- a/chrome/browser/ash/policy/dlp/dlp_files_controller.cc +++ b/chrome/browser/ash/policy/dlp/dlp_files_controller.cc
@@ -326,12 +326,13 @@ std::vector<FileDaemonInfo> restricted_files; std::vector<FileDaemonInfo> warned_files; DlpConfidentialContents dialog_files; + std::string source_pattern, destination_pattern; for (const auto& file : transferred_files) { DlpRulesManager::Level level; if (dst_component.has_value()) { level = rules_manager_.IsRestrictedComponent( GURL(file.source_url), dst_component.value(), - DlpRulesManager::Restriction::kFiles, nullptr); + DlpRulesManager::Restriction::kFiles, &source_pattern); MaybeReportEvent(file.source_url.spec(), DlpFileDestination((dst_component.value())), level); } else { @@ -340,7 +341,8 @@ DCHECK(destination.url_or_path.has_value()); level = rules_manager_.IsRestrictedDestination( GURL(file.source_url), GURL(*destination.url_or_path), - DlpRulesManager::Restriction::kFiles, nullptr, nullptr); + DlpRulesManager::Restriction::kFiles, &source_pattern, + &destination_pattern); MaybeReportEvent(file.source_url.spec(), DlpFileDestination(*destination.url_or_path), level); } @@ -370,7 +372,8 @@ weak_ptr_factory_.GetWeakPtr(), std::move(restricted_files), std::move(warned_files), files_action, std::move(result_callback)), - std::move(dialog_files), files_action); + std::move(dialog_files), dst_component, destination_pattern, + files_action); } std::vector<DlpFilesController::DlpFileRestrictionDetails>
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_unittest.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller_unittest.cc index d3d5e30d..88e3417 100644 --- a/chrome/browser/ash/policy/dlp/dlp_files_controller_unittest.cc +++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_unittest.cc
@@ -980,6 +980,7 @@ } DlpWarnDialog::DlpWarnDialogOptions expected_dialog_options( DlpWarnDialog::Restriction::kFiles, expected_contents, + DlpRulesManager::Component::kUsb, /*destination_pattern=*/"", transfer_info.files_action); EXPECT_CALL(*rules_manager_,
diff --git a/chrome/browser/ash/privacy_hub/privacy_hub_util.cc b/chrome/browser/ash/privacy_hub/privacy_hub_util.cc new file mode 100644 index 0000000..f8c620c --- /dev/null +++ b/chrome/browser/ash/privacy_hub/privacy_hub_util.cc
@@ -0,0 +1,51 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ash/privacy_hub/privacy_hub_util.h" + +#include "ash/shell.h" +#include "ash/system/privacy_hub/camera_privacy_switch_controller.h" +#include "ash/system/privacy_hub/microphone_privacy_switch_controller.h" +#include "ash/system/privacy_hub/privacy_hub_controller.h" +#include "chromeos/ash/components/audio/cras_audio_handler.h" + +namespace ash::privacy_hub_util { + +namespace { +PrivacyHubController* ControllerIfAvailable() { + if (!Shell::HasInstance()) { + // Shell may not be available when used from a test. + return nullptr; + } + Shell* const shell = Shell::Get(); + DCHECK(shell != nullptr); + return shell->privacy_hub_controller(); +} +} // namespace + +void SetFrontend(PrivacyHubDelegate* ptr) { + PrivacyHubController* const controller = ControllerIfAvailable(); + if (controller != nullptr) { + // Controller may not be available when used from a test. + controller->set_frontend(ptr); + } +} + +cros::mojom::CameraPrivacySwitchState CameraHWSwitchState() { + PrivacyHubController* const controller = ControllerIfAvailable(); + if (controller == nullptr) { + return cros::mojom::CameraPrivacySwitchState::UNKNOWN; + } + return controller->camera_controller().HWSwitchState(); +} + +bool MicrophoneSwitchState() { + return ui::MicrophoneMuteSwitchMonitor::Get()->microphone_mute_switch_on(); +} + +bool HasActiveInputDeviceForSimpleUsage() { + return CrasAudioHandler::Get()->HasActiveInputDeviceForSimpleUsage(); +} + +} // namespace ash::privacy_hub_util
diff --git a/chrome/browser/ash/privacy_hub/privacy_hub_util.h b/chrome/browser/ash/privacy_hub/privacy_hub_util.h new file mode 100644 index 0000000..98eaa923 --- /dev/null +++ b/chrome/browser/ash/privacy_hub/privacy_hub_util.h
@@ -0,0 +1,29 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ASH_PRIVACY_HUB_PRIVACY_HUB_UTIL_H_ +#define CHROME_BROWSER_ASH_PRIVACY_HUB_PRIVACY_HUB_UTIL_H_ + +#include "ash/public/cpp/privacy_hub_delegate.h" +#include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h" + +namespace ash { + +class PrivacyHubDelegate; + +namespace privacy_hub_util { + +// Sets a given frontend handler withing the controller. +void SetFrontend(PrivacyHubDelegate* ptr); +// Returns the current HW switch state of the camera. +cros::mojom::CameraPrivacySwitchState CameraHWSwitchState(); +// Returns the current switch state of the microphone. +bool MicrophoneSwitchState(); +// Checks whether there are active input devices for simple usage. +bool HasActiveInputDeviceForSimpleUsage(); + +} // namespace privacy_hub_util +} // namespace ash + +#endif // CHROME_BROWSER_ASH_PRIVACY_HUB_PRIVACY_HUB_CONTROLLER_PROXY_H_
diff --git a/chrome/browser/autofill/manual_filling_controller.h b/chrome/browser/autofill/manual_filling_controller.h index fdf6502..4cd4983 100644 --- a/chrome/browser/autofill/manual_filling_controller.h +++ b/chrome/browser/autofill/manual_filling_controller.h
@@ -130,8 +130,7 @@ // Called by the UI to explicitly request a new sheet of the given type. virtual void RequestAccessorySheet( autofill::AccessoryTabType tab_type, - base::OnceCallback<void(const autofill::AccessorySheetData&)> - callback) = 0; + base::OnceCallback<void(autofill::AccessorySheetData)> callback) = 0; // ----------------- // Member accessors:
diff --git a/chrome/browser/autofill/manual_filling_controller_impl.cc b/chrome/browser/autofill/manual_filling_controller_impl.cc index 03cbaab9..df77c07 100644 --- a/chrome/browser/autofill/manual_filling_controller_impl.cc +++ b/chrome/browser/autofill/manual_filling_controller_impl.cc
@@ -231,7 +231,7 @@ void ManualFillingControllerImpl::RequestAccessorySheet( autofill::AccessoryTabType tab_type, - base::OnceCallback<void(const autofill::AccessorySheetData&)> callback) { + base::OnceCallback<void(autofill::AccessorySheetData)> callback) { // TODO(crbug.com/1169167): Consider to execute this async to reduce jank. absl::optional<AccessorySheetData> sheet = GetControllerForTabType(tab_type)->GetSheetData();
diff --git a/chrome/browser/autofill/manual_filling_controller_impl.h b/chrome/browser/autofill/manual_filling_controller_impl.h index 144fe451..f6c5c24c 100644 --- a/chrome/browser/autofill/manual_filling_controller_impl.h +++ b/chrome/browser/autofill/manual_filling_controller_impl.h
@@ -9,7 +9,6 @@ #include "base/callback_forward.h" #include "base/containers/flat_set.h" -#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/trace_event/memory_dump_provider.h" #include "chrome/browser/autofill/accessory_controller.h" @@ -59,8 +58,7 @@ bool enabled) const override; void RequestAccessorySheet( autofill::AccessoryTabType tab_type, - base::OnceCallback<void(const autofill::AccessorySheetData&)> callback) - override; + base::OnceCallback<void(autofill::AccessorySheetData)> callback) override; gfx::NativeView container_view() const override;
diff --git a/chrome/browser/autofill/manual_filling_view_interface.h b/chrome/browser/autofill/manual_filling_view_interface.h index 538d01d..c592bf1 100644 --- a/chrome/browser/autofill/manual_filling_view_interface.h +++ b/chrome/browser/autofill/manual_filling_view_interface.h
@@ -58,7 +58,7 @@ // Called with data that should replace the data currently shown in an // accessory sheet of the same type. - virtual void OnItemsAvailable(const autofill::AccessorySheetData& data) = 0; + virtual void OnItemsAvailable(autofill::AccessorySheetData data) = 0; // Called when the generation action should be offered or rescinded // in the keyboard accessory.
diff --git a/chrome/browser/autofill/mock_manual_filling_controller.h b/chrome/browser/autofill/mock_manual_filling_controller.h index 44f7728..d6e6c65 100644 --- a/chrome/browser/autofill/mock_manual_filling_controller.h +++ b/chrome/browser/autofill/mock_manual_filling_controller.h
@@ -37,10 +37,9 @@ MOCK_CONST_METHOD2(OnToggleChanged, void(autofill::AccessoryAction toggled_action, bool enabled)); - MOCK_METHOD2( - RequestAccessorySheet, - void(autofill::AccessoryTabType, - base::OnceCallback<void(const autofill::AccessorySheetData&)>)); + MOCK_METHOD2(RequestAccessorySheet, + void(autofill::AccessoryTabType, + base::OnceCallback<void(autofill::AccessorySheetData)>)); MOCK_CONST_METHOD0(container_view, gfx::NativeView()); };
diff --git a/chrome/browser/autofill/mock_manual_filling_view.h b/chrome/browser/autofill/mock_manual_filling_view.h index 9f6d7ad6..07fd513 100644 --- a/chrome/browser/autofill/mock_manual_filling_view.h +++ b/chrome/browser/autofill/mock_manual_filling_view.h
@@ -19,7 +19,7 @@ ~MockManualFillingView() override; - MOCK_METHOD1(OnItemsAvailable, void(const autofill::AccessorySheetData&)); + MOCK_METHOD1(OnItemsAvailable, void(autofill::AccessorySheetData)); MOCK_METHOD1(OnAutomaticGenerationStatusChanged, void(bool)); MOCK_METHOD0(CloseAccessorySheet, void()); MOCK_METHOD0(SwapSheetWithKeyboard, void());
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc index 356eaf4..5e531df 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -442,12 +442,9 @@ case policy::DlpRulesManager::Level::kBlock: return DlpLevel::DLP_LEVEL_BLOCK; case policy::DlpRulesManager::Level::kWarn: + return DlpLevel::DLP_LEVEL_WARN; case policy::DlpRulesManager::Level::kReport: - NOTIMPLEMENTED() - << "Warn and Report DLP levels for Files are not supported yet."; - // TODO(https://crbug.com/1172959): Implement Warn level for Files. - // TODO: Implement Report level for Files. - return DlpLevel::DLP_LEVEL_NONE; + return DlpLevel::DLP_LEVEL_REPORT; case policy::DlpRulesManager::Level::kNotSet: NOTREACHED() << "DLP level not set."; return DlpLevel::DLP_LEVEL_NONE;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc index 22e0ae81..bdb4bcb 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -1300,20 +1300,6 @@ *entry_definition_list))); } -// TODO(crbug.com/1212768): Remove this once Files app SWA has fully launched. -ExtensionFunction::ResponseAction -FileManagerPrivateGetFrameColorFunction::Run() { - ash::ScopedLightModeAsDefault scoped_light_mode_as_default; - std::string frame_color = SkColorToHexString(SK_ColorWHITE); - if (auto* dark_light_mode_controller = ash::DarkLightModeController::Get()) { - frame_color = SkColorToHexString(cros_styles::ResolveColor( - cros_styles::ColorName::kBgColor, - dark_light_mode_controller->IsDarkModeEnabled(), - /*use_debug_colors=*/false)); - } - return RespondNow(WithArguments(frame_color)); -} - ExtensionFunction::ResponseAction FileManagerPrivateIsTabletModeEnabledFunction::Run() { ash::TabletMode* tablet_mode = ash::TabletMode::Get();
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_warn_dialog.cc b/chrome/browser/chromeos/policy/dlp/dlp_warn_dialog.cc index a8873b8..c81e27fb 100644 --- a/chrome/browser/chromeos/policy/dlp/dlp_warn_dialog.cc +++ b/chrome/browser/chromeos/policy/dlp/dlp_warn_dialog.cc
@@ -11,11 +11,13 @@ #include "build/chromeos_buildflags.h" #include "chrome/browser/ash/policy/dlp/dlp_files_controller.h" #include "chrome/browser/chromeos/policy/dlp/dlp_confidential_contents.h" +#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h" #include "components/strings/grit/components_strings.h" #include "components/vector_icons/vector_icons.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/base/ui_base_types.h" +#include "ui/chromeos/strings/grit/ui_chromeos_strings.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/views/controls/image_view.h" @@ -80,6 +82,29 @@ // This can hold seven rows. constexpr int kConfidentialContentListMaxHeight = 240; +// Returns the destination name for |dst_component| +const std::u16string GetDestinationForFiles( + DlpRulesManager::Component dst_component) { + switch (dst_component) { + case DlpRulesManager::Component::kArc: + return l10n_util::GetStringUTF16( + IDS_FILE_BROWSER_ANDROID_FILES_ROOT_LABEL); + case DlpRulesManager::Component::kCrostini: + return l10n_util::GetStringUTF16(IDS_FILE_BROWSER_LINUX_FILES_ROOT_LABEL); + case DlpRulesManager::Component::kPluginVm: + return l10n_util::GetStringUTF16( + IDS_FILE_BROWSER_PLUGIN_VM_DIRECTORY_LABEL); + case DlpRulesManager::Component::kUsb: + return l10n_util::GetStringUTF16( + IDS_POLICY_DLP_FILES_DESTINATION_REMOVABLE_STORAGE); + case DlpRulesManager::Component::kDrive: + return l10n_util::GetStringUTF16(IDS_FILE_BROWSER_DRIVE_DIRECTORY_LABEL); + case DlpRulesManager::Component::kUnknownComponent: + NOTREACHED(); + return u""; + } +} + // Returns the OK button label for |files_action|. const std::u16string GetDialogButtonOkLabelForFiles( DlpFilesController::FileAction files_action) { @@ -116,26 +141,33 @@ // Returns the message for |files_action|. const std::u16string GetMessageForFiles( - DlpFilesController::FileAction files_action, - int files_number) { - switch (files_action) { + const DlpWarnDialog::DlpWarnDialogOptions& options) { + DCHECK(options.files_action.has_value()); + switch (options.files_action.value()) { case DlpFilesController::FileAction::kDownload: return base::ReplaceStringPlaceholders( l10n_util::GetPluralStringFUTF16( // Download action is only allowed for one file. IDS_POLICY_DLP_FILES_DOWNLOAD_WARN_MESSAGE, 1), - // TODO(crbug.com/1350978) Change to the actual destination string. - u"External storage", + GetDestinationForFiles(options.destination_component.value()), /*offset=*/nullptr); case DlpFilesController::FileAction::kTransfer: case DlpFilesController::FileAction::kUnknown: // TODO(crbug.com/1361900) // Set proper text when file // action is unknown + std::u16string destination; + if (options.destination_component.has_value()) { + destination = + GetDestinationForFiles(options.destination_component.value()); + } else { + DCHECK(!options.destination_pattern->empty()); + destination = base::UTF8ToUTF16(options.destination_pattern.value()); + } return base::ReplaceStringPlaceholders( l10n_util::GetPluralStringFUTF16( - IDS_POLICY_DLP_FILES_TRANSFER_WARN_MESSAGE, files_number), - // TODO(crbug.com/1350978) Change to the actual destination string. - u"External storage", + IDS_POLICY_DLP_FILES_TRANSFER_WARN_MESSAGE, + options.confidential_contents.GetContents().size()), + destination, /*offset=*/nullptr); } } @@ -215,9 +247,7 @@ options.application_title.value()); case DlpWarnDialog::Restriction::kFiles: DCHECK(options.files_action.has_value()); - return GetMessageForFiles( - options.files_action.value(), - options.confidential_contents.GetContents().size()); + return GetMessageForFiles(options); } } @@ -381,9 +411,13 @@ DlpWarnDialog::DlpWarnDialogOptions::DlpWarnDialogOptions( Restriction restriction, DlpConfidentialContents confidential_contents, + absl::optional<DlpRulesManager::Component> dst_component, + const std::string& destination_pattern, DlpFilesController::FileAction files_action) : restriction(restriction), confidential_contents(confidential_contents), + destination_component(dst_component), + destination_pattern(destination_pattern), files_action(files_action) {} DlpWarnDialog::DlpWarnDialogOptions::DlpWarnDialogOptions(
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_warn_dialog.h b/chrome/browser/chromeos/policy/dlp/dlp_warn_dialog.h index 41844f3..937dba4 100644 --- a/chrome/browser/chromeos/policy/dlp/dlp_warn_dialog.h +++ b/chrome/browser/chromeos/policy/dlp/dlp_warn_dialog.h
@@ -22,9 +22,9 @@ using OnDlpRestrictionCheckedCallback = base::OnceCallback<void(bool should_proceed)>; -// DlpWarnDialog is a system modal dialog shown when Data Leak Protection on -// screen restriction (Screen Capture, Printing, Screen Share) level is set to -// WARN. +// DlpWarnDialog is a system modal dialog shown when Data Leak Protection +// files and on screen restriction (Screen Capture, Printing, Screen Share) +// level is set to WARN. class DlpWarnDialog : public views::DialogDelegateView { public: METADATA_HEADER(DlpWarnDialog); @@ -49,9 +49,12 @@ DlpWarnDialogOptions(Restriction restriction, DlpConfidentialContents confidential_contents, const std::u16string& application_title); - DlpWarnDialogOptions(Restriction restriction, - DlpConfidentialContents confidential_contents, - DlpFilesController::FileAction files_action); + DlpWarnDialogOptions( + Restriction restriction, + DlpConfidentialContents confidential_contents, + absl::optional<DlpRulesManager::Component> dst_component, + const std::string& destination_pattern, + DlpFilesController::FileAction files_action); DlpWarnDialogOptions(const DlpWarnDialogOptions& other); DlpWarnDialogOptions& operator=(const DlpWarnDialogOptions& other); ~DlpWarnDialogOptions(); @@ -63,6 +66,9 @@ const DlpWarnDialogOptions& b) { return a.restriction == b.restriction && a.application_title == b.application_title && + a.destination_component == b.destination_component && + a.destination_pattern == b.destination_pattern && + a.files_action == b.files_action && EqualWithTitles(a.confidential_contents, b.confidential_contents); } friend bool operator!=(const DlpWarnDialogOptions& a, @@ -74,6 +80,10 @@ DlpConfidentialContents confidential_contents; absl::optional<std::u16string> application_title; + // May have value only if the |restriction| is kFiles. + absl::optional<DlpRulesManager::Component> destination_component; + // Has value only if the |restriction| is kFiles. + absl::optional<std::string> destination_pattern; // Has value only if the |restriction| is kFiles. absl::optional<DlpFilesController::FileAction> files_action; };
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_warn_notifier.cc b/chrome/browser/chromeos/policy/dlp/dlp_warn_notifier.cc index faf67e1..a161157 100644 --- a/chrome/browser/chromeos/policy/dlp/dlp_warn_notifier.cc +++ b/chrome/browser/chromeos/policy/dlp/dlp_warn_notifier.cc
@@ -55,11 +55,14 @@ void DlpWarnNotifier::ShowDlpFilesWarningDialog( OnDlpRestrictionCheckedCallback callback, const DlpConfidentialContents& confidential_contents, + absl::optional<DlpRulesManager::Component> dst_component, + const std::string& destination_pattern, DlpFilesController::FileAction files_action) { ShowDlpWarningDialog( std::move(callback), DlpWarnDialog::DlpWarnDialogOptions(DlpWarnDialog::Restriction::kFiles, - confidential_contents, files_action)); + confidential_contents, dst_component, + destination_pattern, files_action)); } base::WeakPtr<views::Widget> DlpWarnNotifier::ShowDlpScreenShareWarningDialog(
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_warn_notifier.h b/chrome/browser/chromeos/policy/dlp/dlp_warn_notifier.h index fd8c2d6..7fc4d9bd 100644 --- a/chrome/browser/chromeos/policy/dlp/dlp_warn_notifier.h +++ b/chrome/browser/chromeos/policy/dlp/dlp_warn_notifier.h
@@ -47,12 +47,15 @@ OnDlpRestrictionCheckedCallback callback, const DlpConfidentialContents& confidential_contents); - // Shows a warning dialog that informs the user that |files_action| on - // selected |confidential_contents| files is not recommended. Calls |callback| - // and passes user's choice of whether to proceed or not. + // Shows a warning dialog that informs the user that |files_action| to + // |dst_component| or |destination_pattern| on selected + // |confidential_contents| files is not recommended. Calls |callback| and + // passes user's choice of whether to proceed or not. void ShowDlpFilesWarningDialog( OnDlpRestrictionCheckedCallback callback, const DlpConfidentialContents& confidential_contents, + absl::optional<DlpRulesManager::Component> dst_component, + const std::string& destination_pattern, DlpFilesController::FileAction files_action); // Shows a warning dialog that informs the user that screen sharing is not
diff --git a/chrome/browser/chromeos/tablet_mode/tablet_mode_page_behavior_browsertest.cc b/chrome/browser/chromeos/tablet_mode/tablet_mode_page_behavior_browsertest.cc index 7ba1b7c4..bd7f17cc 100644 --- a/chrome/browser/chromeos/tablet_mode/tablet_mode_page_behavior_browsertest.cc +++ b/chrome/browser/chromeos/tablet_mode/tablet_mode_page_behavior_browsertest.cc
@@ -37,13 +37,24 @@ // Runs the specified callback when a change to tablet state is detected. class TabletModeWatcher : public display::DisplayObserver { public: - explicit TabletModeWatcher(base::RepeatingClosure cb) : cb_(cb) {} + explicit TabletModeWatcher(base::RepeatingClosure cb, + display::TabletState current_tablet_state) + : cb_(cb), current_tablet_state_(current_tablet_state) {} void OnDisplayTabletStateChanged(display::TabletState state) override { + // Skip if the notified TabletState is same as the current state. + // This required since it may notify the current tablet state when the + // observer is added (e.g. WaylandScreen::AddObserver()). In such cases, we + // need to ignore the initial notification so that we can only catch + // meeningful notifications for testing. + if (current_tablet_state_ == state) + return; + cb_.Run(); } private: base::RepeatingClosure cb_; + display::TabletState current_tablet_state_; }; #endif @@ -85,7 +96,8 @@ ash::ShellTestApi().SetTabletModeEnabledForTest(enable); #elif BUILDFLAG(IS_CHROMEOS_LACROS) base::RunLoop run_loop; - TabletModeWatcher watcher(run_loop.QuitClosure()); + TabletModeWatcher watcher(run_loop.QuitClosure(), + chromeos::TabletState::Get()->state()); display::Screen::GetScreen()->AddObserver(&watcher); crosapi::mojom::TestControllerAsyncWaiter controller( chromeos::LacrosService::Get()
diff --git a/chrome/browser/component_updater/app_provisioning_component_installer.cc b/chrome/browser/component_updater/app_provisioning_component_installer.cc index 56bcff9c..e4c3ee08 100644 --- a/chrome/browser/component_updater/app_provisioning_component_installer.cc +++ b/chrome/browser/component_updater/app_provisioning_component_installer.cc
@@ -30,11 +30,14 @@ #include "components/component_updater/component_installer.h" #include "components/component_updater/component_updater_paths.h" #include "content/public/browser/browser_thread.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace { -constexpr base::FilePath::CharType kAppProvisioningBinaryPbFileName[] = +constexpr base::FilePath::CharType kAppWithLocaleBinaryPbFileName[] = FILE_PATH_LITERAL("app_data.textproto"); +constexpr base::FilePath::CharType kDeduplicationBinaryPbFileName[] = + FILE_PATH_LITERAL("deduplication_data.pb"); // The SHA256 of the SubjectPublicKeyInfo used to sign the extension. // The extension id is: fellaebeeieagcalnmmpapfioejgihci @@ -45,20 +48,42 @@ constexpr char kAppProvisioningManifestName[] = "App Provisioning"; -std::string LoadAppMetadataFromDisk(const base::FilePath& pb_path) { - if (pb_path.empty()) - return ""; +absl::optional<apps::ComponentFileContents> LoadAppMetadataFromDisk( + const base::FilePath& app_with_locale_pb_path, + const base::FilePath& deduplication_pb_path) { + if (app_with_locale_pb_path.empty() || deduplication_pb_path.empty()) + return absl::nullopt; - VLOG(1) << "Reading Download App Metadata from file: " << pb_path.value(); - std::string binary_pb; - if (!base::ReadFileToString(pb_path, &binary_pb)) { - // ComponentReady will only be called when there is some installation of the - // component ready, so it would be correct to consider this an error. - VLOG(1) << "Failed reading from " << pb_path.value(); - return ""; + VLOG(1) << "Reading Download App Metadata from file: " + << app_with_locale_pb_path.value() + << " and file: " << deduplication_pb_path.value(); + std::string app_with_locale_binary_pb; + std::string deduplication_binary_pb; + if (!base::ReadFileToString(app_with_locale_pb_path, + &app_with_locale_binary_pb)) { + VLOG(1) << "Failed reading from " << app_with_locale_pb_path.value(); + return absl::nullopt; } - return binary_pb; + if (base::FeatureList::IsEnabled(features::kAppDeduplicationService) && + !base::ReadFileToString(deduplication_pb_path, + &deduplication_binary_pb)) { + VLOG(1) << "Failed reading from " << deduplication_pb_path.value(); + return absl::nullopt; + } + + return apps::ComponentFileContents{app_with_locale_binary_pb, + deduplication_binary_pb}; +} + +void UpdateAppMetadataOnUI( + const base::FilePath& install_dir, + const absl::optional<apps::ComponentFileContents>& component_files) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (component_files.has_value()) { + apps::AppProvisioningDataManager::Get()->PopulateFromDynamicUpdate( + component_files.value(), install_dir); + } } } // namespace @@ -71,7 +96,9 @@ const base::FilePath& install_dir) const { // No need to actually validate the proto here, since we'll do the checking // in `PopulateFromDynamicUpdate()`. - return base::PathExists(GetInstalledPath(install_dir)); + return base::PathExists(GetAppWithLocaleInstalledPath(install_dir)) && + (!base::FeatureList::IsEnabled(features::kAppDeduplicationService) || + base::PathExists(GetDeduplicationInstalledPath(install_dir))); } bool AppProvisioningComponentInstallerPolicy:: @@ -99,13 +126,12 @@ base::Value manifest) { VLOG(1) << "Component ready, version " << version.GetString() << " in " << install_dir.value(); - base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&LoadAppMetadataFromDisk, GetInstalledPath(install_dir)), - base::BindOnce( - &AppProvisioningComponentInstallerPolicy::UpdateAppMetadataOnUI, - base::Unretained(this), install_dir)); + base::BindOnce(&LoadAppMetadataFromDisk, + GetAppWithLocaleInstalledPath(install_dir), + GetDeduplicationInstalledPath(install_dir)), + base::BindOnce(&UpdateAppMetadataOnUI, install_dir)); } base::FilePath AppProvisioningComponentInstallerPolicy::GetRelativeInstallDir() @@ -128,19 +154,16 @@ return update_client::InstallerAttributes(); } -base::FilePath AppProvisioningComponentInstallerPolicy::GetInstalledPath( +base::FilePath +AppProvisioningComponentInstallerPolicy::GetAppWithLocaleInstalledPath( const base::FilePath& base) { - return base.Append(kAppProvisioningBinaryPbFileName); + return base.Append(kAppWithLocaleBinaryPbFileName); } -void AppProvisioningComponentInstallerPolicy::UpdateAppMetadataOnUI( - const base::FilePath& install_dir, - const std::string& binary_pb) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (!binary_pb.empty()) { - apps::AppProvisioningDataManager::Get()->PopulateFromDynamicUpdate( - binary_pb, install_dir); - } +base::FilePath +AppProvisioningComponentInstallerPolicy::GetDeduplicationInstalledPath( + const base::FilePath& base) { + return base.Append(kDeduplicationBinaryPbFileName); } void RegisterAppProvisioningComponent(component_updater::ComponentUpdateService* cus) {
diff --git a/chrome/browser/component_updater/app_provisioning_component_installer.h b/chrome/browser/component_updater/app_provisioning_component_installer.h index da6dc50..305505e 100644 --- a/chrome/browser/component_updater/app_provisioning_component_installer.h +++ b/chrome/browser/component_updater/app_provisioning_component_installer.h
@@ -50,9 +50,10 @@ std::string GetName() const override; update_client::InstallerAttributes GetInstallerAttributes() const override; - static base::FilePath GetInstalledPath(const base::FilePath& base); - void UpdateAppMetadataOnUI(const base::FilePath& install_dir, - const std::string& binary_pb); + static base::FilePath GetAppWithLocaleInstalledPath( + const base::FilePath& base); + static base::FilePath GetDeduplicationInstalledPath( + const base::FilePath& base); }; // Call once during startup to make the component update service aware of
diff --git a/chrome/browser/fast_checkout/fast_checkout_tab_helper.cc b/chrome/browser/fast_checkout/fast_checkout_tab_helper.cc new file mode 100644 index 0000000..5061977 --- /dev/null +++ b/chrome/browser/fast_checkout/fast_checkout_tab_helper.cc
@@ -0,0 +1,47 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/fast_checkout/fast_checkout_tab_helper.h" + +#include "base/callback_helpers.h" +#include "chrome/browser/fast_checkout/fast_checkout_capabilities_fetcher.h" +#include "chrome/browser/fast_checkout/fast_checkout_capabilities_fetcher_factory.h" +#include "components/commerce/core/heuristics/commerce_heuristics_provider.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" +#include "url/origin.h" + +FastCheckoutTabHelper::FastCheckoutTabHelper(content::WebContents* web_contents) + : content::WebContentsObserver(web_contents), + content::WebContentsUserData<FastCheckoutTabHelper>(*web_contents) {} + +FastCheckoutTabHelper::~FastCheckoutTabHelper() = default; + +void FastCheckoutTabHelper::DidStartNavigation( + content::NavigationHandle* navigation_handle) { + if (!navigation_handle) + return; + + // Shopping sites should be http or https - save heuristics if this URL + // does not satisfy that. + if (!navigation_handle->GetURL().SchemeIsHTTPOrHTTPS()) + return; + + if (commerce_heuristics::IsVisitCheckout(navigation_handle->GetURL())) { + FastCheckoutCapabilitiesFetcher* fetcher = + FastCheckoutCapabilitiesFetcherFactory::GetForBrowserContext( + GetWebContents().GetBrowserContext()); + if (!fetcher) + return; + + // Converting to an origin is fine here. The scheme is known to be + // http/https and there is no risk associated with origin opaqueness. + fetcher->FetchAvailability(url::Origin::Create(navigation_handle->GetURL()), + base::DoNothing()); + } +} + +WEB_CONTENTS_USER_DATA_KEY_IMPL(FastCheckoutTabHelper);
diff --git a/chrome/browser/fast_checkout/fast_checkout_tab_helper.h b/chrome/browser/fast_checkout/fast_checkout_tab_helper.h new file mode 100644 index 0000000..b8dedc9 --- /dev/null +++ b/chrome/browser/fast_checkout/fast_checkout_tab_helper.h
@@ -0,0 +1,38 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_FAST_CHECKOUT_FAST_CHECKOUT_TAB_HELPER_H_ +#define CHROME_BROWSER_FAST_CHECKOUT_FAST_CHECKOUT_TAB_HELPER_H_ + +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" + +// A tab helper that listens to navigations, uses the commerce heuristics +// framework to decide whether the URL indicates that the user is approaching +// checkout and, if so, ask the `FastCheckoutCapabilitiesFetcher` to prepare +// its cache. +class FastCheckoutTabHelper + : public content::WebContentsObserver, + public content::WebContentsUserData<FastCheckoutTabHelper> { + public: + ~FastCheckoutTabHelper() override; + FastCheckoutTabHelper(const FastCheckoutTabHelper&) = delete; + FastCheckoutTabHelper& operator=(const FastCheckoutTabHelper&) = delete; + + // WebContentsObserver: + // Analyses the URL using commerce heuristics to decide whether to ask the + // `FastCheckoutCapabilitiesFetcher` to fetch availability for the URL. + // The analysis is done on navigation start to allow the capabilities fetcher + // enough time. + void DidStartNavigation( + content::NavigationHandle* navigation_handle) override; + + private: + explicit FastCheckoutTabHelper(content::WebContents* web_contents); + friend class content::WebContentsUserData<FastCheckoutTabHelper>; + + WEB_CONTENTS_USER_DATA_KEY_DECL(); +}; + +#endif // CHROME_BROWSER_FAST_CHECKOUT_FAST_CHECKOUT_TAB_HELPER_H_
diff --git a/chrome/browser/fast_checkout/fast_checkout_tab_helper_browsertest.cc b/chrome/browser/fast_checkout/fast_checkout_tab_helper_browsertest.cc new file mode 100644 index 0000000..d9d0301 --- /dev/null +++ b/chrome/browser/fast_checkout/fast_checkout_tab_helper_browsertest.cc
@@ -0,0 +1,97 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/fast_checkout/fast_checkout_tab_helper.h" + +#include <memory> + +#include "base/bind.h" +#include "base/memory/raw_ptr.h" +#include "base/run_loop.h" +#include "chrome/browser/fast_checkout/fast_checkout_capabilities_fetcher_factory.h" +#include "chrome/browser/fast_checkout/mock_fast_checkout_capabilities_fetcher.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/test/base/android/android_browser_test.h" +#include "chrome/test/base/chrome_test_utils.h" +#include "content/public/browser/browser_context.h" +#include "content/public/test/browser_test.h" +#include "net/dns/mock_host_resolver.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_response.h" +#include "url/gurl.h" +#include "url/origin.h" + +using testing::_; +using testing::Eq; +using testing::SaveArg; +using testing::StrictMock; + +namespace { + +// Creates the same fake http response for every request. +std::unique_ptr<net::test_server::HttpResponse> CreateFakeResponse( + const net::test_server::HttpRequest& request) { + auto response = std::make_unique<net::test_server::BasicHttpResponse>(); + response->set_content("Dummy response."); + response->set_content_type("text/html"); + return response; +} + +} // namespace + +class FastCheckoutTabHelperBrowserTest : public PlatformBrowserTest { + public: + void SetUpOnMainThread() override { + Profile* profile = ProfileManager::GetLastUsedProfileIfLoaded(); + CHECK(profile); + fetcher_ = + FastCheckoutCapabilitiesFetcherFactory::GetInstance() + ->SetTestingSubclassFactoryAndUse( + profile, base::BindRepeating([](content::BrowserContext*) { + return std::make_unique< + StrictMock<MockFastCheckoutCapabilitiesFetcher>>(); + })); + + // Set up the service to be tested - normally this is called during + // `WebContents` creation. + FastCheckoutTabHelper::CreateForWebContents(GetActiveWebContents()); + + host_resolver()->AddRule("*", "127.0.0.1"); + embedded_test_server()->RegisterRequestHandler( + base::BindRepeating(&CreateFakeResponse)); + ASSERT_TRUE(embedded_test_server()->Start()); + } + + protected: + MockFastCheckoutCapabilitiesFetcher* fetcher() { return fetcher_; } + + content::WebContents* GetActiveWebContents() { + return chrome_test_utils::GetActiveWebContents(this); + } + + void NavigateToUrl(const GURL& url) { + ASSERT_TRUE(content::NavigateToURL( + GetActiveWebContents(), + embedded_test_server()->GetURL(url.host(), url.path()))); + base::RunLoop().RunUntilIdle(); + } + + private: + raw_ptr<MockFastCheckoutCapabilitiesFetcher> fetcher_ = nullptr; +}; + +IN_PROC_BROWSER_TEST_F(FastCheckoutTabHelperBrowserTest, + FetchScriptAvailabilityOnNavigateToCheckoutPage) { + // No availability request was started or the `StrickMock` would have failed. + GURL no_shopping_url("http://www.example.com/empty.html"); + NavigateToUrl(no_shopping_url); + + GURL shopping_url("http://www.example2.co.uk/checkout.html"); + url::Origin request_origin; + EXPECT_CALL(*fetcher(), FetchAvailability) + .WillOnce(SaveArg<0>(&request_origin)); + NavigateToUrl(shopping_url); + EXPECT_THAT(shopping_url.host(), Eq(request_origin.host())); +}
diff --git a/chrome/browser/fast_checkout/mock_fast_checkout_capabilities_fetcher.cc b/chrome/browser/fast_checkout/mock_fast_checkout_capabilities_fetcher.cc new file mode 100644 index 0000000..907bfdfc --- /dev/null +++ b/chrome/browser/fast_checkout/mock_fast_checkout_capabilities_fetcher.cc
@@ -0,0 +1,11 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/fast_checkout/mock_fast_checkout_capabilities_fetcher.h" + +MockFastCheckoutCapabilitiesFetcher::MockFastCheckoutCapabilitiesFetcher() = + default; + +MockFastCheckoutCapabilitiesFetcher::~MockFastCheckoutCapabilitiesFetcher() = + default;
diff --git a/chrome/browser/fast_checkout/mock_fast_checkout_capabilities_fetcher.h b/chrome/browser/fast_checkout/mock_fast_checkout_capabilities_fetcher.h new file mode 100644 index 0000000..8c82364 --- /dev/null +++ b/chrome/browser/fast_checkout/mock_fast_checkout_capabilities_fetcher.h
@@ -0,0 +1,31 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_FAST_CHECKOUT_MOCK_FAST_CHECKOUT_CAPABILITIES_FETCHER_H_ +#define CHROME_BROWSER_FAST_CHECKOUT_MOCK_FAST_CHECKOUT_CAPABILITIES_FETCHER_H_ + +#include "chrome/browser/fast_checkout/fast_checkout_capabilities_fetcher.h" + +#include "base/callback.h" +#include "components/autofill/core/common/signatures.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "url/origin.h" + +class MockFastCheckoutCapabilitiesFetcher + : public FastCheckoutCapabilitiesFetcher { + public: + MockFastCheckoutCapabilitiesFetcher(); + ~MockFastCheckoutCapabilitiesFetcher() override; + + MOCK_METHOD(void, + FetchAvailability, + (const url::Origin&, Callback), + (override)); + MOCK_METHOD(bool, + IsTriggerFormSupported, + (const url::Origin&, autofill::FormSignature), + (override)); +}; + +#endif // CHROME_BROWSER_FAST_CHECKOUT_MOCK_FAST_CHECKOUT_CAPABILITIES_FETCHER_H_
diff --git a/chrome/browser/k_anonymity_service/OWNERS b/chrome/browser/k_anonymity_service/OWNERS index 0659e0f..bc4fa03 100644 --- a/chrome/browser/k_anonymity_service/OWNERS +++ b/chrome/browser/k_anonymity_service/OWNERS
@@ -1 +1 @@ -file://third_party/blink/renderer/modules/ad_auction/OWNERS \ No newline at end of file +file://third_party/blink/renderer/modules/ad_auction/OWNERS
diff --git a/chrome/browser/k_anonymity_service/k_anonymity_service_client.cc b/chrome/browser/k_anonymity_service/k_anonymity_service_client.cc new file mode 100644 index 0000000..135892a --- /dev/null +++ b/chrome/browser/k_anonymity_service/k_anonymity_service_client.cc
@@ -0,0 +1,118 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/k_anonymity_service/k_anonymity_service_client.h" + +#include "base/callback.h" +#include "base/feature_list.h" +#include "chrome/browser/k_anonymity_service/k_anonymity_service_urls.h" +#include "chrome/browser/k_anonymity_service/remote_trust_token_query_answerer.h" +#include "chrome/browser/signin/identity_manager_factory.h" +#include "chrome/common/chrome_features.h" +#include "content/public/browser/browser_thread.h" +#include "services/network/public/mojom/trust_tokens.mojom.h" + +KAnonymityServiceClient::PendingJoinRequest::PendingJoinRequest( + std::string set_id, + base::OnceCallback<void(bool)> callback) + : id(std::move(set_id)), callback(std::move(callback)) {} + +KAnonymityServiceClient::PendingJoinRequest::~PendingJoinRequest() = default; + +KAnonymityServiceClient::KAnonymityServiceClient(Profile* profile) + : url_loader_factory_(profile->GetURLLoaderFactory()), + enable_ohttp_requests_(base::FeatureList::IsEnabled( + features::kKAnonymityServiceOHTTPRequests)), + // Pass the auth server origin as if it is our "top frame". + trust_token_answerer_(url::Origin::Create(GURL(kKAnonymityAuthServer)), + profile), + token_getter_(IdentityManagerFactory::GetForProfile(profile), + url_loader_factory_, + &trust_token_answerer_) { + // We are currently relying on callers of this service to limit which users + // are allowed to use this service. No children should use this service + // since we are not approved to process their data. + DCHECK(!profile->IsChild()); +} + +KAnonymityServiceClient::~KAnonymityServiceClient() = default; + +void KAnonymityServiceClient::JoinSet(std::string id, + base::OnceCallback<void(bool)> callback) { + // Add to the queue. If this is the only request in the queue, start it. + join_queue_.push_back( + std::make_unique<PendingJoinRequest>(std::move(id), std::move(callback))); + if (join_queue_.size() > 1) + return; + JoinSetStartNextQueued(); +} + +void KAnonymityServiceClient::JoinSetStartNextQueued() { + DCHECK(!join_queue_.empty()); + // TODO(behamilton): Instead of requesting the trust tokens here, we should + // check the OHTTP Key first. + JoinSetCheckTrustTokens(); +} + +void KAnonymityServiceClient::JoinSetCheckTrustTokens() { + token_getter_.TryGetTrustTokenAndKey( + base::BindOnce(&KAnonymityServiceClient::OnMaybeHasTrustTokens, + weak_ptr_factory_.GetWeakPtr())); +} + +void KAnonymityServiceClient::OnMaybeHasTrustTokens( + absl::optional<KAnonymityTrustTokenGetter::KeyAndNonUniqueUserId> + maybe_key_and_id) { + if (!maybe_key_and_id) { + FailJoinSetRequests(); + return; + } + + if (!enable_ohttp_requests_) { + CompleteJoinSetRequest(); + return; + } + // Once we know we have a trust token and have the OHTTP key we can send the + // request. + JoinSetSendRequest(std::move(*maybe_key_and_id)); +} + +void KAnonymityServiceClient::JoinSetSendRequest( + KAnonymityTrustTokenGetter::KeyAndNonUniqueUserId key_and_id) { + NOTIMPLEMENTED(); + FailJoinSetRequests(); +} + +void KAnonymityServiceClient::FailJoinSetRequests() { + while (!join_queue_.empty()) + DoJoinSetCallback(false); +} + +void KAnonymityServiceClient::CompleteJoinSetRequest() { + DoJoinSetCallback(true); + // If we have a request queued, process that one. + if (!join_queue_.empty()) + JoinSetStartNextQueued(); +} + +void KAnonymityServiceClient::DoJoinSetCallback(bool status) { + DCHECK(!join_queue_.empty()); + + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(join_queue_.front()->callback), status)); + join_queue_.pop_front(); +} + +void KAnonymityServiceClient::QuerySets( + std::vector<std::string> set_ids, + base::OnceCallback<void(std::vector<bool>)> callback) { + if (enable_ohttp_requests_) { + NOTIMPLEMENTED(); + } + + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), + std::vector<bool>(set_ids.size(), false))); +}
diff --git a/chrome/browser/k_anonymity_service/k_anonymity_service_client.h b/chrome/browser/k_anonymity_service/k_anonymity_service_client.h new file mode 100644 index 0000000..526b3c5 --- /dev/null +++ b/chrome/browser/k_anonymity_service/k_anonymity_service_client.h
@@ -0,0 +1,111 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_K_ANONYMITY_SERVICE_K_ANONYMITY_SERVICE_CLIENT_H_ +#define CHROME_BROWSER_K_ANONYMITY_SERVICE_K_ANONYMITY_SERVICE_CLIENT_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/containers/circular_deque.h" +#include "base/memory/scoped_refptr.h" +#include "base/time/time.h" +#include "chrome/browser/k_anonymity_service/k_anonymity_trust_token_getter.h" +#include "chrome/browser/k_anonymity_service/remote_trust_token_query_answerer.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/browser/k_anonymity_service_delegate.h" +#include "services/network/public/mojom/trust_tokens.mojom.h" + +// This class will implement the KAnonymityServiceDelegate by sending requests +// to the Chrome k-anonymity Service. For now this class only requests the +// trust token. In the future this class will send requests over OHTTP in order +// to anonymize the source of the requests. The requests are internally queued +// and performed serially. +// +// In the case of JoinSet this is necessary because we need +// to ensure that there is a trust token available to attach to the call, and +// the network service does not expose a method to get the count. +// +// In the case of QuerySets, requests are performed serially in order to +// simplify implementation. With only one request out at a time 1) it is clear +// which request the responses are associated with and 2) the limit on the +// number of outstanding requests can be handled by the caller. +class KAnonymityServiceClient : public content::KAnonymityServiceDelegate { + public: + // The profile must outlive the KAnonymityServiceClient. + explicit KAnonymityServiceClient(Profile* profile); + ~KAnonymityServiceClient() override; + + // Implementation of content::KAnonymityServiceDelegate. + + // JoinSet corresponds directly to the JoinSet endpoint provided by the + // K-anonymity Service endpoint. The endpoint requires us to provide a trust + // token for rate limiting for each call, so we need to check that before + // performing the OHTTP request (assuming we have the key). For now this + // function only fetches the trust token without performing the request. + // + // The trust token interface (and network isolation configuration) assume + // there exists both a "top frame" and a "current frame" for any requests. + // The KAnonymityServiceClient makes requests in the background so those + // concepts don't really apply here, but for the purposes of the interface we + // choose to use the kKAnonymityAuthServer's origin as the origin for both + // frames. Not only does this ensure that requests that can be cached are + // cached with the appropriate isolation applied, but also avoids the less + // common (and less tested) configuration where trust tokens are issued in a + // third-party frame. + void JoinSet(std::string id, + base::OnceCallback<void(bool)> callback) override; + // QuerySets will be implemented as multiple calls to the QuerySet endpoint of + // the K-anonymity Service. For now no requests are made and this function + // just marks all of the requested sets as not k-anonymous. + void QuerySets(std::vector<std::string> set_ids, + base::OnceCallback<void(std::vector<bool>)> callback) override; + + private: + struct PendingJoinRequest { + PendingJoinRequest(std::string set_id, + base::OnceCallback<void(bool)> callback); + ~PendingJoinRequest(); + std::string id; + base::OnceCallback<void(bool)> callback; + }; + + // Starts processing items in the queue by calling JoinSetCheckTrustTokens() + void JoinSetStartNextQueued(); + // Calls the token_getter_ to ensure there is a trust token for the request. + void JoinSetCheckTrustTokens(); + // Asynchronous callback from token_getter_ which is passed the key commitment + // and non-unique client ID that are needed to complete JoinSet. If the + // provided optional is not empty this triggers the JoinSet request. + void OnMaybeHasTrustTokens( + absl::optional<KAnonymityTrustTokenGetter::KeyAndNonUniqueUserId> + maybe_key_and_id); + // In the future, this will start the OHTTP JoinSet request for the + // join_queue_.front() request, but for now just calls CompleteJoinSetRequest. + void JoinSetSendRequest( + KAnonymityTrustTokenGetter::KeyAndNonUniqueUserId key_and_id); + // Calls DoJoinSetCallback indicating the current request completed + // successfully. If there are other items in the queue calls + // JoinSetStartNextQueued to start processing them. + void FailJoinSetRequests(); + // Calls DoJoinSetCallback for each of the requests in the join_queue_ + // indicating the requests were unsuccessful. + void CompleteJoinSetRequest(); + // Asynchronously calls the callback for the join_queue_.front() request with + // the provided status and removes it from the queue. + void DoJoinSetCallback(bool status); + + base::circular_deque<std::unique_ptr<PendingJoinRequest>> join_queue_; + + const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; + const bool enable_ohttp_requests_; + RemoteTrustTokenQueryAnswerer trust_token_answerer_; + KAnonymityTrustTokenGetter token_getter_; + + base::WeakPtrFactory<KAnonymityServiceClient> weak_ptr_factory_{this}; +}; + +#endif // CHROME_BROWSER_K_ANONYMITY_SERVICE_K_ANONYMITY_SERVICE_CLIENT_H_
diff --git a/chrome/browser/k_anonymity_service/k_anonymity_service_client_unittest.cc b/chrome/browser/k_anonymity_service/k_anonymity_service_client_unittest.cc new file mode 100644 index 0000000..d6c0837 --- /dev/null +++ b/chrome/browser/k_anonymity_service/k_anonymity_service_client_unittest.cc
@@ -0,0 +1,227 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/k_anonymity_service/k_anonymity_service_client.h" + +#include "base/callback.h" +#include "base/run_loop.h" +#include "base/test/bind.h" +#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h" +#include "chrome/common/chrome_features.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "content/public/test/browser_task_environment.h" +#include "net/dns/mock_host_resolver.h" +#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" +#include "services/network/public/cpp/features.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +class KAnonymityServiceClientTest : public testing::Test { + protected: + void SetUp() override { + feature_list_.InitAndEnableFeature(network::features::kTrustTokens); + TestingProfile::Builder builder; + builder.SetSharedURLLoaderFactory( + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_)); + profile_ = IdentityTestEnvironmentProfileAdaptor:: + CreateProfileForIdentityTestEnvironment( + builder, signin::AccountConsistencyMethod::kMirror); + } + + void InitializeIdentity(bool signed_on) { + auto identity_test_env_adaptor = + std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile_.get()); + auto* identity_test_env = identity_test_env_adaptor->identity_test_env(); + auto* identity_manager = identity_test_env->identity_manager(); + identity_test_env->SetAutomaticIssueOfAccessTokens(true); + if (signed_on) { + identity_test_env->MakePrimaryAccountAvailable( + "user@gmail.com", signin::ConsentLevel::kSignin); + ASSERT_TRUE( + identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin)); + EXPECT_EQ(1U, identity_manager->GetAccountsWithRefreshTokens().size()); + } + } + + void SimulateResponseForPendingRequest(std::string url, std::string content) { + task_environment_.RunUntilIdle(); + EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest( + url, content, net::HTTP_OK, + network::TestURLLoaderFactory::ResponseMatchFlags::kUrlMatchPrefix)); + } + + void SimulateFailedResponseForPendingRequest(std::string url) { + task_environment_.RunUntilIdle(); + EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest( + url, "", net::HTTP_NOT_FOUND, + network::TestURLLoaderFactory::ResponseMatchFlags::kUrlMatchPrefix)); + } + + void RespondWithTrustTokenNonUniqueUserID(int id) { + SimulateResponseForPendingRequest( + "https://chromekanonymityauth-pa.googleapis.com/v1/" + "generateShortIdentifier", + base::StringPrintf("{\"shortClientIdentifier\": %d}", id)); + } + + void RespondWithTrustTokenKeys(int id) { + SimulateResponseForPendingRequest( + base::StringPrintf( + "https://chromekanonymityauth-pa.googleapis.com/v1/%d/fetchKeys", + id), + R"({ + "protocolVersion":"TrustTokenV3VOPRF", + "id": 1, + "batchSize": 1, + "keys": [ + { + "keyIdentifier": 0, + "keyMaterial": "InsertKeyHere", + "expirationTimestampUsec": "253402300799000000" + } + ] + })"); + } + + void RespondWithTrustTokenIssued(int id) { + SimulateResponseForPendingRequest( + base::StringPrintf("https://chromekanonymityauth-pa.googleapis.com/v1/" + "%d/issueTrustToken", + id), + ""); + } + + Profile* profile() { return profile_.get(); } + + private: + base::test::ScopedFeatureList feature_list_; + content::BrowserTaskEnvironment task_environment_; + network::TestURLLoaderFactory test_url_loader_factory_; + std::unique_ptr<TestingProfile> profile_; + data_decoder::test::InProcessDataDecoder decoder_; +}; + +TEST_F(KAnonymityServiceClientTest, TryJoinSetFetchTokenFails) { + InitializeIdentity(false); + KAnonymityServiceClient k_service(profile()); + base::RunLoop run_loop; + k_service.JoinSet("1", + base::OnceCallback<void(bool)>( + base::BindLambdaForTesting([&run_loop](bool result) { + EXPECT_FALSE(result); + run_loop.Quit(); + }))); + run_loop.Run(); +} + +TEST_F(KAnonymityServiceClientTest, TryJoinSetSuccess) { + InitializeIdentity(true); + KAnonymityServiceClient k_service(profile()); + base::RunLoop run_loop; + k_service.JoinSet("1", + base::OnceCallback<void(bool)>( + base::BindLambdaForTesting([&run_loop](bool result) { + EXPECT_TRUE(result); + run_loop.Quit(); + }))); + RespondWithTrustTokenNonUniqueUserID(2); + RespondWithTrustTokenKeys(2); + RespondWithTrustTokenIssued(2); + run_loop.Run(); +} + +TEST_F(KAnonymityServiceClientTest, TryJoinSetRepeatedly) { + InitializeIdentity(true); + KAnonymityServiceClient k_service(profile()); + base::RunLoop run_loop; + int callback_count = 0; + for (int i = 0; i < 10; i++) { + k_service.JoinSet("1", + base::OnceCallback<void(bool)>(base::BindLambdaForTesting( + [&callback_count, &run_loop, i](bool result) { + EXPECT_TRUE(result) << "iteration " << i; + callback_count++; + if (callback_count == 10) + run_loop.Quit(); + }))); + } + RespondWithTrustTokenNonUniqueUserID(2); + RespondWithTrustTokenKeys(2); + // The network layer doesn't actually get a token, so the fetcher requests one + // every time. + for (int i = 0; i < 10; i++) + RespondWithTrustTokenIssued(2); + run_loop.Run(); + EXPECT_EQ(10, callback_count); +} + +TEST_F(KAnonymityServiceClientTest, TryJoinSetOneAtATime) { + InitializeIdentity(true); + KAnonymityServiceClient k_service(profile()); + int callback_count = 0; + for (int i = 0; i < 10; i++) { + base::RunLoop run_loop; + k_service.JoinSet("1", + base::OnceCallback<void(bool)>(base::BindLambdaForTesting( + [&callback_count, &run_loop, i](bool result) { + EXPECT_TRUE(result) << "iteration " << i; + callback_count++; + run_loop.Quit(); + }))); + if (i == 0) { + RespondWithTrustTokenNonUniqueUserID(2); + RespondWithTrustTokenKeys(2); + } + // The network layer doesn't actually get a token, so the fetcher requests + // one every time. + RespondWithTrustTokenIssued(2); + run_loop.Run(); + } + EXPECT_EQ(10, callback_count); +} + +TEST_F(KAnonymityServiceClientTest, TryJoinSetFailureDropsAllRequests) { + InitializeIdentity(true); + KAnonymityServiceClient k_service(profile()); + base::RunLoop run_loop; + int callback_count = 0; + for (int i = 0; i < 10; i++) { + k_service.JoinSet("1", + base::OnceCallback<void(bool)>(base::BindLambdaForTesting( + [&callback_count, &run_loop, i](bool result) { + EXPECT_FALSE(result) << "iteration " << i; + callback_count++; + if (callback_count == 10) + run_loop.Quit(); + }))); + } + SimulateFailedResponseForPendingRequest( + "https://chromekanonymityauth-pa.googleapis.com/v1/" + "generateShortIdentifier"); + run_loop.Run(); + EXPECT_EQ(10, callback_count); +} + +TEST_F(KAnonymityServiceClientTest, TryQuerySetAllNotKAnon) { + KAnonymityServiceClient k_service(profile()); + base::RunLoop run_loop; + std::vector<std::string> sets; + sets.push_back("1"); + sets.push_back("2"); + k_service.QuerySets( + std::move(sets), + base::OnceCallback<void(std::vector<bool>)>( + base::BindLambdaForTesting([&run_loop](std::vector<bool> result) { + ASSERT_EQ(2u, result.size()); + EXPECT_FALSE(result[0]); + EXPECT_FALSE(result[1]); + run_loop.Quit(); + }))); + run_loop.Run(); +}
diff --git a/chrome/browser/k_anonymity_service/remote_trust_token_query_answerer.cc b/chrome/browser/k_anonymity_service/remote_trust_token_query_answerer.cc new file mode 100644 index 0000000..1e65e6f --- /dev/null +++ b/chrome/browser/k_anonymity_service/remote_trust_token_query_answerer.cc
@@ -0,0 +1,42 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/k_anonymity_service/remote_trust_token_query_answerer.h" + +#include "content/public/browser/storage_partition.h" + +RemoteTrustTokenQueryAnswerer::RemoteTrustTokenQueryAnswerer( + url::Origin top_frame_origin, + Profile* profile) + : top_frame_origin_(std::move(top_frame_origin)), profile_(profile) {} + +RemoteTrustTokenQueryAnswerer::~RemoteTrustTokenQueryAnswerer() = default; + +void RemoteTrustTokenQueryAnswerer::HasTrustTokens( + const url::Origin& issuer, + HasTrustTokensCallback callback) { + if (!cached_answerer_ || !cached_answerer_.is_connected()) { + UpdateCachedAnswerer(); + } + // TODO(behamilton): If the network service crashes while this request + // has been queued the callback will never be called. + return cached_answerer_->HasTrustTokens(issuer, std::move(callback)); +} + +void RemoteTrustTokenQueryAnswerer::HasRedemptionRecord( + const url::Origin& issuer, + HasRedemptionRecordCallback callback) { + if (!cached_answerer_ || !cached_answerer_.is_connected()) { + UpdateCachedAnswerer(); + } + // TODO(behamilton): If the network service crashes while this request + // has been queued the callback will never be called. + return cached_answerer_->HasRedemptionRecord(issuer, std::move(callback)); +} + +void RemoteTrustTokenQueryAnswerer::UpdateCachedAnswerer() { + cached_answerer_.reset(); + profile_->GetDefaultStoragePartition()->CreateTrustTokenQueryAnswerer( + cached_answerer_.BindNewPipeAndPassReceiver(), top_frame_origin_); +}
diff --git a/chrome/browser/k_anonymity_service/remote_trust_token_query_answerer.h b/chrome/browser/k_anonymity_service/remote_trust_token_query_answerer.h new file mode 100644 index 0000000..a6886e20 --- /dev/null +++ b/chrome/browser/k_anonymity_service/remote_trust_token_query_answerer.h
@@ -0,0 +1,43 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_K_ANONYMITY_SERVICE_REMOTE_TRUST_TOKEN_QUERY_ANSWERER_H_ +#define CHROME_BROWSER_K_ANONYMITY_SERVICE_REMOTE_TRUST_TOKEN_QUERY_ANSWERER_H_ + +#include "base/memory/raw_ptr.h" +#include "chrome/browser/profiles/profile.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "services/network/public/mojom/trust_tokens.mojom.h" + +// This class acts as a proxy to the TrustTokenQueryAnswerer in the network +// service. When something happens to the mojom connection to the +// TrustTokenQueryAnswerer it sets up a new connection and uses that for further +// queries. +// +// The k-anonymity service code is the only user of this utility class, so it +// can share the directory with them. That may change if there are other users. +class RemoteTrustTokenQueryAnswerer + : public network::mojom::TrustTokenQueryAnswerer { + public: + RemoteTrustTokenQueryAnswerer(url::Origin top_frame_origin, Profile* profile); + + ~RemoteTrustTokenQueryAnswerer() override; + + // Implementation of network::mojom::TrustTokenQueryAnswerer + void HasTrustTokens(const url::Origin& issuer, + HasTrustTokensCallback callback) override; + void HasRedemptionRecord(const url::Origin& issuer, + HasRedemptionRecordCallback callback) override; + + private: + // Create a new connection to the TrustTokenQueryAnswerer and update the + // cache to use it instead. + void UpdateCachedAnswerer(); + + const url::Origin top_frame_origin_; + const base::raw_ptr<Profile> profile_; + mojo::Remote<network::mojom::TrustTokenQueryAnswerer> cached_answerer_; +}; + +#endif // CHROME_BROWSER_K_ANONYMITY_SERVICE_REMOTE_TRUST_TOKEN_QUERY_ANSWERER_H_
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc index 8a2fd31..0315c09 100644 --- a/chrome/browser/metrics/process_memory_metrics_emitter.cc +++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -43,6 +43,10 @@ #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h" #include "url/gurl.h" +#if BUILDFLAG(IS_ANDROID) +#include "base/android/child_process_binding_types.h" +#endif + #if BUILDFLAG(ENABLE_EXTENSIONS) #include "extensions/browser/extension_registry.h" #include "extensions/browser/process_map.h" @@ -960,6 +964,33 @@ builder.Record(ukm_recorder); } +#if BUILDFLAG(IS_ANDROID) +// Return the base::android::ChildBindingState if the process with `pid` is a +// renderer. If the `pid` is not in the list of live renderers it is assumed to +// be unbound. If the `process_type` is not for a renderer return nullopt. +absl::optional<base::android::ChildBindingState> +GetAndroidRendererProcessBindingState( + memory_instrumentation::mojom::ProcessType process_type, + base::ProcessId pid) { + if (process_type != memory_instrumentation::mojom::ProcessType::RENDERER) { + return absl::nullopt; + } + for (auto iter = content::RenderProcessHost::AllHostsIterator(); + !iter.IsAtEnd(); iter.Advance()) { + if (!iter.GetCurrentValue()->GetProcess().IsValid()) + continue; + + if (iter.GetCurrentValue()->GetProcess().Pid() == pid) { + return iter.GetCurrentValue()->GetEffectiveChildBindingState(); + } + } + // This can occur if the process no longer exists. Specifically, it is + // possible a memory dump was requested, but the process was killed before + // reaching this point so we cannot check its status. Treat as UNBOUND. + return base::android::ChildBindingState::UNBOUND; +} +#endif // BUILDFLAG(IS_ANDROID) + } // namespace ProcessMemoryMetricsEmitter::ProcessMemoryMetricsEmitter() @@ -1126,6 +1157,12 @@ return; uint32_t private_footprint_total_kb = 0; +#if BUILDFLAG(IS_ANDROID) + uint32_t private_footprint_excluding_waived_total_kb = 0; + uint32_t renderer_private_footprint_excluding_waived_total_kb = 0; + uint32_t private_footprint_visible_or_higher_total_kb = 0; + uint32_t renderer_private_footprint_visible_or_higher_total_kb = 0; +#endif // BUILDFLAG(IS_ANDROID) uint32_t renderer_private_footprint_total_kb = 0; uint32_t renderer_malloc_total_kb = 0; uint32_t shared_footprint_total_kb = 0; @@ -1139,6 +1176,24 @@ for (const auto& pmd : global_dump_->process_dumps()) { uint32_t process_pmf_kb = pmd.os_dump().private_footprint_kb; private_footprint_total_kb += process_pmf_kb; +#if BUILDFLAG(IS_ANDROID) + bool is_waived_renderer = false; + bool is_less_than_visible_renderer = false; + auto renderer_binding_state_android = + GetAndroidRendererProcessBindingState(pmd.process_type(), pmd.pid()); + if (renderer_binding_state_android) { + // Also exclude base::android::ChildBindingState::UNBOUND which can occur + // as the state change can be racy. + is_waived_renderer = *renderer_binding_state_android <= + base::android::ChildBindingState::WAIVED; + is_less_than_visible_renderer = *renderer_binding_state_android < + base::android::ChildBindingState::VISIBLE; + } + private_footprint_excluding_waived_total_kb += + is_waived_renderer ? 0 : process_pmf_kb; + private_footprint_visible_or_higher_total_kb += + is_less_than_visible_renderer ? 0 : process_pmf_kb; +#endif // BUILDFLAG(IS_ANDROID) shared_footprint_total_kb += pmd.os_dump().shared_footprint_kb; resident_set_total_kb += pmd.os_dump().resident_set_kb; @@ -1154,6 +1209,12 @@ } case memory_instrumentation::mojom::ProcessType::RENDERER: { renderer_private_footprint_total_kb += process_pmf_kb; +#if BUILDFLAG(IS_ANDROID) + renderer_private_footprint_excluding_waived_total_kb += + is_waived_renderer ? 0 : process_pmf_kb; + renderer_private_footprint_visible_or_higher_total_kb += + is_less_than_visible_renderer ? 0 : process_pmf_kb; +#endif // BUILDFLAG(IS_ANDROID) const PageInfo* single_page_info = nullptr; auto iter = process_infos_.find(pmd.pid()); if (iter != process_infos_.end()) { @@ -1287,9 +1348,22 @@ renderer_malloc_total_kb / kKiB); UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Total.SharedMemoryFootprint", shared_footprint_total_kb / kKiB); - UMA_HISTOGRAM_MEMORY_MEDIUM_MB("Memory.Total.TileMemory", tiles_total_memory / kMiB); +#if BUILDFLAG(IS_ANDROID) + UMA_HISTOGRAM_MEMORY_LARGE_MB( + "Memory.Total.PrivateMemoryFootprintExcludingWaivedRenderers", + private_footprint_excluding_waived_total_kb / kKiB); + UMA_HISTOGRAM_MEMORY_LARGE_MB( + "Memory.Total.RendererPrivateMemoryFootprintExcludingWaived", + renderer_private_footprint_excluding_waived_total_kb / kKiB); + UMA_HISTOGRAM_MEMORY_LARGE_MB( + "Memory.Total.PrivateMemoryFootprintVisibleOrHigherPriorityRenderers", + private_footprint_visible_or_higher_total_kb / kKiB); + UMA_HISTOGRAM_MEMORY_LARGE_MB( + "Memory.Total.RendererPrivateMemoryFootprintVisibleOrHigherPriority", + renderer_private_footprint_visible_or_higher_total_kb / kKiB); +#endif Memory_Experimental(ukm::UkmRecorder::GetNewSourceID()) .SetTotal2_PrivateMemoryFootprint(private_footprint_total_kb / kKiB)
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc b/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc index e8897e4..32dc1e4 100644 --- a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc +++ b/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
@@ -950,6 +950,16 @@ "Memory.NativeLibrary.NotResidentOrderedCodeMemoryFootprint", 0); histograms.ExpectTotalCount( "Memory.NativeLibrary.ResidentNotOrderedCodeMemoryFootprint", 0); +#if BUILDFLAG(IS_ANDROID) + histograms.ExpectTotalCount( + "Memory.Total.PrivateMemoryFootprintExcludingWaivedRenderers", 0); + histograms.ExpectTotalCount( + "Memory.Total.RendererPrivateMemoryFootprintExcludingWaived", 0); + histograms.ExpectTotalCount( + "Memory.Total.PrivateMemoryFootprintVisibleOrHigherPriorityRenderers", 0); + histograms.ExpectTotalCount( + "Memory.Total.RendererPrivateMemoryFootprintVisibleOrHigherPriority", 0); +#endif // Simulate some metrics emission. scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter = @@ -996,6 +1006,20 @@ histograms.ExpectUniqueSample( "Memory.NativeLibrary.ResidentNotOrderedCodeMemoryFootprint", kNativeLibraryResidentNotOrderedCodeFootprint, 1); +#if BUILDFLAG(IS_ANDROID) + // Expect values of 0 as the Renderer is not in the list of active processes + // and is therefore considered UNBOUND and will not emit these values. + histograms.ExpectUniqueSample( + "Memory.Total.PrivateMemoryFootprintExcludingWaivedRenderers", 0, 1); + histograms.ExpectUniqueSample( + "Memory.Total.RendererPrivateMemoryFootprintExcludingWaived", 0, 1); + histograms.ExpectUniqueSample( + "Memory.Total.PrivateMemoryFootprintVisibleOrHigherPriorityRenderers", 0, + 1); + histograms.ExpectUniqueSample( + "Memory.Total.RendererPrivateMemoryFootprintVisibleOrHigherPriority", 0, + 1); +#endif } TEST_F(ProcessMemoryMetricsEmitterTest, MainFramePMFEmitted) {
diff --git a/chrome/browser/net/private_network_access_browsertest.cc b/chrome/browser/net/private_network_access_browsertest.cc index 76777a2..1a5263da 100644 --- a/chrome/browser/net/private_network_access_browsertest.cc +++ b/chrome/browser/net/private_network_access_browsertest.cc
@@ -1504,8 +1504,8 @@ // load due to a transient network error, it is auto-reloaded a short while // later and that fetch is not blocked as a private network request. // -// TODO(crbug.com/1326341): Flaky on Linux ChromiumOS MSAN. -#if BUILDFLAG(IS_CHROMEOS) +// TODO(crbug.com/1326341): Flaky on Linux MSan. +#if BUILDFLAG(IS_LINUX) && defined(MEMORY_SANITIZER) #define MAYBE_AutoReloadWorks DISABLED_AutoReloadWorks #else #define MAYBE_AutoReloadWorks AutoReloadWorks
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index c16596a..e500322 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -487,17 +487,6 @@ const char kDiceMigrationCompletePref[] = "signin.DiceMigrationComplete"; #endif -#if BUILDFLAG(IS_CHROMEOS_ASH) -// Deprecated 07/2022. -// The name of a boolean pref that determines whether we can show the folder -// selection user nudge for the screen capture tool. When this pref is false, it -// means that we showed the nudge at some point and the user interacted with the -// capture mode session UI in such a way that the nudge no longer needs to be -// displayed again. -constexpr char kCanShowFolderSelectionNudge[] = - "ash.capture_mode.can_show_folder_selection_nudge"; -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - #if !BUILDFLAG(IS_ANDROID) // Deprecated 09/2021. const char kNtpSearchSuggestionsBlocklist[] = @@ -747,6 +736,13 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) // Deprecated 07/2022. +// The name of a boolean pref that determines whether we can show the folder +// selection user nudge for the screen capture tool. When this pref is false, it +// means that we showed the nudge at some point and the user interacted with the +// capture mode session UI in such a way that the nudge no longer needs to be +// displayed again. +constexpr char kCanShowFolderSelectionNudge[] = + "ash.capture_mode.can_show_folder_selection_nudge"; const char kSettingsShowOSBanner[] = "settings.cros.show_os_banner"; #endif @@ -764,6 +760,8 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) // Deprecated 09/2022. +constexpr char kClipboardHistoryNewFeatureBadgeCount[] = + "ash.clipboard.multipaste_nudges.new_feature_shown_count"; constexpr char kUsersLastInputMethod[] = "UsersLRUInputMethod"; #endif // BUILDFLAG(IS_CHROMEOS_ASH) @@ -1018,6 +1016,10 @@ // Deprecated 09/2022 registry->RegisterBooleanPref(kPrivacySandboxFirstPartySetsDataAccessAllowed, true); + +#if BUILDFLAG(IS_CHROMEOS_ASH) + registry->RegisterIntegerPref(kClipboardHistoryNewFeatureBadgeCount, 0); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } } // namespace @@ -1768,11 +1770,6 @@ feed::MigrateObsoleteProfilePrefsJune_2021(profile_prefs); #endif // BUILDFLAG(IS_ANDROID) -#if BUILDFLAG(IS_CHROMEOS_ASH) - // Added 07/2022. - profile_prefs->ClearPref(kCanShowFolderSelectionNudge); -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - #if !BUILDFLAG(IS_ANDROID) // Added 09/2021. profile_prefs->ClearPref(kNtpSearchSuggestionsBlocklist); @@ -1966,6 +1963,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) // Added 07/2022. + profile_prefs->ClearPref(kCanShowFolderSelectionNudge); profile_prefs->ClearPref(kSettingsShowOSBanner); #endif @@ -1995,6 +1993,11 @@ // Added 09/2022. profile_prefs->ClearPref(kPrivacySandboxFirstPartySetsDataAccessAllowed); +#if BUILDFLAG(IS_CHROMEOS_ASH) + // Added 09/2022. + profile_prefs->ClearPref(kClipboardHistoryNewFeatureBadgeCount); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + // Please don't delete the following line. It is used by PRESUBMIT.py. // END_MIGRATE_OBSOLETE_PROFILE_PREFS
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index 5afb23b..ad388b0 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc
@@ -1384,6 +1384,17 @@ return FederatedIdentitySharingPermissionContextFactory::GetForProfile(this); } +std::unique_ptr<content::KAnonymityServiceDelegate> +ProfileImpl::CreateKAnonymityServiceDelegate() { +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + if (!base::FeatureList::IsEnabled(features::kKAnonymityService)) + return nullptr; + return std::make_unique<KAnonymityServiceClient>(this); +#else + return nullptr; +#endif +} + content::ReduceAcceptLanguageControllerDelegate* ProfileImpl::GetReduceAcceptLanguageControllerDelegate() { return ReduceAcceptLanguageFactory::GetForProfile(this);
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h index c46005d..fa114390 100644 --- a/chrome/browser/profiles/profile_impl.h +++ b/chrome/browser/profiles/profile_impl.h
@@ -106,6 +106,8 @@ GetFederatedIdentityActiveSessionPermissionContext() override; content::FederatedIdentitySharingPermissionContextDelegate* GetFederatedIdentitySharingPermissionContext() override; + std::unique_ptr<content::KAnonymityServiceDelegate> + CreateKAnonymityServiceDelegate() override; // Profile implementation: scoped_refptr<base::SequencedTaskRunner> GetIOTaskRunner() override;
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index ec0ec68..2b00f858 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -2021,16 +2021,6 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) menu_model_.AddItemWithStringId(IDC_CONTENT_CLIPBOARD_HISTORY_MENU, IDS_CONTEXT_MENU_SHOW_CLIPBOARD_HISTORY_MENU); - ash::ClipboardHistoryController* clipboard_history_controller = - ash::ClipboardHistoryController::Get(); - if (clipboard_history_controller && - clipboard_history_controller->ShouldShowNewFeatureBadge()) { - menu_model_.SetIsNewFeatureAt( - menu_model_.GetIndexOfCommandId(IDC_CONTENT_CLIPBOARD_HISTORY_MENU) - .value(), - true); - clipboard_history_controller->MarkNewFeatureBadgeShown(); - } #endif #if BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc index 99a6ce0..fe8904f 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -452,18 +452,20 @@ "var l = document.getElementById('link1');" "l.click();")); - // Wait for the guest contents of the PDF plugin is created. - WebContents* guest_contents = - test_guest_view_manager_->DeprecatedWaitForSingleGuestCreated(); - TestMimeHandlerViewGuest* guest = static_cast<TestMimeHandlerViewGuest*>( - extensions::MimeHandlerViewGuest::FromWebContents(guest_contents)); - ASSERT_TRUE(guest); - // Wait for the guest is attached to the embedder. + // Wait for the guest view of the PDF plugin to be created. + auto* guest_view = + test_guest_view_manager_->WaitForSingleGuestViewCreated(); + ASSERT_TRUE(guest_view); + TestMimeHandlerViewGuest* guest = + static_cast<TestMimeHandlerViewGuest*>(guest_view); + + // Wait for the guest to be attached to the embedder. guest->WaitForGuestAttached(); - ASSERT_NE(web_contents, guest_contents); + // Get the pdf plugin's main frame. - content::RenderFrameHost* frame = guest_contents->GetPrimaryMainFrame(); + content::RenderFrameHost* frame = guest_view->GetGuestMainFrame(); ASSERT_TRUE(frame); + ASSERT_NE(web_contents->GetPrimaryMainFrame(), frame); content::ContextMenuParams params; params.page_url = page_url;
diff --git a/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json b/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json index 573acdf..603bde0 100644 --- a/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json +++ b/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json
@@ -1247,6 +1247,17 @@ ] }, { + "name": "__MSG_keyboard_hindi_inscript__", + "id": "vkd_hi_inscript", + "indicator": "\u0939\u093f", + "language": [ + "hi" + ], + "layouts": [ + "us" + ] + }, + { "name": "__MSG_keyboard_kannada_phonetic__", "id": "vkd_kn_phone", "language": [
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn index 1599b94..8c0f8a2 100644 --- a/chrome/browser/resources/chromeos/login/BUILD.gn +++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -244,7 +244,6 @@ "screens/common/assistant_optin.m.js", "screens/common/consolidated_consent.m.js", "screens/common/device_disabled.m.js", - "screens/common/error_message.m.js", "screens/common/family_link_notice.m.js", "screens/common/gaia_signin.m.js", "screens/common/guest_tos.m.js", @@ -290,6 +289,7 @@ "screens/common/arc_terms_of_service.js", "screens/common/autolaunch.js", "screens/common/enable_kiosk.js", + "screens/common/error_message.js", "screens/common/fingerprint_setup.js", "screens/common/gesture_navigation.js", "screens/common/local_state_error.js",
diff --git a/chrome/browser/resources/chromeos/login/screens.js b/chrome/browser/resources/chromeos/login/screens.js index 29b6e04..83aab34 100644 --- a/chrome/browser/resources/chromeos/login/screens.js +++ b/chrome/browser/resources/chromeos/login/screens.js
@@ -15,7 +15,7 @@ import './screens/common/consolidated_consent.m.js'; import './screens/common/device_disabled.m.js'; import './screens/common/enable_kiosk.js'; -import './screens/common/error_message.m.js'; +import './screens/common/error_message.js'; import './screens/common/family_link_notice.m.js'; import './screens/common/fingerprint_setup.js'; import './screens/common/gaia_signin.m.js';
diff --git a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn index 517ae78..2288eee9 100644 --- a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn +++ b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn
@@ -17,7 +17,6 @@ ":assistant_optin_module", ":consolidated_consent_module", ":device_disabled_module", - ":error_message_module", ":family_link_notice_module", ":gaia_signin_module", ":guest_tos_module", @@ -56,7 +55,7 @@ ":consolidated_consent.m", ":device_disabled.m", ":enable_kiosk", - ":error_message.m", + ":error_message", ":family_link_notice.m", ":fingerprint_setup", ":gaia_signin.m", @@ -651,8 +650,8 @@ extra_deps = [ ":web_components" ] } -js_library("error_message.m") { - sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/common/error_message.m.js" ] +js_library("error_message") { + sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/common/error_message.js" ] deps = [ "../../:cr_ui.m", "../../components:display_manager_types.m", @@ -665,7 +664,7 @@ "../../components/dialogs:oobe_adaptive_dialog.m", "//ui/webui/resources/js:parse_html_subset", ] - extra_deps = [ ":error_message_module" ] + extra_deps = [ ":web_components" ] } polymer_modulizer("app_launch_splash") { @@ -824,15 +823,6 @@ migrated_imports = oobe_migrated_imports } -polymer_modulizer("error_message") { - js_file = "error_message.js" - html_file = "error_message.html" - html_type = "dom-module" - auto_imports = oobe_auto_imports - migrated_imports = oobe_migrated_imports - namespace_rewrites = oobe_namespace_rewrites -} - html_to_js("web_components") { js_files = [ "adb_sideloading.js", @@ -840,6 +830,7 @@ "arc_terms_of_service.js", "autolaunch.js", "enable_kiosk.js", + "error_message.js", "fingerprint_setup.js", "gesture_navigation.js", "local_state_error.js",
diff --git a/chrome/browser/resources/chromeos/login/screens/common/error_message.html b/chrome/browser/resources/chromeos/login/screens/common/error_message.html index 354e2d0..9409f93 100644 --- a/chrome/browser/resources/chromeos/login/screens/common/error_message.html +++ b/chrome/browser/resources/chromeos/login/screens/common/error_message.html
@@ -1,191 +1,166 @@ -<link rel="import" href="chrome://resources/html/polymer.html"> +<style include="oobe-common-styles action-link"> + .scrollable { + overflow: auto; + } -<link rel="import" href="chrome://resources/html/action_link.html"> -<link rel="import" href="chrome://resources/cr_elements/i18n_behavior.html"> -<link rel="import" href="chrome://resources/html/load_time_data.html"> -<link rel="import" href="chrome://resources/html/parse_html_subset.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html"> + #offline-network-control { + margin-bottom: 20px; + min-height: 200px; + } -<link rel="import" href="../../components/behaviors/oobe_i18n_behavior.html"> -<link rel="import" href="../../components/behaviors/oobe_dialog_host_behavior.html"> -<link rel="import" href="../../components/behaviors/login_screen_behavior.html"> -<link rel="import" href="../../components/buttons/oobe_back_button.html"> -<link rel="import" href="../../components/buttons/oobe_text_button.html"> -<link rel="import" href="../../components/common_styles/common_styles.html"> -<link rel="import" href="../../components/dialogs/oobe_adaptive_dialog.html"> -<link rel="import" href="../../components/display_manager_types.html"> -<link rel="import" href="../../components/network_select_login.html"> -<link rel="import" href="../../cr_ui.html"> + @keyframes connecting-indicator-ellipsis { + 0% { + opacity: 0; + } + 10% { + opacity: 1; + } + 50% { + opacity: .8; + } + 100% { + opacity: 0; + } + } -<dom-module id="error-message-element"> - <template> - <style include="oobe-common-styles action-link"> - .scrollable { - overflow: auto; - } + #connecting-indicator-ellipsis-1 { + animation: connecting-indicator-ellipsis 3s 0s infinite; + } - #offline-network-control { - margin-bottom: 20px; - min-height: 200px; - } + #connecting-indicator-ellipsis-2 { + animation: connecting-indicator-ellipsis 3s 500ms infinite; + } - @keyframes connecting-indicator-ellipsis { - 0% { - opacity: 0; - } - 10% { - opacity: 1; - } - 50% { - opacity: .8; - } - 100% { - opacity: 0; - } - } - - #connecting-indicator-ellipsis-1 { - animation: connecting-indicator-ellipsis 3s 0s infinite; - } - - #connecting-indicator-ellipsis-2 { - animation: connecting-indicator-ellipsis 3s 500ms infinite; - } - - #connecting-indicator-ellipsis-3 { - animation: connecting-indicator-ellipsis 3s 1s infinite; - } - </style> - <oobe-adaptive-dialog role="dialog" id="dialog"> - <iron-icon slot="icon" icon="oobe-32:wifi"> - </iron-icon> - <h1 slot="title" aria-live="assertive"> - [[getDialogTitle_(locale, errorState_, uiState_)]] - </h1> - <div slot="subtitle"> - <div hidden="[[!isOneOf_(errorState_, 'kiosk-online')]]"> - [[i18nDynamic(locale, 'kioskOnlineMessageBody')]] - </div> - <div id="offlineMessageBody" hidden="[[!isOneOf_(errorState_, - 'offline', 'auth-ext-timeout')]]"> - <span hidden="[[!isOneOf_(uiState_, 'ui-state-update')]]"> - [[i18nDynamic(locale, 'updateOfflineMessageBody')]] - </span> - <span hidden="[[!isOneOf_(uiState_, - 'ui-state-signin', 'ui-state-supervised')]]"> - [[i18nDynamic(locale, 'signinOfflineMessageBody')]] - </span> - <span hidden="[[!isOneOf_(uiState_, 'ui-state-kiosk-mode')]]"> - [[i18nDynamic(locale, 'kioskOfflineMessageBody')]] - </span> - </div> - <div hidden="[[!isOneOf_(errorState_, 'portal')]]"> - <span id="captive-portal-message-text" - hidden="[[!isOneOf_(uiState_, - 'ui-state-update', - 'ui-state-signin', - 'ui-state-supervised', - 'ui-state-kiosk-mode')]]"> - </span> - </div> - <div hidden="[[!isOneOf_(errorState_, - 'portal', - 'auth-ext-timeout')]]"> - <span id="captive-portal-proxy-message-text" - hidden="[[!isOneOf_(uiState_, - 'ui-state-update', - 'ui-state-signin', - 'ui-state-supervised', - 'ui-state-kiosk-mode')]]"> - </span> - </div> - <div hidden="[[!isOneOf_(errorState_, 'proxy')]]"> - <span id="update-proxy-message-text" - hidden="[[!isOneOf_(uiState_, - 'ui-state-update')]]"> - </span> - <span id="signin-proxy-message-text" - hidden="[[!isOneOf_(uiState_, - 'ui-state-signin', - 'ui-state-supervised', - 'ui-state-kiosk-mode')]]"> - </span> - </div> - <span hidden="[[!isOneOf_(uiState_,'ui-state-auto-enrollment-error')]]"> - [[i18nDynamic(locale, 'autoEnrollmentOfflineMessageBody')]] - </span> - <div hidden="[[!isOneOf_(uiState_, 'ui-state-rollback-error')]]"> - [[i18nDynamic(locale, 'rollbackErrorMessageBody')]] - </div> - <div id="guestSessionText" hidden="[[!isOneOf_(uiState_, - 'ui-state-update', - 'ui-state-signin', - 'ui-state-supervised', - 'ui-state-kiosk-mode')]]"> - <span id="error-guest-signin" hidden="[[!guestSessionAllowed_]]"> - </span> - </div> - <div hidden="[[!isOneOf_(uiState_, 'ui-state-auto-enrollment-error')]]"> - <span id="error-guest-signin-fix-network" - hidden="[[!guestSessionAllowed_]]"> - </span> - </div> - <div id="error-offline-login" hidden="[[!offlineLoginAllowed_]]"> - </div> - <div hidden="[[!connectingIndicatorShown_]]"> - [[i18nDynamic(locale, 'connectingIndicatorText')]] - <span id="connecting-indicator-ellipsis-1">.</span> - <span id="connecting-indicator-ellipsis-2">.</span> - <span id="connecting-indicator-ellipsis-3">.</span> - </div> - </div> - <div slot="content" class="flex layout vertical"> - <div class="error-body" aria-live="assertive"> - <div hidden="[[!isOneOf_(uiState_, + #connecting-indicator-ellipsis-3 { + animation: connecting-indicator-ellipsis 3s 1s infinite; + } +</style> +<oobe-adaptive-dialog role="dialog" id="dialog"> + <iron-icon slot="icon" icon="oobe-32:wifi"> + </iron-icon> + <h1 slot="title" aria-live="assertive"> + [[getDialogTitle_(locale, errorState_, uiState_)]] + </h1> + <div slot="subtitle"> + <div hidden="[[!isOneOf_(errorState_, 'kiosk-online')]]"> + [[i18nDynamic(locale, 'kioskOnlineMessageBody')]] + </div> + <div id="offlineMessageBody" hidden="[[!isOneOf_(errorState_, + 'offline', 'auth-ext-timeout')]]"> + <span hidden="[[!isOneOf_(uiState_, 'ui-state-update')]]"> + [[i18nDynamic(locale, 'updateOfflineMessageBody')]] + </span> + <span hidden="[[!isOneOf_(uiState_, + 'ui-state-signin', 'ui-state-supervised')]]"> + [[i18nDynamic(locale, 'signinOfflineMessageBody')]] + </span> + <span hidden="[[!isOneOf_(uiState_, 'ui-state-kiosk-mode')]]"> + [[i18nDynamic(locale, 'kioskOfflineMessageBody')]] + </span> + </div> + <div hidden="[[!isOneOf_(errorState_, 'portal')]]"> + <span id="captive-portal-message-text" + hidden="[[!isOneOf_(uiState_, 'ui-state-update', 'ui-state-signin', 'ui-state-supervised', - 'ui-state-kiosk-mode', - 'ui-state-auto-enrollment-error')]]" class="scrollable"> - <network-select-login id="offline-network-control" - class="layout vertical flex" configure-connected - enable-wifi-scans="[[enableWifiScans_]]" - on-selected-network-connected="onNetworkConnected_"> - </network-select-login> - </div> - </div> + 'ui-state-kiosk-mode')]]"> + </span> + </div> + <div hidden="[[!isOneOf_(errorState_, + 'portal', + 'auth-ext-timeout')]]"> + <span id="captive-portal-proxy-message-text" + hidden="[[!isOneOf_(uiState_, + 'ui-state-update', + 'ui-state-signin', + 'ui-state-supervised', + 'ui-state-kiosk-mode')]]"> + </span> + </div> + <div hidden="[[!isOneOf_(errorState_, 'proxy')]]"> + <span id="update-proxy-message-text" + hidden="[[!isOneOf_(uiState_, + 'ui-state-update')]]"> + </span> + <span id="signin-proxy-message-text" + hidden="[[!isOneOf_(uiState_, + 'ui-state-signin', + 'ui-state-supervised', + 'ui-state-kiosk-mode')]]"> + </span> + </div> + <span hidden="[[!isOneOf_(uiState_,'ui-state-auto-enrollment-error')]]"> + [[i18nDynamic(locale, 'autoEnrollmentOfflineMessageBody')]] + </span> + <div hidden="[[!isOneOf_(uiState_, 'ui-state-rollback-error')]]"> + [[i18nDynamic(locale, 'rollbackErrorMessageBody')]] + </div> + <div id="guestSessionText" hidden="[[!isOneOf_(uiState_, + 'ui-state-update', + 'ui-state-signin', + 'ui-state-supervised', + 'ui-state-kiosk-mode')]]"> + <span id="error-guest-signin" hidden="[[!guestSessionAllowed_]]"> + </span> + </div> + <div hidden="[[!isOneOf_(uiState_, 'ui-state-auto-enrollment-error')]]"> + <span id="error-guest-signin-fix-network" + hidden="[[!guestSessionAllowed_]]"> + </span> + </div> + <div id="error-offline-login" hidden="[[!offlineLoginAllowed_]]"> + </div> + <div hidden="[[!connectingIndicatorShown_]]"> + [[i18nDynamic(locale, 'connectingIndicatorText')]] + <span id="connecting-indicator-ellipsis-1">.</span> + <span id="connecting-indicator-ellipsis-2">.</span> + <span id="connecting-indicator-ellipsis-3">.</span> + </div> + </div> + <div slot="content" class="flex layout vertical"> + <div class="error-body" aria-live="assertive"> + <div hidden="[[!isOneOf_(uiState_, + 'ui-state-update', + 'ui-state-signin', + 'ui-state-supervised', + 'ui-state-kiosk-mode', + 'ui-state-auto-enrollment-error')]]" class="scrollable"> + <network-select-login id="offline-network-control" + class="layout vertical flex" configure-connected + enable-wifi-scans="[[enableWifiScans_]]" + on-selected-network-connected="onNetworkConnected_"> + </network-select-login> </div> - <div slot="back-navigation"> - <oobe-back-button id="backButton" on-click="cancel"> - </oobe-back-button> - </div> - <div slot="bottom-buttons"> - <oobe-text-button on-click="rebootButtonClicked" - text-key="rebootButton" - hidden="[[!isOneOf_(uiState_, 'ui-state-kiosk-mode')]]"> - </oobe-text-button> - <oobe-text-button on-click="diagnoseButtonClicked" - text-key="diagnoseButton" - hidden="[[!isOneOf_(uiState_, 'ui-state-kiosk-mode')]]"> - </oobe-text-button> - <oobe-text-button id="configureCertsButton" - on-click="configureCertsButtonClicked" - text-key="configureCertsButton" - hidden="[[!isOneOf_(uiState_, 'ui-state-kiosk-mode')]]"> - </oobe-text-button> - <oobe-text-button id="continueButton" - on-click="continueButtonClicked" - text-key="continueButton" - hidden="[[!isOneOf_(errorState_, 'kiosk-online')]]"> - </oobe-text-button> - <oobe-text-button id="okButton" - on-click="okButtonClicked" - text-key="okButton" - hidden="[[!isOneOf_(uiState_, 'ui-state-rollback-error')]]"> - </oobe-text-button> - </div> - </oobe-adaptive-dialog> - </template> - <script src="error_message.js"></script> -</dom-module> + </div> + </div> + <div slot="back-navigation"> + <oobe-back-button id="backButton" on-click="cancel"> + </oobe-back-button> + </div> + <div slot="bottom-buttons"> + <oobe-text-button on-click="rebootButtonClicked" + text-key="rebootButton" + hidden="[[!isOneOf_(uiState_, 'ui-state-kiosk-mode')]]"> + </oobe-text-button> + <oobe-text-button on-click="diagnoseButtonClicked" + text-key="diagnoseButton" + hidden="[[!isOneOf_(uiState_, 'ui-state-kiosk-mode')]]"> + </oobe-text-button> + <oobe-text-button id="configureCertsButton" + on-click="configureCertsButtonClicked" + text-key="configureCertsButton" + hidden="[[!isOneOf_(uiState_, 'ui-state-kiosk-mode')]]"> + </oobe-text-button> + <oobe-text-button id="continueButton" + on-click="continueButtonClicked" + text-key="continueButton" + hidden="[[!isOneOf_(errorState_, 'kiosk-online')]]"> + </oobe-text-button> + <oobe-text-button id="okButton" + on-click="okButtonClicked" + text-key="okButton" + hidden="[[!isOneOf_(uiState_, 'ui-state-rollback-error')]]"> + </oobe-text-button> + </div> +</oobe-adaptive-dialog>
diff --git a/chrome/browser/resources/chromeos/login/screens/common/error_message.js b/chrome/browser/resources/chromeos/login/screens/common/error_message.js index 5b8c1899..816e04fa 100644 --- a/chrome/browser/resources/chromeos/login/screens/common/error_message.js +++ b/chrome/browser/resources/chromeos/login/screens/common/error_message.js
@@ -6,7 +6,24 @@ * @fileoverview Offline message screen implementation. */ -/* #js_imports_placeholder */ +import '//resources/js/action_link.js'; +import '//resources/polymer/v3_0/iron-icon/iron-icon.js'; +import '//resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js'; +import '../../components/buttons/oobe_back_button.m.js'; +import '../../components/buttons/oobe_text_button.m.js'; +import '../../components/common_styles/common_styles.m.js'; +import '../../components/dialogs/oobe_adaptive_dialog.m.js'; +import '../../components/network_select_login.m.js'; + +import {SanitizeInnerHtmlOpts} from '//resources/js/parse_html_subset.js'; +import {html, mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {LoginScreenBehavior, LoginScreenBehaviorInterface} from '../../components/behaviors/login_screen_behavior.m.js'; +import {OobeDialogHostBehavior} from '../../components/behaviors/oobe_dialog_host_behavior.m.js'; +import {OobeI18nBehavior, OobeI18nBehaviorInterface} from '../../components/behaviors/oobe_i18n_behavior.m.js'; +import {OOBE_UI_STATE} from '../../components/display_manager_types.m.js'; +import {Oobe} from '../../cr_ui.m.js'; + const USER_ACTION_LAUNCH_OOBE_GUEST = 'launch-oobe-guest'; const USER_ACTION_SHOW_CAPTIVE_PORTAL = 'show-captive-portal'; @@ -71,9 +88,9 @@ * @implements {OobeI18nBehaviorInterface} * @implements {LoginScreenBehaviorInterface} */ -const ErrorMessageScreenBase = Polymer.mixinBehaviors( +const ErrorMessageScreenBase = mixinBehaviors( [OobeI18nBehavior, OobeDialogHostBehavior, LoginScreenBehavior], - Polymer.Element); + PolymerElement); /** * @polymer @@ -83,7 +100,9 @@ return 'error-message-element'; } - /* #html_template_placeholder */ + static get template() { + return html`{__html_template__}`; + } /** @override */ get EXTERNAL_API() {
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/quick_start.html b/chrome/browser/resources/chromeos/login/screens/oobe/quick_start.html index 6caf209..e6905cf 100644 --- a/chrome/browser/resources/chromeos/login/screens/oobe/quick_start.html +++ b/chrome/browser/resources/chromeos/login/screens/oobe/quick_start.html
@@ -22,7 +22,7 @@ margin: 28px 14px; } - #verification { + #figures { margin: auto; } @@ -49,9 +49,24 @@ <oobe-adaptive-dialog for-step="verification"> <h1 slot="title"> <!--TODO(https://crbug.com/1278686) Update with finalize strings --> + Scan the QR code + </h1> + <div id="code" class="layout horizontal" slot="content"> + <div id="qrCodeWrapper"> + <canvas id="qrCodeCanvas" width="[[canvasSize_]]" + height="[[canvasSize_]]"> + </div> + </div> + <div slot="bottom-buttons"> + <oobe-next-button on-click="onNextClicked_"></oobe-next-button> + </div> + </oobe-adaptive-dialog> + <oobe-adaptive-dialog for-step="figures"> + <h1 slot="title"> + <!--TODO(https://crbug.com/1278686) Update with finalize strings --> Verify the shapes </h1> - <div id="verification" class="layout horizontal" slot="content"> + <div id="figures" class="layout horizontal" slot="content"> <!-- We inline SVGs here to be able to control the color of them. --> <template is="dom-repeat" items="[[figures_]]"> <div class="layout vertical center">
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/quick_start.js b/chrome/browser/resources/chromeos/login/screens/oobe/quick_start.js index ff6e5324..76c6d00 100644 --- a/chrome/browser/resources/chromeos/login/screens/oobe/quick_start.js +++ b/chrome/browser/resources/chromeos/login/screens/oobe/quick_start.js
@@ -15,11 +15,20 @@ const QuickStartUIState = { LOADING: 'loading', VERIFICATION: 'verification', + FIGURES: 'figures', }; // Should be in sync with the C++ enum (ash::quick_start::Color). const QuickStartColors = ['blue', 'red', 'green', 'yellow']; +// TODO(b/246697586) Figure out the right DPI. +// The size of each tile in pixels. +const QR_CODE_TILE_SIZE = 5; + +// TODO(b/246698826) Figure out the dark light modes. +// Styling for filled tiles in the QR code. +const QR_CODE_FILL_STYLE = '#000000'; + /** * @constructor * @extends {PolymerElement} @@ -45,6 +54,10 @@ value: {CIRCLE: 0, DIAMOND: 1, TRIANGLE: 2, SQUARE: 3}, readOnly: true, }, + canvasSize_: { + type: Number, + value: 0, + }, }; } @@ -52,10 +65,11 @@ super(); this.UI_STEPS = QuickStartUIState; this.figures_ = []; + this.canvasSize_ = 0; } get EXTERNAL_API() { - return ['setFigures']; + return ['setFigures', 'setQRCode']; } /** @override */ @@ -73,12 +87,41 @@ * @param {!Array<OobeTypes.QuickStartScreenFigureData>} figures */ setFigures(figures) { - this.setUIStep(QuickStartUIState.VERIFICATION); + this.setUIStep(QuickStartUIState.FIGURES); this.figures_ = figures.map(x => { return {shape: x.shape, color: QuickStartColors[x.color], digit: x.digit}; }); } + /** + * @param {!Array<boolean>} qrCode + */ + setQRCode(qrCode) { + const qrSize = Math.round(Math.sqrt(qrCode.length)); + this.setUIStep(QuickStartUIState.VERIFICATION); + + this.canvasSize_ = qrSize * QR_CODE_TILE_SIZE; + Polymer.dom.flush(); + const context = this.getCanvasContext_(); + context.clearRect(0, 0, this.canvasSize_, this.canvasSize_); + context.fillStyle = QR_CODE_FILL_STYLE; + let index = 0; + for (let x = 0; x < qrSize; x++) { + for (let y = 0; y < qrSize; y++) { + if (qrCode[index]) { + context.fillRect( + x * QR_CODE_TILE_SIZE, y * QR_CODE_TILE_SIZE, QR_CODE_TILE_SIZE, + QR_CODE_TILE_SIZE); + } + index++; + } + } + } + + getCanvasContext_() { + return this.shadowRoot.querySelector('#qrCodeCanvas').getContext('2d'); + } + onNextClicked_() { this.userActed('next'); }
diff --git a/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js b/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js index 00cd4d6..eafda03 100644 --- a/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js +++ b/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js
@@ -13,7 +13,7 @@ GEN('#include "ash/constants/ash_features.h"'); GEN('#include "content/public/test/browser_test.h"'); -var PolymerSecurityTokenPinTest = class extends Polymer2DeprecatedTest { +var PolymerSecurityTokenPinTest = class extends PolymerTest { /** @override */ get browsePreload() { return 'chrome://oobe/login'; @@ -29,7 +29,12 @@ } get extraLibraries() { - return super.extraLibraries.concat(['components/oobe_types.js']); + return [ + '//ui/webui/resources/js/assert.js', + '//third_party/mocha/mocha.js', + '//chrome/test/data/webui/mocha_adapter.js', + 'components/oobe_types.js', + ]; } };
diff --git a/chrome/browser/resources/password_manager/passwords_section.html b/chrome/browser/resources/password_manager/passwords_section.html index a46e58a..1d27ce1e 100644 --- a/chrome/browser/resources/password_manager/passwords_section.html +++ b/chrome/browser/resources/password_manager/passwords_section.html
@@ -4,8 +4,9 @@ display: flex; } - a { + a[href] { text-decoration: none; + color: var(--cr-link-color); } </style> <div id="header">
diff --git a/chrome/browser/resources/settings/icons.html b/chrome/browser/resources/settings/icons.html index 00e58f4..0f5b8b57 100644 --- a/chrome/browser/resources/settings/icons.html +++ b/chrome/browser/resources/settings/icons.html
@@ -125,6 +125,7 @@ <g id="midi-off"><path d="M21.19,21.19L2.81,2.81L1.39,4.22L3,5.83V19c0,1.1,0.9,2,2,2h13.17l1.61,1.61L21.19,21.19z M8.25,19H5V7.83l2,2v3.67 c0,0.55,0.45,1,1,1h0.25V19z M9.75,19v-4.5H10c0.46,0,0.82-0.31,0.94-0.73l3.31,3.31V19H9.75z M11,8.17L5.83,3H19c1.1,0,2,0.9,2,2 v13.17l-2-2V5h-2v8.5c0,0.19-0.07,0.36-0.16,0.51L13,10.17V5h-2V8.17z"></path></g> <g id="music-note"><path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"></path></g> <g id="notifications"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"></path></g> + <g id="notifications-none"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6v-5c0-3.07-1.63-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.64 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2zm-2 1H8v-6c0-2.48 1.51-4.5 4-4.5s4 2.02 4 4.5v6z"></path></g> <g id="notifications-off"><path d="M18,10c0-2.79-1.91-5.14-4.5-5.8V3.5C13.5,2.67,12.83,2,12,2s-1.5,0.67-1.5,1.5v0.7C9.64,4.42,8.87,4.84,8.21,5.38 L18,15.17V10z M12,22c1.1,0,2-0.9,2-2h-4C10,21.1,10.9,22,12,22z M2.81,2.81L1.39,4.22L6.1,8.93C6.04,9.28,6,9.63,6,10v7H4v2h12.17 l3.61,3.61l1.41-1.41L2.81,2.81z"></path></g> <g id="open-in-new-off"><path d="M17.59,5H14V3h7v7h-2V6.41l-4.88,4.88l-1.41-1.41L17.59,5z M19,12v4.17l2,2V12H19z M19.78,22.61L18.17,21H5 c-1.11,0-2-0.9-2-2V5.83L1.39,4.22l1.41-1.41l18.38,18.38L19.78,22.61z M16.17,19l-4.88-4.88L9.7,15.71L8.29,14.3l1.59-1.59L5,7.83 V19H16.17z M7.83,5H12V3H5.83L7.83,5z"></path></g> <g id="open-in-browser"><path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.11.9 2 2 2h5v-2H4V9h16v9h-5v2h5c1.1 0 2-.89 2-2V6c0-1.1-.9-2-2-2zm-3.79 10.21L12 10l-4.21 4.21 1.42 1.41L11 13.83V20h2v-6.17l1.79 1.79z"></path></g>
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_child.ts b/chrome/browser/resources/settings/safety_check_page/safety_check_child.ts index 7810573..fd663a11 100644 --- a/chrome/browser/resources/settings/safety_check_page/safety_check_child.ts +++ b/chrome/browser/resources/settings/safety_check_page/safety_check_child.ts
@@ -6,7 +6,7 @@ * @fileoverview * 'settings-safety-check-element' bundles functionality safety check elements * have in common. It is used by all safety check elements: parent, updates, - * passwors, etc. + * passwords, etc. */ import 'chrome://resources/cr_elements/cr_actionable_row_style.css.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.js'; @@ -30,6 +30,8 @@ SAFE = 1, INFO = 2, WARNING = 3, + NOTIFICATION_PERMISSIONS = 4, + UNUSED_SITE_PERMISSIONS = 5, } const SettingsSafetyCheckChildElementBase = I18nMixin(PolymerElement); @@ -115,6 +117,10 @@ return 'cr:info'; case SafetyCheckIconStatus.WARNING: return 'cr:warning'; + case SafetyCheckIconStatus.NOTIFICATION_PERMISSIONS: + return 'settings:notifications-none'; + case SafetyCheckIconStatus.UNUSED_SITE_PERMISSIONS: + return 'cr:info-outline'; default: assertNotReached(); } @@ -142,7 +148,7 @@ } /** @return The left hand icon aria label for an icon status. */ - private getStatusIconAriaLabel_(): string { + private getStatusIconAriaLabel_(): string|undefined { switch (this.iconStatus) { case SafetyCheckIconStatus.RUNNING: return this.i18n('safetyCheckIconRunningAriaLabel'); @@ -152,6 +158,9 @@ return this.i18n('safetyCheckIconInfoAriaLabel'); case SafetyCheckIconStatus.WARNING: return this.i18n('safetyCheckIconWarningAriaLabel'); + case SafetyCheckIconStatus.NOTIFICATION_PERMISSIONS: + case SafetyCheckIconStatus.UNUSED_SITE_PERMISSIONS: + return undefined; default: assertNotReached(); }
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.ts b/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.ts index cc26fc1..5da6a92 100644 --- a/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.ts +++ b/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.ts
@@ -40,7 +40,7 @@ iconStatus_: { type: SafetyCheckIconStatus, value() { - return SafetyCheckIconStatus.WARNING; + return SafetyCheckIconStatus.NOTIFICATION_PERMISSIONS; }, }, };
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_unused_site_permissions.ts b/chrome/browser/resources/settings/safety_check_page/safety_check_unused_site_permissions.ts index 65017b0..50c0dce 100644 --- a/chrome/browser/resources/settings/safety_check_page/safety_check_unused_site_permissions.ts +++ b/chrome/browser/resources/settings/safety_check_page/safety_check_unused_site_permissions.ts
@@ -40,7 +40,7 @@ iconStatus_: { type: SafetyCheckIconStatus, value() { - return SafetyCheckIconStatus.WARNING; + return SafetyCheckIconStatus.UNUSED_SITE_PERMISSIONS; }, }, };
diff --git a/chrome/browser/search_engines/OWNERS b/chrome/browser/search_engines/OWNERS index c91a1b6c..e759e30 100644 --- a/chrome/browser/search_engines/OWNERS +++ b/chrome/browser/search_engines/OWNERS
@@ -1,3 +1 @@ file://components/search_engines/OWNERS - -treib@chromium.org
diff --git a/chrome/browser/speech/speech_recognition_service_browsertest.cc b/chrome/browser/speech/speech_recognition_service_browsertest.cc index 1c67a7fa1..1a99c69 100644 --- a/chrome/browser/speech/speech_recognition_service_browsertest.cc +++ b/chrome/browser/speech/speech_recognition_service_browsertest.cc
@@ -487,7 +487,8 @@ // TestStreamFactory::stream_, to test end-to-end. std::string device_id = media::AudioDeviceDescription::kDefaultDeviceId; media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, - media::CHANNEL_LAYOUT_STEREO, 10000, 1000); + media::ChannelLayoutConfig::Stereo(), 10000, + 1000); // Create a fake stream factory. std::unique_ptr<StrictMock<TestStreamFactory>> stream_factory =
diff --git a/chrome/browser/supervised_user/supervised_user_error_page/resources/blocked_icon_dark_theme.svg b/chrome/browser/supervised_user/supervised_user_error_page/resources/blocked_icon_dark_theme.svg new file mode 100644 index 0000000..7e64fbf --- /dev/null +++ b/chrome/browser/supervised_user/supervised_user_error_page/resources/blocked_icon_dark_theme.svg
@@ -0,0 +1,3 @@ +<svg width="24" height="23" viewBox="0 0 24 23" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M10.8 15.6279H13.2V11.1628H10.8V15.6279ZM12 2.23254C6.70082 2.23254 2.40002 6.23329 2.40002 11.1628C2.40002 16.0923 6.70082 20.093 12 20.093C17.2992 20.093 21.6 16.0923 21.6 11.1628C21.6 6.23329 17.2992 2.23254 12 2.23254ZM12 17.8605C8.03102 17.8605 4.80002 14.8549 4.80002 11.1628C4.80002 7.47068 8.03102 4.4651 12 4.4651C15.969 4.4651 19.2 7.47068 19.2 11.1628C19.2 14.8549 15.969 17.8605 12 17.8605ZM10.8 13.3953H13.2V6.69766H10.8V13.3953Z" fill="#e9eaed"/> +</svg> \ No newline at end of file
diff --git a/chrome/browser/supervised_user/supervised_user_error_page/resources/blocked_icon.svg b/chrome/browser/supervised_user/supervised_user_error_page/resources/blocked_icon_light_theme.svg similarity index 100% rename from chrome/browser/supervised_user/supervised_user_error_page/resources/blocked_icon.svg rename to chrome/browser/supervised_user/supervised_user_error_page/resources/blocked_icon_light_theme.svg
diff --git a/chrome/browser/supervised_user/supervised_user_error_page/resources/supervised_user_block_interstitial.css b/chrome/browser/supervised_user/supervised_user_error_page/resources/supervised_user_block_interstitial.css index d415222..cdc2c218 100644 --- a/chrome/browser/supervised_user/supervised_user_error_page/resources/supervised_user_block_interstitial.css +++ b/chrome/browser/supervised_user/supervised_user_error_page/resources/supervised_user_block_interstitial.css
@@ -9,6 +9,8 @@ --focused-details-button-border: rgba(26, 115, 232, 0.4); --header-color: var(--google-gray-900); --paragraph-color: var(--google-gray-700); + --callout-text-color: var(--google-gray-900); + --callout-bg-color: var(--google-gray-100); font-family: "Roboto", sans-serif; padding: 24px 24px 20px 24px; } @@ -270,7 +272,7 @@ .interstitial-refresh-enabled #block-reason { align-items: center; - background-color: var(--google-gray-100); + background-color: var(--callout-bg-color); border-radius: 8px; color: var(--header-color); display: flex; @@ -288,6 +290,7 @@ } .interstitial-refresh-enabled #block-reason-message { + color: var(--callout-text-color); font-weight: 400; font-size: 14px; line-height: 20px; @@ -322,6 +325,8 @@ body.supervised-user-block.interstitial-refresh-enabled { --header-color: #e9eaed; --paragraph-color: var(--google-gray-500); + --callout-bg-color: var(--google-gray-800); + --callout-text-color: var(--google-gray-200); } .interstitial-refresh-enabled .remote-approvals-button {
diff --git a/chrome/browser/supervised_user/supervised_user_error_page/resources/supervised_user_block_interstitial.html b/chrome/browser/supervised_user/supervised_user_error_page/resources/supervised_user_block_interstitial.html index d61f279..a2361c6 100644 --- a/chrome/browser/supervised_user/supervised_user_error_page/resources/supervised_user_block_interstitial.html +++ b/chrome/browser/supervised_user/supervised_user_error_page/resources/supervised_user_block_interstitial.html
@@ -27,7 +27,13 @@ src="error_page_illustration_light_theme.svg"> </picture> <div id="block-reason"> - <img id="blocked-icon" src="blocked_icon.svg"> + <picture id="blocked-icon"> + <source + srcset="blocked_icon_dark_theme.svg" + media="(prefers-color-scheme: dark)"> + <img id="illustration" + src="blocked_icon_light_theme.svg"> + </picture> <div> <h2 id="block-reason-header">$i18n{siteBlockHeader}</h2> <p id="block-reason-message">$i18n{blockReasonMessage}</p>
diff --git a/chrome/browser/ui/android/passwords/manual_filling_view_android.cc b/chrome/browser/ui/android/passwords/manual_filling_view_android.cc index 3eddab7..b6077e6 100644 --- a/chrome/browser/ui/android/passwords/manual_filling_view_android.cc +++ b/chrome/browser/ui/android/passwords/manual_filling_view_android.cc
@@ -16,6 +16,7 @@ #include "base/android/jni_string.h" #include "base/bind.h" #include "base/callback.h" +#include "base/feature_list.h" #include "base/strings/utf_string_conversions.h" #include "base/trace_event/trace_event.h" #include "chrome/android/features/keyboard_accessory/jni_headers/ManualFillingComponentBridge_jni.h" @@ -25,6 +26,7 @@ #include "chrome/browser/password_manager/android/password_accessory_metrics_util.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "components/autofill/core/browser/ui/accessory_sheet_data.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/password_manager/core/browser/credential_cache.h" #include "components/password_manager/core/browser/password_form.h" #include "components/password_manager/core/browser/password_form_manager.h" @@ -43,9 +45,101 @@ using base::android::ConvertUTF16ToJavaString; using base::android::ConvertUTF8ToJavaString; using base::android::JavaRef; +using base::android::ScopedJavaGlobalRef; using base::android::ScopedJavaLocalRef; using password_manager::PasswordForm; +namespace { + +AccessorySheetField ConvertJavaUserInfoField( + JNIEnv* env, + const JavaRef<jobject>& j_field_to_convert) { + std::u16string display_text = ConvertJavaStringToUTF16( + env, Java_UserInfoField_getDisplayText(env, j_field_to_convert)); + std::u16string text_to_fill = ConvertJavaStringToUTF16( + env, Java_UserInfoField_getTextToFill(env, j_field_to_convert)); + std::u16string a11y_description = ConvertJavaStringToUTF16( + env, Java_UserInfoField_getA11yDescription(env, j_field_to_convert)); + std::string id = ConvertJavaStringToUTF8( + env, Java_UserInfoField_getId(env, j_field_to_convert)); + bool is_obfuscated = Java_UserInfoField_isObfuscated(env, j_field_to_convert); + bool selectable = Java_UserInfoField_isSelectable(env, j_field_to_convert); + return AccessorySheetField(display_text, text_to_fill, a11y_description, id, + is_obfuscated, selectable); +} + +// The Conversion does not require any actual methods from either side of the +// bridge — it's only required because it is referenced in callbacks. Therefore, +// the java_object can always be used, even if the controller has been +// dismissed. +// TODO(crbug.com/1354183): Pass a delegate/callback and not the bridge object. +ScopedJavaGlobalRef<jobject> ConvertAccessorySheetDataToJavaObject( + ScopedJavaGlobalRef<jobject> java_object, + AccessorySheetData tab_data) { + // Keep the ManualFillingViewAndroid:: prefix for easier trace comparison. + TRACE_EVENT0( + "passwords", + "ManualFillingViewAndroid::ConvertAccessorySheetDataToJavaObject"); + DCHECK(java_object); + JNIEnv* env = base::android::AttachCurrentThread(); + ScopedJavaGlobalRef<jobject> j_tab_data; + j_tab_data.Reset(Java_ManualFillingComponentBridge_createAccessorySheetData( + env, static_cast<int>(tab_data.get_sheet_type()), + ConvertUTF16ToJavaString(env, tab_data.title()), + ConvertUTF16ToJavaString(env, tab_data.warning()))); + + if (tab_data.option_toggle().has_value()) { + const autofill::OptionToggle& toggle = tab_data.option_toggle().value(); + Java_ManualFillingComponentBridge_addOptionToggleToAccessorySheetData( + env, java_object, j_tab_data, + ConvertUTF16ToJavaString(env, toggle.display_text()), + toggle.is_enabled(), static_cast<int>(toggle.accessory_action())); + } + + for (const UserInfo& user_info : tab_data.user_info_list()) { + ScopedJavaLocalRef<jobject> j_user_info = + Java_ManualFillingComponentBridge_addUserInfoToAccessorySheetData( + env, java_object, j_tab_data, + ConvertUTF8ToJavaString(env, user_info.origin()), + user_info.is_exact_match().value(), + url::GURLAndroid::FromNativeGURL(env, user_info.icon_url())); + for (const AccessorySheetField& field : user_info.fields()) { + Java_ManualFillingComponentBridge_addFieldToUserInfo( + env, java_object, j_user_info, + static_cast<int>(tab_data.get_sheet_type()), + ConvertUTF16ToJavaString(env, field.display_text()), + ConvertUTF16ToJavaString(env, field.text_to_fill()), + ConvertUTF16ToJavaString(env, field.a11y_description()), + ConvertUTF8ToJavaString(env, field.id()), field.is_obfuscated(), + field.selectable()); + } + } + + for (const autofill::PromoCodeInfo& promo_code_info : + tab_data.promo_code_info_list()) { + const AccessorySheetField& promo_code = promo_code_info.promo_code(); + const std::u16string& detailsText = promo_code_info.details_text(); + Java_ManualFillingComponentBridge_addPromoCodeInfoToAccessorySheetData( + env, java_object, j_tab_data, + static_cast<int>(tab_data.get_sheet_type()), + ConvertUTF16ToJavaString(env, promo_code.display_text()), + ConvertUTF16ToJavaString(env, promo_code.text_to_fill()), + ConvertUTF16ToJavaString(env, promo_code.a11y_description()), + ConvertUTF8ToJavaString(env, promo_code.id()), + promo_code.is_obfuscated(), ConvertUTF16ToJavaString(env, detailsText)); + } + + for (const FooterCommand& footer_command : tab_data.footer_commands()) { + Java_ManualFillingComponentBridge_addFooterCommandToAccessorySheetData( + env, java_object, j_tab_data, + ConvertUTF16ToJavaString(env, footer_command.display_text()), + static_cast<int>(footer_command.accessory_action())); + } + return j_tab_data; +} + +} // namespace + ManualFillingViewAndroid::ManualFillingViewAndroid( ManualFillingController* controller, content::WebContents* web_contents) @@ -59,13 +153,23 @@ java_object_internal_.Reset(nullptr); } -void ManualFillingViewAndroid::OnItemsAvailable( - const AccessorySheetData& data) { +void ManualFillingViewAndroid::OnItemsAvailable(AccessorySheetData data) { TRACE_EVENT0("passwords", "ManualFillingViewAndroid::OnItemsAvailable"); if (auto obj = GetOrCreateJavaObject()) { - JNIEnv* env = base::android::AttachCurrentThread(); - Java_ManualFillingComponentBridge_onItemsAvailable( - env, obj, ConvertAccessorySheetDataToJavaObject(env, data)); + if (base::FeatureList::IsEnabled( + autofill::features::kAutofillKeyboardAccessory)) { + background_task_runner_->PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce(&ConvertAccessorySheetDataToJavaObject, obj, + std::move(data)), + base::BindOnce(&Java_ManualFillingComponentBridge_onItemsAvailable, + base::android::AttachCurrentThread(), obj)); + } else { + // Preserve legacy behavior for validation and to guard threading changes. + Java_ManualFillingComponentBridge_onItemsAvailable( + base::android::AttachCurrentThread(), obj, + ConvertAccessorySheetDataToJavaObject(obj, std::move(data))); + } } } @@ -162,87 +266,6 @@ java_object_internal_.Reset(nullptr); } -ScopedJavaLocalRef<jobject> -ManualFillingViewAndroid::ConvertAccessorySheetDataToJavaObject( - JNIEnv* env, - const AccessorySheetData& tab_data) { - TRACE_EVENT0( - "passwords", - "ManualFillingViewAndroid::ConvertAccessorySheetDataToJavaObject"); - DCHECK(java_object_internal_); - ScopedJavaLocalRef<jobject> j_tab_data = - Java_ManualFillingComponentBridge_createAccessorySheetData( - env, static_cast<int>(tab_data.get_sheet_type()), - ConvertUTF16ToJavaString(env, tab_data.title()), - ConvertUTF16ToJavaString(env, tab_data.warning())); - - if (tab_data.option_toggle().has_value()) { - autofill::OptionToggle toggle = tab_data.option_toggle().value(); - Java_ManualFillingComponentBridge_addOptionToggleToAccessorySheetData( - env, java_object_internal_, j_tab_data, - ConvertUTF16ToJavaString(env, toggle.display_text()), - toggle.is_enabled(), static_cast<int>(toggle.accessory_action())); - } - - for (const UserInfo& user_info : tab_data.user_info_list()) { - ScopedJavaLocalRef<jobject> j_user_info = - Java_ManualFillingComponentBridge_addUserInfoToAccessorySheetData( - env, java_object_internal_, j_tab_data, - ConvertUTF8ToJavaString(env, user_info.origin()), - user_info.is_exact_match().value(), - url::GURLAndroid::FromNativeGURL(env, user_info.icon_url())); - for (const AccessorySheetField& field : user_info.fields()) { - Java_ManualFillingComponentBridge_addFieldToUserInfo( - env, java_object_internal_, j_user_info, - static_cast<int>(tab_data.get_sheet_type()), - ConvertUTF16ToJavaString(env, field.display_text()), - ConvertUTF16ToJavaString(env, field.text_to_fill()), - ConvertUTF16ToJavaString(env, field.a11y_description()), - ConvertUTF8ToJavaString(env, field.id()), field.is_obfuscated(), - field.selectable()); - } - } - - for (const autofill::PromoCodeInfo& promo_code_info : - tab_data.promo_code_info_list()) { - const AccessorySheetField promo_code = promo_code_info.promo_code(); - const std::u16string detailsText = promo_code_info.details_text(); - Java_ManualFillingComponentBridge_addPromoCodeInfoToAccessorySheetData( - env, java_object_internal_, j_tab_data, - static_cast<int>(tab_data.get_sheet_type()), - ConvertUTF16ToJavaString(env, promo_code.display_text()), - ConvertUTF16ToJavaString(env, promo_code.text_to_fill()), - ConvertUTF16ToJavaString(env, promo_code.a11y_description()), - ConvertUTF8ToJavaString(env, promo_code.id()), - promo_code.is_obfuscated(), ConvertUTF16ToJavaString(env, detailsText)); - } - - for (const FooterCommand& footer_command : tab_data.footer_commands()) { - Java_ManualFillingComponentBridge_addFooterCommandToAccessorySheetData( - env, java_object_internal_, j_tab_data, - ConvertUTF16ToJavaString(env, footer_command.display_text()), - static_cast<int>(footer_command.accessory_action())); - } - return j_tab_data; -} - -AccessorySheetField ManualFillingViewAndroid::ConvertJavaUserInfoField( - JNIEnv* env, - const JavaRef<jobject>& j_field_to_convert) { - std::u16string display_text = ConvertJavaStringToUTF16( - env, Java_UserInfoField_getDisplayText(env, j_field_to_convert)); - std::u16string text_to_fill = ConvertJavaStringToUTF16( - env, Java_UserInfoField_getTextToFill(env, j_field_to_convert)); - std::u16string a11y_description = ConvertJavaStringToUTF16( - env, Java_UserInfoField_getA11yDescription(env, j_field_to_convert)); - std::string id = ConvertJavaStringToUTF8( - env, Java_UserInfoField_getId(env, j_field_to_convert)); - bool is_obfuscated = Java_UserInfoField_isObfuscated(env, j_field_to_convert); - bool selectable = Java_UserInfoField_isSelectable(env, j_field_to_convert); - return AccessorySheetField(display_text, text_to_fill, a11y_description, id, - is_obfuscated, selectable); -} - base::android::ScopedJavaGlobalRef<jobject> ManualFillingViewAndroid::GetOrCreateJavaObject() { if (java_object_internal_)
diff --git a/chrome/browser/ui/android/passwords/manual_filling_view_android.h b/chrome/browser/ui/android/passwords/manual_filling_view_android.h index 8a28ec0..0c156b0 100644 --- a/chrome/browser/ui/android/passwords/manual_filling_view_android.h +++ b/chrome/browser/ui/android/passwords/manual_filling_view_android.h
@@ -10,6 +10,7 @@ #include "base/android/scoped_java_ref.h" #include "base/callback_forward.h" #include "base/memory/raw_ptr.h" +#include "base/task/thread_pool.h" #include "chrome/browser/autofill/manual_filling_view_interface.h" #include "components/autofill/core/browser/ui/accessory_sheet_data.h" @@ -38,7 +39,7 @@ ~ManualFillingViewAndroid() override; // ManualFillingViewInterface: - void OnItemsAvailable(const autofill::AccessorySheetData& data) override; + void OnItemsAvailable(autofill::AccessorySheetData data) override; void OnAutomaticGenerationStatusChanged(bool available) override; void CloseAccessorySheet() override; void SwapSheetWithKeyboard() override; @@ -77,17 +78,12 @@ base::android::ScopedJavaGlobalRef<jobject> j_callback, const gfx::Image& image); - base::android::ScopedJavaLocalRef<jobject> - ConvertAccessorySheetDataToJavaObject( - JNIEnv* env, - const autofill::AccessorySheetData& tab_data); - - autofill::AccessorySheetField ConvertJavaUserInfoField( - JNIEnv* env, - const base::android::JavaRef<jobject>& j_field_to_convert); - base::android::ScopedJavaGlobalRef<jobject> GetOrCreateJavaObject(); + scoped_refptr<base::SequencedTaskRunner> background_task_runner_ = + base::ThreadPool::CreateSequencedTaskRunner( + {base::TaskPriority::BEST_EFFORT}); + // The controller provides data for this view and owns it. raw_ptr<ManualFillingController> controller_;
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/CaptureReadinessResult.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/CaptureReadinessResult.java index 08b006b..455a02b 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/CaptureReadinessResult.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/CaptureReadinessResult.java
@@ -6,6 +6,7 @@ import androidx.annotation.IntDef; +import org.chromium.base.TraceEvent; import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.browser.toolbar.top.ToolbarSnapshotState.ToolbarSnapshotDifference; @@ -21,7 +22,7 @@ class CaptureReadinessResult { /** * Reasons to allow toolbar captures. Treat this list as append only and keep it in sync with - * TopToolbarAllowCaptureReason in enums.xml. + * TopToolbarAllowCaptureReason in enums.xml, as well as the proto in chrome_track_event.proto. **/ @IntDef({TopToolbarAllowCaptureReason.UNKNOWN, TopToolbarAllowCaptureReason.FORCE_CAPTURE, TopToolbarAllowCaptureReason.SNAPSHOT_DIFFERENCE, @@ -36,7 +37,7 @@ /** * Reasons to block toolbar captures. Treat this list as append only and keep it in sync with - * TopToolbarBlockCaptureReason in enums.xml. + * TopToolbarBlockCaptureReason in enums.xml, as well as the proto in chrome_track_event.proto. **/ @IntDef({TopToolbarBlockCaptureReason.UNKNOWN, TopToolbarBlockCaptureReason.TOOLBAR_OR_RESULT_NULL, @@ -87,28 +88,42 @@ TopToolbarBlockCaptureReason.UNKNOWN, ToolbarSnapshotDifference.NONE); } - public static void logAllowCaptureReason(@TopToolbarAllowCaptureReason int reason) { + private static void logAllowCaptureReason(@TopToolbarAllowCaptureReason int reason) { RecordHistogram.recordEnumeratedHistogram("Android.TopToolbar.AllowCaptureReason", reason, TopToolbarAllowCaptureReason.NUM_ENTRIES); } - public static void logBlockCaptureReason(@TopToolbarBlockCaptureReason int reason) { + private static void logBlockCaptureReason(@TopToolbarBlockCaptureReason int reason) { RecordHistogram.recordEnumeratedHistogram("Android.TopToolbar.BlockCaptureReason", reason, TopToolbarBlockCaptureReason.NUM_ENTRIES); } public static void logCaptureReasonFromResult(CaptureReadinessResult result) { + // The Java -> C++ layer makes passing enums tricky so we store the integer value and then + // convert it to a proto enum on the C++ side. If we pass a -1 we will not set that + // corresponding field. + int blockReason = -1; + int allowReason = -1; + int snapshotDiff = -1; + + // Log the reason to UMA and update our trace event values. if (result == null) { - logBlockCaptureReason(TopToolbarBlockCaptureReason.TOOLBAR_OR_RESULT_NULL); + blockReason = TopToolbarBlockCaptureReason.TOOLBAR_OR_RESULT_NULL; + logBlockCaptureReason(blockReason); } else if (result.isReady) { - logAllowCaptureReason(result.allowReason); + allowReason = result.allowReason; + logAllowCaptureReason(allowReason); if (result.allowReason == TopToolbarAllowCaptureReason.SNAPSHOT_DIFFERENCE) { + snapshotDiff = result.snapshotDifference; RecordHistogram.recordEnumeratedHistogram("Android.TopToolbar.SnapshotDifference", - result.snapshotDifference, ToolbarSnapshotDifference.NUM_ENTRIES); + snapshotDiff, ToolbarSnapshotDifference.NUM_ENTRIES); } } else { - logBlockCaptureReason(result.blockReason); + blockReason = result.blockReason; + logBlockCaptureReason(blockReason); } + // Emit our trace event that will tell use why this capture occurred. + TraceEvent.instantAndroidToolbar(blockReason, allowReason, snapshotDiff); } public final boolean isReady;
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java index 1c27dccc..6ad32d2b8 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
@@ -255,8 +255,8 @@ @Override public boolean isDirty() { if (!super.isDirty()) { - CaptureReadinessResult.logBlockCaptureReason( - TopToolbarBlockCaptureReason.VIEW_NOT_DIRTY); + CaptureReadinessResult.logCaptureReasonFromResult(CaptureReadinessResult.notReady( + TopToolbarBlockCaptureReason.VIEW_NOT_DIRTY)); return false; } @@ -271,8 +271,9 @@ boolean isNativePage = tab == null || tab.isNativePage(); if (!isNativePage && mConstraintsObserver.areControlsLocked()) { mConstraintsObserver.scheduleRequestResourceOnUnlock(); - CaptureReadinessResult.logBlockCaptureReason( - TopToolbarBlockCaptureReason.BROWSER_CONTROLS_LOCKED); + CaptureReadinessResult.logCaptureReasonFromResult( + CaptureReadinessResult.notReady( + TopToolbarBlockCaptureReason.BROWSER_CONTROLS_LOCKED)); return false; } }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarSnapshotState.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarSnapshotState.java index 507cc71..f972fbf 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarSnapshotState.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarSnapshotState.java
@@ -25,7 +25,8 @@ class ToolbarSnapshotState { /** * Reasons that two snapshots are different. Treat this list as append only and keep it in sync - * with ToolbarSnapshotDifference in enums.xml. + * with ToolbarSnapshotDifference in enums.xml, as well as the proto in + * chrome_track_event.proto. **/ @IntDef({ToolbarSnapshotDifference.NONE, ToolbarSnapshotDifference.NULL, ToolbarSnapshotDifference.TINT, ToolbarSnapshotDifference.TAB_COUNT,
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc b/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc index 3470337f..26c0ace1 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc
@@ -9,6 +9,7 @@ #include "ash/components/arc/session/arc_bridge_service.h" #include "ash/components/arc/session/arc_service_manager.h" +#include "ash/constants/ash_features.h" #include "ash/public/cpp/holding_space/holding_space_constants.h" #include "ash/public/cpp/holding_space/holding_space_item.h" #include "ash/public/cpp/holding_space/holding_space_model.h" @@ -167,8 +168,10 @@ continue; holding_space_util::ValidityRequirement requirements; - if (item->type() != HoldingSpaceItem::Type::kPinnedFile) - requirements.must_be_newer_than = kMaxFileAge; + if (!features::IsHoldingSpacePredictabilityEnabled()) { + if (item->type() != HoldingSpaceItem::Type::kPinnedFile) + requirements.must_be_newer_than = kMaxFileAge; + } ScheduleFilePathValidityCheck({item->file_path(), requirements}); } } @@ -324,9 +327,10 @@ continue; holding_space_util::ValidityRequirement requirements; - if (item->type() != HoldingSpaceItem::Type::kPinnedFile) - requirements.must_be_newer_than = kMaxFileAge; - + if (!features::IsHoldingSpacePredictabilityEnabled()) { + if (item->type() != HoldingSpaceItem::Type::kPinnedFile) + requirements.must_be_newer_than = kMaxFileAge; + } ScheduleFilePathValidityCheck({item->file_path(), requirements}); } } @@ -369,8 +373,10 @@ continue; holding_space_util::ValidityRequirement requirements; - if (item->type() != HoldingSpaceItem::Type::kPinnedFile) - requirements.must_be_newer_than = kMaxFileAge; + if (!features::IsHoldingSpacePredictabilityEnabled()) { + if (item->type() != HoldingSpaceItem::Type::kPinnedFile) + requirements.must_be_newer_than = kMaxFileAge; + } ScheduleFilePathValidityCheck({item->file_path(), requirements}); } }
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 a147950..e763e32 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
@@ -7,6 +7,7 @@ #include <vector> #include "ash/components/arc/session/arc_service_manager.h" +#include "ash/constants/ash_features.h" #include "ash/public/cpp/holding_space/holding_space_constants.h" #include "ash/public/cpp/holding_space/holding_space_controller.h" #include "ash/public/cpp/holding_space/holding_space_controller_observer.h" @@ -497,7 +498,25 @@ arc::ArcServiceManager arc_service_manager_; }; -TEST_F(HoldingSpaceKeyedServiceTest, GuestUserProfile) { +class HoldingSpaceKeyedServiceWithPredictabilityFeatureTest + : public HoldingSpaceKeyedServiceTest, + public testing::WithParamInterface<bool> { + public: + HoldingSpaceKeyedServiceWithPredictabilityFeatureTest() { + scoped_feature_list_.InitWithFeatureState( + features::kHoldingSpacePredictability, GetParam()); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P(All, + HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + ::testing::Bool()); + +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + GuestUserProfile) { // Construct a guest session profile. TestingProfile::Builder guest_profile_builder; guest_profile_builder.SetGuestSession(); @@ -552,7 +571,8 @@ secondary_otr_guest_profile_service); } -TEST_F(HoldingSpaceKeyedServiceTest, OffTheRecordProfile) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + OffTheRecordProfile) { // Service instances should be created for on the record profiles. HoldingSpaceKeyedService* const primary_profile_service = HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(GetProfile()); @@ -575,7 +595,8 @@ ASSERT_FALSE(incognito_primary_profile_service); } -TEST_F(HoldingSpaceKeyedServiceTest, SecondaryUserProfile) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + SecondaryUserProfile) { HoldingSpaceKeyedService* const primary_holding_space_service = HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(GetProfile()); @@ -600,7 +621,8 @@ } // Verifies that updates to the holding space model are persisted. -TEST_F(HoldingSpaceKeyedServiceTest, UpdatePersistentStorage) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + UpdatePersistentStorage) { // Create a file system mount point. std::unique_ptr<ScopedTestMountPoint> downloads_mount = ScopedTestMountPoint::CreateAndMountDownloads(GetProfile()); @@ -652,7 +674,8 @@ // Verifies that only finalized holding space items are persisted and that, // once finalized, previously in progress holding space items are persisted at // the appropriate index. -TEST_F(HoldingSpaceKeyedServiceTest, PersistenceOfInProgressItems) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + PersistenceOfInProgressItems) { // Create a file system mount point. std::unique_ptr<ScopedTestMountPoint> downloads_mount = ScopedTestMountPoint::CreateAndMountDownloads(GetProfile()); @@ -779,7 +802,8 @@ // Verifies that when a file backing a holding space item is moved, the holding // space item is updated in place and persistence storage is updated. -TEST_F(HoldingSpaceKeyedServiceTest, UpdatePersistentStorageAfterMove) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + UpdatePersistentStorageAfterMove) { // Create a file system mount point. std::unique_ptr<ScopedTestMountPoint> downloads_mount = ScopedTestMountPoint::CreateAndMountDownloads(GetProfile()); @@ -905,7 +929,8 @@ // backing file is changed using move operation. Furthermore, verifies that // conflicts caused by moving a holding space item file to another path present // in the holding space get resolved. -TEST_F(HoldingSpaceKeyedServiceTest, UpdateItemsOverwrittenByMove) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + UpdateItemsOverwrittenByMove) { // Create a file system mount point. std::unique_ptr<ScopedTestMountPoint> downloads_mount = ScopedTestMountPoint::CreateAndMountDownloads(GetProfile()); @@ -1049,7 +1074,8 @@ // Verifies that the holding space model is restored from persistence. Note that // when restoring from persistence, existence of backing files is verified and // any stale holding space items are removed. -TEST_F(HoldingSpaceKeyedServiceTest, RestorePersistentStorage) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + RestorePersistentStorage) { // Verify expected histograms. base::HistogramTester histogram_tester; histogram_tester.ExpectTotalCount("HoldingSpace.Item.TotalCount.All", 0); @@ -1167,7 +1193,7 @@ // Verifies that items from volumes that are not immediately mounted during // startup get restored into the holding space. -TEST_F(HoldingSpaceKeyedServiceTest, +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, RestorePersistentStorageForDelayedVolumeMount) { // Create file system mount point. std::unique_ptr<ScopedTestMountPoint> downloads_mount = @@ -1324,7 +1350,7 @@ // startup get restored into the holding space - same as // RestorePersistentStorageForDelayedVolumeMount, but the volume gets mounted // while item restoration is in progress. -TEST_F(HoldingSpaceKeyedServiceTest, +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, RestorePersistentStorageForDelayedVolumeMountDuringRestoration) { // Create file system mount point. std::unique_ptr<ScopedTestMountPoint> downloads_mount = @@ -1449,7 +1475,7 @@ // Verifies that mounting volumes that contain no holding space items does not // interfere with holding space restoration. -TEST_F(HoldingSpaceKeyedServiceTest, +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, RestorePersistentStorageWithUnrelatedVolumeMounts) { // Create file system mount point. std::unique_ptr<ScopedTestMountPoint> downloads_mount = @@ -1567,7 +1593,8 @@ } // Tests that items from an unmounted volume get removed from the holding space. -TEST_F(HoldingSpaceKeyedServiceTest, RemoveItemsFromUnmountedVolumes) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + RemoveItemsFromUnmountedVolumes) { auto test_mount_1 = std::make_unique<ScopedTestMountPoint>( "test_mount_1", storage::kFileSystemTypeLocal, file_manager::VOLUME_TYPE_TESTING); @@ -1613,8 +1640,11 @@ } // Verifies that files restored from persistence are not older than -// `kMaxFileAge`. -TEST_F(HoldingSpaceKeyedServiceTest, RemoveOlderFilesFromPersistence) { +// `kMaxFileAge`, when the predictability feature is off. +// Verifies that files restored from persistence are restored, regardless of +// `kMaxFileAge`, when the predictability feature is on. +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + RemoveOlderFilesFromPersistence) { // Create file system mount point. std::unique_ptr<ScopedTestMountPoint> downloads_mount = ScopedTestMountPoint::CreateAndMountDownloads(GetProfile()); @@ -1651,7 +1681,8 @@ // expect all holding space items of other types to be removed from // persistence during restoration due to being older than // `kMaxFileAge`. - if (type == HoldingSpaceItem::Type::kPinnedFile) { + if (features::IsHoldingSpacePredictabilityEnabled() || + type == HoldingSpaceItem::Type::kPinnedFile) { persisted_holding_space_items_after_restoration.Append( fresh_holding_space_item->Serialize()); restored_holding_space_items.push_back( @@ -1707,7 +1738,8 @@ persisted_holding_space_items_after_restoration); } -TEST_F(HoldingSpaceKeyedServiceTest, AddArcDownloadItem) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + AddArcDownloadItem) { // Wait for the holding space model to attach. TestingProfile* profile = GetProfile(); HoldingSpaceModelAttachedWaiter(profile).Wait(); @@ -1743,7 +1775,8 @@ base::FilePath("Download.png"))); } -TEST_F(HoldingSpaceKeyedServiceTest, AddInProgressDownloadItem) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + AddInProgressDownloadItem) { // Wait for the holding space model to attach. TestingProfile* profile = GetProfile(); HoldingSpaceModelAttachedWaiter(profile).Wait(); @@ -2010,7 +2043,7 @@ EXPECT_TRUE(BitmapsAreEqual(actual_image, expected_image)); } -TEST_F(HoldingSpaceKeyedServiceTest, RemoveAll) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, RemoveAll) { // Wait for the holding space model to attach. TestingProfile* profile = GetProfile(); HoldingSpaceModelAttachedWaiter(profile).Wait(); @@ -2046,7 +2079,8 @@ EXPECT_EQ(0u, model->items().size()); } -TEST_F(HoldingSpaceKeyedServiceTest, CreateInterruptedDownloadItem) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + CreateInterruptedDownloadItem) { // Wait for the holding space model to attach. TestingProfile* profile = GetProfile(); HoldingSpaceModelAttachedWaiter(profile).Wait(); @@ -2121,7 +2155,8 @@ EXPECT_TRUE(model->items()[0]->progress().IsComplete()); } -TEST_F(HoldingSpaceKeyedServiceTest, InterruptAndResumeDownload) { +TEST_P(HoldingSpaceKeyedServiceWithPredictabilityFeatureTest, + InterruptAndResumeDownload) { // Wait for the holding space model to attach. TestingProfile* profile = GetProfile(); HoldingSpaceModelAttachedWaiter(profile).Wait();
diff --git a/chrome/browser/ui/signin_view_controller.h b/chrome/browser/ui/signin_view_controller.h index f0845fc..d766cebf 100644 --- a/chrome/browser/ui/signin_view_controller.h +++ b/chrome/browser/ui/signin_view_controller.h
@@ -183,6 +183,8 @@ EnterpriseConfirmationDefaultFocus); FRIEND_TEST_ALL_PREFIXES(SigninViewControllerDelegateViewsBrowserTest, CloseImmediately); + FRIEND_TEST_ALL_PREFIXES(ProfilePickerLocalProfileCreationDialogBrowserTest, + CreateLocalProfile); friend class login_ui_test_utils::SigninViewControllerTestUtil; friend class SigninReauthViewControllerBrowserTest; friend class SigninInterceptFirstRunExperienceDialogBrowserTest;
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index 11ba97e..01ac958 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -154,6 +154,8 @@ #include "chrome/browser/android/policy/policy_auditor_bridge.h" #include "chrome/browser/banners/android/chrome_app_banner_manager_android.h" #include "chrome/browser/content_settings/request_desktop_site_web_contents_observer_android.h" +#include "chrome/browser/fast_checkout/fast_checkout_features.h" +#include "chrome/browser/fast_checkout/fast_checkout_tab_helper.h" #include "chrome/browser/flags/android/chrome_feature_list.h" #include "chrome/browser/plugins/plugin_observer_android.h" #include "chrome/browser/ui/android/context_menu_helper.h" @@ -467,6 +469,9 @@ webapps::ChromeAppBannerManagerAndroid::CreateForWebContents(web_contents); } ContextMenuHelper::CreateForWebContents(web_contents); + if (base::FeatureList::IsEnabled(features::kFastCheckout)) { + FastCheckoutTabHelper::CreateForWebContents(web_contents); + } javascript_dialogs::TabModalDialogManager::CreateForWebContents( web_contents, std::make_unique<JavaScriptTabModalDialogManagerDelegateAndroid>(
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc index d0607e01..e5ae7c26 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
@@ -27,6 +27,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/test_future.h" #include "base/time/time.h" +#include "base/values.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/browser_process.h" @@ -43,6 +44,7 @@ #include "chrome/browser/signin/chrome_signin_client_test_util.h" #include "chrome/browser/signin/dice_tab_helper.h" #include "chrome/browser/signin/identity_manager_factory.h" +#include "chrome/browser/signin/signin_features.h" #include "chrome/browser/sync/sync_encryption_keys_tab_helper.h" #include "chrome/browser/sync/sync_service_factory.h" #include "chrome/browser/themes/theme_service.h" @@ -62,6 +64,8 @@ #include "chrome/browser/ui/webui/signin/login_ui_service.h" #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" #include "chrome/browser/ui/webui/signin/login_ui_test_utils.h" +#include "chrome/browser/ui/webui/signin/profile_customization_handler.h" +#include "chrome/browser/ui/webui/signin/profile_customization_ui.h" #include "chrome/browser/ui/webui/signin/profile_picker_handler.h" #include "chrome/browser/ui/webui/signin/profile_picker_ui.h" #include "chrome/browser/ui/webui/signin/signin_url_utils.h" @@ -92,6 +96,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/test_navigation_observer.h" #include "extensions/common/extension_id.h" #include "google_apis/gaia/gaia_urls.h" #include "services/network/test/test_url_loader_factory.h" @@ -347,8 +352,14 @@ class ProfilePickerCreationFlowBrowserTest : public ProfilePickerTestBase { public: - ProfilePickerCreationFlowBrowserTest() - : feature_list_(feature_engagement::kIPHProfileSwitchFeature) { + explicit ProfilePickerCreationFlowBrowserTest( + bool local_profile_creation_dialog_enabled) { + std::vector<base::Feature> enabled_features = { + feature_engagement::kIPHProfileSwitchFeature}; + if (local_profile_creation_dialog_enabled) { + enabled_features.push_back(kSyncPromoAfterSigninIntercept); + } + feature_list_.InitWithFeatures(enabled_features, /*disabled_features=*/{}); #if BUILDFLAG(IS_MAC) // Ensure the platform is unmanaged platform_management_ = @@ -358,6 +369,10 @@ #endif } + ProfilePickerCreationFlowBrowserTest() + : ProfilePickerCreationFlowBrowserTest( + /*local_profile_creation_dialog_enabled=*/false) {} + void SetUpInProcessBrowserTestFixture() override { ProfilePickerTestBase::SetUpInProcessBrowserTestFixture(); create_services_subscription_ = @@ -1865,6 +1880,88 @@ ForceEphemeralProfilesPolicy::kDisabled, ForceEphemeralProfilesPolicy::kEnabled)); +class ProfilePickerLocalProfileCreationDialogBrowserTest + : public ProfilePickerCreationFlowBrowserTest { + public: + ProfilePickerLocalProfileCreationDialogBrowserTest() + : ProfilePickerCreationFlowBrowserTest( + /*local_profile_creation_dialog_enabled=*/true) {} + + // Simulates a click on "Continue without an account" to create a local + // profile and open the profile customization dialog. + void CreateLocalProfile() { + base::Value::List args; + args.Append(base::Value()); + profile_picker_handler()->HandleCreateProfileAndOpenCustomizationDialog( + args); + } + + // Simulates a click on "Done" on the Profile Customization to confirm the + // creation of the local profile. + void ConfirmLocalProfileCreation(content::WebContents* dialog_web_contents) { + base::Value::List args; + args.Append(base::Value(kProfileName)); + dialog_web_contents->GetWebUI() + ->GetController() + ->GetAs<ProfileCustomizationUI>() + ->GetProfileCustomizationHandlerForTesting() + ->HandleDone(args); + } + + protected: + const GURL kProfileCustomizationUrl = AppendProfileCustomizationQueryParams( + GURL("chrome://profile-customization"), + ProfileCustomizationStyle::kLocalProfileCreation); + const std::string kProfileName = "Test"; +}; + +IN_PROC_BROWSER_TEST_F(ProfilePickerLocalProfileCreationDialogBrowserTest, + CreateLocalProfile) { + ASSERT_EQ(1u, BrowserList::GetInstance()->size()); + ASSERT_EQ(1u, g_browser_process->profile_manager() + ->GetProfileAttributesStorage() + .GetNumberOfProfiles()); + + content::TestNavigationObserver profile_customization_observer( + kProfileCustomizationUrl); + profile_customization_observer.StartWatchingNewWebContents(); + BrowserAddedWaiter waiter = BrowserAddedWaiter(2u); + + ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint( + ProfilePicker::EntryPoint::kProfileMenuAddNewProfile)); + // Wait until webUI is fully initialized. + WaitForLoadStop(GURL("chrome://profile-picker/new-profile")); + + // Simulate clicking the "Continue without an account" button. + CreateLocalProfile(); + + Browser* new_browser = waiter.Wait(); + profile_customization_observer.Wait(); + content::WebContents* dialog_web_contents = + new_browser->signin_view_controller() + ->GetModalDialogWebContentsForTesting(); + EXPECT_EQ(dialog_web_contents->GetLastCommittedURL(), + kProfileCustomizationUrl); + + ProfileAttributesEntry* entry = + g_browser_process->profile_manager() + ->GetProfileAttributesStorage() + .GetProfileAttributesWithPath(new_browser->profile()->GetPath()); + ASSERT_TRUE(entry->IsEphemeral()); + EXPECT_FALSE(ProfilePicker::IsOpen()); + EXPECT_TRUE(new_browser->signin_view_controller()->ShowsModalDialog()); + + // Simulate clicking the "Done" button on the profile customization dialog. + ConfirmLocalProfileCreation(dialog_web_contents); + + ASSERT_FALSE(entry->IsEphemeral()); + ASSERT_EQ(kProfileName, base::UTF16ToUTF8(entry->GetLocalProfileName())); + ASSERT_EQ(2u, g_browser_process->profile_manager() + ->GetProfileAttributesStorage() + .GetNumberOfProfiles()); + EXPECT_FALSE(new_browser->signin_view_controller()->ShowsModalDialog()); +} + #if BUILDFLAG(IS_CHROMEOS_LACROS) class ProfilePickerLacrosFirstRunBrowserTestBase
diff --git a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.cc b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.cc index 27a99d7..430cce7 100644 --- a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.cc +++ b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog.cc
@@ -9,12 +9,14 @@ #include "chrome/browser/favicon/favicon_service_factory.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/collected_cookies_infobar_delegate.h" #include "chrome/browser/ui/views/site_data/page_specific_site_data_dialog_controller.h" #include "chrome/browser/ui/views/site_data/site_data_row_view.h" #include "chrome/grit/generated_resources.h" #include "components/constrained_window/constrained_window_views.h" #include "components/content_settings/browser/page_specific_content_settings.h" #include "components/content_settings/core/browser/cookie_settings.h" +#include "components/infobars/content/content_infobar_manager.h" #include "components/omnibox/browser/favicon_cache.h" #include "components/strings/grit/components_strings.h" #include "content/public/browser/web_contents.h" @@ -137,14 +139,29 @@ } void OnDialogExplicitlyClosed() { + // If the user closes our parent tab while we're still open, this method + // will (eventually) be called in response to a WebContentsDestroyed() call + // from the WebContentsImpl to its observers. But since the + // infobars::ContentInfoBarManager is also torn down in response to + // WebContentsDestroyed(), it may already be null. Since the tab is going + // away anyway, we can just omit showing an infobar, which prevents any + // attempt to access a null infobars::ContentInfoBarManager. Same applies to + // removing the webcontents' user data. + if (!web_contents_ || web_contents_->IsBeingDestroyed()) + return; + + if (status_changed_) { + CollectedCookiesInfoBarDelegate::Create( + infobars::ContentInfoBarManager::FromWebContents( + web_contents_.get())); + } + // Reset the dialog reference in the user data. If the dialog is opened // again, a new instance should be created. When the dialog is destroyed // because of the web contents being destroyed, no need to remove the user // data because it will be destroyed. - if (web_contents_) { - web_contents_->RemoveUserData( - PageSpecificSiteDataDialogController::UserDataKey()); - } + web_contents_->RemoveUserData( + PageSpecificSiteDataDialogController::UserDataKey()); } std::vector<PageSpecificSiteDataDialogSite> GetAllSites() { @@ -173,6 +190,7 @@ void DeleteStoredObjects(const url::Origin& origin) { // TODO(crbug.com/1344787): Record metrics. + status_changed_ = true; DCHECK(DeleteMatchingHostNodeFromModel(allowed_cookies_tree_model_.get(), origin)) << "The node with a matching origin should be found and deleted in the " @@ -181,6 +199,7 @@ void SetContentException(const url::Origin& origin, ContentSetting setting) { // TODO(crbug.com/1344787): Record metrics. + status_changed_ = true; DCHECK(setting == CONTENT_SETTING_ALLOW || setting == CONTENT_SETTING_BLOCK || setting == CONTENT_SETTING_SESSION_ONLY); @@ -237,6 +256,10 @@ std::unique_ptr<CookiesTreeModel> blocked_cookies_tree_model_; std::unique_ptr<FaviconCache> favicon_cache_; scoped_refptr<content_settings::CookieSettings> cookie_settings_; + + // Whether user has done any changes to the site data, deleted site data for a + // site or created a content setting exception for a site. + bool status_changed_ = false; }; } // namespace
diff --git a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_browsertest.cc b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_browsertest.cc index 1fd75e7..f014972e 100644 --- a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_browsertest.cc +++ b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_browsertest.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/ui/views/site_data/site_data_row_view.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/infobars/content/content_infobar_manager.h" #include "components/page_info/core/features.h" #include "content/public/test/browser_test.h" #include "net/dns/mock_host_resolver.h" @@ -91,6 +92,15 @@ row_view->OnClearOnExitMenuItemClicked(/*event_flags*/ 0); } + size_t infobar_count() const { + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + return web_contents + ? infobars::ContentInfoBarManager::FromWebContents(web_contents) + ->infobar_count() + : 0; + } + private: base::test::ScopedFeatureList feature_list_; }; @@ -106,6 +116,8 @@ dialog->Close(); EXPECT_TRUE(dialog->IsClosed()); + + EXPECT_EQ(0u, infobar_count()); } IN_PROC_BROWSER_TEST_P(PageSpecificSiteDataDialogBrowserTest, @@ -132,13 +144,29 @@ EXPECT_TRUE(dialog->IsClosed()); } -IN_PROC_BROWSER_TEST_P(PageSpecificSiteDataDialogBrowserTest, CloseTab) { +IN_PROC_BROWSER_TEST_P(PageSpecificSiteDataDialogBrowserTest, + ChangeAndCloseTab) { + if (!GetParam()) { + return; + } + // Test closing tab while the dialog is open. // Closing the owning tab will close dialog. auto* dialog = OpenDialog(); + ui::ElementContext context = + views::ElementTrackerViews::GetContextForWidget(dialog); + + auto* view = + GetViewByIdentifier(context, kPageSpecificSiteDataDialogRowForTesting); + auto* row_view = static_cast<SiteDataRowView*>(view); + EXPECT_TRUE(row_view->GetVisible()); + ClickDeleteMenuItem(row_view); + EXPECT_FALSE(row_view->GetVisible()); + browser()->tab_strip_model()->GetActiveWebContents()->Close(); EXPECT_TRUE(dialog->IsClosed()); + EXPECT_EQ(0u, infobar_count()); } // Closing the widget asynchronously destroys the CollectedCookiesViews object, @@ -196,6 +224,9 @@ EXPECT_TRUE(row_view->state_label_for_testing()->GetVisible()); EXPECT_EQ(row_view->state_label_for_testing()->GetText(), u"Blocked"); // TODO(crbug.com/1344787): Check the histograms value. + + dialog->Close(); + EXPECT_EQ(1u, infobar_count()); } IN_PROC_BROWSER_TEST_P(PageSpecificSiteDataDialogBrowserTest, AllowMenuItem) { @@ -220,6 +251,9 @@ EXPECT_TRUE(row_view->state_label_for_testing()->GetVisible()); EXPECT_EQ(row_view->state_label_for_testing()->GetText(), u"Allowed"); // TODO(crbug.com/1344787): Check the histograms value. + + dialog->Close(); + EXPECT_EQ(1u, infobar_count()); } IN_PROC_BROWSER_TEST_P(PageSpecificSiteDataDialogBrowserTest, @@ -241,6 +275,9 @@ EXPECT_TRUE(row_view->state_label_for_testing()->GetVisible()); EXPECT_EQ(row_view->state_label_for_testing()->GetText(), u"Clear on close"); // TODO(crbug.com/1344787): Check the histograms value. + + dialog->Close(); + EXPECT_EQ(1u, infobar_count()); } // Run tests with kPageSpecificSiteDataDialog flag enabled and disabled.
diff --git a/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.cc index 849dbdb..7db7c27 100644 --- a/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.cc
@@ -34,6 +34,10 @@ CallExternalAPI("setFigures", ToValue(shape_list)); } +void QuickStartScreenHandler::SetQRCode(base::Value::List blob) { + CallExternalAPI("setQRCode", std::move(blob)); +} + void QuickStartScreenHandler::DeclareLocalizedValues( ::login::LocalizedValuesBuilder* builder) {}
diff --git a/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.h index 8f54338a..0d5f06c 100644 --- a/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_QUICK_START_SCREEN_HANDLER_H_ #include "base/memory/weak_ptr.h" +#include "base/values.h" #include "chrome/browser/ash/login/oobe_quick_start/verification_shapes.h" #include "chrome/browser/ash/login/oobe_screen.h" #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h" @@ -25,6 +26,7 @@ virtual void Show() = 0; virtual void SetShapes(const ash::quick_start::ShapeList& shape_list) = 0; + virtual void SetQRCode(base::Value::List blob) = 0; }; // WebUI implementation of QuickStartView. @@ -43,6 +45,7 @@ // QuickStartView: void Show() override; void SetShapes(const ash::quick_start::ShapeList& shape_list) override; + void SetQRCode(base::Value::List blob) override; // BaseScreenHandler: void DeclareLocalizedValues(
diff --git a/chrome/browser/ui/webui/settings/ash/privacy_hub_handler.cc b/chrome/browser/ui/webui/settings/ash/privacy_hub_handler.cc index 6c7ac3c..0403043 100644 --- a/chrome/browser/ui/webui/settings/ash/privacy_hub_handler.cc +++ b/chrome/browser/ui/webui/settings/ash/privacy_hub_handler.cc
@@ -5,9 +5,13 @@ #include "chrome/browser/ui/webui/settings/ash/privacy_hub_handler.h" #include "base/bind.h" +#include "base/logging.h" +#include "chrome/browser/ash/privacy_hub/privacy_hub_util.h" + +namespace chromeos::settings { namespace { - +// Translates CameraPrivacySwitch state into base::Value base::Value CameraPrivacySwitchStateToBaseValue( cros::mojom::CameraPrivacySwitchState state) { switch (state) { @@ -22,23 +26,14 @@ } // namespace -namespace chromeos::settings { - -PrivacyHubHandler::PrivacyHubHandler() - : camera_privacy_switch_state_(media::CameraHalDispatcherImpl::GetInstance() - ->AddCameraPrivacySwitchObserver(this)) { - ui::MicrophoneMuteSwitchMonitor::Get()->AddObserver(this); - CrasAudioHandler::Get()->AddAudioObserver(this); -} +PrivacyHubHandler::PrivacyHubHandler() = default; PrivacyHubHandler::~PrivacyHubHandler() { - media::CameraHalDispatcherImpl::GetInstance() - ->RemoveCameraPrivacySwitchObserver(this); - ui::MicrophoneMuteSwitchMonitor::Get()->RemoveObserver(this); - CrasAudioHandler::Get()->RemoveAudioObserver(this); + ash::privacy_hub_util::SetFrontend(nullptr); } void PrivacyHubHandler::RegisterMessages() { + ash::privacy_hub_util::SetFrontend(this); web_ui()->RegisterMessageCallback( "getInitialCameraHardwareToggleState", base::BindRepeating(&PrivacyHubHandler::HandleInitialCameraSwitchState, @@ -56,37 +51,13 @@ base::Unretained(this))); } -void PrivacyHubHandler::OnAudioNodesChanged() { +void PrivacyHubHandler::NotifyJS(const std::string& event_name, + const base::Value& value) { if (IsJavascriptAllowed()) { - FireWebUIListener( - "availability-of-microphone-for-simple-usage-changed", - base::Value( - CrasAudioHandler::Get()->HasActiveInputDeviceForSimpleUsage())); + FireWebUIListener(event_name, value); } else { - DVLOG(1) << "JS disabled. Skip updating the availability of microphone for " - "simple usage until enabled"; - } -} - -void PrivacyHubHandler::OnCameraHWPrivacySwitchStatusChanged( - int32_t camera_id, - cros::mojom::CameraPrivacySwitchState state) { - camera_privacy_switch_state_ = state; - if (IsJavascriptAllowed()) { - const base::Value value = - CameraPrivacySwitchStateToBaseValue(camera_privacy_switch_state_); - FireWebUIListener("camera-hardware-toggle-changed", value); - } else { - DVLOG(1) << "JS disabled. Skip camera privacy switch update until enabled"; - } -} - -void PrivacyHubHandler::OnMicrophoneMuteSwitchValueChanged(bool muted) { - if (IsJavascriptAllowed()) { - FireWebUIListener("microphone-hardware-toggle-changed", base::Value(muted)); - } else { - DVLOG(1) << "JS disabled. Skip microphone hardware privacy switch update " - "until enabled"; + DVLOG(1) << "JS disabled. Skip \"" << event_name + << "\" event until enabled."; } } @@ -97,8 +68,8 @@ DCHECK_GE(1U, args.size()) << ": Did not expect arguments"; DCHECK_EQ(1U, args.size()) << ": Callback ID is required"; const auto& callback_id = args[0]; - const base::Value value = - CameraPrivacySwitchStateToBaseValue(camera_privacy_switch_state_); + const base::Value value = CameraPrivacySwitchStateToBaseValue( + ash::privacy_hub_util::CameraHWSwitchState()); ResolveJavascriptCallback(callback_id, value); } @@ -110,8 +81,8 @@ DCHECK_GE(1U, args.size()) << ": Did not expect arguments"; DCHECK_EQ(1U, args.size()) << ": Callback ID is required"; const auto& callback_id = args[0]; - const base::Value value = base::Value( - ui::MicrophoneMuteSwitchMonitor::Get()->microphone_mute_switch_on()); + const base::Value value = + base::Value(ash::privacy_hub_util::MicrophoneSwitchState()); ResolveJavascriptCallback(callback_id, value); } @@ -123,10 +94,27 @@ DCHECK_GE(1U, args.size()) << ": Did not expect arguments"; DCHECK_EQ(1U, args.size()) << ": Callback ID is required"; const auto& callback_id = args[0]; - const base::Value value = base::Value( - CrasAudioHandler::Get()->HasActiveInputDeviceForSimpleUsage()); + + const base::Value value = + base::Value(ash::privacy_hub_util::HasActiveInputDeviceForSimpleUsage()); ResolveJavascriptCallback(callback_id, value); } +void PrivacyHubHandler::AvailabilityOfMicrophoneChanged( + bool has_active_input_device) { + NotifyJS("availability-of-microphone-for-simple-usage-changed", + base::Value(has_active_input_device)); +} + +void PrivacyHubHandler::MicrophoneHardwareToggleChanged(bool muted) { + NotifyJS("microphone-hardware-toggle-changed", base::Value(muted)); +} + +void PrivacyHubHandler::CameraHardwareToggleChanged( + cros::mojom::CameraPrivacySwitchState state) { + NotifyJS("camera-hardware-toggle-changed", + CameraPrivacySwitchStateToBaseValue(state)); +} + } // namespace chromeos::settings
diff --git a/chrome/browser/ui/webui/settings/ash/privacy_hub_handler.h b/chrome/browser/ui/webui/settings/ash/privacy_hub_handler.h index 711c892..f894b13 100644 --- a/chrome/browser/ui/webui/settings/ash/privacy_hub_handler.h +++ b/chrome/browser/ui/webui/settings/ash/privacy_hub_handler.h
@@ -5,17 +5,17 @@ #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_PRIVACY_HUB_HANDLER_H_ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_PRIVACY_HUB_HANDLER_H_ -#include "chromeos/ash/components/audio/cras_audio_handler.h" +#include <string> + +#include "ash/public/cpp/privacy_hub_delegate.h" +#include "base/values.h" #include "content/public/browser/web_ui_message_handler.h" -#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" -#include "ui/events/devices/microphone_mute_switch_monitor.h" +#include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h" namespace chromeos::settings { class PrivacyHubHandler : public content::WebUIMessageHandler, - public media::CameraPrivacySwitchObserver, - public ui::MicrophoneMuteSwitchMonitor::Observer, - public CrasAudioHandler::AudioObserver { + public ash::PrivacyHubDelegate { public: PrivacyHubHandler(); ~PrivacyHubHandler() override; @@ -24,20 +24,19 @@ PrivacyHubHandler& operator=(const PrivacyHubHandler&) = delete; + // ash::PrivacyHubDelegate + void AvailabilityOfMicrophoneChanged(bool has_active_Input_device) override; + + void MicrophoneHardwareToggleChanged(bool muted) override; + + void CameraHardwareToggleChanged( + cros::mojom::CameraPrivacySwitchState state) override; + protected: // content::WebUIMessageHandler void RegisterMessages() override; - // CrasAudioHandler::AudioObserver overrides - void OnAudioNodesChanged() override; - - // media::CameraPrivacySwitchObserver - void OnCameraHWPrivacySwitchStatusChanged( - int32_t camera_id, - cros::mojom::CameraPrivacySwitchState state) override; - - // ui::MicrophoneMuteSwitchMonitor::Observer - void OnMicrophoneMuteSwitchValueChanged(bool muted) override; + void NotifyJS(const std::string& event_name, const base::Value& value); void HandleInitialCameraSwitchState(const base::Value::List& args); @@ -45,9 +44,6 @@ void HandleInitialAvailabilityOfMicrophoneForSimpleUsage( const base::Value::List& args); - - private: - cros::mojom::CameraPrivacySwitchState camera_privacy_switch_state_; }; } // namespace chromeos::settings
diff --git a/chrome/browser/ui/webui/settings/ash/privacy_hub_handler_unittest.cc b/chrome/browser/ui/webui/settings/ash/privacy_hub_handler_unittest.cc index 90075cb..ddcd60c 100644 --- a/chrome/browser/ui/webui/settings/ash/privacy_hub_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/ash/privacy_hub_handler_unittest.cc
@@ -8,6 +8,7 @@ #include "base/test/task_environment.h" #include "chromeos/ash/components/audio/cras_audio_handler.h" #include "content/public/test/test_web_ui.h" +#include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h" #include "testing/gtest/include/gtest/gtest.h" namespace chromeos::settings { @@ -20,8 +21,6 @@ using PrivacyHubHandler::HandleInitialAvailabilityOfMicrophoneForSimpleUsage; using PrivacyHubHandler::HandleInitialCameraSwitchState; using PrivacyHubHandler::HandleInitialMicrophoneSwitchState; - using PrivacyHubHandler::OnAudioNodesChanged; - using PrivacyHubHandler::OnCameraHWPrivacySwitchStatusChanged; }; using cps = cros::mojom::CameraPrivacySwitchState; @@ -129,9 +128,8 @@ } }; -TEST_P(PrivacyHubHandlerCameraTest, CameraHardwarePrivacySwitchChanged) { - privacy_hub_handler_.OnCameraHWPrivacySwitchStatusChanged(/*camera_id=*/0, - GetParam()); +TEST_P(PrivacyHubHandlerCameraTest, CameraHardwareToggleChanged) { + privacy_hub_handler_.CameraHardwareToggleChanged(GetParam()); const base::Value data = GetLastWebUIListenerData("camera-hardware-toggle-changed"); @@ -158,7 +156,7 @@ TEST_P(PrivacyHubHandlerMicrophoneTest, MicrophoneHardwarePrivacySwitchChanged) { - SetParamValueMicrophoneMute(); + privacy_hub_handler_.MicrophoneHardwareToggleChanged(GetParam()); const base::Value data = GetLastWebUIListenerData("microphone-hardware-toggle-changed"); @@ -179,13 +177,25 @@ ExpectValueMatchesBoolParam(data); } -TEST_F(PrivacyHubHandlerMicrophoneTest, OnAudioNodesChanged) { - privacy_hub_handler_.OnAudioNodesChanged(); +TEST_F(PrivacyHubHandlerMicrophoneTest, + HandleInitialAvailabilityOfSimpleMicrophone) { + base::Value::List args; + args.Append(this_test_name_); + + privacy_hub_handler_.HandleInitialAvailabilityOfMicrophoneForSimpleUsage( + args); + + const base::Value data = GetLastWebUIResponse(this_test_name_); + EXPECT_FALSE(data.is_none()); +} + +TEST_P(PrivacyHubHandlerMicrophoneTest, AvailabilityOfMicrophoneChanged) { + privacy_hub_handler_.AvailabilityOfMicrophoneChanged(GetParam()); const base::Value data = GetLastWebUIListenerData( "availability-of-microphone-for-simple-usage-changed"); - EXPECT_FALSE(data.is_none()); + ExpectValueMatchesBoolParam(data); } INSTANTIATE_TEST_SUITE_P(HardwareSwitchStates,
diff --git a/chrome/browser/ui/webui/signin/profile_customization_handler.h b/chrome/browser/ui/webui/signin/profile_customization_handler.h index ba9e8bd..cfbd4eb 100644 --- a/chrome/browser/ui/webui/signin/profile_customization_handler.h +++ b/chrome/browser/ui/webui/signin/profile_customization_handler.h
@@ -52,6 +52,8 @@ const std::u16string& old_profile_name) override; private: + friend class ProfilePickerLocalProfileCreationDialogBrowserTest; + // Handlers for messages from javascript. void HandleInitialized(const base::Value::List& args); void HandleGetAvailableIcons(const base::Value::List& args);
diff --git a/chrome/browser/ui/webui/signin/profile_customization_ui.cc b/chrome/browser/ui/webui/signin/profile_customization_ui.cc index 5ea8c6f..f79b47f 100644 --- a/chrome/browser/ui/webui/signin/profile_customization_ui.cc +++ b/chrome/browser/ui/webui/signin/profile_customization_ui.cc
@@ -120,8 +120,11 @@ void ProfileCustomizationUI::Initialize( base::OnceCallback<void(ProfileCustomizationHandler::CustomizationResult)> completion_callback) { - web_ui()->AddMessageHandler(std::make_unique<ProfileCustomizationHandler>( - Profile::FromWebUI(web_ui()), std::move(completion_callback))); + std::unique_ptr<ProfileCustomizationHandler> handler = + std::make_unique<ProfileCustomizationHandler>( + Profile::FromWebUI(web_ui()), std::move(completion_callback)); + profile_customization_handler_ = handler.get(); + web_ui()->AddMessageHandler(std::move(handler)); } void ProfileCustomizationUI::BindInterface( @@ -133,6 +136,11 @@ customize_themes_factory_receiver_.Bind(std::move(pending_receiver)); } +ProfileCustomizationHandler* +ProfileCustomizationUI::GetProfileCustomizationHandlerForTesting() { + return profile_customization_handler_; +} + void ProfileCustomizationUI::CreateCustomizeThemesHandler( mojo::PendingRemote<customize_themes::mojom::CustomizeThemesClient> pending_client,
diff --git a/chrome/browser/ui/webui/signin/profile_customization_ui.h b/chrome/browser/ui/webui/signin/profile_customization_ui.h index f004809..ed9bfbda 100644 --- a/chrome/browser/ui/webui/signin/profile_customization_ui.h +++ b/chrome/browser/ui/webui/signin/profile_customization_ui.h
@@ -45,6 +45,9 @@ customize_themes::mojom::CustomizeThemesHandlerFactory> pending_receiver); + // Allows tests to trigger page events. + ProfileCustomizationHandler* GetProfileCustomizationHandlerForTesting(); + private: // customize_themes::mojom::CustomizeThemesHandlerFactory: void CreateCustomizeThemesHandler( @@ -57,6 +60,9 @@ mojo::Receiver<customize_themes::mojom::CustomizeThemesHandlerFactory> customize_themes_factory_receiver_; + // Stored for tests. + raw_ptr<ProfileCustomizationHandler> profile_customization_handler_ = nullptr; + WEB_UI_CONTROLLER_TYPE_DECL(); };
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.h b/chrome/browser/ui/webui/signin/profile_picker_handler.h index acfc8b60..04560e4 100644 --- a/chrome/browser/ui/webui/signin/profile_picker_handler.h +++ b/chrome/browser/ui/webui/signin/profile_picker_handler.h
@@ -61,6 +61,7 @@ friend class ProfilePickerHandlerTest; friend class ProfilePickerHandlerInUserProfileTest; friend class ProfilePickerCreationFlowBrowserTest; + friend class ProfilePickerLocalProfileCreationDialogBrowserTest; friend class StartupBrowserCreatorPickerInfobarTest; FRIEND_TEST_ALL_PREFIXES(ProfilePickerHandlerInUserProfileTest, HandleExtendedAccountInformation);
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 7ef3312..513f7fe 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1663135073-b658346ca3ce49ab641572b7c7e6d23ee209e125.profdata +chrome-linux-main-1663156614-f71198c489c4a5814c94ba00ab4ae608d4b538cb.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 0d628ac..f32d37c 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1663135073-71be82a32e7ee78f7ab370576aa01ef2bd38b3ec.profdata +chrome-mac-arm-main-1663156614-e4697d5d67c3ca93fa21d8118a6039f4d320d565.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index a9d88ec..66b059d0 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1663135073-4a1abcd635c13668f5bf1c10aed02b62de7e438f.profdata +chrome-mac-main-1663156614-d7faeeca9068b9cb6d11fa789d6589f932981d5c.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 3be0619..43ca3c4 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1663124270-54c8ad74a405afb2d3e33cbf9606e8b30275e257.profdata +chrome-win32-main-1663156614-b26fa12d766d939ac34d1e8cd57d7f19cc5fb372.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index f8e0d15..3c7f203b 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1663135073-e6a8fa82d3d570ed597fbb362fce05fd9cabf02c.profdata +chrome-win64-main-1663156614-992666b2abf71954c92c2f8b587bfc34200276aa.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index c711a30b..68903a6a 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -614,6 +614,15 @@ base::FEATURE_DISABLED_BY_DEFAULT); #endif // BUILDFLAG(IS_CHROMEOS) +// When enabled, allows other features to use the k-Anonymity Service. +const base::Feature kKAnonymityService{"KAnonymityService", + base::FEATURE_DISABLED_BY_DEFAULT}; + +// When enabled, the k-Anonymity Service will send requests to the Join and +// Query k-anonymity servers. +const base::Feature kKAnonymityServiceOHTTPRequests{ + "KAnonymityServiceOHTTPRequests", base::FEATURE_DISABLED_BY_DEFAULT}; + // When enabled, removes any entry points to the history UI from Incognito mode. const base::Feature kUpdateHistoryEntryPointsInIncognito{ "UpdateHistoryEntryPointsInIncognito", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index bfac4d78..76d6679 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -432,6 +432,12 @@ #endif COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kKAnonymityService; + +COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kKAnonymityServiceOHTTPRequests; + +COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kUpdateHistoryEntryPointsInIncognito; #if BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl index 9b11c2f..baeec64 100644 --- a/chrome/common/extensions/api/file_manager_private.idl +++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -390,7 +390,11 @@ }; enum DlpLevel { - // User cannot perform an action. + // Report every action to the admin, doesn't affect the user. + report, + // Warn the user on every action. + warn, + // Block the user on every action. block, // No restriction. allow @@ -1121,9 +1125,6 @@ // |result| Hash containing the string assets. callback GetStringsCallback = void(object result); -// |color| String containing the color of the title bar. -callback GetFrameColorCallback = void(DOMString color); - // |success| True when file watch is successfully added. callback AddFileWatchCallback = void(optional boolean success); @@ -1785,9 +1786,6 @@ // |callback| The result callback. static void getHoldingSpaceState(HoldingSpaceStateCallback callback); - // Returns color via `callback` for Files app foreground window frame. - static void getFrameColor(GetFrameColorCallback callback); - // Returns true via `callback` if tablet mode is enabled, false otherwise. static void isTabletModeEnabled(BooleanCallback callback);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index eb005e2..3325a66 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -865,6 +865,7 @@ "../browser/browsing_data/browsing_data_remover_browsertest_base.h", "../browser/browsing_data/chrome_browsing_data_lifetime_manager_browsertest.cc", "../browser/engagement/important_sites_util_browsertest.cc", + "../browser/fast_checkout/fast_checkout_tab_helper_browsertest.cc", "../browser/metrics/metrics_log_browsertest.cc", "../browser/metrics/metrics_service_user_demographics_browsertest.cc", "../browser/metrics/sampled_out_client_id_saved_browsertest.cc", @@ -5245,6 +5246,7 @@ "../browser/history_clusters/history_clusters_tab_helper_unittest.cc", "../browser/idle/idle_detection_permission_context_unittest.cc", "../browser/internal_auth_unittest.cc", + "../browser/k_anonymity_service/k_anonymity_service_client_unittest.cc", "../browser/k_anonymity_service/k_anonymity_trust_token_getter_unittest.cc", "../browser/language/language_model_manager_factory_unittest.cc", "../browser/language/url_language_histogram_factory_unittest.cc",
diff --git a/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts b/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts index 8fe86a5..ce5c47b 100644 --- a/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts +++ b/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts
@@ -126,6 +126,12 @@ } } +interface WaitForSuccessParams { + retryIntervalMs: number; + totalMs: number; + assertionFn: () => void; +} + suite('CrComponentsHelpBubbleMixinTest', () => { let testProxy: TestHelpBubbleProxy; let container: HelpBubbleMixinTestElement; @@ -152,6 +158,44 @@ }); } + /** + * Returns the current timestamp in milliseconds since UNIX epoch + */ + function now() { + return +new Date(); + } + + /** + * Try/catch a function for some time, retrying after failures + * + * If the callback function succeeds, return early with the total time + * If the callback always fails, throw the error after the last run + */ + async function waitForSuccess(params: WaitForSuccessParams): + Promise<number|null> { + const startMs = now(); + let lastAttemptMs = startMs; + let lastError: Error|null = null; + let attempts = 0; + while (now() - startMs < params.totalMs) { + await sleep(params.retryIntervalMs); + lastAttemptMs = now(); + try { + params.assertionFn(); + return lastAttemptMs - startMs; + } catch (e) { + lastError = e as Error; + } + attempts++; + } + if (lastError !== null) { + lastError.message = `[Attempts: ${attempts}, Total time: ${ + lastAttemptMs - startMs}ms]: ${lastError.message}`; + throw lastError; + } + return Infinity; + } + setup(() => { testProxy = new TestHelpBubbleProxy(); HelpBubbleProxyImpl.setInstance(testProxy); @@ -568,21 +612,55 @@ timeoutParams.position = HelpBubbleArrowPosition.TOP_CENTER; timeoutParams.bodyText = 'This is another help bubble.'; timeoutParams.titleText = 'This is a title'; - timeoutParams.timeout = { - microseconds: BigInt(250 * 1000), // 250ms - }; timeoutParams.buttons = []; - test('help bubble mixin sends timeout event', async () => { - container.showHelpBubble('p1', timeoutParams); + // It is hard to guarantee the correct timing on various test systems, + // so the 'before timeout' and 'after timeout' tests are split + // into 2 separate fixtures + + // Before timeout + // Use a long timeout to test base state that a timeout will + // not be accidentally triggered when a timeout is set + test('help bubble mixin does not immediately timeout', async () => { + const longTimeoutParams = { + ...timeoutParams, + timeout: { + microseconds: BigInt(10 * 1000 * 1000), // 10s + }, + }; + + container.showHelpBubble('p1', longTimeoutParams); + await waitAfterNextRender(container); assertEquals( 0, testProxy.getHandler().getCallCount('helpBubbleClosed'), - 'helpBubbleClosed was not called'); + 'helpBubbleClosed should not be called'); + assertTrue(container.isHelpBubbleShowing()); + }); + + // After timeout + // Use a short timeout and a retry loop to + test('help bubble mixin sends timeout event', async () => { + const timeoutMs = 100; + const shortTimeoutParams = { + ...timeoutParams, + timeout: { + microseconds: BigInt(timeoutMs * 1000), // 100ms + }, + }; + + container.showHelpBubble('p1', shortTimeoutParams); await waitAfterNextRender(container); - await sleep(500); // 500ms - assertEquals( - 1, testProxy.getHandler().getCallCount('helpBubbleClosed'), - 'helpBubbleClosed was called'); + const timeUntilSuccess = + await waitForSuccess({ + retryIntervalMs: 50, + totalMs: 1500, + assertionFn: () => assertEquals( + 1, testProxy.getHandler().getCallCount('helpBubbleClosed'), + 'helpBubbleClosed should be called called'), + }) as number; + assertTrue( + timeUntilSuccess >= timeoutMs, + 'timeout should happen in reasonable amount of time'); assertDeepEquals( [[PARAGRAPH_NATIVE_ID, HelpBubbleClosedReason.kTimedOut]], testProxy.getHandler().getArgs('helpBubbleClosed'));
diff --git a/chrome/test/data/webui/cr_components/help_bubble_test.ts b/chrome/test/data/webui/cr_components/help_bubble_test.ts index 71a655bc..55af208 100644 --- a/chrome/test/data/webui/cr_components/help_bubble_test.ts +++ b/chrome/test/data/webui/cr_components/help_bubble_test.ts
@@ -12,6 +12,12 @@ import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {isVisible, waitAfterNextRender} from 'chrome://webui-test/test_util.js'; +interface WaitForSuccessParams { + retryIntervalMs: number; + totalMs: number; + assertionFn: () => void; +} + suite('CrComponentsHelpBubbleTest', () => { let helpBubble: HelpBubbleElement; @@ -57,11 +63,49 @@ * Create a promise that resolves after a given amount of time */ async function sleep(milliseconds: number) { - return new Promise((resolve) => { - setTimeout(resolve, milliseconds); + return new Promise((res) => { + setTimeout(res, milliseconds); }); } + /** + * Returns the current timestamp in milliseconds since UNIX epoch + */ + function now() { + return +new Date(); + } + + /** + * Try/catch a function for some time, retrying after failures + * + * If the callback function succeeds, return early with the total time + * If the callback always fails, throw the error after the last run + */ + async function waitForSuccess(params: WaitForSuccessParams): + Promise<number|null> { + const startMs = now(); + let lastAttemptMs = startMs; + let lastError: Error|null = null; + let attempts = 0; + while (now() - startMs < params.totalMs) { + await sleep(params.retryIntervalMs); + lastAttemptMs = now(); + try { + params.assertionFn(); + return lastAttemptMs - startMs; + } catch (e) { + lastError = e as Error; + } + attempts++; + } + if (lastError !== null) { + lastError.message = `[Attempts: ${attempts}, Total time: ${ + lastAttemptMs - startMs}ms]: ${lastError.message}`; + throw lastError; + } + return Infinity; + } + setup(() => { document.body.innerHTML = ` <div id='container'> @@ -243,7 +287,7 @@ assertEquals(1, clicked, 'close button should be clicked once'); }); - test('help bubble timeout generates event', async () => { + test('help bubble with timeout does not immediately emit event', async () => { let timedOut: number = 0; const callback = (e: HelpBubbleTimedOutEvent) => { assertEquals( @@ -254,12 +298,36 @@ helpBubble.anchorId = 'title'; helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; helpBubble.bodyText = HELP_BUBBLE_BODY; - helpBubble.timeoutMs = 250; // 250ms + helpBubble.timeoutMs = 10 * 1000; // 10s helpBubble.show(); - assertEquals(0, timedOut, 'timeout should not be triggered'); await waitAfterNextRender(helpBubble); - await sleep(500); // 500ms - assertEquals(1, timedOut, 'timeout should only emit event once'); + assertEquals(0, timedOut, 'timeout should not be triggered'); + }); + + test('help bubble with timeout generates event', async () => { + const timeoutMs: number = 100; + let timedOut: number = 0; + const callback = (e: HelpBubbleTimedOutEvent) => { + assertEquals( + 'title', e.detail.anchorId, 'timeout event anchorId should match'); + ++timedOut; + }; + helpBubble.addEventListener(HELP_BUBBLE_TIMED_OUT_EVENT, callback); + helpBubble.anchorId = 'title'; + helpBubble.position = HelpBubbleArrowPosition.TOP_CENTER; + helpBubble.bodyText = HELP_BUBBLE_BODY; + helpBubble.timeoutMs = timeoutMs; // 100ms + helpBubble.show(); + await waitAfterNextRender(helpBubble); + const timeUntilSuccess = await waitForSuccess({ + retryIntervalMs: 50, + totalMs: 1500, + assertionFn: () => assertEquals( + 1, timedOut, 'timeout should emit event'), + }) as number; + assertTrue( + timeUntilSuccess >= timeoutMs, + 'timeout should happen in reasonable amount of time'); }); test('help bubble without timeout does not generate event', async () => { @@ -276,7 +344,7 @@ helpBubble.show(); assertEquals(0, timedOut, 'timeout should not be triggered'); await waitAfterNextRender(helpBubble); - await sleep(500); // 500ms + await sleep(100); // 100ms assertEquals(0, timedOut, 'timeout is never triggered'); });
diff --git a/chrome/test/data/webui/polymer_browser_test_base.js b/chrome/test/data/webui/polymer_browser_test_base.js index afe1699..e5f027f7 100644 --- a/chrome/test/data/webui/polymer_browser_test_base.js +++ b/chrome/test/data/webui/polymer_browser_test_base.js
@@ -32,33 +32,6 @@ }; /** - * Test fixture for Polymer2 elements testing (deprecated). - * TODO(crbug.com/965770): Delete once all remaining Polymer2 UIs have been - * migrated. - * @constructor - * @extends PolymerTest - */ -function Polymer2DeprecatedTest() {} - -Polymer2DeprecatedTest.prototype = { - __proto__: PolymerTest.prototype, - - /** - * Files that need not be compiled. - * @override - */ - extraLibraries: [ - '//ui/webui/resources/js/cr.js', - '//ui/webui/resources/js/assert.js', - '//ui/webui/resources/js/promise_resolver.js', - '//third_party/mocha/mocha.js', - '//chrome/test/data/webui/mocha_adapter.js', - '//third_party/polymer/v1_0/components-chromium/iron-test-helpers/' + - 'mock-interactions.js', - ], -}; - -/** * Imports the HTML file. * @param {string} src The URL to load. * @return {!Promise} A promise that is resolved/rejected on success/failure.
diff --git a/chrome/test/data/webui/polymer_interactive_ui_test.js b/chrome/test/data/webui/polymer_interactive_ui_test.js index f21c48f5..88be28b 100644 --- a/chrome/test/data/webui/polymer_interactive_ui_test.js +++ b/chrome/test/data/webui/polymer_interactive_ui_test.js
@@ -20,18 +20,3 @@ GEN(' browser()->tab_strip_model()->GetActiveWebContents()->Focus();'); }, }; - -// TODO(crbug.com/965770): Delete once all remaining Polymer2 UIs have been -// migrated. -function Polymer2DeprecatedInteractiveUITest() {} - -Polymer2DeprecatedInteractiveUITest.prototype = { - __proto__: Polymer2DeprecatedTest.prototype, - - /** @override */ - testGenPreamble: function() { - // Must explicitly focus the web contents before running the test on Mac. - // See: https://crbug.com/642467. - GEN(' browser()->tab_strip_model()->GetActiveWebContents()->Focus();'); - }, -};
diff --git a/chrome/test/data/webui/settings/safety_check_permissions_test.ts b/chrome/test/data/webui/settings/safety_check_permissions_test.ts index 76c51ed..df2589be 100644 --- a/chrome/test/data/webui/settings/safety_check_permissions_test.ts +++ b/chrome/test/data/webui/settings/safety_check_permissions_test.ts
@@ -29,7 +29,7 @@ // Ensure the elements are correct. assertSafetyCheckChild({ page: page, - iconStatus: SafetyCheckIconStatus.WARNING, + iconStatus: SafetyCheckIconStatus.UNUSED_SITE_PERMISSIONS, label: 'Permissions removed from unused websites', buttonLabel: 'Review', buttonAriaLabel: 'Review', @@ -63,7 +63,7 @@ // Ensure the elements are correct. assertSafetyCheckChild({ page: page, - iconStatus: SafetyCheckIconStatus.WARNING, + iconStatus: SafetyCheckIconStatus.NOTIFICATION_PERMISSIONS, label: 'Review sites that recently sent a lot of notifications', buttonLabel: 'Review', buttonAriaLabel: 'Review', @@ -78,4 +78,4 @@ routes.SITE_SETTINGS_NOTIFICATIONS, Router.getInstance().getCurrentRoute()); }); -}); \ No newline at end of file +});
diff --git a/components/autofill/core/browser/address_profile_save_manager_unittest.cc b/components/autofill/core/browser/address_profile_save_manager_unittest.cc index 68823429..a416d462 100644 --- a/components/autofill/core/browser/address_profile_save_manager_unittest.cc +++ b/components/autofill/core/browser/address_profile_save_manager_unittest.cc
@@ -5,6 +5,7 @@ #include "components/autofill/core/browser/address_profile_save_manager.h" #include "base/strings/strcat.h" +#include "base/strings/string_piece.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" @@ -59,6 +60,13 @@ constexpr char kProfileUpdateEditComplementedCountryHistogram[] = "Autofill.ProfileImport.UpdateProfileEditedComplementedCountry"; +// Histograms related to `kAutofillIgnoreInvalidCountryOnImport`. +// TODO(crbug.com/1362472): Cleanup when launched. +constexpr char kNewProfileWithIgnoredCountryDecisionHistogram[] = + "Autofill.ProfileImport.NewProfileWithIgnoredCountryDecision"; +constexpr char kProfileUpdateWithIgnoredCountryDecisionHistogram[] = + "Autofill.ProfileImport.UpdateProfileWithIgnoredCountryDecision"; + // Histograms related to |kAutofillRemoveInvalidPhoneNumberOnImport| // TODO(crbug.com/1298424): Cleanup when launched. constexpr char kNewProfileWithRemovedPhoneNumberDecisionHistogram[] = @@ -169,11 +177,18 @@ class AddressProfileSaveManagerTest : public testing::Test, - public testing::WithParamInterface<std::tuple<bool, bool>> { + public testing::WithParamInterface<std::tuple<bool, bool, bool>> { public: void SetUp() override { - complement_country_ = std::get<0>(GetParam()); - remove_invalid_phone_number_ = std::get<1>(GetParam()); + // These parameters would typically be set by `FormDataImporter` when + // creating the `ImportScenarioTestCase::observed_profile`. This step + // precedes the saving logic tested here. They expand the + // `ImportScenarioTestCase`, but are part of the fixture, so they can be + // tested in a parameterized way. + import_metadata_ = { + .did_complement_country = std::get<0>(GetParam()), + .did_ignore_invalid_country = std::get<1>(GetParam()), + .did_remove_invalid_phone_number = std::get<2>(GetParam())}; // Enable both explicit save prompts and structured names. // The latter is needed to test the concept of silent updates. scoped_feature_list_.InitWithFeatures( @@ -191,15 +206,55 @@ // Tests the |test_scenario|. void TestImportScenario(ImportScenarioTestCase& test_scenario); + const ProfileImportMetadata& import_metadata() const { + return import_metadata_; + } + protected: base::test::TaskEnvironment task_environment_; TestAutofillClient autofill_client_; MockPersonalDataManager mock_personal_data_manager_; base::test::ScopedFeatureList scoped_feature_list_; - bool complement_country_; - bool remove_invalid_phone_number_; + ProfileImportMetadata import_metadata_; }; +// Expects that none of the histograms `names` has any samples. +void ExpectEmptyHistograms(const base::HistogramTester& histogram_tester, + const std::vector<base::StringPiece>& names) { + for (base::StringPiece name : names) + histogram_tester.ExpectTotalCount(name, 0); +} + +// Helper function that tests the reporting of feature-specific metrics around +// the user decision. These metrics usually exist twice, once for new profile +// creations and once for updates. Verifies that: +// - If the feature that is being tested and supposed to emit these metrics is +// enabled (`feature_enabled`), a unique sample in either the +// `new_profile_histogram_name` or the `update_profile_histogram_name` +// histogram is collected, depending on the import type. +// - If the feature is disabled, no metrics are collected. +void TestFeatureSpecificNewOrUpdateProfileMetrics( + const base::HistogramTester& histogram_tester, + const ImportScenarioTestCase& test_scenario, + bool feature_enabled, + base::StringPiece new_profile_histogram_name, + base::StringPiece update_profile_histogram_name) { + bool is_new_profile = test_scenario.expected_import_type == + AutofillProfileImportType::kNewProfile; + if (feature_enabled) { + histogram_tester.ExpectUniqueSample(is_new_profile + ? new_profile_histogram_name + : update_profile_histogram_name, + test_scenario.user_decision, 1); + ExpectEmptyHistograms(histogram_tester, + {!is_new_profile ? new_profile_histogram_name + : update_profile_histogram_name}); + } else { + ExpectEmptyHistograms(histogram_tester, {new_profile_histogram_name, + update_profile_histogram_name}); + } +} + void AddressProfileSaveManagerTest::TestImportScenario( ImportScenarioTestCase& test_scenario) { static const GURL url("https://www.importmyform.com/index.html"); @@ -256,13 +311,10 @@ mock_personal_data_manager_.SetProfiles(&test_scenario.existing_profiles); // Initiate the profile import. - ProfileImportMetadata import_metadata{ - .did_complement_country = complement_country_, - .did_remove_invalid_phone_number = remove_invalid_phone_number_}; save_manager.ImportProfileFromForm( test_scenario.observed_profile, "en-US", url, /*allow_only_silent_updates=*/test_scenario.allow_only_silent_updates, - import_metadata); + import_metadata()); // Assert that there is a finished import process on record. ASSERT_NE(save_manager.last_import(), nullptr); @@ -290,7 +342,8 @@ ? kSilentUpdatesProfileImportTypeHistogram : kProfileImportTypeHistogram, test_scenario.expected_import_type, 1); - if (test_scenario.allow_only_silent_updates && remove_invalid_phone_number_) { + if (test_scenario.allow_only_silent_updates && + import_metadata().did_remove_invalid_phone_number) { histogram_tester.ExpectUniqueSample( kSilentUpdatesWithRemovedPhoneNumberProfileImportTypeHistogram, test_scenario.expected_import_type, 1); @@ -305,16 +358,16 @@ AutofillProfileImportType::kConfirmableMergeAndSilentUpdate; // If the import was neither a new profile or a confirmable merge, test that - // the corresponding updates are unchanged. + // the corresponding histograms are unchanged. if (!is_new_profile && !is_confirmable_merge) { - histogram_tester.ExpectTotalCount(kNewProfileEditsHistogram, 0); - histogram_tester.ExpectTotalCount(kNewProfileDecisionHistogram, 0); - histogram_tester.ExpectTotalCount( - kNewProfileWithComplementedCountryDecisionHistogram, 0); - histogram_tester.ExpectTotalCount(kProfileUpdateEditsHistogram, 0); - histogram_tester.ExpectTotalCount(kProfileUpdateDecisionHistogram, 0); - histogram_tester.ExpectTotalCount( - kProfileUpdateWithComplementedCountryDecisionHistogram, 0); + ExpectEmptyHistograms( + histogram_tester, + {kNewProfileEditsHistogram, kNewProfileDecisionHistogram, + kNewProfileWithComplementedCountryDecisionHistogram, + kNewProfileWithIgnoredCountryDecisionHistogram, + kProfileUpdateEditsHistogram, kProfileUpdateDecisionHistogram, + kProfileUpdateWithComplementedCountryDecisionHistogram, + kProfileUpdateWithIgnoredCountryDecisionHistogram}); } else { DCHECK(!is_new_profile || !is_confirmable_merge); @@ -349,7 +402,7 @@ test_scenario.expected_edited_types_for_metrics.size()); // Metrics related to country complemention. - if (complement_country_) { + if (import_metadata().did_complement_country) { if (is_new_profile) { histogram_tester.ExpectTotalCount( kProfileUpdateWithComplementedCountryDecisionHistogram, 0); @@ -390,29 +443,27 @@ kProfileUpdateEditComplementedCountryHistogram, 0); } } else { - histogram_tester.ExpectTotalCount( - kNewProfileWithComplementedCountryDecisionHistogram, 0); - histogram_tester.ExpectTotalCount( - kProfileUpdateWithComplementedCountryDecisionHistogram, 0); - histogram_tester.ExpectTotalCount( - kNewProfileEditComplementedCountryHistogram, 0); - histogram_tester.ExpectTotalCount( - kProfileUpdateEditComplementedCountryHistogram, 0); + ExpectEmptyHistograms( + histogram_tester, + {kNewProfileWithComplementedCountryDecisionHistogram, + kProfileUpdateWithComplementedCountryDecisionHistogram, + kNewProfileEditComplementedCountryHistogram, + kProfileUpdateEditComplementedCountryHistogram}); } - // Metrics related to removing invalid phone numbers for non silent updates. - if (remove_invalid_phone_number_) { - histogram_tester.ExpectTotalCount( - !is_new_profile - ? kNewProfileWithRemovedPhoneNumberDecisionHistogram - : kProfileUpdateWithRemovedPhoneNumberDecisionHistogram, - 0); - histogram_tester.ExpectUniqueSample( - is_new_profile - ? kNewProfileWithRemovedPhoneNumberDecisionHistogram - : kProfileUpdateWithRemovedPhoneNumberDecisionHistogram, - test_scenario.user_decision, 1); - } + // Metrics related to ignoring an invalid country. + TestFeatureSpecificNewOrUpdateProfileMetrics( + histogram_tester, test_scenario, + import_metadata().did_ignore_invalid_country, + kNewProfileWithIgnoredCountryDecisionHistogram, + kProfileUpdateWithIgnoredCountryDecisionHistogram); + + // Metrics related to removing invalid phone numbers. + TestFeatureSpecificNewOrUpdateProfileMetrics( + histogram_tester, test_scenario, + import_metadata().did_remove_invalid_phone_number, + kNewProfileWithRemovedPhoneNumberDecisionHistogram, + kProfileUpdateWithRemovedPhoneNumberDecisionHistogram); for (auto edited_type : test_scenario.expected_edited_types_for_metrics) { histogram_tester.ExpectBucketCount(affected_edits_histo, edited_type, 1); @@ -1357,7 +1408,9 @@ // `kAutofillRemoveInvalidPhoneNumberOnImport`. INSTANTIATE_TEST_SUITE_P(, AddressProfileSaveManagerTest, - testing::Combine(testing::Bool(), testing::Bool())); + testing::Combine(testing::Bool(), + testing::Bool(), + testing::Bool())); } // namespace
diff --git a/components/autofill/core/browser/autofill_profile_import_process.cc b/components/autofill/core/browser/autofill_profile_import_process.cc index bf945e6..fd14254 100644 --- a/components/autofill/core/browser/autofill_profile_import_process.cc +++ b/components/autofill/core/browser/autofill_profile_import_process.cc
@@ -364,6 +364,10 @@ AutofillMetrics::LogNewProfileWithComplementedCountryImportDecision( user_decision_); } + if (import_metadata_.did_ignore_invalid_country) { + AutofillMetrics::LogNewProfileWithIgnoredCountryImportDecision( + user_decision_); + } if (import_metadata_.did_remove_invalid_phone_number) { AutofillMetrics::LogNewProfileWithRemovedPhoneNumberImportDecision( user_decision_); @@ -399,6 +403,12 @@ AutofillMetrics::LogProfileUpdateWithComplementedCountryImportDecision( user_decision_); } + // Ignoring an invalid country made the update possible, so this should be + // logged in any case. + if (import_metadata_.did_ignore_invalid_country) { + AutofillMetrics::LogProfileUpdateWithIgnoredCountryImportDecision( + user_decision_); + } AutofillMetrics::LogUpdateProfileNumberOfAffectedFields( merge_difference.size(), user_decision_);
diff --git a/components/autofill/core/browser/autofill_profile_import_process.h b/components/autofill/core/browser/autofill_profile_import_process.h index e1edbda..5a410ad 100644 --- a/components/autofill/core/browser/autofill_profile_import_process.h +++ b/components/autofill/core/browser/autofill_profile_import_process.h
@@ -63,9 +63,13 @@ struct ProfileImportMetadata { // Whether the profile's country was complemented automatically. bool did_complement_country = false; - // Whether the profile originally contained an invalid phone number, that was: - // - removed due to |kAutofillRemoveInvalidPhoneNumberOnImport| - // - the only requirement preventing an import. + // Whether the form original contained an invalid country, that was ignored + // due to AutofillOverwriteInvalidCountryOnImport. + // TODO(crbug.com/1362472): Cleanup when launched. + bool did_ignore_invalid_country = false; + // Whether the form originally contained an invalid phone number, that was: + // - Removed due to AutofillRemoveInvalidPhoneNumberOnImport. + // - The only requirement preventing an import. // TODO(crbug.com/1298424): Cleanup when launched. bool did_remove_invalid_phone_number = false; };
diff --git a/components/autofill/core/browser/form_data_importer.cc b/components/autofill/core/browser/form_data_importer.cc index 7c9d1d5..ea867c8 100644 --- a/components/autofill/core/browser/form_data_importer.cc +++ b/components/autofill/core/browser/form_data_importer.cc
@@ -557,10 +557,18 @@ } // Check if the country code was still not determined correctly. if (!candidate_profile.HasRawInfo(ADDRESS_HOME_COUNTRY)) { - LOG_AF(import_log_buffer) - << LogMessage::kImportAddressProfileFromFormFailed - << "Missing country." << CTag{}; has_invalid_country = true; + // If AutofillIgnoreInvalidCountryOnImport is enable, we cannot just + // set `has_invalid_country` to false, because the flag is used to + // collect metrics further down. + import_metadata.did_ignore_invalid_country = + base::FeatureList::IsEnabled( + features::kAutofillIgnoreInvalidCountryOnImport); + if (!import_metadata.did_ignore_invalid_country) { + LOG_AF(import_log_buffer) + << LogMessage::kImportAddressProfileFromFormFailed + << "Missing country." << CTag{}; + } } } } @@ -598,7 +606,8 @@ bool has_invalid_information = !IsValidLearnableProfile(candidate_profile, import_log_buffer) || has_multiple_distinct_email_addresses || has_invalid_field_types || - has_invalid_country || has_invalid_phone_number; + (has_invalid_country && !import_metadata.did_ignore_invalid_country) || + has_invalid_phone_number; // Profiles with valid information qualify for multi-step imports. // This requires the profile to be finalized to apply the merging logic. @@ -618,7 +627,7 @@ // For multi-step imports, |did_complement_country| might be set twice, but as // the metric is only logged if it wasn't present before, this is fine. import_metadata.did_complement_country = - !has_invalid_country && + (!has_invalid_country || import_metadata.did_ignore_invalid_country) && ComplementCountry(candidate_profile, predicted_country_code); // This relies on the profile's country code and must be done strictly after
diff --git a/components/autofill/core/browser/form_data_importer_unittest.cc b/components/autofill/core/browser/form_data_importer_unittest.cc index 3f0bb17..1f5ad47f 100644 --- a/components/autofill/core/browser/form_data_importer_unittest.cc +++ b/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -782,6 +782,31 @@ ImportWithCountry("", {kDefaultGermanProfile}); } +// Tests how invalid countries in submitted forms are treated depending on +// `kAutofillIgnoreInvalidCountryOnImport`. +TEST_P(FormDataImporterTest, InvalidCountry) { + // Due to the extra 'A', the country of this `form_structure` is invalid. + std::unique_ptr<FormStructure> form_structure = + ConstructFormStructureFromTypeValuePairs( + GetDefaultProfileTypeValuePairsWithOverriddenCountry("USAA")); + // With `kAutofillIgnoreInvalidCountryOnImport` disabled, profiles with + // invalid country information are rejected. + { + base::test::ScopedFeatureList ignore_invalid_country_feature; + ignore_invalid_country_feature.InitAndDisableFeature( + features::kAutofillIgnoreInvalidCountryOnImport); + ImportAddressProfileAndVerifyImportOfNoProfile(*form_structure); + } + // With the feature enabled, the invalid country is ignored and country + // complemention overwrites it. It becomes US due to the locale. + { + base::test::ScopedFeatureList ignore_invalid_country_feature; + ignore_invalid_country_feature.InitAndEnableFeature( + features::kAutofillIgnoreInvalidCountryOnImport); + ImportAddressProfileAndVerifyImportOfDefaultProfile(*form_structure); + } +} + TEST_P(FormDataImporterTest, InvalidPhoneNumber) { TypeValuePairs profile_with_invalid_phone_number = GetDefaultProfileTypeValuePairs();
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.cc b/components/autofill/core/browser/metrics/autofill_metrics.cc index 38503bcb..52e9d25 100644 --- a/components/autofill/core/browser/metrics/autofill_metrics.cc +++ b/components/autofill/core/browser/metrics/autofill_metrics.cc
@@ -2862,6 +2862,12 @@ decision); } +void AutofillMetrics::LogNewProfileWithIgnoredCountryImportDecision( + AutofillClient::SaveAddressProfileOfferUserDecision decision) { + base::UmaHistogramEnumeration( + "Autofill.ProfileImport.NewProfileWithIgnoredCountryDecision", decision); +} + void AutofillMetrics::LogNewProfileWithRemovedPhoneNumberImportDecision( AutofillClient::SaveAddressProfileOfferUserDecision decision) { base::UmaHistogramEnumeration( @@ -2901,6 +2907,13 @@ decision); } +void AutofillMetrics::LogProfileUpdateWithIgnoredCountryImportDecision( + AutofillClient::SaveAddressProfileOfferUserDecision decision) { + base::UmaHistogramEnumeration( + "Autofill.ProfileImport.UpdateProfileWithIgnoredCountryDecision", + decision); +} + void AutofillMetrics::LogProfileUpdateWithRemovedPhoneNumberImportDecision( AutofillClient::SaveAddressProfileOfferUserDecision decision) { base::UmaHistogramEnumeration(
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.h b/components/autofill/core/browser/metrics/autofill_metrics.h index 7839ebf..1927195 100644 --- a/components/autofill/core/browser/metrics/autofill_metrics.h +++ b/components/autofill/core/browser/metrics/autofill_metrics.h
@@ -1601,11 +1601,16 @@ static void LogNewProfileImportDecision( AutofillClient::SaveAddressProfileOfferUserDecision decision); - // Logs the user decision for importing a new profile with auto complemented + // Logs the user decision for importing a new profile with a complemented // country. static void LogNewProfileWithComplementedCountryImportDecision( AutofillClient::SaveAddressProfileOfferUserDecision decision); + // Logs the user decision for importing a new profile, which could only + // be imported after an invalid country was ignored. + static void LogNewProfileWithIgnoredCountryImportDecision( + AutofillClient::SaveAddressProfileOfferUserDecision decision); + // Logs the user decision for importing a new profile, which was only possible // after an invalid phone number was removed. // TODO(crbug.com/1298424): Cleanup when launched. @@ -1625,11 +1630,16 @@ static void LogProfileUpdateImportDecision( AutofillClient::SaveAddressProfileOfferUserDecision decision); - // Logs the user decision for updating an exiting profile with auto - // complemented country. + // Logs the user decision for updating an exiting profile with a complemented + // country. static void LogProfileUpdateWithComplementedCountryImportDecision( AutofillClient::SaveAddressProfileOfferUserDecision decision); + // Logs the user decision for updating an exiting profile, which could only + // be imported after an invalid country was ignored. + static void LogProfileUpdateWithIgnoredCountryImportDecision( + AutofillClient::SaveAddressProfileOfferUserDecision decision); + // Logs the user decision for updating an existing profile, which was only // possible after an invalid phone number was removed. // TODO(crbug.com/1298424): Cleanup when launched.
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc index ed657a555..71637f2 100644 --- a/components/autofill/core/common/autofill_features.cc +++ b/components/autofill/core/common/autofill_features.cc
@@ -93,6 +93,13 @@ const base::FeatureParam<base::TimeDelta> kAutofillAssociateFormsTTL{ &kAutofillAssociateForms, "associate_forms_ttl", base::Minutes(5)}; +// When enabled, Autofill ignores invalid country information on import, which +// would otherwise prevent an import. Instead, ignoring it will trigger the +// country complemention logic. +// TODO(crbug.com/1362472): Cleanup when launched. +extern const base::Feature kAutofillIgnoreInvalidCountryOnImport{ + "AutofillIgnoreInvalidCountryOnImport", base::FEATURE_DISABLED_BY_DEFAULT}; + // If enabled, the country calling code for nationally formatted phone numbers // is inferred from the profile's country, if available. // TODO(crbug.com/1311937): Cleanup when launched.
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h index 128d09b..25340c2 100644 --- a/components/autofill/core/common/autofill_features.h +++ b/components/autofill/core/common/autofill_features.h
@@ -49,6 +49,8 @@ COMPONENT_EXPORT(AUTOFILL) extern const base::FeatureParam<base::TimeDelta> kAutofillAssociateFormsTTL; COMPONENT_EXPORT(AUTOFILL) +extern const base::Feature kAutofillIgnoreInvalidCountryOnImport; +COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillInferCountryCallingCode; COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillConsiderPhoneNumberSeparatorsValidLabels;
diff --git a/components/autofill_assistant/browser/features.cc b/components/autofill_assistant/browser/features.cc index 41cf1d7..fe00e67f6 100644 --- a/components/autofill_assistant/browser/features.cc +++ b/components/autofill_assistant/browser/features.cc
@@ -156,5 +156,12 @@ const base::Feature kAutofillAssistantCudFilterProfiles{ "AutofillAssistantCudFilterProfiles", base::FEATURE_ENABLED_BY_DEFAULT}; +// Controls whether the DidFinishNavigation should be used instead of +// PrimaryPageChanged. This is a just-in-case switch that will be removed once +// we are confident using DidFinishNavigation is working properly. b/243897243 +const base::Feature kAutofillAssistantUseDidFinishNavigation{ + "AutofillAssistantUseDidFinishNavigation", + base::FEATURE_ENABLED_BY_DEFAULT}; + } // namespace features } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/features.h b/components/autofill_assistant/browser/features.h index 2eed117..4742851 100644 --- a/components/autofill_assistant/browser/features.h +++ b/components/autofill_assistant/browser/features.h
@@ -14,18 +14,19 @@ extern const base::Feature kAutofillAssistant; extern const base::Feature kAutofillAssistantAnnotateDom; extern const base::Feature kAutofillAssistantChromeEntry; +extern const base::Feature kAutofillAssistantCudFilterProfiles; extern const base::Feature kAutofillAssistantDesktop; extern const base::Feature kAutofillAssistantDialogOnboarding; extern const base::Feature kAutofillAssistantDirectActions; extern const base::Feature kAutofillAssistantDisableOnboardingFlow; extern const base::Feature kAutofillAssistantDisableProactiveHelpTiedToMSBB; +extern const base::Feature kAutofillAssistantFeedbackChip; extern const base::Feature kAutofillAssistantFullJsFlowStackTraces; extern const base::Feature kAutofillAssistantFullJsSnippetStackTraces; extern const base::Feature kAutofillAssistantGetPaymentsClientToken; extern const base::Feature kAutofillAssistantGetTriggerScriptsByHashPrefix; extern const base::Feature kAutofillAssistantInCCTTriggering; extern const base::Feature kAutofillAssistantInTabTriggering; -extern const base::Feature kAutofillAssistantFeedbackChip; extern const base::Feature kAutofillAssistantLoadDFMForTriggerScripts; extern const base::Feature kAutofillAssistantProactiveHelp; extern const base::Feature kAutofillAssistantRemoteAssistantUi; @@ -38,8 +39,8 @@ extern const base::Feature kAutofillAssistantUrlHeuristic4; extern const base::Feature kAutofillAssistantUrlHeuristic5; extern const base::Feature kAutofillAssistantUrlHeuristics; +extern const base::Feature kAutofillAssistantUseDidFinishNavigation; extern const base::Feature kAutofillAssistantVerifyGetActionsResponses; -extern const base::Feature kAutofillAssistantCudFilterProfiles; extern const base::Feature kAutofillAssistantVerifyGetNoRoundTripScriptsByHashResponses;
diff --git a/components/autofill_assistant/browser/starter.cc b/components/autofill_assistant/browser/starter.cc index 14fc910..96fdc13 100644 --- a/components/autofill_assistant/browser/starter.cc +++ b/components/autofill_assistant/browser/starter.cc
@@ -181,6 +181,12 @@ Starter::~Starter() = default; void Starter::PrimaryPageChanged(content::Page& page) { + // Early return if we want to use DidFinishNavigation instead. + if (base::FeatureList::IsEnabled( + features::kAutofillAssistantUseDidFinishNavigation)) { + return; + } + // Navigating away from the deeplink domain during startup OR ending up on an // error page will break the flow, unless a trigger script is currently // running (in which case, the trigger script will handle this event). @@ -195,22 +201,59 @@ // Ignore; navigations to the target domain during startup are allowed. return; } - RecordNavigatedAwayMetrics(page, rfh.GetPageUkmSourceId(), - rfh.IsErrorDocument()); + RecordNavigatedAwayMetrics(rfh.GetPageUkmSourceId(), rfh.IsErrorDocument()); // Note: do not early-return here. While the previous startup has failed, we // may have navigated to a new supported domain and may need to start // implicitly. CancelPendingStartup(absl::nullopt); } - if (!rfh.IsErrorDocument()) { current_ukm_source_id_ = page.GetMainDocument().GetPageUkmSourceId(); MaybeStartImplicitlyForUrl(gurl, current_ukm_source_id_); } } -void Starter::RecordNavigatedAwayMetrics(content::Page& page, - ukm::SourceId source_id, +void Starter::DidFinishNavigation( + content::NavigationHandle* navigation_handle) { + // Early return if we want to use PrimaryPageChanged instead. + if (!base::FeatureList::IsEnabled( + features::kAutofillAssistantUseDidFinishNavigation)) { + return; + } + + // Navigating away from the deeplink domain during startup OR ending up on an + // error page will break the flow, unless a trigger script is currently + // running (in which case, the trigger script will handle this event). + if (!navigation_handle->IsInPrimaryMainFrame() || + !navigation_handle->HasCommitted()) { + return; + } + content::RenderFrameHost* rfh = web_contents()->GetPrimaryMainFrame(); + const GURL& new_url = navigation_handle->GetURL(); + if (IsStartupPending() && !trigger_script_coordinator_) { + if (NavigatedToTargetDomain(new_url, *GetPendingTriggerContext())) { + current_ukm_source_id_ = rfh->GetPageUkmSourceId(); + if (waiting_for_deeplink_navigation_) { + Start(std::move(pending_trigger_context_)); + } + // Ignore; navigations to the target domain during startup are allowed. + return; + } + RecordNavigatedAwayMetrics(rfh->GetPageUkmSourceId(), + rfh->IsErrorDocument()); + // Note: do not early-return here. While the previous startup has failed, we + // may have navigated to a new supported domain and may need to start + // implicitly. + CancelPendingStartup(absl::nullopt); + } + + if (!rfh->IsErrorDocument()) { + current_ukm_source_id_ = rfh->GetPageUkmSourceId(); + MaybeStartImplicitlyForUrl(new_url, current_ukm_source_id_); + } +} + +void Starter::RecordNavigatedAwayMetrics(ukm::SourceId source_id, bool is_error_document) const { if (GetPendingTriggerContext() ->GetScriptParameters()
diff --git a/components/autofill_assistant/browser/starter.h b/components/autofill_assistant/browser/starter.h index 7d698f45..47e2c31 100644 --- a/components/autofill_assistant/browser/starter.h +++ b/components/autofill_assistant/browser/starter.h
@@ -74,6 +74,10 @@ preconditions_checked_callback); // content::WebContentsObserver: + // Only one function will execute, the other will early return based on the + // AutofillAssistantUseDidFinishNavigation feature. + void DidFinishNavigation( + content::NavigationHandle* navigation_handle) override; void PrimaryPageChanged(content::Page& page) override; // Invoked when the tab interactability has changed. @@ -172,8 +176,7 @@ // successful. void ReportPreconditionsChecked(bool start_script); - void RecordNavigatedAwayMetrics(content::Page& page, - ukm::SourceId source_id, + void RecordNavigatedAwayMetrics(ukm::SourceId source_id, bool is_error_document) const; WEB_CONTENTS_USER_DATA_KEY_DECL();
diff --git a/components/autofill_assistant/browser/starter_heuristic.cc b/components/autofill_assistant/browser/starter_heuristic.cc index 0689f574..2222899 100644 --- a/components/autofill_assistant/browser/starter_heuristic.cc +++ b/components/autofill_assistant/browser/starter_heuristic.cc
@@ -38,45 +38,61 @@ url_matcher_ = std::make_unique<url_matcher::URLMatcher>(); matcher_id_to_config_map_.clear(); - url_matcher::URLMatcherConditionSet::Vector condition_sets; + url_matcher::URLMatcherConditionSet::Vector overall_condition_set; base::flat_map<base::MatcherStringPattern::ID, HeuristicConfigEntry> mapping; base::MatcherStringPattern::ID next_condition_set_id = 0; for (const StarterHeuristicConfig* config : configs) { + // Will only be added to |overall_condition_set| if all condition sets of + // |config| are valid. + url_matcher::URLMatcherConditionSet::Vector temp_condition_set; for (const auto& condition_set : config->GetConditionSetsForClientState( platform_delegate, browser_context)) { if (!condition_set.is_dict()) { LOG(ERROR) << "Invalid heuristic config: expected a dictionary for " "each condition set, but got " << base::Value::GetTypeName(condition_set.type()); - return; + break; } auto* url_conditions = condition_set.FindKeyOfType( kHeuristicUrlConditionSetKey, base::Value::Type::DICTIONARY); if (!url_conditions) { - VLOG(1) << "Condition dict did not contain a value for 'conditionSet'"; - return; + LOG(ERROR) + << "Condition dict did not contain a value for 'conditionSet'"; + break; } std::string error; - condition_sets.emplace_back( + temp_condition_set.emplace_back( url_matcher::URLMatcherFactory::CreateFromURLFilterDictionary( url_matcher_->condition_factory(), url_conditions->GetDict(), next_condition_set_id, &error)); if (!error.empty()) { - VLOG(1) << "Error parsing url conditions: " << error; - return; + LOG(ERROR) << "Error parsing url conditions: " << error; + break; } mapping.insert( std::make_pair(next_condition_set_id++, HeuristicConfigEntry(config->GetIntent(), config->GetDenylistedDomains()))); } + + if (overall_condition_set.size() + temp_condition_set.size() != + mapping.size()) { + LOG(ERROR) << "Condition set for " << config->GetIntent() + << " included invalid conditions, skipping"; + continue; + } + overall_condition_set.insert(overall_condition_set.end(), + temp_condition_set.begin(), + temp_condition_set.end()); } - VLOG(2) << "Read " << condition_sets.size() << " condition sets from " - << configs.size() << " configs."; - url_matcher_->AddConditionSets(condition_sets); + url_matcher_->AddConditionSets(overall_condition_set); + // Necessary to clean up condition sets that failed to parse. + url_matcher_->ClearUnusedConditionSets(); matcher_id_to_config_map_ = std::move(mapping); + VLOG(2) << "Read " << overall_condition_set.size() << " condition sets for " + << matcher_id_to_config_map_.size() << " intents"; } bool StarterHeuristic::HasConditionSets() const {
diff --git a/components/autofill_assistant/browser/starter_heuristic_unittest.cc b/components/autofill_assistant/browser/starter_heuristic_unittest.cc index bbfc664..c98dfbc9 100644 --- a/components/autofill_assistant/browser/starter_heuristic_unittest.cc +++ b/components/autofill_assistant/browser/starter_heuristic_unittest.cc
@@ -231,6 +231,69 @@ IsEmpty()); } +TEST_F(StarterHeuristicTest, + ConfigsContainingInvalidConditionSetsAreSilentlySkipped) { + auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>(); + scoped_feature_list->InitWithFeaturesAndParameters( + {{features::kAutofillAssistantUrlHeuristic1, {{"json_parameters", R"json( + { + "intent":"NEW_INTENT_A", + "heuristics":[ + { + "conditionSet":{ + "### INVALID ###":"whatever" + } + }, + { + "conditionSet":{ + "urlContains":"trigger-for-a" + } + } + ], + "enabledInCustomTabs":true + } + )json"}}}, + {features::kAutofillAssistantUrlHeuristic2, {{"json_parameters", R"json( + { + "intent":"NEW_INTENT_B", + "heuristics":[ + { + "conditionSet":{ + "urlContains":"trigger-for-b" + } + } + ], + "enabledInCustomTabs":true + } + )json"}}}}, + /* disabled_features = */ {}); + + FinchStarterHeuristicConfig finch_config_1{base::FeatureParam<std::string>{ + &features::kAutofillAssistantUrlHeuristic1, "json_parameters", ""}}; + FinchStarterHeuristicConfig finch_config_2{base::FeatureParam<std::string>{ + &features::kAutofillAssistantUrlHeuristic2, "json_parameters", ""}}; + std::vector<const StarterHeuristicConfig*> configs{&finch_config_1, + &finch_config_2}; + auto starter_heuristic = base::MakeRefCounted<StarterHeuristic>(); + fake_platform_delegate_.is_custom_tab_ = true; + fake_platform_delegate_.is_web_layer_ = false; + starter_heuristic->InitFromHeuristicConfigs(configs, &fake_platform_delegate_, + &context_); + + // config for NEW_INTENT_A contains both valid and invalid conditions and + // should be skipped entirely. + EXPECT_THAT( + IsHeuristicMatchForTest(*starter_heuristic, + GURL("https://www.example.com/trigger-for-a")), + IsEmpty()); + + // config for NEW_INTENT_B is valid and should thus work. + EXPECT_THAT( + IsHeuristicMatchForTest(*starter_heuristic, + GURL("https://www.example.com/trigger-for-b")), + ElementsAre("NEW_INTENT_B")); +} + TEST_F(StarterHeuristicTest, MultipleUrlHeuristicTrials) { auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>(); scoped_feature_list->InitWithFeaturesAndParameters(
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json index 0c87b3e..88f3d6d 100644 --- a/components/certificate_transparency/data/log_list.json +++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@ { - "version": "11.21", - "log_list_timestamp": "2022-09-13T12:55:50Z", + "version": "11.22", + "log_list_timestamp": "2022-09-14T12:54:52Z", "operators": [ { "name": "Google",
diff --git a/components/password_manager/core/browser/import/password_importer.cc b/components/password_manager/core/browser/import/password_importer.cc index cec4d3c..3f7bd791 100644 --- a/components/password_manager/core/browser/import/password_importer.cc +++ b/components/password_manager/core/browser/import/password_importer.cc
@@ -54,12 +54,12 @@ ImportEntry::Status ToImportEntryStatus( SavedPasswordsPresenter::AddResult add_result) { switch (add_result) { - case SavedPasswordsPresenter::AddResult::kExistsInProfileStore: + case SavedPasswordsPresenter::AddResult::kConflictInProfileStore: return ImportEntry::Status::CONFLICT_PROFILE; - case SavedPasswordsPresenter::AddResult::kExistsInAccountStore: + case SavedPasswordsPresenter::AddResult::kConflictInAccountStore: // We report a double collision for now as a collision in account store. - case SavedPasswordsPresenter::AddResult::kExistsInProfileAndAccountStore: + case SavedPasswordsPresenter::AddResult::kConflictInProfileAndAccountStore: return ImportEntry::Status::CONFLICT_ACCOUNT; case SavedPasswordsPresenter::AddResult::kInvalid: @@ -72,10 +72,15 @@ return ImportEntry::Status::UNKNOWN_ERROR; } +bool IsSuccessOrExactMatch(const SavedPasswordsPresenter::AddResult& status) { + return status == SavedPasswordsPresenter::AddResult::kSuccess || + status == SavedPasswordsPresenter::AddResult::kExactMatch; +} + ImportEntry CreateFailedImportEntry( SavedPasswordsPresenter::AddResult add_result, const CredentialUIEntry& credential) { - DCHECK_NE(add_result, SavedPasswordsPresenter::AddResult::kSuccess); + DCHECK(!IsSuccessOrExactMatch(add_result)); ImportEntry result; result.url = credential.url.possibly_invalid_spec(); result.username = base::UTF16ToUTF8(credential.username); @@ -140,9 +145,9 @@ const std::vector<SavedPasswordsPresenter::AddResult>& add_results) { import_results.number_imported = 0; for (size_t i = 0; i < add_results.size(); i++) { - if (add_results[i] == SavedPasswordsPresenter::AddResult::kSuccess) + if (IsSuccessOrExactMatch(add_results[i])) { import_results.number_imported++; - else { + } else { import_results.failed_imports.emplace_back( CreateFailedImportEntry(add_results[i], credentials[i])); }
diff --git a/components/password_manager/core/browser/import/password_importer_unittest.cc b/components/password_manager/core/browser/import/password_importer_unittest.cc index ae90220..5ea98f3 100644 --- a/components/password_manager/core/browser/import/password_importer_unittest.cc +++ b/components/password_manager/core/browser/import/password_importer_unittest.cc
@@ -194,6 +194,139 @@ EXPECT_EQ(ImportResults::Status::BAD_FORMAT, results.status); } +TEST_F(PasswordImporterTest, CSVImportExactMatchProfileStore) { + constexpr char kTestCSVInput[] = + "Url,Username,Password\n" + "https://" + "test.com,username_exists_in_profile_store,password_already_stored\n"; + + PasswordForm form_profile_store; + form_profile_store.url = GURL("https://test.com"); + form_profile_store.signon_realm = form_profile_store.url.spec(); + form_profile_store.username_value = u"username_exists_in_profile_store"; + form_profile_store.password_value = u"password_already_stored"; + form_profile_store.in_store = + password_manager::PasswordForm::Store::kProfileStore; + + ASSERT_TRUE(AddPasswordForm(form_profile_store)); + + base::HistogramTester histogram_tester; + + base::FilePath input_path = + temp_directory_.GetPath().AppendASCII(kTestFileName); + ASSERT_EQ(static_cast<int>(strlen(kTestCSVInput)), + base::WriteFile(input_path, kTestCSVInput, strlen(kTestCSVInput))); + ASSERT_NO_FATAL_FAILURE(StartImportAndWaitForCompletion(input_path)); + + histogram_tester.ExpectUniqueSample("PasswordManager.ImportResultsStatus", + ImportResults::Status::SUCCESS, 1); + histogram_tester.ExpectTotalCount("PasswordManager.ImportDuration", 1); + histogram_tester.ExpectUniqueSample( + "PasswordManager.ImportedPasswordsPerUserInCSV", 1, 1); + + const password_manager::ImportResults& results = GetImportResults(); + + ASSERT_EQ(0u, results.failed_imports.size()); + + EXPECT_EQ(1u, results.number_imported); + ASSERT_EQ(1u, stored_passwords().size()); + EXPECT_EQ(GURL("https://test.com"), stored_passwords()[0].url); + EXPECT_EQ(u"username_exists_in_profile_store", + stored_passwords()[0].username); + EXPECT_EQ(u"password_already_stored", stored_passwords()[0].password); +} + +TEST_F(PasswordImporterTest, CSVImportExactMatchAccountStore) { + constexpr char kTestCSVInput[] = + "Url,Username,Password\n" + "https://" + "test.com,username_exists_in_account_store,password_already_stored\n"; + + PasswordForm form_profile_store; + form_profile_store.url = GURL("https://test.com"); + form_profile_store.signon_realm = form_profile_store.url.spec(); + form_profile_store.username_value = u"username_exists_in_account_store"; + form_profile_store.password_value = u"password_already_stored"; + form_profile_store.in_store = + password_manager::PasswordForm::Store::kAccountStore; + + ASSERT_TRUE(AddPasswordForm(form_profile_store)); + + base::HistogramTester histogram_tester; + + base::FilePath input_path = + temp_directory_.GetPath().AppendASCII(kTestFileName); + ASSERT_EQ(static_cast<int>(strlen(kTestCSVInput)), + base::WriteFile(input_path, kTestCSVInput, strlen(kTestCSVInput))); + ASSERT_NO_FATAL_FAILURE(StartImportAndWaitForCompletion(input_path)); + + histogram_tester.ExpectUniqueSample("PasswordManager.ImportResultsStatus", + ImportResults::Status::SUCCESS, 1); + histogram_tester.ExpectTotalCount("PasswordManager.ImportDuration", 1); + histogram_tester.ExpectUniqueSample( + "PasswordManager.ImportedPasswordsPerUserInCSV", 1, 1); + + const password_manager::ImportResults& results = GetImportResults(); + + ASSERT_EQ(0u, results.failed_imports.size()); + + EXPECT_EQ(1u, results.number_imported); + ASSERT_EQ(1u, stored_passwords().size()); + EXPECT_EQ(GURL("https://test.com"), stored_passwords()[0].url); + EXPECT_EQ(u"username_exists_in_account_store", + stored_passwords()[0].username); + EXPECT_EQ(u"password_already_stored", stored_passwords()[0].password); +} + +TEST_F(PasswordImporterTest, CSVImportExactMatchProfileAndAccountStore) { + constexpr char kTestCSVInput[] = + "Url,Username,Password\n" + "https://" + "test.com,username_exists_in_profile_and_account_store,password_already_" + "stored\n" + "https://test2.com,username2,password2\n"; + + PasswordForm form_account_profile_store; + form_account_profile_store.url = GURL("https://test.com"); + form_account_profile_store.signon_realm = + form_account_profile_store.url.spec(); + form_account_profile_store.username_value = + u"username_exists_in_profile_and_account_store"; + form_account_profile_store.password_value = u"password_already_stored"; + + AddToProfileAndAccountStores(std::move(form_account_profile_store)); + + base::HistogramTester histogram_tester; + + base::FilePath input_path = + temp_directory_.GetPath().AppendASCII(kTestFileName); + ASSERT_EQ(static_cast<int>(strlen(kTestCSVInput)), + base::WriteFile(input_path, kTestCSVInput, strlen(kTestCSVInput))); + ASSERT_NO_FATAL_FAILURE(StartImportAndWaitForCompletion( + input_path, password_manager::PasswordForm::Store::kAccountStore)); + + histogram_tester.ExpectUniqueSample("PasswordManager.ImportResultsStatus", + ImportResults::Status::SUCCESS, 1); + histogram_tester.ExpectTotalCount("PasswordManager.ImportDuration", 1); + histogram_tester.ExpectUniqueSample( + "PasswordManager.ImportedPasswordsPerUserInCSV", 2, 1); + + const password_manager::ImportResults& results = GetImportResults(); + + ASSERT_EQ(0u, results.failed_imports.size()); + + EXPECT_EQ(password_manager::ImportResults::Status::SUCCESS, results.status); + EXPECT_EQ(2u, results.number_imported); + ASSERT_EQ(2u, stored_passwords().size()); + EXPECT_EQ(GURL("https://test.com"), stored_passwords()[0].url); + EXPECT_EQ(u"username_exists_in_profile_and_account_store", + stored_passwords()[0].username); + EXPECT_EQ(u"password_already_stored", stored_passwords()[0].password); + EXPECT_EQ(GURL("https://test2.com"), stored_passwords()[1].url); + EXPECT_EQ(u"username2", stored_passwords()[1].username); + EXPECT_EQ(u"password2", stored_passwords()[1].password); +} + TEST_F(PasswordImporterTest, CSVImportConflictProfileStore) { constexpr char kTestCSVInput[] = "Url,Username,Password\n" @@ -204,7 +337,7 @@ form_profile_store.url = GURL("https://test.com"); form_profile_store.signon_realm = form_profile_store.url.spec(); form_profile_store.username_value = u"username_exists_in_profile_store"; - form_profile_store.password_value = u"password1"; + form_profile_store.password_value = u"password_does_not_match"; form_profile_store.in_store = password_manager::PasswordForm::Store::kProfileStore; @@ -245,14 +378,14 @@ TEST_F(PasswordImporterTest, CSVImportConflictAccountStore) { constexpr char kTestCSVInput[] = "Url,Username,Password\n" - "https://test.com,username_exists_in_profile_store,password1\n" + "https://test.com,username_exists_in_account_store,password1\n" "https://test2.com,username2,password2\n"; PasswordForm form_profile_store; form_profile_store.url = GURL("https://test.com"); form_profile_store.signon_realm = form_profile_store.url.spec(); - form_profile_store.username_value = u"username_exists_in_profile_store"; - form_profile_store.password_value = u"password1"; + form_profile_store.username_value = u"username_exists_in_account_store"; + form_profile_store.password_value = u"password_does_not_match"; form_profile_store.in_store = password_manager::PasswordForm::Store::kAccountStore; @@ -279,7 +412,7 @@ ASSERT_EQ(1u, results.failed_imports.size()); EXPECT_EQ("https://test.com/", results.failed_imports[0].url); - EXPECT_EQ("username_exists_in_profile_store", + EXPECT_EQ("username_exists_in_account_store", results.failed_imports[0].username); EXPECT_EQ(password_manager::ImportEntry::Status::CONFLICT_ACCOUNT, results.failed_imports[0].status); @@ -305,7 +438,7 @@ form_account_profile_store.url.spec(); form_account_profile_store.username_value = u"username_exists_in_profile_and_account_store"; - form_account_profile_store.password_value = u"password1"; + form_account_profile_store.password_value = u"password_does_not_match"; AddToProfileAndAccountStores(std::move(form_account_profile_store));
diff --git a/components/password_manager/core/browser/password_reuse_manager_impl.cc b/components/password_manager/core/browser/password_reuse_manager_impl.cc index e3c3d70..7da675c 100644 --- a/components/password_manager/core/browser/password_reuse_manager_impl.cc +++ b/components/password_manager/core/browser/password_reuse_manager_impl.cc
@@ -5,12 +5,17 @@ #include "components/password_manager/core/browser/password_reuse_manager_impl.h" #include "base/bind.h" +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" #include "base/task/thread_pool.h" #include "components/password_manager/core/browser/password_store_signin_notifier.h" #include "components/password_manager/core/common/password_manager_features.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" +using base::RecordAction; +using base::UserMetricsAction; + namespace password_manager { namespace { @@ -184,6 +189,8 @@ bool is_primary_account, GaiaPasswordHashChange event) { DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); + RecordAction( + UserMetricsAction("PasswordProtection.Gaia.HashedPasswordSaved")); SaveProtectedPasswordHash(username, password, is_primary_account, /*is_gaia_password=*/true, event); } @@ -192,6 +199,8 @@ const std::string& username, const std::u16string& password) { DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); + RecordAction(UserMetricsAction( + "PasswordProtection.NonGaiaEnterprise.HashedPasswordSaved")); SaveProtectedPasswordHash( username, password, /*is_primary_account=*/false, /*is_gaia_password=*/false,
diff --git a/components/password_manager/core/browser/ui/saved_passwords_presenter.cc b/components/password_manager/core/browser/ui/saved_passwords_presenter.cc index cc3aee2..98de90b 100644 --- a/components/password_manager/core/browser/ui/saved_passwords_presenter.cc +++ b/components/password_manager/core/browser/ui/saved_passwords_presenter.cc
@@ -210,19 +210,29 @@ entry.IsUsingAccountStore(); }; - bool existing_password_profile = base::ranges::any_of( + bool existing_credential_profile = base::ranges::any_of( passwords_, have_equal_username_and_realm_in_profile_store); - bool existing_password_account = base::ranges::any_of( + bool existing_credential_account = base::ranges::any_of( passwords_, have_equal_username_and_realm_in_account_store); - if (!existing_password_profile && !existing_password_account) + if (!existing_credential_profile && !existing_credential_account) return AddResult::kSuccess; - if (existing_password_profile && !existing_password_account) - return AddResult::kExistsInProfileStore; - if (existing_password_account && !existing_password_profile) - return AddResult::kExistsInAccountStore; - return AddResult::kExistsInProfileAndAccountStore; + auto have_exact_match = + [&credential, &have_equal_username_and_realm](const PasswordForm& entry) { + return have_equal_username_and_realm(entry) && + credential.password == entry.password_value; + }; + + if (base::ranges::any_of(passwords_, have_exact_match)) + return AddResult::kExactMatch; + + if (!existing_credential_profile) + return AddResult::kConflictInAccountStore; + if (!existing_credential_account) + return AddResult::kConflictInProfileStore; + + return AddResult::kConflictInProfileAndAccountStore; } void SavedPasswordsPresenter::AddCredentialAsync(
diff --git a/components/password_manager/core/browser/ui/saved_passwords_presenter.h b/components/password_manager/core/browser/ui/saved_passwords_presenter.h index a7acece..000e75d 100644 --- a/components/password_manager/core/browser/ui/saved_passwords_presenter.h +++ b/components/password_manager/core/browser/ui/saved_passwords_presenter.h
@@ -79,13 +79,19 @@ kSuccess, // Credential is invalid. kInvalid, - // Credential already exists in the profile store. - kExistsInProfileStore, - // Credential already exists in the account store. - kExistsInAccountStore, - // Credential already exists in the profile and account store. - kExistsInProfileAndAccountStore, - kMaxValue = kExistsInProfileAndAccountStore, + // Credential (with the same username, realm, and password) already exists + // in the profile or/and account store. + kExactMatch, + // Credential with the same username and realm already exists in the profile + // store. + kConflictInProfileStore, + // Credential with the same username and realm already exists in the account + // store. + kConflictInAccountStore, + // Credential with the same username and realm already exists in both + // profile and account stores. + kConflictInProfileAndAccountStore, + kMaxValue = kConflictInProfileAndAccountStore, }; using AddCredentialsCallback =
diff --git a/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc b/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc index 05e3840..389cf189 100644 --- a/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc +++ b/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc
@@ -966,10 +966,101 @@ presenter().RemoveObserver(&observer); } +// Tests whether adding 2 credentials with 1 that has same username and realm in +// the profile store fails with the correct response. +TEST_F(SavedPasswordsPresenterWithTwoStoresTest, + AddCredentialsListTwoPasswordOneConflictsProfileStore) { + PasswordForm existing_profile_form = + CreateTestPasswordForm(PasswordForm::Store::kProfileStore, /*index=*/0); + PasswordForm new_profile_form = + CreateTestPasswordForm(PasswordForm::Store::kProfileStore, /*index=*/1); + + profile_store().AddLogin(existing_profile_form); + RunUntilIdle(); + + PasswordForm conflicting_profile_form = existing_profile_form; + conflicting_profile_form.password_value = u"abc"; + + base::MockCallback<SavedPasswordsPresenter::AddCredentialsCallback> + completion_callback; + + presenter().AddCredentials({CredentialUIEntry(conflicting_profile_form), + CredentialUIEntry(new_profile_form)}, + password_manager::PasswordForm::Type::kImported, + completion_callback.Get()); + EXPECT_CALL(completion_callback, + Run(std::vector<SavedPasswordsPresenter::AddResult>{ + SavedPasswordsPresenter::AddResult::kConflictInProfileStore, + SavedPasswordsPresenter::AddResult::kSuccess})); + RunUntilIdle(); +} + +// Tests whether adding whether adding 2 credentials with 1 that has same +// username and realm in the account store fails with the correct response. +TEST_F(SavedPasswordsPresenterWithTwoStoresTest, + AddCredentialsListTwoPasswordOneConflictsAccountStore) { + PasswordForm existing_account_form = + CreateTestPasswordForm(PasswordForm::Store::kAccountStore, /*index=*/0); + PasswordForm new_account_form = + CreateTestPasswordForm(PasswordForm::Store::kAccountStore, /*index=*/1); + + account_store().AddLogin(existing_account_form); + RunUntilIdle(); + + PasswordForm conflicting_account_form = existing_account_form; + conflicting_account_form.password_value = u"abc"; + + base::MockCallback<SavedPasswordsPresenter::AddCredentialsCallback> + completion_callback; + presenter().AddCredentials({CredentialUIEntry(conflicting_account_form), + CredentialUIEntry(new_account_form)}, + password_manager::PasswordForm::Type::kImported, + completion_callback.Get()); + EXPECT_CALL(completion_callback, + Run(std::vector<SavedPasswordsPresenter::AddResult>{ + SavedPasswordsPresenter::AddResult::kConflictInAccountStore, + SavedPasswordsPresenter::AddResult::kSuccess})); + RunUntilIdle(); +} + +// Tests whether adding 2 credentials with 1 that has same username and realm in +// both profile and account store fails with the correct response. +TEST_F(SavedPasswordsPresenterWithTwoStoresTest, + AddCredentialsListTwoPasswordOneConflictsProfileAndAccountStore) { + PasswordForm existing_profile_form = + CreateTestPasswordForm(PasswordForm::Store::kProfileStore, /*index=*/0); + + PasswordForm existing_account_form = + CreateTestPasswordForm(PasswordForm::Store::kAccountStore, /*index=*/0); + + PasswordForm new_profile_form = + CreateTestPasswordForm(PasswordForm::Store::kProfileStore, /*index=*/1); + + profile_store().AddLogin(existing_profile_form); + account_store().AddLogin(existing_account_form); + RunUntilIdle(); + + PasswordForm conflicting_profile_form = existing_profile_form; + conflicting_profile_form.password_value = u"abc"; + + base::MockCallback<SavedPasswordsPresenter::AddCredentialsCallback> + completion_callback; + presenter().AddCredentials({CredentialUIEntry(conflicting_profile_form), + CredentialUIEntry(new_profile_form)}, + password_manager::PasswordForm::Type::kImported, + completion_callback.Get()); + EXPECT_CALL( + completion_callback, + Run(std::vector<SavedPasswordsPresenter::AddResult>{ + SavedPasswordsPresenter::AddResult::kConflictInProfileAndAccountStore, + SavedPasswordsPresenter::AddResult::kSuccess})); + RunUntilIdle(); +} + // Tests whether adding 2 passwords with 1 that already exists in the profile // store fails with the correct response. TEST_F(SavedPasswordsPresenterWithTwoStoresTest, - AddCredentialsListTwoPasswordOneConflictsProfileStore) { + AddCredentialsListTwoPasswordOneExactMatchProfileStore) { PasswordForm existing_profile_form = CreateTestPasswordForm(PasswordForm::Store::kProfileStore, /*index=*/0); PasswordForm new_profile_form = @@ -987,7 +1078,7 @@ completion_callback.Get()); EXPECT_CALL(completion_callback, Run(std::vector<SavedPasswordsPresenter::AddResult>{ - SavedPasswordsPresenter::AddResult::kExistsInProfileStore, + SavedPasswordsPresenter::AddResult::kExactMatch, SavedPasswordsPresenter::AddResult::kSuccess})); RunUntilIdle(); } @@ -995,7 +1086,7 @@ // Tests whether adding whether adding 2 passwords with 1 that already exists in // the account store fails with the correct response. TEST_F(SavedPasswordsPresenterWithTwoStoresTest, - AddCredentialsListTwoPasswordOneConflictsAccountStore) { + AddCredentialsListTwoPasswordOneExactMatchAccountStore) { PasswordForm existing_account_form = CreateTestPasswordForm(PasswordForm::Store::kAccountStore, /*index=*/0); PasswordForm new_account_form = @@ -1012,7 +1103,7 @@ completion_callback.Get()); EXPECT_CALL(completion_callback, Run(std::vector<SavedPasswordsPresenter::AddResult>{ - SavedPasswordsPresenter::AddResult::kExistsInAccountStore, + SavedPasswordsPresenter::AddResult::kExactMatch, SavedPasswordsPresenter::AddResult::kSuccess})); RunUntilIdle(); } @@ -1020,7 +1111,7 @@ // Tests whether adding 2 passwords with 1 that already exists in both profile // and account store fails with the correct response. TEST_F(SavedPasswordsPresenterWithTwoStoresTest, - AddCredentialsListTwoPasswordOneConflictsProfileAndAccountStore) { + AddCredentialsListTwoPasswordOneExactMatchProfileAndAccountStore) { PasswordForm existing_profile_form = CreateTestPasswordForm(PasswordForm::Store::kProfileStore, /*index=*/0); PasswordForm existing_account_form = @@ -1039,11 +1130,10 @@ CredentialUIEntry(new_profile_form)}, password_manager::PasswordForm::Type::kImported, completion_callback.Get()); - EXPECT_CALL( - completion_callback, - Run(std::vector<SavedPasswordsPresenter::AddResult>{ - SavedPasswordsPresenter::AddResult::kExistsInProfileAndAccountStore, - SavedPasswordsPresenter::AddResult::kSuccess})); + EXPECT_CALL(completion_callback, + Run(std::vector<SavedPasswordsPresenter::AddResult>{ + SavedPasswordsPresenter::AddResult::kExactMatch, + SavedPasswordsPresenter::AddResult::kSuccess})); RunUntilIdle(); } @@ -1550,7 +1640,6 @@ PasswordForm expected_account_store_form = expected_profile_store_form; expected_account_store_form.in_store = PasswordForm::Store::kAccountStore; - EXPECT_THAT(profile_store().stored_passwords(), ElementsAre(Pair(profile_store_form.signon_realm, ElementsAre(expected_profile_store_form))));
diff --git a/components/password_manager/ios/account_select_fill_data.cc b/components/password_manager/ios/account_select_fill_data.cc index 2e1e156..2079376d 100644 --- a/components/password_manager/ios/account_select_fill_data.cc +++ b/components/password_manager/ios/account_select_fill_data.cc
@@ -29,8 +29,8 @@ AccountSelectFillData::AccountSelectFillData() = default; AccountSelectFillData::~AccountSelectFillData() = default; -void AccountSelectFillData::Add( - const autofill::PasswordFormFillData& form_data) { +void AccountSelectFillData::Add(const autofill::PasswordFormFillData& form_data, + bool is_cross_origin_iframe) { auto iter_ok = forms_.insert( std::make_pair(form_data.form_renderer_id.value(), FormInfo())); FormInfo& form_info = iter_ok.first->second; @@ -43,15 +43,22 @@ // the latest known credentials, since credentials can be updated between // loading of different forms. credentials_.clear(); - credentials_.push_back({form_data.username_field.value, - form_data.password_field.value, - form_data.preferred_realm}); + + credentials_.push_back( + {form_data.username_field.value, form_data.password_field.value, + is_cross_origin_iframe && form_data.preferred_realm.empty() + ? form_data.url.spec() + : form_data.preferred_realm}); for (const auto& username_password_and_realm : form_data.additional_logins) { const std::u16string& username = username_password_and_realm.username; const std::u16string& password = username_password_and_realm.password; const std::string& realm = username_password_and_realm.realm; - credentials_.push_back({username, password, realm}); + if (is_cross_origin_iframe && realm.empty()) { + credentials_.push_back({username, password, form_data.url.spec()}); + } else { + credentials_.push_back({username, password, realm}); + } } }
diff --git a/components/password_manager/ios/account_select_fill_data.h b/components/password_manager/ios/account_select_fill_data.h index f5b21779..916ce99 100644 --- a/components/password_manager/ios/account_select_fill_data.h +++ b/components/password_manager/ios/account_select_fill_data.h
@@ -77,7 +77,8 @@ // Adds form structure from |form_data| to internal lists of known forms and // overrides known credentials with credentials from |form_data|. So only the // credentials from the latest |form_data| will be shown to the user. - void Add(const autofill::PasswordFormFillData& form_data); + void Add(const autofill::PasswordFormFillData& form_data, + bool is_cross_origin_iframe); void Reset(); bool Empty() const;
diff --git a/components/password_manager/ios/account_select_fill_data_unittest.cc b/components/password_manager/ios/account_select_fill_data_unittest.cc index a96f0a5..054b2b2 100644 --- a/components/password_manager/ios/account_select_fill_data_unittest.cc +++ b/components/password_manager/ios/account_select_fill_data_unittest.cc
@@ -53,7 +53,7 @@ AccountSelectFillData account_select_fill_data; EXPECT_TRUE(account_select_fill_data.Empty()); - account_select_fill_data.Add(form_data_[0]); + account_select_fill_data.Add(form_data_[0], /*is_cross_origin_iframe=*/false); EXPECT_FALSE(account_select_fill_data.Empty()); account_select_fill_data.Reset(); @@ -62,7 +62,7 @@ TEST_F(AccountSelectFillDataTest, IsSuggestionsAvailableOneForm) { AccountSelectFillData account_select_fill_data; - account_select_fill_data.Add(form_data_[0]); + account_select_fill_data.Add(form_data_[0], /*is_cross_origin_iframe=*/false); // Suggestions are available for the correct form and field ids. EXPECT_TRUE(account_select_fill_data.IsSuggestionsAvailable( @@ -87,8 +87,8 @@ TEST_F(AccountSelectFillDataTest, IsSuggestionsAvailableTwoForms) { AccountSelectFillData account_select_fill_data; - account_select_fill_data.Add(form_data_[0]); - account_select_fill_data.Add(form_data_[1]); + account_select_fill_data.Add(form_data_[0], /*is_cross_origin_iframe=*/false); + account_select_fill_data.Add(form_data_[1], /*is_cross_origin_iframe=*/false); // Suggestions are available for the correct form and field names. EXPECT_TRUE(account_select_fill_data.IsSuggestionsAvailable( @@ -106,7 +106,7 @@ TEST_F(AccountSelectFillDataTest, RetrieveSuggestionsOneForm) { AccountSelectFillData account_select_fill_data; - account_select_fill_data.Add(form_data_[0]); + account_select_fill_data.Add(form_data_[0], /*is_cross_origin_iframe=*/false); for (bool is_password_field : {false, true}) { const FieldRendererId field_id = @@ -130,8 +130,8 @@ // emulates the case when credentials in the Password Store were changed // between load the first and the second forms. AccountSelectFillData account_select_fill_data; - account_select_fill_data.Add(form_data_[0]); - account_select_fill_data.Add(form_data_[1]); + account_select_fill_data.Add(form_data_[0], /*is_cross_origin_iframe=*/false); + account_select_fill_data.Add(form_data_[1], /*is_cross_origin_iframe=*/false); std::vector<UsernameAndRealm> suggestions = account_select_fill_data.RetrieveSuggestions( @@ -156,7 +156,7 @@ form_data_[0].preferred_realm = kRealm; form_data_[0].additional_logins.begin()->realm = kAdditionalRealm; - account_select_fill_data.Add(form_data_[0]); + account_select_fill_data.Add(form_data_[0], /*is_cross_origin_iframe=*/false); std::vector<UsernameAndRealm> suggestions = account_select_fill_data.RetrieveSuggestions( form_data_[0].form_renderer_id, @@ -171,8 +171,8 @@ TEST_F(AccountSelectFillDataTest, GetFillData) { AccountSelectFillData account_select_fill_data; - account_select_fill_data.Add(form_data_[0]); - account_select_fill_data.Add(form_data_[1]); + account_select_fill_data.Add(form_data_[0], /*is_cross_origin_iframe=*/false); + account_select_fill_data.Add(form_data_[1], /*is_cross_origin_iframe=*/false); for (bool is_password_field : {false, true}) { for (size_t form_i = 0; form_i < std::size(form_data_); ++form_i) { @@ -209,8 +209,8 @@ TEST_F(AccountSelectFillDataTest, GetFillDataOldCredentials) { AccountSelectFillData account_select_fill_data; - account_select_fill_data.Add(form_data_[0]); - account_select_fill_data.Add(form_data_[1]); + account_select_fill_data.Add(form_data_[0], /*is_cross_origin_iframe=*/false); + account_select_fill_data.Add(form_data_[1], /*is_cross_origin_iframe=*/false); // GetFillData() doesn't have form identifier in arguments, it should be // provided in RetrieveSuggestions(). @@ -225,4 +225,21 @@ EXPECT_FALSE(fill_data); } +TEST_F(AccountSelectFillDataTest, CrossOriginSuggestionHasRealm) { + AccountSelectFillData account_select_fill_data; + account_select_fill_data.Add(form_data_[0], /*is_cross_origin_iframe=*/true); + + for (bool is_password_field : {false, true}) { + const FieldRendererId field_id = + is_password_field ? form_data_[0].password_field.unique_renderer_id + : form_data_[0].username_field.unique_renderer_id; + std::vector<UsernameAndRealm> suggestions = + account_select_fill_data.RetrieveSuggestions( + form_data_[0].form_renderer_id, field_id, is_password_field); + EXPECT_EQ(2u, suggestions.size()); + EXPECT_EQ(kUrl, suggestions[0].realm); + EXPECT_EQ(kUrl, suggestions[1].realm); + } +} + } // namespace
diff --git a/components/password_manager/ios/password_manager_ios_util.h b/components/password_manager/ios/password_manager_ios_util.h index b56fb47e..136050b 100644 --- a/components/password_manager/ios/password_manager_ios_util.h +++ b/components/password_manager/ios/password_manager_ios_util.h
@@ -10,6 +10,7 @@ #include "url/gurl.h" namespace web { +class WebFrame; class WebState; } @@ -29,6 +30,9 @@ autofill::FormData* form_data, GURL page_url); +// Returns whether an iframe is cross-origin. +bool IsCrossOriginIframe(web::WebState* web_state, web::WebFrame* web_frame); + } // namespace password_manager #endif // COMPONENTS_PASSWORD_MANAGER_IOS_PASSWORD_MANAGER_IOS_UTIL_H_
diff --git a/components/password_manager/ios/password_manager_ios_util.mm b/components/password_manager/ios/password_manager_ios_util.mm index dd805b5..4185e1f 100644 --- a/components/password_manager/ios/password_manager_ios_util.mm +++ b/components/password_manager/ios/password_manager_ios_util.mm
@@ -57,4 +57,10 @@ page_url.DeprecatedGetOriginAsURL(), form_data); } +bool IsCrossOriginIframe(web::WebState* web_state, web::WebFrame* web_frame) { + return !web_frame->IsMainFrame() && + !url::Origin::Create(web_state->GetLastCommittedURL()) + .IsSameOriginWith(web_frame->GetSecurityOrigin()); +} + } // namespace password_manager
diff --git a/components/password_manager/ios/password_suggestion_helper.h b/components/password_manager/ios/password_suggestion_helper.h index 4b2cb32..dd711bff 100644 --- a/components/password_manager/ios/password_suggestion_helper.h +++ b/components/password_manager/ios/password_suggestion_helper.h
@@ -49,6 +49,12 @@ // Delegate to receive callbacks. @property(nonatomic, weak) id<PasswordSuggestionHelperDelegate> delegate; +// Creates a instance with the given |webState|. +- (instancetype)initWithWebState:(web::WebState*)webState + NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + // Retrieves suggestions as username and realm pairs // (defined in |password_manager::UsernameAndRealm|) and converts // them into objective C representations. In the returned |FormSuggestion| @@ -67,7 +73,6 @@ // of other parameters. - (void)checkIfSuggestionsAvailableForForm: (FormSuggestionProviderQuery*)formQuery - webState:(web::WebState*)webState completionHandler: (SuggestionsAvailableCompletion)completion;
diff --git a/components/password_manager/ios/password_suggestion_helper.mm b/components/password_manager/ios/password_suggestion_helper.mm index f60e4c5c..838b942 100644 --- a/components/password_manager/ios/password_suggestion_helper.mm +++ b/components/password_manager/ios/password_suggestion_helper.mm
@@ -9,6 +9,7 @@ #import "components/autofill/ios/browser/form_suggestion.h" #include "components/password_manager/core/browser/password_ui_utils.h" #include "components/password_manager/ios/account_select_fill_data.h" +#import "components/password_manager/ios/password_manager_ios_util.h" #include "ios/web/public/js_messaging/web_frame.h" #include "ios/web/public/js_messaging/web_frame_util.h" #import "ios/web/public/web_state.h" @@ -17,21 +18,24 @@ #error "This file requires ARC support." #endif -using autofill::FormData; -using autofill::PasswordFormFillData; -using autofill::FormRendererId; using autofill::FieldRendererId; +using autofill::FormData; +using autofill::FormRendererId; +using autofill::PasswordFormFillData; using base::SysNSStringToUTF16; using base::SysNSStringToUTF8; using base::SysUTF16ToNSString; using base::SysUTF8ToNSString; using password_manager::AccountSelectFillData; using password_manager::FillData; +using password_manager::IsCrossOriginIframe; typedef void (^PasswordSuggestionsAvailableCompletion)( const password_manager::AccountSelectFillData* __nullable); @implementation PasswordSuggestionHelper { + base::WeakPtr<web::WebState> _webState; + // The value of the map is a C++ interface to cache and retrieve password // suggestions. The interfaces are grouped by the frame of the form. base::flat_map<web::WebFrame*, std::unique_ptr<AccountSelectFillData>> @@ -50,9 +54,12 @@ PasswordSuggestionsAvailableCompletion _suggestionsAvailableCompletion; } -- (instancetype)init { +#pragma mark - Initialization + +- (instancetype)initWithWebState:(web::WebState*)webState { self = [super init]; if (self) { + _webState = webState->GetWeakPtr(); _sentPasswordFormToPasswordManager = NO; } return self; @@ -97,7 +104,6 @@ - (void)checkIfSuggestionsAvailableForForm: (FormSuggestionProviderQuery*)formQuery - webState:(web::WebState*)webState completionHandler: (SuggestionsAvailableCompletion)completion { // When password controller's -processWithPasswordFormFillData: is already @@ -106,8 +112,9 @@ // Otherwise, -suggestionHelperShouldTriggerFormExtraction: will be called // and |completion| will not be called until // -processWithPasswordFormFillData: is called. - web::WebFrame* frame = - web::GetWebFrameWithId(webState, SysNSStringToUTF8(formQuery.frameID)); + DCHECK(_webState.get()); + web::WebFrame* frame = web::GetWebFrameWithId( + _webState.get(), SysNSStringToUTF8(formQuery.frameID)); DCHECK(frame); BOOL isPasswordField = [formQuery isOnPasswordField]; @@ -159,7 +166,9 @@ fillData = it.first->second.get(); } - fillData->Add(formData); + DCHECK(_webState.get()); + fillData->Add(formData, IsCrossOriginIframe(_webState.get(), frame)); + _processedPasswordSuggestions = YES; if (_suggestionsAvailableCompletion) {
diff --git a/components/password_manager/ios/shared_password_controller.mm b/components/password_manager/ios/shared_password_controller.mm index e4f1595..357bb36 100644 --- a/components/password_manager/ios/shared_password_controller.mm +++ b/components/password_manager/ios/shared_password_controller.mm
@@ -71,6 +71,7 @@ using password_manager::AccountSelectFillData; using password_manager::FillData; using password_manager::GetPageURLAndCheckTrustLevel; +using password_manager::IsCrossOriginIframe; using password_manager::JsonStringToFormData; using password_manager::PasswordFormManagerForUI; using password_manager::PasswordGenerationFrameHelper; @@ -278,7 +279,8 @@ [self.formHelper setUpForUniqueIDsWithInitialState:nextAvailableRendererID inFrame:web_frame]; - if ([self isCrossOriginIframe:web_frame] && !canProcessCrossOriginIframes()) { + if (IsCrossOriginIframe(_webState, web_frame) && + !canProcessCrossOriginIframes()) { return; } @@ -300,7 +302,8 @@ return; } - if ([self isCrossOriginIframe:web_frame] && !canProcessCrossOriginIframes()) { + if (IsCrossOriginIframe(_webState, web_frame) && + !canProcessCrossOriginIframes()) { return; } @@ -351,14 +354,13 @@ // previous clicked field in the previous password form. Getting the frame // from this previous frame id will result in a null frame pointer, hence // the check below. - if (!frame || - ([self isCrossOriginIframe:frame] && !canProcessCrossOriginIframes())) { + if (!frame || (IsCrossOriginIframe(_webState, frame) && + !canProcessCrossOriginIframes())) { completion(NO); return; } [self.suggestionHelper checkIfSuggestionsAvailableForForm:formQuery - webState:webState completionHandler:^(BOOL suggestionsAvailable) { // Always display "Show All..." for password fields. completion([formQuery isOnPasswordField] || @@ -418,7 +420,8 @@ web::WebFrame* frame = web::GetWebFrameWithId(_webState, SysNSStringToUTF8(formQuery.frameID)); - if ([self isCrossOriginIframe:frame] && !canProcessCrossOriginIframes()) { + if (IsCrossOriginIframe(_webState, frame) && + !canProcessCrossOriginIframes()) { completion({}, self); return; } @@ -584,7 +587,8 @@ if (frame->IsMainFrame()) { _passwordManager->OnPasswordFormSubmitted(driver, form); } else { - if ([self isCrossOriginIframe:frame] && !canProcessCrossOriginIframes()) { + if (IsCrossOriginIframe(_webState, frame) && + !canProcessCrossOriginIframes()) { return; } // Show a save prompt immediately because for iframes it is very hard to @@ -861,12 +865,6 @@ return YES; } -- (BOOL)isCrossOriginIframe:(web::WebFrame*)webFrame { - return !webFrame->IsMainFrame() && - _webState->GetLastCommittedURL().DeprecatedGetOriginAsURL() != - webFrame->GetSecurityOrigin(); -} - #pragma mark - FormActivityObserver - (void)webState:(web::WebState*)webState @@ -877,7 +875,8 @@ GURL pageURL; if (!GetPageURLAndCheckTrustLevel(webState, &pageURL) || !frame || !frame->CanCallJavaScriptFunction() || params.input_missing || - ([self isCrossOriginIframe:frame] && !canProcessCrossOriginIframes())) { + (IsCrossOriginIframe(_webState, frame) && + !canProcessCrossOriginIframes())) { _lastFocusedFormIdentifier = FormRendererId(); _lastFocusedFieldIdentifier = FieldRendererId(); _lastFocusedFrame = nullptr; @@ -922,7 +921,8 @@ didRegisterFormRemoval:(const autofill::FormRemovalParams&)params inFrame:(web::WebFrame*)frame { DCHECK_EQ(_webState, webState); - if ([self isCrossOriginIframe:frame] && !canProcessCrossOriginIframes()) { + if (IsCrossOriginIframe(_webState, frame) && + !canProcessCrossOriginIframes()) { return; } if (!params.unique_form_id) {
diff --git a/components/password_manager/ios/shared_password_controller_unittest.mm b/components/password_manager/ios/shared_password_controller_unittest.mm index e2c5de9..eafac16 100644 --- a/components/password_manager/ios/shared_password_controller_unittest.mm +++ b/components/password_manager/ios/shared_password_controller_unittest.mm
@@ -179,6 +179,8 @@ auto web_frames_manager = std::make_unique<web::FakeWebFramesManager>(); web_frames_manager_ = web_frames_manager.get(); web_state_.SetWebFramesManager(std::move(web_frames_manager)); + + web_state_.SetCurrentURL(GURL(kTestURL)); } void SetUp() override { @@ -220,7 +222,7 @@ auto web_frame = web::FakeWebFrame::Create(SysNSStringToUTF8(kTestFrameID), - /*is_main_frame=*/true, GURL::EmptyGURL()); + /*is_main_frame=*/true, GURL(kTestURL)); web_frames_manager_->AddWebFrame(std::move(web_frame)); EXPECT_CALL(password_manager_, PropagateFieldDataManagerInfo); @@ -231,11 +233,12 @@ // Tests that forms are found, parsed, and sent to PasswordManager. TEST_F(SharedPasswordControllerTest, FormsArePropagatedOnHTMLPageLoad) { - web_state_.SetCurrentURL(GURL("https://www.chromium.org/")); + web_state_.SetCurrentURL(GURL(kTestURL)); web_state_.SetContentIsHTML(true); - auto web_frame = web::FakeWebFrame::Create("dummy-frame-id", - /*is_main_frame=*/true, GURL()); + auto web_frame = + web::FakeWebFrame::Create("dummy-frame-id", + /*is_main_frame=*/true, GURL(kTestURL)); web::WebFrame* frame = web_frame.get(); web_frames_manager_->AddWebFrame(std::move(web_frame)); [[[form_helper_ expect] ignoringNonObjectArgs] @@ -265,7 +268,7 @@ // Tests form finding and parsing is not triggered for non HTML pages. TEST_F(SharedPasswordControllerTest, NoFormsArePropagatedOnNonHTMLPageLoad) { - web_state_.SetCurrentURL(GURL("https://www.chromium.org/")); + web_state_.SetCurrentURL(GURL(kTestURL)); web_state_.SetContentIsHTML(false); auto web_frame = @@ -287,8 +290,9 @@ // Tests that new frames will trigger PasswordFormHelper to set up unique IDs. TEST_F(SharedPasswordControllerTest, FormHelperSetsUpUniqueIDsForNewFrame) { - auto web_frame = web::FakeWebFrame::Create("dummy-frame-id", - /*is_main_frame=*/true, GURL()); + auto web_frame = + web::FakeWebFrame::Create("dummy-frame-id", + /*is_main_frame=*/true, GURL(kTestURL)); [[[form_helper_ expect] ignoringNonObjectArgs] setUpForUniqueIDsWithInitialState:1 inFrame:web_frame.get()]; @@ -312,7 +316,7 @@ auto web_frame = web::FakeWebFrame::Create(SysNSStringToUTF8(kTestFrameID), - /*is_main_frame=*/false, GURL::EmptyGURL()); + /*is_main_frame=*/false, GURL(kTestURL)); web_frames_manager_->AddWebFrame(std::move(web_frame)); id mock_completion_handler = @@ -323,7 +327,6 @@ }]; [[suggestion_helper_ expect] checkIfSuggestionsAvailableForForm:form_query - webState:&web_state_ completionHandler:mock_completion_handler]; __block BOOL completion_was_called = NO; @@ -352,7 +355,7 @@ frameID:kTestFrameID]; auto web_frame = web::FakeWebFrame::Create(SysNSStringToUTF8(kTestFrameID), - /*is_main_frame=*/false, GURL::EmptyGURL()); + /*is_main_frame=*/false, GURL(kTestURL)); web::WebFrame* frame = web_frame.get(); web_frames_manager_->AddWebFrame(std::move(web_frame)); @@ -399,7 +402,7 @@ auto web_frame = web::FakeWebFrame::Create(SysNSStringToUTF8(kTestFrameID), - /*is_main_frame=*/false, GURL::EmptyGURL()); + /*is_main_frame=*/false, GURL(kTestURL)); web::WebFrame* frame = web_frame.get(); web_frames_manager_->AddWebFrame(std::move(web_frame)); @@ -442,7 +445,7 @@ auto web_frame = web::FakeWebFrame::Create(SysNSStringToUTF8(kTestFrameID), - /*is_main_frame=*/false, GURL::EmptyGURL()); + /*is_main_frame=*/false, GURL(kTestURL)); web::WebFrame* frame = web_frame.get(); web_frames_manager_->AddWebFrame(std::move(web_frame)); @@ -651,8 +654,8 @@ params.type = "focus"; params.input_missing = false; - auto web_frame = - web::FakeWebFrame::Create("frame-id", /*is_main_frame=*/true, GURL()); + auto web_frame = web::FakeWebFrame::Create("frame-id", /*is_main_frame=*/true, + GURL(kTestURL)); web::FakeWebFrame* frame = web_frame.get(); web_frames_manager_->AddWebFrame(std::move(web_frame)); @@ -698,8 +701,8 @@ params.type = "focus"; params.input_missing = true; - auto web_frame = - web::FakeWebFrame::Create("frame-id", /*is_main_frame=*/true, GURL()); + auto web_frame = web::FakeWebFrame::Create("frame-id", /*is_main_frame=*/true, + GURL(kTestURL)); [controller_ webState:&web_state_ didRegisterFormActivity:params @@ -731,8 +734,8 @@ return YES; }]; - auto web_frame = - web::FakeWebFrame::Create("frame-id", /*is_main_frame=*/true, GURL()); + auto web_frame = web::FakeWebFrame::Create("frame-id", /*is_main_frame=*/true, + GURL(kTestURL)); web::FakeWebFrame* frame = web_frame.get(); web_frames_manager_->AddWebFrame(std::move(web_frame)); @@ -756,7 +759,14 @@ : public PlatformTest { public: SharedPasswordControllerTestWithRealSuggestionHelper() : PlatformTest() { - suggestion_helper_ = [[PasswordSuggestionHelper alloc] init]; + delegate_ = OCMProtocolMock(@protocol(SharedPasswordControllerDelegate)); + password_manager::PasswordManagerClient* client_ptr = + &password_manager_client_; + [[[delegate_ stub] andReturnValue:OCMOCK_VALUE(client_ptr)] + passwordManagerClient]; + + suggestion_helper_ = + [[PasswordSuggestionHelper alloc] initWithWebState:&web_state_]; form_helper_ = OCMStrictClassMock([PasswordFormHelper class]); OCMExpect([form_helper_ setDelegate:[OCMArg any]]); @@ -771,11 +781,15 @@ driverHelper:driver_helper]; [form_helper_ verify]; + controller_.delegate = delegate_; + UniqueIDDataTabHelper::CreateForWebState(&web_state_); auto web_frames_manager = std::make_unique<web::FakeWebFramesManager>(); web_frames_manager_ = web_frames_manager.get(); web_state_.SetWebFramesManager(std::move(web_frames_manager)); + + web_state_.SetCurrentURL(GURL(kTestURL)); } void SetUp() override { @@ -791,6 +805,7 @@ testing::StrictMock<MockPasswordManager> password_manager_; PasswordSuggestionHelper* suggestion_helper_; id form_helper_; + id delegate_; password_manager::StubPasswordManagerClient password_manager_client_; SharedPasswordController* controller_; }; @@ -946,6 +961,67 @@ EXPECT_TRUE(completion_was_called2); } +// Test that the password suggestions for cross-origin iframes have the origin +// as their description. +TEST_F(SharedPasswordControllerTestWithRealSuggestionHelper, + CrossOriginIframeSugesstionHasOriginAsDescription) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + password_manager::features::kIOSPasswordManagerCrossOriginIframeSupport); + + // Simulate that the form is parsed and sent to PasswordManager. + FormData form = test_helpers::MakeSimpleFormData(); + + web_state_.SetCurrentURL(GURL()); + web_state_.SetContentIsHTML(true); + + auto web_frame = + web::FakeWebFrame::Create(SysNSStringToUTF8(kTestFrameID), + /*is_main_frame=*/false, GURL(kTestURL)); + web::WebFrame* frame = web_frame.get(); + web_frames_manager_->AddWebFrame(std::move(web_frame)); + + ASSERT_TRUE(web_state_.GetLastCommittedURL().DeprecatedGetOriginAsURL() != + frame->GetSecurityOrigin()); + + PasswordFormFillData form_fill_data; + test_helpers::SetPasswordFormFillData( + kTestURL, "", form.unique_renderer_id.value(), "", + form.fields[0].unique_renderer_id.value(), "john.doe@gmail.com", "", + form.fields[1].unique_renderer_id.value(), "super!secret", nullptr, + nullptr, false, &form_fill_data); + + OCMExpect([form_helper_ fillPasswordForm:form_fill_data + inFrame:frame + completionHandler:nil]); + + [controller_ fillPasswordForm:form_fill_data + inFrame:frame + completionHandler:nil]; + + FormSuggestionProviderQuery* form_query = [[FormSuggestionProviderQuery alloc] + initWithFormName:@"form" + uniqueFormID:autofill::FormRendererId(0) + fieldIdentifier:@"field" + uniqueFieldID:autofill::FieldRendererId(1) + fieldType:kPasswordFieldType + type:@"focus" + typedValue:@"" + frameID:kTestFrameID]; + + [controller_ + retrieveSuggestionsForForm:form_query + webState:&web_state_ + completionHandler:^(NSArray<FormSuggestion*>* suggestions, + id<FormSuggestionProvider> delegate) { + // Assert that kTestURL contains [suggestions[0] + // displayDescription]. + ASSERT_NE(kTestURL.find(SysNSStringToUTF8( + [suggestions[0] displayDescription])), + std::string::npos); + }]; +} + class SharedPasswordControllerTestCrossOrigin : public SharedPasswordControllerTest, public testing::WithParamInterface<bool> { @@ -1059,7 +1135,6 @@ [[suggestion_helper_ expect] checkIfSuggestionsAvailableForForm:form_query - webState:&web_state_ completionHandler:mock_completion_handler]; [controller_ checkIfSuggestionsAvailableForForm:form_query
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index e6adcb7..e64fd17 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -29911,7 +29911,8 @@ 'schema': { 'type': 'string', 'enum': [ - 'remove_all', + 'none', + 'keep_none', 'keep_safe_data', 'keep_all' ], @@ -29950,6 +29951,8 @@ 'tags': [], 'desc': '''This setting decides how much user data is kept after <ph name="LACROS_NAME">Lacros</ph> is disabled. + If the policy is set to <ph name="LACROS_BACKWARD_MIGRATION_NONE">none</ph>, backward data migration is not performed. + If the policy is set to <ph name="LACROS_BACKWARD_MIGRATION_KEEP_NONE">keep_none</ph>, all user data is removed. This is the safest option. If the policy is set to <ph name="LACROS_BACKWARD_MIGRATION_KEEP_SAFE_DATA">keep_safe_data</ph>, most user data is removed. Only browser independent files are kept (such as Downloads).
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp index 7fdde5192..9b4a94ca 100644 --- a/components/policy_strings.grdp +++ b/components/policy_strings.grdp
@@ -822,6 +822,9 @@ <message name="IDS_POLICY_DLP_FILES_TRANSFER_WARN_CONTINUE_BUTTON" desc="Continue dialog button label for warning before action on files."> Transfer anyway </message> + <message name="IDS_POLICY_DLP_FILES_DESTINATION_REMOVABLE_STORAGE" desc="A label for the 'Removable storage' files transfer destination."> + Removable storage + </message> <message name="IDS_POLICY_DLP_WARN_CANCEL_BUTTON" desc="Cancel dialog button label for warning."> Cancel </message>
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_DESTINATION_REMOVABLE_STORAGE.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_DESTINATION_REMOVABLE_STORAGE.png.sha1 new file mode 100644 index 0000000..6227e51 --- /dev/null +++ b/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_DESTINATION_REMOVABLE_STORAGE.png.sha1
@@ -0,0 +1 @@ +a986a8868156ae0adbca0f897d484de139cfd481 \ No newline at end of file
diff --git a/components/remote_cocoa/app_shim/immersive_mode_controller.h b/components/remote_cocoa/app_shim/immersive_mode_controller.h index 2e74b05..25800efa 100644 --- a/components/remote_cocoa/app_shim/immersive_mode_controller.h +++ b/components/remote_cocoa/app_shim/immersive_mode_controller.h
@@ -38,10 +38,13 @@ base::OnceCallback<void()> callback); ~ImmersiveModeController(); + void Enable(); void OnTopViewBoundsChanged(const gfx::Rect& bounds); void UpdateToolbarVisibility(bool always_show); private: + bool enabled_ = false; + NSWindow* const browser_widget_; NSWindow* const overlay_widget_;
diff --git a/components/remote_cocoa/app_shim/immersive_mode_controller.mm b/components/remote_cocoa/app_shim/immersive_mode_controller.mm index f9d2ce3b..1490d99 100644 --- a/components/remote_cocoa/app_shim/immersive_mode_controller.mm +++ b/components/remote_cocoa/app_shim/immersive_mode_controller.mm
@@ -133,8 +133,6 @@ addSubview:overlay_content_view]; immersive_mode_titlebar_view_controller_.get().layoutAttribute = NSLayoutAttributeBottom; - [browser_widget_ addTitlebarAccessoryViewController: - immersive_mode_titlebar_view_controller_]; } ImmersiveModeController::~ImmersiveModeController() { @@ -149,6 +147,13 @@ browser_widget_.styleMask |= NSWindowStyleMaskFullSizeContentView; } +void ImmersiveModeController::Enable() { + DCHECK(!enabled_); + enabled_ = true; + [browser_widget_ addTitlebarAccessoryViewController: + immersive_mode_titlebar_view_controller_]; +} + void ImmersiveModeController::OnTopViewBoundsChanged(const gfx::Rect& bounds) { [immersive_mode_titlebar_view_controller_.get().view setFrameSize:bounds.size().ToCGSize()];
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm index d68f3c7a..fc1c625 100644 --- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm +++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
@@ -910,6 +910,7 @@ immersive_mode_controller_ = std::make_unique<ImmersiveModeController>( ns_window(), GetFromId(fullscreen_overlay_widget_id)->ns_window(), std::move(callback)); + immersive_mode_controller_->Enable(); } void NativeWidgetNSWindowBridge::DisableImmersiveFullscreen() { @@ -917,14 +918,12 @@ } void NativeWidgetNSWindowBridge::UpdateToolbarVisibility(bool always_show) { - if (immersive_mode_controller_) - immersive_mode_controller_->UpdateToolbarVisibility(always_show); + immersive_mode_controller_->UpdateToolbarVisibility(always_show); } void NativeWidgetNSWindowBridge::OnTopContainerViewBoundsChanged( const gfx::Rect& bounds) { - if (immersive_mode_controller_) - immersive_mode_controller_->OnTopViewBoundsChanged(bounds); + immersive_mode_controller_->OnTopViewBoundsChanged(bounds); } void NativeWidgetNSWindowBridge::SetCanGoBack(bool can_go_back) {
diff --git a/components/resources/version_ui_scaled_resources.grdp b/components/resources/version_ui_scaled_resources.grdp index 5e9f8ee..4cd808e 100644 --- a/components/resources/version_ui_scaled_resources.grdp +++ b/components/resources/version_ui_scaled_resources.grdp
@@ -1,13 +1,21 @@ <?xml version="1.0" encoding="utf-8"?> <grit-part> - <if expr="_google_chrome"> + <if expr="_google_chrome_for_testing"> <then> - <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO" file="google_chrome/product_logo.png" /> - <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_WHITE" file="google_chrome/product_logo_white.png" /> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO" file="google_chrome/google_chrome_for_testing/product_logo.png" /> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_WHITE" file="google_chrome/google_chrome_for_testing/product_logo_white.png" /> </then> <else> - <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO" file="chromium/product_logo.png" /> - <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_WHITE" file="chromium/product_logo_white.png" /> + <if expr="_google_chrome"> + <then> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO" file="google_chrome/product_logo.png" /> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_WHITE" file="google_chrome/product_logo_white.png" /> + </then> + <else> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO" file="chromium/product_logo.png" /> + <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_WHITE" file="chromium/product_logo_white.png" /> + </else> + </if> </else> </if> </grit-part>
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc index abbd0c1..7954d114 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc +++ b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc
@@ -791,6 +791,7 @@ return; case TrustedVaultRegistrationStatus::kLocalDataObsolete: per_user_vault->set_keys_are_stale(true); + WriteToDisk(data_, file_path_); return; case TrustedVaultRegistrationStatus::kAccessTokenFetchingFailure: // Request wasn't sent to the server, so there is no need for throttling.
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc b/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc index 576a6667..878abe7 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc +++ b/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc
@@ -13,7 +13,6 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/raw_ptr.h" -#include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h" @@ -24,6 +23,7 @@ #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h" #include "components/sync/base/features.h" #include "components/sync/driver/trusted_vault_histograms.h" +#include "components/sync/protocol/local_trusted_vault.pb.h" #include "components/sync/trusted_vault/proto_string_bytes_conversion.h" #include "components/sync/trusted_vault/securebox.h" #include "components/sync/trusted_vault/trusted_vault_connection.h" @@ -83,6 +83,17 @@ return account_info; } +bool WriteLocalTrustedVaultFile(const sync_pb::LocalTrustedVault& content, + const base::FilePath& path) { + std::string encrypted_content; + if (!OSCrypt::EncryptString(content.SerializeAsString(), + &encrypted_content)) { + return false; + } + return base::WriteFile(path, encrypted_content.c_str(), + encrypted_content.size()) != -1; +} + sync_pb::LocalTrustedVault ReadLocalTrustedVaultFile( const base::FilePath& path) { std::string ciphertext; @@ -259,13 +270,7 @@ backend()->WriteDegradedRecoverabilityState(degraded_recoverability_state); // Read the file from disk. - std::string ciphertext; - std::string decrypted_content; - sync_pb::LocalTrustedVault proto; - EXPECT_TRUE(base::ReadFileToString(file_path(), &ciphertext)); - EXPECT_THAT(ciphertext, Ne("")); - EXPECT_TRUE(OSCrypt::DecryptString(ciphertext, &decrypted_content)); - EXPECT_TRUE(proto.ParseFromString(decrypted_content)); + sync_pb::LocalTrustedVault proto = ReadLocalTrustedVaultFile(file_path()); ASSERT_THAT(proto.user_size(), Eq(1)); EXPECT_THAT(proto.user(0).degraded_recoverability_state(), DegradedRecoverabilityStateEq(degraded_recoverability_state)); @@ -317,12 +322,7 @@ user_data2->add_vault_key()->set_key_material(kKey2.data(), kKey2.size()); user_data2->add_vault_key()->set_key_material(kKey3.data(), kKey3.size()); - std::string encrypted_data; - ASSERT_TRUE(OSCrypt::EncryptString(initial_data.SerializeAsString(), - &encrypted_data)); - ASSERT_NE(-1, base::WriteFile(file_path(), encrypted_data.c_str(), - encrypted_data.size())); - + ASSERT_TRUE(WriteLocalTrustedVaultFile(initial_data, file_path())); backend()->ReadDataFromDisk(); // Keys should be fetched immediately for both accounts. @@ -345,12 +345,7 @@ GetConstantTrustedVaultKey().data(), GetConstantTrustedVaultKey().size()); user_data->add_vault_key()->set_key_material(kKey.data(), kKey.size()); - std::string encrypted_data; - ASSERT_TRUE(OSCrypt::EncryptString(initial_data.SerializeAsString(), - &encrypted_data)); - ASSERT_NE(-1, base::WriteFile(file_path(), encrypted_data.c_str(), - encrypted_data.size())); - + ASSERT_TRUE(WriteLocalTrustedVaultFile(initial_data, file_path())); backend()->ReadDataFromDisk(); // Keys should be fetched immediately, constant key must be filtered out. @@ -374,13 +369,7 @@ backend()->StoreKeys(kGaiaId2, {kKey3, kKey4}, /*last_key_version=*/9); // Read the file from disk. - std::string ciphertext; - std::string decrypted_content; - sync_pb::LocalTrustedVault proto; - EXPECT_TRUE(base::ReadFileToString(file_path(), &ciphertext)); - EXPECT_THAT(ciphertext, Ne("")); - EXPECT_TRUE(OSCrypt::DecryptString(ciphertext, &decrypted_content)); - EXPECT_TRUE(proto.ParseFromString(decrypted_content)); + sync_pb::LocalTrustedVault proto = ReadLocalTrustedVaultFile(file_path()); ASSERT_THAT(proto.user_size(), Eq(2)); EXPECT_THAT(proto.user(0).vault_key(), ElementsAre(KeyMaterialEq(kKey1))); EXPECT_THAT(proto.user(0).last_vault_key_version(), Eq(7)); @@ -411,23 +400,12 @@ AssignBytesToProtoString(kKey2, user_data2->add_vault_key()->mutable_key_material()); - std::string encrypted_data; - ASSERT_TRUE(OSCrypt::EncryptString(initial_data.SerializeAsString(), - &encrypted_data)); - ASSERT_NE(-1, base::WriteFile(file_path(), encrypted_data.c_str(), - encrypted_data.size())); - + ASSERT_TRUE(WriteLocalTrustedVaultFile(initial_data, file_path())); // Backend should fix corrupted data and write new state. backend()->ReadDataFromDisk(); // Read the file from disk. - std::string ciphertext; - std::string decrypted_content; - sync_pb::LocalTrustedVault proto; - ASSERT_TRUE(base::ReadFileToString(file_path(), &ciphertext)); - ASSERT_THAT(ciphertext, Ne("")); - ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decrypted_content)); - ASSERT_TRUE(proto.ParseFromString(decrypted_content)); + sync_pb::LocalTrustedVault proto = ReadLocalTrustedVaultFile(file_path()); ASSERT_THAT(proto.user_size(), Eq(2)); // Constant key should be added for the first user. EXPECT_THAT(proto.user(0).vault_key(), @@ -452,11 +430,7 @@ user_data1->set_keys_are_stale(true); user_data2->set_gaia_id(account_info_2.gaia); user_data2->set_keys_are_stale(true); - std::string encrypted_data; - ASSERT_TRUE(OSCrypt::EncryptString(initial_data.SerializeAsString(), - &encrypted_data)); - ASSERT_NE(-1, base::WriteFile(file_path(), encrypted_data.c_str(), - encrypted_data.size())); + ASSERT_TRUE(WriteLocalTrustedVaultFile(initial_data, file_path())); // Backend should reset |keys_are_stale| for both accounts and write new // state. @@ -661,6 +635,61 @@ } TEST_F(StandaloneTrustedVaultBackendTest, + ShouldHandleLocalDataObsoleteAndPersistState) { + const CoreAccountInfo account_info = MakeAccountInfoWithGaiaId("user"); + const std::vector<uint8_t> kVaultKey = {1, 2, 3}; + const int kLastKeyVersion = 1; + + backend()->StoreKeys(account_info.gaia, {kVaultKey}, kLastKeyVersion); + + TrustedVaultConnection::RegisterAuthenticationFactorCallback + device_registration_callback; + EXPECT_CALL(*connection(), + RegisterAuthenticationFactor( + Eq(account_info), ElementsAre(kVaultKey), kLastKeyVersion, _, + AuthenticationFactorType::kPhysicalDevice, + /*authentication_factor_type_hint=*/Eq(absl::nullopt), _)) + .WillOnce([&](const CoreAccountInfo&, + const std::vector<std::vector<uint8_t>>&, int, + const SecureBoxPublicKey& device_public_key, + AuthenticationFactorType, absl::optional<int>, + TrustedVaultConnection::RegisterAuthenticationFactorCallback + callback) { + device_registration_callback = std::move(callback); + return std::make_unique<TrustedVaultConnection::Request>(); + }); + + // Setting the primary account will trigger device registration. + backend()->SetPrimaryAccount(account_info, + /*has_persistent_auth_error=*/false); + ASSERT_FALSE(device_registration_callback.is_null()); + + // Pretend that the registration failed with kLocalDataObsolete. + std::move(device_registration_callback) + .Run(TrustedVaultRegistrationStatus::kLocalDataObsolete); + + // Verify persisted file state. + std::string ciphertext; + std::string decrypted_content; + sync_pb::LocalTrustedVault proto; + EXPECT_TRUE(base::ReadFileToString(file_path(), &ciphertext)); + EXPECT_THAT(ciphertext, Ne("")); + EXPECT_TRUE(OSCrypt::DecryptString(ciphertext, &decrypted_content)); + EXPECT_TRUE(proto.ParseFromString(decrypted_content)); + ASSERT_THAT(proto.user_size(), Eq(1)); + // Ensure that keys are marked as stale, regression test for + // crbug.com/1358015. + EXPECT_TRUE(proto.user(0).keys_are_stale()); + // Additionally ensure that |local_device_registration_info| has correct + // state. + EXPECT_FALSE( + proto.user(0).local_device_registration_info().device_registered()); + EXPECT_TRUE(proto.user(0) + .local_device_registration_info() + .has_private_key_material()); +} + +TEST_F(StandaloneTrustedVaultBackendTest, ShouldClearDataAndAttemptDeviceRegistration) { const CoreAccountInfo account_info = MakeAccountInfoWithGaiaId("user"); const std::vector<std::vector<uint8_t>> kInitialVaultKeys = {{1, 2, 3}};
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc index a4b37faea..5900b991 100644 --- a/components/viz/common/features.cc +++ b/components/viz/common/features.cc
@@ -195,7 +195,7 @@ // If enabled, do not rely on surface garbage collection to happen // periodically, but trigger it eagerly, to avoid missing calls. const base::Feature kEagerSurfaceGarbageCollection{ - "EagerSurfaceGarbageCollecton", base::FEATURE_DISABLED_BY_DEFAULT}; + "EagerSurfaceGarbageCollection", base::FEATURE_DISABLED_BY_DEFAULT}; bool IsAdpfEnabled() { // TODO(crbug.com/1157620): Limit this to correct android version.
diff --git a/components/viz/service/display/overlay_candidate_factory.cc b/components/viz/service/display/overlay_candidate_factory.cc index 6917bd4..ee96f727 100644 --- a/components/viz/service/display/overlay_candidate_factory.cc +++ b/components/viz/service/display/overlay_candidate_factory.cc
@@ -451,8 +451,8 @@ return CandidateStatus::kFailNearFilter; if (quad->background_color != SkColors::kTransparent && - (quad->background_color != SkColors::kBlack || - quad->ShouldDrawWithBlending())) { + (quad->ShouldDrawWithBlendingForReasonOtherThanMaskFilter() || + quad->shared_quad_state->mask_filter_info.HasGradientMask())) { // This path can also be used by other platforms like Ash/Chrome, which does // not support overlays with background color. Only LaCros/Wayland supports // that.
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc index f238797..2bbd4016 100644 --- a/components/viz/service/display/overlay_unittest.cc +++ b/components/viz/service/display/overlay_unittest.cc
@@ -1679,29 +1679,7 @@ EXPECT_FALSE(overlay_damage_rect.IsEmpty()); } -TEST_F(SingleOverlayOnTopTest, RejectBackgroundColor) { - auto pass = CreateRenderPass(); - TextureDrawQuad* quad = CreateFullscreenCandidateQuad( - resource_provider_.get(), child_resource_provider_.get(), - child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); - quad->background_color = SkColors::kRed; - - OverlayCandidateList candidate_list; - OverlayProcessorInterface::FilterOperationsMap render_pass_filters; - OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters; - AggregatedRenderPassList pass_list; - pass_list.push_back(std::move(pass)); - SurfaceDamageRectList surface_damage_rect_list; - - overlay_processor_->ProcessForOverlays( - resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), - render_pass_filters, render_pass_backdrop_filters, - std::move(surface_damage_rect_list), nullptr, &candidate_list, - &damage_rect_, &content_bounds_); - EXPECT_EQ(0U, candidate_list.size()); -} - -TEST_F(SingleOverlayOnTopTest, AcceptBlackBackgroundColor) { +TEST_F(SingleOverlayOnTopTest, AcceptBackgroundColorWithoutBlending) { auto pass = CreateRenderPass(); TextureDrawQuad* quad = CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), @@ -1723,7 +1701,7 @@ EXPECT_EQ(1U, candidate_list.size()); } -TEST_F(SingleOverlayOnTopTest, RejectBlackBackgroundColorWithBlending) { +TEST_F(SingleOverlayOnTopTest, RejectBackgroundColorWithBlending) { auto pass = CreateRenderPass(); TextureDrawQuad* quad = CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), @@ -1746,6 +1724,33 @@ EXPECT_EQ(0U, candidate_list.size()); } +TEST_F(SingleOverlayOnTopTest, RejectBackgroundColorWithGradient) { + auto pass = CreateRenderPass(); + + auto* sqs = pass->shared_quad_state_list.back(); + sqs->mask_filter_info = + gfx::MaskFilterInfo(gfx::RectF(kOverlayRect), gfx::RoundedCornersF(1.f), + gfx::LinearGradient(3)); + TextureDrawQuad* quad = CreateFullscreenCandidateQuad( + resource_provider_.get(), child_resource_provider_.get(), + child_provider_.get(), sqs, pass.get()); + quad->background_color = SkColors::kBlack; + + OverlayCandidateList candidate_list; + OverlayProcessorInterface::FilterOperationsMap render_pass_filters; + OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters; + AggregatedRenderPassList pass_list; + pass_list.push_back(std::move(pass)); + SurfaceDamageRectList surface_damage_rect_list; + + overlay_processor_->ProcessForOverlays( + resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), + render_pass_filters, render_pass_backdrop_filters, + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); + EXPECT_EQ(0U, candidate_list.size()); +} + TEST_F(SingleOverlayOnTopTest, RejectBlendMode) { auto pass = CreateRenderPass(); CreateFullscreenCandidateQuad( @@ -2141,6 +2146,34 @@ ASSERT_EQ(1U, candidate_list.size()); } +TEST_F(UnderlayTest, AllowRoundedCornerRectWithBackgroundColor) { + auto pass = CreateRenderPass(); + auto* sqs = pass->shared_quad_state_list.back(); + sqs->mask_filter_info = + gfx::MaskFilterInfo(gfx::RectF(kOverlayRect), gfx::RoundedCornersF(10.f), + gfx::LinearGradient::GetEmpty()); + auto* quad = CreateFullscreenCandidateQuad( + resource_provider_.get(), child_resource_provider_.get(), + child_provider_.get(), sqs, pass.get()); + quad->needs_blending = false; + // Any color is valid for this tests except transparent. + quad->background_color = SkColors::kYellow; + + OverlayCandidateList candidate_list; + OverlayProcessorInterface::FilterOperationsMap render_pass_filters; + OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters; + AggregatedRenderPassList pass_list; + pass_list.push_back(std::move(pass)); + SurfaceDamageRectList surface_damage_rect_list; + + overlay_processor_->ProcessForOverlays( + resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), + render_pass_filters, render_pass_backdrop_filters, + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); + ASSERT_EQ(1U, candidate_list.size()); +} + TEST_F(UnderlayTest, DisallowsTransparentCandidates) { auto pass = CreateRenderPass(); CreateFullscreenCandidateQuad(
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index cc1fe51..e66dc7f 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1120,6 +1120,8 @@ "interest_group/debuggable_auction_worklet_tracker.h", "interest_group/interest_group_auction.cc", "interest_group/interest_group_auction.h", + "interest_group/interest_group_k_anonymity_manager.cc", + "interest_group/interest_group_k_anonymity_manager.h", "interest_group/interest_group_manager_impl.cc", "interest_group/interest_group_manager_impl.h", "interest_group/interest_group_permissions_cache.cc",
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index 0661614..c1ba1833 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc
@@ -21,6 +21,10 @@ #include "content/public/common/content_switches.h" #include "content/public/common/sandboxed_process_launcher_delegate.h" +#if BUILDFLAG(IS_ANDROID) +#include "base/android/child_process_binding_types.h" +#endif + #if BUILDFLAG(IS_MAC) #include "content/browser/child_process_task_port_provider_mac.h" #endif @@ -227,6 +231,11 @@ } #if BUILDFLAG(IS_ANDROID) +base::android::ChildBindingState +ChildProcessLauncher::GetEffectiveChildBindingState() { + return helper_->GetEffectiveChildBindingState(); +} + void ChildProcessLauncher::DumpProcessStack() { base::Process to_pass = process_.process.Duplicate(); GetProcessLauncherTaskRunner()->PostTask(
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h index 928cfaf6..e12fcf6d 100644 --- a/content/browser/child_process_launcher.h +++ b/content/browser/child_process_launcher.h
@@ -40,7 +40,12 @@ namespace base { class CommandLine; +#if BUILDFLAG(IS_ANDROID) +namespace android { +enum class ChildBindingState; } +#endif +} // namespace base namespace perfetto { namespace protos { @@ -264,6 +269,9 @@ Client* ReplaceClientForTest(Client* client); #if BUILDFLAG(IS_ANDROID) + // Returns the highest binding state for the ChildProcessConnection. + base::android::ChildBindingState GetEffectiveChildBindingState(); + // Dumps the stack of the child process without crashing it. void DumpProcessStack(); #endif
diff --git a/content/browser/child_process_launcher_helper.h b/content/browser/child_process_launcher_helper.h index 5337642..25b92b6e 100644 --- a/content/browser/child_process_launcher_helper.h +++ b/content/browser/child_process_launcher_helper.h
@@ -77,8 +77,8 @@ // process. Since ChildProcessLauncher can be deleted by its client at any time, // this class is used to keep state as the process is started asynchronously. // It also contains the platform specific pieces. -class ChildProcessLauncherHelper : - public base::RefCountedThreadSafe<ChildProcessLauncherHelper> { +class ChildProcessLauncherHelper + : public base::RefCountedThreadSafe<ChildProcessLauncherHelper> { public: // Abstraction around a process required to deal in a platform independent way // between Linux (which can use zygotes) and the other platforms. @@ -191,8 +191,9 @@ const ChildProcessLauncherPriority& priority); #if BUILDFLAG(IS_ANDROID) - void OnChildProcessStarted(JNIEnv* env, - jint handle); + void OnChildProcessStarted(JNIEnv* env, jint handle); + + base::android::ChildBindingState GetEffectiveChildBindingState(); // Dumps the stack of the child process without crashing it. void DumpProcessStack(const base::Process& process);
diff --git a/content/browser/child_process_launcher_helper_android.cc b/content/browser/child_process_launcher_helper_android.cc index ba1957b..0bf6bdd 100644 --- a/content/browser/child_process_launcher_helper_android.cc +++ b/content/browser/child_process_launcher_helper_android.cc
@@ -250,6 +250,15 @@ return base::File(base::android::OpenApkAsset(path.value(), region)); } +base::android::ChildBindingState +ChildProcessLauncherHelper::GetEffectiveChildBindingState() { + JNIEnv* env = AttachCurrentThread(); + DCHECK(env); + return static_cast<base::android::ChildBindingState>( + Java_ChildProcessLauncherHelperImpl_getEffectiveChildBindingState( + env, java_peer_)); +} + void ChildProcessLauncherHelper::DumpProcessStack( const base::Process& process) { JNIEnv* env = AttachCurrentThread();
diff --git a/content/browser/direct_sockets/direct_sockets_tcp_browsertest.cc b/content/browser/direct_sockets/direct_sockets_tcp_browsertest.cc index 6fa31a0..ab871e5d 100644 --- a/content/browser/direct_sockets/direct_sockets_tcp_browsertest.cc +++ b/content/browser/direct_sockets/direct_sockets_tcp_browsertest.cc
@@ -393,6 +393,25 @@ waiter.Await(); } +IN_PROC_BROWSER_TEST_F(DirectSocketsTcpBrowserTest, WriteLargeTcpPacket) { + // The default capacity of TCPSocket mojo pipe is 65536 bytes. This test + // verifies that out asynchronous writing logic actually works. + constexpr uint32_t defaultMojoPipeCapacity = (1 << 16); + constexpr int32_t kRequiredBytes = 3 * defaultMojoPipeCapacity + 1; + + const int listening_port = StartTcpServer(); + ReadWriteWaiter waiter(/*required_receive_bytes=*/kRequiredBytes, + /*required_send_bytes=*/0, tcp_server_socket()); + + const std::string script = + JsReplace("writeLargeTcpPacket($1, $2, $3)", + net::IPAddress::IPv4Localhost().ToString(), listening_port, + kRequiredBytes); + + EXPECT_EQ("writeLargeTcpPacket succeeded", EvalJs(shell(), script)); + waiter.Await(); +} + IN_PROC_BROWSER_TEST_F(DirectSocketsTcpBrowserTest, ReadTcp) { constexpr int32_t kRequiredBytes = 150000;
diff --git a/content/browser/first_party_sets/first_party_sets_loader.cc b/content/browser/first_party_sets/first_party_sets_loader.cc index 75ca1db..5c8264cf 100644 --- a/content/browser/first_party_sets/first_party_sets_loader.cc +++ b/content/browser/first_party_sets/first_party_sets_loader.cc
@@ -11,9 +11,7 @@ #include <vector> #include "base/check.h" -#include "base/containers/contains.h" #include "base/containers/flat_map.h" -#include "base/containers/flat_set.h" #include "base/files/file_util.h" #include "base/metrics/histogram_functions.h" #include "base/ranges/algorithm.h" @@ -87,8 +85,8 @@ std::istringstream stream(raw_sets); FirstPartySetParser::SetsAndAliases public_sets = FirstPartySetParser::ParseSetsFromStream(stream, /*emit_errors=*/false); - sets_ = std::move(public_sets.first); - aliases_ = std::move(public_sets.second); + public_sets_ = net::PublicSets(std::move(public_sets.first), + std::move(public_sets.second)); component_sets_parse_progress_ = Progress::kFinished; UmaHistogramTimes( @@ -109,94 +107,17 @@ } } -base::flat_set<net::SchemefulSite> FirstPartySetsLoader::FindIntersection() - const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(HasAllInputs()); - std::vector<net::SchemefulSite> intersection; - for (const std::pair<net::SchemefulSite, net::FirstPartySetEntry>& - public_site_and_entry : sets_) { - const net::SchemefulSite& public_site = public_site_and_entry.first; - const net::SchemefulSite& public_primary = - public_site_and_entry.second.primary(); - bool is_affected_by_local_set = - public_site == manually_specified_set_->GetPrimary() || - public_primary == manually_specified_set_->GetPrimary() || - base::ranges::any_of( - manually_specified_set_->GetSet(), - [&](const std::pair<net::SchemefulSite, net::FirstPartySetEntry>& - manual_site_and_entry) { - const net::SchemefulSite& manual_site = - manual_site_and_entry.first; - return manual_site == public_site || - manual_site == public_primary; - }); - if (is_affected_by_local_set) { - intersection.push_back(public_site_and_entry.first); - } - }; - - return intersection; -} - -base::flat_set<net::SchemefulSite> FirstPartySetsLoader::FindSingletons() - const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - std::vector<net::SchemefulSite> primaries_with_members; - for (const auto& [site, entry] : sets_) { - if (site != entry.primary()) - primaries_with_members.push_back(entry.primary()); - } - std::vector<net::SchemefulSite> singletons; - for (const auto& [site, entry] : sets_) { - if (site == entry.primary() && - !base::Contains(primaries_with_members, site)) { - singletons.push_back(site); - } - } - - return singletons; -} - -void FirstPartySetsLoader::ApplyManuallySpecifiedSet() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(HasAllInputs()); - if (manually_specified_set_->empty()) - return; - - base::flat_set<net::SchemefulSite> intersection = FindIntersection(); - for (const auto& site : intersection) { - sets_.erase(site); - } - - base::flat_set<net::SchemefulSite> singletons = FindSingletons(); - for (const auto& singleton : singletons) { - sets_.erase(singleton); - } - - base::ranges::copy(manually_specified_set_->GetSet(), - std::inserter(sets_, sets_.end())); - - // Finally, remove any aliases for public sites that were affected (deleted), - // and add any aliases defined in the local set. - base::EraseIf( - aliases_, - [&](const std::pair<net::SchemefulSite, net::SchemefulSite>& alias) { - return intersection.contains(alias.second) || - singletons.contains(alias.second); - }); - base::flat_map<net::SchemefulSite, net::SchemefulSite> manual_aliases = - manually_specified_set_->GetAliases(); - aliases_.insert(manual_aliases.begin(), manual_aliases.end()); -} - void FirstPartySetsLoader::MaybeFinishLoading() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!HasAllInputs()) return; - ApplyManuallySpecifiedSet(); - std::move(on_load_complete_) - .Run(net::PublicSets(std::move(sets_), std::move(aliases_))); + if (!manually_specified_set_->empty()) { + public_sets_->ApplyManuallySpecifiedSet( + manually_specified_set_->GetPrimary(), + manually_specified_set_->GetSet(), + manually_specified_set_->GetAliases()); + } + std::move(on_load_complete_).Run(std::move(public_sets_).value()); } bool FirstPartySetsLoader::HasAllInputs() const {
diff --git a/content/browser/first_party_sets/first_party_sets_loader.h b/content/browser/first_party_sets/first_party_sets_loader.h index 34283a1a..8be5ea28 100644 --- a/content/browser/first_party_sets/first_party_sets_loader.h +++ b/content/browser/first_party_sets/first_party_sets_loader.h
@@ -6,7 +6,6 @@ #define CONTENT_BROWSER_FIRST_PARTY_SETS_FIRST_PARTY_SETS_LOADER_H_ #include "base/callback.h" -#include "base/containers/flat_set.h" #include "base/files/file.h" #include "base/sequence_checker.h" #include "base/thread_annotations.h" @@ -41,10 +40,9 @@ // flag/switch. void SetManuallySpecifiedSet(const LocalSetDeclaration& local_set); - // Asynchronously parses and stores the sets from `sets_file` into the - // members-to-owners map `sets_`, and merges with any previously-loaded sets - // as needed. In case of invalid input, the set of sets provided by the file - // is considered empty. + // Asynchronously parses and stores the sets from `sets_file`, and merges with + // any previously-loaded sets as needed. In case of invalid input, the set of + // sets provided by the file is considered empty. // // Only the first call to SetComponentSets can have any effect; subsequent // invocations are ignored. @@ -55,11 +53,11 @@ private: // Parses the contents of `raw_sets` as a collection of First-Party Set - // declarations, and assigns to `sets_`. + // declarations, and stores the result. void OnReadSetsFile(const std::string& raw_sets); - // Modifies `sets_` to include the CLI-provided set, if any. Must not be - // called until the loader has received the CLI flag value via + // Modifies `public_sets_` to include the CLI-provided set, if any. Must not + // be called until the loader has received the CLI flag value via // `SetManuallySpecifiedSet`, and the public sets via `SetComponentSets`. void ApplyManuallySpecifiedSet(); @@ -67,30 +65,13 @@ // callback `on_load_complete_`, after merging sets appropriately. void MaybeFinishLoading(); - // Returns true if all sources are present (Component Updater sets, CLI set, - // and Policy sets). The Policy sets are provided at construction time, so - // this effectively checks that the other two sources are ready. + // Returns true if all sources are present (Component Updater sets, CLI set). bool HasAllInputs() const; - // Finds the intersection between `sets_` and `manually_specified_set_`. - // - // The returned collection also includes any sites in `sets_` whose primary - // was in the intersection. - base::flat_set<net::SchemefulSite> FindIntersection() const; - - // Finds singleton sets in `sets_`, which are sets that consist of only a - // single site. - base::flat_set<net::SchemefulSite> FindSingletons() const; - - // Represents the mapping of site -> site, where keys are members of sets, - // and values are owners of the sets (explicitly including an entry of owner - // -> owner). - // It holds partial data until all of the sources (component updater + - // manually specified) have been merged, and then holds the merged data. - FlattenedSets sets_ GUARDED_BY_CONTEXT(sequence_checker_); - - // Aliases that were defined by the public set declarations. - FirstPartySetParser::Aliases aliases_ GUARDED_BY_CONTEXT(sequence_checker_); + // Holds the public First-Party Sets. This is nullopt until received from + // Component Updater. It may be modified based on the manually-specified set. + absl::optional<net::PublicSets> public_sets_ + GUARDED_BY_CONTEXT(sequence_checker_); // Holds the set that was provided on the command line (if any). This is // nullopt until `SetManuallySpecifiedSet` is called.
diff --git a/content/browser/first_party_sets/first_party_sets_loader_unittest.cc b/content/browser/first_party_sets/first_party_sets_loader_unittest.cc index 1b38d47d..ad2f81d 100644 --- a/content/browser/first_party_sets/first_party_sets_loader_unittest.cc +++ b/content/browser/first_party_sets/first_party_sets_loader_unittest.cc
@@ -29,6 +29,7 @@ #include "url/gurl.h" using ::testing::IsEmpty; +using ::testing::Optional; using ::testing::Pair; using ::testing::UnorderedElementsAre; using ::testing::UnorderedElementsAreArray; @@ -226,245 +227,20 @@ EXPECT_THAT(WaitAndGetResult(), PublicSetsAre(IsEmpty(), IsEmpty())); } -TEST_F(FirstPartySetsLoaderTest, SetsManuallySpecified_DeduplicatesOwnerOwner) { - SetComponentSets( - loader(), - R"({"primary": "https://example.test", "associatedSites": )" - R"(["https://associatedsite2.test", "https://associatedsite3.test"]})" - "\n" - R"({"primary": "https://bar.test",)" - R"("associatedSites": ["https://associatedsite4.test"]})"); - loader().SetManuallySpecifiedSet(LocalSetDeclaration( - R"({"primary": "https://example.test",)" - R"("associatedSites":)" - R"(["https://associatedsite1.test", "https://associatedsite2.test"]})")); - - EXPECT_THAT(WaitAndGetResult(), - PublicSetsAre( - UnorderedElementsAre( - Pair(SerializesTo("https://example.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kPrimary, absl::nullopt)), - Pair(SerializesTo("https://associatedsite1.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kAssociated, 0)), - Pair(SerializesTo("https://associatedsite2.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kAssociated, 1)), - Pair(SerializesTo("https://bar.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://bar.test")), - net::SiteType::kPrimary, absl::nullopt)), - Pair(SerializesTo("https://associatedsite4.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://bar.test")), - net::SiteType::kAssociated, 0))), - IsEmpty())); -} - -TEST_F(FirstPartySetsLoaderTest, - SetsManuallySpecified_DeduplicatesOwnerMember) { - SetComponentSets( - loader(), R"({"primary": "https://foo.test",)" - R"("associatedSites": )" - R"(["https://associatedsite1.test", "https://example.test"]})" - "\n" - R"({"primary": "https://bar.test",)" - R"("associatedSites": ["https://associatedsite2.test"]})"); - loader().SetManuallySpecifiedSet(LocalSetDeclaration( - R"({"primary": "https://example.test",)" - R"("associatedSites":)" - R"(["https://associatedsite1.test", "https://associatedsite3.test"]})")); - - EXPECT_THAT(WaitAndGetResult(), - PublicSetsAre( - UnorderedElementsAre( - Pair(SerializesTo("https://example.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kPrimary, absl::nullopt)), - Pair(SerializesTo("https://associatedsite1.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kAssociated, 0)), - Pair(SerializesTo("https://associatedsite3.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kAssociated, 1)), - Pair(SerializesTo("https://bar.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://bar.test")), - net::SiteType::kPrimary, absl::nullopt)), - Pair(SerializesTo("https://associatedsite2.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://bar.test")), - net::SiteType::kAssociated, 0))), - IsEmpty())); -} - -TEST_F(FirstPartySetsLoaderTest, - SetsManuallySpecified_DeduplicatesMemberOwner) { - SetComponentSets( - loader(), - R"({"primary": "https://foo.test", "associatedSites": )" - R"(["https://associatedsite1.test", "https://associatedsite2.test"]})" - "\n" - R"({"primary" : "https://associatedsite3.test",)" - R"("associatedSites" : ["https://associatedsite4.test"]})"); - loader().SetManuallySpecifiedSet(LocalSetDeclaration( - R"({"primary": "https://example.test",)" - R"("associatedSites": ["https://associatedsite3.test"]})")); - - EXPECT_THAT(WaitAndGetResult(), - PublicSetsAre( - UnorderedElementsAre( - Pair(SerializesTo("https://example.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kPrimary, absl::nullopt)), - Pair(SerializesTo("https://associatedsite3.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kAssociated, 0)), - Pair(SerializesTo("https://foo.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://foo.test")), - net::SiteType::kPrimary, absl::nullopt)), - Pair(SerializesTo("https://associatedsite1.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://foo.test")), - net::SiteType::kAssociated, 0)), - Pair(SerializesTo("https://associatedsite2.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://foo.test")), - net::SiteType::kAssociated, 1))), - IsEmpty())); -} - -TEST_F(FirstPartySetsLoaderTest, - SetsManuallySpecified_DeduplicatesMemberMember) { - SetComponentSets( - loader(), - R"({"primary": "https://foo.test", "associatedSites": )" - R"(["https://associatedsite2.test", "https://associatedsite3.test"]})" - "\n" - R"({"primary": "https://bar.test",)" - R"("associatedSites": ["https://associatedsite4.test"]})"); - loader().SetManuallySpecifiedSet(LocalSetDeclaration( - R"({"primary": "https://example.test",)" - R"("associatedSites":)" - R"(["https://associatedsite1.test", "https://associatedsite2.test"]})")); - - EXPECT_THAT(WaitAndGetResult(), - PublicSetsAre( - UnorderedElementsAre( - Pair(SerializesTo("https://example.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kPrimary, absl::nullopt)), - Pair(SerializesTo("https://associatedsite1.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kAssociated, 0)), - Pair(SerializesTo("https://associatedsite2.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kAssociated, 1)), - Pair(SerializesTo("https://foo.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://foo.test")), - net::SiteType::kPrimary, absl::nullopt)), - Pair(SerializesTo("https://associatedsite3.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://foo.test")), - net::SiteType::kAssociated, 1)), - Pair(SerializesTo("https://bar.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://bar.test")), - net::SiteType::kPrimary, absl::nullopt)), - Pair(SerializesTo("https://associatedsite4.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://bar.test")), - net::SiteType::kAssociated, 0))), - IsEmpty())); -} - -TEST_F(FirstPartySetsLoaderTest, - SetsManuallySpecified_PrunesInducedSingletons) { +TEST_F(FirstPartySetsLoaderTest, SetsManuallySpecified) { SetComponentSets(loader(), - R"({"primary": "https://foo.test",)" - R"("associatedSites": ["https://associatedsite1.test"]})"); + R"({"primary": "https://example.test", "associatedSites": )" + R"(["https://associatedsite1.test"]})"); loader().SetManuallySpecifiedSet(LocalSetDeclaration( - R"({"primary": "https://example.test",)" - R"("associatedSites": ["https://associatedsite1.test"]})")); + R"({"primary": "https://bar.test",)" + R"("associatedSites": ["https://associatedsite2.test"]})")); - // If we just erased entries that overlapped with the manually-supplied - // set, https://foo.test would be left as a singleton set. But since we - // disallow singleton sets, we ensure that such cases are caught and - // removed. - EXPECT_THAT(WaitAndGetResult(), - PublicSetsAre( - UnorderedElementsAre( - Pair(SerializesTo("https://example.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kPrimary, absl::nullopt)), - Pair(SerializesTo("https://associatedsite1.test"), - net::FirstPartySetEntry( - net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kAssociated, 0))), - IsEmpty())); -} - -TEST_F(FirstPartySetsLoaderTest, SetsManuallySpecified_MergesAliases) { - net::SchemefulSite foo(GURL("https://foo.test")); - net::SchemefulSite example(GURL("https://example.test")); - net::SchemefulSite associated(GURL("https://associated.test")); - net::SchemefulSite associated_cctld1(GURL("https://associated.cctld1")); - net::SchemefulSite associated_cctld2(GURL("https://associated.cctld2")); - net::SchemefulSite foo_service(GURL("https://foo_service.test")); - net::SchemefulSite foo_service_cctld(GURL("https://foo_service.cctld")); - - // Both the public sets and the locally-defined set define an alias for - // https://associated.test, but both define a different set for that site too. - // Only the locally-defined alias should be kept. - SetComponentSets( - loader(), - R"({"primary": "https://foo.test",)" - R"("associatedSites": ["https://associated.test"],)" - R"("serviceSites": ["https://foo_service.test"],)" - R"("ccTLDs": {)" - R"( "https://associated.test": ["https://associated.cctld1"],)" - R"( "https://foo_service.test": ["https://foo_service.cctld"],)" - R"(})" - R"(})"); - loader().SetManuallySpecifiedSet(LocalSetDeclaration( - R"({"primary": "https://example.test",)" - R"("associatedSites": ["https://associated.test"],)" - R"("ccTLDs": {)" - R"( "https://associated.test": ["https://associated.cctld2"],)" - R"(})" - R"(})")); - - EXPECT_THAT( - WaitAndGetResult(), - PublicSetsAre( - UnorderedElementsAre( - Pair(example, - net::FirstPartySetEntry(example, net::SiteType::kPrimary, - absl::nullopt)), - Pair(associated, net::FirstPartySetEntry( - example, net::SiteType::kAssociated, 0)), - Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - absl::nullopt)), - Pair(foo_service, - net::FirstPartySetEntry(foo, net::SiteType::kService, - absl::nullopt))), - UnorderedElementsAre(Pair(foo_service_cctld, foo_service), - Pair(associated_cctld2, associated)))); + EXPECT_THAT(WaitAndGetResult().FindEntry( + net::SchemefulSite(GURL("https://associatedsite2.test")), + /*config=*/nullptr), + Optional(net::FirstPartySetEntry( + net::SchemefulSite(GURL("https://bar.test")), + net::SiteType::kAssociated, 0))); } } // namespace content
diff --git a/content/browser/interest_group/auction_runner.cc b/content/browser/interest_group/auction_runner.cc index d93698b4..a291833 100644 --- a/content/browser/interest_group/auction_runner.cc +++ b/content/browser/interest_group/auction_runner.cc
@@ -168,6 +168,7 @@ interest_group_manager_->RecordInterestGroupWin(winning_group_key, ad_metadata); + interest_group_manager_->RegisterAdAsWon(auction_.top_bid()->bid->render_url); std::vector<GURL> debug_win_report_urls; std::vector<GURL> debug_loss_report_urls;
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc index f182bac..14d5d57 100644 --- a/content/browser/interest_group/auction_runner_unittest.cc +++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -1664,7 +1664,8 @@ interest_group_manager_ = std::make_unique<InterestGroupManagerImpl>( base::FilePath(), /*in_memory=*/true, InterestGroupManagerImpl::ProcessMode::kDedicated, - /*url_loader_factory=*/nullptr); + /*url_loader_factory=*/nullptr, + /*k_anonymity_service=*/nullptr); if (!auction_process_manager_) { auction_process_manager_ = std::make_unique<SameProcessAuctionProcessManager>();
diff --git a/content/browser/interest_group/interest_group_k_anonymity_manager.cc b/content/browser/interest_group/interest_group_k_anonymity_manager.cc new file mode 100644 index 0000000..5b4db2d --- /dev/null +++ b/content/browser/interest_group/interest_group_k_anonymity_manager.cc
@@ -0,0 +1,144 @@ +// 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. + +#include "content/browser/interest_group/interest_group_k_anonymity_manager.h" + +#include "base/bind.h" +#include "base/time/time.h" +#include "content/browser/interest_group/interest_group_manager_impl.h" +#include "crypto/sha2.h" + +namespace content { +namespace { + +constexpr base::TimeDelta kUpdateExpiration = base::Hours(24); + +// Calculates a SHA256 hash of the input string. +std::string KAnonHash(const std::string& input) { + return crypto::SHA256HashString(input); +} + +} // namespace + +std::string KAnonKeyFor(const url::Origin& owner, const std::string& name) { + return owner.GetURL().spec() + '\n' + name; +} + +InterestGroupKAnonymityManager::InterestGroupKAnonymityManager( + InterestGroupManagerImpl* interest_group_manager, + std::unique_ptr<KAnonymityServiceDelegate> k_anonymity_service) + : interest_group_manager_(interest_group_manager), + k_anonymity_service_(std::move(k_anonymity_service)), + weak_ptr_factory_(this) {} + +InterestGroupKAnonymityManager::~InterestGroupKAnonymityManager() = default; + +void InterestGroupKAnonymityManager::QueryKAnonymityForInterestGroup( + const StorageInterestGroup& storage_group) { + if (!k_anonymity_service_) + return; + + std::vector<std::string> unhashed_ids_to_query; + base::Time check_time = base::Time::Now(); + + if (!storage_group.name_kanon || + storage_group.name_kanon->last_updated < check_time - kUpdateExpiration) { + unhashed_ids_to_query.push_back(KAnonKeyFor( + storage_group.interest_group.owner, storage_group.interest_group.name)); + } + + if (storage_group.interest_group.daily_update_url) { + if (!storage_group.daily_update_url_kanon || + storage_group.daily_update_url_kanon->last_updated < + check_time - kUpdateExpiration) { + unhashed_ids_to_query.push_back( + storage_group.interest_group.daily_update_url->spec()); + } + } + + for (const auto& ad : storage_group.ads_kanon) { + if (ad.last_updated < check_time - kUpdateExpiration) { + unhashed_ids_to_query.push_back(ad.key); + } + } + + std::vector<std::string> hashed_ids_to_query; + for (const auto& input : unhashed_ids_to_query) { + hashed_ids_to_query.push_back(KAnonHash(input)); + } + + k_anonymity_service_->QuerySets( + std::move(hashed_ids_to_query), + base::BindOnce(&InterestGroupKAnonymityManager::QuerySetsCallback, + weak_ptr_factory_.GetWeakPtr(), + std::move(unhashed_ids_to_query), std::move(check_time))); +} + +void InterestGroupKAnonymityManager::QuerySetsCallback( + std::vector<std::string> unhashed_query, + base::Time update_time, + std::vector<bool> status) { + DCHECK_LE(status.size(), unhashed_query.size()); + int size = std::min(unhashed_query.size(), status.size()); + for (int i = 0; i < size; i++) { + StorageInterestGroup::KAnonymityData data = {unhashed_query[i], status[i], + update_time}; + interest_group_manager_->UpdateKAnonymity(data); + } + for (size_t i = size; i < unhashed_query.size(); i++) { + // If we fail, update the data set anyway until we can verify that the + // server is stable. + StorageInterestGroup::KAnonymityData data = {unhashed_query[i], false, + update_time}; + interest_group_manager_->UpdateKAnonymity(data); + } +} + +void InterestGroupKAnonymityManager::RegisterInterestGroupAsJoined( + const blink::InterestGroup& group) { + RegisterIDAsJoined(KAnonKeyFor(group.owner, group.name)); + if (group.daily_update_url) + RegisterIDAsJoined(group.daily_update_url->spec()); +} + +void InterestGroupKAnonymityManager::RegisterAdAsWon(const GURL& render_url) { + RegisterIDAsJoined(render_url.spec()); +} + +void InterestGroupKAnonymityManager::RegisterIDAsJoined( + const std::string& key) { + if (!k_anonymity_service_) + return; + interest_group_manager_->GetLastKAnonymityReported( + key, + base::BindOnce(&InterestGroupKAnonymityManager::OnGotLastReportedTime, + weak_ptr_factory_.GetWeakPtr(), key)); +} + +void InterestGroupKAnonymityManager::OnGotLastReportedTime( + std::string key, + absl::optional<base::Time> last_update_time) { + DCHECK(last_update_time); + if (!last_update_time) + return; + + // If it has been long enough since we last joined + if (base::Time::Now() < + last_update_time.value_or(base::Time()) + kUpdateExpiration) + return; + + std::string hash = KAnonHash(key); + k_anonymity_service_->JoinSet( + std::move(hash), + base::BindOnce(&InterestGroupKAnonymityManager::JoinSetCallback, + weak_ptr_factory_.GetWeakPtr(), std::move(key))); +} + +void InterestGroupKAnonymityManager::JoinSetCallback(std::string key, + bool status) { + // Update the time regardless of status until we verify the server is stable. + interest_group_manager_->UpdateLastKAnonymityReported(key); +} + +} // namespace content
diff --git a/content/browser/interest_group/interest_group_k_anonymity_manager.h b/content/browser/interest_group/interest_group_k_anonymity_manager.h new file mode 100644 index 0000000..3abc3bb --- /dev/null +++ b/content/browser/interest_group/interest_group_k_anonymity_manager.h
@@ -0,0 +1,79 @@ +// 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 CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_K_ANONYMITY_MANAGER_H_ +#define CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_K_ANONYMITY_MANAGER_H_ + +#include "base/memory/raw_ptr.h" +#include "content/browser/interest_group/storage_interest_group.h" +#include "content/public/browser/k_anonymity_service_delegate.h" +#include "third_party/blink/public/common/interest_group/interest_group.h" + +namespace content { +class InterestGroupManagerImpl; + +// Calculates the k-anonymity key for an interest group from the owner and name +std::string KAnonKeyFor(const url::Origin& owner, const std::string& name); + +// Manages k-anonymity updates. Checks last updated times in the database +// to limit updates (joins and queries) to once per day. Called by the +// InterestGroupManagerImpl for interest group k-anonymity updates. Calls +// The InterestGroupManagerImpl to access interest group storage to perform +// interest group updates. +class InterestGroupKAnonymityManager { + public: + InterestGroupKAnonymityManager( + InterestGroupManagerImpl* interest_group_manager, + std::unique_ptr<KAnonymityServiceDelegate> k_anonymity_service); + ~InterestGroupKAnonymityManager(); + + // Requests the k-anonymity status of elements of the interest group that + // haven't been updated in 24 hours or more. Results are passed to + // interest_group_manater_->UpdateKAnonymity. + void QueryKAnonymityForInterestGroup( + const StorageInterestGroup& storage_group); + + // Notify the k-anonymity service that we are joining this interest group. + // Internally this calls RegisterIDAsJoined() for interest group name and + // update URL. + void RegisterInterestGroupAsJoined(const blink::InterestGroup& group); + + // Notify the k-anonymity service that this ad won an auction. Internally this + // calls RegisterIDAsJoined(). + void RegisterAdAsWon(const GURL& render_url); + + private: + // Callback from k-anonymity service QuerySets(). Saves the updated results to + // the database by calling interest_group_manager_->UpdateKAnonymity for each + // URL in query with the corresponding k-anonymity status from status. + void QuerySetsCallback(std::vector<std::string> query, + base::Time update_time, + std::vector<bool> status); + + // Starts fetching the LastKAnonymityReported time for `url` from the + // database. + void RegisterIDAsJoined(const std::string& key); + + // Called by the database when the update time for `url` has been retrieved. + // If the last reported time is too long ago, calls JoinSet() on the + // k-anonymity service. + void OnGotLastReportedTime(std::string key, + absl::optional<base::Time> last_update_time); + + // Callback from k-anonymity service JoinSet(). Updates the LastReported time + // for key in the database, regardless of status (fail close). + void JoinSetCallback(std::string key, bool status); + + // An unowned pointer to the InterestGroupManagerImpl that owns this + // InterestGroupUpdateManager. Used as an intermediary to talk to the + // database. + raw_ptr<InterestGroupManagerImpl> interest_group_manager_; + + std::unique_ptr<KAnonymityServiceDelegate> k_anonymity_service_; + base::WeakPtrFactory<InterestGroupKAnonymityManager> weak_ptr_factory_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_K_ANONYMITY_MANAGER_H_
diff --git a/content/browser/interest_group/interest_group_k_anonymity_manager_unittest.cc b/content/browser/interest_group/interest_group_k_anonymity_manager_unittest.cc new file mode 100644 index 0000000..8c42933 --- /dev/null +++ b/content/browser/interest_group/interest_group_k_anonymity_manager_unittest.cc
@@ -0,0 +1,301 @@ +// 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. + +#include "content/browser/interest_group/interest_group_k_anonymity_manager.h" + +#include "base/files/scoped_temp_dir.h" +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "base/time/time.h" +#include "content/browser/interest_group/interest_group_manager_impl.h" +#include "content/browser/interest_group/storage_interest_group.h" +#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/interest_group/interest_group.h" +#include "url/origin.h" + +namespace content { + +namespace { + +constexpr char kAdURL[] = "https://www.foo.com/ad1.html"; +constexpr char kUpdateURL[] = "https://www.example.com/update"; + +class TestKAnonymityServiceDelegate : public KAnonymityServiceDelegate { + public: + TestKAnonymityServiceDelegate(bool has_error = false) + : has_error_(has_error) {} + + void JoinSet(std::string id, + base::OnceCallback<void(bool)> callback) override { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), has_error_)); + } + + void QuerySets( + std::vector<std::string> ids, + base::OnceCallback<void(std::vector<bool>)> callback) override { + if (has_error_) { + // An error is indicated by an empty status. + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), std::vector<bool>())); + } else { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), + std::vector<bool>(ids.size(), true))); + } + } + + private: + bool has_error_; +}; + +blink::InterestGroup MakeInterestGroup(url::Origin owner, std::string name) { + blink::InterestGroup group; + group.expiry = base::Time::Now() + base::Days(1); + group.owner = owner; + group.name = name; + group.daily_update_url = GURL(kUpdateURL); + group.ads.emplace(); + group.ads->push_back(blink::InterestGroup::Ad(GURL(kAdURL), /*metadata=*/"")); + EXPECT_TRUE(group.IsValid()); + return group; +} + +} // namespace + +class InterestGroupKAnonymityManagerTest : public testing::Test { + public: + void SetUp() override { ASSERT_TRUE(temp_directory_.CreateUniqueTempDir()); } + + absl::optional<StorageInterestGroup> getGroup( + InterestGroupManagerImpl* manager, + url::Origin owner, + std::string name) { + absl::optional<StorageInterestGroup> result; + base::RunLoop run_loop; + manager->GetInterestGroup( + blink::InterestGroupKey(owner, name), + base::BindLambdaForTesting( + [&result, &run_loop](absl::optional<StorageInterestGroup> group) { + result = std::move(group); + run_loop.Quit(); + })); + run_loop.Run(); + return result; + } + + absl::optional<base::Time> getLastReported(InterestGroupManagerImpl* manager, + std::string key) { + absl::optional<base::Time> result; + base::RunLoop run_loop; + manager->GetLastKAnonymityReported( + key, base::BindLambdaForTesting( + [&result, &run_loop](absl::optional<base::Time> reported) { + result = std::move(reported); + run_loop.Quit(); + })); + run_loop.Run(); + return result; + } + + std::unique_ptr<InterestGroupManagerImpl> CreateManager( + bool has_error = false) { + return std::make_unique<InterestGroupManagerImpl>( + temp_directory_.GetPath(), false, + InterestGroupManagerImpl::ProcessMode::kDedicated, nullptr, + std::make_unique<TestKAnonymityServiceDelegate>(has_error)); + } + + base::test::TaskEnvironment& task_environment() { return task_environment_; } + + private: + base::ScopedTempDir temp_directory_; + base::test::TaskEnvironment task_environment_{ + base::test::TaskEnvironment::TimeSource::MOCK_TIME}; +}; + +TEST_F(InterestGroupKAnonymityManagerTest, + QueueUpdatePerformsQuerySetsForGroup) { + auto manager = CreateManager(); + const GURL top_frame = GURL("https://www.example.com/foo"); + const url::Origin owner = url::Origin::Create(top_frame); + const std::string name = "foo"; + + EXPECT_FALSE(getGroup(manager.get(), owner, name)); + base::Time before_join = base::Time::Now(); + + // Join queues the update, but returns first. + manager->JoinInterestGroup(MakeInterestGroup(owner, "foo"), top_frame); + auto maybe_group = getGroup(manager.get(), owner, name); + ASSERT_TRUE(maybe_group); + EXPECT_EQ(base::Time::Min(), maybe_group->name_kanon->last_updated); + + // k-anonymity update happens here. + task_environment().FastForwardBy(base::Minutes(1)); + + maybe_group = getGroup(manager.get(), owner, name); + ASSERT_TRUE(maybe_group); + base::Time last_updated = maybe_group->name_kanon->last_updated; + EXPECT_LE(before_join, last_updated); + EXPECT_GT(base::Time::Now(), last_updated); + + // Updated recently so we shouldn't update again. + manager->QueueKAnonymityUpdateForInterestGroup(*maybe_group); + + // k-anonymity update happens here. + task_environment().FastForwardBy(base::Minutes(1)); + + maybe_group = getGroup(manager.get(), owner, name); + ASSERT_TRUE(maybe_group); + EXPECT_EQ(last_updated, maybe_group->name_kanon->last_updated); + + task_environment().FastForwardBy(base::Hours(24)); + + // Updated more than 24 hours ago, so update. + manager->QueueKAnonymityUpdateForInterestGroup(*maybe_group); + task_environment().RunUntilIdle(); + maybe_group = getGroup(manager.get(), owner, name); + ASSERT_TRUE(maybe_group); + EXPECT_LT(last_updated, maybe_group->name_kanon->last_updated); +} + +TEST_F(InterestGroupKAnonymityManagerTest, QueueUpdatePerformsJoinSetForGroup) { + const GURL top_frame = GURL("https://www.example.com/foo"); + const url::Origin owner = url::Origin::Create(top_frame); + const std::string name = "foo"; + + std::string group_name_url = "https://www.example.com/\nfoo"; + std::string group_update_url = kUpdateURL; + + auto manager = CreateManager(); + EXPECT_FALSE(getLastReported(manager.get(), group_name_url)); + EXPECT_FALSE(getGroup(manager.get(), owner, name)); + base::Time before_join = base::Time::Now(); + + // JoinInterestGroup should call QueueKAnonymityUpdateForInterestGroup. + manager->JoinInterestGroup(MakeInterestGroup(owner, "foo"), top_frame); + + // k-anonymity update happens here. + task_environment().FastForwardBy(base::Minutes(1)); + + EXPECT_TRUE(getGroup(manager.get(), owner, name)); + + absl::optional<base::Time> group_name_reported = + getLastReported(manager.get(), group_name_url); + ASSERT_TRUE(group_name_reported); + EXPECT_LE(before_join, group_name_reported); + + absl::optional<base::Time> update_url_reported = + getLastReported(manager.get(), kUpdateURL); + ASSERT_TRUE(update_url_reported); + EXPECT_LE(before_join, update_url_reported); + + auto maybe_group = getGroup(manager.get(), owner, name); + ASSERT_TRUE(maybe_group); + + manager->QueueKAnonymityUpdateForInterestGroup(*maybe_group); + + // k-anonymity update would happen here. + task_environment().FastForwardBy(base::Minutes(1)); + + // Second update shouldn't change anything. + EXPECT_EQ(group_name_reported, + getLastReported(manager.get(), group_name_url)); + EXPECT_EQ(update_url_reported, getLastReported(manager.get(), kUpdateURL)); + + task_environment().FastForwardBy(base::Hours(24)); + + // Updated more than 24 hours ago, so update. + manager->QueueKAnonymityUpdateForInterestGroup(*maybe_group); + task_environment().RunUntilIdle(); + EXPECT_LT(update_url_reported, getLastReported(manager.get(), kUpdateURL)); +} + +TEST_F(InterestGroupKAnonymityManagerTest, RegisterAdAsWonPerformsJoinSet) { + const GURL top_frame = GURL("https://www.example.com/foo"); + const url::Origin owner = url::Origin::Create(top_frame); + const std::string name = "foo"; + + auto manager = CreateManager(); + EXPECT_FALSE(getGroup(manager.get(), owner, name)); + EXPECT_FALSE(getLastReported(manager.get(), kAdURL)); + + manager->JoinInterestGroup(MakeInterestGroup(owner, "foo"), top_frame); + // The group *must* exist when JoinInterestGroup returns. + ASSERT_TRUE(getGroup(manager.get(), owner, name)); + + // k-anonymity would happens here. + task_environment().FastForwardBy(base::Minutes(1)); + + // Ads are *not* reported as part of joining an interest group. + absl::optional<base::Time> reported = getLastReported(manager.get(), kAdURL); + EXPECT_EQ(base::Time::Min(), reported); + + base::Time before_mark_ad = base::Time::Now(); + manager->RegisterAdAsWon(GURL(kAdURL)); + + // k-anonymity update happens here. + task_environment().FastForwardBy(base::Minutes(1)); + + reported = getLastReported(manager.get(), kAdURL); + EXPECT_LE(before_mark_ad, reported); + ASSERT_TRUE(reported); + base::Time last_reported = *reported; + + manager->RegisterAdAsWon(GURL(kAdURL)); + task_environment().FastForwardBy(base::Minutes(1)); + + // Second update shouldn't have changed the update time (too recent). + EXPECT_EQ(last_reported, getLastReported(manager.get(), kAdURL)); + + task_environment().FastForwardBy(base::Hours(24)); + + // Updated more than 24 hours ago, so update. + manager->RegisterAdAsWon(GURL(kAdURL)); + task_environment().RunUntilIdle(); + EXPECT_LT(last_reported, getLastReported(manager.get(), kAdURL)); +} + +TEST_F(InterestGroupKAnonymityManagerTest, HandlesServerErrors) { + const GURL top_frame = GURL("https://www.example.com/foo"); + const url::Origin owner = url::Origin::Create(top_frame); + const std::string name = "foo"; + + base::Time start_time = base::Time::Now(); + + auto manager = CreateManager(/*has_error=*/true); + manager->JoinInterestGroup(MakeInterestGroup(owner, "foo"), top_frame); + // The group *must* exist when JoinInterestGroup returns. + ASSERT_TRUE(getGroup(manager.get(), owner, name)); + + // k-anonymity update happens here. + task_environment().FastForwardBy(base::Minutes(1)); + + // If the updates succeed then we normally would not record the update as + // having been completed, so we would try it later. + // For now we'll record the update as having been completed to to reduce + // bandwidth and provide more accurate use counts. + // When the server is actually implemented we'll need to change the expected + // values below. + + absl::optional<base::Time> group_name_reported = + getLastReported(manager.get(), kUpdateURL); + ASSERT_TRUE(group_name_reported); + + // TODO(behamilton): Change this once we expect the server to be stable. + EXPECT_LE(start_time, group_name_reported); + // EXPECT_EQ(base::Time::Min(), group_name_reported); + + auto maybe_group = getGroup(manager.get(), owner, name); + ASSERT_TRUE(maybe_group); + + // TODO(behamilton): Change this once we expect the server to be stable. + EXPECT_LE(start_time, maybe_group->name_kanon->last_updated); + // EXPECT_EQ(base::Time::Min(), maybe_group->name_kanon->last_updated); +} + +} // namespace content
diff --git a/content/browser/interest_group/interest_group_manager_impl.cc b/content/browser/interest_group/interest_group_manager_impl.cc index 7d19d61..321893c 100644 --- a/content/browser/interest_group/interest_group_manager_impl.cc +++ b/content/browser/interest_group/interest_group_manager_impl.cc
@@ -96,7 +96,8 @@ const base::FilePath& path, bool in_memory, ProcessMode process_mode, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + std::unique_ptr<KAnonymityServiceDelegate> k_anonymity_service) : impl_(base::ThreadPool::CreateSequencedTaskRunner( {base::MayBlock(), base::TaskPriority::USER_VISIBLE, base::TaskShutdownBehavior::BLOCK_SHUTDOWN}), @@ -107,6 +108,9 @@ new DedicatedAuctionProcessManager()) : new InRendererAuctionProcessManager())), update_manager_(this, std::move(url_loader_factory)), + k_anonymity_manager_(std::make_unique<InterestGroupKAnonymityManager>( + this, + std::move(k_anonymity_service))), max_active_report_requests_(kMaxActiveReportRequests), max_report_queue_length_(kMaxReportQueueLength), reporting_interval_(kReportingInterval), @@ -159,8 +163,27 @@ const GURL& joining_url) { NotifyInterestGroupAccessed(InterestGroupObserverInterface::kJoin, group.owner.Serialize(), group.name); + blink::InterestGroupKey group_key(group.owner, group.name); impl_.AsyncCall(&InterestGroupStorage::JoinInterestGroup) .WithArgs(std::move(group), std::move(joining_url)); + // This needs to happen second so that the DB row is created. + GetInterestGroup( + group_key, + base::BindOnce( + &InterestGroupManagerImpl:: + QueueKAnonymityUpdateForInterestGroupFromJoinInterestGroup, + weak_factory_.GetWeakPtr())); +} + +void InterestGroupManagerImpl:: + QueueKAnonymityUpdateForInterestGroupFromJoinInterestGroup( + absl::optional<StorageInterestGroup> maybe_group) { + // We just joined the group, so it must exist. + // We don't need to worry about the DB size limit, since older groups + // are removed first. + DCHECK(maybe_group); + if (maybe_group) + QueueKAnonymityUpdateForInterestGroup(*maybe_group); } void InterestGroupManagerImpl::LeaveInterestGroup( @@ -216,6 +239,10 @@ .WithArgs(group_key, std::move(ad_json)); } +void InterestGroupManagerImpl::RegisterAdAsWon(const GURL& render_url) { + k_anonymity_manager_->RegisterAdAsWon(render_url); +} + void InterestGroupManagerImpl::GetInterestGroup( const url::Origin& owner, const std::string& name, @@ -467,6 +494,31 @@ .WithArgs(group_key, priority); } +void InterestGroupManagerImpl::QueueKAnonymityUpdateForInterestGroup( + const StorageInterestGroup& group) { + k_anonymity_manager_->QueryKAnonymityForInterestGroup(group); + k_anonymity_manager_->RegisterInterestGroupAsJoined(group.interest_group); +} + +void InterestGroupManagerImpl::UpdateKAnonymity( + const StorageInterestGroup::KAnonymityData& data) { + impl_.AsyncCall(&InterestGroupStorage::UpdateKAnonymity).WithArgs(data); +} + +void InterestGroupManagerImpl::GetLastKAnonymityReported( + const std::string& key, + base::OnceCallback<void(absl::optional<base::Time>)> callback) { + impl_.AsyncCall(&InterestGroupStorage::GetLastKAnonymityReported) + .WithArgs(key) + .Then(std::move(callback)); +} + +void InterestGroupManagerImpl::UpdateLastKAnonymityReported( + const std::string& key) { + impl_.AsyncCall(&InterestGroupStorage::UpdateLastKAnonymityReported) + .WithArgs(key); +} + void InterestGroupManagerImpl::set_max_report_queue_length_for_testing( int max_queue_length) { max_report_queue_length_ = max_queue_length;
diff --git a/content/browser/interest_group/interest_group_manager_impl.h b/content/browser/interest_group/interest_group_manager_impl.h index e7d2d671..c34091d 100644 --- a/content/browser/interest_group/interest_group_manager_impl.h +++ b/content/browser/interest_group/interest_group_manager_impl.h
@@ -17,12 +17,14 @@ #include "base/threading/sequence_bound.h" #include "base/time/time.h" #include "content/browser/interest_group/auction_process_manager.h" +#include "content/browser/interest_group/interest_group_k_anonymity_manager.h" #include "content/browser/interest_group/interest_group_permissions_checker.h" #include "content/browser/interest_group/interest_group_update.h" #include "content/browser/interest_group/interest_group_update_manager.h" #include "content/browser/interest_group/storage_interest_group.h" #include "content/common/content_export.h" #include "content/public/browser/interest_group_manager.h" +#include "content/public/browser/k_anonymity_service_delegate.h" #include "content/public/browser/storage_partition.h" #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom-forward.h" #include "services/network/public/cpp/resource_request.h" @@ -63,7 +65,8 @@ const base::FilePath& path, bool in_memory, ProcessMode process_mode, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + std::unique_ptr<KAnonymityServiceDelegate> k_anonymity_service); ~InterestGroupManagerImpl() override; InterestGroupManagerImpl(const InterestGroupManagerImpl& other) = delete; InterestGroupManagerImpl& operator=(const InterestGroupManagerImpl& other) = @@ -157,6 +160,11 @@ // piece of opaque data to identify the winning ad. void RecordInterestGroupWin(const blink::InterestGroupKey& group_key, const std::string& ad_json); + + // Reports the AD URL to the k-anonymity service. Should be called when FLEDGE + // selects and ad. + void RegisterAdAsWon(const GURL& render_url); + // Gets a single interest group. void GetInterestGroup( const blink::InterestGroupKey& group_key, @@ -240,10 +248,29 @@ return report_requests_.size(); } + // Handles daily k-anonymity updates for the interest group. Triggers an + // update request for the k-anonymity of all parts of the interest group + // (including ads). Also reports membership in the interest group to the + // k-anonymity of interest-group service. + void QueueKAnonymityUpdateForInterestGroup(const StorageInterestGroup& group); + // Records K-anonymity to the database. + void UpdateKAnonymity(const StorageInterestGroup::KAnonymityData& data); + // Gets the last time that the key was reported to the k-anonymity server. + void GetLastKAnonymityReported( + const std::string& key, + base::OnceCallback<void(absl::optional<base::Time>)> callback); + // Updates the last time that the key was reported to the k-anonymity server. + void UpdateLastKAnonymityReported(const std::string& key); + InterestGroupPermissionsChecker& permissions_checker_for_testing() { return permissions_checker_; } + void set_k_anonymity_manager_for_testing( + std::unique_ptr<InterestGroupKAnonymityManager> k_anonymity_manager) { + k_anonymity_manager_ = std::move(k_anonymity_manager); + } + private: // InterestGroupUpdateManager calls private members to write updates to the // database. @@ -336,6 +363,12 @@ std::unique_ptr<network::SimpleURLLoader> simple_url_loader, scoped_refptr<net::HttpResponseHeaders> response_headers); + // A version of QueueKAnonymityUpdateForInterestGroup() called from + // JoinInterestGroup which passes the group in an optional (the group must + // always exist). Called from JoinInterestGroup. + void QueueKAnonymityUpdateForInterestGroupFromJoinInterestGroup( + absl::optional<StorageInterestGroup> maybe_group); + // Owns and manages access to the InterestGroupStorage living on a different // thread. base::SequenceBound<InterestGroupStorage> impl_; @@ -355,6 +388,17 @@ // methods so that updates are cancelled before those fields are destroyed. InterestGroupUpdateManager update_manager_; + // Manages the logic required to support k-anonymity updates. + // + // InterestGroupKAnonymityManager keeps a pointer to this + // InterestGroupManagerImpl to make database reads and writes.... + // + // Therefore, `k_anonymity_manager_` *must* be declared after fields used by + // those methods so that k-anonymity operations are cancelled before those + // fields are destroyed. + // Stored as pointer so that tests can override it. + std::unique_ptr<InterestGroupKAnonymityManager> k_anonymity_manager_; + // Checks if a frame can join or leave an interest group. Global so that // pending operations can continue after a page has been navigate away from. InterestGroupPermissionsChecker permissions_checker_;
diff --git a/content/browser/interest_group/interest_group_storage.cc b/content/browser/interest_group/interest_group_storage.cc index 0b49a70..b06cd82b 100644 --- a/content/browser/interest_group/interest_group_storage.cc +++ b/content/browser/interest_group/interest_group_storage.cc
@@ -26,6 +26,7 @@ #include "base/strings/stringprintf.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/time/time.h" +#include "content/browser/interest_group/interest_group_k_anonymity_manager.h" #include "content/browser/interest_group/interest_group_update.h" #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h" #include "mojo/public/cpp/bindings/receiver.h" @@ -86,12 +87,6 @@ // |kCurrentVersionNumber| without razing the database. const int kDeprecatedVersionNumber = 5; -GURL KAnonKeyFor(url::Origin interest_group_owner, - std::string interest_group_name) { - return interest_group_owner.GetURL().Resolve( - base::EscapePath(interest_group_name)); -} - std::string Serialize(const base::Value& value) { std::string json_output; JSONStringValueSerializer serializer(&json_output); @@ -626,7 +621,7 @@ } bool DoCreateOrMarkKAnonReferenced(sql::Database& db, - const GURL& key, + const std::string key, const base::Time& now) { base::Time distant_past = base::Time::Min(); base::Time cutoff = now - InterestGroupStorage::kHistoryLength; @@ -654,7 +649,7 @@ maybe_insert_kanon.Reset(true); maybe_insert_kanon.BindTime(0, now); - maybe_insert_kanon.BindString(1, Serialize(key)); + maybe_insert_kanon.BindString(1, key); maybe_insert_kanon.BindTime(2, distant_past); maybe_insert_kanon.BindTime(3, distant_past); @@ -686,7 +681,7 @@ update_kanon.BindTime(0, now); update_kanon.BindTime(1, cutoff); update_kanon.BindTime(2, distant_past); - update_kanon.BindString(3, Serialize(key)); + update_kanon.BindString(3, key); return update_kanon.Run(); } @@ -702,13 +697,13 @@ sql::Database& db, const GURL& daily_update_url, const base::Time& now) { - return DoCreateOrMarkKAnonReferenced(db, daily_update_url, now); + return DoCreateOrMarkKAnonReferenced(db, daily_update_url.spec(), now); } bool DoCreateOrMarkAdReferenced(sql::Database& db, const blink::InterestGroup::Ad& ad, const base::Time& now) { - return DoCreateOrMarkKAnonReferenced(db, ad.render_url, now); + return DoCreateOrMarkKAnonReferenced(db, ad.render_url.spec(), now); } // Takes a blink::InterestGroup, or InterestGroupUpdate. @@ -1310,15 +1305,12 @@ } bool DoUpdateKAnonymity(sql::Database& db, - const StorageInterestGroup::KAnonymityData& data, - const absl::optional<base::Time>& update_sent_time) { + const StorageInterestGroup::KAnonymityData& data) { // clang-format off sql::Statement update( db.GetCachedStatement(SQL_FROM_HERE, "UPDATE k_anon " - "SET is_k_anon=?, last_k_anon_updated_time=?," - "last_reported_to_anon_server_time=" - "IFNULL(?,last_reported_to_anon_server_time) " + "SET is_k_anon=?, last_k_anon_updated_time=? " "WHERE key=?")); // clang-format on if (!update.is_valid()) @@ -1327,35 +1319,32 @@ update.Reset(true); update.BindInt(0, data.is_k_anonymous); update.BindTime(1, data.last_updated); - if (update_sent_time) - update.BindTime(2, update_sent_time.value()); - else - update.BindNull(2); - update.BindString(3, Serialize(data.key)); + update.BindString(2, data.key); return update.Run(); } -base::Time DoGetLastKAnonymityReported(sql::Database& db, const GURL& key) { +absl::optional<base::Time> DoGetLastKAnonymityReported(sql::Database& db, + const std::string& key) { sql::Statement get_reported(db.GetCachedStatement( SQL_FROM_HERE, "SELECT last_reported_to_anon_server_time FROM k_anon WHERE key=?")); if (!get_reported.is_valid()) { DLOG(ERROR) << "GetLastKAnonymityReported SQL statement did not compile: " << db.GetErrorMessage(); - return {}; + return absl::nullopt; } get_reported.Reset(true); - get_reported.BindString(0, key.spec()); + get_reported.BindString(0, key); if (!get_reported.Step()) { - return {}; + return absl::nullopt; } if (!get_reported.Succeeded()) - return {}; + return absl::nullopt; return get_reported.ColumnTime(0); } void DoUpdateLastKAnonymityReported(sql::Database& db, - const GURL& key, + const std::string& key, base::Time now) { sql::Statement set_reported(db.GetCachedStatement( SQL_FROM_HERE, @@ -1368,7 +1357,7 @@ } set_reported.Reset(true); set_reported.BindTime(0, now); - set_reported.BindString(1, key.spec()); + set_reported.BindString(1, key); if (!set_reported.Run()) { return; } @@ -1424,7 +1413,7 @@ bool DoGetKAnonymity( sql::Database& db, - const GURL& key, + const std::string& key, absl::optional<StorageInterestGroup::KAnonymityData>& output) { // clang-format off sql::Statement interest_group_kanon( @@ -1443,7 +1432,7 @@ } interest_group_kanon.Reset(true); - interest_group_kanon.BindString(0, Serialize(key)); + interest_group_kanon.BindString(0, key); if (!interest_group_kanon.Step()) { return false; @@ -1462,6 +1451,13 @@ return DoGetKAnonymity(db, KAnonKeyFor(owner, name), output); } +bool DoGetURLKAnonymity( + sql::Database& db, + const GURL& url, + absl::optional<StorageInterestGroup::KAnonymityData>& output) { + return DoGetKAnonymity(db, url.spec(), output); +} + bool GetPreviousWins(sql::Database& db, const blink::InterestGroupKey& group_key, base::Time win_time_after, @@ -1591,10 +1587,20 @@ if (!DoGetInterestGroupNameKAnonymity(db, group_key.owner, group_key.name, db_interest_group.name_kanon)) { - return absl::nullopt; + // This should only happen if the database was created with an older version + // of the k-anon key for interest group names. Try the old group name. + // TODO(behamilton): Remove this in a new version + if (!DoGetKAnonymity(db, + group_key.owner.GetURL() + .Resolve(base::EscapePath(group_key.name)) + .spec(), + db_interest_group.name_kanon)) + return absl::nullopt; + db_interest_group.name_kanon->key = + KAnonKeyFor(group_key.owner, group_key.name); } if (db_interest_group.interest_group.daily_update_url && - !DoGetKAnonymity( + !DoGetURLKAnonymity( db, db_interest_group.interest_group.daily_update_url.value(), db_interest_group.daily_update_url_kanon)) { return absl::nullopt; @@ -1602,7 +1608,7 @@ if (db_interest_group.interest_group.ads) { for (auto& ad : db_interest_group.interest_group.ads.value()) { absl::optional<StorageInterestGroup::KAnonymityData> ad_kanon; - if (!DoGetKAnonymity(db, ad.render_url, ad_kanon)) { + if (!DoGetURLKAnonymity(db, ad.render_url, ad_kanon)) { return absl::nullopt; } if (!ad_kanon) @@ -1613,7 +1619,7 @@ if (db_interest_group.interest_group.ad_components) { for (auto& ad : db_interest_group.interest_group.ad_components.value()) { absl::optional<StorageInterestGroup::KAnonymityData> ad_kanon; - if (!DoGetKAnonymity(db, ad.render_url, ad_kanon)) { + if (!DoGetURLKAnonymity(db, ad.render_url, ad_kanon)) { return absl::nullopt; } if (!ad_kanon) @@ -2209,18 +2215,18 @@ } void InterestGroupStorage::UpdateKAnonymity( - const StorageInterestGroup::KAnonymityData& data, - const absl::optional<base::Time>& update_sent_time) { + const StorageInterestGroup::KAnonymityData& data) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!EnsureDBInitialized()) return; - if (!DoUpdateKAnonymity(*db_, data, update_sent_time)) { + if (!DoUpdateKAnonymity(*db_, data)) { DLOG(ERROR) << "Could not update k-anonymity: " << db_->GetErrorMessage(); } } -base::Time InterestGroupStorage::GetLastKAnonymityReported(const GURL& key) { +absl::optional<base::Time> InterestGroupStorage::GetLastKAnonymityReported( + const std::string& key) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!EnsureDBInitialized()) return {}; @@ -2228,7 +2234,8 @@ return DoGetLastKAnonymityReported(*db_, key); } -void InterestGroupStorage::UpdateLastKAnonymityReported(const GURL& key) { +void InterestGroupStorage::UpdateLastKAnonymityReported( + const std::string& key) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!EnsureDBInitialized()) return;
diff --git a/content/browser/interest_group/interest_group_storage.h b/content/browser/interest_group/interest_group_storage.h index c7f7d24..2398ff3b 100644 --- a/content/browser/interest_group/interest_group_storage.h +++ b/content/browser/interest_group/interest_group_storage.h
@@ -83,13 +83,12 @@ void RecordInterestGroupWin(const blink::InterestGroupKey& group_key, const std::string& ad_json); // Records K-anonymity. - void UpdateKAnonymity(const StorageInterestGroup::KAnonymityData& data, - const absl::optional<base::Time>& update_sent_time); + void UpdateKAnonymity(const StorageInterestGroup::KAnonymityData& data); // Gets the last time that the key was reported to the k-anonymity server. - base::Time GetLastKAnonymityReported(const GURL& key); + absl::optional<base::Time> GetLastKAnonymityReported(const std::string& key); // Updates the last time that the key was reported to the k-anonymity server. - void UpdateLastKAnonymityReported(const GURL& key); + void UpdateLastKAnonymityReported(const std::string& key); // Gets a single interest group. absl::optional<StorageInterestGroup> GetInterestGroup(
diff --git a/content/browser/interest_group/interest_group_storage_unittest.cc b/content/browser/interest_group/interest_group_storage_unittest.cc index beaed5349..d695b02 100644 --- a/content/browser/interest_group/interest_group_storage_unittest.cc +++ b/content/browser/interest_group/interest_group_storage_unittest.cc
@@ -422,8 +422,8 @@ const std::string name = "name with space"; const std::string name2 = "name%20with%20space"; - const GURL key = test_origin.GetURL().Resolve(base::EscapePath(name)); - const GURL key2 = test_origin.GetURL().Resolve(base::EscapePath(name2)); + const std::string key = test_origin.GetURL().spec() + '\n' + name; + const std::string key2 = test_origin.GetURL().spec() + '\n' + name2; std::unique_ptr<InterestGroupStorage> storage = CreateStorage(); @@ -457,7 +457,7 @@ base::Time update_time = base::Time::Now(); StorageInterestGroup::KAnonymityData kanon{key, true, update_time}; - storage->UpdateKAnonymity(kanon, absl::nullopt); + storage->UpdateKAnonymity(kanon); groups = storage->GetInterestGroupsForOwner(test_origin); @@ -478,7 +478,7 @@ update_time = base::Time::Now(); kanon = StorageInterestGroup::KAnonymityData{key, true, update_time}; - storage->UpdateKAnonymity(kanon, absl::nullopt); + storage->UpdateKAnonymity(kanon); groups = storage->GetInterestGroupsForOwner(test_origin); @@ -536,9 +536,9 @@ EXPECT_EQ(base::Time::Min(), groups[1].daily_update_url_kanon->last_updated); base::Time update_time = base::Time::Now(); - StorageInterestGroup::KAnonymityData kanon{daily_update_url, true, + StorageInterestGroup::KAnonymityData kanon{daily_update_url.spec(), true, update_time}; - storage->UpdateKAnonymity(kanon, absl::nullopt); + storage->UpdateKAnonymity(kanon); groups = storage->GetInterestGroupsForOwner(test_origin); @@ -558,9 +558,9 @@ task_environment().FastForwardBy(base::Seconds(1)); update_time = base::Time::Now(); - kanon = - StorageInterestGroup::KAnonymityData{daily_update_url, true, update_time}; - storage->UpdateKAnonymity(kanon, absl::nullopt); + kanon = StorageInterestGroup::KAnonymityData{daily_update_url.spec(), true, + update_time}; + storage->UpdateKAnonymity(kanon); groups = storage->GetInterestGroupsForOwner(test_origin); @@ -606,10 +606,10 @@ groups = storage->GetInterestGroupsForOwner(test_origin); std::vector<StorageInterestGroup::KAnonymityData> expected_output = { - {ad1_url, false, base::Time::Min()}, - {ad2_url, false, base::Time::Min()}, - {ad1_url, false, base::Time::Min()}, - {ad3_url, false, base::Time::Min()}, + {ad1_url.spec(), false, base::Time::Min()}, + {ad2_url.spec(), false, base::Time::Min()}, + {ad1_url.spec(), false, base::Time::Min()}, + {ad3_url.spec(), false, base::Time::Min()}, }; ASSERT_EQ(1u, groups.size()); @@ -617,8 +617,8 @@ testing::UnorderedElementsAreArray(expected_output)); base::Time update_time = base::Time::Now(); - StorageInterestGroup::KAnonymityData kanon{ad1_url, true, update_time}; - storage->UpdateKAnonymity(kanon, absl::nullopt); + StorageInterestGroup::KAnonymityData kanon{ad1_url.spec(), true, update_time}; + storage->UpdateKAnonymity(kanon); expected_output[0] = kanon; expected_output[2] = kanon; @@ -631,8 +631,9 @@ task_environment().FastForwardBy(base::Seconds(1)); update_time = base::Time::Now(); - kanon = StorageInterestGroup::KAnonymityData{ad2_url, true, update_time}; - storage->UpdateKAnonymity(kanon, absl::nullopt); + kanon = + StorageInterestGroup::KAnonymityData{ad2_url.spec(), true, update_time}; + storage->UpdateKAnonymity(kanon); expected_output[1] = kanon; groups = storage->GetInterestGroupsForOwner(test_origin); @@ -646,7 +647,7 @@ GURL daily_update_url("https://owner.example.com/groupUpdate"); url::Origin test_origin = url::Origin::Create(daily_update_url); const std::string name = "name"; - const GURL key = test_origin.GetURL().Resolve(base::EscapePath(name)); + const std::string key = test_origin.GetURL().spec() + '\n' + name; // We make the ad urls equal to the name key and update urls to verify the // database stores them separately. GURL ad1_url = GURL("https://owner.example.com/groupUpdate"); @@ -667,17 +668,17 @@ // Update the k-anonymity data. base::Time update_kanon_time = base::Time::Now(); - StorageInterestGroup::KAnonymityData ad1_kanon{ad1_url, true, + StorageInterestGroup::KAnonymityData ad1_kanon{ad1_url.spec(), true, update_kanon_time}; - StorageInterestGroup::KAnonymityData ad2_kanon{ad2_url, true, + StorageInterestGroup::KAnonymityData ad2_kanon{ad2_url.spec(), true, update_kanon_time}; - StorageInterestGroup::KAnonymityData update_kanon{daily_update_url, true, - update_kanon_time}; + StorageInterestGroup::KAnonymityData update_kanon{daily_update_url.spec(), + true, update_kanon_time}; StorageInterestGroup::KAnonymityData name_kanon{key, true, update_kanon_time}; - storage->UpdateKAnonymity(ad1_kanon, update_kanon_time); - storage->UpdateKAnonymity(ad2_kanon, update_kanon_time); - storage->UpdateKAnonymity(update_kanon, update_kanon_time); - storage->UpdateKAnonymity(name_kanon, update_kanon_time); + storage->UpdateKAnonymity(ad1_kanon); + storage->UpdateKAnonymity(ad2_kanon); + storage->UpdateKAnonymity(update_kanon); + storage->UpdateKAnonymity(name_kanon); // Check k-anonymity data was correctly set. std::vector<StorageInterestGroup::KAnonymityData> expected_output = { @@ -725,10 +726,11 @@ storage->JoinInterestGroup(g, GURL("https://owner.example.com/join3")); // K-anon data should be the default. - ad1_kanon = {ad1_url, 0, base::Time::Min()}; - ad2_kanon = {ad2_url, 0, base::Time::Min()}; - update_kanon = {daily_update_url, 0, base::Time::Min()}; - name_kanon = {key, 0, base::Time::Min()}; + ad1_kanon = {ad1_url.spec(), /*is_k_anonymous=*/false, base::Time::Min()}; + ad2_kanon = {ad2_url.spec(), /*is_k_anonymous=*/false, base::Time::Min()}; + update_kanon = {daily_update_url.spec(), /*is_k_anonymous=*/false, + base::Time::Min()}; + name_kanon = {key, /*is_k_anonymous=*/false, base::Time::Min()}; expected_output = {ad1_kanon, ad2_kanon}; groups = storage->GetInterestGroupsForOwner(test_origin); ASSERT_EQ(1u, groups.size()); @@ -1182,18 +1184,18 @@ 4)))), Field("name_kanon", &StorageInterestGroup::name_kanon, StorageInterestGroup::KAnonymityData{ - GURL("https://owner.example.com/group1"), false, + "https://owner.example.com/\ngroup1", false, base::Time::Min()}), Field("daily_update_url_kanon", &StorageInterestGroup::daily_update_url_kanon, StorageInterestGroup::KAnonymityData{ - GURL("https://owner.example.com/update"), false, + "https://owner.example.com/update", false, base::Time::Min()}), - Field("ads_kanon", &StorageInterestGroup::ads_kanon, - testing::UnorderedElementsAre( - StorageInterestGroup::KAnonymityData{ - GURL("https://ads.example.com/1"), false, - base::Time::Min()})), + Field( + "ads_kanon", &StorageInterestGroup::ads_kanon, + testing::UnorderedElementsAre( + StorageInterestGroup::KAnonymityData{ + "https://ads.example.com/1", false, base::Time::Min()})), Field("joining_origin", &StorageInterestGroup::joining_origin, url::Origin::Create(GURL("https://publisher.example.com"))), Field("join_time", &StorageInterestGroup::join_time, @@ -1263,18 +1265,18 @@ 3)))), Field("name_kanon", &StorageInterestGroup::name_kanon, StorageInterestGroup::KAnonymityData{ - GURL("https://owner.example.com/group2"), false, + "https://owner.example.com/\ngroup2", false, base::Time::Min()}), Field("daily_update_url_kanon", &StorageInterestGroup::daily_update_url_kanon, StorageInterestGroup::KAnonymityData{ - GURL("https://owner.example.com/update"), false, + "https://owner.example.com/update", false, base::Time::Min()}), - Field("ads_kanon", &StorageInterestGroup::ads_kanon, - testing::UnorderedElementsAre( - StorageInterestGroup::KAnonymityData{ - GURL("https://ads.example.com/1"), false, - base::Time::Min()})), + Field( + "ads_kanon", &StorageInterestGroup::ads_kanon, + testing::UnorderedElementsAre( + StorageInterestGroup::KAnonymityData{ + "https://ads.example.com/1", false, base::Time::Min()})), Field("joining_origin", &StorageInterestGroup::joining_origin, url::Origin::Create(GURL("https://publisher.example.com"))), Field("join_time", &StorageInterestGroup::join_time, @@ -1344,18 +1346,18 @@ 4)))), Field("name_kanon", &StorageInterestGroup::name_kanon, StorageInterestGroup::KAnonymityData{ - GURL("https://owner.example.com/group3"), false, + "https://owner.example.com/\ngroup3", false, base::Time::Min()}), Field("daily_update_url_kanon", &StorageInterestGroup::daily_update_url_kanon, StorageInterestGroup::KAnonymityData{ - GURL("https://owner.example.com/update"), false, + "https://owner.example.com/update", false, base::Time::Min()}), - Field("ads_kanon", &StorageInterestGroup::ads_kanon, - testing::UnorderedElementsAre( - StorageInterestGroup::KAnonymityData{ - GURL("https://ads.example.com/1"), false, - base::Time::Min()})), + Field( + "ads_kanon", &StorageInterestGroup::ads_kanon, + testing::UnorderedElementsAre( + StorageInterestGroup::KAnonymityData{ + "https://ads.example.com/1", false, base::Time::Min()})), Field("joining_origin", &StorageInterestGroup::joining_origin, url::Origin::Create(GURL("https://publisher.example.com"))), Field("join_time", &StorageInterestGroup::join_time, @@ -1599,46 +1601,50 @@ blink::InterestGroup::Ad(ad3_url, "component_metadata3")); std::unique_ptr<InterestGroupStorage> storage = CreateStorage(); + absl::optional<base::Time> last_report = + storage->GetLastKAnonymityReported(ad1_url.spec()); + EXPECT_FALSE(last_report); // Not in the database. + storage->JoinInterestGroup(g, GURL("https://owner.example.com/join")); base::Time expected_last_report; - base::Time last_report = storage->GetLastKAnonymityReported(ad1_url); + last_report = storage->GetLastKAnonymityReported(ad1_url.spec()); EXPECT_EQ(last_report, base::Time::Min()); - storage->UpdateLastKAnonymityReported(ad1_url); + storage->UpdateLastKAnonymityReported(ad1_url.spec()); expected_last_report = base::Time::Now(); task_environment().FastForwardBy(base::Seconds(1)); - last_report = storage->GetLastKAnonymityReported(ad1_url); + last_report = storage->GetLastKAnonymityReported(ad1_url.spec()); EXPECT_EQ(last_report, expected_last_report); task_environment().FastForwardBy(base::Seconds(1)); - last_report = storage->GetLastKAnonymityReported(ad2_url); + last_report = storage->GetLastKAnonymityReported(ad2_url.spec()); EXPECT_EQ(last_report, base::Time::Min()); - storage->UpdateLastKAnonymityReported(ad2_url); + storage->UpdateLastKAnonymityReported(ad2_url.spec()); expected_last_report = base::Time::Now(); task_environment().FastForwardBy(base::Seconds(1)); - last_report = storage->GetLastKAnonymityReported(ad2_url); + last_report = storage->GetLastKAnonymityReported(ad2_url.spec()); EXPECT_EQ(last_report, expected_last_report); task_environment().FastForwardBy(base::Seconds(1)); - last_report = storage->GetLastKAnonymityReported(ad3_url); + last_report = storage->GetLastKAnonymityReported(ad3_url.spec()); EXPECT_EQ(last_report, base::Time::Min()); - storage->UpdateLastKAnonymityReported(ad3_url); + storage->UpdateLastKAnonymityReported(ad3_url.spec()); expected_last_report = base::Time::Now(); task_environment().FastForwardBy(base::Seconds(1)); - last_report = storage->GetLastKAnonymityReported(ad3_url); + last_report = storage->GetLastKAnonymityReported(ad3_url.spec()); EXPECT_EQ(last_report, expected_last_report); task_environment().FastForwardBy(base::Seconds(1)); - GURL group_name_key = test_origin.GetURL().Resolve("name"); + std::string group_name_key = test_origin.GetURL().spec() + "\nname"; last_report = storage->GetLastKAnonymityReported(group_name_key); EXPECT_EQ(last_report, base::Time::Min()); storage->UpdateLastKAnonymityReported(group_name_key);
diff --git a/content/browser/interest_group/interest_group_update_manager.cc b/content/browser/interest_group/interest_group_update_manager.cc index 1604e109..74c1f36 100644 --- a/content/browser/interest_group/interest_group_update_manager.cc +++ b/content/browser/interest_group/interest_group_update_manager.cc
@@ -457,8 +457,10 @@ net::IsolationInfo::CreateTransient(); for (auto& storage_group : storage_groups) { + manager_->QueueKAnonymityUpdateForInterestGroup(storage_group); if (!storage_group.interest_group.daily_update_url) continue; + // TODO(behamilton): Don't update unless daily update url is k-anonymous ++num_in_flight_updates_; base::UmaHistogramCounts100000( "Ads.InterestGroup.Net.RequestUrlSizeBytes.Update",
diff --git a/content/browser/interest_group/storage_interest_group.h b/content/browser/interest_group/storage_interest_group.h index e9988064..5bb1b6db 100644 --- a/content/browser/interest_group/storage_interest_group.h +++ b/content/browser/interest_group/storage_interest_group.h
@@ -42,7 +42,7 @@ // Unique identifier associated with the data being anonymized, usually a // URL. - GURL key; + std::string key; // Whether the `key` was k-anonymous during the last update. bool is_k_anonymous; // The last time the unique user count was updated.
diff --git a/content/browser/renderer_host/input/synthetic_gesture_controller.cc b/content/browser/renderer_host/input/synthetic_gesture_controller.cc index b8caa3f..a544d1e 100644 --- a/content/browser/renderer_host/input/synthetic_gesture_controller.cc +++ b/content/browser/renderer_host/input/synthetic_gesture_controller.cc
@@ -26,8 +26,11 @@ } SyntheticGestureController::~SyntheticGestureController() { - if (!pending_gesture_queue_.IsEmpty()) - GestureCompleted(SyntheticGesture::GESTURE_FINISHED); + while (!pending_gesture_queue_.IsEmpty()) { + pending_gesture_queue_.FrontCallback().Run( + SyntheticGesture::GESTURE_FINISHED); + pending_gesture_queue_.Pop(); + } } void SyntheticGestureController::EnsureRendererInitialized(
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index a225289..a7f5630 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -204,6 +204,7 @@ #include "url/origin.h" #if BUILDFLAG(IS_ANDROID) +#include "base/android/child_process_binding_types.h" #include "content/browser/android/java_interfaces_impl.h" #include "content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h" #include "content/public/browser/android/java_interfaces.h" @@ -2890,6 +2891,16 @@ return effective_importance_; } +base::android::ChildBindingState +RenderProcessHostImpl::GetEffectiveChildBindingState() { + if (child_process_launcher_) { + return child_process_launcher_->GetEffectiveChildBindingState(); + } + + // If there is no ChildProcessLauncher this is the best default. + return base::android::ChildBindingState::UNBOUND; +} + void RenderProcessHostImpl::DumpProcessStack() { if (child_process_launcher_) child_process_launcher_->DumpProcessStack();
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index 40317bd0..2f6f2c7 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -90,6 +90,11 @@ namespace base { class CommandLine; class PersistentMemoryAllocator; +#if BUILDFLAG(IS_ANDROID) +namespace android { +enum class ChildBindingState; +} +#endif } // namespace base namespace blink { @@ -238,6 +243,7 @@ void ClearPriorityOverride() override; #if BUILDFLAG(IS_ANDROID) ChildProcessImportance GetEffectiveImportance() override; + base::android::ChildBindingState GetEffectiveChildBindingState() override; void DumpProcessStack() override; #endif void SetSuddenTerminationAllowed(bool enabled) override;
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index a33dbe6..1928594 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc
@@ -1332,7 +1332,8 @@ #else InterestGroupManagerImpl::ProcessMode::kDedicated, #endif - GetURLLoaderFactoryForBrowserProcess()); + GetURLLoaderFactoryForBrowserProcess(), + browser_context_->CreateKAnonymityServiceDelegate()); } // The Topics API is not available in Incognito mode.
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java index b37c58e..e433cbb 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
@@ -831,6 +831,18 @@ } } + // Called on client (UI or IO) thread. + @CalledByNative + private @ChildBindingState int getEffectiveChildBindingState() { + ChildProcessConnection connection = mLauncher.getConnection(); + // Here we are accessing the connection from a thread other than the launcher thread, but it + // does not change once it's been set. So it is safe to test whether it's null here and + // access it afterwards. + if (connection == null) return ChildBindingState.UNBOUND; + + return connection.bindingStateCurrent(); + } + /** * Dumps the stack of the child process with |pid| without crashing it. * @param pid Process id of the child process.
diff --git a/content/public/browser/k_anonymity_service_delegate.h b/content/public/browser/k_anonymity_service_delegate.h index 703511d..6c1e4ad 100644 --- a/content/public/browser/k_anonymity_service_delegate.h +++ b/content/public/browser/k_anonymity_service_delegate.h
@@ -25,17 +25,19 @@ // JoinSets marks the provided ID as being used by this client. The // caller of this function should avoid calling this function repeatedly for // the same IDs, as there is no guarantee the implementer deduplicates calls. - // The callback is called when the join has completed or failed. A value of - // 'true' passed to the callback indicates the join completed successfully. + // The callback is called asynchronously when the join has completed or + // failed. A value of 'true' passed to the callback indicates the join + // completed successfully. virtual void JoinSet(std::string id, base::OnceCallback<void(bool)> callback) = 0; - // QuerySet requests the k-anonymity status of the provided IDs. If the - // request is successful, the callback will be passed a vector where `true` - // means the ID in the same index of the request is k-anonymous and `false` - // means that the ID isn't k-anonymous. In the event of an error, an empty - // vector will be passed to the callback. There is no requirement that a user - // has joined an ID or has not joined and ID to perform a query on that ID. + // QuerySet requests the k-anonymity status of the provided IDs. The callback + // will be called asynchronously. If the request is successful, the callback + // will be passed a vector where `true` means the ID in the same index of the + // request is k-anonymous and `false` means that the ID isn't k-anonymous. In + // the event of an error, an empty vector will be passed to the callback. + // There is no requirement that a user has joined an ID or has not joined and + // ID to perform a query on that ID. virtual void QuerySets( std::vector<std::string> ids, base::OnceCallback<void(std::vector<bool>)> callback) = 0;
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h index 1cd6ece..10ce960b 100644 --- a/content/public/browser/render_process_host.h +++ b/content/public/browser/render_process_host.h
@@ -63,6 +63,11 @@ class PersistentMemoryAllocator; class TimeDelta; class Token; +#if BUILDFLAG(IS_ANDROID) +namespace android { +enum class ChildBindingState; +} +#endif } // namespace base namespace blink { @@ -317,6 +322,9 @@ // Return the highest importance of all widgets in this process. virtual ChildProcessImportance GetEffectiveImportance() = 0; + // Return the highest binding this process has. + virtual base::android::ChildBindingState GetEffectiveChildBindingState() = 0; + // Dumps the stack of this render process without crashing it. virtual void DumpProcessStack() = 0; #endif
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc index ebfb073..f955a6c 100644 --- a/content/public/test/mock_render_process_host.cc +++ b/content/public/test/mock_render_process_host.cc
@@ -356,6 +356,12 @@ return ChildProcessImportance::NORMAL; } +base::android::ChildBindingState +MockRenderProcessHost::GetEffectiveChildBindingState() { + NOTIMPLEMENTED(); + return base::android::ChildBindingState::UNBOUND; +} + void MockRenderProcessHost::DumpProcessStack() {} #endif @@ -598,7 +604,7 @@ MockRenderProcessHostFactory::MockRenderProcessHostFactory() = default; -MockRenderProcessHostFactory::~MockRenderProcessHostFactory() {} +MockRenderProcessHostFactory::~MockRenderProcessHostFactory() = default; RenderProcessHost* MockRenderProcessHostFactory::CreateRenderProcessHost( BrowserContext* browser_context,
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h index 077c85d..1be88cc 100644 --- a/content/public/test/mock_render_process_host.h +++ b/content/public/test/mock_render_process_host.h
@@ -34,6 +34,7 @@ #include "net/base/network_isolation_key.h" #if BUILDFLAG(IS_ANDROID) +#include "base/android/child_process_binding_types.h" #include "content/public/browser/android/child_process_importance.h" #endif @@ -146,6 +147,7 @@ void ClearPriorityOverride() override; #if BUILDFLAG(IS_ANDROID) ChildProcessImportance GetEffectiveImportance() override; + base::android::ChildBindingState GetEffectiveChildBindingState() override; void DumpProcessStack() override; #endif void SetSuddenTerminationAllowed(bool allowed) override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 2def34b..7b8e25bd 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -2257,6 +2257,7 @@ "../browser/interest_group/auction_runner_unittest.cc", "../browser/interest_group/auction_url_loader_factory_proxy_unittest.cc", "../browser/interest_group/auction_worklet_manager_unittest.cc", + "../browser/interest_group/interest_group_k_anonymity_manager_unittest.cc", "../browser/interest_group/interest_group_permissions_cache_unittest.cc", "../browser/interest_group/interest_group_permissions_checker_unittest.cc", "../browser/interest_group/interest_group_priority_util_unittest.cc",
diff --git a/content/test/data/direct_sockets/tcp.js b/content/test/data/direct_sockets/tcp.js index 0f02bd6..50c4bced 100644 --- a/content/test/data/direct_sockets/tcp.js +++ b/content/test/data/direct_sockets/tcp.js
@@ -30,6 +30,24 @@ } } +async function writeLargeTcpPacket(address, port, size) { + try { + let tcpSocket = new TCPSocket(address, port); + let { writable } = await tcpSocket.opened; + let writer = writable.getWriter(); + + let chunk = new Uint8Array(size); + for (let index = 0; index < size; ++index) { + chunk[index] = index % 256; + } + await writer.write(chunk); + + return 'writeLargeTcpPacket succeeded'; + } catch(error) { + return ('writeLargeTcpPacket failed: ' + error); + } +} + async function readLoop(reader, requiredBytes) { if (!(reader instanceof ReadableStreamDefaultReader)) return 'read failed: reader is not a ReadableStreamDefaultReader';
diff --git a/device/gamepad/gamepad_id_list.cc b/device/gamepad/gamepad_id_list.cc index 597b197..4946e67 100644 --- a/device/gamepad/gamepad_id_list.cc +++ b/device/gamepad/gamepad_id_list.cc
@@ -88,6 +88,7 @@ {0x045e, 0x0719, kXInputTypeXbox360}, {0x045e, 0x0b00, kXInputTypeXboxOne}, {0x045e, 0x0b05, kXInputTypeNone}, + {0x045e, 0x0b06, kXInputTypeXboxOne}, {0x045e, 0x0b0a, kXInputTypeXboxOne}, {0x045e, 0x0b0c, kXInputTypeNone}, {0x045e, 0x0b12, kXInputTypeXboxOne},
diff --git a/device/gamepad/gamepad_id_list.h b/device/gamepad/gamepad_id_list.h index 2ed3379..da7cbe8b 100644 --- a/device/gamepad/gamepad_id_list.h +++ b/device/gamepad/gamepad_id_list.h
@@ -77,6 +77,7 @@ kMicrosoftProduct0719 = 0x045e0719, kMicrosoftProduct0b00 = 0x045e0b00, kMicrosoftProduct0b05 = 0x045e0b05, + kMicrosoftProduct0b06 = 0x045e0b06, kMicrosoftProduct0b0a = 0x045e0b0a, kMicrosoftProduct0b0c = 0x045e0b0c, kMicrosoftProduct0b12 = 0x045e0b12,
diff --git a/device/gamepad/wgi_data_fetcher_win.cc b/device/gamepad/wgi_data_fetcher_win.cc index 838c609..d610b05 100644 --- a/device/gamepad/wgi_data_fetcher_win.cc +++ b/device/gamepad/wgi_data_fetcher_win.cc
@@ -161,6 +161,8 @@ gamepad_id == GamepadId::kMicrosoftProduct02ea || // Xbox One S Bluetooth gamepad_id == GamepadId::kMicrosoftProduct02e0 || + // Xbox One S USB + gamepad_id == GamepadId::kMicrosoftProduct0b06 || // Xbox Series X USB gamepad_id == GamepadId::kMicrosoftProduct0b12 || // Xbox Series X Bluetooth
diff --git a/device/gamepad/wgi_data_fetcher_win_unittest.cc b/device/gamepad/wgi_data_fetcher_win_unittest.cc index 9af02df8..7cc7381 100644 --- a/device/gamepad/wgi_data_fetcher_win_unittest.cc +++ b/device/gamepad/wgi_data_fetcher_win_unittest.cc
@@ -63,9 +63,10 @@ GamepadId::kMicrosoftProduct02d1, GamepadId::kMicrosoftProduct02dd, GamepadId::kMicrosoftProduct02fd, GamepadId::kMicrosoftProduct0b20, GamepadId::kMicrosoftProduct02ea, GamepadId::kMicrosoftProduct02e0, - GamepadId::kMicrosoftProduct0b12, GamepadId::kMicrosoftProduct0b13, - GamepadId::kMicrosoftProduct02e3, GamepadId::kMicrosoftProduct0b00, - GamepadId::kMicrosoftProduct0b05, GamepadId::kMicrosoftProduct0b22}; + GamepadId::kMicrosoftProduct0b06, GamepadId::kMicrosoftProduct0b12, + GamepadId::kMicrosoftProduct0b13, GamepadId::kMicrosoftProduct02e3, + GamepadId::kMicrosoftProduct0b00, GamepadId::kMicrosoftProduct0b05, + GamepadId::kMicrosoftProduct0b22}; constexpr WgiTestErrorCode kErrors[] = { WgiTestErrorCode::kErrorWgiRawGameControllerActivateFailed,
diff --git a/ios/PRESUBMIT.py b/ios/PRESUBMIT.py index 3c3918b..0d03c4b 100644 --- a/ios/PRESUBMIT.py +++ b/ios/PRESUBMIT.py
@@ -16,6 +16,7 @@ TODO_PATTERN = r'TO[D]O\(([^\)]*)\)' CRBUG_PATTERN = r'crbug\.com/\d+$' INCLUDE_PATTERN = r'^#include' +PIPE_IN_COMMENT_PATTERN = r'//.*[^|]\|(?!\|)' IOS_PACKAGE_PATTERN = r'^ios' ARC_COMPILE_GUARD = [ '#if !defined(__has_feature) || !__has_feature(objc_arc)', @@ -140,6 +141,28 @@ return [output_api.PresubmitError(error_message)] +def _CheckHasNoPipeInComment(input_api, output_api): + """ Checks that comments don't contain pipes.""" + pipe_regex = input_api.re.compile(PIPE_IN_COMMENT_PATTERN) + + errors = [] + for f in input_api.AffectedFiles(): + if not _IsInIosPackage(input_api, f.LocalPath()): + continue + for line_num, line in f.ChangedContents(): + if pipe_regex.search(line): + errors.append('%s:%s' % (f.LocalPath(), line_num)) + if not errors: + return [] + error_message = '\n'.join([ + 'Please use backticks "`" instead of pipes "|" if you need to quote' + ' variable names and symbols in comments.\n' + 'Found potential uses of pipes in:' + ] + errors) + '\n' + + return [output_api.PresubmitPromptWarning(error_message)] + + def _IsInIosPackage(input_api, path): """ Returns True if path is within ios package""" ios_package_regex = input_api.re.compile(IOS_PACKAGE_PATTERN) @@ -172,4 +195,5 @@ results.extend(_CheckNullabilityAnnotations(input_api, output_api)) results.extend(_CheckARCCompilationGuard(input_api, output_api)) results.extend(_CheckHasNoIncludeDirectives(input_api, output_api)) + results.extend(_CheckHasNoPipeInComment(input_api, output_api)) return results
diff --git a/ios/PRESUBMIT_test.py b/ios/PRESUBMIT_test.py index d6d0c5b..633b750 100755 --- a/ios/PRESUBMIT_test.py +++ b/ios/PRESUBMIT_test.py
@@ -128,5 +128,36 @@ self.assertTrue('ios/path/foo_controller.mm:4' in errors[0].message) +class CheckHasNoPipeInCommentTest(unittest.TestCase): + """Test the _CheckHasNoPipeInComment presubmit check.""" + + def testFindsIncludeDirectives(self): + good_lines = [ + '#if !defined(__has_feature) || !__has_feature(objc_arc)', + '// This does A || B', '// `MySymbol` is correct', + 'bitVariable1 | bitVariable2' + ] + bad_lines = [ + '// |MySymbol| is wrong', '// What is wrong is: |MySymbol|' + ] + mock_input = PRESUBMIT_test_mocks.MockInputApi() + mock_input.files = [ + PRESUBMIT_test_mocks.MockFile('ios/path/foo_controller.mm', + good_lines + bad_lines), + PRESUBMIT_test_mocks.MockFile('ios/path/foo_controller.h', + bad_lines + good_lines), + ] + mock_output = PRESUBMIT_test_mocks.MockOutputApi() + errors = PRESUBMIT._CheckHasNoPipeInComment(mock_input, mock_output) + self.assertEqual(len(errors), 1) + self.assertEqual('warning', errors[0].type) + self.assertTrue('ios/path/foo_controller.mm:5' in errors[0].message) + self.assertTrue('ios/path/foo_controller.mm:6' in errors[0].message) + self.assertTrue('ios/path/foo_controller.h:1' in errors[0].message) + self.assertTrue('ios/path/foo_controller.h:2' in errors[0].message) + error_lines = errors[0].message.split('\n') + self.assertEqual(len(error_lines), len(bad_lines) * 2 + 3) + + if __name__ == '__main__': unittest.main()
diff --git a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-1024.png b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-1024.png index e8e731f..70819c8 100644 --- a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-1024.png +++ b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-1024.png Binary files differ
diff --git a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-120.png b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-120.png index c32b9c6..1360766 100644 --- a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-120.png +++ b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-120.png Binary files differ
diff --git a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-152.png b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-152.png index 2d8ec5a3..6440d22 100644 --- a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-152.png +++ b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-152.png Binary files differ
diff --git a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-167.png b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-167.png index 03234e917..01c40c2 100644 --- a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-167.png +++ b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-167.png Binary files differ
diff --git a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-180.png b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-180.png index 08d0423..526f3f9e 100644 --- a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-180.png +++ b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-180.png Binary files differ
diff --git a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-29.png b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-29.png index 6203697..9b06c753 100644 --- a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-29.png +++ b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-29.png Binary files differ
diff --git a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-40.png b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-40.png index 84d515f..28e97e1 100644 --- a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-40.png +++ b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-40.png Binary files differ
diff --git a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-58.png b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-58.png index d79139b8..cdee8ab 100644 --- a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-58.png +++ b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-58.png Binary files differ
diff --git a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-80.png b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-80.png index f79c4c0..0bb4ace 100644 --- a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-80.png +++ b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-80.png Binary files differ
diff --git a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-87.png b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-87.png index 244d5691..3ad76f28 100644 --- a/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-87.png +++ b/ios/chrome/app/resources/chromium/AppIcon.appiconset/Icon-87.png Binary files differ
diff --git a/ios/chrome/app/resources/launchscreen_app_logo.imageset/launchscreen_app_logo@2x.png b/ios/chrome/app/resources/launchscreen_app_logo.imageset/launchscreen_app_logo@2x.png index 9ec9aba..71cdabe5 100644 --- a/ios/chrome/app/resources/launchscreen_app_logo.imageset/launchscreen_app_logo@2x.png +++ b/ios/chrome/app/resources/launchscreen_app_logo.imageset/launchscreen_app_logo@2x.png Binary files differ
diff --git a/ios/chrome/app/resources/launchscreen_app_logo.imageset/launchscreen_app_logo@3x.png b/ios/chrome/app/resources/launchscreen_app_logo.imageset/launchscreen_app_logo@3x.png index 432a40d..f79e49a 100644 --- a/ios/chrome/app/resources/launchscreen_app_logo.imageset/launchscreen_app_logo@3x.png +++ b/ios/chrome/app/resources/launchscreen_app_logo.imageset/launchscreen_app_logo@3x.png Binary files differ
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 4af2ff96..b29e386 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1629,6 +1629,9 @@ <message name="IDS_IOS_OPTIONS_PRIVACY_GOOGLE_SERVICES_FOOTER" desc="Footer to invite the user to open the Sync and Google Services settings."> For more settings that relate to privacy, security, and data collection, see <ph name="BEGIN_LINK">BEGIN_LINK</ph>Sync and Google Services<ph name="END_LINK">END_LINK</ph>. </message> + <message name="IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACKING_TITLE" desc="Title for Price Tracking Notifications settings menu row."> + Tracking Price + </message> <message name="IDS_IOS_PRIVACY_SAFE_BROWSING_ENHANCED_PROTECTION_SUMMARY" desc="Summary for Privacy Safe Browsing enhanced protection mode."> Faster, proactive protection against dangerous websites, downloads, and extensions. Warns you about password breaches. Requires browsing data to be sent to Google. </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACKING_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACKING_TITLE.png.sha1 new file mode 100644 index 0000000..ff588094 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACKING_TITLE.png.sha1
@@ -0,0 +1 @@ +1ee2e891ce8bfd970ad0cc8410468fa1e7518ed5 \ No newline at end of file
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm index d35de4b..78c8bd05 100644 --- a/ios/chrome/browser/passwords/password_controller.mm +++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -192,7 +192,7 @@ PasswordFormHelper* formHelper = [[PasswordFormHelper alloc] initWithWebState:webState]; PasswordSuggestionHelper* suggestionHelper = - [[PasswordSuggestionHelper alloc] init]; + [[PasswordSuggestionHelper alloc] initWithWebState:_webState]; PasswordControllerDriverHelper* driverHelper = [[PasswordControllerDriverHelper alloc] initWithWebState:_webState]; _sharedPasswordController = [[SharedPasswordController alloc]
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm index a993a25..889af78 100644 --- a/ios/chrome/browser/prefs/browser_prefs.mm +++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -289,9 +289,7 @@ // Register pref storing whether the Incognito interstitial for third-party // intents is enabled. - if (base::FeatureList::IsEnabled(kIOS3PIntentsInIncognito)) { - registry->RegisterBooleanPref(prefs::kIncognitoInterstitialEnabled, false); - } + registry->RegisterBooleanPref(prefs::kIncognitoInterstitialEnabled, false); // Register pref used to determine whether the User Policy notification was // already shown.
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm index e91a33c..78432caf 100644 --- a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm +++ b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
@@ -1083,6 +1083,14 @@ config.features_enabled.push_back(switches::kEnableCbdSignOut); [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; + // Remove closed tab history to make sure the sign-in promo is always visible + // in recent tabs. + [ChromeEarlGrey clearBrowsingHistory]; + [ChromeEarlGrey waitForBookmarksToFinishLoading]; + [ChromeEarlGrey clearBookmarks]; + GREYAssertNil([MetricsAppInterface setupHistogramTester], + @"Failed to set up histogram tester."); + FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; [self signInOpenCBDAndClearDataWithFakeIdentity:fakeIdentity]; [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity]; @@ -1105,6 +1113,14 @@ config.features_disabled.push_back(switches::kEnableCbdSignOut); [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; + // Remove closed tab history to make sure the sign-in promo is always visible + // in recent tabs. + [ChromeEarlGrey clearBrowsingHistory]; + [ChromeEarlGrey waitForBookmarksToFinishLoading]; + [ChromeEarlGrey clearBookmarks]; + GREYAssertNil([MetricsAppInterface setupHistogramTester], + @"Failed to set up histogram tester."); + FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1]; [self signInOpenCBDAndClearDataWithFakeIdentity:fakeIdentity]; [SigninEarlGrey verifySignedOut];
diff --git a/ios/chrome/browser/ui/icons/settings_icon.mm b/ios/chrome/browser/ui/icons/settings_icon.mm index e5729c4..3a09630 100644 --- a/ios/chrome/browser/ui/icons/settings_icon.mm +++ b/ios/chrome/browser/ui/icons/settings_icon.mm
@@ -24,24 +24,12 @@ NSString* const kPrivacySecuritySymbol = @"checkerboard.shield"; NSString* const kDiscoverSymbol = @"flame"; -namespace { - -// The default configuration with the given `pointSize` for the Settings root -// screen. -UIImageSymbolConfiguration* kDefaultSettingsRootSymbolConfiguration = - [UIImageSymbolConfiguration - configurationWithPointSize:kSettingsRootSymbolImagePointSize - weight:UIImageSymbolWeightMedium - scale:UIImageSymbolScaleMedium]; - -} // namespace - UIImage* DefaultSettingsRootSymbol(NSString* symbol_name) { - return DefaultSymbolWithConfiguration( - symbol_name, kDefaultSettingsRootSymbolConfiguration); + return DefaultSymbolWithPointSize(symbol_name, + kSettingsRootSymbolImagePointSize); } UIImage* CustomSettingsRootSymbol(NSString* symbol_name) { - return CustomSymbolWithConfiguration(symbol_name, - kDefaultSettingsRootSymbolConfiguration); + return CustomSymbolWithPointSize(symbol_name, + kSettingsRootSymbolImagePointSize); }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm index f2d4a22..6974a2b 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
@@ -232,9 +232,9 @@ self.returnDelegate = [[ForwardingReturnDelegate alloc] init]; self.returnDelegate.acceptDelegate = _editView.get(); - coordinator.pedalExtractor.matchPreviewDelegate = self.mediator; - coordinator.pedalExtractor.acceptDelegate = self.returnDelegate; - self.viewController.returnKeyDelegate = coordinator.pedalExtractor; + coordinator.popupMatchPreviewDelegate = self.mediator; + coordinator.acceptReturnDelegate = self.returnDelegate; + self.viewController.returnKeyDelegate = coordinator.popupReturnDelegate; return coordinator; }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_ui_features.cc b/ios/chrome/browser/ui/omnibox/omnibox_ui_features.cc index 9994f50..949d1457 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_ui_features.cc +++ b/ios/chrome/browser/ui/omnibox/omnibox_ui_features.cc
@@ -42,11 +42,5 @@ } bool IsSwiftUIPopupEnabled() { - if (!IsOmniboxActionsEnabled()) { - return false; - } - auto param = base::GetFieldTrialParamValueByFeature( - kIOSOmniboxUpdatedPopupUI, kIOSOmniboxUpdatedPopupUIVariationName); - return param == kIOSOmniboxUpdatedPopupUIVariation1 || - param == kIOSOmniboxUpdatedPopupUIVariation2; + return false; }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_ui_features.h b/ios/chrome/browser/ui/omnibox/omnibox_ui_features.h index 8f35038..c97a743 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_ui_features.h +++ b/ios/chrome/browser/ui/omnibox/omnibox_ui_features.h
@@ -31,7 +31,7 @@ bool IsOmniboxActionsVisualTreatment1(); // Same as above, but for "version 2". bool IsOmniboxActionsVisualTreatment2(); -// Returns true when Actions are set to one of the SwiftUI variations. +// Returns false, swift version not supported anymore. bool IsSwiftUIPopupEnabled(); #endif // IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_UI_FEATURES_H_
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h index 60e7dbe7..f219fb3 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h +++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
@@ -40,9 +40,9 @@ @end -@interface OmniboxViewController : UIViewController<EditViewAnimatee, - LocationBarOffsetProvider, - OmniboxConsumer> +@interface OmniboxViewController : UIViewController <EditViewAnimatee, + LocationBarOffsetProvider, + OmniboxConsumer> // The textfield used by this view controller. @property(nonatomic, readonly, strong) OmniboxTextFieldIOS* textField;
diff --git a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn index 5dfb1801..ee02816 100644 --- a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn +++ b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
@@ -63,7 +63,6 @@ "pedal_section_extractor.mm", "pedal_suggestion_wrapper.h", "pedal_suggestion_wrapper.mm", - "popup_match_preview_delegate.h", ] deps = [ ":popup_internal", @@ -161,6 +160,7 @@ "//ios/chrome/browser/ui/omnibox:features", "//ios/chrome/browser/ui/omnibox:omnibox_popup_shared", "//ios/chrome/browser/ui/omnibox:omnibox_suggestion_icon_util", + "//ios/chrome/browser/ui/omnibox:omnibox_util", "//ios/chrome/browser/ui/toolbar/buttons", "//ios/chrome/browser/ui/toolbar/public", "//ios/chrome/browser/ui/util", @@ -209,6 +209,7 @@ "content_providing.h", "omnibox_icon.h", "omnibox_pedal.h", + "popup_match_preview_delegate.h", ] configs += [ "//build/config/compiler:enable_arc" ] }
diff --git a/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.h b/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.h index 23dd5f9..6555a633 100644 --- a/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.h +++ b/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.h
@@ -21,7 +21,7 @@ @property(nonatomic, assign) BOOL defaultSearchEngineIsGoogle; // The pedal data for the underlying match. -@property(nonatomic) OmniboxPedalData* pedalData; +@property(nonatomic, assign) OmniboxPedalData* pedalData; - (instancetype)initWithMatch:(const AutocompleteMatch&)match NS_DESIGNATED_INITIALIZER; @@ -30,6 +30,9 @@ // Convenience constuctor. + (instancetype)formatterWithMatch:(const AutocompleteMatch&)match; +// Underlying match. +- (const AutocompleteMatch&)autocompleteMatch; + @end #endif // IOS_CHROME_BROWSER_UI_OMNIBOX_POPUP_AUTOCOMPLETE_MATCH_FORMATTER_H_
diff --git a/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.mm b/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.mm index 8071a230..18b225e 100644 --- a/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.mm +++ b/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.mm
@@ -257,6 +257,10 @@ return [[CrURL alloc] initWithGURL:_match.destination_url]; } +- (const AutocompleteMatch&)autocompleteMatch { + return _match; +} + #pragma mark tail suggest - (BOOL)isTailSuggestion {
diff --git a/ios/chrome/browser/ui/omnibox/popup/autocomplete_result_consumer.h b/ios/chrome/browser/ui/omnibox/popup/autocomplete_result_consumer.h index 06fa6e0..5265617e 100644 --- a/ios/chrome/browser/ui/omnibox/popup/autocomplete_result_consumer.h +++ b/ios/chrome/browser/ui/omnibox/popup/autocomplete_result_consumer.h
@@ -7,40 +7,33 @@ #import <UIKit/UIKit.h> +@protocol AutocompleteSuggestion; @protocol AutocompleteSuggestionGroup; - @protocol AutocompleteResultConsumer; // Delegate for AutocompleteResultConsumer. @protocol AutocompleteResultConsumerDelegate <NSObject> -// Tells the delegate when a row containing a suggestion is highlighted (i.e. -// with arrow keys). -- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didHighlightRow:(NSUInteger)row - inSection:(NSUInteger)section; - -// Highlighting has been cancelled, no row is highlighted. -- (void)autocompleteResultConsumerCancelledHighlighting: - (id<AutocompleteResultConsumer>)sender; - -// Tells the delegate when a row containing a suggestion is clicked. -- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didSelectRow:(NSUInteger)row - inSection:(NSUInteger)section; -// Tells the delegate when a suggestion in `row` was chosen for appending to -// omnibox. -- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didTapTrailingButtonForRow:(NSUInteger)row - inSection:(NSUInteger)section; -// Tells the delegate when a suggestion in `row` was removed. -- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didSelectRowForDeletion:(NSUInteger)row - inSection:(NSUInteger)section; // Tells the delegate on scroll. - (void)autocompleteResultConsumerDidScroll: (id<AutocompleteResultConsumer>)sender; +// Tells the delegate when `suggestion` in `row` was selected. +- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender + didSelectSuggestion:(id<AutocompleteSuggestion>)suggestion + inRow:(NSUInteger)row; + +// Tells the delegate when `suggestion` in `row` was chosen for appending to +// omnibox. +- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender + didTapTrailingButtonOnSuggestion:(id<AutocompleteSuggestion>)suggestion + inRow:(NSUInteger)row; + +// Tells the delegate when `suggestion` in `row` was removed. +- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender + didSelectSuggestionForDeletion:(id<AutocompleteSuggestion>)suggestion + inRow:(NSUInteger)row; + @end // An abstract consumer of autocomplete results.
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.h b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.h index f3c9f5c..ef1276b 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.h +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.h
@@ -9,11 +9,12 @@ #include <memory> -@protocol OmniboxPopupPresenterDelegate; @protocol OmniboxCommands; -@class OmniboxTextFieldIOS; -@class PedalSectionExtractor; +@protocol OmniboxPopupPresenterDelegate; class OmniboxPopupViewIOS; +@protocol OmniboxReturnDelegate; +@class OmniboxTextFieldIOS; +@protocol PopupMatchPreviewDelegate; // Coordinator for the Omnibox Popup. @interface OmniboxPopupCoordinator : ChromeCoordinator @@ -33,8 +34,15 @@ @property(nonatomic, assign, readonly) BOOL hasResults; // Whether the popup is open. @property(nonatomic, assign, readonly) BOOL isOpen; -// The pedal extractor that wraps pedals as a separate suggestion section. -@property(nonatomic, strong) PedalSectionExtractor* pedalExtractor; + +// Object implementing OmniboxReturnDelegate in OmniboxPopupCoordinator. +@property(nonatomic, weak, readonly) id<OmniboxReturnDelegate> + popupReturnDelegate; +// Delegate for OmniboxReturnDelegate used in OmniboxPopupCoordinator. +@property(nonatomic, weak) id<OmniboxReturnDelegate> acceptReturnDelegate; +// Delegate for PopupMatchPreviewDelegate used in OmniboxPopupCoordinator. +@property(nonatomic, weak) id<PopupMatchPreviewDelegate> + popupMatchPreviewDelegate; @end
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 33e6d37d..ee51fbe 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
@@ -43,8 +43,7 @@ std::unique_ptr<OmniboxPopupViewIOS> _popupView; } -@property(nonatomic, strong) - UIViewController<ContentProviding>* popupViewController; +@property(nonatomic, strong) OmniboxPopupViewController* popupViewController; @property(nonatomic, strong) OmniboxPopupMediator* mediator; @property(nonatomic, strong) PopupModel* model; @property(nonatomic, strong) PopupUIConfiguration* uiConfiguration; @@ -53,9 +52,6 @@ @implementation OmniboxPopupCoordinator -@synthesize mediator = _mediator; -@synthesize popupViewController = _popupViewController; - #pragma mark - Public - (instancetype) @@ -65,7 +61,8 @@ self = [super initWithBaseViewController:nil browser:browser]; if (self) { _popupView = std::move(popupView); - self.pedalExtractor = [[PedalSectionExtractor alloc] init]; + _popupViewController = [[OmniboxPopupViewController alloc] init]; + _popupReturnDelegate = _popupViewController; } return self; } @@ -96,68 +93,21 @@ templateURLService->search_terms_data()) == SEARCH_ENGINE_GOOGLE; if (IsSwiftUIPopupEnabled()) { - self.model = [[PopupModel alloc] initWithMatches:@[] - headers:@[] - dataSource:self.mediator - delegate:self.pedalExtractor]; - ToolbarConfiguration* toolbarConfiguration = [[ToolbarConfiguration alloc] - initWithStyle:isIncognito ? INCOGNITO : NORMAL]; - self.uiConfiguration = [[PopupUIConfiguration alloc] - initWithToolbarConfiguration:toolbarConfiguration]; - if (@available(iOS 16, *)) { - self.uiConfiguration.shouldDismissKeyboardOnScroll = - (ui::GetDeviceFormFactor() != ui::DEVICE_FORM_FACTOR_TABLET || - base::FeatureList::IsEnabled(kEnableSuggestionsScrollingOnIPad)); - } - - BOOL popupShouldSelfSize = - (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET); - self.mediator.model = self.model; - - PopupUIVariation popupUIVariation = IsOmniboxActionsVisualTreatment1() - ? PopupUIVariationOne - : PopupUIVariationTwo; - - std::string pasteButtonVariationName = - base::GetFieldTrialParamValueByFeature( - kOmniboxPasteButton, kOmniboxPasteButtonParameterName); - - PopupPasteButtonVariation popupPasteButtonVariation = - (pasteButtonVariationName == - kOmniboxPasteButtonParameterBlueFullCapsule) - ? PopupPasteButtonVariationIconText - : PopupPasteButtonVariationIcon; - - self.popupViewController = [OmniboxPopupViewProvider - makeViewControllerWithModel:self.model - uiConfiguration:self.uiConfiguration - popupUIVariation:popupUIVariation - popupPasteButtonVariation:popupPasteButtonVariation - popupShouldSelfSize:popupShouldSelfSize - appearanceContainerType:[OmniboxPopupContainerView class]]; - [self.browser->GetCommandDispatcher() - startDispatchingToTarget:self.model - forProtocol:@protocol(OmniboxSuggestionCommands)]; - self.mediator.consumer = self.pedalExtractor; - self.pedalExtractor.dataSink = self.model; - self.pedalExtractor.delegate = self.mediator; + NOTREACHED() << "Swift version not supported anymore."; } else { - OmniboxPopupViewController* popupViewController = - [[OmniboxPopupViewController alloc] init]; - popupViewController.imageRetriever = self.mediator; - popupViewController.faviconRetriever = self.mediator; - popupViewController.delegate = self.pedalExtractor; - popupViewController.dataSource = self.mediator; - popupViewController.incognito = isIncognito; + self.popupViewController.imageRetriever = self.mediator; + self.popupViewController.faviconRetriever = self.mediator; + self.popupViewController.delegate = self.mediator; + self.popupViewController.dataSource = self.mediator; + self.popupViewController.incognito = isIncognito; [self.browser->GetCommandDispatcher() - startDispatchingToTarget:popupViewController + startDispatchingToTarget:self.popupViewController forProtocol:@protocol(OmniboxSuggestionCommands)]; - self.mediator.consumer = self.pedalExtractor; - self.pedalExtractor.dataSink = popupViewController; - self.pedalExtractor.delegate = self.mediator; - - self.popupViewController = popupViewController; + self.mediator.consumer = self.popupViewController; + self.popupViewController.matchPreviewDelegate = + self.popupMatchPreviewDelegate; + self.popupViewController.acceptReturnDelegate = self.acceptReturnDelegate; } if (IsOmniboxActionsEnabled()) {
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm index 2ff0a83..a62a9b0 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm
@@ -21,6 +21,8 @@ #import "ios/chrome/browser/ui/omnibox/popup/autocomplete_suggestion_group_impl.h" #import "ios/chrome/browser/ui/omnibox/popup/omnibox_pedal_annotator.h" #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_presenter.h" +#import "ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor.h" +#import "ios/chrome/browser/ui/omnibox/popup/pedal_suggestion_wrapper.h" #import "ios/chrome/browser/ui/omnibox/popup/popup_swift.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/chrome/common/ui/favicon/favicon_attributes.h" @@ -33,6 +35,16 @@ const CGFloat kOmniboxIconSize = 16; } // namespace +@interface OmniboxPopupMediator () <PedalSectionExtractorDelegate> + +// Extracts pedals from AutocompleSuggestions. +@property(nonatomic, strong) PedalSectionExtractor* pedalSectionExtractor; +// List of suggestions without the pedal group. Used to debouce pedals. +@property(nonatomic, strong) + NSArray<id<AutocompleteSuggestionGroup>>* nonPedalSuggestions; + +@end + @implementation OmniboxPopupMediator { // Fetcher for Answers in Suggest images. std::unique_ptr<image_fetcher::ImageDataFetcher> _imageFetcher; @@ -59,6 +71,8 @@ _imageFetcher = std::move(imageFetcher); _faviconLoader = faviconLoader; _open = NO; + _pedalSectionExtractor = [[PedalSectionExtractor alloc] init]; + _pedalSectionExtractor.delegate = self; } return self; } @@ -66,6 +80,7 @@ - (void)updateMatches:(const AutocompleteResult&)result { _currentResult.Reset(); _currentResult.CopyFrom(result); + self.nonPedalSuggestions = nil; self.hasResults = !_currentResult.empty(); if (base::FeatureList::IsEnabled(omnibox::kAdaptiveSuggestionsCount)) { @@ -107,71 +122,90 @@ [self groupCurrentSuggestionsFrom:visibleSuggestions to:_currentResult.size()]; - NSArray<id<AutocompleteSuggestion>>* matches = [self wrappedMatches]; + NSArray<id<AutocompleteSuggestionGroup>>* groups = [self wrappedMatches]; - [self.consumer updateMatches:@[ [AutocompleteSuggestionGroupImpl - groupWithTitle:nil - suggestions:matches] ] - preselectedMatchGroupIndex:0]; + // When pressing down arrow with pedal, skip the pedal to select search + // suggestions first. + NSUInteger preselectedGroupIndex = 0; + if (groups.count > 1) { + preselectedGroupIndex = 1; + } + + [self.consumer updateMatches:groups + preselectedMatchGroupIndex:preselectedGroupIndex]; [self loadModelImages]; } #pragma mark - AutocompleteResultConsumerDelegate -- (void)autocompleteResultConsumerCancelledHighlighting: - (id<AutocompleteResultConsumer>)sender { -} - - (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didHighlightRow:(NSUInteger)row - inSection:(NSUInteger)section { -} - -- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didSelectRow:(NSUInteger)row - inSection:(NSUInteger)section { - // OpenMatch() may close the popup, which will clear the result set and, by - // extension, `match` and its contents. So copy the relevant match out to - // make sure it stays alive until the call completes. - const AutocompleteMatch& match = - ((const AutocompleteResult&)_currentResult).match_at(row); - - // Don't log pastes in incognito. - if (!self.incognito && match.type == AutocompleteMatchType::CLIPBOARD_URL) { - [self.promoScheduler logUserPastedInOmnibox]; - } - - _delegate->OnMatchSelected(match, row, WindowOpenDisposition::CURRENT_TAB); -} - -- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didTapTrailingButtonForRow:(NSUInteger)row - inSection:(NSUInteger)section { - const AutocompleteMatch& match = - ((const AutocompleteResult&)_currentResult).match_at(row); - - if (match.has_tab_match.value_or(false)) { - _delegate->OnMatchSelected(match, row, - WindowOpenDisposition::SWITCH_TO_TAB); - } else { - if (AutocompleteMatch::IsSearchType(match.type)) { - base::RecordAction( - base::UserMetricsAction("MobileOmniboxRefineSuggestion.Search")); - } else { - base::RecordAction( - base::UserMetricsAction("MobileOmniboxRefineSuggestion.Url")); + didSelectSuggestion:(id<AutocompleteSuggestion>)suggestion + inRow:(NSUInteger)row { + if ([suggestion isKindOfClass:[PedalSuggestionWrapper class]]) { + PedalSuggestionWrapper* pedalSuggestionWrapper = + (PedalSuggestionWrapper*)suggestion; + if (pedalSuggestionWrapper.innerPedal.action) { + pedalSuggestionWrapper.innerPedal.action(); } - _delegate->OnMatchSelectedForAppending(match); + } else if ([suggestion isKindOfClass:[AutocompleteMatchFormatter class]]) { + AutocompleteMatchFormatter* autocompleteMatchFormatter = + (AutocompleteMatchFormatter*)suggestion; + const AutocompleteMatch& match = + autocompleteMatchFormatter.autocompleteMatch; + + // Don't log pastes in incognito. + if (!self.incognito && match.type == AutocompleteMatchType::CLIPBOARD_URL) { + [self.promoScheduler logUserPastedInOmnibox]; + } + + _delegate->OnMatchSelected(match, row, WindowOpenDisposition::CURRENT_TAB); + } else { + NOTREACHED() << "Suggestion type " << NSStringFromClass(suggestion.class) + << " not handled for selection."; } } - (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didSelectRowForDeletion:(NSUInteger)row - inSection:(NSUInteger)section { - const AutocompleteMatch& match = - ((const AutocompleteResult&)_currentResult).match_at(row); - _delegate->OnMatchSelectedForDeletion(match); + didTapTrailingButtonOnSuggestion:(id<AutocompleteSuggestion>)suggestion + inRow:(NSUInteger)row { + if ([suggestion isKindOfClass:[AutocompleteMatchFormatter class]]) { + AutocompleteMatchFormatter* autocompleteMatchFormatter = + (AutocompleteMatchFormatter*)suggestion; + const AutocompleteMatch& match = + autocompleteMatchFormatter.autocompleteMatch; + if (match.has_tab_match.value_or(false)) { + _delegate->OnMatchSelected(match, row, + WindowOpenDisposition::SWITCH_TO_TAB); + } else { + if (AutocompleteMatch::IsSearchType(match.type)) { + base::RecordAction( + base::UserMetricsAction("MobileOmniboxRefineSuggestion.Search")); + } else { + base::RecordAction( + base::UserMetricsAction("MobileOmniboxRefineSuggestion.Url")); + } + _delegate->OnMatchSelectedForAppending(match); + } + } else { + NOTREACHED() << "Suggestion type " << NSStringFromClass(suggestion.class) + << " not handled for trailing button tap."; + } +} + +- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender + didSelectSuggestionForDeletion:(id<AutocompleteSuggestion>)suggestion + inRow:(NSUInteger)row { + if ([suggestion isKindOfClass:[AutocompleteMatchFormatter class]]) { + AutocompleteMatchFormatter* autocompleteMatchFormatter = + (AutocompleteMatchFormatter*)suggestion; + const AutocompleteMatch& match = + autocompleteMatchFormatter.autocompleteMatch; + _delegate->OnMatchSelectedForDeletion(match); + } else { + NOTREACHED() << "Suggestion type " << NSStringFromClass(suggestion.class) + << " not handled for deletion."; + } } - (void)autocompleteResultConsumerDidScroll: @@ -241,10 +275,22 @@ }); } +#pragma mark - PedalSectionExtractorDelegate + +// Removes the pedal group from suggestions. Pedal are removed from suggestions +// with a debouce timer in `PedalSectionExtractor`. When the timer ends the +// pedal group is removed. +- (void)invalidatePedals { + if (self.nonPedalSuggestions) { + [self.consumer updateMatches:self.nonPedalSuggestions + preselectedMatchGroupIndex:0]; + } +} + #pragma mark - Private methods -- (NSArray<id<AutocompleteSuggestion>>*)wrappedMatches { - NSMutableArray<id<AutocompleteSuggestion>>* wrappedMatches = +- (NSArray<id<AutocompleteSuggestionGroup>>*)wrappedMatches { + NSMutableArray<id<AutocompleteSuggestion>>* wrappedSuggestions = [[NSMutableArray alloc] init]; size_t size = _currentResult.size(); @@ -258,10 +304,22 @@ formatter.defaultSearchEngineIsGoogle = self.defaultSearchEngineIsGoogle; formatter.pedalData = [self.pedalAnnotator pedalForMatch:match incognito:_incognito]; - [wrappedMatches addObject:formatter]; + [wrappedSuggestions addObject:formatter]; } - return wrappedMatches; + id<AutocompleteSuggestionGroup> pedalGroup = + [self.pedalSectionExtractor extractPedals:wrappedSuggestions]; + id<AutocompleteSuggestionGroup> suggestionGroup = + [[AutocompleteSuggestionGroupImpl alloc] + initWithTitle:nil + suggestions:wrappedSuggestions]; + + self.nonPedalSuggestions = @[ suggestionGroup ]; + if (pedalGroup) { + return @[ pedalGroup, suggestionGroup ]; + } else { + return self.nonPedalSuggestions; + } } - (void)groupCurrentSuggestionsFrom:(NSUInteger)begin to:(NSUInteger)end {
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h index f2decd8..305ac5a 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h
@@ -8,11 +8,13 @@ #import <UIKit/UIKit.h> #import "ios/chrome/browser/ui/commands/omnibox_suggestion_commands.h" +#import "ios/chrome/browser/ui/omnibox/omnibox_text_change_delegate.h" #import "ios/chrome/browser/ui/omnibox/popup/autocomplete_result_consumer.h" #import "ios/chrome/browser/ui/omnibox/popup/content_providing.h" @protocol ImageRetriever; @protocol FaviconRetriever; +@protocol PopupMatchPreviewDelegate; // View controller used to display a list of omnibox autocomplete matches in the // omnibox popup. @@ -24,12 +26,15 @@ @interface OmniboxPopupViewController : UIViewController <AutocompleteResultConsumer, ContentProviding, + OmniboxReturnDelegate, OmniboxSuggestionCommands, UIScrollViewDelegate> @property(nonatomic, assign) BOOL incognito; @property(nonatomic, weak) id<AutocompleteResultConsumerDelegate> delegate; @property(nonatomic, weak) id<AutocompleteResultDataSource> dataSource; +@property(nonatomic, weak) id<OmniboxReturnDelegate> acceptReturnDelegate; +@property(nonatomic, weak) id<PopupMatchPreviewDelegate> matchPreviewDelegate; @property(nonatomic, weak) id<ImageRetriever> imageRetriever; @property(nonatomic, weak) id<FaviconRetriever> faviconRetriever;
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm index bd5a953..42f084df 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
@@ -17,6 +17,7 @@ #import "ios/chrome/browser/ui/omnibox/popup/content_providing.h" #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_accessibility_identifier_constants.h" #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.h" +#import "ios/chrome/browser/ui/omnibox/popup/popup_match_preview_delegate.h" #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h" #import "ios/chrome/browser/ui/util/keyboard_observer_helper.h" #import "ios/chrome/browser/ui/util/layout_guide_names.h" @@ -84,6 +85,10 @@ // view updates are received. @property(nonatomic, assign) BOOL shouldUpdateVisibleSuggestionCount; +// Index of the suggestion group that contains the first suggestion to preview +// and highlight. +@property(nonatomic, assign) NSUInteger preselectedMatchGroupIndex; + @end @implementation OmniboxPopupViewController @@ -91,6 +96,7 @@ - (instancetype)init { if (self = [super initWithNibName:nil bundle:nil]) { _forwardsScrollEvents = YES; + _preselectedMatchGroupIndex = 0; NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) { // The iPad keyboard can cover some of the rows of the scroll view. The @@ -139,6 +145,19 @@ [self updateBackgroundColor]; } +#pragma mark - Getter/Setter + +- (void)setHighlightedIndexPath:(NSIndexPath*)highlightedIndexPath { + if (_highlightedIndexPath) { + [self unhighlightRowAtIndexPath:_highlightedIndexPath]; + } + _highlightedIndexPath = highlightedIndexPath; + if (highlightedIndexPath) { + [self highlightRowAtIndexPath:_highlightedIndexPath]; + [self didHighlightSelectedSuggestion]; + } +} + #pragma mark - View lifecycle - (void)viewDidLoad { @@ -242,27 +261,22 @@ - (void)updateMatches:(NSArray<id<AutocompleteSuggestionGroup>>*)result preselectedMatchGroupIndex:(NSInteger)groupIndex { + DCHECK(groupIndex == 0 || groupIndex < (NSInteger)result.count); self.forwardsScrollEvents = NO; // Reset highlight state. - if (self.highlightedIndexPath) { - [self unhighlightRowAtIndexPath:self.highlightedIndexPath]; - self.highlightedIndexPath = nil; - } + self.highlightedIndexPath = nil; + self.preselectedMatchGroupIndex = groupIndex; self.currentResult = result; [self.tableView reloadData]; self.forwardsScrollEvents = YES; -} - -- (void)highlightRowAtIndexPath:(NSIndexPath*)indexPath { - UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath]; - [cell setHighlighted:YES animated:NO]; -} - -- (void)unhighlightRowAtIndexPath:(NSIndexPath*)indexPath { - UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath]; - [cell setHighlighted:NO animated:NO]; + id<AutocompleteSuggestion> firstSuggestionOfPreselectedGroup = + [self suggestionAtIndexPath:[NSIndexPath indexPathForRow:0 + inSection:groupIndex]]; + [self.matchPreviewDelegate + setPreviewSuggestion:firstSuggestionOfPreselectedGroup + isFirstUpdate:YES]; } // Set text alignment for popup cells. @@ -278,12 +292,55 @@ requestResultsWithVisibleSuggestionCount:self.visibleSuggestionCount]; } +#pragma mark - OmniboxPopupRowCellDelegate + +- (void)trailingButtonTappedForCell:(OmniboxPopupRowCell*)cell { + NSIndexPath* indexPath = [self.tableView indexPathForCell:cell]; + id<AutocompleteSuggestion> suggestion = + [self suggestionAtIndexPath:indexPath]; + DCHECK(suggestion); + [self.delegate autocompleteResultConsumer:self + didTapTrailingButtonOnSuggestion:suggestion + inRow:indexPath.row]; +} + +#pragma mark - OmniboxReturnDelegate + +- (void)omniboxReturnPressed:(id)sender { + if (self.highlightedIndexPath) { + id<AutocompleteSuggestion> suggestion = + [self suggestionAtIndexPath:self.highlightedIndexPath]; + if (suggestion) { + [self.delegate autocompleteResultConsumer:self + didSelectSuggestion:suggestion + inRow:self.highlightedIndexPath.row]; + return; + } + } + [self.acceptReturnDelegate omniboxReturnPressed:sender]; +} + #pragma mark - OmniboxSuggestionCommands - (void)highlightPreviousSuggestion { NSIndexPath* path = self.highlightedIndexPath; if (path == nil) { - // When nothing is highlighted, pressing Up Arrow doesn't do anything. + // If there is a section above `preselectedMatchGroupIndex` select the last + // suggestion of this section. + if (self.preselectedMatchGroupIndex > 0 && + self.currentResult.count > self.preselectedMatchGroupIndex - 1) { + NSInteger sectionAbovePreselectedGroup = + self.preselectedMatchGroupIndex - 1; + NSIndexPath* suggestionIndex = [NSIndexPath + indexPathForRow:(NSInteger)self + .currentResult[sectionAbovePreselectedGroup] + .suggestions.count - + 1 + inSection:sectionAbovePreselectedGroup]; + if ([self suggestionAtIndexPath:suggestionIndex]) { + self.highlightedIndexPath = suggestionIndex; + } + } return; } @@ -302,33 +359,25 @@ // Can't move up from first row. Call the delegate again so that the // inline autocomplete text is set again (in case the user exited the // inline autocomplete). - [self.delegate - autocompleteResultConsumer:self - didHighlightRow:self.highlightedIndexPath.row - inSection:self.highlightedIndexPath.section]; + [self didHighlightSelectedSuggestion]; return; } } else { path = [NSIndexPath indexPathForRow:path.row - 1 inSection:path.section]; } - [self unhighlightRowAtIndexPath:self.highlightedIndexPath]; self.highlightedIndexPath = path; - [self highlightRowAtIndexPath:self.highlightedIndexPath]; - - [self.delegate autocompleteResultConsumer:self - didHighlightRow:self.highlightedIndexPath.row - inSection:self.highlightedIndexPath.section]; } - (void)highlightNextSuggestion { - if ([self.tableView numberOfRowsInSection:0] == 0) { - return; - } if (!self.highlightedIndexPath) { - // Initialize the highlighted row to -1, so that pressing down when nothing - // is highlighted highlights the first row (at index 0). - self.highlightedIndexPath = [NSIndexPath indexPathForRow:-1 inSection:0]; + NSIndexPath* preselectedSuggestionIndex = + [NSIndexPath indexPathForRow:0 + inSection:self.preselectedMatchGroupIndex]; + if ([self suggestionAtIndexPath:preselectedSuggestionIndex]) { + self.highlightedIndexPath = preselectedSuggestionIndex; + } + return; } NSIndexPath* path = self.highlightedIndexPath; @@ -346,10 +395,7 @@ // Can't go below last row. Call the delegate again so that the inline // autocomplete text is set again (in case the user exited the inline // autocomplete). - [self.delegate - autocompleteResultConsumer:self - didHighlightRow:self.highlightedIndexPath.row - inSection:self.highlightedIndexPath.section]; + [self didHighlightSelectedSuggestion]; return; } } else { @@ -357,19 +403,26 @@ } // There is a row below, move highlight there. - [self unhighlightRowAtIndexPath:self.highlightedIndexPath]; self.highlightedIndexPath = path; - [self highlightRowAtIndexPath:self.highlightedIndexPath]; - - [self.delegate autocompleteResultConsumer:self - didHighlightRow:self.highlightedIndexPath.row - inSection:self.highlightedIndexPath.section]; } -- (void)keyCommandReturn { - [self.tableView selectRowAtIndexPath:self.highlightedIndexPath - animated:YES - scrollPosition:UITableViewScrollPositionNone]; +#pragma mark OmniboxSuggestionCommands Private + +- (void)highlightRowAtIndexPath:(NSIndexPath*)indexPath { + UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath]; + [cell setHighlighted:YES animated:NO]; +} + +- (void)unhighlightRowAtIndexPath:(NSIndexPath*)indexPath { + UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath]; + [cell setHighlighted:NO animated:NO]; +} + +- (void)didHighlightSelectedSuggestion { + id<AutocompleteSuggestion> suggestion = + [self suggestionAtIndexPath:self.highlightedIndexPath]; + DCHECK(suggestion); + [self.matchPreviewDelegate setPreviewSuggestion:suggestion isFirstUpdate:NO]; } #pragma mark - Table view delegate @@ -406,9 +459,11 @@ // early. See b/5813291. if (row >= self.currentResult[indexPath.section].suggestions.count) return; - [self.delegate autocompleteResultConsumer:self - didSelectRow:row - inSection:indexPath.section]; + [self.delegate + autocompleteResultConsumer:self + didSelectSuggestion:self.currentResult[indexPath.section] + .suggestions[row] + inRow:row]; } - (CGFloat)tableView:(UITableView*)tableView @@ -491,10 +546,13 @@ forRowAtIndexPath:(NSIndexPath*)indexPath { DCHECK_LT((NSUInteger)indexPath.row, self.currentResult[indexPath.section].suggestions.count); + id<AutocompleteSuggestion> suggestion = + [self suggestionAtIndexPath:indexPath]; + DCHECK(suggestion); if (editingStyle == UITableViewCellEditingStyleDelete) { [self.delegate autocompleteResultConsumer:self - didSelectRowForDeletion:indexPath.row - inSection:indexPath.section]; + didSelectSuggestionForDeletion:suggestion + inRow:indexPath.row]; } } @@ -601,15 +659,6 @@ return cell; } -#pragma mark - OmniboxPopupRowCellDelegate - -- (void)trailingButtonTappedForCell:(OmniboxPopupRowCell*)cell { - NSIndexPath* indexPath = [self.tableView indexPathForCell:cell]; - [self.delegate autocompleteResultConsumer:self - didTapTrailingButtonForRow:indexPath.row - inSection:indexPath.section]; -} - #pragma mark - Keyboard events - (void)keyboardDidShow:(NSNotification*)notification { @@ -651,6 +700,19 @@ #pragma mark - Private Methods +- (id<AutocompleteSuggestion>)suggestionAtIndexPath:(NSIndexPath*)indexPath { + if (indexPath.section < 0 || indexPath.row < 0) { + return nil; + } + if (!self.currentResult || self.currentResult.count == 0 || + self.currentResult.count <= (NSUInteger)indexPath.section || + self.currentResult[indexPath.section].suggestions.count <= + (NSUInteger)indexPath.row) { + return nil; + } + return self.currentResult[indexPath.section].suggestions[indexPath.row]; +} + - (void)updateVisibleSuggestionCount { CGFloat keyboardHeight = [[KeyboardObserverHelper sharedKeyboardObserver] visibleKeyboardHeight];
diff --git a/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor.h b/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor.h index 81454ed7..dcc5012 100644 --- a/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor.h +++ b/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor.h
@@ -7,30 +7,28 @@ #import "ios/chrome/browser/ui/omnibox/omnibox_text_change_delegate.h" #import "ios/chrome/browser/ui/omnibox/popup/autocomplete_result_consumer.h" +#import "ios/chrome/browser/ui/omnibox/popup/autocomplete_suggestion.h" @protocol PopupMatchPreviewDelegate; -// Extractor can be inserted in between the OmniboxPopupMediator and its -// consumer. It acts as a consumer and a consumer delegate, and is intended to -// intercept any calls in these protocols. -// It extracts any pedals being pushed to it, wraps them to look like -// suggestions, and passes it down to `dataSink`. -// It also intercepts the return key (by proxying OmniboxReturnDelegate) to -// allow "return" key to execute the pedal whenever it selected; if a non-pedal -// is highlighted, it forwards the call to its accept delegate. -// When a pedal is highlighted, it also tells the match preview delegate -// to display the corresponding image and text. -@interface PedalSectionExtractor : NSObject <AutocompleteResultConsumer, - AutocompleteResultConsumerDelegate, - OmniboxReturnDelegate> +// Delegate for PedalSectionExtractor. +@protocol PedalSectionExtractorDelegate <NSObject> -// The sink to forward AutocompleteResultConsumer calls. -@property(nonatomic, weak) id<AutocompleteResultConsumer> dataSink; -// The delegate to forward AutocompleteResultConsumerDelegate calls to. -@property(nonatomic, weak) id<AutocompleteResultConsumerDelegate> delegate; -// The delegate that receives text/image when a pedal is highlighted. -@property(nonatomic, weak) id<PopupMatchPreviewDelegate> matchPreviewDelegate; -@property(nonatomic, weak) id<OmniboxReturnDelegate> acceptDelegate; +// Removes the pedal group from suggestions. Pedal are removed from suggestions +// with a debouce timer in `PedalSectionExtractor`. When the timer ends the +// pedal group is removed. +- (void)invalidatePedals; + +@end + +// Extract pedal from AutocompleteSuggestion and wrap them in new +// AutocompleteSuggestion. +@interface PedalSectionExtractor : NSObject + +@property(nonatomic, weak) id<PedalSectionExtractorDelegate> delegate; + +- (id<AutocompleteSuggestionGroup>)extractPedals: + (NSArray<id<AutocompleteSuggestion>>*)suggestions; @end
diff --git a/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor.mm b/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor.mm index 6f02d5b..4c82fcf21 100644 --- a/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor.mm +++ b/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor.mm
@@ -27,238 +27,20 @@ @interface PedalSectionExtractor () -@property(nonatomic, strong) - NSArray<id<OmniboxPedal, OmniboxIcon>>* extractedPedals; +@property(nonatomic, strong) id<AutocompleteSuggestionGroup> previousPedalGroup; // Timer for pedal debouncing. @property(nonatomic, strong) NSTimer* removePedalsTimer; @property(nonatomic, strong) - NSArray<id<AutocompleteSuggestionGroup>>* originalResult; -@property(nonatomic, assign) NSInteger highlightedPedalIndex; -// Currently highlighted index path, if any. -// This is index path in `consumer` numeration, not in `originalResult` one. -@property(nonatomic, assign) NSIndexPath* highlightedIndexPath; + NSArray<id<AutocompleteSuggestion>>* originalResult; @end @implementation PedalSectionExtractor -- (instancetype)init { - self = [super init]; - if (self) { - _highlightedPedalIndex = NSNotFound; - } - return self; -} - -#pragma mark - AutocompleteResultConsumer - -- (void)updateMatches:(NSArray<id<AutocompleteSuggestionGroup>>*)result - preselectedMatchGroupIndex:(NSInteger)groupIndex { - NSMutableArray* extractedPedals = [[NSMutableArray alloc] init]; - self.highlightedPedalIndex = NSNotFound; - self.highlightedIndexPath = nil; - self.originalResult = result; - - if (result.count > 0 && result[groupIndex].suggestions.count > 0) { - id<AutocompleteSuggestion> preselectedSuggestion = - result[groupIndex].suggestions[0]; - [self.matchPreviewDelegate setPreviewSuggestion:preselectedSuggestion - isFirstUpdate:YES]; - } else { - [self.matchPreviewDelegate setPreviewSuggestion:nil isFirstUpdate:YES]; - } - - NSInteger totalSuggestionCount = 0; - for (id<AutocompleteSuggestionGroup> group in result) { - totalSuggestionCount += group.suggestions.count; - for (NSUInteger i = 0; i < group.suggestions.count; i++) { - id<AutocompleteSuggestion> suggestion = group.suggestions[i]; - - if (suggestion.pedal != nil) { - [extractedPedals addObject:suggestion.pedal]; - } - } - } - - if (extractedPedals.count == 0 && self.extractedPedals.count > 0 && - totalSuggestionCount > 0) { - // If no pedals, display old pedal for a duration of `kPedalDebouceTimer` - // with new suggestion. This avoids pedal flickering because the pedal - // results are async. (cf. crbug.com/1316404). - [self updateMatchesWithPedals:self.extractedPedals suggestionGroup:result]; - if (!self.removePedalsTimer) { - self.removePedalsTimer = - [NSTimer scheduledTimerWithTimeInterval:kPedalDebouceTimer - target:self - selector:@selector(removePedals:) - userInfo:nil - repeats:NO]; - } - return; - } else { - [self.removePedalsTimer invalidate]; - self.removePedalsTimer = nil; - } - - self.extractedPedals = extractedPedals; - - [self updateMatchesWithPedals:extractedPedals suggestionGroup:result]; -} - -- (void)setTextAlignment:(NSTextAlignment)alignment { - [self.dataSink setTextAlignment:alignment]; -} - -- (void)setSemanticContentAttribute: - (UISemanticContentAttribute)semanticContentAttribute { - [self.dataSink setSemanticContentAttribute:semanticContentAttribute]; -} - -- (void)newResultsAvailable { - return [self.dataSink newResultsAvailable]; -} - -#pragma mark - AutocompleteResultConsumerDelegate - -- (void)autocompleteResultConsumerCancelledHighlighting: - (id<AutocompleteResultConsumer>)sender { - self.highlightedPedalIndex = NSNotFound; - self.highlightedIndexPath = nil; - [self.delegate autocompleteResultConsumerCancelledHighlighting:self]; - [self.matchPreviewDelegate setPreviewSuggestion:nil isFirstUpdate:NO]; -} - -- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didHighlightRow:(NSUInteger)row - inSection:(NSUInteger)section { - self.highlightedIndexPath = [NSIndexPath indexPathForRow:row - inSection:section]; - if (self.extractedPedals.count > 0) { - if (section == 0) { - [self.delegate autocompleteResultConsumerCancelledHighlighting:self]; - [self.matchPreviewDelegate - setPreviewSuggestion:[[PedalSuggestionWrapper alloc] - initWithPedal:self.extractedPedals[row]] - isFirstUpdate:NO]; - self.highlightedPedalIndex = row; - return; - } else { - self.highlightedPedalIndex = NSNotFound; - section -= 1; - } - } - - id<AutocompleteSuggestion> match = - self.originalResult[section].suggestions[row]; - [self.matchPreviewDelegate setPreviewSuggestion:match isFirstUpdate:NO]; -} - -- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didSelectRow:(NSUInteger)row - inSection:(NSUInteger)section { - if (self.extractedPedals.count > 0) { - if (section == 0) { - id<OmniboxPedal> pedal = self.extractedPedals[row]; - if (pedal.action) { - for (id<OmniboxPedal> displayedPedal in self.extractedPedals) { - base::UmaHistogramEnumeration( - "Omnibox.PedalShown", - static_cast<OmniboxPedalId>(displayedPedal.type), - OmniboxPedalId::TOTAL_COUNT); - } - - base::UmaHistogramEnumeration("Omnibox.SuggestionUsed.Pedal", - static_cast<OmniboxPedalId>(pedal.type), - OmniboxPedalId::TOTAL_COUNT); - pedal.action(); - } - return; - } else { - section -= 1; - } - } - - [self.delegate autocompleteResultConsumer:self - didSelectRow:row - inSection:section]; -} - -- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didTapTrailingButtonForRow:(NSUInteger)row - inSection:(NSUInteger)section { - if (self.extractedPedals.count > 0) { - // Pedals do not have trailing buttons. - DCHECK(section > 0); - section -= 1; - } - - [self.delegate autocompleteResultConsumer:self - didTapTrailingButtonForRow:row - inSection:section]; -} - -- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender - didSelectRowForDeletion:(NSUInteger)row - inSection:(NSUInteger)section { - if (self.extractedPedals.count > 0) { - // Pedals do not support deletion. - DCHECK(section > 0); - section -= 1; - } - - [self.delegate autocompleteResultConsumer:self - didSelectRowForDeletion:row - inSection:section]; -} - -- (void)autocompleteResultConsumerDidScroll: - (id<AutocompleteResultConsumer>)sender { - [self.delegate autocompleteResultConsumerDidScroll:self]; -} - -#pragma mark - OmniboxReturnDelegate - -- (void)omniboxReturnPressed:(id)sender { - if (self.highlightedPedalIndex != NSNotFound) { - id<OmniboxPedal> pedal = self.extractedPedals[self.highlightedPedalIndex]; - if (pedal.action) { - pedal.action(); - } - return; - } - - if (self.highlightedIndexPath) { - // Pretend that the consumer actually selected the highlighted row. - [self autocompleteResultConsumer:nil - didSelectRow:self.highlightedIndexPath.row - inSection:self.highlightedIndexPath.section]; - return; - } - - [self.acceptDelegate omniboxReturnPressed:sender]; -} - -#pragma mark - Private methods - -// Removes pedals from suggestions. This is used to debouce pedal with a timer -// to avoid pedal flickering. -- (void)removePedals:(NSTimer*)timer { - [self.dataSink updateMatches:self.originalResult - preselectedMatchGroupIndex:0]; - - self.extractedPedals = nil; - self.removePedalsTimer = nil; -} - -// Updates matches in `self.dataSink` with pedals from `extractedPedals` and -// suggestions from `result`. -- (void)updateMatchesWithPedals: - (NSArray<id<OmniboxPedal, OmniboxIcon>>*)extractedPedals - suggestionGroup: - (NSArray<id<AutocompleteSuggestionGroup>>*)result { ++ (id<AutocompleteSuggestionGroup>)wrapPedals: + (NSArray<id<OmniboxPedal, OmniboxIcon>>*)extractedPedals { if (extractedPedals.count == 0) { - [self.dataSink updateMatches:result preselectedMatchGroupIndex:0]; - return; + return nil; } NSMutableArray* wrappedPedals = [[NSMutableArray alloc] init]; @@ -270,12 +52,59 @@ AutocompleteSuggestionGroupImpl* pedalGroup = [AutocompleteSuggestionGroupImpl groupWithTitle:nil suggestions:wrappedPedals]; - NSArray* combinedGroups = @[ pedalGroup ]; - combinedGroups = [combinedGroups arrayByAddingObjectsFromArray:result]; - const NSInteger suggestionGroupIndexInCombinedGroups = 1; + return pedalGroup; +} - [self.dataSink updateMatches:combinedGroups - preselectedMatchGroupIndex:suggestionGroupIndexInCombinedGroups]; +- (id<AutocompleteSuggestionGroup>)extractPedals: + (NSArray<id<AutocompleteSuggestion>>*)suggestions { + self.originalResult = suggestions; + // Extract pedals + NSMutableArray* extractedPedals = [[NSMutableArray alloc] init]; + for (NSUInteger i = 0; i < suggestions.count; i++) { + id<AutocompleteSuggestion> suggestion = suggestions[i]; + if (suggestion.pedal != nil) { + [extractedPedals addObject:suggestion.pedal]; + } + } + + if (extractedPedals.count > 0) { + [self.removePedalsTimer invalidate]; + self.removePedalsTimer = nil; + + id<AutocompleteSuggestionGroup> pedalGroup = + [PedalSectionExtractor wrapPedals:extractedPedals]; + self.previousPedalGroup = pedalGroup; + return pedalGroup; + } else if (self.previousPedalGroup && suggestions.count > 0) { + // If no pedals, display old pedal for a duration of `kPedalDebouceTimer` + // with new suggestion. This avoids pedal flickering because the pedal + // results are async. (cf. crbug.com/1316404). + if (!self.removePedalsTimer) { + self.removePedalsTimer = [NSTimer + scheduledTimerWithTimeInterval:kPedalDebouceTimer + target:self + selector:@selector(expirePreviousPedals:) + userInfo:nil + repeats:NO]; + } + return self.previousPedalGroup; + } else { + // Remove cached pedals when the popup is closed. + if (suggestions.count == 0) { + [self expirePreviousPedals:nil]; + } + return nil; + } +} + +// Removes pedals from suggestions. This is used to debouce pedal with a timer +// to avoid pedal flickering. +- (void)expirePreviousPedals:(NSTimer*)timer { + [self.removePedalsTimer invalidate]; + self.previousPedalGroup = nil; + self.removePedalsTimer = nil; + + [self.delegate invalidatePedals]; } @end
diff --git a/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor_unittest.mm b/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor_unittest.mm index 6565e82..1c10cf3 100644 --- a/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor_unittest.mm +++ b/ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor_unittest.mm
@@ -19,404 +19,6 @@ namespace { -// Waits without blocking the runloop. -void Wait(NSTimeInterval timeout) { - NSDate* deadline = [NSDate dateWithTimeIntervalSinceNow:timeout]; - while ([[NSDate date] compare:deadline] != NSOrderedDescending) { - base::test::ios::SpinRunLoopWithMaxDelay(base::Seconds(0.01)); - } -} - -class PedalSectionExtractorTest : public PlatformTest { - protected: - void ExpectPreviewSuggestion(id suggestion, BOOL is_first_update) { - [[preview_delegate_ expect] setPreviewSuggestion:suggestion - isFirstUpdate:is_first_update]; - } - - void SetUp() override { - PlatformTest::SetUp(); - extractor_ = [[PedalSectionExtractor alloc] init]; - data_sink_ = - [OCMockObject mockForProtocol:@protocol(AutocompleteResultConsumer)]; - delegate_ = [OCMockObject - mockForProtocol:@protocol(AutocompleteResultConsumerDelegate)]; - preview_delegate_ = - [OCMockObject mockForProtocol:@protocol(PopupMatchPreviewDelegate)]; - - extractor_.dataSink = data_sink_; - extractor_.delegate = delegate_; - extractor_.matchPreviewDelegate = preview_delegate_; - } - - PedalSectionExtractor* extractor_; - OCMockObject<AutocompleteResultConsumer>* data_sink_; - OCMockObject<AutocompleteResultConsumerDelegate>* delegate_; - OCMockObject<PopupMatchPreviewDelegate>* preview_delegate_; -}; - -// When there's no pedals, extractor doesn't change the result. -TEST_F(PedalSectionExtractorTest, ForwardsWhenNoPedals) { - id mockSuggestion = - [OCMockObject mockForProtocol:@protocol(AutocompleteSuggestion)]; - [[[mockSuggestion expect] andReturn:nil] pedal]; - - AutocompleteSuggestionGroupImpl* group = - [AutocompleteSuggestionGroupImpl groupWithTitle:@"" - suggestions:@[ mockSuggestion ]]; - - ExpectPreviewSuggestion(mockSuggestion, YES); - [[data_sink_ expect] updateMatches:@[ group ] preselectedMatchGroupIndex:0]; - - [extractor_ updateMatches:@[ group ] preselectedMatchGroupIndex:0]; - - [data_sink_ verify]; -} - -// When there's a pedal, it's extracted into a "suggestion" with the same name -// in a separate group. -TEST_F(PedalSectionExtractorTest, ExtractsPedalsIntoSeparateSection) { - id mockSuggestionNoPedal = - [OCMockObject mockForProtocol:@protocol(AutocompleteSuggestion)]; - [[[mockSuggestionNoPedal stub] andReturn:nil] pedal]; - - id mockPedal = [OCMockObject mockForProtocol:@protocol(OmniboxPedal)]; - [[[mockPedal stub] andReturn:@"pedal title"] title]; - id mockSuggestionWithPedal = - [OCMockObject mockForProtocol:@protocol(AutocompleteSuggestion)]; - [[[mockSuggestionWithPedal stub] andReturn:mockPedal] pedal]; - - AutocompleteSuggestionGroupImpl* group = [AutocompleteSuggestionGroupImpl - groupWithTitle:@"" - suggestions:@[ mockSuggestionNoPedal, mockSuggestionWithPedal ]]; - - void (^verifyGroups)(NSInvocation*) = ^(NSInvocation* invocation) { - __unsafe_unretained NSArray<id<AutocompleteSuggestionGroup>>* groups = nil; - [invocation getArgument:&groups atIndex:2]; - NSInteger preselectedMatchGroupIndex = -1; - [invocation getArgument:&preselectedMatchGroupIndex atIndex:3]; - - EXPECT_EQ(preselectedMatchGroupIndex, 1); - EXPECT_EQ(groups.count, 2u); - EXPECT_EQ(groups[0].suggestions.count, 1u); - - id<AutocompleteSuggestion> suggestion = groups[0].suggestions[0]; - EXPECT_EQ(suggestion.text.string, @"pedal title"); - }; - - [[[data_sink_ stub] andDo:verifyGroups] updateMatches:[OCMArg any] - preselectedMatchGroupIndex:1]; - - ExpectPreviewSuggestion(mockSuggestionNoPedal, YES); - [extractor_ updateMatches:@[ group ] preselectedMatchGroupIndex:0]; - - [data_sink_ verify]; -} - -// When a pedal disappears from the result list, the extractor prevents -// its disappearance for a short time to reduce UI updates. -TEST_F(PedalSectionExtractorTest, Debounce) { - id mockSuggestionNoPedal = - [OCMockObject mockForProtocol:@protocol(AutocompleteSuggestion)]; - [[[mockSuggestionNoPedal stub] andReturn:nil] pedal]; - - id mockPedal = [OCMockObject mockForProtocol:@protocol(OmniboxPedal)]; - [[[mockPedal stub] andReturn:@"pedal title"] title]; - id mockSuggestionWithPedal = - [OCMockObject mockForProtocol:@protocol(AutocompleteSuggestion)]; - [[[mockSuggestionWithPedal stub] andReturn:mockPedal] pedal]; - - AutocompleteSuggestionGroupImpl* group = [AutocompleteSuggestionGroupImpl - groupWithTitle:@"" - suggestions:@[ mockSuggestionNoPedal, mockSuggestionWithPedal ]]; - - // Showing a result with pedals passes a pedal to the sink. - - [[data_sink_ expect] updateMatches:[OCMArg any] preselectedMatchGroupIndex:1]; - ExpectPreviewSuggestion(mockSuggestionNoPedal, YES); - - [extractor_ updateMatches:@[ group ] preselectedMatchGroupIndex:0]; - [data_sink_ verify]; - - AutocompleteSuggestionGroupImpl* groupNoPedals = - [AutocompleteSuggestionGroupImpl - groupWithTitle:@"" - suggestions:@[ mockSuggestionNoPedal ]]; - - // Updating with no pedals continues to pass a pedal to the sink. - - ExpectPreviewSuggestion(mockSuggestionNoPedal, YES); - [[data_sink_ expect] updateMatches:[OCMArg any] preselectedMatchGroupIndex:1]; - [extractor_ updateMatches:@[ groupNoPedals ] preselectedMatchGroupIndex:0]; - - [data_sink_ verify]; - - // Expect pedal removal when debounce timer expires - [[data_sink_ expect] updateMatches:@[ groupNoPedals ] - preselectedMatchGroupIndex:0]; - - // Wait for debounce to happen - Wait(1); - [data_sink_ verify]; - - // Now updating from no pedals to no pedals, nothing happens - [[data_sink_ expect] updateMatches:@[ groupNoPedals ] - preselectedMatchGroupIndex:0]; - ExpectPreviewSuggestion(mockSuggestionNoPedal, YES); - [extractor_ updateMatches:@[ groupNoPedals ] preselectedMatchGroupIndex:0]; - - [data_sink_ verify]; - - // Since there's no update, nothing happens after the debounce timer expires - // again. - Wait(1); - [data_sink_ verify]; -} - -// When the list of suggestions is completely empty, prevent the pedal from -// sticking around. This should only happen when the popup is being closed, -// otherwise there's at least a what-you-type suggestion. -TEST_F(PedalSectionExtractorTest, DontDebounceEmptyList) { - id mockSuggestionNoPedal = - [OCMockObject mockForProtocol:@protocol(AutocompleteSuggestion)]; - [[[mockSuggestionNoPedal stub] andReturn:nil] pedal]; - - id mockPedal = [OCMockObject mockForProtocol:@protocol(OmniboxPedal)]; - [[[mockPedal stub] andReturn:@"pedal title"] title]; - id mockSuggestionWithPedal = - [OCMockObject mockForProtocol:@protocol(AutocompleteSuggestion)]; - [[[mockSuggestionWithPedal stub] andReturn:mockPedal] pedal]; - - AutocompleteSuggestionGroupImpl* group = [AutocompleteSuggestionGroupImpl - groupWithTitle:@"" - suggestions:@[ mockSuggestionNoPedal, mockSuggestionWithPedal ]]; - - // Showing a result with pedals passes a pedal to the sink. - - [[data_sink_ expect] updateMatches:[OCMArg any] preselectedMatchGroupIndex:1]; - ExpectPreviewSuggestion(mockSuggestionNoPedal, YES); - [extractor_ updateMatches:@[ group ] preselectedMatchGroupIndex:0]; - [data_sink_ verify]; - - AutocompleteSuggestionGroupImpl* groupNoPedals = - [AutocompleteSuggestionGroupImpl - groupWithTitle:@"" - suggestions:@[ mockSuggestionNoPedal ]]; - - // Updating with no pedals continues to pass a pedal to the sink. - - [[data_sink_ expect] updateMatches:[OCMArg any] preselectedMatchGroupIndex:1]; - ExpectPreviewSuggestion(mockSuggestionNoPedal, YES); - [extractor_ updateMatches:@[ groupNoPedals ] preselectedMatchGroupIndex:0]; - - [data_sink_ verify]; - - // Expect pedal removal when debounce timer expires - [[data_sink_ expect] updateMatches:@[ groupNoPedals ] - preselectedMatchGroupIndex:0]; - - // Wait for debounce to happen - Wait(1); - [data_sink_ verify]; - - // Now updating from no pedals to no suggestions at all, the update goes - // through. - [[data_sink_ expect] updateMatches:@[] preselectedMatchGroupIndex:0]; - ExpectPreviewSuggestion(nil, YES); - [extractor_ updateMatches:@[] preselectedMatchGroupIndex:0]; - - [data_sink_ verify]; - - // Since there's no update, nothing happens after the debounce timer expires - // again. - Wait(1); - [data_sink_ verify]; -} - -// Forwards methods that are not affected by the pedal section. -TEST_F(PedalSectionExtractorTest, ForwardsIrrelevantMethods) { - // consumer methods - [[data_sink_ expect] setTextAlignment:NSTextAlignmentLeft]; - [extractor_ setTextAlignment:NSTextAlignmentLeft]; - [data_sink_ verify]; - - [[data_sink_ expect] - setSemanticContentAttribute:UISemanticContentAttributeSpatial]; - [extractor_ setSemanticContentAttribute:UISemanticContentAttributeSpatial]; - [data_sink_ verify]; - - // delegate methods - [[delegate_ expect] autocompleteResultConsumerDidScroll:extractor_]; - [extractor_ autocompleteResultConsumerDidScroll:nil]; - [delegate_ verify]; -} - -#pragma mark - highlight tests - -// Tests in this class start with a pedal and a regular match. -class PedalSectionExtractorHighlightTest : public PedalSectionExtractorTest { - protected: - void ExpectPedalPreviewSuggestion(BOOL is_first_update) { - void (^verifyPreviewMatch)(NSInvocation*) = ^(NSInvocation* invocation) { - __unsafe_unretained id<AutocompleteSuggestion> match = nil; - [invocation getArgument:&match atIndex:2]; - EXPECT_TRUE([match.text.string isEqualToString:@"pedal title"]); - }; - - [[[preview_delegate_ expect] andDo:verifyPreviewMatch] - setPreviewSuggestion:[OCMArg any] - isFirstUpdate:is_first_update]; - } - - void SetUp() override { - PedalSectionExtractorTest::SetUp(); - - return_delegate_ = - [OCMockObject mockForProtocol:@protocol(OmniboxReturnDelegate)]; - extractor_.acceptDelegate = return_delegate_; - - mock_suggestion_no_pedal_ = - [OCMockObject mockForProtocol:@protocol(AutocompleteSuggestion)]; - [[[mock_suggestion_no_pedal_ stub] andReturn:nil] pedal]; - - mock_pedal_ = [OCMockObject mockForProtocol:@protocol(OmniboxPedal)]; - [[[mock_pedal_ stub] andReturn:@"pedal title"] title]; - mock_suggestion_with_pedal_ = - [OCMockObject mockForProtocol:@protocol(AutocompleteSuggestion)]; - [[[mock_suggestion_with_pedal_ stub] andReturn:mock_pedal_] pedal]; - - AutocompleteSuggestionGroupImpl* group = [AutocompleteSuggestionGroupImpl - groupWithTitle:@"" - suggestions:@[ - mock_suggestion_no_pedal_, mock_suggestion_with_pedal_ - ]]; - - [[data_sink_ expect] updateMatches:[OCMArg any] - preselectedMatchGroupIndex:1]; - ExpectPreviewSuggestion(mock_suggestion_no_pedal_, YES); - [extractor_ updateMatches:@[ group ] preselectedMatchGroupIndex:0]; - [preview_delegate_ verify]; - } - - OCMockObject<OmniboxPedal>* mock_pedal_; - OCMockObject<OmniboxReturnDelegate>* return_delegate_; - id mock_suggestion_no_pedal_; - id mock_suggestion_with_pedal_; -}; - -// Test highlighting: highlighting sets the preview correctly, even for pedals. -TEST_F(PedalSectionExtractorHighlightTest, highlightsPedalsAndSuggestions) { - // When the first suggestion is highlighted in the popup, pretend there's no - // pedal section at index 0. - ExpectPreviewSuggestion(mock_suggestion_no_pedal_, NO); - [extractor_ autocompleteResultConsumer:nil didHighlightRow:0 inSection:1]; - [preview_delegate_ verify]; - - // Same for second suggestion - ExpectPreviewSuggestion(mock_suggestion_with_pedal_, NO); - [extractor_ autocompleteResultConsumer:nil didHighlightRow:1 inSection:1]; - [preview_delegate_ verify]; - - // When the pedal is highlighted in the popup, pretend the highlighting has - // went away. Then fake the highlighting by updating the match preview. - ExpectPedalPreviewSuggestion(NO); - [[delegate_ expect] - autocompleteResultConsumerCancelledHighlighting:extractor_]; - [extractor_ autocompleteResultConsumer:nil didHighlightRow:0 inSection:0]; - [preview_delegate_ verify]; - - // When the highlighting is cancelled, forward this. - ExpectPreviewSuggestion(nil, NO); - [[delegate_ expect] - autocompleteResultConsumerCancelledHighlighting:extractor_]; - [extractor_ autocompleteResultConsumerCancelledHighlighting:extractor_]; -} - -TEST_F(PedalSectionExtractorHighlightTest, ForwardsTrailingButton) { - [[delegate_ expect] autocompleteResultConsumer:extractor_ - didTapTrailingButtonForRow:0 - inSection:0]; - [extractor_ autocompleteResultConsumer:nil - didTapTrailingButtonForRow:0 - inSection:1]; - [delegate_ verify]; -} - -TEST_F(PedalSectionExtractorHighlightTest, ForwardsDeletion) { - [[delegate_ expect] autocompleteResultConsumer:extractor_ - didSelectRowForDeletion:0 - inSection:0]; - [extractor_ autocompleteResultConsumer:nil - didSelectRowForDeletion:0 - inSection:1]; - [delegate_ verify]; -} - -// Return button is equivalent to selection, unless a pedal is selected. -// When a pedal is selected, it's immediately executed. -TEST_F(PedalSectionExtractorHighlightTest, ReturnButton) { - __block BOOL pedalTriggered = NO; - void (^pedalBlock)(void) = ^() { - pedalTriggered = YES; - }; - - [[[mock_pedal_ stub] andReturn:pedalBlock] action]; - - // When the first suggestion is highlighted in the popup, and return is - // pressed, the delegate receives a selection event and the pedal is not - // triggered. - ExpectPreviewSuggestion(mock_suggestion_no_pedal_, NO); - [extractor_ autocompleteResultConsumer:nil didHighlightRow:0 inSection:1]; - [[delegate_ expect] autocompleteResultConsumer:[OCMArg any] - didSelectRow:0 - inSection:0]; - [extractor_ omniboxReturnPressed:nil]; - [delegate_ verify]; - [return_delegate_ verify]; - EXPECT_EQ(pedalTriggered, NO); - - // Same for second suggestion - ExpectPreviewSuggestion(mock_suggestion_with_pedal_, NO); - [[delegate_ expect] autocompleteResultConsumer:[OCMArg any] - didSelectRow:1 - inSection:0]; - [extractor_ autocompleteResultConsumer:nil didHighlightRow:1 inSection:1]; - [extractor_ omniboxReturnPressed:nil]; - [delegate_ verify]; - [return_delegate_ verify]; - [preview_delegate_ verify]; - EXPECT_EQ(pedalTriggered, NO); - - // Highlight the pedal - ExpectPedalPreviewSuggestion(NO); - [[delegate_ expect] - autocompleteResultConsumerCancelledHighlighting:extractor_]; - [extractor_ autocompleteResultConsumer:nil didHighlightRow:0 inSection:0]; - [delegate_ verify]; - [preview_delegate_ verify]; - - // Cancel highlighting and hit return. This should be forwarded. - ExpectPreviewSuggestion(nil, NO); - [[delegate_ expect] - autocompleteResultConsumerCancelledHighlighting:extractor_]; - [extractor_ autocompleteResultConsumerCancelledHighlighting:extractor_]; - [delegate_ verify]; - [[return_delegate_ expect] omniboxReturnPressed:nil]; - [extractor_ omniboxReturnPressed:nil]; - [return_delegate_ verify]; - EXPECT_EQ(pedalTriggered, NO); - - // Highlight the pedal again. - ExpectPedalPreviewSuggestion(NO); - [[delegate_ expect] - autocompleteResultConsumerCancelledHighlighting:extractor_]; - [extractor_ autocompleteResultConsumer:nil didHighlightRow:0 inSection:0]; - [delegate_ verify]; - [preview_delegate_ verify]; - - // Hit return. The pedal should be executed. - [extractor_ omniboxReturnPressed:nil]; - EXPECT_EQ(pedalTriggered, YES); -} +// TODO in next CL. } // namespace
diff --git a/ios/chrome/browser/ui/omnibox/popup/shared/popup_model.swift b/ios/chrome/browser/ui/omnibox/popup/shared/popup_model.swift index 6bb6572e..41df964a 100644 --- a/ios/chrome/browser/ui/omnibox/popup/shared/popup_model.swift +++ b/ios/chrome/browser/ui/omnibox/popup/shared/popup_model.swift
@@ -98,11 +98,7 @@ } if indexPath.section == 0 && indexPath.row == 0 { - // Can't move up from first row. Call the delegate again so that the inline - // autocomplete text is set again (in case the user exited the inline - // autocomplete). - self.delegate?.autocompleteResultConsumer( - self, didHighlightRow: UInt(indexPath.row), inSection: UInt(indexPath.section)) + // Can't move up from first row. return } @@ -116,8 +112,6 @@ } self.highlightedMatchIndexPath = indexPath - self.delegate?.autocompleteResultConsumer( - self, didHighlightRow: UInt(indexPath.row), inSection: UInt(indexPath.section)) } public func highlightNextSuggestion() { @@ -140,10 +134,6 @@ indexPath.section += 1 } - // We call the delegate again even if we stayed on the last row so that the inline - // autocomplete text is set again (in case the user exited the inline autocomplete). - self.delegate?.autocompleteResultConsumer( - self, didHighlightRow: UInt(indexPath.row), inSection: UInt(indexPath.section)) self.highlightedMatchIndexPath = indexPath } }
diff --git a/ios/chrome/browser/ui/omnibox/popup/shared/popup_view.swift b/ios/chrome/browser/ui/omnibox/popup/shared/popup_view.swift index c5fa9c12..88156c7 100644 --- a/ios/chrome/browser/ui/omnibox/popup/shared/popup_view.swift +++ b/ios/chrome/browser/ui/omnibox/popup/shared/popup_view.swift
@@ -195,12 +195,12 @@ toolbarConfiguration: uiConfiguration.toolbarConfiguration, selectionHandler: { model.delegate?.autocompleteResultConsumer( - model, didSelectRow: UInt(matchIndex), inSection: UInt(sectionIndex)) + model, didSelect: match.suggestion, inRow: UInt(matchIndex)) }, trailingButtonHandler: { model.delegate?.autocompleteResultConsumer( - model, didTapTrailingButtonForRow: UInt(matchIndex), - inSection: UInt(sectionIndex)) + model, didTapTrailingButtonOn: match.suggestion, + inRow: UInt(matchIndex)) shouldIgnoreScrollEvents = true DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { shouldIgnoreScrollEvents = false @@ -223,7 +223,8 @@ .onDelete { indexSet in for matchIndex in indexSet { model.delegate?.autocompleteResultConsumer( - model, didSelectRowForDeletion: UInt(matchIndex), inSection: UInt(sectionIndex)) + model, didSelectSuggestionForDeletion: section.matches[matchIndex].suggestion, + inRow: UInt(matchIndex)) } } }
diff --git a/ios/chrome/browser/ui/promos_manager/BUILD.gn b/ios/chrome/browser/ui/promos_manager/BUILD.gn index f53d52d..457b56a9 100644 --- a/ios/chrome/browser/ui/promos_manager/BUILD.gn +++ b/ios/chrome/browser/ui/promos_manager/BUILD.gn
@@ -56,6 +56,8 @@ "//ios/chrome/browser/application_context", "//ios/chrome/browser/promos_manager:constants", "//ios/chrome/browser/ui/main:scene_state_header", + "//ios/chrome/browser/ui/post_restore_signin", + "//ios/chrome/browser/ui/post_restore_signin:features", "//ios/chrome/common/ui/confirmation_alert", "//third_party/abseil-cpp:absl", ]
diff --git a/ios/chrome/browser/ui/promos_manager/promos_manager_coordinator.mm b/ios/chrome/browser/ui/promos_manager/promos_manager_coordinator.mm index 78d3b94..0c2ea75 100644 --- a/ios/chrome/browser/ui/promos_manager/promos_manager_coordinator.mm +++ b/ios/chrome/browser/ui/promos_manager/promos_manager_coordinator.mm
@@ -15,6 +15,8 @@ #import "ios/chrome/browser/ui/commands/promos_manager_commands.h" #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" #import "ios/chrome/browser/ui/main/scene_state_browser_agent.h" +#import "ios/chrome/browser/ui/post_restore_signin/features.h" +#import "ios/chrome/browser/ui/post_restore_signin/post_restore_signin_provider.h" #import "ios/chrome/browser/ui/promos_manager/promos_manager_mediator.h" #import "ios/chrome/browser/ui/promos_manager/promos_manager_scene_agent.h" #import "ios/chrome/browser/ui/promos_manager/standard_promo_action_handler.h" @@ -177,8 +179,11 @@ // Add StandardPromoDisplayHandler promos here. For example: // TODO(crbug.com/1360880): Create first StandardPromoDisplayHandler promo. - // Add StandardPromoViewProvider promos here. For example: - // TODO(crbug.com/1360881): Create first StandardPromoViewProvider promo. + // StandardPromoViewProvider promo(s) below: + if (post_restore_signin::features::CurrentPostRestoreSignInType() == + post_restore_signin::features::PostRestoreSignInType::kFullscreen) + _viewProviderPromos[promos_manager::Promo::PostRestoreSignInFullscreen] = + [[PostRestoreSignInProvider alloc] init]; } - (base::small_map<std::map<promos_manager::Promo, NSArray<ImpressionLimit*>*>>)
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn index 24d3475..4a6423c 100644 --- a/ios/chrome/browser/ui/settings/BUILD.gn +++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -175,6 +175,7 @@ "//ios/chrome/browser/ui/settings/language:language", "//ios/chrome/browser/ui/settings/language:language_ui", "//ios/chrome/browser/ui/settings/password", + "//ios/chrome/browser/ui/settings/price_notifications", "//ios/chrome/browser/ui/settings/privacy", "//ios/chrome/browser/ui/settings/privacy:privacy_ui", "//ios/chrome/browser/ui/settings/safety_check",
diff --git a/ios/chrome/browser/ui/settings/password/BUILD.gn b/ios/chrome/browser/ui/settings/password/BUILD.gn index d8375c09b..de151e8 100644 --- a/ios/chrome/browser/ui/settings/password/BUILD.gn +++ b/ios/chrome/browser/ui/settings/password/BUILD.gn
@@ -276,6 +276,7 @@ "//ios/chrome/browser/ui/authentication:eg_test_support+eg2", "//ios/chrome/browser/ui/settings:settings_root_constants", "//ios/chrome/browser/ui/settings/google_services:constants", + "//ios/chrome/browser/ui/settings/password/password_settings:password_settings_constants", "//ios/chrome/browser/ui/util", "//ios/chrome/common/ui/reauthentication", "//ios/chrome/common/ui/table_view:cells_constants",
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm index b48ad07..1a882c51 100644 --- a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm +++ b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
@@ -18,6 +18,7 @@ #import "ios/chrome/browser/metrics/metrics_app_interface.h" #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h" #import "ios/chrome/browser/ui/settings/google_services/manage_sync_settings_constants.h" +#import "ios/chrome/browser/ui/settings/password/password_settings/password_settings_constants.h" #import "ios/chrome/browser/ui/settings/password/password_settings_app_interface.h" #import "ios/chrome/browser/ui/settings/password/passwords_table_view_constants.h" #import "ios/chrome/browser/ui/settings/settings_root_table_constants.h" @@ -122,7 +123,7 @@ id<GREYMatcher> matcher) { return [[EarlGrey selectElementWithMatcher:grey_allOf(matcher, grey_interactable(), nil)] - inRoot:grey_accessibilityID(kPasswordsExportConfirmViewId)]; + inRoot:grey_accessibilityID(kPasswordSettingsExportConfirmViewId)]; } GREYElementInteraction* GetPasswordDetailTextFieldWithID(int detail_id) { @@ -1258,10 +1259,14 @@ OpenPasswordManager(); - [PasswordSettingsAppInterface setUpMockReauthenticationModuleForExport]; + [PasswordSettingsAppInterface + setUpMockReauthenticationModuleForExportFromSettings]; [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult: ReauthenticationResult::kSuccess]; + [[EarlGrey selectElementWithMatcher:ToolbarSettingsSubmenuButton()] + performAction:grey_tap()]; + [[[EarlGrey selectElementWithMatcher: grey_allOf(chrome_test_util::ButtonWithAccessibilityLabelId( IDS_IOS_EXPORT_PASSWORDS),
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm index 54c626e..f544a3b 100644 --- a/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm
@@ -600,10 +600,12 @@ } // Export passwords button. - [model addSectionWithIdentifier:SectionIdentifierExportPasswordsButton]; - _exportPasswordsItem = [self exportPasswordsItem]; - [model addItem:_exportPasswordsItem - toSectionWithIdentifier:SectionIdentifierExportPasswordsButton]; + if (ShouldShowSettingsUI()) { + [model addSectionWithIdentifier:SectionIdentifierExportPasswordsButton]; + _exportPasswordsItem = [self exportPasswordsItem]; + [model addItem:_exportPasswordsItem + toSectionWithIdentifier:SectionIdentifierExportPasswordsButton]; + } // Add the descriptive text at the top of the screen. Do this at the end to // ensure the section to which it's being attached already exists. @@ -1729,6 +1731,10 @@ } - (void)setExportPasswordsButtonEnabled:(BOOL)enabled { + // Will be nil when settings content in this UI is disabled. + if (!_exportPasswordsItem) + return; + if (enabled) { DCHECK(_exportReady && !self.editing); _exportPasswordsItem.textColor = [UIColor colorNamed:kBlueColor];
diff --git a/ios/chrome/browser/ui/settings/password/password_settings/BUILD.gn b/ios/chrome/browser/ui/settings/password/password_settings/BUILD.gn index bcd0007d..4d29c035 100644 --- a/ios/chrome/browser/ui/settings/password/password_settings/BUILD.gn +++ b/ios/chrome/browser/ui/settings/password/password_settings/BUILD.gn
@@ -13,6 +13,7 @@ "password_settings_mediator.mm", ] deps = [ + ":common", ":password_settings_constants", ":password_settings_ui", "//components/keyed_service/core", @@ -61,3 +62,15 @@ ] deps = [ "//ios/chrome/browser/ui/list_model" ] } + +source_set("common") { + configs += [ "//build/config/compiler:enable_arc" ] + sources = [ + "scoped_password_settings_reauth_module_override.h", + "scoped_password_settings_reauth_module_override.mm", + ] + deps = [ + "//base", + "//ios/chrome/common/ui/reauthentication", + ] +}
diff --git a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_coordinator.mm index fe19ff4..521eada 100644 --- a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_coordinator.mm
@@ -17,6 +17,7 @@ #import "ios/chrome/browser/ui/settings/password/password_settings/password_settings_coordinator_delegate.h" #import "ios/chrome/browser/ui/settings/password/password_settings/password_settings_mediator.h" #import "ios/chrome/browser/ui/settings/password/password_settings/password_settings_view_controller.h" +#import "ios/chrome/browser/ui/settings/password/password_settings/scoped_password_settings_reauth_module_override.h" #import "ios/chrome/browser/ui/settings/utils/settings_utils.h" #import "ios/chrome/common/ui/reauthentication/reauthentication_module.h" #import "ios/chrome/grit/ios_chromium_strings.h" @@ -109,7 +110,10 @@ #pragma mark - ChromeCoordinator - (void)start { - self.reauthModule = [[ReauthenticationModule alloc] init]; + self.reauthModule = + ScopedPasswordSettingsReauthModuleOverride::instance + ? ScopedPasswordSettingsReauthModuleOverride::instance->module + : [[ReauthenticationModule alloc] init]; _savedPasswordsPresenter = std::make_unique<password_manager::SavedPasswordsPresenter>(
diff --git a/ios/chrome/browser/ui/settings/password/password_settings/scoped_password_settings_reauth_module_override.h b/ios/chrome/browser/ui/settings/password/password_settings/scoped_password_settings_reauth_module_override.h new file mode 100644 index 0000000..0817bdb --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_settings/scoped_password_settings_reauth_module_override.h
@@ -0,0 +1,37 @@ +// 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_SETTINGS_PASSWORD_PASSWORD_SETTINGS_SCOPED_PASSWORD_SETTINGS_REAUTH_MODULE_OVERRIDE_H_ +#define IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_SETTINGS_SCOPED_PASSWORD_SETTINGS_REAUTH_MODULE_OVERRIDE_H_ + +#import "base/memory/raw_ptr.h" + +@protocol ReauthenticationProtocol; + +// Util class enabling a global override of the Reauthentication Module used in +// newly-constructed PasswordSettingsCoordinators, for testing purposes only. +class ScopedPasswordSettingsReauthModuleOverride { + public: + ~ScopedPasswordSettingsReauthModuleOverride(); + + // Creates a scoped override so that the provided fake/mock/disarmed/etc + // reauthentication module will be used in place of the production + // implementation. + // Newly created coordinators will use `module` as their reauthentication + // module until the override is destroyed. Any coordinator created while an + // override is active will hold a strong ref to `module`. + static std::unique_ptr<ScopedPasswordSettingsReauthModuleOverride> + MakeAndArmForTesting(id<ReauthenticationProtocol> module); + + // Singleton instance of this class. + static raw_ptr<ScopedPasswordSettingsReauthModuleOverride> instance; + + // The module to be used. + id<ReauthenticationProtocol> module; + + private: + ScopedPasswordSettingsReauthModuleOverride() = default; +}; + +#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_SETTINGS_SCOPED_PASSWORD_SETTINGS_REAUTH_MODULE_OVERRIDE_H_
diff --git a/ios/chrome/browser/ui/settings/password/password_settings/scoped_password_settings_reauth_module_override.mm b/ios/chrome/browser/ui/settings/password/password_settings/scoped_password_settings_reauth_module_override.mm new file mode 100644 index 0000000..3734cd8 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_settings/scoped_password_settings_reauth_module_override.mm
@@ -0,0 +1,34 @@ +// 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. + +#import "ios/chrome/browser/ui/settings/password/password_settings/scoped_password_settings_reauth_module_override.h" + +#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +// static +raw_ptr<ScopedPasswordSettingsReauthModuleOverride> + ScopedPasswordSettingsReauthModuleOverride::instance; + +// static +std::unique_ptr<ScopedPasswordSettingsReauthModuleOverride> +ScopedPasswordSettingsReauthModuleOverride::MakeAndArmForTesting( + id<ReauthenticationProtocol> module) { + DCHECK(!instance); + // Using new instead of make_unique to access private constructor. + std::unique_ptr<ScopedPasswordSettingsReauthModuleOverride> new_instance( + new ScopedPasswordSettingsReauthModuleOverride); + new_instance->module = module; + instance = new_instance.get(); + return new_instance; +} + +ScopedPasswordSettingsReauthModuleOverride:: + ~ScopedPasswordSettingsReauthModuleOverride() { + DCHECK(instance == this); + instance = nullptr; +}
diff --git a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h index ec7c11b..0fe859568 100644 --- a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h +++ b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h
@@ -22,6 +22,10 @@ (ReauthenticationResult)expectedResult; + (void)mockReauthenticationModuleCanAttempt:(BOOL)canAttempt; +// Similar to the methods above, but with a companion to remove the override. ++ (void)setUpMockReauthenticationModuleForExportFromSettings; ++ (void)removeMockReauthenticationModuleForExportFromSettings; + // Dismisses snack bar. Used before next test. + (void)dismissSnackBar;
diff --git a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm index 32cd5b0..0027f7dd4 100644 --- a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm +++ b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm
@@ -6,6 +6,7 @@ #import <MaterialComponents/MaterialSnackbar.h> +#import "base/mac/foundation_util.h" #import "base/strings/stringprintf.h" #import "base/strings/sys_string_conversions.h" #import "base/strings/utf_string_conversions.h" @@ -27,9 +28,11 @@ #error "This file requires ARC support." #endif -using password_manager::PasswordForm; using chrome_test_util::SetUpAndReturnMockReauthenticationModule; using chrome_test_util::SetUpAndReturnMockReauthenticationModuleForExport; +using chrome_test_util:: + SetUpAndReturnMockReauthenticationModuleForExportFromSettings; +using password_manager::PasswordForm; namespace { @@ -147,6 +150,8 @@ @implementation PasswordSettingsAppInterface static MockReauthenticationModule* _mockReauthenticationModule; +static std::unique_ptr<ScopedPasswordSettingsReauthModuleOverride> + _scopedReauthOverride; + (void)setUpMockReauthenticationModule { _mockReauthenticationModule = SetUpAndReturnMockReauthenticationModule(); @@ -159,13 +164,30 @@ + (void)mockReauthenticationModuleExpectedResult: (ReauthenticationResult)expectedResult { - _mockReauthenticationModule.expectedResult = expectedResult; + if (_mockReauthenticationModule) { + _mockReauthenticationModule.expectedResult = expectedResult; + } + if (_scopedReauthOverride) { + MockReauthenticationModule* mockModule = + base::mac::ObjCCastStrict<MockReauthenticationModule>( + _scopedReauthOverride->module); + mockModule.expectedResult = expectedResult; + } } + (void)mockReauthenticationModuleCanAttempt:(BOOL)canAttempt { _mockReauthenticationModule.canAttempt = canAttempt; } ++ (void)setUpMockReauthenticationModuleForExportFromSettings { + _scopedReauthOverride = + SetUpAndReturnMockReauthenticationModuleForExportFromSettings(); +} + ++ (void)removeMockReauthenticationModuleForExportFromSettings { + _scopedReauthOverride = nullptr; +} + + (void)dismissSnackBar { [MDCSnackbarManager.defaultManager dismissAndCallCompletionBlocksWithCategory:@"PasswordsSnackbarCategory"];
diff --git a/ios/chrome/browser/ui/settings/price_notifications/BUILD.gn b/ios/chrome/browser/ui/settings/price_notifications/BUILD.gn new file mode 100644 index 0000000..723d678 --- /dev/null +++ b/ios/chrome/browser/ui/settings/price_notifications/BUILD.gn
@@ -0,0 +1,43 @@ +# 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. + +source_set("price_notifications") { + configs += [ "//build/config/compiler:enable_arc" ] + sources = [ + "price_notifications_mediator.h", + "price_notifications_mediator.mm", + ] + deps = [ + ":constants", + ":price_notifications_ui", + "//base", + "//ios/chrome/app/strings", + "//ios/chrome/browser/ui/icons:settings_icons", + "//ios/chrome/browser/ui/icons:symbols", + "//ios/chrome/browser/ui/list_model", + "//ios/chrome/browser/ui/settings:settings_root", + "//ios/chrome/browser/ui/table_view:utils", + "//ios/chrome/browser/ui/table_view/cells", + "//ios/chrome/common/ui/colors", + "//ui/base", + ] +} + +source_set("price_notifications_ui") { + configs += [ "//build/config/compiler:enable_arc" ] + sources = [ + "price_notifications_consumer.h", + "price_notifications_navigation_commands.h", + "price_notifications_view_controller_delegate.h", + ] + deps = [ "//ios/chrome/browser/ui/table_view" ] +} + +source_set("constants") { + configs += [ "//build/config/compiler:enable_arc" ] + sources = [ + "price_notifications_constants.h", + "price_notifications_constants.mm", + ] +}
diff --git a/ios/chrome/browser/ui/settings/price_notifications/price_notifications_constants.h b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_constants.h new file mode 100644 index 0000000..3e1c592 --- /dev/null +++ b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_constants.h
@@ -0,0 +1,16 @@ +// 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_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_CONSTANTS_H_ +#define IOS_CHROME_BROWSER_UI_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_CONSTANTS_H_ + +#import <Foundation/Foundation.h> + +// The accessibility identifier of the Price Notifications setting table view. +extern NSString* const kPriceNotificationsTableViewId; + +// The accessibility identifier of the Price Notifications price tracking cell. +extern NSString* const kSettingsPriceNotificationsPriceTrackingCellId; + +#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/settings/price_notifications/price_notifications_constants.mm b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_constants.mm new file mode 100644 index 0000000..d6d6786 --- /dev/null +++ b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_constants.mm
@@ -0,0 +1,15 @@ +// 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. + +#import "ios/chrome/browser/ui/settings/price_notifications/price_notifications_constants.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +NSString* const kPriceNotificationsTableViewId = + @"kPriceNotificationsTableViewId"; + +NSString* const kSettingsPriceNotificationsPriceTrackingCellId = + @"kSettingsPriceNotificationsPriceTrackingCellId";
diff --git a/ios/chrome/browser/ui/settings/price_notifications/price_notifications_consumer.h b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_consumer.h new file mode 100644 index 0000000..f62c5412 --- /dev/null +++ b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_consumer.h
@@ -0,0 +1,22 @@ +// 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_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_CONSUMER_H_ +#define IOS_CHROME_BROWSER_UI_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_CONSUMER_H_ + +#import <UIKit/UIKit.h> + +#import "ios/chrome/browser/ui/table_view/chrome_table_view_consumer.h" + +@class TableViewItem; + +// Consumer protocol for Price Notifications settings. +@protocol PriceNotificationsConsumer <ChromeTableViewConsumer> + +// Initializes price tracking item. +- (void)setPriceTrackingItem:(TableViewItem*)priceTrackingItem; + +@end + +#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/settings/price_notifications/price_notifications_mediator.h b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_mediator.h new file mode 100644 index 0000000..4ea7ce7 --- /dev/null +++ b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_mediator.h
@@ -0,0 +1,27 @@ +// 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_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_MEDIATOR_H_ +#define IOS_CHROME_BROWSER_UI_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_MEDIATOR_H_ + +#import <UIKit/UIKit.h> + +#import "ios/chrome/browser/ui/settings/price_notifications/price_notifications_view_controller_delegate.h" + +@protocol PriceNotificationsConsumer; +@protocol PriceNotificationsNavigationCommands; + +// Mediator for Price Notifications. +@interface PriceNotificationsMediator + : NSObject <PriceNotificationsViewControllerDelegate> + +// View controller. +@property(nonatomic, weak) id<PriceNotificationsConsumer> consumer; + +// Handler used to navigate inside the Price Notifications setting. +@property(nonatomic, weak) id<PriceNotificationsNavigationCommands> handler; + +@end + +#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/settings/price_notifications/price_notifications_mediator.mm b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_mediator.mm new file mode 100644 index 0000000..96fa85b --- /dev/null +++ b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_mediator.mm
@@ -0,0 +1,102 @@ +// 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. + +#import "ios/chrome/browser/ui/settings/price_notifications/price_notifications_mediator.h" + +#import "base/notreached.h" +#import "ios/chrome/browser/ui/icons/chrome_symbol.h" +#import "ios/chrome/browser/ui/icons/settings_icon.h" +#import "ios/chrome/browser/ui/list_model/list_model.h" +#import "ios/chrome/browser/ui/settings/price_notifications/price_notifications_constants.h" +#import "ios/chrome/browser/ui/settings/price_notifications/price_notifications_consumer.h" +#import "ios/chrome/browser/ui/settings/price_notifications/price_notifications_navigation_commands.h" +#import "ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.h" +#import "ios/chrome/common/ui/colors/semantic_color_names.h" +#import "ios/chrome/grit/ios_strings.h" +#import "ui/base/l10n/l10n_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +// List of items. +typedef NS_ENUM(NSInteger, ItemType) { + ItemTypeTrackingPrice = kItemTypeEnumZero, +}; + +@interface PriceNotificationsMediator () + +// All the items for the price notifications section. +@property(nonatomic, strong, readonly) TableViewItem* priceTrackingItem; + +@end + +@implementation PriceNotificationsMediator + +@synthesize priceTrackingItem = _priceTrackingItem; + +#pragma mark - Properties + +- (TableViewItem*)priceTrackingItem { + if (!_priceTrackingItem) { + // TODO(crbug.com/1363175): Replace kReadingListSymbol with proper symbol. + _priceTrackingItem = [self + detailItemWithType:ItemTypeTrackingPrice + text: + l10n_util::GetNSString( + IDS_IOS_PRICE_NOTIFICATIONS_PRICE_TRACKING_TITLE) + detailText:nil + symbol:CustomSettingsRootSymbol(kReadingListSymbol) + symbolBackgroundColor:[UIColor colorNamed:kGrey500Color] + accessibilityIdentifier:kSettingsPriceNotificationsPriceTrackingCellId]; + } + return _priceTrackingItem; +} + +- (void)setConsumer:(id<PriceNotificationsConsumer>)consumer { + if (_consumer == consumer) + return; + _consumer = consumer; + [_consumer setPriceTrackingItem:self.priceTrackingItem]; +} + +#pragma mark - Private methods + +// Creates item with details and icon image. +- (TableViewDetailIconItem*)detailItemWithType:(NSInteger)type + text:(NSString*)text + detailText:(NSString*)detailText + symbol:(UIImage*)symbol + symbolBackgroundColor:(UIColor*)backgroundColor + accessibilityIdentifier: + (NSString*)accessibilityIdentifier { + TableViewDetailIconItem* detailItem = + [[TableViewDetailIconItem alloc] initWithType:type]; + detailItem.text = text; + detailItem.detailText = detailText; + detailItem.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + detailItem.accessibilityTraits |= UIAccessibilityTraitButton; + detailItem.accessibilityIdentifier = accessibilityIdentifier; + detailItem.iconImage = symbol; + detailItem.iconBackgroundColor = backgroundColor; + detailItem.iconTintColor = UIColor.whiteColor; + detailItem.iconCornerRadius = kColorfulBackgroundSymbolCornerRadius; + return detailItem; +} + +#pragma mark - PriceNotificationsViewControllerDelegate + +- (void)didSelectItem:(TableViewItem*)item { + ItemType type = static_cast<ItemType>(item.type); + switch (type) { + case ItemTypeTrackingPrice: + [self.handler showTrackingPrice]; + break; + default: + NOTREACHED(); + break; + } +} + +@end
diff --git a/ios/chrome/browser/ui/settings/price_notifications/price_notifications_navigation_commands.h b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_navigation_commands.h new file mode 100644 index 0000000..1399c08e --- /dev/null +++ b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_navigation_commands.h
@@ -0,0 +1,17 @@ +// 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_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_NAVIGATION_COMMANDS_H_ +#define IOS_CHROME_BROWSER_UI_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_NAVIGATION_COMMANDS_H_ + +// Protocol for navigating to different setting pages from Price Notifications +// setting. +@protocol PriceNotificationsNavigationCommands <NSObject> + +// Shows tracking price screen. +- (void)showTrackingPrice; + +@end + +#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_NAVIGATION_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/settings/price_notifications/price_notifications_view_controller_delegate.h b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_view_controller_delegate.h new file mode 100644 index 0000000..aa5508a --- /dev/null +++ b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_view_controller_delegate.h
@@ -0,0 +1,19 @@ +// 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_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_VIEW_CONTROLLER_DELEGATE_H_ +#define IOS_CHROME_BROWSER_UI_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_VIEW_CONTROLLER_DELEGATE_H_ + +@class TableViewItem; + +// Delegate for PriceNotificationsViewController instance to manage the +// model. +@protocol PriceNotificationsViewControllerDelegate <NSObject> + +// Sends `item` to the model to handle logic and navigation. +- (void)didSelectItem:(TableViewItem*)item; + +@end + +#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_VIEW_CONTROLLER_DELEGATE_H_
diff --git a/ios/chrome/test/app/BUILD.gn b/ios/chrome/test/app/BUILD.gn index 4f6fdd05..f4cbbba 100644 --- a/ios/chrome/test/app/BUILD.gn +++ b/ios/chrome/test/app/BUILD.gn
@@ -84,6 +84,7 @@ "//ios/chrome/browser/ui/settings/password:password_ui", "//ios/chrome/browser/ui/settings/password:test_support", "//ios/chrome/browser/ui/settings/password/password_details:password_details_ui", + "//ios/chrome/browser/ui/settings/password/password_settings:common", "//ios/chrome/browser/ui/tab_switcher/tab_grid", "//ios/chrome/browser/ui/tabs", "//ios/chrome/browser/ui/util",
diff --git a/ios/chrome/test/app/password_test_util.h b/ios/chrome/test/app/password_test_util.h index 1589ed8..2fdbbb5 100644 --- a/ios/chrome/test/app/password_test_util.h +++ b/ios/chrome/test/app/password_test_util.h
@@ -5,8 +5,12 @@ #ifndef IOS_CHROME_TEST_APP_PASSWORD_TEST_UTIL_H_ #define IOS_CHROME_TEST_APP_PASSWORD_TEST_UTIL_H_ +#import <memory> + #import "ios/chrome/common/ui/reauthentication/reauthentication_module.h" +#import "ios/chrome/browser/ui/settings/password/password_settings/scoped_password_settings_reauth_module_override.h" + @interface MockReauthenticationModule : NSObject<ReauthenticationProtocol> // Localized string containing the reason why reauthentication is requested. @@ -28,11 +32,17 @@ // blocked with a reauth prompt, and return the fake reauthentication module. MockReauthenticationModule* SetUpAndReturnMockReauthenticationModule(); -// Replace the reauthentication module in +// Replace the reauthentication module in Password Manager's // PasswordExporter with a fake one to avoid being // blocked with a reauth prompt, and return the fake reauthentication module. MockReauthenticationModule* SetUpAndReturnMockReauthenticationModuleForExport(); +// Replace the reauthentication module in Password Settings' +// PasswordExporter with a fake one to avoid being +// blocked with a reauth prompt, and return the fake reauthentication module. +std::unique_ptr<ScopedPasswordSettingsReauthModuleOverride> +SetUpAndReturnMockReauthenticationModuleForExportFromSettings(); + } // namespace chrome_test_util #endif // IOS_CHROME_TEST_APP_PASSWORD_TEST_UTIL_H_
diff --git a/ios/chrome/test/app/password_test_util.mm b/ios/chrome/test/app/password_test_util.mm index 20b48cc..d9361cd 100644 --- a/ios/chrome/test/app/password_test_util.mm +++ b/ios/chrome/test/app/password_test_util.mm
@@ -61,7 +61,7 @@ return mock_reauthentication_module; } -// Replace the reauthentication module in +// Replace the reauthentication module in Password Manager's // PasswordExporter with a fake one to avoid being // blocked with a reauth prompt, and return the fake reauthentication module. MockReauthenticationModule* @@ -80,4 +80,15 @@ return mock_reauthentication_module; } +// Replace the reauthentication module in Password Settings' +// PasswordExporter with a fake one to avoid being +// blocked with a reauth prompt, and return the fake reauthentication module. +std::unique_ptr<ScopedPasswordSettingsReauthModuleOverride> +SetUpAndReturnMockReauthenticationModuleForExportFromSettings() { + MockReauthenticationModule* mock_reauthentication_module = + [[MockReauthenticationModule alloc] init]; + return ScopedPasswordSettingsReauthModuleOverride::MakeAndArmForTesting( + mock_reauthentication_module); +} + } // namespace
diff --git a/ios/web_view/internal/cwv_web_view.mm b/ios/web_view/internal/cwv_web_view.mm index c5f26b1..edc0ab1 100644 --- a/ios/web_view/internal/cwv_web_view.mm +++ b/ios/web_view/internal/cwv_web_view.mm
@@ -758,7 +758,7 @@ PasswordFormHelper* formHelper = [[PasswordFormHelper alloc] initWithWebState:_webState.get()]; PasswordSuggestionHelper* suggestionHelper = - [[PasswordSuggestionHelper alloc] init]; + [[PasswordSuggestionHelper alloc] initWithWebState:_webState.get()]; PasswordControllerDriverHelper* driverHelper = [[PasswordControllerDriverHelper alloc] initWithWebState:_webState.get()]; SharedPasswordController* passwordController =
diff --git a/media/gpu/v4l2/v4l2_video_decoder_delegate_av1.cc b/media/gpu/v4l2/v4l2_video_decoder_delegate_av1.cc index 4970daa..e531d4a 100644 --- a/media/gpu/v4l2/v4l2_video_decoder_delegate_av1.cc +++ b/media/gpu/v4l2/v4l2_video_decoder_delegate_av1.cc
@@ -115,6 +115,63 @@ v4l2_seq_params.max_frame_height_minus_1 = seq_header.max_frame_height - 1; } +// Section 5.9.11. Loop filter params syntax. +// Note that |update_ref_delta| and |update_mode_delta| flags in the spec +// are not needed for V4L2 AV1 API. +void FillLoopFilterParams(v4l2_av1_loop_filter& v4l2_lf, + const libgav1::LoopFilter& lf) { + if (lf.delta_enabled) + v4l2_lf.flags |= V4L2_AV1_LOOP_FILTER_FLAG_DELTA_ENABLED; + + if (lf.delta_update) + v4l2_lf.flags |= V4L2_AV1_LOOP_FILTER_FLAG_DELTA_UPDATE; + + static_assert(std::size(decltype(v4l2_lf.level){}) == libgav1::kFrameLfCount, + "Invalid size of loop filter level (strength) array"); + for (size_t i = 0; i < libgav1::kFrameLfCount; i++) + v4l2_lf.level[i] = base::checked_cast<__u8>(lf.level[i]); + + v4l2_lf.sharpness = lf.sharpness; + + static_assert(std::size(decltype(v4l2_lf.ref_deltas){}) == + libgav1::kNumReferenceFrameTypes, + "Invalid size of ref deltas array"); + for (size_t i = 0; i < libgav1::kNumReferenceFrameTypes; i++) + v4l2_lf.ref_deltas[i] = lf.ref_deltas[i]; + + static_assert(std::size(decltype(v4l2_lf.mode_deltas){}) == + libgav1::kLoopFilterMaxModeDeltas, + "Invalid size of mode deltas array"); + for (size_t i = 0; i < libgav1::kLoopFilterMaxModeDeltas; i++) + v4l2_lf.mode_deltas[i] = lf.mode_deltas[i]; +} + +// Section 5.9.12. Quantization params syntax +void FillQuantizationParams(v4l2_av1_quantization& v4l2_quant, + const libgav1::QuantizerParameters& quant) { + if (quant.use_matrix) + v4l2_quant.flags |= V4L2_AV1_QUANTIZATION_FLAG_USING_QMATRIX; + + v4l2_quant.base_q_idx = quant.base_index; + + // Note that quant.delta_ac[0] is useless + // because it is always 0 according to libgav1. + v4l2_quant.delta_q_y_dc = quant.delta_dc[0]; + + v4l2_quant.delta_q_u_dc = quant.delta_dc[1]; + v4l2_quant.delta_q_u_ac = quant.delta_ac[1]; + + v4l2_quant.delta_q_v_dc = quant.delta_dc[2]; + v4l2_quant.delta_q_v_ac = quant.delta_ac[2]; + + if (!quant.use_matrix) + return; + + v4l2_quant.qm_y = base::checked_cast<uint8_t>(quant.matrix_level[0]); + v4l2_quant.qm_u = base::checked_cast<uint8_t>(quant.matrix_level[1]); + v4l2_quant.qm_v = base::checked_cast<uint8_t>(quant.matrix_level[2]); +} + } // namespace V4L2VideoDecoderDelegateAV1::V4L2VideoDecoderDelegateAV1( @@ -145,9 +202,16 @@ const libgav1::Vector<libgav1::TileBuffer>& tile_buffers, base::span<const uint8_t> data) { struct v4l2_ctrl_av1_sequence v4l2_seq_params = {}; - FillSequenceParams(v4l2_seq_params, sequence_header); + const libgav1::ObuFrameHeader& frame_header = pic.frame_header; + + struct v4l2_av1_loop_filter v4l2_lf = {}; + FillLoopFilterParams(v4l2_lf, frame_header.loop_filter); + + struct v4l2_av1_quantization v4l2_quant = {}; + FillQuantizationParams(v4l2_quant, frame_header.quantizer); + NOTIMPLEMENTED(); return DecodeStatus::kFail;
diff --git a/net/cookies/cookie_access_delegate.cc b/net/cookies/cookie_access_delegate.cc index fb71fb7c..63d8675 100644 --- a/net/cookies/cookie_access_delegate.cc +++ b/net/cookies/cookie_access_delegate.cc
@@ -48,7 +48,7 @@ } absl::optional<base::flat_map<net::SchemefulSite, FirstPartySetEntry>> - maybe_entries = delegate->FindFirstPartySetOwners( + maybe_entries = delegate->FindFirstPartySetEntries( {cookie_partition_key.site()}, base::BindOnce(&CreateCookiePartitionKeyFromFirstPartySetEntry, cookie_partition_key)
diff --git a/net/cookies/cookie_access_delegate.h b/net/cookies/cookie_access_delegate.h index 5f0136e..9d9c6b3 100644 --- a/net/cookies/cookie_access_delegate.h +++ b/net/cookies/cookie_access_delegate.h
@@ -78,7 +78,7 @@ // not both, and not neither. [[nodiscard]] virtual absl::optional< base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>> - FindFirstPartySetOwners( + FindFirstPartySetEntries( const base::flat_set<net::SchemefulSite>& sites, base::OnceCallback< void(base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>)>
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc index f568449..7af2eb3 100644 --- a/net/cookies/cookie_monster.cc +++ b/net/cookies/cookie_monster.cc
@@ -2263,7 +2263,7 @@ } } absl::optional<base::flat_map<SchemefulSite, FirstPartySetEntry>> - maybe_sets = cookie_access_delegate()->FindFirstPartySetOwners( + maybe_sets = cookie_access_delegate()->FindFirstPartySetEntries( sites, base::BindOnce(&CookieMonster::RecordPeriodicFirstPartySetsStats, weak_ptr_factory_.GetWeakPtr()));
diff --git a/net/cookies/cookie_partition_key_collection.cc b/net/cookies/cookie_partition_key_collection.cc index c01f7c5..59a7454 100644 --- a/net/cookies/cookie_partition_key_collection.cc +++ b/net/cookies/cookie_partition_key_collection.cc
@@ -82,7 +82,7 @@ if (sites.empty()) return *this; absl::optional<base::flat_map<SchemefulSite, FirstPartySetEntry>> - maybe_sites_to_entries = cookie_access_delegate->FindFirstPartySetOwners( + maybe_sites_to_entries = cookie_access_delegate->FindFirstPartySetEntries( sites, base::BindOnce(&TransformWithFirstPartySetEntries, PartitionKeys()) .Then(std::move(callback)));
diff --git a/net/cookies/test_cookie_access_delegate.cc b/net/cookies/test_cookie_access_delegate.cc index 3df3415..b9f0e57 100644 --- a/net/cookies/test_cookie_access_delegate.cc +++ b/net/cookies/test_cookie_access_delegate.cc
@@ -56,18 +56,16 @@ const std::set<SchemefulSite>& party_context, base::OnceCallback<void(FirstPartySetMetadata)> callback) const { absl::optional<FirstPartySetEntry> top_frame_owner = - top_frame_site ? FindFirstPartySetOwnerSync(*top_frame_site) - : absl::nullopt; + top_frame_site ? FindFirstPartySetEntry(*top_frame_site) : absl::nullopt; return RunMaybeAsync( - FirstPartySetMetadata( - SamePartyContext(), - base::OptionalToPtr(FindFirstPartySetOwnerSync(site)), - base::OptionalToPtr(top_frame_owner)), + FirstPartySetMetadata(SamePartyContext(), + base::OptionalToPtr(FindFirstPartySetEntry(site)), + base::OptionalToPtr(top_frame_owner)), std::move(callback)); } absl::optional<FirstPartySetEntry> -TestCookieAccessDelegate::FindFirstPartySetOwnerSync( +TestCookieAccessDelegate::FindFirstPartySetEntry( const SchemefulSite& site) const { auto entry = first_party_sets_.find(site); @@ -76,13 +74,13 @@ } absl::optional<base::flat_map<SchemefulSite, FirstPartySetEntry>> -TestCookieAccessDelegate::FindFirstPartySetOwners( +TestCookieAccessDelegate::FindFirstPartySetEntries( const base::flat_set<SchemefulSite>& sites, base::OnceCallback<void(base::flat_map<SchemefulSite, FirstPartySetEntry>)> callback) const { std::vector<std::pair<SchemefulSite, FirstPartySetEntry>> mapping; for (const SchemefulSite& site : sites) { - absl::optional<FirstPartySetEntry> entry = FindFirstPartySetOwnerSync(site); + absl::optional<FirstPartySetEntry> entry = FindFirstPartySetEntry(site); if (entry) mapping.emplace_back(site, *entry); }
diff --git a/net/cookies/test_cookie_access_delegate.h b/net/cookies/test_cookie_access_delegate.h index 0124675..1618a7b 100644 --- a/net/cookies/test_cookie_access_delegate.h +++ b/net/cookies/test_cookie_access_delegate.h
@@ -47,7 +47,7 @@ const std::set<SchemefulSite>& party_context, base::OnceCallback<void(FirstPartySetMetadata)> callback) const override; absl::optional<base::flat_map<SchemefulSite, FirstPartySetEntry>> - FindFirstPartySetOwners( + FindFirstPartySetEntries( const base::flat_set<SchemefulSite>& sites, base::OnceCallback< void(base::flat_map<SchemefulSite, FirstPartySetEntry>)> callback) @@ -67,7 +67,7 @@ bool require_secure_origin); // Set the test delegate's First-Party Sets. The map's keys are the sites in - // the sets. Owner sites must be included among the keys for a given set. + // the sets. Primary sites must be included among the keys for a given set. void SetFirstPartySets( const base::flat_map<SchemefulSite, FirstPartySetEntry>& sets); @@ -76,8 +76,8 @@ } private: - // Synchronous version of FindFirstPartySetOwner, for convenience. - absl::optional<FirstPartySetEntry> FindFirstPartySetOwnerSync( + // Finds a FirstPartySetEntry for the given site, if one exists. + absl::optional<FirstPartySetEntry> FindFirstPartySetEntry( const SchemefulSite& site) const; // Discard any leading dot in the domain string.
diff --git a/net/first_party_sets/public_sets.cc b/net/first_party_sets/public_sets.cc index 4ebc688..183be81 100644 --- a/net/first_party_sets/public_sets.cc +++ b/net/first_party_sets/public_sets.cc
@@ -6,6 +6,8 @@ #include <tuple> +#include "base/containers/contains.h" +#include "base/containers/flat_set.h" #include "net/base/schemeful_site.h" #include "net/first_party_sets/first_party_set_entry.h" #include "net/first_party_sets/first_party_sets_context_config.h" @@ -74,6 +76,80 @@ return absl::nullopt; } +base::flat_set<net::SchemefulSite> PublicSets::FindIntersection( + const SchemefulSite& manual_primary, + const base::flat_map<SchemefulSite, FirstPartySetEntry>& manual_entries) + const { + std::vector<net::SchemefulSite> intersection; + for (const std::pair<net::SchemefulSite, net::FirstPartySetEntry>& + public_site_and_entry : entries_) { + const net::SchemefulSite& public_site = public_site_and_entry.first; + const net::SchemefulSite& public_primary = + public_site_and_entry.second.primary(); + bool is_affected_by_local_set = + public_site == manual_primary || public_primary == manual_primary || + base::ranges::any_of( + manual_entries, + [&](const std::pair<net::SchemefulSite, net::FirstPartySetEntry>& + manual_site_and_entry) { + const net::SchemefulSite& manual_site = + manual_site_and_entry.first; + return manual_site == public_site || + manual_site == public_primary; + }); + if (is_affected_by_local_set) { + intersection.push_back(public_site_and_entry.first); + } + }; + + return intersection; +} + +base::flat_set<net::SchemefulSite> PublicSets::FindSingletons() const { + std::vector<net::SchemefulSite> primaries_with_members; + for (const auto& [site, entry] : entries_) { + if (site != entry.primary()) + primaries_with_members.push_back(entry.primary()); + } + std::vector<net::SchemefulSite> singletons; + for (const auto& [site, entry] : entries_) { + if (site == entry.primary() && + !base::Contains(primaries_with_members, site)) { + singletons.push_back(site); + } + } + + return singletons; +} + +void PublicSets::ApplyManuallySpecifiedSet( + const SchemefulSite& manual_primary, + const base::flat_map<SchemefulSite, FirstPartySetEntry>& manual_entries, + const base::flat_map<SchemefulSite, SchemefulSite>& manual_aliases) { + base::flat_set<net::SchemefulSite> intersection = + FindIntersection(manual_primary, manual_entries); + for (const auto& site : intersection) { + entries_.erase(site); + } + + base::flat_set<net::SchemefulSite> singletons = FindSingletons(); + for (const auto& singleton : singletons) { + entries_.erase(singleton); + } + + base::ranges::copy(manual_entries, std::inserter(entries_, entries_.end())); + + // Finally, remove any aliases for public sites that were affected (deleted), + // and add any aliases defined in the local set. + base::EraseIf( + aliases_, + [&](const std::pair<net::SchemefulSite, net::SchemefulSite>& alias) { + return intersection.contains(alias.second) || + singletons.contains(alias.second); + }); + aliases_.insert(manual_aliases.begin(), manual_aliases.end()); +} + std::ostream& operator<<(std::ostream& os, const PublicSets& ps) { os << "{entries = {"; for (const auto& [site, entry] : ps.entries()) {
diff --git a/net/first_party_sets/public_sets.h b/net/first_party_sets/public_sets.h index 27e18e3..c90d4f0 100644 --- a/net/first_party_sets/public_sets.h +++ b/net/first_party_sets/public_sets.h
@@ -6,6 +6,7 @@ #define NET_FIRST_PARTY_SETS_PUBLIC_SETS_H_ #include "base/containers/flat_map.h" +#include "base/containers/flat_set.h" #include "net/base/net_export.h" #include "net/base/schemeful_site.h" #include "net/first_party_sets/first_party_set_entry.h" @@ -50,7 +51,28 @@ const SchemefulSite& site, const FirstPartySetsContextConfig* config) const; + // Modifies this instance such that it will respect the given + // manually-specified set. + void ApplyManuallySpecifiedSet( + const SchemefulSite& manual_primary, + const base::flat_map<SchemefulSite, FirstPartySetEntry>& manual_entries, + const base::flat_map<SchemefulSite, SchemefulSite>& manual_aliases); + private: + // Finds the intersection between the underlying entries and the given + // manually-specified set. + // + // The returned collection also includes any sites in the underlying entries + // whose primary was in the intersection. + base::flat_set<net::SchemefulSite> FindIntersection( + const SchemefulSite& manual_primary, + const base::flat_map<SchemefulSite, FirstPartySetEntry>& manual_entries) + const; + + // Finds singleton sets in the underlying entries, which are sets that consist + // of only a single site. + base::flat_set<net::SchemefulSite> FindSingletons() const; + // Represents the mapping of site -> entry, where keys are sites within sets, // and values are entries of the sets. base::flat_map<SchemefulSite, FirstPartySetEntry> entries_;
diff --git a/net/first_party_sets/public_sets_unittest.cc b/net/first_party_sets/public_sets_unittest.cc index 0ea5ab04..ebd17fa 100644 --- a/net/first_party_sets/public_sets_unittest.cc +++ b/net/first_party_sets/public_sets_unittest.cc
@@ -17,16 +17,46 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" +using ::testing::IsEmpty; using ::testing::Optional; +using ::testing::Pair; +using ::testing::UnorderedElementsAre; namespace net { +const SchemefulSite kPrimary(GURL("https://primary.test")); +const SchemefulSite kPrimary2(GURL("https://primary2.test")); +const SchemefulSite kPrimary3(GURL("https://primary3.test")); +const SchemefulSite kAssociated1(GURL("https://associated1.test")); +const SchemefulSite kAssociated1Cctld(GURL("https://associated1.cctld")); +const SchemefulSite kAssociated1Cctld2(GURL("https://associated1.cctld2")); +const SchemefulSite kAssociated2(GURL("https://associated2.test")); +const SchemefulSite kAssociated3(GURL("https://associated3.test")); +const SchemefulSite kAssociated4(GURL("https://associated4.test")); +const SchemefulSite kService(GURL("https://service.test")); + class PublicSetsTest : public ::testing::Test { public: PublicSetsTest() = default; FirstPartySetsContextConfig* config() { return &fps_context_config_; } + // A helper to repeatedly call `PublicSets::FindEntry` and accumulate the + // non-nullopt results. + base::flat_map<SchemefulSite, FirstPartySetEntry> FindEntries( + const PublicSets& public_sets, + const base::flat_set<SchemefulSite>& sites) { + std::vector<std::pair<SchemefulSite, FirstPartySetEntry>> results; + for (const SchemefulSite& site : sites) { + if (absl::optional<FirstPartySetEntry> entry = + public_sets.FindEntry(site, config()); + entry.has_value()) { + results.emplace_back(site, *entry); + } + } + return results; + } + private: FirstPartySetsContextConfig fps_context_config_; }; @@ -164,4 +194,220 @@ public_entry); } +class PopulatedPublicSetsTest : public PublicSetsTest { + public: + PopulatedPublicSetsTest() + : public_sets_( + { + {kPrimary, FirstPartySetEntry(kPrimary, + SiteType::kPrimary, + absl::nullopt)}, + {kAssociated1, + FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + {kAssociated2, + FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)}, + {kService, FirstPartySetEntry(kPrimary, + SiteType::kService, + absl::nullopt)}, + {kPrimary2, FirstPartySetEntry(kPrimary2, + SiteType::kPrimary, + absl::nullopt)}, + {kAssociated3, + FirstPartySetEntry(kPrimary2, SiteType::kAssociated, 0)}, + }, + { + {kAssociated1Cctld, kAssociated1}, + }) {} + + base::flat_map<SchemefulSite, FirstPartySetEntry> FindEntries( + const base::flat_set<SchemefulSite>& sites) { + return PublicSetsTest::FindEntries(public_sets(), sites); + } + + PublicSets& public_sets() { return public_sets_; } + + private: + PublicSets public_sets_; +}; + +TEST_F(PopulatedPublicSetsTest, + ApplyManuallySpecifiedSet_DeduplicatesPrimaryPrimary) { + // kPrimary overlaps as primary of both sets, so the existing set should be + // wiped out. + public_sets().ApplyManuallySpecifiedSet( + kPrimary, + { + {kPrimary, + FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)}, + {kAssociated4, + FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + }, + {}); + + EXPECT_THAT( + FindEntries({ + kPrimary, + kAssociated1, + kAssociated2, + kAssociated4, + kService, + kAssociated1Cctld, + }), + UnorderedElementsAre( + Pair(kPrimary, + FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)), + Pair(kAssociated4, + FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)))); +} + +TEST_F(PopulatedPublicSetsTest, + ApplyManuallySpecifiedSet_DeduplicatesPrimaryNonprimary) { + // kPrimary overlaps as a primary of the public set and non-primary of the CLI + // set, so the existing set should be wiped out. + public_sets().ApplyManuallySpecifiedSet( + kPrimary3, + { + {kPrimary3, + FirstPartySetEntry(kPrimary3, SiteType::kPrimary, absl::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)}, + }, + {}); + + EXPECT_THAT( + FindEntries({ + kPrimary, + kAssociated1, + kAssociated2, + kAssociated4, + kService, + kPrimary3, + kAssociated1Cctld, + }), + UnorderedElementsAre( + Pair(kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary, + absl::nullopt)), + Pair(kPrimary, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)))); +} + +TEST_F(PopulatedPublicSetsTest, + ApplyManuallySpecifiedSet_DeduplicatesNonprimaryPrimary) { + // kAssociated1 overlaps as a non-primary of the public set and primary of the + // CLI set, so the CLI set should steal it and wipe out its alias, but + // otherwise leave the set intact. + public_sets().ApplyManuallySpecifiedSet( + kAssociated1, + { + {kAssociated1, + FirstPartySetEntry(kAssociated1, SiteType::kPrimary, absl::nullopt)}, + {kAssociated4, + FirstPartySetEntry(kAssociated1, SiteType::kAssociated, 0)}, + }, + {}); + + EXPECT_THAT( + FindEntries({ + kPrimary, + kAssociated1, + kAssociated2, + kAssociated4, + kService, + kPrimary3, + kAssociated1Cctld, + }), + UnorderedElementsAre( + Pair(kPrimary, + FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)), + Pair(kAssociated2, + FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)), + Pair(kService, + FirstPartySetEntry(kPrimary, SiteType::kService, absl::nullopt)), + Pair(kAssociated1, + FirstPartySetEntry(kAssociated1, SiteType::kPrimary, + absl::nullopt)), + Pair(kAssociated4, + FirstPartySetEntry(kAssociated1, SiteType::kAssociated, 0)))); +} + +TEST_F(PopulatedPublicSetsTest, + ApplyManuallySpecifiedSet_DeduplicatesNonprimaryNonprimary) { + // kAssociated1 overlaps as a non-primary of the public set and non-primary of + // the CLI set, so the CLI set should steal it and wipe out its alias. + public_sets().ApplyManuallySpecifiedSet( + kPrimary3, + { + {kPrimary3, + FirstPartySetEntry(kPrimary3, SiteType::kPrimary, absl::nullopt)}, + {kAssociated1, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)}, + }, + {}); + + EXPECT_THAT( + FindEntries({ + kPrimary, + kAssociated1, + kAssociated2, + kAssociated4, + kService, + kPrimary3, + kAssociated1Cctld, + }), + UnorderedElementsAre( + Pair(kPrimary, + FirstPartySetEntry(kPrimary, SiteType::kPrimary, absl::nullopt)), + Pair(kAssociated2, + FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)), + Pair(kService, + FirstPartySetEntry(kPrimary, SiteType::kService, absl::nullopt)), + Pair(kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary, + absl::nullopt)), + Pair(kAssociated1, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)))); +} + +TEST_F(PopulatedPublicSetsTest, + ApplyManuallySpecifiedSet_PrunesInducedSingletons) { + // Steal kAssociated3, so that kPrimary2 becomes a singleton, and verify that + // kPrimary2 is no longer considered in a set. + public_sets().ApplyManuallySpecifiedSet( + kPrimary3, + { + {kPrimary3, + FirstPartySetEntry(kPrimary3, SiteType::kPrimary, absl::nullopt)}, + {kAssociated3, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)}, + }, + {}); + + EXPECT_THAT(FindEntries({kPrimary2}), IsEmpty()); +} + +TEST_F(PopulatedPublicSetsTest, ApplyManuallySpecifiedSet_RespectsManualAlias) { + // Both the public sets and the locally-defined set define an alias for + // kAssociated1, but both define a different set for that site too. Only the + // locally-defined alias should be observable. + public_sets().ApplyManuallySpecifiedSet( + kPrimary3, + { + {kPrimary3, + FirstPartySetEntry(kPrimary3, SiteType::kPrimary, absl::nullopt)}, + {kAssociated1, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)}, + }, + {{kAssociated1Cctld2, kAssociated1}}); + + EXPECT_THAT( + FindEntries({ + kAssociated1, + kAssociated1Cctld, + kAssociated1Cctld2, + }), + UnorderedElementsAre( + Pair(kAssociated1, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)), + Pair(kAssociated1Cctld2, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)))); +} + } // namespace net
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins index dbd5baa..6bffb00 100644 --- a/net/http/transport_security_state_static.pins +++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@ # hash function for preloaded entries again (we have already done so once). # -# Last updated: 2022-09-13 12:55 UTC +# Last updated: 2022-09-14 12:54 UTC PinsListTimestamp -1663073750 +1663160092 TestSPKI sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/remoting/host/linux/input_injector_wayland.cc b/remoting/host/linux/input_injector_wayland.cc index b2d228ea..400ebfef 100644 --- a/remoting/host/linux/input_injector_wayland.cc +++ b/remoting/host/linux/input_injector_wayland.cc
@@ -425,7 +425,7 @@ latest_tick_y_direction_ = WheelDeltaToScrollDirection(ticks_y); latest_tick_y_event_ = now; InjectMouseScroll(RemoteDesktopPortalInjector::ScrollType::VERTICAL_SCROLL, - ticks_y); + -ticks_y); } int ticks_x = 0; @@ -438,7 +438,7 @@ } if (ticks_x != 0) { InjectMouseScroll( - RemoteDesktopPortalInjector::ScrollType::HORIZONTAL_SCROLL, ticks_x); + RemoteDesktopPortalInjector::ScrollType::HORIZONTAL_SCROLL, -ticks_x); } }
diff --git a/services/network/cookie_access_delegate_impl.cc b/services/network/cookie_access_delegate_impl.cc index b082fa4c..bdbc96c8 100644 --- a/services/network/cookie_access_delegate_impl.cc +++ b/services/network/cookie_access_delegate_impl.cc
@@ -72,15 +72,15 @@ site, top_frame_site, party_context, std::move(callback)); } -absl::optional<FirstPartySetsAccessDelegate::OwnersResult> -CookieAccessDelegateImpl::FindFirstPartySetOwners( +absl::optional<FirstPartySetsAccessDelegate::EntriesResult> +CookieAccessDelegateImpl::FindFirstPartySetEntries( const base::flat_set<net::SchemefulSite>& sites, - base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnersResult)> + base::OnceCallback<void(FirstPartySetsAccessDelegate::EntriesResult)> callback) const { if (!first_party_sets_access_delegate_) return {{}}; - return first_party_sets_access_delegate_->FindOwners(sites, - std::move(callback)); + return first_party_sets_access_delegate_->FindEntries(sites, + std::move(callback)); } } // namespace network
diff --git a/services/network/cookie_access_delegate_impl.h b/services/network/cookie_access_delegate_impl.h index b59061e3..fd59cb9 100644 --- a/services/network/cookie_access_delegate_impl.h +++ b/services/network/cookie_access_delegate_impl.h
@@ -62,10 +62,10 @@ const std::set<net::SchemefulSite>& party_context, base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const override; - [[nodiscard]] absl::optional<FirstPartySetsAccessDelegate::OwnersResult> - FindFirstPartySetOwners( + [[nodiscard]] absl::optional<FirstPartySetsAccessDelegate::EntriesResult> + FindFirstPartySetEntries( const base::flat_set<net::SchemefulSite>& sites, - base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnersResult)> + base::OnceCallback<void(FirstPartySetsAccessDelegate::EntriesResult)> callback) const override; private:
diff --git a/services/network/cookie_access_delegate_impl_unittest.cc b/services/network/cookie_access_delegate_impl_unittest.cc index 0dfb2e6..6e480fb4 100644 --- a/services/network/cookie_access_delegate_impl_unittest.cc +++ b/services/network/cookie_access_delegate_impl_unittest.cc
@@ -53,9 +53,9 @@ Optional(std::ref(expected_metadata))); EXPECT_THAT( - delegate().FindFirstPartySetOwners( + delegate().FindFirstPartySetEntries( {site}, - base::BindOnce([](FirstPartySetsManager::OwnersResult) { FAIL(); })), + base::BindOnce([](FirstPartySetsManager::EntriesResult) { FAIL(); })), Optional(IsEmpty())); }
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate.cc b/services/network/first_party_sets/first_party_sets_access_delegate.cc index 1642c3c4..26d8056 100644 --- a/services/network/first_party_sets/first_party_sets_access_delegate.cc +++ b/services/network/first_party_sets/first_party_sets_access_delegate.cc
@@ -71,10 +71,10 @@ context_config_, std::move(callback)); } -absl::optional<FirstPartySetsAccessDelegate::OwnersResult> -FirstPartySetsAccessDelegate::FindOwners( +absl::optional<FirstPartySetsAccessDelegate::EntriesResult> +FirstPartySetsAccessDelegate::FindEntries( const base::flat_set<net::SchemefulSite>& sites, - base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnersResult)> + base::OnceCallback<void(FirstPartySetsAccessDelegate::EntriesResult)> callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -86,12 +86,12 @@ // `pending_queries_` will not run the enqueued callbacks after `this` is // destroyed. EnqueuePendingQuery( - base::BindOnce(&FirstPartySetsAccessDelegate::FindOwnersAndInvoke, + base::BindOnce(&FirstPartySetsAccessDelegate::FindEntriesAndInvoke, base::Unretained(this), sites, std::move(callback))); return absl::nullopt; } - return manager_->FindOwners(sites, context_config_, std::move(callback)); + return manager_->FindEntries(sites, context_config_, std::move(callback)); } void FirstPartySetsAccessDelegate::ComputeMetadataAndInvoke( @@ -115,20 +115,20 @@ std::move(callbacks.second).Run(std::move(sync_result.value())); } -void FirstPartySetsAccessDelegate::FindOwnersAndInvoke( +void FirstPartySetsAccessDelegate::FindEntriesAndInvoke( const base::flat_set<net::SchemefulSite>& sites, - base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnersResult)> + base::OnceCallback<void(FirstPartySetsAccessDelegate::EntriesResult)> callback) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(enabled_); std::pair< - base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnersResult)>, - base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnersResult)>> + base::OnceCallback<void(FirstPartySetsAccessDelegate::EntriesResult)>, + base::OnceCallback<void(FirstPartySetsAccessDelegate::EntriesResult)>> callbacks = base::SplitOnceCallback(std::move(callback)); - absl::optional<FirstPartySetsAccessDelegate::OwnersResult> sync_result = - manager_->FindOwners(sites, context_config_, std::move(callbacks.first)); + absl::optional<FirstPartySetsAccessDelegate::EntriesResult> sync_result = + manager_->FindEntries(sites, context_config_, std::move(callbacks.first)); if (sync_result.has_value()) std::move(callbacks.second).Run(sync_result.value());
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate.h b/services/network/first_party_sets/first_party_sets_access_delegate.h index c5e6710..6f3d921 100644 --- a/services/network/first_party_sets/first_party_sets_access_delegate.h +++ b/services/network/first_party_sets/first_party_sets_access_delegate.h
@@ -31,7 +31,7 @@ class FirstPartySetsAccessDelegate : public mojom::FirstPartySetsAccessDelegate { public: - using OwnersResult = FirstPartySetsManager::OwnersResult; + using EntriesResult = FirstPartySetsManager::EntriesResult; using FlattenedSets = FirstPartySetsManager::FlattenedSets; // Construct a FirstPartySetsAccessDelegate that provides customizations @@ -68,21 +68,16 @@ const std::set<net::SchemefulSite>& party_context, base::OnceCallback<void(net::FirstPartySetMetadata)> callback); - // Batched version of `FindOwner`. Returns the mapping of sites to owners for - // the given input sites (if an owner exists). - // - // When FPS is disabled, returns an empty map. - // When FPS is enabled, this maps each input site to its owner (if one - // exists), and returns the resulting mapping. If a site isn't in a - // non-trivial First-Party Set, it is not added to the output map. + // Calls FirstPartySetsManager::FindEntries either asynchronously or + // synchronously, once initialization is complete. // // This may return a result synchronously, or asynchronously invoke `callback` // with the result. The callback will be invoked iff the return value is // nullopt; i.e. a result will be provided via return value or callback, but // not both, and not neither. - [[nodiscard]] absl::optional<OwnersResult> FindOwners( + [[nodiscard]] absl::optional<EntriesResult> FindEntries( const base::flat_set<net::SchemefulSite>& sites, - base::OnceCallback<void(OwnersResult)> callback); + base::OnceCallback<void(EntriesResult)> callback); private: // Same as `ComputeMetadata`, but plumbs the result into the callback. Must @@ -93,11 +88,11 @@ const std::set<net::SchemefulSite>& party_context, base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const; - // Same as `FindOwners`, but plumbs the result into the callback. Must only be - // called once the instance is fully initialized. - void FindOwnersAndInvoke( + // Same as `FindEntries`, but plumbs the result into the callback. Must only + // be called once the instance is fully initialized. + void FindEntriesAndInvoke( const base::flat_set<net::SchemefulSite>& sites, - base::OnceCallback<void(OwnersResult)> callback) const; + base::OnceCallback<void(EntriesResult)> callback) const; // Runs all pending queries. Must not be called until the instance is fully // initialized.
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc b/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc index 4bdb082..4c2334c 100644 --- a/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc +++ b/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc
@@ -111,10 +111,11 @@ net::SamePartyContext(Type::kSameParty)); } -TEST_F(NoopFirstPartySetsAccessDelegateTest, FindOwners) { +TEST_F(NoopFirstPartySetsAccessDelegateTest, FindEntries) { EXPECT_THAT( - delegate().FindOwners({kSet1Member1, kSet2Member1}, base::NullCallback()), - FirstPartySetsAccessDelegate::OwnersResult({ + delegate().FindEntries({kSet1Member1, kSet2Member1}, + base::NullCallback()), + FirstPartySetsAccessDelegate::EntriesResult({ {kSet1Member1, net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 0)}, {kSet2Member1, @@ -159,11 +160,11 @@ return result.has_value() ? std::move(result).value() : future.Take(); } - FirstPartySetsAccessDelegate::OwnersResult FindOwnersAndWait( + FirstPartySetsAccessDelegate::EntriesResult FindEntriesAndWait( const base::flat_set<net::SchemefulSite>& site) { - base::test::TestFuture<FirstPartySetsAccessDelegate::OwnersResult> future; - absl::optional<FirstPartySetsAccessDelegate::OwnersResult> result = - delegate_.FindOwners(site, future.GetCallback()); + base::test::TestFuture<FirstPartySetsAccessDelegate::EntriesResult> future; + absl::optional<FirstPartySetsAccessDelegate::EntriesResult> result = + delegate_.FindEntries(site, future.GetCallback()); return result.has_value() ? result.value() : future.Get(); } @@ -201,11 +202,11 @@ Optional(std::ref(expected_metadata))); } -TEST_F(FirstPartySetsAccessDelegateDisabledTest, FindOwners) { +TEST_F(FirstPartySetsAccessDelegateDisabledTest, FindEntries) { EXPECT_THAT( - delegate().FindOwners( + delegate().FindEntries( {kSet1Member1, kSet2Member1}, - base::BindOnce([](FirstPartySetsManager::OwnersResult) { FAIL(); })), + base::BindOnce([](FirstPartySetsManager::EntriesResult) { FAIL(); })), Optional(IsEmpty())); } @@ -236,16 +237,16 @@ &entry, &entry)); } -TEST_F(AsyncFirstPartySetsAccessDelegateTest, QueryBeforeReady_FindOwners) { - base::test::TestFuture<FirstPartySetsAccessDelegate::OwnersResult> future; - EXPECT_FALSE(delegate().FindOwners({kSet1Member1, kSet2Member1}, - future.GetCallback())); +TEST_F(AsyncFirstPartySetsAccessDelegateTest, QueryBeforeReady_FindEntries) { + base::test::TestFuture<FirstPartySetsAccessDelegate::EntriesResult> future; + EXPECT_FALSE(delegate().FindEntries({kSet1Member1, kSet2Member1}, + future.GetCallback())); delegate_remote()->NotifyReady(mojom::FirstPartySetsReadyEvent::New()); EXPECT_THAT( future.Get(), - FirstPartySetsAccessDelegate::OwnersResult({ + FirstPartySetsAccessDelegate::EntriesResult({ {kSet1Member1, net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 0)}, {kSet2Member1, @@ -271,14 +272,14 @@ &primary_entry, &associated_entry)); } -TEST_F(AsyncFirstPartySetsAccessDelegateTest, OverrideSets_FindOwners) { +TEST_F(AsyncFirstPartySetsAccessDelegateTest, OverrideSets_FindEntries) { delegate_remote()->NotifyReady(CreateFirstPartySetsReadyEvent({ {kSet3Owner, {net::FirstPartySetEntry(kSet3Owner, net::SiteType::kPrimary, absl::nullopt)}}, })); - EXPECT_THAT(FindOwnersAndWait({kSet3Owner}), + EXPECT_THAT(FindEntriesAndWait({kSet3Owner}), UnorderedElementsAre(Pair(kSet3Owner, _))); } @@ -303,10 +304,10 @@ &entry, &entry)); } -TEST_F(SyncFirstPartySetsAccessDelegateTest, FindOwners) { +TEST_F(SyncFirstPartySetsAccessDelegateTest, FindEntries) { EXPECT_THAT( - FindOwnersAndWait({kSet1Member1, kSet2Member1, kSet3Member1}), - FirstPartySetsAccessDelegate::OwnersResult({ + FindEntriesAndWait({kSet1Member1, kSet2Member1, kSet3Member1}), + FirstPartySetsAccessDelegate::EntriesResult({ {kSet1Member1, net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 0)}, {kSet2Member1,
diff --git a/services/network/first_party_sets/first_party_sets_manager.cc b/services/network/first_party_sets/first_party_sets_manager.cc index 1c8d8cc..78934f77 100644 --- a/services/network/first_party_sets/first_party_sets_manager.cc +++ b/services/network/first_party_sets/first_party_sets_manager.cc
@@ -137,13 +137,13 @@ "Cookie.FirstPartySets.ComputeContext.Latency", timer.Elapsed(), base::Microseconds(1), base::Milliseconds(100), 50); - absl::optional<net::FirstPartySetEntry> top_frame_owner = + absl::optional<net::FirstPartySetEntry> top_frame_entry = top_frame_site ? FindEntry(*top_frame_site, fps_context_config) : absl::nullopt; return net::FirstPartySetMetadata( context, base::OptionalToPtr(FindEntry(site, fps_context_config)), - base::OptionalToPtr(top_frame_owner)); + base::OptionalToPtr(top_frame_entry)); } absl::optional<net::FirstPartySetEntry> FirstPartySetsManager::FindEntry( @@ -163,27 +163,28 @@ return entry; } -absl::optional<FirstPartySetsManager::OwnersResult> -FirstPartySetsManager::FindOwners( +absl::optional<FirstPartySetsManager::EntriesResult> +FirstPartySetsManager::FindEntries( const base::flat_set<net::SchemefulSite>& sites, const net::FirstPartySetsContextConfig& fps_context_config, - base::OnceCallback<void(FirstPartySetsManager::OwnersResult)> callback) { + base::OnceCallback<void(FirstPartySetsManager::EntriesResult)> callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!sets_.has_value()) { - EnqueuePendingQuery(base::BindOnce( - &FirstPartySetsManager::FindOwnersAndInvoke, weak_factory_.GetWeakPtr(), - sites, fps_context_config, std::move(callback), base::ElapsedTimer())); + EnqueuePendingQuery( + base::BindOnce(&FirstPartySetsManager::FindEntriesAndInvoke, + weak_factory_.GetWeakPtr(), sites, fps_context_config, + std::move(callback), base::ElapsedTimer())); return absl::nullopt; } - return FindOwnersInternal(sites, fps_context_config); + return FindEntriesInternal(sites, fps_context_config); } -void FirstPartySetsManager::FindOwnersAndInvoke( +void FirstPartySetsManager::FindEntriesAndInvoke( const base::flat_set<net::SchemefulSite>& sites, const net::FirstPartySetsContextConfig& fps_context_config, - base::OnceCallback<void(FirstPartySetsManager::OwnersResult)> callback, + base::OnceCallback<void(FirstPartySetsManager::EntriesResult)> callback, base::ElapsedTimer timer) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(sets_.has_value()); @@ -191,10 +192,10 @@ UMA_HISTOGRAM_TIMES("Cookie.FirstPartySets.EnqueueingDelay.FindOwners", timer.Elapsed()); - std::move(callback).Run(FindOwnersInternal(sites, fps_context_config)); + std::move(callback).Run(FindEntriesInternal(sites, fps_context_config)); } -FirstPartySetsManager::OwnersResult FirstPartySetsManager::FindOwnersInternal( +FirstPartySetsManager::EntriesResult FirstPartySetsManager::FindEntriesInternal( const base::flat_set<net::SchemefulSite>& sites, const net::FirstPartySetsContextConfig& fps_context_config) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/services/network/first_party_sets/first_party_sets_manager.h b/services/network/first_party_sets/first_party_sets_manager.h index 121274d..11f1e22 100644 --- a/services/network/first_party_sets/first_party_sets_manager.h +++ b/services/network/first_party_sets/first_party_sets_manager.h
@@ -30,7 +30,7 @@ // answers queries about First-Party Sets after they've been loaded. class FirstPartySetsManager { public: - using OwnersResult = + using EntriesResult = base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>; using FlattenedSets = base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>; @@ -80,10 +80,10 @@ // with the result. The callback will be invoked iff the return value is // nullopt; i.e. a result will be provided via return value or callback, but // not both, and not neither. - [[nodiscard]] absl::optional<OwnersResult> FindOwners( + [[nodiscard]] absl::optional<EntriesResult> FindEntries( const base::flat_set<net::SchemefulSite>& sites, const net::FirstPartySetsContextConfig& fps_context_config, - base::OnceCallback<void(OwnersResult)> callback); + base::OnceCallback<void(EntriesResult)> callback); private: // Same as `ComputeMetadata`, but plumbs the result into the callback. Must @@ -125,17 +125,17 @@ const net::SchemefulSite& site, const net::FirstPartySetsContextConfig& fps_context_config) const; - // Same as `FindOwners`, but plumbs the result into the callback. Must only be - // called once the instance is fully initialized. - void FindOwnersAndInvoke( + // Same as `FindEntries`, but plumbs the result into the callback. Must only + // be called once the instance is fully initialized. + void FindEntriesAndInvoke( const base::flat_set<net::SchemefulSite>& sites, const net::FirstPartySetsContextConfig& fps_context_config, - base::OnceCallback<void(OwnersResult)> callback, + base::OnceCallback<void(EntriesResult)> callback, base::ElapsedTimer timer) const; - // Synchronous version of `FindOwners`, to be run only once the instance is + // Synchronous version of `FindEntries`, to be run only once the instance is // initialized. - OwnersResult FindOwnersInternal( + EntriesResult FindEntriesInternal( const base::flat_set<net::SchemefulSite>& sites, const net::FirstPartySetsContextConfig& fps_context_config) const;
diff --git a/services/network/first_party_sets/first_party_sets_manager_unittest.cc b/services/network/first_party_sets/first_party_sets_manager_unittest.cc index ae8bb51..f5dc992 100644 --- a/services/network/first_party_sets/first_party_sets_manager_unittest.cc +++ b/services/network/first_party_sets/first_party_sets_manager_unittest.cc
@@ -60,11 +60,11 @@ return result.has_value() ? std::move(result).value() : future.Take(); } - FirstPartySetsManager::OwnersResult FindOwnersAndWait( + FirstPartySetsManager::EntriesResult FindEntriesAndWait( const base::flat_set<net::SchemefulSite>& site) { - base::test::TestFuture<FirstPartySetsManager::OwnersResult> future; - absl::optional<FirstPartySetsManager::OwnersResult> result = - manager_.FindOwners(site, fps_context_config_, future.GetCallback()); + base::test::TestFuture<FirstPartySetsManager::EntriesResult> future; + absl::optional<FirstPartySetsManager::EntriesResult> result = + manager_.FindEntries(site, fps_context_config_, future.GetCallback()); return result.has_value() ? result.value() : future.Get(); } @@ -105,7 +105,7 @@ example_test, net::SiteType::kPrimary, absl::nullopt)}}, {{example_cctld, example_test}}); - EXPECT_THAT(FindOwnersAndWait({ + EXPECT_THAT(FindEntriesAndWait({ aaaa, example_test, example_cctld, @@ -113,11 +113,11 @@ IsEmpty()); } -TEST_F(FirstPartySetsManagerDisabledTest, FindOwners) { +TEST_F(FirstPartySetsManagerDisabledTest, FindEntries) { net::SchemefulSite kExample = net::SchemefulSite(GURL("https://example.test")); - EXPECT_THAT(FindOwnersAndWait({kExample}), IsEmpty()); + EXPECT_THAT(FindEntriesAndWait({kExample}), IsEmpty()); } TEST_F(FirstPartySetsManagerDisabledTest, ComputeMetadata_InfersSingletons) { @@ -168,7 +168,7 @@ {{example_cctld, example_test}}); EXPECT_THAT( - FindOwnersAndWait({ + FindEntriesAndWait({ aaaa, example_test, example_cctld, @@ -186,7 +186,7 @@ TEST_F(FirstPartySetsEnabledTest, SetCompleteSets_Idempotent) { SetCompleteSets({}, {}); - EXPECT_THAT(FindOwnersAndWait({}), IsEmpty()); + EXPECT_THAT(FindEntriesAndWait({}), IsEmpty()); // The second call to SetCompleteSets should have no effect. SetCompleteSets({{net::SchemefulSite(GURL("https://aaaa.test")), @@ -198,7 +198,7 @@ net::SchemefulSite(GURL("https://example.test")), net::SiteType::kPrimary, absl::nullopt)}}, {}); - EXPECT_THAT(FindOwnersAndWait({ + EXPECT_THAT(FindEntriesAndWait({ net::SchemefulSite(GURL("https://aaaa.test")), net::SchemefulSite(GURL("https://example.test")), }), @@ -276,9 +276,9 @@ } } -TEST_F(AsyncPopulatedFirstPartySetsManagerTest, QueryBeforeReady_FindOwners) { - base::test::TestFuture<FirstPartySetsManager::OwnersResult> future; - EXPECT_FALSE(manager().FindOwners( +TEST_F(AsyncPopulatedFirstPartySetsManagerTest, QueryBeforeReady_FindEntries) { + base::test::TestFuture<FirstPartySetsManager::EntriesResult> future; + EXPECT_FALSE(manager().FindEntries( { net::SchemefulSite(GURL("https://member1.test")), net::SchemefulSite(GURL("https://member2.test")), @@ -793,41 +793,41 @@ &associated_entry, &associated_entry)); } -TEST_F(PopulatedFirstPartySetsManagerTest, FindOwners) { +TEST_F(PopulatedFirstPartySetsManagerTest, FindEntries) { net::SchemefulSite kExample(GURL("https://example.test")); net::SchemefulSite kFoo(GURL("https://foo.test")); net::SchemefulSite kMember1(GURL("https://member1.test")); net::SchemefulSite kMember2(GURL("https://member2.test")); net::SchemefulSite kNonmember(GURL("https://nonmember.test")); - EXPECT_THAT(FindOwnersAndWait({kExample}), + EXPECT_THAT(FindEntriesAndWait({kExample}), UnorderedElementsAre( Pair(SerializesTo("https://example.test"), net::FirstPartySetEntry( net::SchemefulSite(GURL("https://example.test")), net::SiteType::kPrimary, absl::nullopt)))); - EXPECT_THAT(FindOwnersAndWait({kMember1}), + EXPECT_THAT(FindEntriesAndWait({kMember1}), UnorderedElementsAre( Pair(SerializesTo("https://member1.test"), net::FirstPartySetEntry( net::SchemefulSite(GURL("https://example.test")), net::SiteType::kAssociated, 0)))); - EXPECT_THAT(FindOwnersAndWait({kNonmember}), IsEmpty()); + EXPECT_THAT(FindEntriesAndWait({kNonmember}), IsEmpty()); - EXPECT_THAT(FindOwnersAndWait({kExample, kNonmember}), + EXPECT_THAT(FindEntriesAndWait({kExample, kNonmember}), UnorderedElementsAre( Pair(SerializesTo("https://example.test"), net::FirstPartySetEntry( net::SchemefulSite(GURL("https://example.test")), net::SiteType::kPrimary, absl::nullopt)))); - EXPECT_THAT(FindOwnersAndWait({kMember1, kNonmember}), + EXPECT_THAT(FindEntriesAndWait({kMember1, kNonmember}), UnorderedElementsAre( Pair(SerializesTo("https://member1.test"), net::FirstPartySetEntry( net::SchemefulSite(GURL("https://example.test")), net::SiteType::kAssociated, 0)))); - EXPECT_THAT(FindOwnersAndWait({kExample, kFoo}), + EXPECT_THAT(FindEntriesAndWait({kExample, kFoo}), UnorderedElementsAre( Pair(SerializesTo("https://example.test"), net::FirstPartySetEntry( @@ -837,7 +837,7 @@ net::FirstPartySetEntry( net::SchemefulSite(GURL("https://foo.test")), net::SiteType::kPrimary, absl::nullopt)))); - EXPECT_THAT(FindOwnersAndWait({kMember1, kFoo}), + EXPECT_THAT(FindEntriesAndWait({kMember1, kFoo}), UnorderedElementsAre( Pair(SerializesTo("https://member1.test"), net::FirstPartySetEntry( @@ -847,7 +847,7 @@ net::FirstPartySetEntry( net::SchemefulSite(GURL("https://foo.test")), net::SiteType::kPrimary, absl::nullopt)))); - EXPECT_THAT(FindOwnersAndWait({kExample, kMember2}), + EXPECT_THAT(FindEntriesAndWait({kExample, kMember2}), UnorderedElementsAre( Pair(SerializesTo("https://example.test"), net::FirstPartySetEntry( @@ -857,7 +857,7 @@ net::FirstPartySetEntry( net::SchemefulSite(GURL("https://foo.test")), net::SiteType::kAssociated, 0)))); - EXPECT_THAT(FindOwnersAndWait({kMember1, kMember2}), + EXPECT_THAT(FindEntriesAndWait({kMember1, kMember2}), UnorderedElementsAre( Pair(SerializesTo("https://member1.test"), net::FirstPartySetEntry( @@ -907,13 +907,13 @@ } }; -TEST_F(OverrideSetsFirstPartySetsManagerTest, FindOwners) { +TEST_F(OverrideSetsFirstPartySetsManagerTest, FindEntries) { net::SchemefulSite foo(GURL("https://foo.test")); net::SchemefulSite example_test(GURL("https://example.test")); net::SchemefulSite example_cctld(GURL("https://example.cctld")); net::SchemefulSite member2(GURL("https://member2.test")); - EXPECT_THAT(FindOwnersAndWait({ + EXPECT_THAT(FindEntriesAndWait({ net::SchemefulSite(GURL("https://member1.test")), member2, foo,
diff --git a/styleguide/objective-c/objective-c.md b/styleguide/objective-c/objective-c.md index 74d91fa5..741e6e0 100644 --- a/styleguide/objective-c/objective-c.md +++ b/styleguide/objective-c/objective-c.md
@@ -112,5 +112,13 @@ ## #import and #include in the `ios/` directory #import directive can be used to import C++ and Objective-C headers for all -source code in the `ios/` directory. This differs from the Google Objective-C Style -Guide, which requires using #include directive for C++ headers. +source code in the `ios/` directory. This differs from the Google Objective-C +Style Guide, which requires using #include directive for C++ headers. + +## Disambiguating Symbols +Where needed to avoid ambiguity, use backticks to quote variable names and +symbols in comments in preference to using quotation marks or naming the symbols +inline. + +This is more specific than the Google Objective-C Style Guide which allows pipes +or backticks.
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json index 476996b..7ba2422 100644 --- a/testing/buildbot/chrome.json +++ b/testing/buildbot/chrome.json
@@ -1880,7 +1880,7 @@ { "args": [], "cros_board": "atlas", - "cros_img": "atlas-release/R107-15111.0.0", + "cros_img": "atlas-release/R107-15113.0.0", "name": "lacros_all_tast_tests ATLAS_RELEASE_LKGM", "resultdb": { "enable": true, @@ -1944,7 +1944,7 @@ { "args": [], "cros_board": "eve", - "cros_img": "eve-release/R107-15111.0.0", + "cros_img": "eve-release/R107-15113.0.0", "name": "lacros_all_tast_tests EVE_RELEASE_LKGM", "resultdb": { "enable": true, @@ -2051,7 +2051,7 @@ { "args": [], "cros_board": "jacuzzi", - "cros_img": "jacuzzi-release/R107-15111.0.0", + "cros_img": "jacuzzi-release/R107-15113.0.0", "name": "lacros_all_tast_tests JACUZZI_RELEASE_LKGM", "resultdb": { "enable": true,
diff --git a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter index d295def..0e993393 100644 --- a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter +++ b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_negative.filter
@@ -134,6 +134,7 @@ -PresetPolicyDeviceDisablingTest.* -PrimaryUserPoliciesProxiedTest.* -QuickStartBrowserTest.* +-QuickStartNotDeterminedBrowserTest.* -RecommendAppsScreenManagedTest.* -RecommendAppsScreenTest.* -ResetFirstAfterBootTest.*
diff --git a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter index 6574bc8..8d73510 100644 --- a/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter +++ b/testing/buildbot/filters/chromeos.msan.browser_tests.oobe_positive.filter
@@ -134,6 +134,7 @@ PresetPolicyDeviceDisablingTest.* PrimaryUserPoliciesProxiedTest.* QuickStartBrowserTest.* +QuickStartNotDeterminedBrowserTest.* RecommendAppsScreenManagedTest.* RecommendAppsScreenTest.* ResetFirstAfterBootTest.*
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json index 6a97f9dd..a46bdbb 100644 --- a/testing/buildbot/internal.chromeos.fyi.json +++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1037,7 +1037,7 @@ { "args": [], "cros_board": "octopus", - "cros_img": "octopus-release/R107-15111.0.0", + "cros_img": "octopus-release/R107-15113.0.0", "name": "lacros_fyi_tast_tests OCTOPUS_RELEASE_LKGM", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)", @@ -1085,7 +1085,7 @@ { "args": [], "cros_board": "octopus", - "cros_img": "octopus-release/R107-15111.0.0", + "cros_img": "octopus-release/R107-15113.0.0", "name": "ozone_unittests OCTOPUS_RELEASE_LKGM", "swarming": {}, "test": "ozone_unittests", @@ -1136,7 +1136,7 @@ { "args": [], "cros_board": "hana", - "cros_img": "hana-release/R107-15098.0.0", + "cros_img": "hana-release/R107-15113.0.0", "name": "lacros_all_tast_tests HANA_RELEASE_LKGM", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)", @@ -1184,7 +1184,7 @@ { "args": [], "cros_board": "strongbad", - "cros_img": "strongbad-release/R107-15111.0.0", + "cros_img": "strongbad-release/R107-15113.0.0", "name": "lacros_all_tast_tests STRONGBAD_RELEASE_LKGM", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)", @@ -1232,7 +1232,7 @@ { "args": [], "cros_board": "hana", - "cros_img": "hana-release/R107-15098.0.0", + "cros_img": "hana-release/R107-15113.0.0", "name": "ozone_unittests HANA_RELEASE_LKGM", "swarming": {}, "test": "ozone_unittests", @@ -1276,7 +1276,7 @@ { "args": [], "cros_board": "strongbad", - "cros_img": "strongbad-release/R107-15111.0.0", + "cros_img": "strongbad-release/R107-15113.0.0", "name": "ozone_unittests STRONGBAD_RELEASE_LKGM", "swarming": {}, "test": "ozone_unittests", @@ -1320,7 +1320,7 @@ { "args": [], "cros_board": "hana", - "cros_img": "hana-release/R107-15098.0.0", + "cros_img": "hana-release/R107-15113.0.0", "name": "viz_unittests HANA_RELEASE_LKGM", "swarming": {}, "test": "viz_unittests", @@ -1364,7 +1364,7 @@ { "args": [], "cros_board": "strongbad", - "cros_img": "strongbad-release/R107-15111.0.0", + "cros_img": "strongbad-release/R107-15113.0.0", "name": "viz_unittests STRONGBAD_RELEASE_LKGM", "swarming": {}, "test": "viz_unittests",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index 39163ff..29059638 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -826,8 +826,8 @@ 'CROS_ATLAS_RELEASE_LKGM': { 'skylab': { 'cros_board': 'atlas', - 'cros_chrome_version': '107.0.5295.0', - 'cros_img': 'atlas-release/R107-15111.0.0', + 'cros_chrome_version': '107.0.5297.0', + 'cros_img': 'atlas-release/R107-15113.0.0', }, 'enabled': True, 'identifier': 'ATLAS_RELEASE_LKGM', @@ -862,8 +862,8 @@ 'CROS_EVE_RELEASE_LKGM': { 'skylab': { 'cros_board': 'eve', - 'cros_chrome_version': '107.0.5295.0', - 'cros_img': 'eve-release/R107-15111.0.0', + 'cros_chrome_version': '107.0.5297.0', + 'cros_img': 'eve-release/R107-15113.0.0', }, 'enabled': True, 'identifier': 'EVE_RELEASE_LKGM', @@ -908,8 +908,8 @@ 'CROS_HANA_RELEASE_LKGM': { 'skylab': { 'cros_board': 'hana', - 'cros_chrome_version': '107.0.5283.0', - 'cros_img': 'hana-release/R107-15098.0.0', + 'cros_chrome_version': '107.0.5297.0', + 'cros_img': 'hana-release/R107-15113.0.0', }, 'enabled': True, 'identifier': 'HANA_RELEASE_LKGM', @@ -953,8 +953,8 @@ 'CROS_JACUZZI_RELEASE_LKGM': { 'skylab': { 'cros_board': 'jacuzzi', - 'cros_chrome_version': '107.0.5295.0', - 'cros_img': 'jacuzzi-release/R107-15111.0.0', + 'cros_chrome_version': '107.0.5297.0', + 'cros_img': 'jacuzzi-release/R107-15113.0.0', }, 'enabled': True, 'identifier': 'JACUZZI_RELEASE_LKGM', @@ -1019,8 +1019,8 @@ 'CROS_OCTOPUS_RELEASE_LKGM': { 'skylab': { 'cros_board': 'octopus', - 'cros_chrome_version': '107.0.5295.0', - 'cros_img': 'octopus-release/R107-15111.0.0', + 'cros_chrome_version': '107.0.5297.0', + 'cros_img': 'octopus-release/R107-15113.0.0', }, 'enabled': True, 'identifier': 'OCTOPUS_RELEASE_LKGM', @@ -1055,8 +1055,8 @@ 'CROS_STRONGBAD_RELEASE_LKGM': { 'skylab': { 'cros_board': 'strongbad', - 'cros_chrome_version': '107.0.5295.0', - 'cros_img': 'strongbad-release/R107-15111.0.0', + 'cros_chrome_version': '107.0.5297.0', + 'cros_img': 'strongbad-release/R107-15113.0.0', }, 'enabled': True, 'identifier': 'STRONGBAD_RELEASE_LKGM',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 20d627b1..eadd86ed 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -970,7 +970,7 @@ { "name": "Enabled", "params": { - "json_parameters": "\n {\n \"intent\":\"NIU_COWIN_CERTIFICATE_DOWNLOAD\",\n \"heuristics\":[\n {\n \"conditionSet\":{\"\n urlMatches\":\"https://www.cowin.gov.in\"\n }\n }\n ],\n \"enabledInCustomTabs\":true,\n \"enabledForSignedOutUsers\":true\n }\n " + "json_parameters": "\n {\n \"intent\":\"NIU_COWIN_CERTIFICATE_DOWNLOAD\",\n \"heuristics\":[\n {\n \"conditionSet\":{\n \"urlMatches\":\"https://www.cowin.gov.in\"\n }\n }\n ],\n \"enabledInCustomTabs\":true,\n \"enabledForSignedOutUsers\":true\n }\n " }, "enable_features": [ "AutofillAssistantUrlHeuristic1" @@ -2905,6 +2905,29 @@ ] } ], + "CompositorFrameGarbageCollection": [ + { + "platforms": [ + "android", + "android_weblayer", + "android_webview", + "chromeos", + "chromeos_lacros", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Both", + "enable_features": [ + "AggressiveFrameCulling", + "EagerSurfaceGarbageCollection" + ] + } + ] + } + ], "ConsolidatedSiteStorageControls": [ { "platforms": [ @@ -6930,6 +6953,22 @@ ] } ], + "OmniboxZeroSuggestPrefetching": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "ZeroSuggestPrefetchingOnSRP", + "ZeroSuggestPrefetchingOnWeb" + ] + } + ] + } + ], "OnDemandAT": [ { "platforms": [
diff --git a/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in b/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in index 5769e3a..75691b1 100644 --- a/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in +++ b/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in
@@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.2) +cmake_minimum_required(VERSION 3.10) project(googletest-external NONE)
diff --git a/third_party/abseil-cpp/CMake/README.md b/third_party/abseil-cpp/CMake/README.md index 0be3b92..19fb327 100644 --- a/third_party/abseil-cpp/CMake/README.md +++ b/third_party/abseil-cpp/CMake/README.md
@@ -39,7 +39,7 @@ Here is a short CMakeLists.txt example of an application project using Abseil. ```cmake -cmake_minimum_required(VERSION 3.8.2) +cmake_minimum_required(VERSION 3.10) project(my_app_project) # Pick the C++ standard to compile with. @@ -62,7 +62,7 @@ example: ```cmake -cmake_minimum_required(VERSION 3.8.2) +cmake_minimum_required(VERSION 3.10) project(my_lib_project) # Leave C++ standard up to the root application, so set it only if this is the
diff --git a/third_party/abseil-cpp/CMake/install_test_project/CMakeLists.txt b/third_party/abseil-cpp/CMake/install_test_project/CMakeLists.txt index b865b2e..30c23b2c 100644 --- a/third_party/abseil-cpp/CMake/install_test_project/CMakeLists.txt +++ b/third_party/abseil-cpp/CMake/install_test_project/CMakeLists.txt
@@ -15,7 +15,7 @@ # A simple CMakeLists.txt for testing cmake installation -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) project(absl_cmake_testing CXX) add_executable(simple simple.cc)
diff --git a/third_party/abseil-cpp/CMakeLists.txt b/third_party/abseil-cpp/CMakeLists.txt index 016dd91..3b67d8f 100644 --- a/third_party/abseil-cpp/CMakeLists.txt +++ b/third_party/abseil-cpp/CMakeLists.txt
@@ -14,12 +14,9 @@ # limitations under the License. # -# Most widely used distributions have cmake 3.5 or greater available as of March -# 2019. A notable exception is RHEL-7 (CentOS7). You can install a current -# version of CMake by first installing Extra Packages for Enterprise Linux -# (https://fedoraproject.org/wiki/EPEL#Extra_Packages_for_Enterprise_Linux_.28EPEL.29) -# and then issuing `yum install cmake3` on the command line. -cmake_minimum_required(VERSION 3.5) +# https://github.com/google/oss-policies-info/blob/main/foundational-cxx-support-matrix.md +# As of 2022-09-06, CMake 3.10 is the minimum supported version. +cmake_minimum_required(VERSION 3.10) # Compiler id for Apple Clang is now AppleClang. if (POLICY CMP0025)
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium index d6ada64e..9ae2f674 100644 --- a/third_party/abseil-cpp/README.chromium +++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@ License: Apache 2.0 License File: LICENSE Version: 0 -Revision: 308bbf300fe9332130f4784c7a91fa2ad707d6e4 +Revision: 1be36c8a50e1c2aae525c0fa95cb300ecf9abbe4 Security Critical: yes Description:
diff --git a/third_party/abseil-cpp/absl/BUILD.bazel b/third_party/abseil-cpp/absl/BUILD.bazel index 7cccbbb..29963ccc 100644 --- a/third_party/abseil-cpp/absl/BUILD.bazel +++ b/third_party/abseil-cpp/absl/BUILD.bazel
@@ -28,6 +28,14 @@ ) config_setting( + name = "gcc_compiler", + flag_values = { + "@bazel_tools//tools/cpp:compiler": "gcc", + }, + visibility = [":__subpackages__"], +) + +config_setting( name = "msvc_compiler", flag_values = { "@bazel_tools//tools/cpp:compiler": "msvc-cl",
diff --git a/third_party/abseil-cpp/absl/algorithm/container_test.cc b/third_party/abseil-cpp/absl/algorithm/container_test.cc index 605afc8..0fbc777 100644 --- a/third_party/abseil-cpp/absl/algorithm/container_test.cc +++ b/third_party/abseil-cpp/absl/algorithm/container_test.cc
@@ -67,13 +67,16 @@ bool IsOdd(int x) { return x % 2 != 0; } TEST_F(NonMutatingTest, Distance) { - EXPECT_EQ(container_.size(), absl::c_distance(container_)); - EXPECT_EQ(sequence_.size(), absl::c_distance(sequence_)); - EXPECT_EQ(vector_.size(), absl::c_distance(vector_)); - EXPECT_EQ(ABSL_ARRAYSIZE(array_), absl::c_distance(array_)); + EXPECT_EQ(container_.size(), + static_cast<size_t>(absl::c_distance(container_))); + EXPECT_EQ(sequence_.size(), static_cast<size_t>(absl::c_distance(sequence_))); + EXPECT_EQ(vector_.size(), static_cast<size_t>(absl::c_distance(vector_))); + EXPECT_EQ(ABSL_ARRAYSIZE(array_), + static_cast<size_t>(absl::c_distance(array_))); // Works with a temporary argument. - EXPECT_EQ(vector_.size(), absl::c_distance(std::vector<int>(vector_))); + EXPECT_EQ(vector_.size(), + static_cast<size_t>(absl::c_distance(std::vector<int>(vector_)))); } TEST_F(NonMutatingTest, Distance_OverloadedBeginEnd) {
diff --git a/third_party/abseil-cpp/absl/base/internal/direct_mmap.h b/third_party/abseil-cpp/absl/base/internal/direct_mmap.h index e492bb0..815b8d2 100644 --- a/third_party/abseil-cpp/absl/base/internal/direct_mmap.h +++ b/third_party/abseil-cpp/absl/base/internal/direct_mmap.h
@@ -97,7 +97,8 @@ #ifdef __BIONIC__ // SYS_mmap2 has problems on Android API level <= 16. // Workaround by invoking __mmap2() instead. - return __mmap2(start, length, prot, flags, fd, offset / pagesize); + return __mmap2(start, length, prot, flags, fd, + static_cast<size_t>(offset / pagesize)); #else return reinterpret_cast<void*>( syscall(SYS_mmap2, start, length, prot, flags, fd,
diff --git a/third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc b/third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc index aa6c3c3..662167b 100644 --- a/third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc +++ b/third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc
@@ -332,7 +332,7 @@ #elif defined(__wasm__) || defined(__asmjs__) return getpagesize(); #else - return sysconf(_SC_PAGESIZE); + return static_cast<size_t>(sysconf(_SC_PAGESIZE)); #endif }
diff --git a/third_party/abseil-cpp/absl/base/internal/sysinfo.cc b/third_party/abseil-cpp/absl/base/internal/sysinfo.cc index a3e08b9..d820ce38 100644 --- a/third_party/abseil-cpp/absl/base/internal/sysinfo.cc +++ b/third_party/abseil-cpp/absl/base/internal/sysinfo.cc
@@ -136,7 +136,7 @@ // Other possibilities: // - Read /sys/devices/system/cpu/online and use cpumask_parse() // - sysconf(_SC_NPROCESSORS_ONLN) - return std::thread::hardware_concurrency(); + return static_cast<int>(std::thread::hardware_concurrency()); #endif } @@ -194,7 +194,7 @@ char line[1024]; char *err; memset(line, '\0', sizeof(line)); - int len = read(fd, line, sizeof(line) - 1); + ssize_t len = read(fd, line, sizeof(line) - 1); if (len <= 0) { ret = false; } else { @@ -376,7 +376,7 @@ #endif pid_t GetTID() { - return syscall(SYS_gettid); + return static_cast<pid_t>(syscall(SYS_gettid)); } #elif defined(__akaros__) @@ -429,11 +429,11 @@ // Returns the TID to tid_array. static void FreeTID(void *v) { intptr_t tid = reinterpret_cast<intptr_t>(v); - int word = tid / kBitsPerWord; + intptr_t word = tid / kBitsPerWord; uint32_t mask = ~(1u << (tid % kBitsPerWord)); absl::base_internal::SpinLockHolder lock(&tid_lock); assert(0 <= word && static_cast<size_t>(word) < tid_array->size()); - (*tid_array)[word] &= mask; + (*tid_array)[static_cast<size_t>(word)] &= mask; } static void InitGetTID() { @@ -455,7 +455,7 @@ intptr_t tid = reinterpret_cast<intptr_t>(pthread_getspecific(tid_key)); if (tid != 0) { - return tid; + return static_cast<pid_t>(tid); } int bit; // tid_array[word] = 1u << bit; @@ -476,7 +476,8 @@ while (bit < kBitsPerWord && (((*tid_array)[word] >> bit) & 1) != 0) { ++bit; } - tid = (word * kBitsPerWord) + bit; + tid = + static_cast<intptr_t>((word * kBitsPerWord) + static_cast<size_t>(bit)); (*tid_array)[word] |= 1u << bit; // Mark the TID as allocated. }
diff --git a/third_party/abseil-cpp/absl/base/spinlock_test_common.cc b/third_party/abseil-cpp/absl/base/spinlock_test_common.cc index 7b6e4b3..52ecf580 100644 --- a/third_party/abseil-cpp/absl/base/spinlock_test_common.cc +++ b/third_party/abseil-cpp/absl/base/spinlock_test_common.cc
@@ -34,7 +34,7 @@ #include "absl/synchronization/blocking_counter.h" #include "absl/synchronization/notification.h" -constexpr int32_t kNumThreads = 10; +constexpr uint32_t kNumThreads = 10; constexpr int32_t kIters = 1000; namespace absl { @@ -55,7 +55,7 @@ namespace { -static constexpr int kArrayLength = 10; +static constexpr size_t kArrayLength = 10; static uint32_t values[kArrayLength]; ABSL_CONST_INIT static SpinLock static_cooperative_spinlock( @@ -79,11 +79,11 @@ return c; } -static void TestFunction(int thread_salt, SpinLock* spinlock) { +static void TestFunction(uint32_t thread_salt, SpinLock* spinlock) { for (int i = 0; i < kIters; i++) { SpinLockHolder h(spinlock); - for (int j = 0; j < kArrayLength; j++) { - const int index = (j + thread_salt) % kArrayLength; + for (size_t j = 0; j < kArrayLength; j++) { + const size_t index = (j + thread_salt) % kArrayLength; values[index] = Hash32(values[index], thread_salt); std::this_thread::yield(); } @@ -93,7 +93,7 @@ static void ThreadedTest(SpinLock* spinlock) { std::vector<std::thread> threads; threads.reserve(kNumThreads); - for (int i = 0; i < kNumThreads; ++i) { + for (uint32_t i = 0; i < kNumThreads; ++i) { threads.push_back(std::thread(TestFunction, i, spinlock)); } for (auto& thread : threads) { @@ -101,7 +101,7 @@ } SpinLockHolder h(spinlock); - for (int i = 1; i < kArrayLength; i++) { + for (size_t i = 1; i < kArrayLength; i++) { EXPECT_EQ(values[0], values[i]); } } @@ -153,7 +153,7 @@ int64_t cycles = cycle_distribution(generator); int64_t end_time = start_time + cycles; uint32_t lock_value = SpinLockTest::EncodeWaitCycles(start_time, end_time); - EXPECT_EQ(0, lock_value & kLockwordReservedMask); + EXPECT_EQ(0u, lock_value & kLockwordReservedMask); int64_t decoded = SpinLockTest::DecodeWaitCycles(lock_value); EXPECT_EQ(0, decoded & kProfileTimestampMask); EXPECT_EQ(cycles & ~kProfileTimestampMask, decoded);
diff --git a/third_party/abseil-cpp/absl/container/inlined_vector.h b/third_party/abseil-cpp/absl/container/inlined_vector.h index 08a4770..60f1246 100644 --- a/third_party/abseil-cpp/absl/container/inlined_vector.h +++ b/third_party/abseil-cpp/absl/container/inlined_vector.h
@@ -626,9 +626,9 @@ ABSL_HARDENING_ASSERT(pos <= end()); if (ABSL_PREDICT_TRUE(first != last)) { - return storage_.Insert(pos, - IteratorValueAdapter<A, ForwardIterator>(first), - std::distance(first, last)); + return storage_.Insert( + pos, IteratorValueAdapter<A, ForwardIterator>(first), + static_cast<size_type>(std::distance(first, last))); } else { return const_cast<iterator>(pos); } @@ -645,7 +645,7 @@ ABSL_HARDENING_ASSERT(pos >= begin()); ABSL_HARDENING_ASSERT(pos <= end()); - size_type index = std::distance(cbegin(), pos); + size_type index = static_cast<size_type>(std::distance(cbegin(), pos)); for (size_type i = index; first != last; ++i, static_cast<void>(++first)) { insert(data() + i, *first); }
diff --git a/third_party/abseil-cpp/absl/container/inlined_vector_test.cc b/third_party/abseil-cpp/absl/container/inlined_vector_test.cc index 0e52811..b872eb4 100644 --- a/third_party/abseil-cpp/absl/container/inlined_vector_test.cc +++ b/third_party/abseil-cpp/absl/container/inlined_vector_test.cc
@@ -126,20 +126,20 @@ // Append 0..len-1 to *v template <typename Container> -static void Fill(Container* v, int len, int offset = 0) { - for (int i = 0; i < len; i++) { - v->push_back(i + offset); +static void Fill(Container* v, size_t len, int offset = 0) { + for (size_t i = 0; i < len; i++) { + v->push_back(static_cast<int>(i) + offset); } } -static IntVec Fill(int len, int offset = 0) { +static IntVec Fill(size_t len, int offset = 0) { IntVec v; Fill(&v, len, offset); return v; } TEST(IntVec, SimpleOps) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v; const IntVec& cv = v; // const alias @@ -147,42 +147,42 @@ EXPECT_EQ(len, v.size()); EXPECT_LE(len, v.capacity()); - for (int i = 0; i < len; i++) { - EXPECT_EQ(i, v[i]); - EXPECT_EQ(i, v.at(i)); + for (size_t i = 0; i < len; i++) { + EXPECT_EQ(static_cast<int>(i), v[i]); + EXPECT_EQ(static_cast<int>(i), v.at(i)); } EXPECT_EQ(v.begin(), v.data()); EXPECT_EQ(cv.begin(), cv.data()); - int counter = 0; + size_t counter = 0; for (IntVec::iterator iter = v.begin(); iter != v.end(); ++iter) { - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); counter++; } EXPECT_EQ(counter, len); counter = 0; for (IntVec::const_iterator iter = v.begin(); iter != v.end(); ++iter) { - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); counter++; } EXPECT_EQ(counter, len); counter = 0; for (IntVec::const_iterator iter = v.cbegin(); iter != v.cend(); ++iter) { - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); counter++; } EXPECT_EQ(counter, len); if (len > 0) { EXPECT_EQ(0, v.front()); - EXPECT_EQ(len - 1, v.back()); + EXPECT_EQ(static_cast<int>(len - 1), v.back()); v.pop_back(); EXPECT_EQ(len - 1, v.size()); - for (int i = 0; i < v.size(); ++i) { - EXPECT_EQ(i, v[i]); - EXPECT_EQ(i, v.at(i)); + for (size_t i = 0; i < v.size(); ++i) { + EXPECT_EQ(static_cast<int>(i), v[i]); + EXPECT_EQ(static_cast<int>(i), v.at(i)); } } } @@ -191,7 +191,7 @@ TEST(IntVec, PopBackNoOverflow) { IntVec v = {1}; v.pop_back(); - EXPECT_EQ(v.size(), 0); + EXPECT_EQ(v.size(), 0u); } TEST(IntVec, AtThrows) { @@ -202,47 +202,47 @@ } TEST(IntVec, ReverseIterator) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v; Fill(&v, len); - int counter = len; + size_t counter = len; for (IntVec::reverse_iterator iter = v.rbegin(); iter != v.rend(); ++iter) { counter--; - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); } - EXPECT_EQ(counter, 0); + EXPECT_EQ(counter, 0u); counter = len; for (IntVec::const_reverse_iterator iter = v.rbegin(); iter != v.rend(); ++iter) { counter--; - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); } - EXPECT_EQ(counter, 0); + EXPECT_EQ(counter, 0u); counter = len; for (IntVec::const_reverse_iterator iter = v.crbegin(); iter != v.crend(); ++iter) { counter--; - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); } - EXPECT_EQ(counter, 0); + EXPECT_EQ(counter, 0u); } } TEST(IntVec, Erase) { - for (int len = 1; len < 20; len++) { - for (int i = 0; i < len; ++i) { + for (size_t len = 1; len < 20; len++) { + for (size_t i = 0; i < len; ++i) { IntVec v; Fill(&v, len); v.erase(v.begin() + i); EXPECT_EQ(len - 1, v.size()); - for (int j = 0; j < i; ++j) { - EXPECT_EQ(j, v[j]); + for (size_t j = 0; j < i; ++j) { + EXPECT_EQ(static_cast<int>(j), v[j]); } - for (int j = i; j < len - 1; ++j) { - EXPECT_EQ(j + 1, v[j]); + for (size_t j = i; j < len - 1; ++j) { + EXPECT_EQ(static_cast<int>(j + 1), v[j]); } } } @@ -254,7 +254,7 @@ EXPECT_EQ(v[9], 9); #if !defined(NDEBUG) || ABSL_OPTION_HARDENED EXPECT_DEATH_IF_SUPPORTED(v[10], ""); - EXPECT_DEATH_IF_SUPPORTED(v[-1], ""); + EXPECT_DEATH_IF_SUPPORTED(v[static_cast<size_t>(-1)], ""); EXPECT_DEATH_IF_SUPPORTED(v.resize(v.max_size() + 1), ""); #endif } @@ -263,43 +263,43 @@ // should have reference counts == 0, and all others elements should have // reference counts == 1. TEST(RefCountedVec, EraseBeginEnd) { - for (int len = 1; len < 20; ++len) { - for (int erase_begin = 0; erase_begin < len; ++erase_begin) { - for (int erase_end = erase_begin; erase_end <= len; ++erase_end) { + for (size_t len = 1; len < 20; ++len) { + for (size_t erase_begin = 0; erase_begin < len; ++erase_begin) { + for (size_t erase_end = erase_begin; erase_end <= len; ++erase_end) { std::vector<int> counts(len, 0); RefCountedVec v; - for (int i = 0; i < len; ++i) { - v.push_back(RefCounted(i, &counts[i])); + for (size_t i = 0; i < len; ++i) { + v.push_back(RefCounted(static_cast<int>(i), &counts[i])); } - int erase_len = erase_end - erase_begin; + size_t erase_len = erase_end - erase_begin; v.erase(v.begin() + erase_begin, v.begin() + erase_end); EXPECT_EQ(len - erase_len, v.size()); // Check the elements before the first element erased. - for (int i = 0; i < erase_begin; ++i) { - EXPECT_EQ(i, v[i].value_); + for (size_t i = 0; i < erase_begin; ++i) { + EXPECT_EQ(static_cast<int>(i), v[i].value_); } // Check the elements after the first element erased. - for (int i = erase_begin; i < v.size(); ++i) { - EXPECT_EQ(i + erase_len, v[i].value_); + for (size_t i = erase_begin; i < v.size(); ++i) { + EXPECT_EQ(static_cast<int>(i + erase_len), v[i].value_); } // Check that the elements at the beginning are preserved. - for (int i = 0; i < erase_begin; ++i) { + for (size_t i = 0; i < erase_begin; ++i) { EXPECT_EQ(1, counts[i]); } // Check that the erased elements are destroyed - for (int i = erase_begin; i < erase_end; ++i) { + for (size_t i = erase_begin; i < erase_end; ++i) { EXPECT_EQ(0, counts[i]); } // Check that the elements at the end are preserved. - for (int i = erase_end; i < len; ++i) { + for (size_t i = erase_end; i < len; ++i) { EXPECT_EQ(1, counts[i]); } } @@ -378,21 +378,21 @@ absl::InlinedVector<std::pair<std::string, int>, 1> v; v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 1); + EXPECT_EQ(v.capacity(), 1u); v.emplace_back("answer", 42); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 1); + EXPECT_EQ(v.capacity(), 1u); v.emplace_back("taxicab", 1729); - EXPECT_GE(v.capacity(), 2); + EXPECT_GE(v.capacity(), 2u); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); + EXPECT_EQ(v.capacity(), 2u); v.reserve(100); - EXPECT_GE(v.capacity(), 100); + EXPECT_GE(v.capacity(), 100u); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); + EXPECT_EQ(v.capacity(), 2u); } TEST(InlinedVectorTest, ShrinkToFitEdgeCases) { @@ -400,10 +400,10 @@ absl::InlinedVector<std::pair<std::string, int>, 1> v; v.emplace_back("answer", 42); v.emplace_back("taxicab", 1729); - EXPECT_GE(v.capacity(), 2); + EXPECT_GE(v.capacity(), 2u); v.pop_back(); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 1); + EXPECT_EQ(v.capacity(), 1u); EXPECT_EQ(v[0].first, "answer"); EXPECT_EQ(v[0].second, 42); } @@ -412,34 +412,34 @@ absl::InlinedVector<std::string, 2> v(100); v.resize(0); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); // inlined capacity + EXPECT_EQ(v.capacity(), 2u); // inlined capacity } { absl::InlinedVector<std::string, 2> v(100); v.resize(1); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); // inlined capacity + EXPECT_EQ(v.capacity(), 2u); // inlined capacity } { absl::InlinedVector<std::string, 2> v(100); v.resize(2); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); + EXPECT_EQ(v.capacity(), 2u); } { absl::InlinedVector<std::string, 2> v(100); v.resize(3); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 3); + EXPECT_EQ(v.capacity(), 3u); } } TEST(IntVec, Insert) { - for (int len = 0; len < 20; len++) { - for (int pos = 0; pos <= len; pos++) { + for (size_t len = 0; len < 20; len++) { + for (ptrdiff_t pos = 0; pos <= static_cast<ptrdiff_t>(len); pos++) { { // Single element std::vector<int> std_v; @@ -527,16 +527,16 @@ TEST(RefCountedVec, InsertConstructorDestructor) { // Make sure the proper construction/destruction happen during insert // operations. - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { SCOPED_TRACE(len); - for (int pos = 0; pos <= len; pos++) { + for (size_t pos = 0; pos <= len; pos++) { SCOPED_TRACE(pos); std::vector<int> counts(len, 0); int inserted_count = 0; RefCountedVec v; - for (int i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { SCOPED_TRACE(i); - v.push_back(RefCounted(i, &counts[i])); + v.push_back(RefCounted(static_cast<int>(i), &counts[i])); } EXPECT_THAT(counts, Each(Eq(1))); @@ -553,20 +553,20 @@ } TEST(IntVec, Resize) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v; Fill(&v, len); // Try resizing up and down by k elements static const int kResizeElem = 1000000; - for (int k = 0; k < 10; k++) { + for (size_t k = 0; k < 10; k++) { // Enlarging resize v.resize(len + k, kResizeElem); EXPECT_EQ(len + k, v.size()); EXPECT_LE(len + k, v.capacity()); - for (int i = 0; i < len + k; i++) { + for (size_t i = 0; i < len + k; i++) { if (i < len) { - EXPECT_EQ(i, v[i]); + EXPECT_EQ(static_cast<int>(i), v[i]); } else { EXPECT_EQ(kResizeElem, v[i]); } @@ -576,26 +576,26 @@ v.resize(len, kResizeElem); EXPECT_EQ(len, v.size()); EXPECT_LE(len, v.capacity()); - for (int i = 0; i < len; i++) { - EXPECT_EQ(i, v[i]); + for (size_t i = 0; i < len; i++) { + EXPECT_EQ(static_cast<int>(i), v[i]); } } } } TEST(IntVec, InitWithLength) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v(len, 7); EXPECT_EQ(len, v.size()); EXPECT_LE(len, v.capacity()); - for (int i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { EXPECT_EQ(7, v[i]); } } } TEST(IntVec, CopyConstructorAndAssignment) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v; Fill(&v, len); EXPECT_EQ(len, v.size()); @@ -604,7 +604,7 @@ IntVec v2(v); EXPECT_TRUE(v == v2) << PrintToString(v) << PrintToString(v2); - for (int start_len = 0; start_len < 20; start_len++) { + for (size_t start_len = 0; start_len < 20; start_len++) { IntVec v3; Fill(&v3, start_len, 99); // Add dummy elements that should go away v3 = v; @@ -614,7 +614,7 @@ } TEST(IntVec, AliasingCopyAssignment) { - for (int len = 0; len < 20; ++len) { + for (size_t len = 0; len < 20; ++len) { IntVec original; Fill(&original, len); IntVec dup = original; @@ -624,9 +624,9 @@ } TEST(IntVec, MoveConstructorAndAssignment) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v_in; - const int inlined_capacity = v_in.capacity(); + const size_t inlined_capacity = v_in.capacity(); Fill(&v_in, len); EXPECT_EQ(len, v_in.size()); EXPECT_LE(len, v_in.capacity()); @@ -643,7 +643,7 @@ EXPECT_FALSE(v_out.data() == old_data); } } - for (int start_len = 0; start_len < 20; start_len++) { + for (size_t start_len = 0; start_len < 20; start_len++) { IntVec v_out; Fill(&v_out, start_len, 99); // Add dummy elements that should go away IntVec v_temp(v_in); @@ -682,10 +682,10 @@ }; TEST(AliasingTest, Emplace) { - for (int i = 2; i < 20; ++i) { + for (size_t i = 2; i < 20; ++i) { absl::InlinedVector<NotTriviallyDestructible, 10> vec; - for (int j = 0; j < i; ++j) { - vec.push_back(NotTriviallyDestructible(j)); + for (size_t j = 0; j < i; ++j) { + vec.push_back(NotTriviallyDestructible(static_cast<int>(j))); } vec.emplace(vec.begin(), vec[0]); EXPECT_EQ(vec[0], vec[1]); @@ -697,12 +697,12 @@ } TEST(AliasingTest, InsertWithCount) { - for (int i = 1; i < 20; ++i) { + for (size_t i = 1; i < 20; ++i) { absl::InlinedVector<NotTriviallyDestructible, 10> vec; - for (int j = 0; j < i; ++j) { - vec.push_back(NotTriviallyDestructible(j)); + for (size_t j = 0; j < i; ++j) { + vec.push_back(NotTriviallyDestructible(static_cast<int>(j))); } - for (int n = 0; n < 5; ++n) { + for (size_t n = 0; n < 5; ++n) { // We use back where we can because it's guaranteed to become invalidated vec.insert(vec.begin(), n, vec.back()); auto b = vec.begin(); @@ -760,22 +760,22 @@ } TEST(IntVec, Clear) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { SCOPED_TRACE(len); IntVec v; Fill(&v, len); v.clear(); - EXPECT_EQ(0, v.size()); + EXPECT_EQ(0u, v.size()); EXPECT_EQ(v.begin(), v.end()); } } TEST(IntVec, Reserve) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v; Fill(&v, len); - for (int newlen = 0; newlen < 100; newlen++) { + for (size_t newlen = 0; newlen < 100; newlen++) { const int* start_rep = v.data(); v.reserve(newlen); const int* final_rep = v.data(); @@ -842,9 +842,9 @@ } TEST(IntVec, Swap) { - for (int l1 = 0; l1 < 20; l1++) { + for (size_t l1 = 0; l1 < 20; l1++) { SCOPED_TRACE(l1); - for (int l2 = 0; l2 < 20; l2++) { + for (size_t l2 = 0; l2 < 20; l2++) { SCOPED_TRACE(l2); IntVec a = Fill(l1, 0); IntVec b = Fill(l2, 100); @@ -854,13 +854,13 @@ } EXPECT_EQ(l1, b.size()); EXPECT_EQ(l2, a.size()); - for (int i = 0; i < l1; i++) { + for (size_t i = 0; i < l1; i++) { SCOPED_TRACE(i); - EXPECT_EQ(i, b[i]); + EXPECT_EQ(static_cast<int>(i), b[i]); } - for (int i = 0; i < l2; i++) { + for (size_t i = 0; i < l2; i++) { SCOPED_TRACE(i); - EXPECT_EQ(100 + i, a[i]); + EXPECT_EQ(100 + static_cast<int>(i), a[i]); } } } @@ -869,46 +869,48 @@ TYPED_TEST_P(InstanceTest, Swap) { using Instance = TypeParam; using InstanceVec = absl::InlinedVector<Instance, 8>; - for (int l1 = 0; l1 < 20; l1++) { + for (size_t l1 = 0; l1 < 20; l1++) { SCOPED_TRACE(l1); - for (int l2 = 0; l2 < 20; l2++) { + for (size_t l2 = 0; l2 < 20; l2++) { SCOPED_TRACE(l2); InstanceTracker tracker; InstanceVec a, b; const size_t inlined_capacity = a.capacity(); auto min_len = std::min(l1, l2); auto max_len = std::max(l1, l2); - for (int i = 0; i < l1; i++) a.push_back(Instance(i)); - for (int i = 0; i < l2; i++) b.push_back(Instance(100 + i)); - EXPECT_EQ(tracker.instances(), l1 + l2); + for (size_t i = 0; i < l1; i++) + a.push_back(Instance(static_cast<int>(i))); + for (size_t i = 0; i < l2; i++) + b.push_back(Instance(100 + static_cast<int>(i))); + EXPECT_EQ(tracker.instances(), static_cast<int>(l1 + l2)); tracker.ResetCopiesMovesSwaps(); { using std::swap; swap(a, b); } - EXPECT_EQ(tracker.instances(), l1 + l2); + EXPECT_EQ(tracker.instances(), static_cast<int>(l1 + l2)); if (a.size() > inlined_capacity && b.size() > inlined_capacity) { EXPECT_EQ(tracker.swaps(), 0); // Allocations are swapped. EXPECT_EQ(tracker.moves(), 0); } else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) { - EXPECT_EQ(tracker.swaps(), min_len); + EXPECT_EQ(tracker.swaps(), static_cast<int>(min_len)); EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()), - max_len - min_len); + static_cast<int>(max_len - min_len)); } else { // One is allocated and the other isn't. The allocation is transferred // without copying elements, and the inlined instances are copied/moved. EXPECT_EQ(tracker.swaps(), 0); EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()), - min_len); + static_cast<int>(min_len)); } EXPECT_EQ(l1, b.size()); EXPECT_EQ(l2, a.size()); - for (int i = 0; i < l1; i++) { - EXPECT_EQ(i, b[i].value()); + for (size_t i = 0; i < l1; i++) { + EXPECT_EQ(static_cast<int>(i), b[i].value()); } - for (int i = 0; i < l2; i++) { - EXPECT_EQ(100 + i, a[i].value()); + for (size_t i = 0; i < l2; i++) { + EXPECT_EQ(100 + static_cast<int>(i), a[i].value()); } } } @@ -937,9 +939,9 @@ a.clear(); b.clear(); - for (int i = 0; i < 100; i++) { - a.push_back(i); - b.push_back(i); + for (size_t i = 0; i < 100; i++) { + a.push_back(static_cast<int>(i)); + b.push_back(static_cast<int>(i)); EXPECT_TRUE(a == b); EXPECT_FALSE(a != b); @@ -978,26 +980,26 @@ using Instance = TypeParam; using InstanceVec = absl::InlinedVector<Instance, 8>; InstanceTracker tracker; - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { SCOPED_TRACE(len); tracker.ResetCopiesMovesSwaps(); InstanceVec v; const size_t inlined_capacity = v.capacity(); - for (int i = 0; i < len; i++) { - v.push_back(Instance(i)); + for (size_t i = 0; i < len; i++) { + v.push_back(Instance(static_cast<int>(i))); } - EXPECT_EQ(tracker.instances(), len); + EXPECT_EQ(tracker.instances(), static_cast<int>(len)); EXPECT_GE(tracker.copies() + tracker.moves(), - len); // More due to reallocation. + static_cast<int>(len)); // More due to reallocation. tracker.ResetCopiesMovesSwaps(); // Enlarging resize() must construct some objects tracker.ResetCopiesMovesSwaps(); v.resize(len + 10, Instance(100)); - EXPECT_EQ(tracker.instances(), len + 10); + EXPECT_EQ(tracker.instances(), static_cast<int>(len) + 10); if (len <= inlined_capacity && len + 10 > inlined_capacity) { - EXPECT_EQ(tracker.copies() + tracker.moves(), 10 + len); + EXPECT_EQ(tracker.copies() + tracker.moves(), 10 + static_cast<int>(len)); } else { // Only specify a minimum number of copies + moves. We don't want to // depend on the reallocation policy here. @@ -1008,29 +1010,30 @@ // Shrinking resize() must destroy some objects tracker.ResetCopiesMovesSwaps(); v.resize(len, Instance(100)); - EXPECT_EQ(tracker.instances(), len); + EXPECT_EQ(tracker.instances(), static_cast<int>(len)); EXPECT_EQ(tracker.copies(), 0); EXPECT_EQ(tracker.moves(), 0); // reserve() must not increase the number of initialized objects SCOPED_TRACE("reserve"); v.reserve(len + 1000); - EXPECT_EQ(tracker.instances(), len); - EXPECT_EQ(tracker.copies() + tracker.moves(), len); + EXPECT_EQ(tracker.instances(), static_cast<int>(len)); + EXPECT_EQ(tracker.copies() + tracker.moves(), static_cast<int>(len)); // pop_back() and erase() must destroy one object if (len > 0) { tracker.ResetCopiesMovesSwaps(); v.pop_back(); - EXPECT_EQ(tracker.instances(), len - 1); + EXPECT_EQ(tracker.instances(), static_cast<int>(len) - 1); EXPECT_EQ(tracker.copies(), 0); EXPECT_EQ(tracker.moves(), 0); if (!v.empty()) { tracker.ResetCopiesMovesSwaps(); v.erase(v.begin()); - EXPECT_EQ(tracker.instances(), len - 2); - EXPECT_EQ(tracker.copies() + tracker.moves(), len - 2); + EXPECT_EQ(tracker.instances(), static_cast<int>(len) - 2); + EXPECT_EQ(tracker.copies() + tracker.moves(), + static_cast<int>(len) - 2); } } @@ -1087,12 +1090,12 @@ tracker.ResetCopiesMovesSwaps(); { InstanceVec v_copy(std::move(v)); - if (len > inlined_capacity) { + if (static_cast<size_t>(len) > inlined_capacity) { // Allocation is moved as a whole. EXPECT_EQ(tracker.instances(), len); EXPECT_EQ(tracker.live_instances(), len); // Tests an implementation detail, don't rely on this in your code. - EXPECT_EQ(v.size(), 0); // NOLINT misc-use-after-move + EXPECT_EQ(v.size(), 0u); // NOLINT misc-use-after-move EXPECT_EQ(tracker.copies(), 0); EXPECT_EQ(tracker.moves(), 0); } else { @@ -1158,7 +1161,7 @@ tracker.ResetCopiesMovesSwaps(); InstanceVec longer, shorter; - const int inlined_capacity = longer.capacity(); + const size_t inlined_capacity = longer.capacity(); for (int i = 0; i < len; i++) { longer.push_back(Instance(i)); shorter.push_back(Instance(i)); @@ -1177,7 +1180,7 @@ src_len = len; longer = std::move(shorter); } - if (src_len > inlined_capacity) { + if (static_cast<size_t>(src_len) > inlined_capacity) { // Allocation moved as a whole. EXPECT_EQ(tracker.instances(), src_len); EXPECT_EQ(tracker.live_instances(), src_len); @@ -1210,10 +1213,10 @@ absl::InlinedVector<int, 2> v(original_contents.begin(), original_contents.end()); v.assign(2, 123); - EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(123, 123))); + EXPECT_THAT(v, AllOf(SizeIs(2u), ElementsAre(123, 123))); if (original_size <= 2) { // If the original had inline backing, it should stay inline. - EXPECT_EQ(2, v.capacity()); + EXPECT_EQ(2u, v.capacity()); } } } @@ -1227,7 +1230,7 @@ absl::InlinedVector<int, 2> v(original_contents.begin(), original_contents.end()); v.assign(3, 123); - EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(123, 123, 123))); + EXPECT_THAT(v, AllOf(SizeIs(3u), ElementsAre(123, 123, 123))); EXPECT_LE(v.size(), v.capacity()); } } @@ -1242,10 +1245,10 @@ absl::InlinedVector<Instance, 2> v(original_contents.begin(), original_contents.end()); v.assign(2, Instance(123)); - EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(ValueIs(123), ValueIs(123)))); + EXPECT_THAT(v, AllOf(SizeIs(2u), ElementsAre(ValueIs(123), ValueIs(123)))); if (original_size <= 2) { // If the original had inline backing, it should stay inline. - EXPECT_EQ(2, v.capacity()); + EXPECT_EQ(2u, v.capacity()); } } } @@ -1260,8 +1263,8 @@ absl::InlinedVector<Instance, 2> v(original_contents.begin(), original_contents.end()); v.assign(3, Instance(123)); - EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(ValueIs(123), ValueIs(123), - ValueIs(123)))); + EXPECT_THAT(v, AllOf(SizeIs(3u), ElementsAre(ValueIs(123), ValueIs(123), + ValueIs(123)))); EXPECT_LE(v.size(), v.capacity()); } } @@ -1276,16 +1279,17 @@ std::vector<int> source_v = {4, 5, 6}; // First try to fit in inline backing absl::InlinedVector<int, 4> v(source_v.begin(), source_v.end()); - EXPECT_EQ(3, v.size()); - EXPECT_EQ(4, v.capacity()); // Indication that we're still on inlined storage + EXPECT_EQ(3u, v.size()); + EXPECT_EQ(4u, + v.capacity()); // Indication that we're still on inlined storage EXPECT_EQ(4, v[0]); EXPECT_EQ(5, v[1]); EXPECT_EQ(6, v[2]); // Now, force a re-allocate absl::InlinedVector<int, 2> realloc_v(source_v.begin(), source_v.end()); - EXPECT_EQ(3, realloc_v.size()); - EXPECT_LT(2, realloc_v.capacity()); + EXPECT_EQ(3u, realloc_v.size()); + EXPECT_LT(2u, realloc_v.capacity()); EXPECT_EQ(4, realloc_v[0]); EXPECT_EQ(5, realloc_v[1]); EXPECT_EQ(6, realloc_v[2]); @@ -1300,8 +1304,8 @@ tracker.ResetCopiesMovesSwaps(); absl::InlinedVector<Instance, inlined_capacity> v(source_v.begin(), source_v.end()); - EXPECT_EQ(2, v.size()); - EXPECT_LT(1, v.capacity()); + EXPECT_EQ(2u, v.size()); + EXPECT_LT(1u, v.capacity()); EXPECT_EQ(0, v[0].value()); EXPECT_EQ(1, v[1].value()); EXPECT_EQ(tracker.copies(), 2); @@ -1360,12 +1364,12 @@ // Original contents are [12345, 12345, ...] std::vector<int> original_contents(original_size, 12345); - for (size_t target_size = 0; target_size <= 5; ++target_size) { + for (int target_size = 0; target_size <= 5; ++target_size) { SCOPED_TRACE(target_size); // New contents are [3, 4, ...] std::vector<int> new_contents; - for (size_t i = 0; i < target_size; ++i) { + for (int i = 0; i < target_size; ++i) { new_contents.push_back(i + 3); } @@ -1377,7 +1381,7 @@ EXPECT_LE(new_contents.size(), v.capacity()); if (target_size <= 3 && original_size <= 3) { // Storage should stay inline when target size is small. - EXPECT_EQ(3, v.capacity()); + EXPECT_EQ(3u, v.capacity()); } EXPECT_THAT(v, ElementsAreArray(new_contents)); } @@ -1410,7 +1414,7 @@ // TODO(bsamwel): Test with an input iterator. std::vector<Instance> new_contents_in; for (size_t i = 0; i < target_size; ++i) { - new_contents_in.push_back(Instance(i + 3)); + new_contents_in.push_back(Instance(static_cast<int>(i) + 3)); } SourceContainer new_contents(new_contents_in.begin(), new_contents_in.end()); @@ -1423,7 +1427,7 @@ EXPECT_LE(new_contents.size(), v.capacity()); if (target_size <= 3 && original_size <= 3) { // Storage should stay inline when target size is small. - EXPECT_EQ(3, v.capacity()); + EXPECT_EQ(3u, v.capacity()); } EXPECT_TRUE(std::equal(v.begin(), v.end(), new_contents.begin(), InstanceValuesEqual<Instance>)); @@ -1447,12 +1451,12 @@ TEST(InitializerListConstructor, SimpleTypeWithInlineBacking) { EXPECT_THAT((absl::InlinedVector<int, 4>{4, 5, 6}), - AllOf(SizeIs(3), CapacityIs(4), ElementsAre(4, 5, 6))); + AllOf(SizeIs(3u), CapacityIs(4u), ElementsAre(4, 5, 6))); } TEST(InitializerListConstructor, SimpleTypeWithReallocationRequired) { EXPECT_THAT((absl::InlinedVector<int, 2>{4, 5, 6}), - AllOf(SizeIs(3), CapacityIs(Gt(2)), ElementsAre(4, 5, 6))); + AllOf(SizeIs(3u), CapacityIs(Gt(2u)), ElementsAre(4, 5, 6))); } TEST(InitializerListConstructor, DisparateTypesInList) { @@ -1465,14 +1469,14 @@ TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) { EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{ CopyableMovableInstance(0)}), - AllOf(SizeIs(1), CapacityIs(1), ElementsAre(ValueIs(0)))); + AllOf(SizeIs(1u), CapacityIs(1u), ElementsAre(ValueIs(0)))); } TEST(InitializerListConstructor, ComplexTypeWithReallocationRequired) { - EXPECT_THAT( - (absl::InlinedVector<CopyableMovableInstance, 1>{ - CopyableMovableInstance(0), CopyableMovableInstance(1)}), - AllOf(SizeIs(2), CapacityIs(Gt(1)), ElementsAre(ValueIs(0), ValueIs(1)))); + EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{ + CopyableMovableInstance(0), CopyableMovableInstance(1)}), + AllOf(SizeIs(2u), CapacityIs(Gt(1u)), + ElementsAre(ValueIs(0), ValueIs(1)))); } TEST(InitializerListAssign, SimpleTypeFitsInlineBacking) { @@ -1482,14 +1486,14 @@ absl::InlinedVector<int, 2> v1(original_size, 12345); const size_t original_capacity_v1 = v1.capacity(); v1.assign({3}); - EXPECT_THAT( - v1, AllOf(SizeIs(1), CapacityIs(original_capacity_v1), ElementsAre(3))); + EXPECT_THAT(v1, AllOf(SizeIs(1u), CapacityIs(original_capacity_v1), + ElementsAre(3))); absl::InlinedVector<int, 2> v2(original_size, 12345); const size_t original_capacity_v2 = v2.capacity(); v2 = {3}; - EXPECT_THAT( - v2, AllOf(SizeIs(1), CapacityIs(original_capacity_v2), ElementsAre(3))); + EXPECT_THAT(v2, AllOf(SizeIs(1u), CapacityIs(original_capacity_v2), + ElementsAre(3))); } } @@ -1498,13 +1502,13 @@ SCOPED_TRACE(original_size); absl::InlinedVector<int, 2> v1(original_size, 12345); v1.assign({3, 4, 5}); - EXPECT_THAT(v1, AllOf(SizeIs(3), ElementsAre(3, 4, 5))); - EXPECT_LE(3, v1.capacity()); + EXPECT_THAT(v1, AllOf(SizeIs(3u), ElementsAre(3, 4, 5))); + EXPECT_LE(3u, v1.capacity()); absl::InlinedVector<int, 2> v2(original_size, 12345); v2 = {3, 4, 5}; - EXPECT_THAT(v2, AllOf(SizeIs(3), ElementsAre(3, 4, 5))); - EXPECT_LE(3, v2.capacity()); + EXPECT_THAT(v2, AllOf(SizeIs(3u), ElementsAre(3, 4, 5))); + EXPECT_LE(3u, v2.capacity()); } } @@ -1533,7 +1537,7 @@ absl::InlinedVector<Instance, 2> v(original_size, Instance(12345)); const size_t original_capacity = v.capacity(); v.assign({Instance(3)}); - EXPECT_THAT(v, AllOf(SizeIs(1), CapacityIs(original_capacity), + EXPECT_THAT(v, AllOf(SizeIs(1u), CapacityIs(original_capacity), ElementsAre(ValueIs(3)))); } for (size_t original_size = 0; original_size <= 4; ++original_size) { @@ -1541,8 +1545,8 @@ absl::InlinedVector<Instance, 2> v(original_size, Instance(12345)); v.assign({Instance(3), Instance(4), Instance(5)}); EXPECT_THAT( - v, AllOf(SizeIs(3), ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5)))); - EXPECT_LE(3, v.capacity()); + v, AllOf(SizeIs(3u), ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5)))); + EXPECT_LE(3u, v.capacity()); } } @@ -1588,54 +1592,54 @@ MyAlloc alloc(&allocated); { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + 4, alloc); - EXPECT_THAT(allocated, 0); + EXPECT_THAT(allocated, Eq(0)); } - EXPECT_THAT(allocated, 0); + EXPECT_THAT(allocated, Eq(0)); { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); - EXPECT_THAT(allocated, v.size() * sizeof(int)); + EXPECT_THAT(allocated, Eq(static_cast<int64_t>(v.size() * sizeof(int)))); } - EXPECT_THAT(allocated, 0); + EXPECT_THAT(allocated, Eq(0)); { AllocVec v(4, 1, alloc); - EXPECT_THAT(allocated, 0); + EXPECT_THAT(allocated, Eq(0)); int64_t allocated2 = 0; MyAlloc alloc2(&allocated2); AllocVec v2(v, alloc2); - EXPECT_THAT(allocated2, 0); + EXPECT_THAT(allocated2, Eq(0)); int64_t allocated3 = 0; MyAlloc alloc3(&allocated3); AllocVec v3(std::move(v), alloc3); - EXPECT_THAT(allocated3, 0); + EXPECT_THAT(allocated3, Eq(0)); } EXPECT_THAT(allocated, 0); { AllocVec v(8, 2, alloc); - EXPECT_THAT(allocated, v.size() * sizeof(int)); + EXPECT_THAT(allocated, Eq(static_cast<int64_t>(v.size() * sizeof(int)))); int64_t allocated2 = 0; MyAlloc alloc2(&allocated2); AllocVec v2(v, alloc2); - EXPECT_THAT(allocated2, v2.size() * sizeof(int)); + EXPECT_THAT(allocated2, Eq(static_cast<int64_t>(v2.size() * sizeof(int)))); int64_t allocated3 = 0; MyAlloc alloc3(&allocated3); AllocVec v3(std::move(v), alloc3); - EXPECT_THAT(allocated3, v3.size() * sizeof(int)); + EXPECT_THAT(allocated3, Eq(static_cast<int64_t>(v3.size() * sizeof(int)))); } EXPECT_EQ(allocated, 0); { // Test shrink_to_fit deallocations. AllocVec v(8, 2, alloc); - EXPECT_EQ(allocated, 8 * sizeof(int)); + EXPECT_EQ(allocated, static_cast<int64_t>(8 * sizeof(int))); v.resize(5); - EXPECT_EQ(allocated, 8 * sizeof(int)); + EXPECT_EQ(allocated, static_cast<int64_t>(8 * sizeof(int))); v.shrink_to_fit(); - EXPECT_EQ(allocated, 5 * sizeof(int)); + EXPECT_EQ(allocated, static_cast<int64_t>(5 * sizeof(int))); v.resize(4); - EXPECT_EQ(allocated, 5 * sizeof(int)); + EXPECT_EQ(allocated, static_cast<int64_t>(5 * sizeof(int))); v.shrink_to_fit(); EXPECT_EQ(allocated, 0); } @@ -1654,13 +1658,17 @@ AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1); AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2); EXPECT_LT(v1.capacity(), v2.capacity()); - EXPECT_THAT(allocated1, v1.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, v2.capacity() * sizeof(int)); + EXPECT_THAT(allocated1, + Eq(static_cast<int64_t>(v1.capacity() * sizeof(int)))); + EXPECT_THAT(allocated2, + Eq(static_cast<int64_t>(v2.capacity() * sizeof(int)))); v1.swap(v2); EXPECT_THAT(v1, ElementsAreArray(ia2)); EXPECT_THAT(v2, ElementsAreArray(ia1)); - EXPECT_THAT(allocated1, v2.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, v1.capacity() * sizeof(int)); + EXPECT_THAT(allocated1, + Eq(static_cast<int64_t>(v2.capacity() * sizeof(int)))); + EXPECT_THAT(allocated2, + Eq(static_cast<int64_t>(v1.capacity() * sizeof(int)))); } EXPECT_THAT(allocated1, 0); EXPECT_THAT(allocated2, 0); @@ -1678,13 +1686,15 @@ MyAlloc a2(&allocated2); AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1); AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2); - EXPECT_THAT(allocated1, v1.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, 0); + EXPECT_THAT(allocated1, + Eq(static_cast<int64_t>(v1.capacity() * sizeof(int)))); + EXPECT_THAT(allocated2, Eq(0)); v1.swap(v2); EXPECT_THAT(v1, ElementsAreArray(ia2)); EXPECT_THAT(v2, ElementsAreArray(ia1)); - EXPECT_THAT(allocated1, v2.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, 0); + EXPECT_THAT(allocated1, + Eq(static_cast<int64_t>(v2.capacity() * sizeof(int)))); + EXPECT_THAT(allocated2, Eq(0)); EXPECT_TRUE(v2.get_allocator() == a1); EXPECT_TRUE(v1.get_allocator() == a2); } @@ -1746,7 +1756,7 @@ } TEST(AllocatorSupportTest, SizeAllocConstructor) { - constexpr int inlined_size = 4; + constexpr size_t inlined_size = 4; using Alloc = CountingAllocator<int>; using AllocVec = absl::InlinedVector<int, inlined_size, Alloc>; @@ -1756,7 +1766,7 @@ auto v = AllocVec(len, Alloc(&allocated)); // Inline storage used; allocator should not be invoked - EXPECT_THAT(allocated, 0); + EXPECT_THAT(allocated, Eq(0)); EXPECT_THAT(v, AllOf(SizeIs(len), Each(0))); } @@ -1766,7 +1776,7 @@ auto v = AllocVec(len, Alloc(&allocated)); // Out of line storage used; allocation of 8 elements expected - EXPECT_THAT(allocated, len * sizeof(int)); + EXPECT_THAT(allocated, Eq(static_cast<int64_t>(len * sizeof(int)))); EXPECT_THAT(v, AllOf(SizeIs(len), Each(0))); } } @@ -1801,9 +1811,9 @@ // Generate a variety of vectors some of these are small enough for the inline // space but are stored out of line. - for (int i = 0; i < 10; ++i) { + for (size_t i = 0; i < 10; ++i) { V v; - for (int j = 0; j < i; ++j) { + for (int j = 0; j < static_cast<int>(i); ++j) { v.push_back(j); } cases.push_back(v);
diff --git a/third_party/abseil-cpp/absl/container/internal/btree.h b/third_party/abseil-cpp/absl/container/internal/btree.h index 64a610a..bdf2446 100644 --- a/third_party/abseil-cpp/absl/container/internal/btree.h +++ b/third_party/abseil-cpp/absl/container/internal/btree.h
@@ -100,7 +100,7 @@ StringBtreeDefaultLess() = default; // Compatibility constructor. - StringBtreeDefaultLess(std::less<std::string>) {} // NOLINT + StringBtreeDefaultLess(std::less<std::string>) {} // NOLINT StringBtreeDefaultLess(std::less<absl::string_view>) {} // NOLINT // Allow converting to std::less for use in key_comp()/value_comp(). @@ -132,7 +132,7 @@ StringBtreeDefaultGreater() = default; - StringBtreeDefaultGreater(std::greater<std::string>) {} // NOLINT + StringBtreeDefaultGreater(std::greater<std::string>) {} // NOLINT StringBtreeDefaultGreater(std::greater<absl::string_view>) {} // NOLINT // Allow converting to std::greater for use in key_comp()/value_comp(). @@ -376,8 +376,7 @@ std::is_same<key_compare, StringBtreeDefaultLess>::value || std::is_same<key_compare, StringBtreeDefaultGreater>::value; static constexpr bool kIsKeyCompareTransparent = - IsTransparent<original_key_compare>::value || - kIsKeyCompareStringAdapted; + IsTransparent<original_key_compare>::value || kIsKeyCompareStringAdapted; static constexpr bool kEnableGenerations = #ifdef ABSL_BTREE_ENABLE_GENERATIONS true; @@ -430,8 +429,7 @@ // Upper bound for the available space for slots. This is largest for leaf // nodes, which have overhead of at least a pointer + 4 bytes (for storing // 3 field_types and an enum). - kNodeSlotSpace = - TargetNodeSize - /*minimum overhead=*/(sizeof(void *) + 4), + kNodeSlotSpace = TargetNodeSize - /*minimum overhead=*/(sizeof(void *) + 4), }; // This is an integral type large enough to hold as many slots as will fit a @@ -450,7 +448,7 @@ return slot_policy::element(slot); } template <class... Args> - static void construct(Alloc *alloc, slot_type *slot, Args &&... args) { + static void construct(Alloc *alloc, slot_type *slot, Args &&...args) { slot_policy::construct(alloc, slot, std::forward<Args>(args)...); } static void construct(Alloc *alloc, slot_type *slot, slot_type *other) { @@ -628,33 +626,33 @@ constexpr static size_type NodeTargetSlots(const size_type begin, const size_type end) { return begin == end ? begin - : SizeWithNSlots((begin + end) / 2 + 1) > - params_type::kTargetNodeSize - ? NodeTargetSlots(begin, (begin + end) / 2) - : NodeTargetSlots((begin + end) / 2 + 1, end); + : SizeWithNSlots((begin + end) / 2 + 1) > + params_type::kTargetNodeSize + ? NodeTargetSlots(begin, (begin + end) / 2) + : NodeTargetSlots((begin + end) / 2 + 1, end); } - enum { - kTargetNodeSize = params_type::kTargetNodeSize, - kNodeTargetSlots = NodeTargetSlots(0, params_type::kTargetNodeSize), + constexpr static size_type kTargetNodeSize = params_type::kTargetNodeSize; + constexpr static size_type kNodeTargetSlots = + NodeTargetSlots(0, kTargetNodeSize); - // We need a minimum of 3 slots per internal node in order to perform - // splitting (1 value for the two nodes involved in the split and 1 value - // propagated to the parent as the delimiter for the split). For performance - // reasons, we don't allow 3 slots-per-node due to bad worst case occupancy - // of 1/3 (for a node, not a b-tree). - kMinNodeSlots = 4, + // We need a minimum of 3 slots per internal node in order to perform + // splitting (1 value for the two nodes involved in the split and 1 value + // propagated to the parent as the delimiter for the split). For performance + // reasons, we don't allow 3 slots-per-node due to bad worst case occupancy of + // 1/3 (for a node, not a b-tree). + constexpr static size_type kMinNodeSlots = 4; - kNodeSlots = - kNodeTargetSlots >= kMinNodeSlots ? kNodeTargetSlots : kMinNodeSlots, + constexpr static size_type kNodeSlots = + kNodeTargetSlots >= kMinNodeSlots ? kNodeTargetSlots : kMinNodeSlots; - // The node is internal (i.e. is not a leaf node) if and only if `max_count` - // has this value. - kInternalNodeMaxCount = 0, - }; + // The node is internal (i.e. is not a leaf node) if and only if `max_count` + // has this value. + constexpr static field_type kInternalNodeMaxCount = 0; // Leaves can have less than kNodeSlots values. - constexpr static layout_type LeafLayout(const int slot_count = kNodeSlots) { + constexpr static layout_type LeafLayout( + const size_type slot_count = kNodeSlots) { return layout_type( /*parent*/ 1, /*generation*/ params_type::kEnableGenerations ? 1 : 0, @@ -670,7 +668,7 @@ /*slots*/ kNodeSlots, /*children*/ kNodeSlots + 1); } - constexpr static size_type LeafSize(const int slot_count = kNodeSlots) { + constexpr static size_type LeafSize(const size_type slot_count = kNodeSlots) { return LeafLayout(slot_count).AllocSize(); } constexpr static size_type InternalSize() { @@ -693,10 +691,10 @@ } void set_parent(btree_node *p) { *GetField<0>() = p; } field_type &mutable_finish() { return GetField<2>()[2]; } - slot_type *slot(int i) { return &GetField<3>()[i]; } + slot_type *slot(size_type i) { return &GetField<3>()[i]; } slot_type *start_slot() { return slot(start()); } slot_type *finish_slot() { return slot(finish()); } - const slot_type *slot(int i) const { return &GetField<3>()[i]; } + const slot_type *slot(size_type i) const { return &GetField<3>()[i]; } void set_position(field_type v) { GetField<2>()[0] = v; } void set_start(field_type v) { GetField<2>()[1] = v; } void set_finish(field_type v) { GetField<2>()[2] = v; } @@ -773,51 +771,53 @@ } // Getters for the key/value at position i in the node. - const key_type &key(int i) const { return params_type::key(slot(i)); } - reference value(int i) { return params_type::element(slot(i)); } - const_reference value(int i) const { return params_type::element(slot(i)); } + const key_type &key(size_type i) const { return params_type::key(slot(i)); } + reference value(size_type i) { return params_type::element(slot(i)); } + const_reference value(size_type i) const { + return params_type::element(slot(i)); + } // Getters/setter for the child at position i in the node. - btree_node *child(int i) const { return GetField<4>()[i]; } + btree_node *child(field_type i) const { return GetField<4>()[i]; } btree_node *start_child() const { return child(start()); } - btree_node *&mutable_child(int i) { return GetField<4>()[i]; } - void clear_child(int i) { + btree_node *&mutable_child(field_type i) { return GetField<4>()[i]; } + void clear_child(field_type i) { absl::container_internal::SanitizerPoisonObject(&mutable_child(i)); } - void set_child(int i, btree_node *c) { + void set_child(field_type i, btree_node *c) { absl::container_internal::SanitizerUnpoisonObject(&mutable_child(i)); mutable_child(i) = c; c->set_position(i); } - void init_child(int i, btree_node *c) { + void init_child(field_type i, btree_node *c) { set_child(i, c); c->set_parent(this); } // Returns the position of the first value whose key is not less than k. template <typename K> - SearchResult<int, is_key_compare_to::value> lower_bound( + SearchResult<size_type, is_key_compare_to::value> lower_bound( const K &k, const key_compare &comp) const { return use_linear_search::value ? linear_search(k, comp) : binary_search(k, comp); } // Returns the position of the first value whose key is greater than k. template <typename K> - int upper_bound(const K &k, const key_compare &comp) const { + size_type upper_bound(const K &k, const key_compare &comp) const { auto upper_compare = upper_bound_adapter<key_compare>(comp); return use_linear_search::value ? linear_search(k, upper_compare).value : binary_search(k, upper_compare).value; } template <typename K, typename Compare> - SearchResult<int, btree_is_key_compare_to<Compare, key_type>::value> + SearchResult<size_type, btree_is_key_compare_to<Compare, key_type>::value> linear_search(const K &k, const Compare &comp) const { return linear_search_impl(k, start(), finish(), comp, btree_is_key_compare_to<Compare, key_type>()); } template <typename K, typename Compare> - SearchResult<int, btree_is_key_compare_to<Compare, key_type>::value> + SearchResult<size_type, btree_is_key_compare_to<Compare, key_type>::value> binary_search(const K &k, const Compare &comp) const { return binary_search_impl(k, start(), finish(), comp, btree_is_key_compare_to<Compare, key_type>()); @@ -826,8 +826,8 @@ // Returns the position of the first value whose key is not less than k using // linear search performed using plain compare. template <typename K, typename Compare> - SearchResult<int, false> linear_search_impl( - const K &k, int s, const int e, const Compare &comp, + SearchResult<size_type, false> linear_search_impl( + const K &k, size_type s, const size_type e, const Compare &comp, std::false_type /* IsCompareTo */) const { while (s < e) { if (!comp(key(s), k)) { @@ -835,14 +835,14 @@ } ++s; } - return SearchResult<int, false>{s}; + return SearchResult<size_type, false>{s}; } // Returns the position of the first value whose key is not less than k using // linear search performed using compare-to. template <typename K, typename Compare> - SearchResult<int, true> linear_search_impl( - const K &k, int s, const int e, const Compare &comp, + SearchResult<size_type, true> linear_search_impl( + const K &k, size_type s, const size_type e, const Compare &comp, std::true_type /* IsCompareTo */) const { while (s < e) { const absl::weak_ordering c = comp(key(s), k); @@ -859,30 +859,30 @@ // Returns the position of the first value whose key is not less than k using // binary search performed using plain compare. template <typename K, typename Compare> - SearchResult<int, false> binary_search_impl( - const K &k, int s, int e, const Compare &comp, + SearchResult<size_type, false> binary_search_impl( + const K &k, size_type s, size_type e, const Compare &comp, std::false_type /* IsCompareTo */) const { while (s != e) { - const int mid = (s + e) >> 1; + const size_type mid = (s + e) >> 1; if (comp(key(mid), k)) { s = mid + 1; } else { e = mid; } } - return SearchResult<int, false>{s}; + return SearchResult<size_type, false>{s}; } // Returns the position of the first value whose key is not less than k using // binary search performed using compare-to. template <typename K, typename CompareTo> - SearchResult<int, true> binary_search_impl( - const K &k, int s, int e, const CompareTo &comp, + SearchResult<size_type, true> binary_search_impl( + const K &k, size_type s, size_type e, const CompareTo &comp, std::true_type /* IsCompareTo */) const { if (params_type::template can_have_multiple_equivalent_keys<K>()) { MatchKind exact_match = MatchKind::kNe; while (s != e) { - const int mid = (s + e) >> 1; + const size_type mid = (s + e) >> 1; const absl::weak_ordering c = comp(key(mid), k); if (c < 0) { s = mid + 1; @@ -899,7 +899,7 @@ return {s, exact_match}; } else { // Can't have multiple equivalent keys. while (s != e) { - const int mid = (s + e) >> 1; + const size_type mid = (s + e) >> 1; const absl::weak_ordering c = comp(key(mid), k); if (c < 0) { s = mid + 1; @@ -916,7 +916,7 @@ // Emplaces a value at position i, shifting all existing values and // children at positions >= i to the right by 1. template <typename... Args> - void emplace_value(size_type i, allocator_type *alloc, Args &&... args); + void emplace_value(field_type i, allocator_type *alloc, Args &&...args); // Removes the values at positions [i, i + to_erase), shifting all existing // values and children after that range to the left by to_erase. Clears all @@ -924,9 +924,9 @@ void remove_values(field_type i, field_type to_erase, allocator_type *alloc); // Rebalances a node with its right sibling. - void rebalance_right_to_left(int to_move, btree_node *right, + void rebalance_right_to_left(field_type to_move, btree_node *right, allocator_type *alloc); - void rebalance_left_to_right(int to_move, btree_node *right, + void rebalance_left_to_right(field_type to_move, btree_node *right, allocator_type *alloc); // Splits a node, moving a portion of the node's values to its right sibling. @@ -937,7 +937,7 @@ void merge(btree_node *src, allocator_type *alloc); // Node allocation/deletion routines. - void init_leaf(int max_count, btree_node *parent) { + void init_leaf(field_type max_count, btree_node *parent) { set_generation(0); set_parent(parent); set_position(0); @@ -966,7 +966,7 @@ private: template <typename... Args> - void value_init(const field_type i, allocator_type *alloc, Args &&... args) { + void value_init(const field_type i, allocator_type *alloc, Args &&...args) { next_generation(); absl::container_internal::SanitizerUnpoisonObject(slot(i)); params_type::construct(alloc, slot(i), std::forward<Args>(args)...); @@ -1017,10 +1017,15 @@ const size_type src_i, btree_node *src_node, allocator_type *alloc) { next_generation(); - for (slot_type *src = src_node->slot(src_i + n - 1), *end = src - n, - *dest = slot(dest_i + n - 1); + for (slot_type *src = src_node->slot(src_i + n), *end = src - n, + *dest = slot(dest_i + n); src != end; --src, --dest) { - transfer(dest, src, alloc); + // If we modified the loop index calculations above to avoid the -1s here, + // it would result in UB in the computation of `end` (and possibly `src` + // as well, if n == 0), since slot() is effectively an array index and it + // is UB to compute the address of any out-of-bounds array element except + // for one-past-the-end. + transfer(dest - 1, src - 1, alloc); } } @@ -1034,6 +1039,7 @@ template <typename Node, typename Reference, typename Pointer> class btree_iterator { + using field_type = typename Node::field_type; using key_type = typename Node::key_type; using size_type = typename Node::size_type; using params_type = typename Node::params_type; @@ -1105,7 +1111,7 @@ ABSL_HARDENING_ASSERT(node_->start() <= position_); ABSL_HARDENING_ASSERT(node_->finish() > position_); assert_valid_generation(); - return node_->value(position_); + return node_->value(static_cast<field_type>(position_)); } pointer operator->() const { return &operator*(); } @@ -1189,9 +1195,11 @@ #endif } - const key_type &key() const { return node_->key(position_); } + const key_type &key() const { + return node_->key(static_cast<size_type>(position_)); + } decltype(std::declval<Node *>()->slot(0)) slot() { - return node_->slot(position_); + return node_->slot(static_cast<size_type>(position_)); } void assert_valid_generation() const { @@ -1405,7 +1413,7 @@ // Requirement: if `key` already exists in the btree, does not consume `args`. // Requirement: `key` is never referenced after consuming `args`. template <typename K, typename... Args> - std::pair<iterator, bool> insert_unique(const K &key, Args &&... args); + std::pair<iterator, bool> insert_unique(const K &key, Args &&...args); // Inserts with hint. Checks to see if the value should be placed immediately // before `position` in the tree. If so, then the insertion will take @@ -1414,9 +1422,8 @@ // Requirement: if `key` already exists in the btree, does not consume `args`. // Requirement: `key` is never referenced after consuming `args`. template <typename K, typename... Args> - std::pair<iterator, bool> insert_hint_unique(iterator position, - const K &key, - Args &&... args); + std::pair<iterator, bool> insert_hint_unique(iterator position, const K &key, + Args &&...args); // Insert a range of values into the btree. // Note: the first overload avoids constructing a value_type if the key @@ -1543,8 +1550,7 @@ static double average_bytes_per_value() { // The expected number of values per node with random insertion order is the // average of the maximum and minimum numbers of values per node. - const double expected_values_per_node = - (kNodeSlots + kMinNodeValues) / 2.0; + const double expected_values_per_node = (kNodeSlots + kMinNodeValues) / 2.0; return node_type::LeafSize() / expected_values_per_node; } @@ -1600,7 +1606,7 @@ // Allocates a correctly aligned node of at least size bytes using the // allocator. - node_type *allocate(const size_type size) { + node_type *allocate(size_type size) { return reinterpret_cast<node_type *>( absl::container_internal::Allocate<node_type::Alignment()>( mutable_allocator(), size)); @@ -1617,7 +1623,7 @@ n->init_leaf(kNodeSlots, parent); return n; } - node_type *new_leaf_root_node(const int max_count) { + node_type *new_leaf_root_node(field_type max_count) { node_type *n = allocate(node_type::LeafSize(max_count)); n->init_leaf(max_count, /*parent=*/n); return n; @@ -1652,7 +1658,7 @@ // Emplaces a value into the btree immediately before iter. Requires that // key(v) <= iter.key() and (--iter).key() <= key(v). template <typename... Args> - iterator internal_emplace(iterator iter, Args &&... args); + iterator internal_emplace(iterator iter, Args &&...args); // Returns an iterator pointing to the first value >= the value "iter" is // pointing at. Note that "iter" might be pointing to an invalid location such @@ -1685,8 +1691,8 @@ iterator internal_find(const K &key) const; // Verifies the tree structure of node. - int internal_verify(const node_type *node, const key_type *lo, - const key_type *hi) const; + size_type internal_verify(const node_type *node, const key_type *lo, + const key_type *hi) const; node_stats internal_stats(const node_type *node) const { // The root can be a static empty node. @@ -1720,9 +1726,9 @@ // btree_node methods template <typename P> template <typename... Args> -inline void btree_node<P>::emplace_value(const size_type i, +inline void btree_node<P>::emplace_value(const field_type i, allocator_type *alloc, - Args &&... args) { + Args &&...args) { assert(i >= start()); assert(i <= finish()); // Shift old values to create space for new value and then construct it in @@ -1731,7 +1737,7 @@ transfer_n_backward(finish() - i, /*dest_i=*/i + 1, /*src_i=*/i, this, alloc); } - value_init(i, alloc, std::forward<Args>(args)...); + value_init(static_cast<field_type>(i), alloc, std::forward<Args>(args)...); set_finish(finish() + 1); if (is_internal() && finish() > i + 1) { @@ -1767,7 +1773,7 @@ } template <typename P> -void btree_node<P>::rebalance_right_to_left(const int to_move, +void btree_node<P>::rebalance_right_to_left(field_type to_move, btree_node *right, allocator_type *alloc) { assert(parent() == right->parent()); @@ -1791,10 +1797,10 @@ if (is_internal()) { // Move the child pointers from the right to the left node. - for (int i = 0; i < to_move; ++i) { + for (field_type i = 0; i < to_move; ++i) { init_child(finish() + i + 1, right->child(i)); } - for (int i = right->start(); i <= right->finish() - to_move; ++i) { + for (field_type i = right->start(); i <= right->finish() - to_move; ++i) { assert(i + to_move <= right->max_count()); right->init_child(i, right->child(i + to_move)); right->clear_child(i + to_move); @@ -1807,7 +1813,7 @@ } template <typename P> -void btree_node<P>::rebalance_left_to_right(const int to_move, +void btree_node<P>::rebalance_left_to_right(field_type to_move, btree_node *right, allocator_type *alloc) { assert(parent() == right->parent()); @@ -1838,11 +1844,11 @@ if (is_internal()) { // Move the child pointers from the left to the right node. - for (int i = right->finish(); i >= right->start(); --i) { - right->init_child(i + to_move, right->child(i)); - right->clear_child(i); + for (field_type i = right->finish() + 1; i > right->start(); --i) { + right->init_child(i - 1 + to_move, right->child(i - 1)); + right->clear_child(i - 1); } - for (int i = 1; i <= to_move; ++i) { + for (field_type i = 1; i <= to_move; ++i) { right->init_child(i - 1, child(finish() - to_move + i)); clear_child(finish() - to_move + i); } @@ -1883,7 +1889,7 @@ parent()->init_child(position() + 1, dest); if (is_internal()) { - for (int i = dest->start(), j = finish() + 1; i <= dest->finish(); + for (field_type i = dest->start(), j = finish() + 1; i <= dest->finish(); ++i, ++j) { assert(child(j) != nullptr); dest->init_child(i, child(j)); @@ -1944,15 +1950,15 @@ // instead of checking whether the parent is a leaf, we can remove this logic. btree_node *leftmost_leaf = node; #endif - // Use `int` because `pos` needs to be able to hold `kNodeSlots+1`, which - // isn't guaranteed to be a valid `field_type`. - int pos = node->position(); + // Use `size_type` because `pos` needs to be able to hold `kNodeSlots+1`, + // which isn't guaranteed to be a valid `field_type`. + size_type pos = node->position(); btree_node *parent = node->parent(); for (;;) { // In each iteration of the next loop, we delete one leaf node and go right. assert(pos <= parent->finish()); do { - node = parent->child(pos); + node = parent->child(static_cast<field_type>(pos)); if (node->is_internal()) { // Navigate to the leftmost leaf under node. while (node->is_internal()) node = node->start_child(); @@ -2004,7 +2010,7 @@ } } else { assert(position_ < node_->finish()); - node_ = node_->child(position_ + 1); + node_ = node_->child(static_cast<field_type>(position_ + 1)); while (node_->is_internal()) { node_ = node_->start_child(); } @@ -2028,7 +2034,7 @@ } } else { assert(position_ >= node_->start()); - node_ = node_->child(position_); + node_ = node_->child(static_cast<field_type>(position_)); while (node_->is_internal()) { node_ = node_->child(node_->finish()); } @@ -2131,7 +2137,7 @@ template <typename P> template <typename K, typename... Args> -auto btree<P>::insert_unique(const K &key, Args &&... args) +auto btree<P>::insert_unique(const K &key, Args &&...args) -> std::pair<iterator, bool> { if (empty()) { mutable_root() = mutable_rightmost() = new_leaf_root_node(1); @@ -2158,7 +2164,7 @@ template <typename P> template <typename K, typename... Args> inline auto btree<P>::insert_hint_unique(iterator position, const K &key, - Args &&... args) + Args &&...args) -> std::pair<iterator, bool> { if (!empty()) { if (position == end() || compare_keys(key, position.key())) { @@ -2475,16 +2481,19 @@ // We bias rebalancing based on the position being inserted. If we're // inserting at the end of the right node then we bias rebalancing to // fill up the left node. - int to_move = (kNodeSlots - left->count()) / - (1 + (insert_position < static_cast<int>(kNodeSlots))); - to_move = (std::max)(1, to_move); + field_type to_move = + (kNodeSlots - left->count()) / + (1 + (static_cast<field_type>(insert_position) < kNodeSlots)); + to_move = (std::max)(field_type{1}, to_move); - if (insert_position - to_move >= node->start() || - left->count() + to_move < static_cast<int>(kNodeSlots)) { + if (static_cast<field_type>(insert_position) - to_move >= + node->start() || + left->count() + to_move < kNodeSlots) { left->rebalance_right_to_left(to_move, node, mutable_allocator()); assert(node->max_count() - node->count() == to_move); - insert_position = insert_position - to_move; + insert_position = static_cast<int>( + static_cast<field_type>(insert_position) - to_move); if (insert_position < node->start()) { insert_position = insert_position + left->count() + 1; node = left; @@ -2504,12 +2513,13 @@ // We bias rebalancing based on the position being inserted. If we're // inserting at the beginning of the left node then we bias rebalancing // to fill up the right node. - int to_move = (static_cast<int>(kNodeSlots) - right->count()) / - (1 + (insert_position > node->start())); - to_move = (std::max)(1, to_move); + field_type to_move = (kNodeSlots - right->count()) / + (1 + (insert_position > node->start())); + to_move = (std::max)(field_type{1}, to_move); - if (insert_position <= node->finish() - to_move || - right->count() + to_move < static_cast<int>(kNodeSlots)) { + if (static_cast<field_type>(insert_position) <= + node->finish() - to_move || + right->count() + to_move < kNodeSlots) { node->rebalance_left_to_right(to_move, right, mutable_allocator()); if (insert_position > node->finish()) { @@ -2594,8 +2604,9 @@ // from the front of the tree. if (right->count() > kMinNodeValues && (iter->node_->count() == 0 || iter->position_ > iter->node_->start())) { - int to_move = (right->count() - iter->node_->count()) / 2; - to_move = (std::min)(to_move, right->count() - 1); + field_type to_move = (right->count() - iter->node_->count()) / 2; + to_move = + (std::min)(to_move, static_cast<field_type>(right->count() - 1)); iter->node_->rebalance_right_to_left(to_move, right, mutable_allocator()); return false; } @@ -2609,8 +2620,8 @@ if (left->count() > kMinNodeValues && (iter->node_->count() == 0 || iter->position_ < iter->node_->finish())) { - int to_move = (left->count() - iter->node_->count()) / 2; - to_move = (std::min)(to_move, left->count() - 1); + field_type to_move = (left->count() - iter->node_->count()) / 2; + to_move = (std::min)(to_move, static_cast<field_type>(left->count() - 1)); left->rebalance_left_to_right(to_move, iter->node_, mutable_allocator()); iter->position_ += to_move; return false; @@ -2655,7 +2666,7 @@ template <typename P> template <typename... Args> -inline auto btree<P>::internal_emplace(iterator iter, Args &&... args) +inline auto btree<P>::internal_emplace(iterator iter, Args &&...args) -> iterator { if (iter.node_->is_internal()) { // We can't insert on an internal node. Instead, we'll insert after the @@ -2671,8 +2682,8 @@ // Insertion into the root where the root is smaller than the full node // size. Simply grow the size of the root node. assert(iter.node_ == root()); - iter.node_ = - new_leaf_root_node((std::min<int>)(kNodeSlots, 2 * max_count)); + iter.node_ = new_leaf_root_node(static_cast<field_type>( + (std::min)(static_cast<int>(kNodeSlots), 2 * max_count))); // Transfer the values from the old root to the new root. node_type *old_root = root(); node_type *new_root = iter.node_; @@ -2687,7 +2698,8 @@ rebalance_or_split(&iter); } } - iter.node_->emplace_value(iter.position_, alloc, std::forward<Args>(args)...); + iter.node_->emplace_value(static_cast<field_type>(iter.position_), alloc, + std::forward<Args>(args)...); ++size_; iter.update_generation(); return iter; @@ -2699,9 +2711,9 @@ -> SearchResult<iterator, is_key_compare_to::value> { iterator iter(const_cast<node_type *>(root())); for (;;) { - SearchResult<int, is_key_compare_to::value> res = + SearchResult<size_type, is_key_compare_to::value> res = iter.node_->lower_bound(key, key_comp()); - iter.position_ = res.value; + iter.position_ = static_cast<int>(res.value); if (res.IsEq()) { return {iter, MatchKind::kEq}; } @@ -2712,7 +2724,7 @@ if (iter.node_->is_leaf()) { break; } - iter.node_ = iter.node_->child(iter.position_); + iter.node_ = iter.node_->child(static_cast<field_type>(iter.position_)); } // Note: in the non-key-compare-to case, the key may actually be equivalent // here (and the MatchKind::kNe is ignored). @@ -2729,16 +2741,16 @@ return ret; } iterator iter(const_cast<node_type *>(root())); - SearchResult<int, is_key_compare_to::value> res; + SearchResult<size_type, is_key_compare_to::value> res; bool seen_eq = false; for (;;) { res = iter.node_->lower_bound(key, key_comp()); - iter.position_ = res.value; + iter.position_ = static_cast<int>(res.value); if (iter.node_->is_leaf()) { break; } seen_eq = seen_eq || res.IsEq(); - iter.node_ = iter.node_->child(iter.position_); + iter.node_ = iter.node_->child(static_cast<field_type>(iter.position_)); } if (res.IsEq()) return {iter, MatchKind::kEq}; return {internal_last(iter), seen_eq ? MatchKind::kEq : MatchKind::kNe}; @@ -2749,11 +2761,11 @@ auto btree<P>::internal_upper_bound(const K &key) const -> iterator { iterator iter(const_cast<node_type *>(root())); for (;;) { - iter.position_ = iter.node_->upper_bound(key, key_comp()); + iter.position_ = static_cast<int>(iter.node_->upper_bound(key, key_comp())); if (iter.node_->is_leaf()) { break; } - iter.node_ = iter.node_->child(iter.position_); + iter.node_ = iter.node_->child(static_cast<field_type>(iter.position_)); } return internal_last(iter); } @@ -2776,8 +2788,8 @@ } template <typename P> -int btree<P>::internal_verify(const node_type *node, const key_type *lo, - const key_type *hi) const { +typename btree<P>::size_type btree<P>::internal_verify( + const node_type *node, const key_type *lo, const key_type *hi) const { assert(node->count() > 0); assert(node->count() <= node->max_count()); if (lo) { @@ -2789,9 +2801,9 @@ for (int i = node->start() + 1; i < node->finish(); ++i) { assert(!compare_keys(node->key(i), node->key(i - 1))); } - int count = node->count(); + size_type count = node->count(); if (node->is_internal()) { - for (int i = node->start(); i <= node->finish(); ++i) { + for (field_type i = node->start(); i <= node->finish(); ++i) { assert(node->child(i) != nullptr); assert(node->child(i)->parent() == node); assert(node->child(i)->position() == i); @@ -2805,8 +2817,8 @@ struct btree_access { template <typename BtreeContainer, typename Pred> - static auto erase_if(BtreeContainer &container, Pred pred) - -> typename BtreeContainer::size_type { + static auto erase_if(BtreeContainer &container, Pred pred) -> + typename BtreeContainer::size_type { const auto initial_size = container.size(); auto &tree = container.tree_; auto *alloc = tree.mutable_allocator();
diff --git a/third_party/abseil-cpp/absl/container/internal/inlined_vector.h b/third_party/abseil-cpp/absl/container/internal/inlined_vector.h index fdca306..a56b7573 100644 --- a/third_party/abseil-cpp/absl/container/internal/inlined_vector.h +++ b/third_party/abseil-cpp/absl/container/internal/inlined_vector.h
@@ -641,8 +641,8 @@ SizeType<A> insert_count) -> Iterator<A> { StorageView<A> storage_view = MakeStorageView(); - SizeType<A> insert_index = - std::distance(ConstIterator<A>(storage_view.data), pos); + auto insert_index = static_cast<SizeType<A>>( + std::distance(ConstIterator<A>(storage_view.data), pos)); SizeType<A> insert_end_index = insert_index + insert_count; SizeType<A> new_size = storage_view.size + insert_count;
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h index b8118cd..93de2221 100644 --- a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h +++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
@@ -612,9 +612,9 @@ NonIterableBitMask<uint64_t, kWidth, 3> MaskEmpty() const { uint64_t mask = - vget_lane_u64(vreinterpret_u64_u8( - vceq_s8(vdup_n_s8(static_cast<h2_t>(ctrl_t::kEmpty)), - vreinterpret_s8_u8(ctrl))), + vget_lane_u64(vreinterpret_u64_u8(vceq_s8( + vdup_n_s8(static_cast<int8_t>(ctrl_t::kEmpty)), + vreinterpret_s8_u8(ctrl))), 0); return NonIterableBitMask<uint64_t, kWidth, 3>(mask); } @@ -1144,11 +1144,12 @@ std::is_nothrow_default_constructible<key_equal>::value&& std::is_nothrow_default_constructible<allocator_type>::value) {} - explicit raw_hash_set(size_t bucket_count, const hasher& hash = hasher(), + explicit raw_hash_set(size_t bucket_count, + const hasher& hash = hasher(), const key_equal& eq = key_equal(), const allocator_type& alloc = allocator_type()) : ctrl_(EmptyGroup()), - settings_(0, HashtablezInfoHandle(), hash, eq, alloc) { + settings_(0u, HashtablezInfoHandle(), hash, eq, alloc) { if (bucket_count) { capacity_ = NormalizeCapacity(bucket_count); initialize_slots(); @@ -1273,14 +1274,16 @@ std::is_nothrow_copy_constructible<allocator_type>::value) : ctrl_(absl::exchange(that.ctrl_, EmptyGroup())), slots_(absl::exchange(that.slots_, nullptr)), - size_(absl::exchange(that.size_, 0)), - capacity_(absl::exchange(that.capacity_, 0)), + size_(absl::exchange(that.size_, size_t{0})), + capacity_(absl::exchange(that.capacity_, size_t{0})), // Hash, equality and allocator are copied instead of moved because // `that` must be left valid. If Hash is std::function<Key>, moving it // would create a nullptr functor that cannot be called. - settings_(absl::exchange(that.growth_left(), 0), + settings_(absl::exchange(that.growth_left(), size_t{0}), absl::exchange(that.infoz(), HashtablezInfoHandle()), - that.hash_ref(), that.eq_ref(), that.alloc_ref()) {} + that.hash_ref(), + that.eq_ref(), + that.alloc_ref()) {} raw_hash_set(raw_hash_set&& that, const allocator_type& a) : ctrl_(EmptyGroup()),
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc b/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc index 47dc904..fdec769 100644 --- a/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc +++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc
@@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/container/internal/raw_hash_set.h" - #include <numeric> #include <random> +#include <vector> #include "absl/base/internal/raw_logging.h" #include "absl/container/internal/hash_function_defaults.h" +#include "absl/container/internal/raw_hash_set.h" #include "absl/strings/str_format.h" #include "benchmark/benchmark.h" @@ -202,23 +202,46 @@ BENCHMARK(BM_CacheInSteadyState)->Apply(CacheInSteadyStateArgs); void BM_EndComparison(benchmark::State& state) { + StringTable t = {{"a", "a"}, {"b", "b"}}; + auto it = t.begin(); + for (auto i : state) { + benchmark::DoNotOptimize(t); + benchmark::DoNotOptimize(it); + benchmark::DoNotOptimize(it != t.end()); + } +} +BENCHMARK(BM_EndComparison); + +void BM_Iteration(benchmark::State& state) { std::random_device rd; std::mt19937 rng(rd()); string_generator gen{12}; StringTable t; - while (t.size() < state.range(0)) { + + size_t capacity = state.range(0); + size_t size = state.range(1); + t.reserve(capacity); + + while (t.size() < size) { t.emplace(gen(rng), gen(rng)); } - for (auto _ : state) { + for (auto i : state) { + benchmark::DoNotOptimize(t); for (auto it = t.begin(); it != t.end(); ++it) { - benchmark::DoNotOptimize(it); - benchmark::DoNotOptimize(t); - benchmark::DoNotOptimize(it != t.end()); + benchmark::DoNotOptimize(*it); } } } -BENCHMARK(BM_EndComparison)->Arg(400); + +BENCHMARK(BM_Iteration) + ->ArgPair(10, 10) + ->ArgPair(20, 20) + ->ArgPair(100, 100) + ->ArgPair(400, 400) + // sparse + ->ArgPair(100, 1) + ->ArgPair(1000, 10); void BM_CopyCtor(benchmark::State& state) { std::random_device rd; @@ -437,7 +460,6 @@ int odr = (::benchmark::DoNotOptimize(std::make_tuple( &CodegenAbslRawHashSetInt64Find, &CodegenAbslRawHashSetInt64FindNeEnd, - &CodegenAbslRawHashSetInt64Insert, - &CodegenAbslRawHashSetInt64Contains, + &CodegenAbslRawHashSetInt64Insert, &CodegenAbslRawHashSetInt64Contains, &CodegenAbslRawHashSetInt64Iterate)), 1);
diff --git a/third_party/abseil-cpp/absl/copts/configure_copts.bzl b/third_party/abseil-cpp/absl/copts/configure_copts.bzl index 40d5849a..c5e57b38 100644 --- a/third_party/abseil-cpp/absl/copts/configure_copts.bzl +++ b/third_party/abseil-cpp/absl/copts/configure_copts.bzl
@@ -25,6 +25,7 @@ "//absl:msvc_compiler": ABSL_MSVC_FLAGS, "//absl:clang-cl_compiler": ABSL_CLANG_CL_FLAGS, "//absl:clang_compiler": ABSL_LLVM_FLAGS, + "//absl:gcc_compiler": ABSL_GCC_FLAGS, "//conditions:default": ABSL_GCC_FLAGS, }) @@ -32,6 +33,7 @@ "//absl:msvc_compiler": ABSL_MSVC_TEST_FLAGS, "//absl:clang-cl_compiler": ABSL_CLANG_CL_TEST_FLAGS, "//absl:clang_compiler": ABSL_LLVM_TEST_FLAGS, + "//absl:gcc_compiler": ABSL_GCC_TEST_FLAGS, "//conditions:default": ABSL_GCC_TEST_FLAGS, })
diff --git a/third_party/abseil-cpp/absl/debugging/BUILD.bazel b/third_party/abseil-cpp/absl/debugging/BUILD.bazel index 51262058..a40285c 100644 --- a/third_party/abseil-cpp/absl/debugging/BUILD.bazel +++ b/third_party/abseil-cpp/absl/debugging/BUILD.bazel
@@ -49,6 +49,7 @@ ":debugging_internal", "//absl/base:config", "//absl/base:core_headers", + "//absl/base:raw_logging_internal", ], )
diff --git a/third_party/abseil-cpp/absl/debugging/CMakeLists.txt b/third_party/abseil-cpp/absl/debugging/CMakeLists.txt index d8207d6a..051e701 100644 --- a/third_party/abseil-cpp/absl/debugging/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
@@ -41,6 +41,7 @@ absl::debugging_internal absl::config absl::core_headers + absl::raw_logging_internal PUBLIC )
diff --git a/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc index b127a98..5e8f0b0 100644 --- a/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc +++ b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
@@ -135,7 +135,7 @@ #if defined(__wasm__) || defined (__asjms__) const size_t page_mask = getpagesize() - 1; #else - const size_t page_mask = sysconf(_SC_PAGESIZE) - 1; + const size_t page_mask = static_cast<size_t>(sysconf(_SC_PAGESIZE)) - 1; #endif size_t stack_size = (std::max<size_t>(SIGSTKSZ, 65536) + page_mask) & ~page_mask; @@ -356,7 +356,7 @@ if (fsh_options.alarm_on_failure_secs > 0) { alarm(0); // Cancel any existing alarms. signal(SIGALRM, ImmediateAbortSignalHandler); - alarm(fsh_options.alarm_on_failure_secs); + alarm(static_cast<unsigned int>(fsh_options.alarm_on_failure_secs)); } #endif
diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc index a9e2c32..20183fa 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc
@@ -30,6 +30,8 @@ #include <cassert> #include <cstdint> #include <iostream> +#include <limits> +#include <utility> #include "absl/base/attributes.h" #include "absl/debugging/stacktrace.h"
diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc index 1354cb37..9fbfcf7 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -35,8 +35,6 @@ #include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems #include "absl/debugging/stacktrace.h" -#include "absl/base/internal/raw_logging.h" - using absl::debugging_internal::AddressIsReadable; #if defined(__linux__) && defined(__i386__)
diff --git a/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc b/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc index 443ce9e..cf63d191 100644 --- a/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc +++ b/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc
@@ -83,13 +83,14 @@ memmove(out, tmp_buf, len + 1); } } else { - strncpy(out, symbol.c_str(), out_size); + strncpy(out, symbol.c_str(), static_cast<size_t>(out_size)); } if (out[out_size - 1] != '\0') { // strncpy() does not '\0' terminate when it truncates. static constexpr char kEllipsis[] = "..."; - int ellipsis_size = std::min<int>(sizeof(kEllipsis) - 1, out_size - 1); + size_t ellipsis_size = + std::min(sizeof(kEllipsis) - 1, static_cast<size_t>(out_size) - 1); memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size); out[out_size - 1] = '\0'; }
diff --git a/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc b/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc index 276d4ae4..ffb4eec 100644 --- a/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc +++ b/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc
@@ -205,7 +205,8 @@ // PT_LOAD program header describing executable code. // Normally we expect just one, but SWIFT binaries have two. - std::array<ElfW(Phdr), 2> phdr; + // CUDA binaries have 3 (see cr/473913254 description). + std::array<ElfW(Phdr), 4> phdr; }; // Build 4-way associative cache for symbols. Within each cache line, symbols @@ -252,21 +253,21 @@ public: AddrMap() : size_(0), allocated_(0), obj_(nullptr) {} ~AddrMap() { base_internal::LowLevelAlloc::Free(obj_); } - int Size() const { return size_; } - ObjFile *At(int i) { return &obj_[i]; } + size_t Size() const { return size_; } + ObjFile *At(size_t i) { return &obj_[i]; } ObjFile *Add(); void Clear(); private: - int size_; // count of valid elements (<= allocated_) - int allocated_; // count of allocated elements - ObjFile *obj_; // array of allocated_ elements + size_t size_; // count of valid elements (<= allocated_) + size_t allocated_; // count of allocated elements + ObjFile *obj_; // array of allocated_ elements AddrMap(const AddrMap &) = delete; AddrMap &operator=(const AddrMap &) = delete; }; void AddrMap::Clear() { - for (int i = 0; i != size_; i++) { + for (size_t i = 0; i != size_; i++) { At(i)->~ObjFile(); } size_ = 0; @@ -274,7 +275,7 @@ ObjFile *AddrMap::Add() { if (size_ == allocated_) { - int new_allocated = allocated_ * 2 + 50; + size_t new_allocated = allocated_ * 2 + 50; ObjFile *new_obj_ = static_cast<ObjFile *>(base_internal::LowLevelAlloc::AllocWithArena( new_allocated * sizeof(*new_obj_), SigSafeArena())); @@ -300,7 +301,7 @@ private: char *CopyString(const char *s) { - int len = strlen(s); + size_t len = strlen(s); char *dst = static_cast<char *>( base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena())); ABSL_RAW_CHECK(dst != nullptr, "out of memory"); @@ -321,8 +322,8 @@ FindSymbolResult GetSymbolFromObjectFile(const ObjFile &obj, const void *const pc, const ptrdiff_t relocation, - char *out, int out_size, - char *tmp_buf, int tmp_buf_size); + char *out, size_t out_size, + char *tmp_buf, size_t tmp_buf_size); const char *GetUncachedSymbol(const void *pc); enum { @@ -353,11 +354,11 @@ } // namespace -static int SymbolizerSize() { +static size_t SymbolizerSize() { #if defined(__wasm__) || defined(__asmjs__) - int pagesize = getpagesize(); + auto pagesize = static_cast<size_t>(getpagesize()); #else - int pagesize = sysconf(_SC_PAGESIZE); + auto pagesize = static_cast<size_t>(sysconf(_SC_PAGESIZE)); #endif return ((sizeof(Symbolizer) - 1) / pagesize + 1) * pagesize; } @@ -429,7 +430,7 @@ if (len == 0) { // Reached EOF. break; } - num_bytes += len; + num_bytes += static_cast<size_t>(len); } SAFE_ASSERT(num_bytes <= count); return static_cast<ssize_t>(num_bytes); @@ -478,36 +479,37 @@ // inlined. static ABSL_ATTRIBUTE_NOINLINE bool GetSectionHeaderByType( const int fd, ElfW(Half) sh_num, const off_t sh_offset, ElfW(Word) type, - ElfW(Shdr) * out, char *tmp_buf, int tmp_buf_size) { + ElfW(Shdr) * out, char *tmp_buf, size_t tmp_buf_size) { ElfW(Shdr) *buf = reinterpret_cast<ElfW(Shdr) *>(tmp_buf); - const int buf_entries = tmp_buf_size / sizeof(buf[0]); - const int buf_bytes = buf_entries * sizeof(buf[0]); + const size_t buf_entries = tmp_buf_size / sizeof(buf[0]); + const size_t buf_bytes = buf_entries * sizeof(buf[0]); - for (int i = 0; i < sh_num;) { - const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]); - const ssize_t num_bytes_to_read = + for (size_t i = 0; static_cast<int>(i) < sh_num;) { + const size_t num_bytes_left = + (static_cast<size_t>(sh_num) - i) * sizeof(buf[0]); + const size_t num_bytes_to_read = (buf_bytes > num_bytes_left) ? num_bytes_left : buf_bytes; - const off_t offset = sh_offset + i * sizeof(buf[0]); + const off_t offset = sh_offset + static_cast<off_t>(i * sizeof(buf[0])); const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read, offset); if (len < 0) { ABSL_RAW_LOG( WARNING, - "Reading %zd bytes from offset %ju returned %zd which is negative.", + "Reading %zu bytes from offset %ju returned %zd which is negative.", num_bytes_to_read, static_cast<intmax_t>(offset), len); return false; } - if (len % sizeof(buf[0]) != 0) { + if (static_cast<size_t>(len) % sizeof(buf[0]) != 0) { ABSL_RAW_LOG( WARNING, - "Reading %zd bytes from offset %jd returned %zd which is not a " + "Reading %zu bytes from offset %jd returned %zd which is not a " "multiple of %zu.", num_bytes_to_read, static_cast<intmax_t>(offset), len, sizeof(buf[0])); return false; } - const ssize_t num_headers_in_buf = len / sizeof(buf[0]); + const size_t num_headers_in_buf = static_cast<size_t>(len) / sizeof(buf[0]); SAFE_ASSERT(num_headers_in_buf <= buf_entries); - for (int j = 0; j < num_headers_in_buf; ++j) { + for (size_t j = 0; j < num_headers_in_buf; ++j) { if (buf[j].sh_type == type) { *out = buf[j]; return true; @@ -531,8 +533,8 @@ } ElfW(Shdr) shstrtab; - off_t shstrtab_offset = - (elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx); + off_t shstrtab_offset = static_cast<off_t>(elf_header.e_shoff) + + elf_header.e_shentsize * elf_header.e_shstrndx; if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) { return false; } @@ -540,22 +542,23 @@ for (int i = 0; i < elf_header.e_shnum; ++i) { ElfW(Shdr) out; off_t section_header_offset = - (elf_header.e_shoff + elf_header.e_shentsize * i); + static_cast<off_t>(elf_header.e_shoff) + elf_header.e_shentsize * i; if (!ReadFromOffsetExact(fd, &out, sizeof(out), section_header_offset)) { return false; } - off_t name_offset = shstrtab.sh_offset + out.sh_name; + off_t name_offset = static_cast<off_t>(shstrtab.sh_offset) + out.sh_name; char header_name[kMaxSectionNameLen]; ssize_t n_read = ReadFromOffset(fd, &header_name, kMaxSectionNameLen, name_offset); - if (n_read == -1) { + if (n_read < 0) { return false; } else if (n_read > kMaxSectionNameLen) { // Long read? return false; } - absl::string_view name(header_name, strnlen(header_name, n_read)); + absl::string_view name(header_name, + strnlen(header_name, static_cast<size_t>(n_read))); if (!callback(name, out)) { break; } @@ -582,19 +585,19 @@ } ElfW(Shdr) shstrtab; - off_t shstrtab_offset = - (elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx); + off_t shstrtab_offset = static_cast<off_t>(elf_header.e_shoff) + + elf_header.e_shentsize * elf_header.e_shstrndx; if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) { return false; } for (int i = 0; i < elf_header.e_shnum; ++i) { off_t section_header_offset = - (elf_header.e_shoff + elf_header.e_shentsize * i); + static_cast<off_t>(elf_header.e_shoff) + elf_header.e_shentsize * i; if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) { return false; } - off_t name_offset = shstrtab.sh_offset + out->sh_name; + off_t name_offset = static_cast<off_t>(shstrtab.sh_offset) + out->sh_name; ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset); if (n_read < 0) { return false; @@ -652,10 +655,10 @@ } static const char *ComputeOffset(const char *base, ptrdiff_t offset) { - // Note: cast to uintptr_t to avoid undefined behavior when base evaluates to + // Note: cast to intptr_t to avoid undefined behavior when base evaluates to // zero and offset is non-zero. - return reinterpret_cast<const char *>( - reinterpret_cast<uintptr_t>(base) + offset); + return reinterpret_cast<const char *>(reinterpret_cast<intptr_t>(base) + + offset); } // Read a symbol table and look for the symbol containing the @@ -668,18 +671,18 @@ // To keep stack consumption low, we would like this function to not get // inlined. static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol( - const void *const pc, const int fd, char *out, int out_size, + const void *const pc, const int fd, char *out, size_t out_size, ptrdiff_t relocation, const ElfW(Shdr) * strtab, const ElfW(Shdr) * symtab, - const ElfW(Shdr) * opd, char *tmp_buf, int tmp_buf_size) { + const ElfW(Shdr) * opd, char *tmp_buf, size_t tmp_buf_size) { if (symtab == nullptr) { return SYMBOL_NOT_FOUND; } // Read multiple symbols at once to save read() calls. ElfW(Sym) *buf = reinterpret_cast<ElfW(Sym) *>(tmp_buf); - const int buf_entries = tmp_buf_size / sizeof(buf[0]); + const size_t buf_entries = tmp_buf_size / sizeof(buf[0]); - const int num_symbols = symtab->sh_size / symtab->sh_entsize; + const size_t num_symbols = symtab->sh_size / symtab->sh_entsize; // On platforms using an .opd section (PowerPC & IA64), a function symbol // has the address of a function descriptor, which contains the real @@ -694,17 +697,19 @@ ElfW(Sym) best_match; SafeMemZero(&best_match, sizeof(best_match)); bool found_match = false; - for (int i = 0; i < num_symbols;) { - off_t offset = symtab->sh_offset + i * symtab->sh_entsize; - const int num_remaining_symbols = num_symbols - i; - const int entries_in_chunk = std::min(num_remaining_symbols, buf_entries); - const int bytes_in_chunk = entries_in_chunk * sizeof(buf[0]); + for (size_t i = 0; i < num_symbols;) { + off_t offset = + static_cast<off_t>(symtab->sh_offset + i * symtab->sh_entsize); + const size_t num_remaining_symbols = num_symbols - i; + const size_t entries_in_chunk = + std::min(num_remaining_symbols, buf_entries); + const size_t bytes_in_chunk = entries_in_chunk * sizeof(buf[0]); const ssize_t len = ReadFromOffset(fd, buf, bytes_in_chunk, offset); SAFE_ASSERT(len >= 0); - SAFE_ASSERT(len % sizeof(buf[0]) == 0); - const ssize_t num_symbols_in_buf = len / sizeof(buf[0]); + SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0); + const size_t num_symbols_in_buf = static_cast<size_t>(len) / sizeof(buf[0]); SAFE_ASSERT(num_symbols_in_buf <= entries_in_chunk); - for (int j = 0; j < num_symbols_in_buf; ++j) { + for (size_t j = 0; j < num_symbols_in_buf; ++j) { const ElfW(Sym) &symbol = buf[j]; // For a DSO, a symbol address is relocated by the loading address. @@ -721,7 +726,7 @@ // about what encoding is being used; we just want the real start address // of the function. start_address = reinterpret_cast<const char *>( - reinterpret_cast<uintptr_t>(start_address) & ~1); + reinterpret_cast<uintptr_t>(start_address) & ~1u); #endif if (deref_function_descriptor_pointer && @@ -734,7 +739,8 @@ // If pc is inside the .opd section, it points to a function descriptor. const size_t size = pc_in_opd ? kFunctionDescriptorSize : symbol.st_size; - const void *const end_address = ComputeOffset(start_address, size); + const void *const end_address = + ComputeOffset(start_address, static_cast<ptrdiff_t>(size)); if (symbol.st_value != 0 && // Skip null value symbols. symbol.st_shndx != 0 && // Skip undefined symbols. #ifdef STT_TLS @@ -752,16 +758,18 @@ } if (found_match) { - const size_t off = strtab->sh_offset + best_match.st_name; + const off_t off = + static_cast<off_t>(strtab->sh_offset) + best_match.st_name; const ssize_t n_read = ReadFromOffset(fd, out, out_size, off); if (n_read <= 0) { // This should never happen. ABSL_RAW_LOG(WARNING, - "Unable to read from fd %d at offset %zu: n_read = %zd", fd, - off, n_read); + "Unable to read from fd %d at offset %lld: n_read = %zd", fd, + static_cast<long long>(off), n_read); return SYMBOL_NOT_FOUND; } - ABSL_RAW_CHECK(n_read <= out_size, "ReadFromOffset read too much data."); + ABSL_RAW_CHECK(static_cast<size_t>(n_read) <= out_size, + "ReadFromOffset read too much data."); // strtab->sh_offset points into .strtab-like section that contains // NUL-terminated strings: '\0foo\0barbaz\0...". @@ -769,7 +777,7 @@ // sh_offset+st_name points to the start of symbol name, but we don't know // how long the symbol is, so we try to read as much as we have space for, // and usually over-read (i.e. there is a NUL somewhere before n_read). - if (memchr(out, '\0', n_read) == nullptr) { + if (memchr(out, '\0', static_cast<size_t>(n_read)) == nullptr) { // Either out_size was too small (n_read == out_size and no NUL), or // we tried to read past the EOF (n_read < out_size) and .strtab is // corrupt (missing terminating NUL; should never happen for valid ELF). @@ -787,7 +795,7 @@ // See FindSymbol() comment for description of return value. FindSymbolResult Symbolizer::GetSymbolFromObjectFile( const ObjFile &obj, const void *const pc, const ptrdiff_t relocation, - char *out, int out_size, char *tmp_buf, int tmp_buf_size) { + char *out, size_t out_size, char *tmp_buf, size_t tmp_buf_size) { ElfW(Shdr) symtab; ElfW(Shdr) strtab; ElfW(Shdr) opd; @@ -810,13 +818,15 @@ // Consult a regular symbol table, then fall back to the dynamic symbol table. for (const auto symbol_table_type : {SHT_SYMTAB, SHT_DYNSYM}) { if (!GetSectionHeaderByType(obj.fd, obj.elf_header.e_shnum, - obj.elf_header.e_shoff, symbol_table_type, + static_cast<off_t>(obj.elf_header.e_shoff), + static_cast<ElfW(Word)>(symbol_table_type), &symtab, tmp_buf, tmp_buf_size)) { continue; } if (!ReadFromOffsetExact( obj.fd, &strtab, sizeof(strtab), - obj.elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) { + static_cast<off_t>(obj.elf_header.e_shoff + + symtab.sh_link * sizeof(symtab)))) { continue; } const FindSymbolResult rc = @@ -858,7 +868,7 @@ // and snprintf(). class LineReader { public: - explicit LineReader(int fd, char *buf, int buf_len) + explicit LineReader(int fd, char *buf, size_t buf_len) : fd_(fd), buf_len_(buf_len), buf_(buf), @@ -886,12 +896,12 @@ bol_ = eol_ + 1; // Advance to the next line in the buffer. SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_". if (!HasCompleteLine()) { - const int incomplete_line_length = eod_ - bol_; + const auto incomplete_line_length = static_cast<size_t>(eod_ - bol_); // Move the trailing incomplete line to the beginning. memmove(buf_, bol_, incomplete_line_length); // Read text from file and append it. char *const append_pos = buf_ + incomplete_line_length; - const int capacity_left = buf_len_ - incomplete_line_length; + const size_t capacity_left = buf_len_ - incomplete_line_length; const ssize_t num_bytes = ReadPersistent(fd_, append_pos, capacity_left); if (num_bytes <= 0) { // EOF or error. @@ -914,7 +924,8 @@ private: char *FindLineFeed() const { - return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_)); + return reinterpret_cast<char *>( + memchr(bol_, '\n', static_cast<size_t>(eod_ - bol_))); } bool BufferIsEmpty() const { return buf_ == eod_; } @@ -924,7 +935,7 @@ } const int fd_; - const int buf_len_; + const size_t buf_len_; char *const buf_; char *bol_; char *eol_; @@ -942,7 +953,8 @@ int ch = *p; if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) { - hex = (hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9); + hex = (hex << 4) | + static_cast<uint64_t>(ch < 'A' ? ch - '0' : (ch & 0xF) + 9); } else { // Encountered the first non-hex character. break; } @@ -974,7 +986,7 @@ static ABSL_ATTRIBUTE_NOINLINE bool ReadAddrMap( bool (*callback)(const char *filename, const void *const start_addr, const void *const end_addr, uint64_t offset, void *arg), - void *arg, void *tmp_buf, int tmp_buf_size) { + void *arg, void *tmp_buf, size_t tmp_buf_size) { // Use /proc/self/task/<pid>/maps instead of /proc/self/maps. The latter // requires kernel to stop all threads, and is significantly slower when there // are 1000s of threads. @@ -1089,10 +1101,10 @@ } } - int lo = 0; - int hi = addr_map_.Size(); + size_t lo = 0; + size_t hi = addr_map_.Size(); while (lo < hi) { - int mid = (lo + hi) / 2; + size_t mid = (lo + hi) / 2; if (addr < addr_map_.At(mid)->end_addr) { hi = mid; } else { @@ -1114,7 +1126,7 @@ } void Symbolizer::ClearAddrMap() { - for (int i = 0; i != addr_map_.Size(); i++) { + for (size_t i = 0; i != addr_map_.Size(); i++) { ObjFile *o = addr_map_.At(i); base_internal::LowLevelAlloc::Free(o->filename); if (o->fd >= 0) { @@ -1134,7 +1146,7 @@ // Files are supposed to be added in the increasing address order. Make // sure that's the case. - int addr_map_size = impl->addr_map_.Size(); + size_t addr_map_size = impl->addr_map_.Size(); if (addr_map_size != 0) { ObjFile *old = impl->addr_map_.At(addr_map_size - 1); if (old->end_addr > end_addr) { @@ -1178,12 +1190,12 @@ // where the input symbol is demangled in-place. // To keep stack consumption low, we would like this function to not // get inlined. -static ABSL_ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size, +static ABSL_ATTRIBUTE_NOINLINE void DemangleInplace(char *out, size_t out_size, char *tmp_buf, - int tmp_buf_size) { + size_t tmp_buf_size) { if (Demangle(out, tmp_buf, tmp_buf_size)) { // Demangling succeeded. Copy to out if the space allows. - int len = strlen(tmp_buf); + size_t len = strlen(tmp_buf); if (len + 1 <= out_size) { // +1 for '\0'. SAFE_ASSERT(len < tmp_buf_size); memmove(out, tmp_buf, len + 1); @@ -1226,7 +1238,8 @@ SymbolCacheLine *line = GetCacheLine(pc); uint32_t max_age = 0; - int oldest_index = -1; + size_t oldest_index = 0; + bool found_oldest_index = false; for (size_t i = 0; i < ABSL_ARRAYSIZE(line->pc); ++i) { if (line->pc[i] == nullptr) { AgeSymbols(line); @@ -1238,11 +1251,12 @@ if (line->age[i] >= max_age) { max_age = line->age[i]; oldest_index = i; + found_oldest_index = true; } } AgeSymbols(line); - ABSL_RAW_CHECK(oldest_index >= 0, "Corrupt cache"); + ABSL_RAW_CHECK(found_oldest_index, "Corrupt cache"); base_internal::LowLevelAlloc::Free(line->name[oldest_index]); line->pc[oldest_index] = pc; line->name[oldest_index] = CopyString(name); @@ -1311,7 +1325,7 @@ } const int phnum = obj->elf_header.e_phnum; const int phentsize = obj->elf_header.e_phentsize; - size_t phoff = obj->elf_header.e_phoff; + auto phoff = static_cast<off_t>(obj->elf_header.e_phoff); size_t num_executable_load_segments = 0; for (int j = 0; j < phnum; j++) { ElfW(Phdr) phdr; @@ -1329,8 +1343,9 @@ if (num_executable_load_segments < obj->phdr.size()) { memcpy(&obj->phdr[num_executable_load_segments++], &phdr, sizeof(phdr)); } else { - ABSL_RAW_LOG(WARNING, "%s: too many executable LOAD segments", - obj->filename); + ABSL_RAW_LOG( + WARNING, "%s: too many executable LOAD segments: %zu >= %zu", + obj->filename, num_executable_load_segments, obj->phdr.size()); break; } } @@ -1362,7 +1377,7 @@ // // For obj->offset > 0, adjust the relocation since a mapping at offset // X in the file will have a start address of [true relocation]+X. - relocation = start_addr - obj->offset; + relocation = static_cast<ptrdiff_t>(start_addr - obj->offset); // Note: some binaries have multiple "rx" LOAD segments. We must // find the right one. @@ -1537,7 +1552,7 @@ ret = false; } else { // TODO(ckennelly): Move this into a string copy routine. - int len = strlen(filename); + size_t len = strlen(filename); char *dst = static_cast<char *>( base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena())); ABSL_RAW_CHECK(dst != nullptr, "out of memory"); @@ -1593,16 +1608,17 @@ const char *name = s->GetSymbol(pc); bool ok = false; if (name != nullptr && out_size > 0) { - strncpy(out, name, out_size); + strncpy(out, name, static_cast<size_t>(out_size)); ok = true; - if (out[out_size - 1] != '\0') { + if (out[static_cast<size_t>(out_size) - 1] != '\0') { // strncpy() does not '\0' terminate when it truncates. Do so, with // trailing ellipsis. static constexpr char kEllipsis[] = "..."; - int ellipsis_size = - std::min(implicit_cast<int>(strlen(kEllipsis)), out_size - 1); - memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size); - out[out_size - 1] = '\0'; + size_t ellipsis_size = + std::min(strlen(kEllipsis), static_cast<size_t>(out_size) - 1); + memcpy(out + static_cast<size_t>(out_size) - ellipsis_size - 1, kEllipsis, + ellipsis_size); + out[static_cast<size_t>(out_size) - 1] = '\0'; } } debugging_internal::FreeSymbolizer(s);
diff --git a/third_party/abseil-cpp/absl/flags/internal/flag.cc b/third_party/abseil-cpp/absl/flags/internal/flag.cc index 55892d7..cc656f9 100644 --- a/third_party/abseil-cpp/absl/flags/internal/flag.cc +++ b/third_party/abseil-cpp/absl/flags/internal/flag.cc
@@ -406,7 +406,7 @@ StorageT* FlagImpl::OffsetValue() const { char* p = reinterpret_cast<char*>(const_cast<FlagImpl*>(this)); // The offset is deduced via Flag value type specific op_. - size_t offset = flags_internal::ValueOffset(op_); + ptrdiff_t offset = flags_internal::ValueOffset(op_); return reinterpret_cast<StorageT*>(p + offset); } @@ -486,7 +486,7 @@ } void FlagImpl::ReadSequenceLockedData(void* dst) const { - int size = Sizeof(op_); + size_t size = Sizeof(op_); // Attempt to read using the sequence lock. if (ABSL_PREDICT_TRUE(seq_lock_.TryRead(dst, AtomicBufferValue(), size))) { return;
diff --git a/third_party/abseil-cpp/absl/flags/internal/usage.cc b/third_party/abseil-cpp/absl/flags/internal/usage.cc index 949709e..a3b13ed 100644 --- a/third_party/abseil-cpp/absl/flags/internal/usage.cc +++ b/third_party/abseil-cpp/absl/flags/internal/usage.cc
@@ -148,8 +148,7 @@ } // Write the token, ending the string first if necessary/possible. - if (!new_line && - (line_len_ + static_cast<int>(token.size()) >= max_line_len_)) { + if (!new_line && (line_len_ + token.size() >= max_line_len_)) { EndLine(); new_line = true; }
diff --git a/third_party/abseil-cpp/absl/flags/parse.cc b/third_party/abseil-cpp/absl/flags/parse.cc index dd1a679..2851c0f 100644 --- a/third_party/abseil-cpp/absl/flags/parse.cc +++ b/third_party/abseil-cpp/absl/flags/parse.cc
@@ -159,14 +159,14 @@ // Returns success status: true if parsing successful, false otherwise. bool ReadFromFlagfile(const std::string& flag_file_name); - int Size() const { return args_.size() - next_arg_; } - int FrontIndex() const { return next_arg_; } + size_t Size() const { return args_.size() - next_arg_; } + size_t FrontIndex() const { return next_arg_; } absl::string_view Front() const { return args_[next_arg_]; } void PopFront() { next_arg_++; } private: std::vector<std::string> args_; - int next_arg_; + size_t next_arg_; }; bool ArgsList::ReadFromFlagfile(const std::string& flag_file_name) { @@ -626,7 +626,7 @@ std::vector<char*> output_args; std::vector<char*> positional_args; - output_args.reserve(argc); + output_args.reserve(static_cast<size_t>(argc)); // This is the list of undefined flags. The element of the list is the pair // consisting of boolean indicating if flag came from command line (vs from @@ -795,8 +795,8 @@ // All the remaining arguments are positional. if (!input_args.empty()) { - for (int arg_index = input_args.back().FrontIndex(); arg_index < argc; - ++arg_index) { + for (size_t arg_index = input_args.back().FrontIndex(); + arg_index < static_cast<size_t>(argc); ++arg_index) { output_args.push_back(argv[arg_index]); } }
diff --git a/third_party/abseil-cpp/absl/hash/hash_test.cc b/third_party/abseil-cpp/absl/hash/hash_test.cc index ffa45e6e9..744a2e5 100644 --- a/third_party/abseil-cpp/absl/hash/hash_test.cc +++ b/third_party/abseil-cpp/absl/hash/hash_test.cc
@@ -222,7 +222,7 @@ // Limit the scope to the bits we would be using for Swisstable. constexpr size_t kMask = (1 << (kLog2NumValues + 7)) - 1; size_t stuck_bits = (~bits_or | bits_and) & kMask; - EXPECT_EQ(stuck_bits, 0) << "0x" << std::hex << stuck_bits; + EXPECT_EQ(stuck_bits, 0u) << "0x" << std::hex << stuck_bits; } } @@ -737,10 +737,10 @@ // // This test is run on a buffer that is a multiple of the stride size, and one // that isn't. - for (size_t big_buffer_size : {1024 * 2 + 512, 1024 * 3}) { + for (size_t big_buffer_size : {1024u * 2 + 512u, 1024u * 3}) { SCOPED_TRACE(big_buffer_size); std::string big_buffer; - for (int i = 0; i < big_buffer_size; ++i) { + for (size_t i = 0; i < big_buffer_size; ++i) { // Arbitrary string big_buffer.push_back(32 + (i * (i / 3)) % 64); } @@ -1135,10 +1135,10 @@ unsigned char buffer2[kNumStructs * sizeof(StructWithPadding)]; std::memset(buffer2, 255, sizeof(buffer2)); auto* s2 = reinterpret_cast<StructWithPadding*>(buffer2); - for (int i = 0; i < kNumStructs; ++i) { + for (size_t i = 0; i < kNumStructs; ++i) { SCOPED_TRACE(i); - s1[i].c = s2[i].c = '0' + i; - s1[i].i = s2[i].i = i; + s1[i].c = s2[i].c = static_cast<char>('0' + i); + s1[i].i = s2[i].i = static_cast<int>(i); ASSERT_FALSE(memcmp(buffer1 + i * sizeof(StructWithPadding), buffer2 + i * sizeof(StructWithPadding), sizeof(StructWithPadding)) == 0) @@ -1226,7 +1226,9 @@ namespace std { template <> struct hash<ValueWithBoolConversion> { - size_t operator()(ValueWithBoolConversion v) { return v.i; } + size_t operator()(ValueWithBoolConversion v) { + return static_cast<size_t>(v.i); + } }; } // namespace std
diff --git a/third_party/abseil-cpp/absl/log/CMakeLists.txt b/third_party/abseil-cpp/absl/log/CMakeLists.txt index a96e519..a803ca8 100644 --- a/third_party/abseil-cpp/absl/log/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/log/CMakeLists.txt
@@ -173,6 +173,7 @@ ${ABSL_DEFAULT_COPTS} LINKOPTS ${ABSL_DEFAULT_LINKOPTS} + $<$<BOOL:${ANDROID}>:-llog> DEPS absl::base absl::cleanup
diff --git a/third_party/abseil-cpp/absl/log/internal/BUILD.bazel b/third_party/abseil-cpp/absl/log/internal/BUILD.bazel index 54b221b..19243a5 100644 --- a/third_party/abseil-cpp/absl/log/internal/BUILD.bazel +++ b/third_party/abseil-cpp/absl/log/internal/BUILD.bazel
@@ -163,7 +163,10 @@ srcs = ["log_sink_set.cc"], hdrs = ["log_sink_set.h"], copts = ABSL_DEFAULT_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, + linkopts = ABSL_DEFAULT_LINKOPTS + select({ + "//conditions:default": [], + "@platforms//os:android": ["-llog"], + }), deps = [ ":config", ":globals",
diff --git a/third_party/abseil-cpp/absl/profiling/internal/exponential_biased_test.cc b/third_party/abseil-cpp/absl/profiling/internal/exponential_biased_test.cc index 6a6c317..ebfbcad 100644 --- a/third_party/abseil-cpp/absl/profiling/internal/exponential_biased_test.cc +++ b/third_party/abseil-cpp/absl/profiling/internal/exponential_biased_test.cc
@@ -94,13 +94,14 @@ } double AndersonDarlingStatistic(const std::vector<double>& random_sample) { - int n = random_sample.size(); + size_t n = random_sample.size(); double ad_sum = 0; - for (int i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) { ad_sum += (2 * i + 1) * std::log(random_sample[i] * (1 - random_sample[n - 1 - i])); } - double ad_statistic = -n - 1 / static_cast<double>(n) * ad_sum; + const auto n_as_double = static_cast<double>(n); + double ad_statistic = -n_as_double - 1 / n_as_double * ad_sum; return ad_statistic; } @@ -111,14 +112,15 @@ // Marsaglia and Marsaglia for details. double AndersonDarlingTest(const std::vector<double>& random_sample) { double ad_statistic = AndersonDarlingStatistic(random_sample); - double p = AndersonDarlingPValue(random_sample.size(), ad_statistic); + double p = AndersonDarlingPValue(static_cast<int>(random_sample.size()), + ad_statistic); return p; } TEST(ExponentialBiasedTest, CoinTossDemoWithGetSkipCount) { ExponentialBiased eb; for (int runs = 0; runs < 10; ++runs) { - for (int flips = eb.GetSkipCount(1); flips > 0; --flips) { + for (int64_t flips = eb.GetSkipCount(1); flips > 0; --flips) { printf("head..."); } printf("tail\n"); @@ -132,7 +134,7 @@ TEST(ExponentialBiasedTest, SampleDemoWithStride) { ExponentialBiased eb; - int stride = eb.GetStride(10); + int64_t stride = eb.GetStride(10); int samples = 0; for (int i = 0; i < 10000000; ++i) { if (--stride == 0) { @@ -147,7 +149,7 @@ // Testing that NextRandom generates uniform random numbers. Applies the // Anderson-Darling test for uniformity TEST(ExponentialBiasedTest, TestNextRandom) { - for (auto n : std::vector<int>({ + for (auto n : std::vector<size_t>({ 10, // Check short-range correlation 100, 1000, 10000 // Make sure there's no systemic error @@ -161,7 +163,7 @@ } std::vector<uint64_t> int_random_sample(n); // Collect samples - for (int i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) { int_random_sample[i] = x; x = ExponentialBiased::NextRandom(x); } @@ -169,7 +171,7 @@ std::sort(int_random_sample.begin(), int_random_sample.end()); std::vector<double> random_sample(n); // Convert them to uniform randoms (in the range [0,1]) - for (int i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) { random_sample[i] = static_cast<double>(int_random_sample[i]) / max_prng_value; }
diff --git a/third_party/abseil-cpp/absl/random/internal/seed_material.cc b/third_party/abseil-cpp/absl/random/internal/seed_material.cc index c03cad85..1041302b 100644 --- a/third_party/abseil-cpp/absl/random/internal/seed_material.cc +++ b/third_party/abseil-cpp/absl/random/internal/seed_material.cc
@@ -173,12 +173,12 @@ } while (success && buffer_size > 0) { - int bytes_read = read(dev_urandom, buffer, buffer_size); + ssize_t bytes_read = read(dev_urandom, buffer, buffer_size); int read_error = errno; success = (bytes_read > 0); if (success) { buffer += bytes_read; - buffer_size -= bytes_read; + buffer_size -= static_cast<size_t>(bytes_read); } else if (bytes_read == -1 && read_error == EINTR) { success = true; // Need to try again. }
diff --git a/third_party/abseil-cpp/absl/status/statusor_test.cc b/third_party/abseil-cpp/absl/status/statusor_test.cc index 7cae90e..2902154 100644 --- a/third_party/abseil-cpp/absl/status/statusor_test.cc +++ b/third_party/abseil-cpp/absl/status/statusor_test.cc
@@ -1521,7 +1521,7 @@ TEST(StatusOr, TestIgnoreError) { MakeStatus().IgnoreError(); } TEST(StatusOr, EqualityOperator) { - constexpr int kNumCases = 4; + constexpr size_t kNumCases = 4; std::array<absl::StatusOr<int>, kNumCases> group1 = { absl::StatusOr<int>(1), absl::StatusOr<int>(2), absl::StatusOr<int>(absl::InvalidArgumentError("msg")), @@ -1530,8 +1530,8 @@ absl::StatusOr<int>(1), absl::StatusOr<int>(2), absl::StatusOr<int>(absl::InvalidArgumentError("msg")), absl::StatusOr<int>(absl::InternalError("msg"))}; - for (int i = 0; i < kNumCases; ++i) { - for (int j = 0; j < kNumCases; ++j) { + for (size_t i = 0; i < kNumCases; ++i) { + for (size_t j = 0; j < kNumCases; ++j) { if (i == j) { EXPECT_TRUE(group1[i] == group2[j]); EXPECT_FALSE(group1[i] != group2[j]);
diff --git a/third_party/abseil-cpp/absl/strings/ascii_test.cc b/third_party/abseil-cpp/absl/strings/ascii_test.cc index 83af782..dfed114c 100644 --- a/third_party/abseil-cpp/absl/strings/ascii_test.cc +++ b/third_party/abseil-cpp/absl/strings/ascii_test.cc
@@ -27,103 +27,99 @@ TEST(AsciiIsFoo, All) { for (int i = 0; i < 256; i++) { - if ((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z')) - EXPECT_TRUE(absl::ascii_isalpha(i)) << ": failed on " << i; + const auto c = static_cast<unsigned char>(i); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + EXPECT_TRUE(absl::ascii_isalpha(c)) << ": failed on " << c; else - EXPECT_TRUE(!absl::ascii_isalpha(i)) << ": failed on " << i; + EXPECT_TRUE(!absl::ascii_isalpha(c)) << ": failed on " << c; } for (int i = 0; i < 256; i++) { - if ((i >= '0' && i <= '9')) - EXPECT_TRUE(absl::ascii_isdigit(i)) << ": failed on " << i; + const auto c = static_cast<unsigned char>(i); + if ((c >= '0' && c <= '9')) + EXPECT_TRUE(absl::ascii_isdigit(c)) << ": failed on " << c; else - EXPECT_TRUE(!absl::ascii_isdigit(i)) << ": failed on " << i; + EXPECT_TRUE(!absl::ascii_isdigit(c)) << ": failed on " << c; } for (int i = 0; i < 256; i++) { - if (absl::ascii_isalpha(i) || absl::ascii_isdigit(i)) - EXPECT_TRUE(absl::ascii_isalnum(i)) << ": failed on " << i; + const auto c = static_cast<unsigned char>(i); + if (absl::ascii_isalpha(c) || absl::ascii_isdigit(c)) + EXPECT_TRUE(absl::ascii_isalnum(c)) << ": failed on " << c; else - EXPECT_TRUE(!absl::ascii_isalnum(i)) << ": failed on " << i; + EXPECT_TRUE(!absl::ascii_isalnum(c)) << ": failed on " << c; } for (int i = 0; i < 256; i++) { + const auto c = static_cast<unsigned char>(i); if (i != '\0' && strchr(" \r\n\t\v\f", i)) - EXPECT_TRUE(absl::ascii_isspace(i)) << ": failed on " << i; + EXPECT_TRUE(absl::ascii_isspace(c)) << ": failed on " << c; else - EXPECT_TRUE(!absl::ascii_isspace(i)) << ": failed on " << i; + EXPECT_TRUE(!absl::ascii_isspace(c)) << ": failed on " << c; } for (int i = 0; i < 256; i++) { + const auto c = static_cast<unsigned char>(i); if (i >= 32 && i < 127) - EXPECT_TRUE(absl::ascii_isprint(i)) << ": failed on " << i; + EXPECT_TRUE(absl::ascii_isprint(c)) << ": failed on " << c; else - EXPECT_TRUE(!absl::ascii_isprint(i)) << ": failed on " << i; + EXPECT_TRUE(!absl::ascii_isprint(c)) << ": failed on " << c; } for (int i = 0; i < 256; i++) { - if (absl::ascii_isprint(i) && !absl::ascii_isspace(i) && - !absl::ascii_isalnum(i)) - EXPECT_TRUE(absl::ascii_ispunct(i)) << ": failed on " << i; - else - EXPECT_TRUE(!absl::ascii_ispunct(i)) << ": failed on " << i; + const auto c = static_cast<unsigned char>(i); + if (absl::ascii_isprint(c) && !absl::ascii_isspace(c) && + !absl::ascii_isalnum(c)) { + EXPECT_TRUE(absl::ascii_ispunct(c)) << ": failed on " << c; + } else { + EXPECT_TRUE(!absl::ascii_ispunct(c)) << ": failed on " << c; + } } for (int i = 0; i < 256; i++) { + const auto c = static_cast<unsigned char>(i); if (i == ' ' || i == '\t') - EXPECT_TRUE(absl::ascii_isblank(i)) << ": failed on " << i; + EXPECT_TRUE(absl::ascii_isblank(c)) << ": failed on " << c; else - EXPECT_TRUE(!absl::ascii_isblank(i)) << ": failed on " << i; + EXPECT_TRUE(!absl::ascii_isblank(c)) << ": failed on " << c; } for (int i = 0; i < 256; i++) { + const auto c = static_cast<unsigned char>(i); if (i < 32 || i == 127) - EXPECT_TRUE(absl::ascii_iscntrl(i)) << ": failed on " << i; + EXPECT_TRUE(absl::ascii_iscntrl(c)) << ": failed on " << c; else - EXPECT_TRUE(!absl::ascii_iscntrl(i)) << ": failed on " << i; + EXPECT_TRUE(!absl::ascii_iscntrl(c)) << ": failed on " << c; } for (int i = 0; i < 256; i++) { - if (absl::ascii_isdigit(i) || (i >= 'A' && i <= 'F') || - (i >= 'a' && i <= 'f')) - EXPECT_TRUE(absl::ascii_isxdigit(i)) << ": failed on " << i; - else - EXPECT_TRUE(!absl::ascii_isxdigit(i)) << ": failed on " << i; + const auto c = static_cast<unsigned char>(i); + if (absl::ascii_isdigit(c) || (i >= 'A' && i <= 'F') || + (i >= 'a' && i <= 'f')) { + EXPECT_TRUE(absl::ascii_isxdigit(c)) << ": failed on " << c; + } else { + EXPECT_TRUE(!absl::ascii_isxdigit(c)) << ": failed on " << c; + } } for (int i = 0; i < 256; i++) { + const auto c = static_cast<unsigned char>(i); if (i > 32 && i < 127) - EXPECT_TRUE(absl::ascii_isgraph(i)) << ": failed on " << i; + EXPECT_TRUE(absl::ascii_isgraph(c)) << ": failed on " << c; else - EXPECT_TRUE(!absl::ascii_isgraph(i)) << ": failed on " << i; + EXPECT_TRUE(!absl::ascii_isgraph(c)) << ": failed on " << c; } for (int i = 0; i < 256; i++) { + const auto c = static_cast<unsigned char>(i); if (i >= 'A' && i <= 'Z') - EXPECT_TRUE(absl::ascii_isupper(i)) << ": failed on " << i; + EXPECT_TRUE(absl::ascii_isupper(c)) << ": failed on " << c; else - EXPECT_TRUE(!absl::ascii_isupper(i)) << ": failed on " << i; + EXPECT_TRUE(!absl::ascii_isupper(c)) << ": failed on " << c; } for (int i = 0; i < 256; i++) { + const auto c = static_cast<unsigned char>(i); if (i >= 'a' && i <= 'z') - EXPECT_TRUE(absl::ascii_islower(i)) << ": failed on " << i; + EXPECT_TRUE(absl::ascii_islower(c)) << ": failed on " << c; else - EXPECT_TRUE(!absl::ascii_islower(i)) << ": failed on " << i; + EXPECT_TRUE(!absl::ascii_islower(c)) << ": failed on " << c; } - for (int i = 0; i < 128; i++) { - EXPECT_TRUE(absl::ascii_isascii(i)) << ": failed on " << i; + for (unsigned char c = 0; c < 128; c++) { + EXPECT_TRUE(absl::ascii_isascii(c)) << ": failed on " << c; } for (int i = 128; i < 256; i++) { - EXPECT_TRUE(!absl::ascii_isascii(i)) << ": failed on " << i; - } - - // The official is* functions don't accept negative signed chars, but - // our absl::ascii_is* functions do. - for (int i = 0; i < 256; i++) { - signed char sc = static_cast<signed char>(static_cast<unsigned char>(i)); - EXPECT_EQ(absl::ascii_isalpha(i), absl::ascii_isalpha(sc)) << i; - EXPECT_EQ(absl::ascii_isdigit(i), absl::ascii_isdigit(sc)) << i; - EXPECT_EQ(absl::ascii_isalnum(i), absl::ascii_isalnum(sc)) << i; - EXPECT_EQ(absl::ascii_isspace(i), absl::ascii_isspace(sc)) << i; - EXPECT_EQ(absl::ascii_ispunct(i), absl::ascii_ispunct(sc)) << i; - EXPECT_EQ(absl::ascii_isblank(i), absl::ascii_isblank(sc)) << i; - EXPECT_EQ(absl::ascii_iscntrl(i), absl::ascii_iscntrl(sc)) << i; - EXPECT_EQ(absl::ascii_isxdigit(i), absl::ascii_isxdigit(sc)) << i; - EXPECT_EQ(absl::ascii_isprint(i), absl::ascii_isprint(sc)) << i; - EXPECT_EQ(absl::ascii_isgraph(i), absl::ascii_isgraph(sc)) << i; - EXPECT_EQ(absl::ascii_isupper(i), absl::ascii_isupper(sc)) << i; - EXPECT_EQ(absl::ascii_islower(i), absl::ascii_islower(sc)) << i; - EXPECT_EQ(absl::ascii_isascii(i), absl::ascii_isascii(sc)) << i; + const auto c = static_cast<unsigned char>(i); + EXPECT_TRUE(!absl::ascii_isascii(c)) << ": failed on " << c; } } @@ -137,19 +133,20 @@ #endif for (int i = 0; i < 256; i++) { - EXPECT_EQ(isalpha(i) != 0, absl::ascii_isalpha(i)) << i; - EXPECT_EQ(isdigit(i) != 0, absl::ascii_isdigit(i)) << i; - EXPECT_EQ(isalnum(i) != 0, absl::ascii_isalnum(i)) << i; - EXPECT_EQ(isspace(i) != 0, absl::ascii_isspace(i)) << i; - EXPECT_EQ(ispunct(i) != 0, absl::ascii_ispunct(i)) << i; - EXPECT_EQ(isblank(i) != 0, absl::ascii_isblank(i)) << i; - EXPECT_EQ(iscntrl(i) != 0, absl::ascii_iscntrl(i)) << i; - EXPECT_EQ(isxdigit(i) != 0, absl::ascii_isxdigit(i)) << i; - EXPECT_EQ(isprint(i) != 0, absl::ascii_isprint(i)) << i; - EXPECT_EQ(isgraph(i) != 0, absl::ascii_isgraph(i)) << i; - EXPECT_EQ(isupper(i) != 0, absl::ascii_isupper(i)) << i; - EXPECT_EQ(islower(i) != 0, absl::ascii_islower(i)) << i; - EXPECT_EQ(isascii(i) != 0, absl::ascii_isascii(i)) << i; + const auto c = static_cast<unsigned char>(i); + EXPECT_EQ(isalpha(c) != 0, absl::ascii_isalpha(c)) << c; + EXPECT_EQ(isdigit(c) != 0, absl::ascii_isdigit(c)) << c; + EXPECT_EQ(isalnum(c) != 0, absl::ascii_isalnum(c)) << c; + EXPECT_EQ(isspace(c) != 0, absl::ascii_isspace(c)) << c; + EXPECT_EQ(ispunct(c) != 0, absl::ascii_ispunct(c)) << c; + EXPECT_EQ(isblank(c) != 0, absl::ascii_isblank(c)) << c; + EXPECT_EQ(iscntrl(c) != 0, absl::ascii_iscntrl(c)) << c; + EXPECT_EQ(isxdigit(c) != 0, absl::ascii_isxdigit(c)) << c; + EXPECT_EQ(isprint(c) != 0, absl::ascii_isprint(c)) << c; + EXPECT_EQ(isgraph(c) != 0, absl::ascii_isgraph(c)) << c; + EXPECT_EQ(isupper(c) != 0, absl::ascii_isupper(c)) << c; + EXPECT_EQ(islower(c) != 0, absl::ascii_islower(c)) << c; + EXPECT_EQ(isascii(c) != 0, absl::ascii_isascii(c)) << c; } #ifndef __ANDROID__ @@ -166,25 +163,20 @@ #endif for (int i = 0; i < 256; i++) { - if (absl::ascii_islower(i)) - EXPECT_EQ(absl::ascii_toupper(i), 'A' + (i - 'a')) << i; + const auto c = static_cast<unsigned char>(i); + if (absl::ascii_islower(c)) + EXPECT_EQ(absl::ascii_toupper(c), 'A' + (i - 'a')) << c; else - EXPECT_EQ(absl::ascii_toupper(i), static_cast<char>(i)) << i; + EXPECT_EQ(absl::ascii_toupper(c), static_cast<char>(i)) << c; - if (absl::ascii_isupper(i)) - EXPECT_EQ(absl::ascii_tolower(i), 'a' + (i - 'A')) << i; + if (absl::ascii_isupper(c)) + EXPECT_EQ(absl::ascii_tolower(c), 'a' + (i - 'A')) << c; else - EXPECT_EQ(absl::ascii_tolower(i), static_cast<char>(i)) << i; + EXPECT_EQ(absl::ascii_tolower(c), static_cast<char>(i)) << c; // These CHECKs only hold in a C locale. - EXPECT_EQ(static_cast<char>(tolower(i)), absl::ascii_tolower(i)) << i; - EXPECT_EQ(static_cast<char>(toupper(i)), absl::ascii_toupper(i)) << i; - - // The official to* functions don't accept negative signed chars, but - // our absl::ascii_to* functions do. - signed char sc = static_cast<signed char>(static_cast<unsigned char>(i)); - EXPECT_EQ(absl::ascii_tolower(i), absl::ascii_tolower(sc)) << i; - EXPECT_EQ(absl::ascii_toupper(i), absl::ascii_toupper(sc)) << i; + EXPECT_EQ(static_cast<char>(tolower(i)), absl::ascii_tolower(c)) << c; + EXPECT_EQ(static_cast<char>(toupper(i)), absl::ascii_toupper(c)) << c; } #ifndef __ANDROID__ // restore the old locale.
diff --git a/third_party/abseil-cpp/absl/strings/charconv.cc b/third_party/abseil-cpp/absl/strings/charconv.cc index 65d1beb1..9eac9be 100644 --- a/third_party/abseil-cpp/absl/strings/charconv.cc +++ b/third_party/abseil-cpp/absl/strings/charconv.cc
@@ -18,6 +18,7 @@ #include <cassert> #include <cmath> #include <cstring> +#include <limits> #include "absl/base/casts.h" #include "absl/numeric/bits.h" @@ -195,21 +196,22 @@ // // Indexes into these tables are biased by -kPower10TableMin, and the table has // values in the range [kPower10TableMin, kPower10TableMax]. -extern const uint64_t kPower10MantissaTable[]; +extern const uint64_t kPower10MantissaHighTable[]; // High 64 of 128 bits. +extern const uint64_t kPower10MantissaLowTable[]; // Low 64 of 128 bits. extern const int16_t kPower10ExponentTable[]; -// The smallest allowed value for use with the Power10Mantissa() and -// Power10Exponent() functions below. (If a smaller exponent is needed in +// The smallest (inclusive) allowed value for use with the Power10Mantissa() +// and Power10Exponent() functions below. (If a smaller exponent is needed in // calculations, the end result is guaranteed to underflow.) constexpr int kPower10TableMin = -342; -// The largest allowed value for use with the Power10Mantissa() and +// The largest (inclusive) allowed value for use with the Power10Mantissa() and // Power10Exponent() functions below. (If a smaller exponent is needed in // calculations, the end result is guaranteed to overflow.) constexpr int kPower10TableMax = 308; uint64_t Power10Mantissa(int n) { - return kPower10MantissaTable[n - kPower10TableMin]; + return kPower10MantissaHighTable[n - kPower10TableMin]; } int Power10Exponent(int n) { @@ -606,6 +608,128 @@ binary_exponent); } +// As discussed in https://nigeltao.github.io/blog/2020/eisel-lemire.html the +// primary goal of the Eisel-Lemire algorithm is speed, for 99+% of the cases, +// not 100% coverage. As long as Eisel-Lemire doesn’t claim false positives, +// the combined approach (falling back to an alternative implementation when +// this function returns false) is both fast and correct. +template <typename FloatType> +bool EiselLemire(const strings_internal::ParsedFloat& input, bool negative, + FloatType* value) { + // For now, implement Eisel-Lemire only for double, not float. + if (FloatTraits<FloatType>::kTargetMantissaBits != 53) { + return false; + } + + uint64_t man = input.mantissa; + int exp10 = input.exponent; + if (Power10Underflow(exp10) || Power10Overflow(exp10)) { + return false; + } + + // The terse (+) comments in this function body refer to sections of the + // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. + // + // See also "Number Parsing at a Gigabyte per Second, Software: Practice and + // Experience 51 (8), 2021" (https://arxiv.org/abs/2101.11408) for detail. + + // (+) Normalization. + int clz = countl_zero(man); + man <<= static_cast<unsigned int>(clz); + static constexpr int exp2_bias = 1023; + // The 217706 etc magic numbers encode the kPower10ExponentTable as a formula + // instead of a table. Their equivalence is confirmed by + // https://github.com/google/wuffs/blob/315b2e52625ebd7b02d8fac13e3cd85ea374fb80/script/print-mpb-powers-of-10.go + uint64_t ret_exp2 = + static_cast<uint64_t>((217706 * exp10 >> 16) + 64 + exp2_bias - clz); + + // (+) Multiplication. + uint128 x = + static_cast<uint128>(man) * + static_cast<uint128>(kPower10MantissaHighTable[exp10 - kPower10TableMin]); + + // (+) Wider Approximation. + if (((Uint128High64(x) & 0x1FF) == 0x1FF) && + (man > (std::numeric_limits<uint64_t>::max() - Uint128Low64(x)))) { + uint128 y = static_cast<uint128>(man) * + static_cast<uint128>( + kPower10MantissaLowTable[exp10 - kPower10TableMin]); + x += Uint128High64(y); + // For example, parsing "4503599627370497.5" will take the if-true + // branch here, since: + // - x = 0x8000000000000BFF_FFFFFFFFFFFFFFFF + // - y = 0x8000000000000BFF_7FFFFFFFFFFFF400 + // - man = 0xA000000000000F00 + if (((Uint128High64(x) & 0x1FF) == 0x1FF) && ((Uint128Low64(x) + 1) == 0) && + (man > (std::numeric_limits<uint64_t>::max() - Uint128Low64(y)))) { + return false; + } + } + + // (+) Shifting to 54 Bits. + uint64_t msb = Uint128High64(x) >> 63; + uint64_t ret_man = Uint128High64(x) >> (msb + 9); + ret_exp2 -= 1 ^ msb; + + // (+) Half-way Ambiguity. + // + // For example, parsing "1e+23" will take the if-true branch here, since: + // - x = 0x54B40B1F852BDA00_0000000000000000 + // - ret_man = 0x002A5A058FC295ED + if ((Uint128Low64(x) == 0) && ((Uint128High64(x) & 0x1FF) == 0) && + ((ret_man & 3) == 1)) { + return false; + } + + // (+) From 54 to 53 Bits. + ret_man += ret_man & 1; // Line From54a. + ret_man >>= 1; // Line From54b. + // Incrementing ret_man (at line From54a) may have overflowed 54 bits (53 + // bits after the right shift by 1 at line From54b), so adjust for that. + // + // For example, parsing "9223372036854775807" will take the if-true branch + // here, since ret_man = 0x0020000000000000 = (1 << 53). + if ((ret_man >> 53) > 0) { + ret_exp2 += 1; + // Conceptually, we need a "ret_man >>= 1" in this if-block to balance + // incrementing ret_exp2 in the line immediately above. However, we only + // get here when line From54a overflowed (after adding a 1), so ret_man + // here is (1 << 53). Its low 53 bits are therefore all zeroes. The only + // remaining use of ret_man is to mask it with ((1 << 52) - 1), so only its + // low 52 bits matter. A "ret_man >>= 1" would have no effect in practice. + // + // We omit the "ret_man >>= 1", even if it is cheap (and this if-branch is + // rarely taken) and technically 'more correct', so that mutation tests + // that would otherwise modify or omit that "ret_man >>= 1" don't complain + // that such code mutations have no observable effect. + } + + // ret_exp2 is a uint64_t. Zero or underflow means that we're in subnormal + // space. 0x7FF or above means that we're in Inf/NaN space. + // + // The if block is equivalent to (but has fewer branches than): + // if ((ret_exp2 <= 0) || (ret_exp2 >= 0x7FF)) { etc } + // + // For example, parsing "4.9406564584124654e-324" will take the if-true + // branch here, since ret_exp2 = -51. + if ((ret_exp2 - 1) >= (0x7FF - 1)) { + return false; + } + +#ifndef ABSL_BIT_PACK_FLOATS + *value = FloatTraits<FloatType>::Make( + (ret_man & 0x000FFFFFFFFFFFFFu) | 0x0010000000000000u, + ret_exp2 - 1023 - 52, negative); +#else + uint64_t ret_bits = (ret_exp2 << 52) | (ret_man & 0x000FFFFFFFFFFFFFu); + if (negative) { + ret_bits |= 0x8000000000000000u; + } + *value = absl::bit_cast<double>(ret_bits); +#endif // ABSL_BIT_PACK_FLOATS + return true; +} + template <typename FloatType> from_chars_result FromCharsImpl(const char* first, const char* last, FloatType& value, chars_format fmt_flags) { @@ -679,6 +803,12 @@ if (HandleEdgeCase(decimal_parse, negative, &value)) { return result; } + // A nullptr subrange_begin means that the decimal_parse.mantissa is exact + // (not truncated), a precondition of the Eisel-Lemire algorithm. + if ((decimal_parse.subrange_begin == nullptr) && + EiselLemire<FloatType>(decimal_parse, negative, &value)) { + return result; + } CalculatedFloat calculated = CalculateFromParsedDecimal<FloatType>(decimal_parse); EncodeResult(calculated, negative, &result, &value); @@ -701,13 +831,20 @@ // Table of powers of 10, from kPower10TableMin to kPower10TableMax. // -// kPower10MantissaTable[i - kPower10TableMin] stores the 64-bit mantissa (high -// bit always on), and kPower10ExponentTable[i - kPower10TableMin] stores the -// power-of-two exponent. For a given number i, this gives the unique mantissa -// and exponent such that mantissa * 2**exponent <= 10**i < (mantissa + 1) * -// 2**exponent. +// kPower10MantissaHighTable[i - kPower10TableMin] stores the 64-bit mantissa +// (high bit always on), and kPower10ExponentTable[i - kPower10TableMin] stores +// the power-of-two exponent. For a given number i, this gives the unique +// mantissa and exponent such that mantissa * 2**exponent <= 10**i < (mantissa +// + 1) * 2**exponent. +// +// kPower10MantissaLowTable extends that 64-bit mantissa to 128 bits. +// +// The tables were generated by +// https://github.com/google/wuffs/blob/315b2e52625ebd7b02d8fac13e3cd85ea374fb80/script/print-mpb-powers-of-10.go +// after re-formatting its output into two arrays of N uint64_t values (instead +// of an N element array of uint64_t pairs). -const uint64_t kPower10MantissaTable[] = { +const uint64_t kPower10MantissaHighTable[] = { 0xeef453d6923bd65aU, 0x9558b4661b6565f8U, 0xbaaee17fa23ebf76U, 0xe95a99df8ace6f53U, 0x91d8a02bb6c10594U, 0xb64ec836a47146f9U, 0xe3e27a444d8d98b7U, 0x8e6d8c6ab0787f72U, 0xb208ef855c969f4fU, @@ -927,6 +1064,226 @@ 0xb6472e511c81471dU, 0xe3d8f9e563a198e5U, 0x8e679c2f5e44ff8fU, }; +const uint64_t kPower10MantissaLowTable[] = { + 0x113faa2906a13b3fU, 0x4ac7ca59a424c507U, 0x5d79bcf00d2df649U, + 0xf4d82c2c107973dcU, 0x79071b9b8a4be869U, 0x9748e2826cdee284U, + 0xfd1b1b2308169b25U, 0xfe30f0f5e50e20f7U, 0xbdbd2d335e51a935U, + 0xad2c788035e61382U, 0x4c3bcb5021afcc31U, 0xdf4abe242a1bbf3dU, + 0xd71d6dad34a2af0dU, 0x8672648c40e5ad68U, 0x680efdaf511f18c2U, + 0x0212bd1b2566def2U, 0x014bb630f7604b57U, 0x419ea3bd35385e2dU, + 0x52064cac828675b9U, 0x7343efebd1940993U, 0x1014ebe6c5f90bf8U, + 0xd41a26e077774ef6U, 0x8920b098955522b4U, 0x55b46e5f5d5535b0U, + 0xeb2189f734aa831dU, 0xa5e9ec7501d523e4U, 0x47b233c92125366eU, + 0x999ec0bb696e840aU, 0xc00670ea43ca250dU, 0x380406926a5e5728U, + 0xc605083704f5ecf2U, 0xf7864a44c633682eU, 0x7ab3ee6afbe0211dU, + 0x5960ea05bad82964U, 0x6fb92487298e33bdU, 0xa5d3b6d479f8e056U, + 0x8f48a4899877186cU, 0x331acdabfe94de87U, 0x9ff0c08b7f1d0b14U, + 0x07ecf0ae5ee44dd9U, 0xc9e82cd9f69d6150U, 0xbe311c083a225cd2U, + 0x6dbd630a48aaf406U, 0x092cbbccdad5b108U, 0x25bbf56008c58ea5U, + 0xaf2af2b80af6f24eU, 0x1af5af660db4aee1U, 0x50d98d9fc890ed4dU, + 0xe50ff107bab528a0U, 0x1e53ed49a96272c8U, 0x25e8e89c13bb0f7aU, + 0x77b191618c54e9acU, 0xd59df5b9ef6a2417U, 0x4b0573286b44ad1dU, + 0x4ee367f9430aec32U, 0x229c41f793cda73fU, 0x6b43527578c1110fU, + 0x830a13896b78aaa9U, 0x23cc986bc656d553U, 0x2cbfbe86b7ec8aa8U, + 0x7bf7d71432f3d6a9U, 0xdaf5ccd93fb0cc53U, 0xd1b3400f8f9cff68U, + 0x23100809b9c21fa1U, 0xabd40a0c2832a78aU, 0x16c90c8f323f516cU, + 0xae3da7d97f6792e3U, 0x99cd11cfdf41779cU, 0x40405643d711d583U, + 0x482835ea666b2572U, 0xda3243650005eecfU, 0x90bed43e40076a82U, + 0x5a7744a6e804a291U, 0x711515d0a205cb36U, 0x0d5a5b44ca873e03U, + 0xe858790afe9486c2U, 0x626e974dbe39a872U, 0xfb0a3d212dc8128fU, + 0x7ce66634bc9d0b99U, 0x1c1fffc1ebc44e80U, 0xa327ffb266b56220U, + 0x4bf1ff9f0062baa8U, 0x6f773fc3603db4a9U, 0xcb550fb4384d21d3U, + 0x7e2a53a146606a48U, 0x2eda7444cbfc426dU, 0xfa911155fefb5308U, + 0x793555ab7eba27caU, 0x4bc1558b2f3458deU, 0x9eb1aaedfb016f16U, + 0x465e15a979c1cadcU, 0x0bfacd89ec191ec9U, 0xcef980ec671f667bU, + 0x82b7e12780e7401aU, 0xd1b2ecb8b0908810U, 0x861fa7e6dcb4aa15U, + 0x67a791e093e1d49aU, 0xe0c8bb2c5c6d24e0U, 0x58fae9f773886e18U, + 0xaf39a475506a899eU, 0x6d8406c952429603U, 0xc8e5087ba6d33b83U, + 0xfb1e4a9a90880a64U, 0x5cf2eea09a55067fU, 0xf42faa48c0ea481eU, + 0xf13b94daf124da26U, 0x76c53d08d6b70858U, 0x54768c4b0c64ca6eU, + 0xa9942f5dcf7dfd09U, 0xd3f93b35435d7c4cU, 0xc47bc5014a1a6dafU, + 0x359ab6419ca1091bU, 0xc30163d203c94b62U, 0x79e0de63425dcf1dU, + 0x985915fc12f542e4U, 0x3e6f5b7b17b2939dU, 0xa705992ceecf9c42U, + 0x50c6ff782a838353U, 0xa4f8bf5635246428U, 0x871b7795e136be99U, + 0x28e2557b59846e3fU, 0x331aeada2fe589cfU, 0x3ff0d2c85def7621U, + 0x0fed077a756b53a9U, 0xd3e8495912c62894U, 0x64712dd7abbbd95cU, + 0xbd8d794d96aacfb3U, 0xecf0d7a0fc5583a0U, 0xf41686c49db57244U, + 0x311c2875c522ced5U, 0x7d633293366b828bU, 0xae5dff9c02033197U, + 0xd9f57f830283fdfcU, 0xd072df63c324fd7bU, 0x4247cb9e59f71e6dU, + 0x52d9be85f074e608U, 0x67902e276c921f8bU, 0x00ba1cd8a3db53b6U, + 0x80e8a40eccd228a4U, 0x6122cd128006b2cdU, 0x796b805720085f81U, + 0xcbe3303674053bb0U, 0xbedbfc4411068a9cU, 0xee92fb5515482d44U, + 0x751bdd152d4d1c4aU, 0xd262d45a78a0635dU, 0x86fb897116c87c34U, + 0xd45d35e6ae3d4da0U, 0x8974836059cca109U, 0x2bd1a438703fc94bU, + 0x7b6306a34627ddcfU, 0x1a3bc84c17b1d542U, 0x20caba5f1d9e4a93U, + 0x547eb47b7282ee9cU, 0xe99e619a4f23aa43U, 0x6405fa00e2ec94d4U, + 0xde83bc408dd3dd04U, 0x9624ab50b148d445U, 0x3badd624dd9b0957U, + 0xe54ca5d70a80e5d6U, 0x5e9fcf4ccd211f4cU, 0x7647c3200069671fU, + 0x29ecd9f40041e073U, 0xf468107100525890U, 0x7182148d4066eeb4U, + 0xc6f14cd848405530U, 0xb8ada00e5a506a7cU, 0xa6d90811f0e4851cU, + 0x908f4a166d1da663U, 0x9a598e4e043287feU, 0x40eff1e1853f29fdU, + 0xd12bee59e68ef47cU, 0x82bb74f8301958ceU, 0xe36a52363c1faf01U, + 0xdc44e6c3cb279ac1U, 0x29ab103a5ef8c0b9U, 0x7415d448f6b6f0e7U, + 0x111b495b3464ad21U, 0xcab10dd900beec34U, 0x3d5d514f40eea742U, + 0x0cb4a5a3112a5112U, 0x47f0e785eaba72abU, 0x59ed216765690f56U, + 0x306869c13ec3532cU, 0x1e414218c73a13fbU, 0xe5d1929ef90898faU, + 0xdf45f746b74abf39U, 0x6b8bba8c328eb783U, 0x066ea92f3f326564U, + 0xc80a537b0efefebdU, 0xbd06742ce95f5f36U, 0x2c48113823b73704U, + 0xf75a15862ca504c5U, 0x9a984d73dbe722fbU, 0xc13e60d0d2e0ebbaU, + 0x318df905079926a8U, 0xfdf17746497f7052U, 0xfeb6ea8bedefa633U, + 0xfe64a52ee96b8fc0U, 0x3dfdce7aa3c673b0U, 0x06bea10ca65c084eU, + 0x486e494fcff30a62U, 0x5a89dba3c3efccfaU, 0xf89629465a75e01cU, + 0xf6bbb397f1135823U, 0x746aa07ded582e2cU, 0xa8c2a44eb4571cdcU, + 0x92f34d62616ce413U, 0x77b020baf9c81d17U, 0x0ace1474dc1d122eU, + 0x0d819992132456baU, 0x10e1fff697ed6c69U, 0xca8d3ffa1ef463c1U, + 0xbd308ff8a6b17cb2U, 0xac7cb3f6d05ddbdeU, 0x6bcdf07a423aa96bU, + 0x86c16c98d2c953c6U, 0xe871c7bf077ba8b7U, 0x11471cd764ad4972U, + 0xd598e40d3dd89bcfU, 0x4aff1d108d4ec2c3U, 0xcedf722a585139baU, + 0xc2974eb4ee658828U, 0x733d226229feea32U, 0x0806357d5a3f525fU, + 0xca07c2dcb0cf26f7U, 0xfc89b393dd02f0b5U, 0xbbac2078d443ace2U, + 0xd54b944b84aa4c0dU, 0x0a9e795e65d4df11U, 0x4d4617b5ff4a16d5U, + 0x504bced1bf8e4e45U, 0xe45ec2862f71e1d6U, 0x5d767327bb4e5a4cU, + 0x3a6a07f8d510f86fU, 0x890489f70a55368bU, 0x2b45ac74ccea842eU, + 0x3b0b8bc90012929dU, 0x09ce6ebb40173744U, 0xcc420a6a101d0515U, + 0x9fa946824a12232dU, 0x47939822dc96abf9U, 0x59787e2b93bc56f7U, + 0x57eb4edb3c55b65aU, 0xede622920b6b23f1U, 0xe95fab368e45ecedU, + 0x11dbcb0218ebb414U, 0xd652bdc29f26a119U, 0x4be76d3346f0495fU, + 0x6f70a4400c562ddbU, 0xcb4ccd500f6bb952U, 0x7e2000a41346a7a7U, + 0x8ed400668c0c28c8U, 0x728900802f0f32faU, 0x4f2b40a03ad2ffb9U, + 0xe2f610c84987bfa8U, 0x0dd9ca7d2df4d7c9U, 0x91503d1c79720dbbU, + 0x75a44c6397ce912aU, 0xc986afbe3ee11abaU, 0xfbe85badce996168U, + 0xfae27299423fb9c3U, 0xdccd879fc967d41aU, 0x5400e987bbc1c920U, + 0x290123e9aab23b68U, 0xf9a0b6720aaf6521U, 0xf808e40e8d5b3e69U, + 0xb60b1d1230b20e04U, 0xb1c6f22b5e6f48c2U, 0x1e38aeb6360b1af3U, + 0x25c6da63c38de1b0U, 0x579c487e5a38ad0eU, 0x2d835a9df0c6d851U, + 0xf8e431456cf88e65U, 0x1b8e9ecb641b58ffU, 0xe272467e3d222f3fU, + 0x5b0ed81dcc6abb0fU, 0x98e947129fc2b4e9U, 0x3f2398d747b36224U, + 0x8eec7f0d19a03aadU, 0x1953cf68300424acU, 0x5fa8c3423c052dd7U, + 0x3792f412cb06794dU, 0xe2bbd88bbee40bd0U, 0x5b6aceaeae9d0ec4U, + 0xf245825a5a445275U, 0xeed6e2f0f0d56712U, 0x55464dd69685606bU, + 0xaa97e14c3c26b886U, 0xd53dd99f4b3066a8U, 0xe546a8038efe4029U, + 0xde98520472bdd033U, 0x963e66858f6d4440U, 0xdde7001379a44aa8U, + 0x5560c018580d5d52U, 0xaab8f01e6e10b4a6U, 0xcab3961304ca70e8U, + 0x3d607b97c5fd0d22U, 0x8cb89a7db77c506aU, 0x77f3608e92adb242U, + 0x55f038b237591ed3U, 0x6b6c46dec52f6688U, 0x2323ac4b3b3da015U, + 0xabec975e0a0d081aU, 0x96e7bd358c904a21U, 0x7e50d64177da2e54U, + 0xdde50bd1d5d0b9e9U, 0x955e4ec64b44e864U, 0xbd5af13bef0b113eU, + 0xecb1ad8aeacdd58eU, 0x67de18eda5814af2U, 0x80eacf948770ced7U, + 0xa1258379a94d028dU, 0x096ee45813a04330U, 0x8bca9d6e188853fcU, + 0x775ea264cf55347dU, 0x95364afe032a819dU, 0x3a83ddbd83f52204U, + 0xc4926a9672793542U, 0x75b7053c0f178293U, 0x5324c68b12dd6338U, + 0xd3f6fc16ebca5e03U, 0x88f4bb1ca6bcf584U, 0x2b31e9e3d06c32e5U, + 0x3aff322e62439fcfU, 0x09befeb9fad487c2U, 0x4c2ebe687989a9b3U, + 0x0f9d37014bf60a10U, 0x538484c19ef38c94U, 0x2865a5f206b06fb9U, + 0xf93f87b7442e45d3U, 0xf78f69a51539d748U, 0xb573440e5a884d1bU, + 0x31680a88f8953030U, 0xfdc20d2b36ba7c3dU, 0x3d32907604691b4cU, + 0xa63f9a49c2c1b10fU, 0x0fcf80dc33721d53U, 0xd3c36113404ea4a8U, + 0x645a1cac083126e9U, 0x3d70a3d70a3d70a3U, 0xccccccccccccccccU, + 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, + 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, + 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, + 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, + 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, + 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, + 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, + 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, + 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, + 0x0000000000000000U, 0x4000000000000000U, 0x5000000000000000U, + 0xa400000000000000U, 0x4d00000000000000U, 0xf020000000000000U, + 0x6c28000000000000U, 0xc732000000000000U, 0x3c7f400000000000U, + 0x4b9f100000000000U, 0x1e86d40000000000U, 0x1314448000000000U, + 0x17d955a000000000U, 0x5dcfab0800000000U, 0x5aa1cae500000000U, + 0xf14a3d9e40000000U, 0x6d9ccd05d0000000U, 0xe4820023a2000000U, + 0xdda2802c8a800000U, 0xd50b2037ad200000U, 0x4526f422cc340000U, + 0x9670b12b7f410000U, 0x3c0cdd765f114000U, 0xa5880a69fb6ac800U, + 0x8eea0d047a457a00U, 0x72a4904598d6d880U, 0x47a6da2b7f864750U, + 0x999090b65f67d924U, 0xfff4b4e3f741cf6dU, 0xbff8f10e7a8921a4U, + 0xaff72d52192b6a0dU, 0x9bf4f8a69f764490U, 0x02f236d04753d5b4U, + 0x01d762422c946590U, 0x424d3ad2b7b97ef5U, 0xd2e0898765a7deb2U, + 0x63cc55f49f88eb2fU, 0x3cbf6b71c76b25fbU, 0x8bef464e3945ef7aU, + 0x97758bf0e3cbb5acU, 0x3d52eeed1cbea317U, 0x4ca7aaa863ee4bddU, + 0x8fe8caa93e74ef6aU, 0xb3e2fd538e122b44U, 0x60dbbca87196b616U, + 0xbc8955e946fe31cdU, 0x6babab6398bdbe41U, 0xc696963c7eed2dd1U, + 0xfc1e1de5cf543ca2U, 0x3b25a55f43294bcbU, 0x49ef0eb713f39ebeU, + 0x6e3569326c784337U, 0x49c2c37f07965404U, 0xdc33745ec97be906U, + 0x69a028bb3ded71a3U, 0xc40832ea0d68ce0cU, 0xf50a3fa490c30190U, + 0x792667c6da79e0faU, 0x577001b891185938U, 0xed4c0226b55e6f86U, + 0x544f8158315b05b4U, 0x696361ae3db1c721U, 0x03bc3a19cd1e38e9U, + 0x04ab48a04065c723U, 0x62eb0d64283f9c76U, 0x3ba5d0bd324f8394U, + 0xca8f44ec7ee36479U, 0x7e998b13cf4e1ecbU, 0x9e3fedd8c321a67eU, + 0xc5cfe94ef3ea101eU, 0xbba1f1d158724a12U, 0x2a8a6e45ae8edc97U, + 0xf52d09d71a3293bdU, 0x593c2626705f9c56U, 0x6f8b2fb00c77836cU, + 0x0b6dfb9c0f956447U, 0x4724bd4189bd5eacU, 0x58edec91ec2cb657U, + 0x2f2967b66737e3edU, 0xbd79e0d20082ee74U, 0xecd8590680a3aa11U, + 0xe80e6f4820cc9495U, 0x3109058d147fdcddU, 0xbd4b46f0599fd415U, + 0x6c9e18ac7007c91aU, 0x03e2cf6bc604ddb0U, 0x84db8346b786151cU, + 0xe612641865679a63U, 0x4fcb7e8f3f60c07eU, 0xe3be5e330f38f09dU, + 0x5cadf5bfd3072cc5U, 0x73d9732fc7c8f7f6U, 0x2867e7fddcdd9afaU, + 0xb281e1fd541501b8U, 0x1f225a7ca91a4226U, 0x3375788de9b06958U, + 0x0052d6b1641c83aeU, 0xc0678c5dbd23a49aU, 0xf840b7ba963646e0U, + 0xb650e5a93bc3d898U, 0xa3e51f138ab4cebeU, 0xc66f336c36b10137U, + 0xb80b0047445d4184U, 0xa60dc059157491e5U, 0x87c89837ad68db2fU, + 0x29babe4598c311fbU, 0xf4296dd6fef3d67aU, 0x1899e4a65f58660cU, + 0x5ec05dcff72e7f8fU, 0x76707543f4fa1f73U, 0x6a06494a791c53a8U, + 0x0487db9d17636892U, 0x45a9d2845d3c42b6U, 0x0b8a2392ba45a9b2U, + 0x8e6cac7768d7141eU, 0x3207d795430cd926U, 0x7f44e6bd49e807b8U, + 0x5f16206c9c6209a6U, 0x36dba887c37a8c0fU, 0xc2494954da2c9789U, + 0xf2db9baa10b7bd6cU, 0x6f92829494e5acc7U, 0xcb772339ba1f17f9U, + 0xff2a760414536efbU, 0xfef5138519684abaU, 0x7eb258665fc25d69U, + 0xef2f773ffbd97a61U, 0xaafb550ffacfd8faU, 0x95ba2a53f983cf38U, + 0xdd945a747bf26183U, 0x94f971119aeef9e4U, 0x7a37cd5601aab85dU, + 0xac62e055c10ab33aU, 0x577b986b314d6009U, 0xed5a7e85fda0b80bU, + 0x14588f13be847307U, 0x596eb2d8ae258fc8U, 0x6fca5f8ed9aef3bbU, + 0x25de7bb9480d5854U, 0xaf561aa79a10ae6aU, 0x1b2ba1518094da04U, + 0x90fb44d2f05d0842U, 0x353a1607ac744a53U, 0x42889b8997915ce8U, + 0x69956135febada11U, 0x43fab9837e699095U, 0x94f967e45e03f4bbU, + 0x1d1be0eebac278f5U, 0x6462d92a69731732U, 0x7d7b8f7503cfdcfeU, + 0x5cda735244c3d43eU, 0x3a0888136afa64a7U, 0x088aaa1845b8fdd0U, + 0x8aad549e57273d45U, 0x36ac54e2f678864bU, 0x84576a1bb416a7ddU, + 0x656d44a2a11c51d5U, 0x9f644ae5a4b1b325U, 0x873d5d9f0dde1feeU, + 0xa90cb506d155a7eaU, 0x09a7f12442d588f2U, 0x0c11ed6d538aeb2fU, + 0x8f1668c8a86da5faU, 0xf96e017d694487bcU, 0x37c981dcc395a9acU, + 0x85bbe253f47b1417U, 0x93956d7478ccec8eU, 0x387ac8d1970027b2U, + 0x06997b05fcc0319eU, 0x441fece3bdf81f03U, 0xd527e81cad7626c3U, + 0x8a71e223d8d3b074U, 0xf6872d5667844e49U, 0xb428f8ac016561dbU, + 0xe13336d701beba52U, 0xecc0024661173473U, 0x27f002d7f95d0190U, + 0x31ec038df7b441f4U, 0x7e67047175a15271U, 0x0f0062c6e984d386U, + 0x52c07b78a3e60868U, 0xa7709a56ccdf8a82U, 0x88a66076400bb691U, + 0x6acff893d00ea435U, 0x0583f6b8c4124d43U, 0xc3727a337a8b704aU, + 0x744f18c0592e4c5cU, 0x1162def06f79df73U, 0x8addcb5645ac2ba8U, + 0x6d953e2bd7173692U, 0xc8fa8db6ccdd0437U, 0x1d9c9892400a22a2U, + 0x2503beb6d00cab4bU, 0x2e44ae64840fd61dU, 0x5ceaecfed289e5d2U, + 0x7425a83e872c5f47U, 0xd12f124e28f77719U, 0x82bd6b70d99aaa6fU, + 0x636cc64d1001550bU, 0x3c47f7e05401aa4eU, 0x65acfaec34810a71U, + 0x7f1839a741a14d0dU, 0x1ede48111209a050U, 0x934aed0aab460432U, + 0xf81da84d5617853fU, 0x36251260ab9d668eU, 0xc1d72b7c6b426019U, + 0xb24cf65b8612f81fU, 0xdee033f26797b627U, 0x169840ef017da3b1U, + 0x8e1f289560ee864eU, 0xf1a6f2bab92a27e2U, 0xae10af696774b1dbU, + 0xacca6da1e0a8ef29U, 0x17fd090a58d32af3U, 0xddfc4b4cef07f5b0U, + 0x4abdaf101564f98eU, 0x9d6d1ad41abe37f1U, 0x84c86189216dc5edU, + 0x32fd3cf5b4e49bb4U, 0x3fbc8c33221dc2a1U, 0x0fabaf3feaa5334aU, + 0x29cb4d87f2a7400eU, 0x743e20e9ef511012U, 0x914da9246b255416U, + 0x1ad089b6c2f7548eU, 0xa184ac2473b529b1U, 0xc9e5d72d90a2741eU, + 0x7e2fa67c7a658892U, 0xddbb901b98feeab7U, 0x552a74227f3ea565U, + 0xd53a88958f87275fU, 0x8a892abaf368f137U, 0x2d2b7569b0432d85U, + 0x9c3b29620e29fc73U, 0x8349f3ba91b47b8fU, 0x241c70a936219a73U, + 0xed238cd383aa0110U, 0xf4363804324a40aaU, 0xb143c6053edcd0d5U, + 0xdd94b7868e94050aU, 0xca7cf2b4191c8326U, 0xfd1c2f611f63a3f0U, + 0xbc633b39673c8cecU, 0xd5be0503e085d813U, 0x4b2d8644d8a74e18U, + 0xddf8e7d60ed1219eU, 0xcabb90e5c942b503U, 0x3d6a751f3b936243U, + 0x0cc512670a783ad4U, 0x27fb2b80668b24c5U, 0xb1f9f660802dedf6U, + 0x5e7873f8a0396973U, 0xdb0b487b6423e1e8U, 0x91ce1a9a3d2cda62U, + 0x7641a140cc7810fbU, 0xa9e904c87fcb0a9dU, 0x546345fa9fbdcd44U, + 0xa97c177947ad4095U, 0x49ed8eabcccc485dU, 0x5c68f256bfff5a74U, + 0x73832eec6fff3111U, 0xc831fd53c5ff7eabU, 0xba3e7ca8b77f5e55U, + 0x28ce1bd2e55f35ebU, 0x7980d163cf5b81b3U, 0xd7e105bcc332621fU, + 0x8dd9472bf3fefaa7U, 0xb14f98f6f0feb951U, 0x6ed1bf9a569f33d3U, + 0x0a862f80ec4700c8U, 0xcd27bb612758c0faU, 0x8038d51cb897789cU, + 0xe0470a63e6bd56c3U, 0x1858ccfce06cac74U, 0x0f37801e0c43ebc8U, + 0xd30560258f54e6baU, 0x47c6b82ef32a2069U, 0x4cdc331d57fa5441U, + 0xe0133fe4adf8e952U, 0x58180fddd97723a6U, 0x570f09eaa7ea7648U, +}; + const int16_t kPower10ExponentTable[] = { -1200, -1196, -1193, -1190, -1186, -1183, -1180, -1176, -1173, -1170, -1166, -1163, -1160, -1156, -1153, -1150, -1146, -1143, -1140, -1136, -1133, -1130,
diff --git a/third_party/abseil-cpp/absl/strings/numbers_test.cc b/third_party/abseil-cpp/absl/strings/numbers_test.cc index 04e4bd2..41e95b8 100644 --- a/third_party/abseil-cpp/absl/strings/numbers_test.cc +++ b/third_party/abseil-cpp/absl/strings/numbers_test.cc
@@ -406,6 +406,19 @@ EXPECT_TRUE(absl::SimpleAtod("-INF", &d)); EXPECT_TRUE(std::isinf(d) && (d < 0)); + // Parse DBL_MAX. Parsing something more than twice as big should also + // produce infinity. + EXPECT_TRUE(absl::SimpleAtod("1.7976931348623157e+308", &d)); + EXPECT_EQ(d, 1.7976931348623157e+308); + EXPECT_TRUE(absl::SimpleAtod("5e308", &d)); + EXPECT_TRUE(std::isinf(d) && (d > 0)); + + // Parse DBL_MIN (normal) and DBL_TRUE_MIN (subnormal). + EXPECT_TRUE(absl::SimpleAtod("2.2250738585072014e-308", &d)); + EXPECT_EQ(d, 2.2250738585072014e-308); + EXPECT_TRUE(absl::SimpleAtod("4.9406564584124654e-324", &d)); + EXPECT_EQ(d, 4.9406564584124654e-324); + // Leading and/or trailing whitespace is OK. EXPECT_TRUE(absl::SimpleAtod(" \t\r\n 2.718", &d)); EXPECT_EQ(d, 2.718); @@ -439,6 +452,14 @@ EXPECT_TRUE(absl::SimpleAtod("8.9", &d)); EXPECT_FALSE(absl::SimpleAtod("8,9", &d)); + // These examples are called out in the EiselLemire function's comments. + EXPECT_TRUE(absl::SimpleAtod("4503599627370497.5", &d)); + EXPECT_EQ(d, 4503599627370497.5); + EXPECT_TRUE(absl::SimpleAtod("1e+23", &d)); + EXPECT_EQ(d, 1e+23); + EXPECT_TRUE(absl::SimpleAtod("9223372036854775807", &d)); + EXPECT_EQ(d, 9223372036854775807); + // Some parsing algorithms don't always round correctly (but absl::SimpleAtod // should). This test case comes from // https://github.com/serde-rs/json/issues/707
diff --git a/third_party/abseil-cpp/absl/strings/string_view_test.cc b/third_party/abseil-cpp/absl/strings/string_view_test.cc index 9d5463a1..990c211 100644 --- a/third_party/abseil-cpp/absl/strings/string_view_test.cc +++ b/third_party/abseil-cpp/absl/strings/string_view_test.cc
@@ -82,7 +82,7 @@ // Null. absl::string_view s10; EXPECT_TRUE(s10.data() == nullptr); - EXPECT_EQ(0, s10.length()); + EXPECT_EQ(0u, s10.length()); } { @@ -90,17 +90,17 @@ const char* hello = "hello"; absl::string_view s20(hello); EXPECT_TRUE(s20.data() == hello); - EXPECT_EQ(5, s20.length()); + EXPECT_EQ(5u, s20.length()); // const char* with length. absl::string_view s21(hello, 4); EXPECT_TRUE(s21.data() == hello); - EXPECT_EQ(4, s21.length()); + EXPECT_EQ(4u, s21.length()); // Not recommended, but valid C++ absl::string_view s22(hello, 6); EXPECT_TRUE(s22.data() == hello); - EXPECT_EQ(6, s22.length()); + EXPECT_EQ(6u, s22.length()); } { @@ -108,7 +108,7 @@ std::string hola = "hola"; absl::string_view s30(hola); EXPECT_TRUE(s30.data() == hola.data()); - EXPECT_EQ(4, s30.length()); + EXPECT_EQ(4u, s30.length()); // std::string with embedded '\0'. hola.push_back('\0'); @@ -116,7 +116,7 @@ hola.push_back('\0'); absl::string_view s31(hola); EXPECT_TRUE(s31.data() == hola.data()); - EXPECT_EQ(8, s31.length()); + EXPECT_EQ(8u, s31.length()); } { @@ -165,7 +165,7 @@ map.insert(std::make_pair(p1, 0)); map.insert(std::make_pair(p2, 1)); map.insert(std::make_pair(p3, 2)); - EXPECT_EQ(map.size(), 3); + EXPECT_EQ(map.size(), 3u); TestMap::const_iterator iter = map.begin(); EXPECT_EQ(iter->second, 1); @@ -183,7 +183,7 @@ EXPECT_TRUE(new_iter != map.end()); map.erase(new_iter); - EXPECT_EQ(map.size(), 2); + EXPECT_EQ(map.size(), 2u); iter = map.begin(); EXPECT_EQ(iter->second, 2); @@ -261,11 +261,11 @@ TEST(StringViewTest, ComparisonOperatorsByCharacterPosition) { std::string x; - for (int i = 0; i < 256; i++) { + for (size_t i = 0; i < 256; i++) { x += 'a'; std::string y = x; COMPARE(true, ==, x, y); - for (int j = 0; j < i; j++) { + for (size_t j = 0; j < i; j++) { std::string z = x; z[j] = 'b'; // Differs in position 'j' COMPARE(false, ==, x, z); @@ -341,12 +341,12 @@ EXPECT_EQ(*(c.rend() - 1), 'x'); EXPECT_TRUE(a.rbegin() + 26 == a.rend()); - EXPECT_EQ(a.size(), 26); - EXPECT_EQ(b.size(), 3); - EXPECT_EQ(c.size(), 3); - EXPECT_EQ(d.size(), 6); - EXPECT_EQ(e.size(), 0); - EXPECT_EQ(f.size(), 7); + EXPECT_EQ(a.size(), 26u); + EXPECT_EQ(b.size(), 3u); + EXPECT_EQ(c.size(), 3u); + EXPECT_EQ(d.size(), 6u); + EXPECT_EQ(e.size(), 0u); + EXPECT_EQ(f.size(), 7u); EXPECT_TRUE(!d.empty()); EXPECT_TRUE(d.begin() != d.end()); @@ -356,17 +356,17 @@ EXPECT_TRUE(e.begin() == e.end()); char buf[4] = { '%', '%', '%', '%' }; - EXPECT_EQ(a.copy(buf, 4), 4); + EXPECT_EQ(a.copy(buf, 4), 4u); EXPECT_EQ(buf[0], a[0]); EXPECT_EQ(buf[1], a[1]); EXPECT_EQ(buf[2], a[2]); EXPECT_EQ(buf[3], a[3]); - EXPECT_EQ(a.copy(buf, 3, 7), 3); + EXPECT_EQ(a.copy(buf, 3, 7), 3u); EXPECT_EQ(buf[0], a[7]); EXPECT_EQ(buf[1], a[8]); EXPECT_EQ(buf[2], a[9]); EXPECT_EQ(buf[3], a[3]); - EXPECT_EQ(c.copy(buf, 99), 3); + EXPECT_EQ(c.copy(buf, 99), 3u); EXPECT_EQ(buf[0], c[0]); EXPECT_EQ(buf[1], c[1]); EXPECT_EQ(buf[2], c[2]); @@ -393,22 +393,22 @@ 7); d = absl::string_view(); - EXPECT_EQ(d.size(), 0); + EXPECT_EQ(d.size(), 0u); EXPECT_TRUE(d.empty()); EXPECT_TRUE(d.data() == nullptr); EXPECT_TRUE(d.begin() == d.end()); - EXPECT_EQ(a.find(b), 0); + EXPECT_EQ(a.find(b), 0u); EXPECT_EQ(a.find(b, 1), absl::string_view::npos); - EXPECT_EQ(a.find(c), 23); - EXPECT_EQ(a.find(c, 9), 23); + EXPECT_EQ(a.find(c), 23u); + EXPECT_EQ(a.find(c, 9), 23u); EXPECT_EQ(a.find(c, absl::string_view::npos), absl::string_view::npos); EXPECT_EQ(b.find(c), absl::string_view::npos); EXPECT_EQ(b.find(c, absl::string_view::npos), absl::string_view::npos); - EXPECT_EQ(a.find(d), 0); - EXPECT_EQ(a.find(e), 0); - EXPECT_EQ(a.find(d, 12), 12); - EXPECT_EQ(a.find(e, 17), 17); + EXPECT_EQ(a.find(d), 0u); + EXPECT_EQ(a.find(e), 0u); + EXPECT_EQ(a.find(d, 12), 12u); + EXPECT_EQ(a.find(e, 17), 17u); absl::string_view g("xx not found bb"); EXPECT_EQ(a.find(g), absl::string_view::npos); // empty string nonsense @@ -427,17 +427,17 @@ EXPECT_EQ(e.find(d, 4), std::string().find(std::string(), 4)); EXPECT_EQ(e.find(e, 4), std::string().find(std::string(), 4)); - EXPECT_EQ(a.find('a'), 0); - EXPECT_EQ(a.find('c'), 2); - EXPECT_EQ(a.find('z'), 25); + EXPECT_EQ(a.find('a'), 0u); + EXPECT_EQ(a.find('c'), 2u); + EXPECT_EQ(a.find('z'), 25u); EXPECT_EQ(a.find('$'), absl::string_view::npos); EXPECT_EQ(a.find('\0'), absl::string_view::npos); - EXPECT_EQ(f.find('\0'), 3); - EXPECT_EQ(f.find('3'), 2); - EXPECT_EQ(f.find('5'), 5); - EXPECT_EQ(g.find('o'), 4); - EXPECT_EQ(g.find('o', 4), 4); - EXPECT_EQ(g.find('o', 5), 8); + EXPECT_EQ(f.find('\0'), 3u); + EXPECT_EQ(f.find('3'), 2u); + EXPECT_EQ(f.find('5'), 5u); + EXPECT_EQ(g.find('o'), 4u); + EXPECT_EQ(g.find('o', 4), 4u); + EXPECT_EQ(g.find('o', 5), 8u); EXPECT_EQ(a.find('b', 5), absl::string_view::npos); // empty string nonsense EXPECT_EQ(d.find('\0'), absl::string_view::npos); @@ -449,8 +449,8 @@ EXPECT_EQ(d.find('x', 4), absl::string_view::npos); EXPECT_EQ(e.find('x', 7), absl::string_view::npos); - EXPECT_EQ(a.find(b.data(), 1, 0), 1); - EXPECT_EQ(a.find(c.data(), 9, 0), 9); + EXPECT_EQ(a.find(b.data(), 1, 0), 1u); + EXPECT_EQ(a.find(c.data(), 9, 0), 9u); EXPECT_EQ(a.find(c.data(), absl::string_view::npos, 0), absl::string_view::npos); EXPECT_EQ(b.find(c.data(), absl::string_view::npos, 0), @@ -460,16 +460,16 @@ EXPECT_EQ(e.find(b.data(), 7, 0), absl::string_view::npos); EXPECT_EQ(a.find(b.data(), 1), absl::string_view::npos); - EXPECT_EQ(a.find(c.data(), 9), 23); + EXPECT_EQ(a.find(c.data(), 9), 23u); EXPECT_EQ(a.find(c.data(), absl::string_view::npos), absl::string_view::npos); EXPECT_EQ(b.find(c.data(), absl::string_view::npos), absl::string_view::npos); // empty string nonsense EXPECT_EQ(d.find(b.data(), 4), absl::string_view::npos); EXPECT_EQ(e.find(b.data(), 7), absl::string_view::npos); - EXPECT_EQ(a.rfind(b), 0); - EXPECT_EQ(a.rfind(b, 1), 0); - EXPECT_EQ(a.rfind(c), 23); + EXPECT_EQ(a.rfind(b), 0u); + EXPECT_EQ(a.rfind(b, 1), 0u); + EXPECT_EQ(a.rfind(c), 23u); EXPECT_EQ(a.rfind(c, 22), absl::string_view::npos); EXPECT_EQ(a.rfind(c, 1), absl::string_view::npos); EXPECT_EQ(a.rfind(c, 0), absl::string_view::npos); @@ -477,8 +477,8 @@ EXPECT_EQ(b.rfind(c, 0), absl::string_view::npos); EXPECT_EQ(a.rfind(d), std::string(a).rfind(std::string())); EXPECT_EQ(a.rfind(e), std::string(a).rfind(std::string())); - EXPECT_EQ(a.rfind(d, 12), 12); - EXPECT_EQ(a.rfind(e, 17), 17); + EXPECT_EQ(a.rfind(d, 12), 12u); + EXPECT_EQ(a.rfind(e, 17), 17u); EXPECT_EQ(a.rfind(g), absl::string_view::npos); EXPECT_EQ(d.rfind(b), absl::string_view::npos); EXPECT_EQ(e.rfind(b), absl::string_view::npos); @@ -494,28 +494,28 @@ EXPECT_EQ(d.rfind(e), std::string().rfind(std::string())); EXPECT_EQ(e.rfind(e), std::string().rfind(std::string())); - EXPECT_EQ(g.rfind('o'), 8); + EXPECT_EQ(g.rfind('o'), 8u); EXPECT_EQ(g.rfind('q'), absl::string_view::npos); - EXPECT_EQ(g.rfind('o', 8), 8); - EXPECT_EQ(g.rfind('o', 7), 4); + EXPECT_EQ(g.rfind('o', 8), 8u); + EXPECT_EQ(g.rfind('o', 7), 4u); EXPECT_EQ(g.rfind('o', 3), absl::string_view::npos); - EXPECT_EQ(f.rfind('\0'), 3); - EXPECT_EQ(f.rfind('\0', 12), 3); - EXPECT_EQ(f.rfind('3'), 2); - EXPECT_EQ(f.rfind('5'), 5); + EXPECT_EQ(f.rfind('\0'), 3u); + EXPECT_EQ(f.rfind('\0', 12), 3u); + EXPECT_EQ(f.rfind('3'), 2u); + EXPECT_EQ(f.rfind('5'), 5u); // empty string nonsense EXPECT_EQ(d.rfind('o'), absl::string_view::npos); EXPECT_EQ(e.rfind('o'), absl::string_view::npos); EXPECT_EQ(d.rfind('o', 4), absl::string_view::npos); EXPECT_EQ(e.rfind('o', 7), absl::string_view::npos); - EXPECT_EQ(a.rfind(b.data(), 1, 0), 1); - EXPECT_EQ(a.rfind(c.data(), 22, 0), 22); - EXPECT_EQ(a.rfind(c.data(), 1, 0), 1); - EXPECT_EQ(a.rfind(c.data(), 0, 0), 0); - EXPECT_EQ(b.rfind(c.data(), 0, 0), 0); - EXPECT_EQ(d.rfind(b.data(), 4, 0), 0); - EXPECT_EQ(e.rfind(b.data(), 7, 0), 0); + EXPECT_EQ(a.rfind(b.data(), 1, 0), 1u); + EXPECT_EQ(a.rfind(c.data(), 22, 0), 22u); + EXPECT_EQ(a.rfind(c.data(), 1, 0), 1u); + EXPECT_EQ(a.rfind(c.data(), 0, 0), 0u); + EXPECT_EQ(b.rfind(c.data(), 0, 0), 0u); + EXPECT_EQ(d.rfind(b.data(), 4, 0), 0u); + EXPECT_EQ(e.rfind(b.data(), 7, 0), 0u); } // Continued from STL2 @@ -533,18 +533,18 @@ absl::string_view g("xx not found bb"); d = absl::string_view(); - EXPECT_EQ(a.find_first_of(b), 0); - EXPECT_EQ(a.find_first_of(b, 0), 0); - EXPECT_EQ(a.find_first_of(b, 1), 1); - EXPECT_EQ(a.find_first_of(b, 2), 2); + EXPECT_EQ(a.find_first_of(b), 0u); + EXPECT_EQ(a.find_first_of(b, 0), 0u); + EXPECT_EQ(a.find_first_of(b, 1), 1u); + EXPECT_EQ(a.find_first_of(b, 2), 2u); EXPECT_EQ(a.find_first_of(b, 3), absl::string_view::npos); - EXPECT_EQ(a.find_first_of(c), 23); - EXPECT_EQ(a.find_first_of(c, 23), 23); - EXPECT_EQ(a.find_first_of(c, 24), 24); - EXPECT_EQ(a.find_first_of(c, 25), 25); + EXPECT_EQ(a.find_first_of(c), 23u); + EXPECT_EQ(a.find_first_of(c, 23), 23u); + EXPECT_EQ(a.find_first_of(c, 24), 24u); + EXPECT_EQ(a.find_first_of(c, 25), 25u); EXPECT_EQ(a.find_first_of(c, 26), absl::string_view::npos); - EXPECT_EQ(g.find_first_of(b), 13); - EXPECT_EQ(g.find_first_of(c), 0); + EXPECT_EQ(g.find_first_of(b), 13u); + EXPECT_EQ(g.find_first_of(c), 0u); EXPECT_EQ(a.find_first_of(f), absl::string_view::npos); EXPECT_EQ(f.find_first_of(a), absl::string_view::npos); // empty string nonsense @@ -557,19 +557,19 @@ EXPECT_EQ(d.find_first_of(e), absl::string_view::npos); EXPECT_EQ(e.find_first_of(e), absl::string_view::npos); - EXPECT_EQ(a.find_first_not_of(b), 3); - EXPECT_EQ(a.find_first_not_of(c), 0); + EXPECT_EQ(a.find_first_not_of(b), 3u); + EXPECT_EQ(a.find_first_not_of(c), 0u); EXPECT_EQ(b.find_first_not_of(a), absl::string_view::npos); EXPECT_EQ(c.find_first_not_of(a), absl::string_view::npos); - EXPECT_EQ(f.find_first_not_of(a), 0); - EXPECT_EQ(a.find_first_not_of(f), 0); - EXPECT_EQ(a.find_first_not_of(d), 0); - EXPECT_EQ(a.find_first_not_of(e), 0); + EXPECT_EQ(f.find_first_not_of(a), 0u); + EXPECT_EQ(a.find_first_not_of(f), 0u); + EXPECT_EQ(a.find_first_not_of(d), 0u); + EXPECT_EQ(a.find_first_not_of(e), 0u); // empty string nonsense - EXPECT_EQ(a.find_first_not_of(d), 0); - EXPECT_EQ(a.find_first_not_of(e), 0); - EXPECT_EQ(a.find_first_not_of(d, 1), 1); - EXPECT_EQ(a.find_first_not_of(e, 1), 1); + EXPECT_EQ(a.find_first_not_of(d), 0u); + EXPECT_EQ(a.find_first_not_of(e), 0u); + EXPECT_EQ(a.find_first_not_of(d, 1), 1u); + EXPECT_EQ(a.find_first_not_of(e, 1), 1u); EXPECT_EQ(a.find_first_not_of(d, a.size() - 1), a.size() - 1); EXPECT_EQ(a.find_first_not_of(e, a.size() - 1), a.size() - 1); EXPECT_EQ(a.find_first_not_of(d, a.size()), absl::string_view::npos); @@ -588,11 +588,11 @@ absl::string_view h("===="); EXPECT_EQ(h.find_first_not_of('='), absl::string_view::npos); EXPECT_EQ(h.find_first_not_of('=', 3), absl::string_view::npos); - EXPECT_EQ(h.find_first_not_of('\0'), 0); - EXPECT_EQ(g.find_first_not_of('x'), 2); - EXPECT_EQ(f.find_first_not_of('\0'), 0); - EXPECT_EQ(f.find_first_not_of('\0', 3), 4); - EXPECT_EQ(f.find_first_not_of('\0', 2), 2); + EXPECT_EQ(h.find_first_not_of('\0'), 0u); + EXPECT_EQ(g.find_first_not_of('x'), 2u); + EXPECT_EQ(f.find_first_not_of('\0'), 0u); + EXPECT_EQ(f.find_first_not_of('\0', 3), 4u); + EXPECT_EQ(f.find_first_not_of('\0', 2), 2u); // empty string nonsense EXPECT_EQ(d.find_first_not_of('x'), absl::string_view::npos); EXPECT_EQ(e.find_first_not_of('x'), absl::string_view::npos); @@ -618,20 +618,20 @@ d = absl::string_view(); EXPECT_EQ(h.find_last_of(a), absl::string_view::npos); - EXPECT_EQ(g.find_last_of(a), g.size()-1); - EXPECT_EQ(a.find_last_of(b), 2); - EXPECT_EQ(a.find_last_of(c), a.size()-1); - EXPECT_EQ(f.find_last_of(i), 6); - EXPECT_EQ(a.find_last_of('a'), 0); - EXPECT_EQ(a.find_last_of('b'), 1); - EXPECT_EQ(a.find_last_of('z'), 25); - EXPECT_EQ(a.find_last_of('a', 5), 0); - EXPECT_EQ(a.find_last_of('b', 5), 1); + EXPECT_EQ(g.find_last_of(a), g.size() - 1); + EXPECT_EQ(a.find_last_of(b), 2u); + EXPECT_EQ(a.find_last_of(c), a.size() - 1); + EXPECT_EQ(f.find_last_of(i), 6u); + EXPECT_EQ(a.find_last_of('a'), 0u); + EXPECT_EQ(a.find_last_of('b'), 1u); + EXPECT_EQ(a.find_last_of('z'), 25u); + EXPECT_EQ(a.find_last_of('a', 5), 0u); + EXPECT_EQ(a.find_last_of('b', 5), 1u); EXPECT_EQ(a.find_last_of('b', 0), absl::string_view::npos); - EXPECT_EQ(a.find_last_of('z', 25), 25); + EXPECT_EQ(a.find_last_of('z', 25), 25u); EXPECT_EQ(a.find_last_of('z', 24), absl::string_view::npos); - EXPECT_EQ(f.find_last_of(i, 5), 5); - EXPECT_EQ(f.find_last_of(i, 6), 6); + EXPECT_EQ(f.find_last_of(i, 5), 5u); + EXPECT_EQ(f.find_last_of(i, 6), 6u); EXPECT_EQ(f.find_last_of(a, 4), absl::string_view::npos); // empty string nonsense EXPECT_EQ(f.find_last_of(d), absl::string_view::npos); @@ -651,19 +651,19 @@ EXPECT_EQ(d.find_last_of(f, 4), absl::string_view::npos); EXPECT_EQ(e.find_last_of(f, 4), absl::string_view::npos); - EXPECT_EQ(a.find_last_not_of(b), a.size()-1); - EXPECT_EQ(a.find_last_not_of(c), 22); + EXPECT_EQ(a.find_last_not_of(b), a.size() - 1); + EXPECT_EQ(a.find_last_not_of(c), 22u); EXPECT_EQ(b.find_last_not_of(a), absl::string_view::npos); EXPECT_EQ(b.find_last_not_of(b), absl::string_view::npos); - EXPECT_EQ(f.find_last_not_of(i), 4); - EXPECT_EQ(a.find_last_not_of(c, 24), 22); - EXPECT_EQ(a.find_last_not_of(b, 3), 3); + EXPECT_EQ(f.find_last_not_of(i), 4u); + EXPECT_EQ(a.find_last_not_of(c, 24), 22u); + EXPECT_EQ(a.find_last_not_of(b, 3), 3u); EXPECT_EQ(a.find_last_not_of(b, 2), absl::string_view::npos); // empty string nonsense - EXPECT_EQ(f.find_last_not_of(d), f.size()-1); - EXPECT_EQ(f.find_last_not_of(e), f.size()-1); - EXPECT_EQ(f.find_last_not_of(d, 4), 4); - EXPECT_EQ(f.find_last_not_of(e, 4), 4); + EXPECT_EQ(f.find_last_not_of(d), f.size() - 1); + EXPECT_EQ(f.find_last_not_of(e), f.size() - 1); + EXPECT_EQ(f.find_last_not_of(d, 4), 4u); + EXPECT_EQ(f.find_last_not_of(e, 4), 4u); EXPECT_EQ(d.find_last_not_of(d), absl::string_view::npos); EXPECT_EQ(d.find_last_not_of(e), absl::string_view::npos); EXPECT_EQ(e.find_last_not_of(d), absl::string_view::npos); @@ -679,10 +679,10 @@ EXPECT_EQ(h.find_last_not_of('x'), h.size() - 1); EXPECT_EQ(h.find_last_not_of('='), absl::string_view::npos); - EXPECT_EQ(b.find_last_not_of('c'), 1); - EXPECT_EQ(h.find_last_not_of('x', 2), 2); + EXPECT_EQ(b.find_last_not_of('c'), 1u); + EXPECT_EQ(h.find_last_not_of('x', 2), 2u); EXPECT_EQ(h.find_last_not_of('=', 2), absl::string_view::npos); - EXPECT_EQ(b.find_last_not_of('b', 1), 0); + EXPECT_EQ(b.find_last_not_of('b', 1), 0u); // empty string nonsense EXPECT_EQ(d.find_last_not_of('x'), absl::string_view::npos); EXPECT_EQ(e.find_last_not_of('x'), absl::string_view::npos); @@ -734,7 +734,7 @@ TEST(StringViewTest, UTF8) { std::string utf8 = "\u00E1"; std::string utf8_twice = utf8 + " " + utf8; - int utf8_len = strlen(utf8.data()); + size_t utf8_len = strlen(utf8.data()); EXPECT_EQ(utf8_len, absl::string_view(utf8_twice).find_first_of(" ")); EXPECT_EQ(utf8_len, absl::string_view(utf8_twice).find_first_of(" \t")); } @@ -879,12 +879,12 @@ TEST(StringViewTest, NULLInput) { absl::string_view s; EXPECT_EQ(s.data(), nullptr); - EXPECT_EQ(s.size(), 0); + EXPECT_EQ(s.size(), 0u); #ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR s = absl::string_view(nullptr); EXPECT_EQ(s.data(), nullptr); - EXPECT_EQ(s.size(), 0); + EXPECT_EQ(s.size(), 0u); // .ToString() on a absl::string_view with nullptr should produce the empty // string. @@ -959,7 +959,7 @@ { absl::string_view s = absl::NullSafeStringView(nullptr); EXPECT_EQ(nullptr, s.data()); - EXPECT_EQ(0, s.size()); + EXPECT_EQ(0u, s.size()); EXPECT_EQ(absl::string_view(), s); } { @@ -975,7 +975,7 @@ { constexpr absl::string_view s = absl::NullSafeStringView(nullptr); EXPECT_EQ(nullptr, s.data()); - EXPECT_EQ(0, s.size()); + EXPECT_EQ(0u, s.size()); EXPECT_EQ(absl::string_view(), s); } #if !defined(_MSC_VER) || _MSC_VER >= 1910 @@ -990,7 +990,7 @@ } { constexpr absl::string_view s = absl::NullSafeStringView("hello"); - EXPECT_EQ(s.size(), 5); + EXPECT_EQ(s.size(), 5u); EXPECT_EQ("hello", s); } #endif @@ -1036,7 +1036,7 @@ #ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR constexpr absl::string_view cstr_strlen("foo"); - EXPECT_EQ(cstr_strlen.length(), 3); + EXPECT_EQ(cstr_strlen.length(), 3u); constexpr absl::string_view cstr_strlen2 = "bar"; EXPECT_EQ(cstr_strlen2, "bar"); @@ -1111,7 +1111,7 @@ EXPECT_NE(cstr_ptr, nullptr); constexpr size_t sp_npos = sp.npos; - EXPECT_EQ(sp_npos, -1); + EXPECT_EQ(sp_npos, static_cast<size_t>(-1)); } constexpr char ConstexprMethodsHelper() { @@ -1179,7 +1179,7 @@ // Abseil's string_view implementation has bounds-checking in debug mode. absl::string_view h = "hello"; ABSL_EXPECT_DEATH_IF_SUPPORTED(h[5], ""); - ABSL_EXPECT_DEATH_IF_SUPPORTED(h[-1], ""); + ABSL_EXPECT_DEATH_IF_SUPPORTED(h[static_cast<size_t>(-1)], ""); #endif #endif } @@ -1201,17 +1201,17 @@ a.remove_prefix(1); a.remove_suffix(1); - EXPECT_EQ(0, a.find('x')); - EXPECT_EQ(0, a.find('x', 0)); - EXPECT_EQ(4, a.find('x', 1)); - EXPECT_EQ(4, a.find('x', 4)); + EXPECT_EQ(0u, a.find('x')); + EXPECT_EQ(0u, a.find('x', 0)); + EXPECT_EQ(4u, a.find('x', 1)); + EXPECT_EQ(4u, a.find('x', 4)); EXPECT_EQ(absl::string_view::npos, a.find('x', 5)); - EXPECT_EQ(4, a.rfind('x')); - EXPECT_EQ(4, a.rfind('x', 5)); - EXPECT_EQ(4, a.rfind('x', 4)); - EXPECT_EQ(0, a.rfind('x', 3)); - EXPECT_EQ(0, a.rfind('x', 0)); + EXPECT_EQ(4u, a.rfind('x')); + EXPECT_EQ(4u, a.rfind('x', 5)); + EXPECT_EQ(4u, a.rfind('x', 4)); + EXPECT_EQ(0u, a.rfind('x', 3)); + EXPECT_EQ(0u, a.rfind('x', 0)); // Set a = "yyy". a.remove_prefix(1); @@ -1239,8 +1239,8 @@ #if !defined(NDEBUG) && !defined(ABSL_USES_STD_STRING_VIEW) TEST(NonNegativeLenTest, NonNegativeLen) { - ABSL_EXPECT_DEATH_IF_SUPPORTED(absl::string_view("xyz", -1), - "len <= kMaxSize"); + ABSL_EXPECT_DEATH_IF_SUPPORTED( + absl::string_view("xyz", static_cast<size_t>(-1)), "len <= kMaxSize"); } TEST(LenExceedsMaxSizeTest, LenExceedsMaxSize) {
diff --git a/third_party/abseil-cpp/absl/synchronization/internal/futex.h b/third_party/abseil-cpp/absl/synchronization/internal/futex.h index 06fbd6d..cb97da09c 100644 --- a/third_party/abseil-cpp/absl/synchronization/internal/futex.h +++ b/third_party/abseil-cpp/absl/synchronization/internal/futex.h
@@ -87,7 +87,7 @@ public: static int WaitUntil(std::atomic<int32_t> *v, int32_t val, KernelTimeout t) { - int err = 0; + long err = 0; // NOLINT(runtime/int) if (t.has_timeout()) { // https://locklessinc.com/articles/futex_cheat_sheet/ // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time. @@ -105,41 +105,44 @@ FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr); } if (ABSL_PREDICT_FALSE(err != 0)) { - err = -errno; + return -errno; } - return err; + return 0; } static int WaitBitsetAbsoluteTimeout(std::atomic<int32_t> *v, int32_t val, int32_t bits, const struct timespec *abstime) { - int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v), - FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, val, abstime, - nullptr, bits); + // NOLINTNEXTLINE(runtime/int) + long err = syscall(SYS_futex, reinterpret_cast<int32_t*>(v), + FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, val, abstime, + nullptr, bits); if (ABSL_PREDICT_FALSE(err != 0)) { - err = -errno; + return -errno; } - return err; + return 0; } static int Wake(std::atomic<int32_t> *v, int32_t count) { - int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v), - FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count); + // NOLINTNEXTLINE(runtime/int) + long err = syscall(SYS_futex, reinterpret_cast<int32_t*>(v), + FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count); if (ABSL_PREDICT_FALSE(err < 0)) { - err = -errno; + return -errno; } - return err; + return 0; } // FUTEX_WAKE_BITSET static int WakeBitset(std::atomic<int32_t> *v, int32_t count, int32_t bits) { - int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v), - FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG, count, nullptr, - nullptr, bits); + // NOLINTNEXTLINE(runtime/int) + long err = syscall(SYS_futex, reinterpret_cast<int32_t*>(v), + FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG, count, nullptr, + nullptr, bits); if (ABSL_PREDICT_FALSE(err < 0)) { - err = -errno; + return -errno; } - return err; + return 0; } };
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.cc b/third_party/abseil-cpp/absl/synchronization/mutex.cc index 144fdee..c0268b62 100644 --- a/third_party/abseil-cpp/absl/synchronization/mutex.cc +++ b/third_party/abseil-cpp/absl/synchronization/mutex.cc
@@ -1801,8 +1801,8 @@ // operation tsan considers that we've already released the mutex. bool res = false; #ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE - const int flags = read_lock ? __tsan_mutex_read_lock : 0; - const int tryflags = flags | (trylock ? __tsan_mutex_try_lock : 0); + const uint32_t flags = read_lock ? __tsan_mutex_read_lock : 0; + const uint32_t tryflags = flags | (trylock ? __tsan_mutex_try_lock : 0); #endif if (locking) { // For lock we pretend that we have finished the operation,
diff --git a/third_party/abseil-cpp/absl/time/duration.cc b/third_party/abseil-cpp/absl/time/duration.cc index 1f4cf38..911e80f 100644 --- a/third_party/abseil-cpp/absl/time/duration.cc +++ b/third_party/abseil-cpp/absl/time/duration.cc
@@ -617,7 +617,7 @@ rep_lo -= kTicksPerSecond; } } - ts.tv_sec = rep_hi; + ts.tv_sec = static_cast<decltype(ts.tv_sec)>(rep_hi); if (ts.tv_sec == rep_hi) { // no time_t narrowing ts.tv_nsec = rep_lo / kTicksPerNanosecond; return ts; @@ -691,7 +691,7 @@ char* Format64(char* ep, int width, int64_t v) { do { --width; - *--ep = '0' + (v % 10); // contiguous digits + *--ep = static_cast<char>('0' + (v % 10)); // contiguous digits } while (v /= 10); while (--width >= 0) *--ep = '0'; // zero pad return ep;
diff --git a/third_party/abseil-cpp/absl/time/internal/test_util.cc b/third_party/abseil-cpp/absl/time/internal/test_util.cc index 454b33a..4b7849c6 100644 --- a/third_party/abseil-cpp/absl/time/internal/test_util.cc +++ b/third_party/abseil-cpp/absl/time/internal/test_util.cc
@@ -84,14 +84,15 @@ : data_(data), end_(data + size) {} std::size_t Read(void* ptr, std::size_t size) override { - const std::size_t len = std::min<std::size_t>(size, end_ - data_); + const std::size_t len = + std::min(size, static_cast<std::size_t>(end_ - data_)); memcpy(ptr, data_, len); data_ += len; return len; } int Skip(std::size_t offset) override { - data_ += std::min<std::size_t>(offset, end_ - data_); + data_ += std::min(offset, static_cast<std::size_t>(end_ - data_)); return 0; }
diff --git a/third_party/abseil-cpp/absl/time/time.cc b/third_party/abseil-cpp/absl/time/time.cc index 718b88c8..7256a69 100644 --- a/third_party/abseil-cpp/absl/time/time.cc +++ b/third_party/abseil-cpp/absl/time/time.cc
@@ -297,7 +297,7 @@ timespec ts; absl::Duration d = time_internal::ToUnixDuration(t); if (!time_internal::IsInfiniteDuration(d)) { - ts.tv_sec = time_internal::GetRepHi(d); + ts.tv_sec = static_cast<decltype(ts.tv_sec)>(time_internal::GetRepHi(d)); if (ts.tv_sec == time_internal::GetRepHi(d)) { // no time_t narrowing ts.tv_nsec = time_internal::GetRepLo(d) / 4; // floor return ts;
diff --git a/third_party/abseil-cpp/absl/types/optional_test.cc b/third_party/abseil-cpp/absl/types/optional_test.cc index 9477c150..21653a9 100644 --- a/third_party/abseil-cpp/absl/types/optional_test.cc +++ b/third_party/abseil-cpp/absl/types/optional_test.cc
@@ -988,8 +988,8 @@ EXPECT_EQ("foo", *opt); const auto& opt_const = opt; EXPECT_EQ("foo", *opt_const); - EXPECT_EQ(opt->size(), 3); - EXPECT_EQ(opt_const->size(), 3); + EXPECT_EQ(opt->size(), 3u); + EXPECT_EQ(opt_const->size(), 3u); constexpr absl::optional<ConstexprType> opt1(1); static_assert((*opt1).x == ConstexprType::kCtorInt, ""); @@ -1523,7 +1523,7 @@ for (int i = 0; i < 100; ++i) { hashcodes.insert(hash(i)); } - EXPECT_GT(hashcodes.size(), 90); + EXPECT_GT(hashcodes.size(), 90u); static_assert(is_hash_enabled_for<absl::optional<int>>::value, ""); static_assert(is_hash_enabled_for<absl::optional<Hashable>>::value, "");
diff --git a/third_party/abseil-cpp/absl/types/variant_test.cc b/third_party/abseil-cpp/absl/types/variant_test.cc index cf23733..4cd5b7a 100644 --- a/third_party/abseil-cpp/absl/types/variant_test.cc +++ b/third_party/abseil-cpp/absl/types/variant_test.cc
@@ -281,7 +281,7 @@ using X = variant<int>; constexpr variant<int> x{}; ASSERT_FALSE(x.valueless_by_exception()); - ASSERT_EQ(0, x.index()); + ASSERT_EQ(0u, x.index()); EXPECT_EQ(0, absl::get<0>(x)); EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value); } @@ -290,7 +290,7 @@ using X = variant<NonNoexceptDefaultConstructible>; X x{}; ASSERT_FALSE(x.valueless_by_exception()); - ASSERT_EQ(0, x.index()); + ASSERT_EQ(0u, x.index()); EXPECT_EQ(5, absl::get<0>(x).value); EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value); } @@ -299,7 +299,7 @@ using X = variant<int, NonNoexceptDefaultConstructible>; X x{}; ASSERT_FALSE(x.valueless_by_exception()); - ASSERT_EQ(0, x.index()); + ASSERT_EQ(0u, x.index()); EXPECT_EQ(0, absl::get<0>(x)); EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value); } @@ -308,7 +308,7 @@ using X = variant<NonNoexceptDefaultConstructible, int>; X x{}; ASSERT_FALSE(x.valueless_by_exception()); - ASSERT_EQ(0, x.index()); + ASSERT_EQ(0u, x.index()); EXPECT_EQ(5, absl::get<0>(x).value); EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value); } @@ -480,7 +480,7 @@ ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); EXPECT_EQ("ABC", absl::get<std::string>(v2)); - Var v3(in_place_type_t<std::string>(), "ABC", 2); + Var v3(in_place_type_t<std::string>(), "ABC", 2u); ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); EXPECT_EQ("AB", absl::get<std::string>(v3)); @@ -503,7 +503,7 @@ ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); EXPECT_EQ("ABC", absl::get<std::string>(v2)); - Var v3(in_place_type<std::string>, "ABC", 2); + Var v3(in_place_type<std::string>, "ABC", 2u); ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); EXPECT_EQ("AB", absl::get<std::string>(v3)); @@ -544,7 +544,7 @@ ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); EXPECT_EQ("ABC", absl::get<std::string>(v2)); - Var v3(in_place_index_t<1>(), "ABC", 2); + Var v3(in_place_index_t<1>(), "ABC", 2u); ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); EXPECT_EQ("AB", absl::get<std::string>(v3)); @@ -571,7 +571,7 @@ ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); EXPECT_EQ("ABC", absl::get<std::string>(v2)); - Var v3(in_place_index<1>, "ABC", 2); + Var v3(in_place_index<1>, "ABC", 2u); ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); EXPECT_EQ("AB", absl::get<std::string>(v3)); @@ -688,11 +688,11 @@ EXPECT_EQ(long_str, foo); variant<int, std::string> so = long_str; - ASSERT_EQ(1, so.index()); + ASSERT_EQ(1u, so.index()); EXPECT_EQ(long_str, absl::get<1>(so)); so = *&so; - ASSERT_EQ(1, so.index()); + ASSERT_EQ(1u, so.index()); EXPECT_EQ(long_str, absl::get<1>(so)); } @@ -968,16 +968,16 @@ using Var = variant<int, std::string, double>; Var v = 1; - EXPECT_EQ(0, v.index()); + EXPECT_EQ(0u, v.index()); v = "str"; - EXPECT_EQ(1, v.index()); + EXPECT_EQ(1u, v.index()); v = 0.; - EXPECT_EQ(2, v.index()); + EXPECT_EQ(2u, v.index()); Var v2 = v; - EXPECT_EQ(2, v2.index()); + EXPECT_EQ(2u, v2.index()); v2.emplace<int>(3); - EXPECT_EQ(0, v2.index()); + EXPECT_EQ(0u, v2.index()); } TEST(VariantTest, NotValuelessByException) { @@ -1002,11 +1002,11 @@ using Var = variant<MoveCanThrow, std::string, double>; Var v(absl::in_place_index<0>); - EXPECT_EQ(0, v.index()); + EXPECT_EQ(0u, v.index()); ToValuelessByException(v); EXPECT_EQ(absl::variant_npos, v.index()); v = "str"; - EXPECT_EQ(1, v.index()); + EXPECT_EQ(1u, v.index()); } TEST(VariantTest, ValuelessByException) { @@ -1084,18 +1084,18 @@ TEST(VariantTest, VariantSize) { { using Size1Variant = absl::variant<int>; - EXPECT_EQ(1, absl::variant_size<Size1Variant>::value); - EXPECT_EQ(1, absl::variant_size<const Size1Variant>::value); - EXPECT_EQ(1, absl::variant_size<volatile Size1Variant>::value); - EXPECT_EQ(1, absl::variant_size<const volatile Size1Variant>::value); + EXPECT_EQ(1u, absl::variant_size<Size1Variant>::value); + EXPECT_EQ(1u, absl::variant_size<const Size1Variant>::value); + EXPECT_EQ(1u, absl::variant_size<volatile Size1Variant>::value); + EXPECT_EQ(1u, absl::variant_size<const volatile Size1Variant>::value); } { using Size3Variant = absl::variant<int, float, int>; - EXPECT_EQ(3, absl::variant_size<Size3Variant>::value); - EXPECT_EQ(3, absl::variant_size<const Size3Variant>::value); - EXPECT_EQ(3, absl::variant_size<volatile Size3Variant>::value); - EXPECT_EQ(3, absl::variant_size<const volatile Size3Variant>::value); + EXPECT_EQ(3u, absl::variant_size<Size3Variant>::value); + EXPECT_EQ(3u, absl::variant_size<const Size3Variant>::value); + EXPECT_EQ(3u, absl::variant_size<volatile Size3Variant>::value); + EXPECT_EQ(3u, absl::variant_size<const volatile Size3Variant>::value); } } @@ -1799,14 +1799,14 @@ EXPECT_EQ("B", piece); struct StrLen { - int operator()(const char* s) const { return strlen(s); } - int operator()(const std::string& s) const { return s.size(); } + size_t operator()(const char* s) const { return strlen(s); } + size_t operator()(const std::string& s) const { return s.size(); } }; v = "SomeStr"; - EXPECT_EQ(7, absl::visit(StrLen{}, v)); + EXPECT_EQ(7u, absl::visit(StrLen{}, v)); v = std::string("VeryLargeThisTime"); - EXPECT_EQ(17, absl::visit(StrLen{}, v)); + EXPECT_EQ(17u, absl::visit(StrLen{}, v)); } TEST(VariantTest, VisitRValue) { @@ -1979,7 +1979,7 @@ TEST(VariantTest, VariantMonostateDefaultConstruction) { absl::variant<absl::monostate, NonDefaultConstructible> var; - EXPECT_EQ(var.index(), 0); + EXPECT_EQ(var.index(), 0u); } //////////////////////////////// @@ -2100,7 +2100,7 @@ for (int i = 0; i < 100; ++i) { hashcodes.insert(hash(i)); } - EXPECT_GT(hashcodes.size(), 90); + EXPECT_GT(hashcodes.size(), 90u); // test const-qualified static_assert(type_traits_internal::IsHashable<variant<const int>>::value, @@ -2312,9 +2312,9 @@ EXPECT_EQ(42, absl::get<int32_t>(variant2)); variant2 = - ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42)); + ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42u)); ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2)); - EXPECT_EQ(42, absl::get<uint32_t>(variant2)); + EXPECT_EQ(42u, absl::get<uint32_t>(variant2)); #endif // !ABSL_USES_STD_VARIANT variant<Convertible1, Convertible2> variant3( @@ -2361,10 +2361,10 @@ ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2)); EXPECT_EQ(42, absl::get<int32_t>(variant2)); - variant<uint32_t> source6(42); + variant<uint32_t> source6(42u); variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6); ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2)); - EXPECT_EQ(42, absl::get<uint32_t>(variant2)); + EXPECT_EQ(42u, absl::get<uint32_t>(variant2)); #endif variant<Convertible2, Convertible1> source7((Convertible1())); @@ -2455,8 +2455,8 @@ EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42)); variant2 = - ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42)); - EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42)); + ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42u)); + EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42u)); #endif variant<Convertible1, Convertible2> variant3( @@ -2499,9 +2499,9 @@ ConvertVariantTo<variant<int32_t, uint32_t>>(source5)); EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42)); - variant<uint32_t> source6(42); + variant<uint32_t> source6(42u); variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6); - EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42)); + EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42u)); #endif // !ABSL_USES_STD_VARIANT variant<Convertible2, Convertible1> source7((Convertible1())); @@ -2570,7 +2570,7 @@ vec.reserve(3); auto another_vec = absl::move(vec); // As a sanity check, verify vector contents. - ASSERT_EQ(2, another_vec.size()); + ASSERT_EQ(2u, another_vec.size()); EXPECT_EQ(42, *absl::get<std::unique_ptr<int>>(another_vec[0])); EXPECT_EQ("Hello", absl::get<std::string>(another_vec[1])); }
diff --git a/third_party/blink/renderer/bindings/core/v8/array_value.cc b/third_party/blink/renderer/bindings/core/v8/array_value.cc index 5a02a8150..338811c9 100644 --- a/third_party/blink/renderer/bindings/core/v8/array_value.cc +++ b/third_party/blink/renderer/bindings/core/v8/array_value.cc
@@ -52,7 +52,7 @@ return false; DCHECK(isolate_); - DCHECK_EQ(isolate_, v8::Isolate::GetCurrent()); + DCHECK(isolate_->IsCurrent()); v8::Local<v8::Value> indexed_value; if (!array_->Get(isolate_->GetCurrentContext(), index) .ToLocal(&indexed_value) ||
diff --git a/third_party/blink/renderer/bindings/core/v8/dictionary.cc b/third_party/blink/renderer/bindings/core/v8/dictionary.cc index 3dc9540..3b1613f 100644 --- a/third_party/blink/renderer/bindings/core/v8/dictionary.cc +++ b/third_party/blink/renderer/bindings/core/v8/dictionary.cc
@@ -80,7 +80,7 @@ if (v8_value->IsObject()) { DCHECK(isolate_); - DCHECK_EQ(isolate_, v8::Isolate::GetCurrent()); + DCHECK(isolate_->IsCurrent()); // TODO(bashi,yukishiino): Should rethrow the exception. // http://crbug.com/666661 DummyExceptionStateForTesting exception_state;
diff --git a/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc b/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc index bf9b96d..3738ca6 100644 --- a/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc +++ b/third_party/blink/renderer/bindings/core/v8/dictionary_helper_for_core.cc
@@ -245,7 +245,7 @@ return false; DCHECK(dictionary.GetIsolate()); - DCHECK_EQ(dictionary.GetIsolate(), v8::Isolate::GetCurrent()); + DCHECK(dictionary.GetIsolate()->IsCurrent()); value = ArrayValue(v8::Local<v8::Array>::Cast(v8_value), dictionary.GetIsolate()); return true;
diff --git a/third_party/blink/renderer/bindings/core/v8/script_value.h b/third_party/blink/renderer/bindings/core/v8/script_value.h index 6023c97a..c86566f 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_value.h +++ b/third_party/blink/renderer/bindings/core/v8/script_value.h
@@ -164,11 +164,11 @@ namespace WTF { +// VectorTraits for ScriptValue depend entirely on +// WorldSafeV8Reference<v8::Value>. template <> -struct VectorTraits<blink::ScriptValue> : VectorTraitsBase<blink::ScriptValue> { - STATIC_ONLY(VectorTraits); - static constexpr bool kCanClearUnusedSlotsWithMemset = true; -}; +struct VectorTraits<blink::ScriptValue> + : VectorTraits<blink::WorldSafeV8Reference<v8::Value>> {}; } // namespace WTF
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc index a2d4642..18d28ec9 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
@@ -86,7 +86,7 @@ #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/scheduler/public/cooperative_scheduling_manager.h" -#include "third_party/blink/renderer/platform/scheduler/public/thread.h" +#include "third_party/blink/renderer/platform/scheduler/public/main_thread.h" #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/reporting_disposition.h" @@ -149,7 +149,7 @@ void V8Initializer::MessageHandlerInMainThread(v8::Local<v8::Message> message, v8::Local<v8::Value> data) { DCHECK(IsMainThread()); - v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Isolate* isolate = message->GetIsolate(); if (isolate->GetEnteredOrMicrotaskContext().IsEmpty()) return; @@ -192,7 +192,7 @@ void V8Initializer::MessageHandlerInWorker(v8::Local<v8::Message> message, v8::Local<v8::Value> data) { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Isolate* isolate = message->GetIsolate(); // During the frame teardown, there may not be a valid context. ScriptState* script_state = ScriptState::Current(isolate); @@ -354,7 +354,7 @@ v8::Local<v8::Value> data) { // FIXME: We should modify V8 to pass in more contextual information (context, // property, and object). - BindingSecurity::FailedAccessCheckFor(v8::Isolate::GetCurrent(), + BindingSecurity::FailedAccessCheckFor(holder->GetIsolate(), WrapperTypeInfo::Unwrap(data), holder); } @@ -819,9 +819,18 @@ ThreadScheduler* scheduler = ThreadScheduler::Current(); + V8PerIsolateData::V8ContextSnapshotMode snapshot_mode = + GetV8ContextSnapshotMode(); + v8::CreateHistogramCallback create_histogram_callback = nullptr; + v8::AddHistogramSampleCallback add_histogram_sample_callback = nullptr; + // We don't log histograms when taking a snapshot. + if (snapshot_mode != V8PerIsolateData::V8ContextSnapshotMode::kTakeSnapshot) { + create_histogram_callback = CreateHistogram; + add_histogram_sample_callback = AddHistogramSample; + } v8::Isolate* isolate = V8PerIsolateData::Initialize( - scheduler->V8TaskRunner(), GetV8ContextSnapshotMode(), CreateHistogram, - AddHistogramSample); + scheduler->V8TaskRunner(), snapshot_mode, create_histogram_callback, + add_histogram_sample_callback); scheduler->SetV8Isolate(isolate); // ThreadState::isolate_ needs to be set before setting the EmbedderHeapTracer
diff --git a/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h b/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h index 14d14b8..4013eb41 100644 --- a/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h +++ b/third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h
@@ -145,4 +145,38 @@ } // namespace blink +namespace WTF { + +template <typename V8Type> +struct VectorTraits<blink::WorldSafeV8Reference<V8Type>> + : VectorTraitsBase<blink::WorldSafeV8Reference<V8Type>> { + STATIC_ONLY(VectorTraits); + + static constexpr bool kCanInitializeWithMemset = + VectorTraits< + blink::TraceWrapperV8Reference<V8Type>>::kCanInitializeWithMemset && + VectorTraits<scoped_refptr<const blink::DOMWrapperWorld>>:: + kCanInitializeWithMemset; + static constexpr bool kCanClearUnusedSlotsWithMemset = + VectorTraits<blink::TraceWrapperV8Reference<V8Type>>:: + kCanClearUnusedSlotsWithMemset && + VectorTraits<scoped_refptr<const blink::DOMWrapperWorld>>:: + kCanClearUnusedSlotsWithMemset; + static constexpr bool kCanCopyWithMemcpy = + VectorTraits< + blink::TraceWrapperV8Reference<V8Type>>::kCanCopyWithMemcpy && + VectorTraits< + scoped_refptr<const blink::DOMWrapperWorld>>::kCanCopyWithMemcpy; + static constexpr bool kCanMoveWithMemcpy = + VectorTraits< + blink::TraceWrapperV8Reference<V8Type>>::kCanMoveWithMemcpy && + VectorTraits< + scoped_refptr<const blink::DOMWrapperWorld>>::kCanMoveWithMemcpy; + + static constexpr bool kCanTraceConcurrently = VectorTraits< + blink::TraceWrapperV8Reference<V8Type>>::kCanTraceConcurrently; +}; + +} // namespace WTF + #endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORLD_SAFE_V8_REFERENCE_H_
diff --git a/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc b/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc index 150c099..93fdff1 100644 --- a/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc +++ b/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc
@@ -418,7 +418,8 @@ v8::StartupData V8ContextSnapshotImpl::TakeSnapshot() { v8::Isolate* isolate = V8PerIsolateData::MainThreadIsolate(); - CHECK_EQ(isolate, v8::Isolate::GetCurrent()); + CHECK(isolate); + CHECK(isolate->IsCurrent()); V8PerIsolateData* per_isolate_data = V8PerIsolateData::From(isolate); CHECK_EQ(per_isolate_data->GetV8ContextSnapshotMode(), V8PerIsolateData::V8ContextSnapshotMode::kTakeSnapshot);
diff --git a/third_party/blink/renderer/controller/oom_intervention_impl.cc b/third_party/blink/renderer/controller/oom_intervention_impl.cc index 03634ad..5c4c83fe 100644 --- a/third_party/blink/renderer/controller/oom_intervention_impl.cc +++ b/third_party/blink/renderer/controller/oom_intervention_impl.cc
@@ -93,10 +93,7 @@ GetOomIntervention().Bind(std::move(receiver)); } -OomInterventionImpl::OomInterventionImpl() - : delayed_report_timer_(Thread::MainThread()->GetDeprecatedTaskRunner(), - this, - &OomInterventionImpl::TimerFiredUMAReport) { +OomInterventionImpl::OomInterventionImpl() { UpdateStateCrashKey(OomInterventionState::Before); } @@ -174,16 +171,9 @@ current_memory.current_vm_size_kb * 1024 > detection_args_->virtual_memory_thresold; - // Report memory stats every second to send UMA. - ReportMemoryStats(current_memory); - if (oom_detected) { UpdateStateCrashKey(OomInterventionState::During); - UMA_HISTOGRAM_MEMORY_MB( - "Memory.Experimental.OomIntervention.V8UsageBefore", - base::saturated_cast<int>(usage.v8_bytes / 1024 / 1024)); - if (navigate_ads_enabled_ || purge_v8_memory_enabled_) { for (const auto& page : Page::OrdinaryPages()) { for (Frame* frame = page->MainFrame(); frame; @@ -213,88 +203,6 @@ // Notify V8GCForContextDispose that page navigation gc is needed when // intervention runs, as it indicates that memory usage is high. V8GCForContextDispose::Instance().SetForcePageNavigationGC(); - - // Report the memory impact of intervention after 10, 20, 30 seconds. - metrics_at_intervention_ = current_memory; - number_of_report_needed_ = 3; - delayed_report_timer_.StartRepeating(base::Seconds(10), FROM_HERE); - } -} - -void OomInterventionImpl::ReportMemoryStats( - OomInterventionMetrics& current_memory) { - UMA_HISTOGRAM_MEMORY_MB( - "Memory.Experimental.OomIntervention.RendererBlinkUsage", - base::saturated_cast<base::Histogram::Sample>( - current_memory.current_blink_usage_kb / 1024)); - UMA_HISTOGRAM_MEMORY_LARGE_MB( - "Memory.Experimental.OomIntervention." - "RendererPrivateMemoryFootprint", - base::saturated_cast<base::Histogram::Sample>( - current_memory.current_private_footprint_kb / 1024)); - UMA_HISTOGRAM_MEMORY_MB( - "Memory.Experimental.OomIntervention.RendererSwapFootprint", - base::saturated_cast<base::Histogram::Sample>( - current_memory.current_swap_kb / 1024)); - UMA_HISTOGRAM_MEMORY_LARGE_MB( - "Memory.Experimental.OomIntervention.RendererVmSize", - base::saturated_cast<base::Histogram::Sample>( - current_memory.current_vm_size_kb / 1024)); -} - -int ToMemoryUsageDeltaSample(uint64_t after_kb, uint64_t before_kb) { - int delta_mb = (base::saturated_cast<int>(before_kb) - - base::saturated_cast<int>(after_kb)) / - 1024; - return std::min(std::max(delta_mb, -500), 500); -} - -void OomInterventionImpl::TimerFiredUMAReport(TimerBase*) { - MemoryUsage usage = MemoryUsageMonitorInstance().GetCurrentMemoryUsage(); - OomInterventionMetrics current_memory = - CrashMemoryMetricsReporterImpl::MemoryUsageToMetrics(usage); - int blink_usage_delta = - ToMemoryUsageDeltaSample(current_memory.current_blink_usage_kb, - metrics_at_intervention_.current_blink_usage_kb); - int private_footprint_delta = ToMemoryUsageDeltaSample( - current_memory.current_private_footprint_kb, - metrics_at_intervention_.current_private_footprint_kb); - int v8_usage_mb = base::saturated_cast<int>(usage.v8_bytes / 1024 / 1024); - switch (number_of_report_needed_--) { - case 3: - UMA_HISTOGRAM_MEMORY_MB( - "Memory.Experimental.OomIntervention.V8UsageAfter10secs", - v8_usage_mb); - base::UmaHistogramSparse( - "Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter10secs2", - blink_usage_delta); - base::UmaHistogramSparse( - "Memory.Experimental.OomIntervention.ReducedRendererPMFAfter10secs2", - private_footprint_delta); - break; - case 2: - UMA_HISTOGRAM_MEMORY_MB( - "Memory.Experimental.OomIntervention.V8UsageAfter20secs", - v8_usage_mb); - base::UmaHistogramSparse( - "Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter20secs2", - blink_usage_delta); - base::UmaHistogramSparse( - "Memory.Experimental.OomIntervention.ReducedRendererPMFAfter20secs2", - private_footprint_delta); - break; - case 1: - UMA_HISTOGRAM_MEMORY_MB( - "Memory.Experimental.OomIntervention.V8UsageAfter30secs", - v8_usage_mb); - base::UmaHistogramSparse( - "Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter30secs2", - blink_usage_delta); - base::UmaHistogramSparse( - "Memory.Experimental.OomIntervention.ReducedRendererPMFAfter30secs2", - private_footprint_delta); - delayed_report_timer_.Stop(); - break; } }
diff --git a/third_party/blink/renderer/controller/oom_intervention_impl.h b/third_party/blink/renderer/controller/oom_intervention_impl.h index 1f5bb91..3a61315 100644 --- a/third_party/blink/renderer/controller/oom_intervention_impl.h +++ b/third_party/blink/renderer/controller/oom_intervention_impl.h
@@ -76,9 +76,6 @@ bool navigate_ads_enabled_ = false; bool purge_v8_memory_enabled_ = false; std::unique_ptr<ScopedPagePauser> pauser_; - OomInterventionMetrics metrics_at_intervention_; - int number_of_report_needed_ = 0; - TaskRunnerTimer<OomInterventionImpl> delayed_report_timer_; mojo::Receiver<mojom::blink::OomIntervention> receiver_{this}; };
diff --git a/third_party/blink/renderer/controller/oom_intervention_impl_test.cc b/third_party/blink/renderer/controller/oom_intervention_impl_test.cc index 8142d92..7505f53 100644 --- a/third_party/blink/renderer/controller/oom_intervention_impl_test.cc +++ b/third_party/blink/renderer/controller/oom_intervention_impl_test.cc
@@ -348,60 +348,4 @@ EXPECT_TRUE(frame->DomWindow()->IsContextDestroyed()); } -TEST_F(OomInterventionImplTest, ReducedMemoryMetricReporting) { - HistogramTester histogram_tester; - - uint64_t initial_blink_usage_bytes = kTestBlinkThreshold + 1024 * 1024 * 1024; - uint64_t initial_private_footprint_bytes = 0; - - MemoryUsage usage; - // Set value more than the threshold to trigger intervention. - usage.v8_bytes = initial_blink_usage_bytes; - usage.blink_gc_bytes = 0; - usage.partition_alloc_bytes = 0; - usage.private_footprint_bytes = initial_private_footprint_bytes; - usage.swap_bytes = 0; - usage.vm_size_bytes = 0; - intervention_->mock_memory_usage_monitor()->SetMockMemoryUsage(usage); - - Page* page = DetectOnceOnBlankPage(); - - EXPECT_TRUE(page->Paused()); - - usage.v8_bytes = initial_blink_usage_bytes - 2 * 1024 * 1024; - usage.private_footprint_bytes = - initial_private_footprint_bytes + 2 * 1024 * 1024; - intervention_->mock_memory_usage_monitor()->SetMockMemoryUsage(usage); - test::RunDelayedTasks(base::Seconds(10)); - histogram_tester.ExpectUniqueSample( - "Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter10secs2", 2, - 1); - histogram_tester.ExpectUniqueSample( - "Memory.Experimental.OomIntervention.ReducedRendererPMFAfter10secs2", -2, - 1); - - usage.v8_bytes = initial_blink_usage_bytes - 1; - usage.private_footprint_bytes = initial_private_footprint_bytes + 1; - intervention_->mock_memory_usage_monitor()->SetMockMemoryUsage(usage); - test::RunDelayedTasks(base::Seconds(10)); - histogram_tester.ExpectUniqueSample( - "Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter20secs2", 0, - 1); - histogram_tester.ExpectUniqueSample( - "Memory.Experimental.OomIntervention.ReducedRendererPMFAfter20secs2", 0, - 1); - - usage.v8_bytes = initial_blink_usage_bytes - 800 * 1024 * 1024; - usage.private_footprint_bytes = - initial_private_footprint_bytes + 800 * 1024 * 1024; - intervention_->mock_memory_usage_monitor()->SetMockMemoryUsage(usage); - test::RunDelayedTasks(base::Seconds(10)); - histogram_tester.ExpectUniqueSample( - "Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter30secs2", 500, - 1); - histogram_tester.ExpectUniqueSample( - "Memory.Experimental.OomIntervention.ReducedRendererPMFAfter30secs2", - -500, 1); -} - } // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_variable_data.cc b/third_party/blink/renderer/core/css/css_variable_data.cc index a28a3980..b22f1ed 100644 --- a/third_party/blink/renderer/core/css/css_variable_data.cc +++ b/third_party/blink/renderer/core/css/css_variable_data.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/core/css/css_variable_data.h" +#include "base/containers/span.h" #include "third_party/blink/renderer/core/css/css_syntax_definition.h" #include "third_party/blink/renderer/core/css/parser/css_parser_context.h" #include "third_party/blink/renderer/platform/wtf/text/character_names.h" @@ -110,6 +111,51 @@ UpdateTokens<UChar>(range, backing_string, tokens_); } +#if EXPENSIVE_DCHECKS_ARE_ON() + +namespace { + +template <typename CharacterType> +bool IsSubspan(base::span<const CharacterType> inner, + base::span<const CharacterType> outer) { + // Note that base::span uses CheckedContiguousIterator, which restricts + // which comparisons are allowed. Therefore we must avoid begin()/end() here. + return inner.data() >= outer.data() && + (inner.data() + inner.size()) <= (outer.data() + outer.size()); +} + +bool TokenValueIsBacked(const CSSParserToken& token, + const String& backing_string) { + StringView value = token.Value(); + if (value.Is8Bit() != backing_string.Is8Bit()) + return false; + return value.Is8Bit() ? IsSubspan(value.Span8(), backing_string.Span8()) + : IsSubspan(value.Span16(), backing_string.Span16()); +} + +bool TokenValueIsBacked(const CSSParserToken& token, + const Vector<String>& backing_strings) { + DCHECK(token.HasStringBacking()); + for (const String& backing_string : backing_strings) { + if (TokenValueIsBacked(token, backing_string)) { + return true; + } + } + return false; +} + +} // namespace + +void CSSVariableData::VerifyStringBacking() const { + for (const CSSParserToken& token : tokens_) { + DCHECK(!token.HasStringBacking() || + TokenValueIsBacked(token, backing_strings_)) + << "Token value is not backed: " << token.Value().ToString(); + } +} + +#endif // EXPENSIVE_DCHECKS_ARE_ON() + CSSVariableData::CSSVariableData(const CSSTokenizedValue& tokenized_value, bool is_animation_tainted, bool needs_variable_resolution, @@ -121,6 +167,9 @@ base_url_(base_url.IsValid() ? base_url.GetString() : String()), charset_(charset) { ConsumeAndUpdateTokens(tokenized_value.range); +#if EXPENSIVE_DCHECKS_ARE_ON() + VerifyStringBacking(); +#endif // EXPENSIVE_DCHECKS_ARE_ON() } const CSSValue* CSSVariableData::ParseForSyntax(
diff --git a/third_party/blink/renderer/core/css/css_variable_data.h b/third_party/blink/renderer/core/css/css_variable_data.h index f042f85..7be7d20 100644 --- a/third_party/blink/renderer/core/css/css_variable_data.h +++ b/third_party/blink/renderer/core/css/css_variable_data.h
@@ -100,11 +100,18 @@ has_font_units_(has_font_units), has_root_font_units_(has_root_font_units), base_url_(base_url), - charset_(charset) {} + charset_(charset) { +#if EXPENSIVE_DCHECKS_ARE_ON() + VerifyStringBacking(); +#endif // EXPENSIVE_DCHECKS_ARE_ON() + } CSSVariableData(const CSSVariableData&) = delete; CSSVariableData& operator=(const CSSVariableData&) = delete; void ConsumeAndUpdateTokens(const CSSParserTokenRange&); +#if EXPENSIVE_DCHECKS_ARE_ON() + void VerifyStringBacking() const; +#endif // EXPENSIVE_DCHECKS_ARE_ON() // tokens_ may have raw pointers to string data, we store the String objects // owning that data in backing_strings_ to keep it alive alongside the
diff --git a/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc b/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc index cbc8bfb..b51edb3 100644 --- a/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc +++ b/third_party/blink/renderer/core/css/parser/css_at_rule_id.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/core/css/parser/css_at_rule_id.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/renderer/core/css/parser/css_parser_context.h" #include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" @@ -72,74 +73,61 @@ return kCSSAtRuleInvalid; } -void CountAtRule(const CSSParserContext* context, CSSAtRuleID rule_id) { - WebFeature feature; +namespace { +absl::optional<WebFeature> AtRuleFeature(CSSAtRuleID rule_id) { switch (rule_id) { case kCSSAtRuleCharset: - feature = WebFeature::kCSSAtRuleCharset; - break; + return WebFeature::kCSSAtRuleCharset; case kCSSAtRuleFontFace: - feature = WebFeature::kCSSAtRuleFontFace; - break; + return WebFeature::kCSSAtRuleFontFace; case kCSSAtRuleFontPaletteValues: - feature = WebFeature::kCSSAtRuleFontPaletteValues; - break; + return WebFeature::kCSSAtRuleFontPaletteValues; case kCSSAtRuleImport: - feature = WebFeature::kCSSAtRuleImport; - break; + return WebFeature::kCSSAtRuleImport; case kCSSAtRuleKeyframes: - feature = WebFeature::kCSSAtRuleKeyframes; - break; + return WebFeature::kCSSAtRuleKeyframes; case kCSSAtRuleLayer: - feature = WebFeature::kCSSCascadeLayers; - break; + return WebFeature::kCSSCascadeLayers; case kCSSAtRuleMedia: - feature = WebFeature::kCSSAtRuleMedia; - break; + return WebFeature::kCSSAtRuleMedia; case kCSSAtRuleNamespace: - feature = WebFeature::kCSSAtRuleNamespace; - break; + return WebFeature::kCSSAtRuleNamespace; case kCSSAtRulePage: - feature = WebFeature::kCSSAtRulePage; - break; + return WebFeature::kCSSAtRulePage; case kCSSAtRuleProperty: - feature = WebFeature::kCSSAtRuleProperty; - break; + return WebFeature::kCSSAtRuleProperty; case kCSSAtRuleContainer: - feature = WebFeature::kCSSAtRuleContainer; - return; + return WebFeature::kCSSAtRuleContainer; case kCSSAtRuleCounterStyle: - feature = WebFeature::kCSSAtRuleCounterStyle; - break; + return WebFeature::kCSSAtRuleCounterStyle; case kCSSAtRuleScope: - feature = WebFeature::kCSSAtRuleScope; - break; + return WebFeature::kCSSAtRuleScope; case kCSSAtRuleScrollTimeline: - feature = WebFeature::kCSSAtRuleScrollTimeline; - break; + return WebFeature::kCSSAtRuleScrollTimeline; case kCSSAtRuleSupports: - feature = WebFeature::kCSSAtRuleSupports; - break; + return WebFeature::kCSSAtRuleSupports; case kCSSAtRuleViewport: - feature = WebFeature::kCSSAtRuleViewport; - break; + return WebFeature::kCSSAtRuleViewport; case kCSSAtRulePositionFallback: case kCSSAtRuleTry: // TODO(crbug.com/1309178): Add use counter. - return; - + return absl::nullopt; case kCSSAtRuleWebkitKeyframes: - feature = WebFeature::kCSSAtRuleWebkitKeyframes; - break; - + return WebFeature::kCSSAtRuleWebkitKeyframes; case kCSSAtRuleInvalid: - // fallthrough + [[fallthrough]]; default: NOTREACHED(); - return; + return absl::nullopt; } - context->Count(feature); +} + +} // namespace + +void CountAtRule(const CSSParserContext* context, CSSAtRuleID rule_id) { + if (absl::optional<WebFeature> feature = AtRuleFeature(rule_id)) + context->Count(*feature); } } // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/css_tokenizer.h b/third_party/blink/renderer/core/css/parser/css_tokenizer.h index b78c354..9d889c45 100644 --- a/third_party/blink/renderer/core/css/parser/css_tokenizer.h +++ b/third_party/blink/renderer/core/css/parser/css_tokenizer.h
@@ -103,6 +103,7 @@ wtf_size_t Offset() const { return input_.Offset(); } wtf_size_t PreviousOffset() const { return prev_offset_; } StringView StringRangeAt(wtf_size_t start, wtf_size_t length) const; + const Vector<String>& StringPool() const { return string_pool_; } CSSParserToken TokenizeSingle(); CSSParserToken TokenizeSingleWithComments();
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc index a080fd4..58f53c8 100644 --- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc +++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -2169,6 +2169,10 @@ Vector<String> backing_strings; backing_strings.push_back(text); + // CSSTokenizer may allocate new strings for some tokens (e.g. for escapes) + // and produce tokens that point to those strings. We need to retain those + // strings (if any) as well. + backing_strings.AppendVector(tokenizer.StringPool()); const bool has_font_units = false; const bool has_root_font_units = false;
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc index c9e2dc4..c80cdc1 100644 --- a/third_party/blink/renderer/core/css/style_engine_test.cc +++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -4447,6 +4447,26 @@ EXPECT_TRUE(IsUseCounted(WebFeature::kCSSAtRuleCounterStyle)); } +TEST_F(StyleEngineTest, AtContainerUseCount) { + GetDocument().body()->setInnerHTML(R"HTML( + <style> + body { --x: No @container rule here; } + </style> + )HTML"); + UpdateAllLifecyclePhases(); + EXPECT_FALSE(GetDocument().IsUseCounted(WebFeature::kCSSAtRuleContainer)); + + GetDocument().body()->setInnerHTML(R"HTML( + <style> + @container (width > 0px) { + body { --x: Hello world; } + } + </style> + )HTML"); + UpdateAllLifecyclePhases(); + EXPECT_TRUE(GetDocument().IsUseCounted(WebFeature::kCSSAtRuleContainer)); +} + TEST_F(StyleEngineTest, SystemFontsObeyDefaultFontSize) { // <input> get assigned "font: -webkit-small-control" in the UA sheet. Element* body = GetDocument().body();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc index b1dec95d..9e6a3090 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
@@ -207,6 +207,9 @@ is_dirty_(source.is_dirty_), is_last_for_node_(source.is_last_for_node_) { switch (Type()) { + case kInvalid: + CHECK(false) << "Cannot construct invalid value"; + break; case kText: new (&text_) TextItem(source.text_); break; @@ -250,6 +253,9 @@ is_dirty_(source.is_dirty_), is_last_for_node_(source.is_last_for_node_) { switch (Type()) { + case kInvalid: + CHECK(false) << "Cannot construct invalid value"; + break; case kText: new (&text_) TextItem(std::move(source.text_)); break; @@ -271,6 +277,9 @@ NGFragmentItem::~NGFragmentItem() { switch (Type()) { + case kInvalid: + // Slot can be zeroed, do nothing. + return; case kText: text_.~TextItem(); break; @@ -317,6 +326,9 @@ if (auto* line_box = LineBoxFragment()) return line_box->IsBlockInInline(); return false; + case kInvalid: + NOTREACHED(); + return false; default: return false; } @@ -1169,6 +1181,9 @@ << (IsLtr(item.ResolvedDirection()) ? "LTR" : "RTL"); } break; + case NGFragmentItem::kInvalid: + NOTREACHED(); + break; } ostream << " "; switch (item.StyleVariant()) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h index f97d202e..0370e4a 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
@@ -98,7 +98,9 @@ wtf_size_t descendants_count; }; - enum ItemType { kText, kSvgText, kGeneratedText, kLine, kBox }; + // Type of the item. The invalid type is needed to support + // kCanClearUnusedSlotsWithMemset. + enum ItemType { kInvalid = 0, kText, kSvgText, kGeneratedText, kLine, kBox }; enum TracedType { kNone, kLineItem, kBoxItem }; // Create appropriate type for |line_item|. @@ -636,4 +638,6 @@ } // namespace blink +WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(blink::NGFragmentItem) + #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_FRAGMENT_ITEM_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc index 93bd661..26eb2c4 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc
@@ -42,26 +42,19 @@ NGFragmentItems::NGFragmentItems(NGFragmentItemsBuilder* builder) : text_content_(std::move(builder->text_content_)), - first_line_text_content_(std::move(builder->first_line_text_content_)), - size_(builder->items_.size()), - size_of_earlier_fragments_(0) { - NGFragmentItemsBuilder::ItemWithOffsetList& source_items = builder->items_; - for (wtf_size_t i = 0; i < size_; ++i) { - // Call the move constructor to move without |AddRef|. Items in - // |NGFragmentItemsBuilder| are not used after |this| was constructed. - new (&items_[i]) NGFragmentItem(std::move(source_items[i].item)); - } + first_line_text_content_(std::move(builder->first_line_text_content_)) { + items_.ReserveInitialCapacity(builder->items_.size()); + std::transform(builder->items_.begin(), builder->items_.end(), + std::back_inserter(items_), + [](auto& item) { return std::move(item.item); }); } NGFragmentItems::NGFragmentItems(const NGFragmentItems& other) : text_content_(other.text_content_), first_line_text_content_(other.first_line_text_content_), - size_(other.size_), - size_of_earlier_fragments_(other.size_of_earlier_fragments_) { - for (wtf_size_t i = 0; i < size_; ++i) { - const auto& other_item = other.items_[i]; - new (&items_[i]) NGFragmentItem(other_item); - + size_of_earlier_fragments_(other.size_of_earlier_fragments_), + items_(other.items_) { + for (const auto& other_item : other.items_) { // The |other| object is likely going to be freed after this copy. Detach // any |AbstractInlineTextBox|, as they store a pointer to an individual // |NGFragmentItem|. @@ -71,11 +64,6 @@ } } -NGFragmentItems::~NGFragmentItems() { - for (wtf_size_t i = 0; i < size_; ++i) - items_[i].~NGFragmentItem(); -} - bool NGFragmentItems::IsSubSpan(const Span& span) const { return span.empty() || (span.data() >= ItemsData() && &span.back() < ItemsData() + Size()); @@ -507,8 +495,7 @@ #endif void NGFragmentItems::Trace(Visitor* visitor) const { - for (const NGFragmentItem& item : Items()) - visitor->Trace(item); + visitor->Trace(items_); } } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h index c265953..aaad893 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h
@@ -23,21 +23,22 @@ DISALLOW_NEW(); public: + NGFragmentItems() = default; + NGFragmentItems(const NGFragmentItems& other); explicit NGFragmentItems(NGFragmentItemsBuilder* builder); - ~NGFragmentItems(); - wtf_size_t Size() const { return size_; } + wtf_size_t Size() const { return items_.size(); } using Span = base::span<const NGFragmentItem>; - Span Items() const { return base::make_span(ItemsData(), size_); } + Span Items() const { return base::make_span(ItemsData(), items_.size()); } bool Equals(const Span& span) const { return ItemsData() == span.data() && Size() == span.size(); } bool IsSubSpan(const Span& span) const; const NGFragmentItem& front() const { - CHECK_GE(size_, 1u); + CHECK_GE(items_.size(), 1u); return items_[0]; } @@ -59,7 +60,9 @@ wtf_size_t SizeOfEarlierFragments() const { return size_of_earlier_fragments_; } - wtf_size_t EndItemIndex() const { return size_of_earlier_fragments_ + size_; } + wtf_size_t EndItemIndex() const { + return size_of_earlier_fragments_ + items_.size(); + } bool HasItemIndex(wtf_size_t index) const { return index >= SizeOfEarlierFragments() && index < EndItemIndex(); } @@ -104,12 +107,6 @@ const NGPhysicalBoxFragment& new_fragment, const NGPhysicalBoxFragment& containing_fragment); - // The byte size of this instance. - constexpr static wtf_size_t ByteSizeFor(wtf_size_t count) { - return sizeof(NGFragmentItems) + count * sizeof(NGFragmentItem); - } - wtf_size_t ByteSize() const { return ByteSizeFor(Size()); } - #if DCHECK_IS_ON() void CheckAllItemsAreValid() const; #endif @@ -117,7 +114,7 @@ void Trace(Visitor*) const; private: - const NGFragmentItem* ItemsData() const { return items_; } + const NGFragmentItem* ItemsData() const { return items_.data(); } static bool CanReuseAll(NGInlineCursor* cursor); static bool TryDirtyFirstLineFor(const LayoutObject& layout_object, @@ -129,15 +126,11 @@ String text_content_; String first_line_text_content_; - // Note: To make |Trace()| handles flexible array |items_| correctly, |size_| - // must be an immutable. - const wtf_size_t size_; - // Total size of |NGFragmentItem| in earlier fragments when block fragmented. // 0 for the first |NGFragmentItems|. - mutable wtf_size_t size_of_earlier_fragments_; + mutable wtf_size_t size_of_earlier_fragments_ = 0u; - NGFragmentItem items_[0]; + HeapVector<NGFragmentItem> items_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc index 458cdab..f88d94f 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
@@ -107,6 +107,7 @@ // All/LayoutViewHitTestTest.PseudoElementAfter* needs this. return item.IsGeneratedText(); case NGFragmentItem::kLine: + case NGFragmentItem::kInvalid: NOTREACHED(); break; } @@ -846,6 +847,7 @@ DCHECK(child_item.GetLayoutObject()->IsLayoutInline()) << child_item; break; case NGFragmentItem::kLine: + case NGFragmentItem::kInvalid: NOTREACHED(); break; }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc index 0f1b8ab..ee084f3 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -2741,12 +2741,6 @@ void NGBlockLayoutAlgorithm::PropagateBaselineFromChild( const NGPhysicalFragment& child, LayoutUnit block_offset) { - // Check if we've already found an appropriate baseline. - if (container_builder_.FirstBaseline() && - ConstraintSpace().BaselineAlgorithmType() == - NGBaselineAlgorithmType::kDefault) - return; - if (child.IsLineBox()) { const auto& line_box = To<NGPhysicalLineBoxFragment>(child); @@ -2774,12 +2768,7 @@ if (!container_builder_.FirstBaseline()) container_builder_.SetFirstBaseline(baseline); - - // Set the last baseline only if required. - if (ConstraintSpace().BaselineAlgorithmType() == - NGBaselineAlgorithmType::kInlineBlock) - container_builder_.SetLastBaseline(baseline); - + container_builder_.SetLastBaseline(baseline); return; } @@ -2791,8 +2780,8 @@ LayoutUnit block_offset) { DCHECK(child.IsBox()); - // When computing the baseline for an inline-block, table's don't contribute - // to any baselines. + // When computing baselines for an inline-block, table's don't contribute any + // baselines. if (child.IsTableNG() && ConstraintSpace().BaselineAlgorithmType() == NGBaselineAlgorithmType::kInlineBlock) { return; @@ -2803,19 +2792,20 @@ physical_fragment); if (!container_builder_.FirstBaseline()) { - if (auto baseline = fragment.FirstBaseline()) - container_builder_.SetFirstBaseline(block_offset + *baseline); + if (auto first_baseline = fragment.FirstBaseline()) + container_builder_.SetFirstBaseline(block_offset + *first_baseline); } - // Set the last baseline only if required. - if (ConstraintSpace().BaselineAlgorithmType() == - NGBaselineAlgorithmType::kInlineBlock) { - const auto baseline = physical_fragment.UseLastBaselineForInlineBaseline() - ? fragment.LastBaseline() - : fragment.FirstBaseline(); - if (baseline) - container_builder_.SetLastBaseline(block_offset + *baseline); - } + // Counter-intuitively, when computing baselines for an inline-block, some + // fragments use their first-baseline for the container's last-baseline. + bool use_last_baseline = ConstraintSpace().BaselineAlgorithmType() == + NGBaselineAlgorithmType::kDefault || + physical_fragment.UseLastBaselineForInlineBaseline(); + + const auto last_baseline = + use_last_baseline ? fragment.LastBaseline() : fragment.FirstBaseline(); + if (last_baseline) + container_builder_.SetLastBaseline(block_offset + *last_baseline); } bool NGBlockLayoutAlgorithm::ResolveBfcBlockOffset(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc index 9eca59d9..d803779f 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -43,11 +43,10 @@ struct SameSizeAsNGPhysicalBoxFragment : NGPhysicalFragment { unsigned flags; - wtf_size_t const_num_children; LayoutUnit baseline; LayoutUnit last_baseline; NGInkOverflow ink_overflow; - NGLink children[]; + HeapVector<NGLink> children_; }; ASSERT_SIZE(NGPhysicalBoxFragment, SameSizeAsNGPhysicalBoxFragment); @@ -202,11 +201,9 @@ builder->table_cell_column_index_ || !builder->table_section_row_offsets_.IsEmpty() || builder->page_name_; - wtf_size_t num_fragment_items = - builder->ItemsBuilder() ? builder->ItemsBuilder()->Size() : 0; - size_t byte_size = AdditionalByteSize( - num_fragment_items, builder->children_.size(), has_layout_overflow, - has_borders, has_padding, inflow_bounds.has_value(), has_rare_data); + size_t byte_size = + AdditionalByteSize(has_fragment_items, has_layout_overflow, has_borders, + has_padding, inflow_bounds.has_value(), has_rare_data); // We store the children list inline in the fragment as a flexible // array. Therefore, we need to make sure to allocate enough space for @@ -223,12 +220,9 @@ // static const NGPhysicalBoxFragment* NGPhysicalBoxFragment::Clone( const NGPhysicalBoxFragment& other) { - // The size of the new fragment shouldn't differ from the old one. - wtf_size_t num_fragment_items = other.Items() ? other.Items()->Size() : 0; size_t byte_size = AdditionalByteSize( - num_fragment_items, other.const_num_children_, other.has_layout_overflow_, - other.has_borders_, other.has_padding_, other.has_inflow_bounds_, - other.const_has_rare_data_); + other.HasItems(), other.has_layout_overflow_, other.has_borders_, + other.has_padding_, other.has_inflow_bounds_, other.const_has_rare_data_); return MakeGarbageCollected<NGPhysicalBoxFragment>( AdditionalBytes(byte_size), PassKey(), other, other.HasLayoutOverflow(), @@ -248,12 +242,9 @@ has_layout_overflow = layout_overflow != PhysicalRect({}, other.Size()); } - // The size of the new fragment shouldn't differ from the old one. - wtf_size_t num_fragment_items = other.Items() ? other.Items()->Size() : 0; size_t byte_size = AdditionalByteSize( - num_fragment_items, other.const_num_children_, has_layout_overflow, - other.has_borders_, other.has_padding_, other.has_inflow_bounds_, - other.const_has_rare_data_); + other.HasItems(), has_layout_overflow, other.has_borders_, + other.has_padding_, other.has_inflow_bounds_, other.const_has_rare_data_); const auto* cloned_fragment = MakeGarbageCollected<NGPhysicalBoxFragment>( AdditionalBytes(byte_size), PassKey(), other, has_layout_overflow, @@ -309,21 +300,15 @@ } // namespace // static -size_t NGPhysicalBoxFragment::AdditionalByteSize(wtf_size_t num_fragment_items, - wtf_size_t num_children, +size_t NGPhysicalBoxFragment::AdditionalByteSize(bool has_fragment_items, bool has_layout_overflow, bool has_borders, bool has_padding, bool has_inflow_bounds, bool has_rare_data) { - // Padding must be 0 for flexible array members. - static_assert(0 == (sizeof(NGPhysicalBoxFragment) % alignof(NGLink))); - - size_t additional_size = sizeof(NGLink) * num_children; - additional_size = - base::bits::AlignUp(additional_size, alignof(NGFragmentItems)) + - NGFragmentItems::ByteSizeFor(num_fragment_items); - + size_t additional_size = 0; + if (has_fragment_items) + AccountSizeAndPadding<NGFragmentItems>(additional_size); if (has_layout_overflow) AccountSizeAndPadding<PhysicalRect>(additional_size); if (has_borders) @@ -358,15 +343,15 @@ const_has_fragment_items_(has_fragment_items), const_has_rare_data_(has_rare_data), has_descendants_for_table_part_(false), - is_fragmentation_context_root_(builder->is_fragmentation_context_root_), - const_num_children_(builder->children_.size()) { + is_fragmentation_context_root_(builder->is_fragmentation_context_root_) { DCHECK(layout_object_); DCHECK(layout_object_->IsBoxModelObject()); DCHECK(!builder->break_token_ || builder->break_token_->IsBlockType()); - PhysicalSize size = Size(); + children_.resize(builder->children_.size()); + const WritingModeConverter converter( - {block_or_line_writing_mode, builder->Direction()}, size); + {block_or_line_writing_mode, builder->Direction()}, Size()); wtf_size_t i = 0; for (auto& child : builder->children_) { children_[i].offset = @@ -439,7 +424,7 @@ builder->use_last_baseline_for_inline_baseline_; has_descendants_for_table_part_ = - const_num_children_ || NeedsOOFPositionedInfoPropagation(); + children_.size() || NeedsOOFPositionedInfoPropagation(); #if DCHECK_IS_ON() CheckIntegrity(); @@ -467,15 +452,10 @@ is_first_for_node_(other.is_first_for_node_), has_descendants_for_table_part_(other.has_descendants_for_table_part_), is_fragmentation_context_root_(other.is_fragmentation_context_root_), - const_num_children_(other.const_num_children_), first_baseline_(other.first_baseline_), last_baseline_(other.last_baseline_), - ink_overflow_(other.InkOverflowType(), other.ink_overflow_) { - // Shallow-clone the children. - for (wtf_size_t i = 0; i < const_num_children_; ++i) - children_[i] = other.children_[i]; - - ink_overflow_type_ = other.ink_overflow_type_; + ink_overflow_(other.InkOverflowType(), other.ink_overflow_), + children_(other.children_) { if (const_has_fragment_items_) { NGFragmentItems* items = const_cast<NGFragmentItems*>(ComputeItemsAddress()); @@ -1886,13 +1866,7 @@ #endif void NGPhysicalBoxFragment::TraceAfterDispatch(Visitor* visitor) const { - // Accessing |const_num_children_| inside Trace() here is safe since it is - // const. Note we don't check children_valid_ since that is not threadsafe. - // Tracing the child links themselves is safe from a background thread. - for (const auto& child : base::make_span(children_, const_num_children_)) - visitor->Trace(child); - // These if branches are safe since |const_has_fragment_items_| and - // |const_has_rare_data_| are const and set in ctor. + visitor->Trace(children_); if (const_has_fragment_items_) visitor->Trace(*ComputeItemsAddress()); if (const_has_rare_data_)
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h index d9df3ff0..c859edf 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -94,14 +94,14 @@ // from deleted nodes or LayoutObjects. Also see |PostLayoutChildren()|. base::span<const NGLink> Children() const { DCHECK(children_valid_); - return base::make_span(children_, const_num_children_); + return base::make_span(children_); } // Similar to |Children()| but all children are the latest generation of // post-layout, and therefore all descendants are safe. NGPhysicalFragment::PostLayoutChildLinkList PostLayoutChildren() const { DCHECK(children_valid_); - return PostLayoutChildLinkList(const_num_children_, children_); + return PostLayoutChildLinkList(children_.size(), children_.data()); } // This exposes a mutable part of the fragment for |NGOutOfFlowLayoutPart|. @@ -125,7 +125,7 @@ MutableChildrenForOutOfFlow GetMutableChildrenForOutOfFlow() const { DCHECK(children_valid_); - return MutableChildrenForOutOfFlow(children_, const_num_children_); + return MutableChildrenForOutOfFlow(children_.data(), children_.size()); } // Returns |NGFragmentItems| if this fragment has one. @@ -449,8 +449,7 @@ } base::span<NGLink> Children() const { DCHECK(fragment_.children_valid_); - return base::make_span(fragment_.children_, - fragment_.const_num_children_); + return base::make_span(fragment_.children_); } private: @@ -482,8 +481,7 @@ void Dispose(); private: - static size_t AdditionalByteSize(wtf_size_t num_fragment_items, - wtf_size_t num_children, + static size_t AdditionalByteSize(bool has_fragment_items, bool has_layout_overflow, bool has_borders, bool has_padding, @@ -522,22 +520,19 @@ const NGFragmentItems* ComputeItemsAddress() const { DCHECK(const_has_fragment_items_ || has_layout_overflow_ || has_borders_ || has_padding_ || has_inflow_bounds_ || const_has_rare_data_); - const NGLink* children_end = children_ + const_num_children_; - return reinterpret_cast<const NGFragmentItems*>( - base::bits::AlignUp(reinterpret_cast<const uint8_t*>(children_end), - alignof(NGFragmentItems))); + return reinterpret_cast<const NGFragmentItems*>(base::bits::AlignUp( + reinterpret_cast<const uint8_t*>(this + 1), alignof(NGFragmentItems))); } const PhysicalRect* ComputeLayoutOverflowAddress() const { DCHECK(has_layout_overflow_ || has_borders_ || has_padding_ || has_inflow_bounds_ || const_has_rare_data_); const NGFragmentItems* items = ComputeItemsAddress(); - const uint8_t* uint8_t_items = reinterpret_cast<const uint8_t*>(items); - if (const_has_fragment_items_) - uint8_t_items += items->ByteSize(); - + const uint8_t* unaligned_layout_overflow = + const_has_fragment_items_ ? reinterpret_cast<const uint8_t*>(items + 1) + : reinterpret_cast<const uint8_t*>(items); return reinterpret_cast<const PhysicalRect*>( - base::bits::AlignUp(uint8_t_items, alignof(PhysicalRect))); + base::bits::AlignUp(unaligned_layout_overflow, alignof(PhysicalRect))); } const NGPhysicalBoxStrut* ComputeBordersAddress() const { @@ -632,12 +627,10 @@ unsigned has_descendants_for_table_part_ : 1; unsigned is_fragmentation_context_root_ : 1; - const wtf_size_t const_num_children_; - LayoutUnit first_baseline_; LayoutUnit last_baseline_; NGInkOverflow ink_overflow_; - NGLink children_[]; + HeapVector<NGLink> children_; // fragment_items, borders, padding, and rare_data are after |children_| if // they are not empty/initial. };
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc index ecef6661..6e126121 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -867,6 +867,9 @@ } break; } + case NGFragmentItem::kInvalid: + NOTREACHED(); + break; } cursor->MoveToNext(); }
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc index bb25c2b..98b6400 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -1438,6 +1438,9 @@ NOTREACHED(); cursor->MoveToNext(); break; + case NGFragmentItem::kInvalid: + NOTREACHED(); + break; } } }
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 c96c113..bbc1c85 100644 --- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc +++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -752,7 +752,7 @@ return false; } } - v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Isolate* isolate = GetExecutionContext()->GetIsolate(); if (isolate && v8::MicrotasksScope::IsRunningMicrotasks(isolate)) { UseCounter::Count(GetExecutionContext(), WebFeature::kDuring_Microtask_SyncXHR);
diff --git a/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.cc b/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.cc index 2fcfccda..e73dfb3 100644 --- a/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.cc +++ b/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.cc
@@ -31,28 +31,6 @@ namespace blink { -TCPWritableStreamWrapper::CachedDataBuffer::CachedDataBuffer( - v8::Isolate* isolate, - const uint8_t* data, - size_t length) - : isolate_(isolate), length_(length) { - // We use the BufferPartition() allocator here to allow big enough - // allocations, and to do proper accounting of the used memory. If - // BufferPartition() will ever not be able to provide big enough allocations, - // e.g. because bigger ArrayBuffers get supported, then we have to switch to - // another allocator, e.g. the ArrayBuffer allocator. - buffer_ = std::unique_ptr<uint8_t[], OnFree>( - reinterpret_cast<uint8_t*>(WTF::Partitions::BufferPartition()->Alloc( - length, "TCPWritableStreamWrapper"))); - memcpy(buffer_.get(), data, length); - isolate_->AdjustAmountOfExternalAllocatedMemory(static_cast<int64_t>(length)); -} - -TCPWritableStreamWrapper::CachedDataBuffer::~CachedDataBuffer() { - isolate_->AdjustAmountOfExternalAllocatedMemory( - -static_cast<int64_t>(length_)); -} - TCPWritableStreamWrapper::TCPWritableStreamWrapper( ScriptState* script_state, CloseOnceCallback on_close, @@ -85,6 +63,7 @@ } void TCPWritableStreamWrapper::Trace(Visitor* visitor) const { + visitor->Trace(buffer_source_); visitor->Trace(write_promise_resolver_); WritableStreamWrapper::Trace(visitor); } @@ -93,7 +72,7 @@ const mojo::HandleSignalsState&) { switch (result) { case MOJO_RESULT_OK: - WriteCachedData(); + WriteDataAsynchronously(); break; case MOJO_RESULT_FAILED_PRECONDITION: @@ -123,6 +102,7 @@ ExceptionState& exception_state) { // There can only be one call to write() in progress at a time. DCHECK(!write_promise_resolver_); + DCHECK(!buffer_source_); DCHECK_EQ(0u, offset_); if (!data_pipe_) { @@ -132,65 +112,43 @@ return ScriptPromise(); } - auto* buffer_source = V8BufferSource::Create( - GetScriptState()->GetIsolate(), chunk.V8Value(), exception_state); - if (exception_state.HadException()) + buffer_source_ = V8BufferSource::Create(GetScriptState()->GetIsolate(), + chunk.V8Value(), exception_state); + if (exception_state.HadException()) { return ScriptPromise(); - DCHECK(buffer_source); + } + DCHECK(buffer_source_); - DOMArrayPiece array_piece(buffer_source); - return WriteOrCacheData({array_piece.Bytes(), array_piece.ByteLength()}, - exception_state); -} - -// Attempt to write |data|. Cache anything that could not be written -// synchronously. Arrange for the cached data to be written asynchronously. -ScriptPromise TCPWritableStreamWrapper::WriteOrCacheData( - base::span<const uint8_t> data, - ExceptionState& exception_state) { - DCHECK(data_pipe_); - size_t written = WriteDataSynchronously(data); - - if (written == data.size()) - return ScriptPromise::CastUndefined(GetScriptState()); - - DCHECK_LT(written, data.size()); - - DCHECK(!cached_data_); - cached_data_ = std::make_unique<CachedDataBuffer>( - GetScriptState()->GetIsolate(), data.data() + written, - data.size() - written); - DCHECK_EQ(offset_, 0u); - write_watcher_.ArmOrNotify(); write_promise_resolver_ = MakeGarbageCollected<ScriptPromiseResolver>( GetScriptState(), exception_state.GetContext()); - return write_promise_resolver_->Promise(); + auto promise = write_promise_resolver_->Promise(); + + WriteDataAsynchronously(); + + return promise; } -// Write data previously cached. Arrange for any remaining data to be sent -// asynchronously. Fulfill |write_promise_resolver_| once all data has been -// written. -void TCPWritableStreamWrapper::WriteCachedData() { - auto data = base::make_span(static_cast<uint8_t*>(cached_data_->data()), - cached_data_->length()) +void TCPWritableStreamWrapper::WriteDataAsynchronously() { + DCHECK(data_pipe_); + DCHECK(buffer_source_); + + DOMArrayPiece array_piece(buffer_source_); + // From https://webidl.spec.whatwg.org/#dfn-get-buffer-source-copy, if the + // buffer source is detached then an empty byte sequence is returned, which + // means the write is complete. + if (array_piece.IsDetached()) { + FinalizeWrite(); + return; + } + auto data = base::make_span(array_piece.Bytes(), array_piece.ByteLength()) .subspan(offset_); size_t written = WriteDataSynchronously(data); - if (written == data.size()) { - cached_data_.reset(); - offset_ = 0; - write_promise_resolver_->Resolve(); - write_promise_resolver_ = nullptr; + DCHECK_LE(offset_ + written, array_piece.ByteLength()); + if (offset_ + written == array_piece.ByteLength()) { + FinalizeWrite(); return; } - - if (!data_pipe_) { - cached_data_.reset(); - offset_ = 0; - - return; - } - offset_ += written; write_watcher_.ArmOrNotify(); @@ -200,8 +158,6 @@ // bytes written. May close |data_pipe_| as a side-effect on error. size_t TCPWritableStreamWrapper::WriteDataSynchronously( base::span<const uint8_t> data) { - DCHECK(data_pipe_); - // This use of saturated cast means that we will fallback to asynchronous // sending if |data| is larger than 4GB. In practice we'd never be able to // send 4GB synchronously anyway. @@ -224,6 +180,13 @@ } } +void TCPWritableStreamWrapper::FinalizeWrite() { + buffer_source_ = nullptr; + offset_ = 0; + write_promise_resolver_->Resolve(); + write_promise_resolver_ = nullptr; +} + void TCPWritableStreamWrapper::CloseStream() { if (GetState() != State::kOpen) { return; @@ -288,9 +251,8 @@ write_watcher_.Cancel(); close_watcher_.Cancel(); data_pipe_.reset(); - if (cached_data_) { - cached_data_.reset(); - } + buffer_source_ = nullptr; + offset_ = 0; } void TCPWritableStreamWrapper::Dispose() {
diff --git a/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.h b/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.h index 6d747b0..2e0ab345 100644 --- a/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.h +++ b/third_party/blink/renderer/modules/direct_sockets/tcp_writable_stream_wrapper.h
@@ -12,6 +12,7 @@ #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" #include "third_party/blink/renderer/modules/direct_sockets/stream_wrapper.h" @@ -54,18 +55,18 @@ // Called when |data_pipe_| is closed. void OnHandleReset(MojoResult, const mojo::HandleSignalsState&); - // Writes |data| to |data_pipe_|, possible saving unwritten data to - // |cached_data_|. - ScriptPromise WriteOrCacheData(base::span<const uint8_t> data, - ExceptionState&); - - // Attempts to write some more of |cached_data_| to |data_pipe_|. - void WriteCachedData(); + // Writes data contained in |buffer_source_| to |data_pipe_|, possibly in + // several asynchronous attempts. + void WriteDataAsynchronously(); // Writes zero or more bytes of |data| synchronously to |data_pipe_|, // returning the number of bytes that were written. size_t WriteDataSynchronously(base::span<const uint8_t> data); + // Resolves |write_promise_resolver_| and resets |buffer_source_| if write + // operation finished successfully. + void FinalizeWrite(); + // Errors |writable_|, resolves |writing_aborted_| and resets |data_pipe_|. void ErrorStreamAbortAndReset(bool error); @@ -75,31 +76,6 @@ // Prepares the object for destruction. void Dispose(); - // TODO(crbug.com/1337286): Remove this class. - class CachedDataBuffer { - public: - CachedDataBuffer(v8::Isolate* isolate, const uint8_t* data, size_t length); - - ~CachedDataBuffer(); - - size_t length() const { return length_; } - - uint8_t* data() { return buffer_.get(); } - - private: - // We need the isolate to call |AdjustAmountOfExternalAllocatedMemory| for - // the memory stored in |buffer_|. - v8::Isolate* isolate_; - size_t length_ = 0u; - - struct OnFree { - void operator()(void* ptr) const { - WTF::Partitions::BufferPartition()->Free(ptr); - } - }; - std::unique_ptr<uint8_t[], OnFree> buffer_; - }; - CloseOnceCallback on_close_; mojo::ScopedDataPipeProducerHandle data_pipe_; @@ -112,9 +88,7 @@ // Data which has been passed to write() but still needs to be written // asynchronously. - // Uses a custom CachedDataBuffer rather than a Vector because - // WTF::Vector is currently limited to 2GB. - std::unique_ptr<CachedDataBuffer> cached_data_; + Member<V8BufferSource> buffer_source_; // The offset into |cached_data_| of the first byte that still needs to be // written.
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc index 8a740a7a..eb254a1 100644 --- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc +++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
@@ -193,6 +193,26 @@ return direction ? SerializeDirection(*direction) : "null"; } +String SerializeTransceiverKind(const String& indent, + const RTCRtpTransceiverPlatform& transceiver) { + DCHECK(transceiver.Receiver()); + DCHECK(transceiver.Receiver()->Track()); + + auto kind = transceiver.Receiver()->Track()->GetSourceType(); + StringBuilder result; + result.Append(indent); + result.Append("kind:"); + if (kind == MediaStreamSource::StreamType::kTypeAudio) { + result.Append("'audio'"); + } else if (kind == MediaStreamSource::StreamType::kTypeVideo) { + result.Append("'video'"); + } else { + NOTREACHED(); + } + result.Append(",\n"); + return result.ToString(); +} + String SerializeEncodingParameters( const String& indent, const std::vector<webrtc::RtpEncodingParameters>& encodings) { @@ -246,7 +266,8 @@ String SerializeSender(const String& indent, const blink::RTCRtpSenderPlatform& sender) { StringBuilder result; - result.Append("{\n"); + result.Append(indent); + result.Append("sender:{\n"); // track:'id', result.Append(indent); result.Append(" track:"); @@ -266,14 +287,16 @@ result.Append(indent); result.Append( SerializeEncodingParameters(indent, sender.GetParameters()->encodings)); - result.Append("}"); + result.Append("},\n"); + return result.ToString(); } String SerializeReceiver(const String& indent, const RTCRtpReceiverPlatform& receiver) { StringBuilder result; - result.Append("{\n"); + result.Append(indent); + result.Append("receiver:{\n"); // track:'id', DCHECK(receiver.Track()); result.Append(indent); @@ -286,7 +309,7 @@ result.Append(SerializeMediaStreamIds(receiver.StreamIds())); result.Append(",\n"); result.Append(indent); - result.Append("}"); + result.Append("},\n"); return result.ToString(); } @@ -301,14 +324,12 @@ result.Append(String(transceiver.Mid())); result.Append("',\n"); } + // kind:audio|video + result.Append(SerializeTransceiverKind(" ", transceiver)); // sender:{...}, - result.Append(" sender:"); result.Append(SerializeSender(" ", *transceiver.Sender())); - result.Append(",\n"); // receiver:{...}, - result.Append(" receiver:"); result.Append(SerializeReceiver(" ", *transceiver.Receiver())); - result.Append(",\n"); // direction:'sendrecv', result.Append(" direction:"); result.Append(SerializeDirection(transceiver.Direction()));
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc index 1e30d96a..29cb2fc 100644 --- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc
@@ -30,6 +30,7 @@ const char* kDefaultTransceiverString = "getTransceivers()[0]:{\n" " mid:null,\n" + " kind:'audio',\n" " sender:{\n" " track:'senderTrackId',\n" " streams:['senderStreamId'],\n" @@ -283,6 +284,7 @@ "\n" "getTransceivers()[0]:{\n" " mid:'midValue',\n" + " kind:'audio',\n" " sender:{\n" " track:'senderTrackId',\n" " streams:['streamIdA','streamIdB'],\n" @@ -324,6 +326,7 @@ "\n" "getTransceivers()[1]:{\n" " mid:null,\n" + " kind:'audio',\n" " sender:{\n" " track:null,\n" " streams:[],\n"
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_storage_texture_binding_layout.idl b/third_party/blink/renderer/modules/webgpu/gpu_storage_texture_binding_layout.idl index 3fd0f00..77d589b5 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_storage_texture_binding_layout.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_storage_texture_binding_layout.idl
@@ -5,7 +5,7 @@ // https://gpuweb.github.io/gpuweb/ dictionary GPUStorageTextureBindingLayout { - required GPUStorageTextureAccess access; + GPUStorageTextureAccess access = "write-only"; required GPUTextureFormat format; GPUTextureViewDimension viewDimension = "2d"; };
diff --git a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h index 7e2250e..1a6ba5c 100644 --- a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h +++ b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
@@ -37,15 +37,17 @@ static constexpr bool kNeedsDestruction = !std::is_trivially_destructible<blink::TraceWrapperV8Reference<T>>::value; - // TraceWrapperV8Reference is not `is_trivially_default_constructible` as it - // requires initializing with zero. + + // TraceWrapperV8Reference has non-trivial construction/copying/moving. + // However, write barriers in Vector are properly emitted through + // ConstructTraits and as such the type can be trivially initialized, cleared, + // copied, and moved. static constexpr bool kCanInitializeWithMemset = true; - static constexpr bool kCanClearUnusedSlotsWithMemset = - std::is_trivially_destructible<blink::TraceWrapperV8Reference<T>>::value; - static constexpr bool kCanCopyWithMemcpy = std::is_trivially_copy_assignable< - blink::TraceWrapperV8Reference<T>>::value; - static constexpr bool kCanMoveWithMemcpy = std::is_trivially_move_assignable< - blink::TraceWrapperV8Reference<T>>::value; + static constexpr bool kCanClearUnusedSlotsWithMemset = true; + static constexpr bool kCanCopyWithMemcpy = true; + static constexpr bool kCanMoveWithMemcpy = true; + + // TraceWrapperV8Reference supports concurrent tracing. static constexpr bool kCanTraceConcurrently = true; // Wanted behavior that should not break for performance reasons.
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc index d03ae2c..38b9955 100644 --- a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc +++ b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
@@ -67,61 +67,51 @@ V8PerIsolateData::From(isolate)->RunEndOfScopeTasks(); } +static bool AllowAtomicWaits( + V8PerIsolateData::V8ContextSnapshotMode v8_context_snapshot_mode) { + return !IsMainThread() || + v8_context_snapshot_mode == + V8PerIsolateData::V8ContextSnapshotMode::kTakeSnapshot; +} + V8PerIsolateData::V8PerIsolateData( scoped_refptr<base::SingleThreadTaskRunner> task_runner, V8ContextSnapshotMode v8_context_snapshot_mode, v8::CreateHistogramCallback create_histogram_callback, v8::AddHistogramSampleCallback add_histogram_sample_callback) : v8_context_snapshot_mode_(v8_context_snapshot_mode), - isolate_holder_(task_runner, - gin::IsolateHolder::kSingleThread, - IsMainThread() ? gin::IsolateHolder::kDisallowAtomicsWait - : gin::IsolateHolder::kAllowAtomicsWait, - IsMainThread() - ? gin::IsolateHolder::IsolateType::kBlinkMainThread - : gin::IsolateHolder::IsolateType::kBlinkWorkerThread, - gin::IsolateHolder::IsolateCreationMode::kNormal, - create_histogram_callback, - add_histogram_sample_callback), + isolate_holder_( + task_runner, + gin::IsolateHolder::kSingleThread, + AllowAtomicWaits(v8_context_snapshot_mode) + ? gin::IsolateHolder::kAllowAtomicsWait + : gin::IsolateHolder::kDisallowAtomicsWait, + IsMainThread() ? gin::IsolateHolder::IsolateType::kBlinkMainThread + : gin::IsolateHolder::IsolateType::kBlinkWorkerThread, + v8_context_snapshot_mode == + V8PerIsolateData::V8ContextSnapshotMode::kTakeSnapshot + ? gin::IsolateHolder::IsolateCreationMode::kCreateSnapshot + : gin::IsolateHolder::IsolateCreationMode::kNormal, + create_histogram_callback, + add_histogram_sample_callback), string_cache_(std::make_unique<StringCache>(GetIsolate())), private_property_(std::make_unique<V8PrivateProperty>()), constructor_mode_(ConstructorMode::kCreateNewObject), - use_counter_disabled_(false), - is_handling_recursion_level_error_(false), runtime_call_stats_(base::DefaultTickClock::GetInstance()) { - // FIXME: Remove once all v8::Isolate::GetCurrent() calls are gone. - GetIsolate()->Enter(); - GetIsolate()->AddBeforeCallEnteredCallback(&BeforeCallEnteredCallback); - GetIsolate()->AddMicrotasksCompletedCallback(&MicrotasksCompletedCallback); + if (v8_context_snapshot_mode == V8ContextSnapshotMode::kTakeSnapshot) { + // Snapshot should only execute on the main thread. SnapshotCreator enters + // the isolate, so we don't call Isolate::Enter() here. + CHECK(IsMainThread()); + } else { + // FIXME: Remove once all v8::Isolate::GetCurrent() calls are gone. + GetIsolate()->Enter(); + GetIsolate()->AddBeforeCallEnteredCallback(&BeforeCallEnteredCallback); + GetIsolate()->AddMicrotasksCompletedCallback(&MicrotasksCompletedCallback); + } if (IsMainThread()) g_main_thread_per_isolate_data = this; } -// This constructor is used for creating a V8 context snapshot. It must run on -// the main thread. -// TODO(yukishiino): This constructor may not be necessary. Probably We can -// reuse V8PerIsolateData(task_runner, v8_context_snapshot_mode) constructor. -V8PerIsolateData::V8PerIsolateData( - V8ContextSnapshotMode v8_context_snapshot_mode) - : v8_context_snapshot_mode_(v8_context_snapshot_mode), - isolate_holder_(Thread::Current()->GetDeprecatedTaskRunner(), - gin::IsolateHolder::kSingleThread, - gin::IsolateHolder::kAllowAtomicsWait, - gin::IsolateHolder::IsolateType::kBlinkMainThread, - gin::IsolateHolder::IsolateCreationMode::kCreateSnapshot), - string_cache_(std::make_unique<StringCache>(GetIsolate())), - private_property_(std::make_unique<V8PrivateProperty>()), - constructor_mode_(ConstructorMode::kCreateNewObject), - use_counter_disabled_(false), - is_handling_recursion_level_error_(false), - runtime_call_stats_(base::DefaultTickClock::GetInstance()) { - CHECK(IsMainThread()); - CHECK_EQ(v8_context_snapshot_mode_, V8ContextSnapshotMode::kTakeSnapshot); - - // SnapshotCreator enters the isolate, so we don't call Isolate::Enter() here. - g_main_thread_per_isolate_data = this; -} - V8PerIsolateData::~V8PerIsolateData() = default; v8::Isolate* V8PerIsolateData::MainThreadIsolate() { @@ -136,14 +126,9 @@ v8::AddHistogramSampleCallback add_histogram_sample_callback) { TRACE_EVENT1("v8", "V8PerIsolateData::Initialize", "V8ContextSnapshotMode", context_mode); - V8PerIsolateData* data = nullptr; - if (context_mode == V8ContextSnapshotMode::kTakeSnapshot) { - data = new V8PerIsolateData(context_mode); - } else { - data = new V8PerIsolateData(task_runner, context_mode, - create_histogram_callback, - add_histogram_sample_callback); - } + V8PerIsolateData* data = + new V8PerIsolateData(task_runner, context_mode, create_histogram_callback, + add_histogram_sample_callback); DCHECK(data); v8::Isolate* isolate = data->GetIsolate();
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h index 4ed44ca..7f88f8e5 100644 --- a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h +++ b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h
@@ -224,7 +224,6 @@ V8ContextSnapshotMode, v8::CreateHistogramCallback, v8::AddHistogramSampleCallback); - explicit V8PerIsolateData(V8ContextSnapshotMode); ~V8PerIsolateData(); // A really simple hash function, which makes lookups faster. The set of @@ -267,10 +266,10 @@ bool constructor_mode_; friend class ConstructorMode; - bool use_counter_disabled_; + bool use_counter_disabled_ = false; friend class UseCounterDisabledScope; - bool is_handling_recursion_level_error_; + bool is_handling_recursion_level_error_ = false; Vector<base::OnceClosure> end_of_scope_tasks_; std::unique_ptr<Data> thread_debugger_;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 04923b64..6fd8845 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -57,6 +57,7 @@ # Flaking on WebKit Linux MSAN crbug.com/1207373 [ Linux ] external/wpt/uievents/order-of-events/mouse-events/mousemove-across.html [ Failure Pass ] crbug.com/1339285 [ Linux ] fast/loader/iframe-window-open-stealing-focus.html [ Failure Pass Timeout ] +crbug.com/1339285 [ Win ] fast/loader/iframe-window-open-stealing-focus.html [ Failure Pass Timeout ] crbug.com/1339285 [ Mac ] fast/loader/iframe-window-open-stealing-focus.html [ Pass Timeout ] # WPT Test harness doesn't deal with finding an about:blank ref test
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index 322276b..3f41839 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -239608,6 +239608,19 @@ {} ] ], + "image-loading-lazy-data-url-to-https.html": [ + "809068dd05adcde2dcc4e761969e587f32cd5813", + [ + null, + [ + [ + "/html/semantics/embedded-content/the-img-element/image-loading-lazy-data-url-to-https-ref.html", + "==" + ] + ], + {} + ] + ], "image-loading-lazy-slow-aspect-ratio.html": [ "662ada69095c5079924008ad2a252fdaa474267e", [ @@ -323739,6 +323752,10 @@ "05a60034ad0683c72db70f659c66075ac52c17bf", [] ], + "image-loading-lazy-data-url-to-https-ref.html": [ + "05a60034ad0683c72db70f659c66075ac52c17bf", + [] + ], "image-loading-lazy-expected.txt": [ "724ecac7ecfd4ce12ff9faf48d58d6c79ef61472", [] @@ -342158,6 +342175,10 @@ "3f1c072d108ca5b271d81118698a5e0ebc0e3649", [] ], + "background-sync.https.html": [ + "f11a951818a68bcb895b1ae489f95bae79637bf8", + [] + ], "battery-status.https.html": [ "eb611175381240b483bb8776a1610286bd3b7219", [] @@ -342194,6 +342215,14 @@ "5f8621ef83660c66f0d037ea28fafefb558140f1", [] ], + "dedicated-worker.https.html": [ + "570d4b33a147e02ba8fbdbc874a8a1d652359497", + [] + ], + "dedicated-worker.js": [ + "d8029556be21eeaedf0a59a2fe2b24fa5d3f0eab", + [] + ], "deferred-promise-utils.js": [ "19bc981a2ace513ce33f71d5f86aae292b3e8f1d", [] @@ -386516,7 +386545,7 @@ ] ], "anchor-position-multicol-003.tentative.html": [ - "0d3e3d8db995f18609a3fe6af45e64cdb76efda4", + "8ab938988c45183afb43b1c1f4029eabc19b8b16", [ null, {} @@ -490154,7 +490183,14 @@ ] ], "image-loading-lazy-crossorigin-change.sub.html": [ - "83e61d8465f4f91ac62ed01e0683561c1e297a94", + "84efc7b0d14f0be7daab2573cce96dac47d78399", + [ + null, + {} + ] + ], + "image-loading-lazy-empty-src.html": [ + "2a0aefea1df26b90d3455b370de3284a8037740c", [ null, {} @@ -545613,6 +545649,16 @@ } ] ], + "restriction-background-sync.tentative.https.html": [ + "7d49e14830aefcab13174144b9dc547258fb15f6", + [ + null, + { + "testdriver": true, + "timeout": "long" + } + ] + ], "restriction-battery-status.https.html": [ "80e25b08e723a73a75235608c9d902065b96eadd", [ @@ -545640,6 +545686,15 @@ } ] ], + "restriction-dedicated-worker.https.html": [ + "c58bd3434f8b9d1160fbed12bf0c7e62c5798ecc", + [ + null, + { + "timeout": "long" + } + ] + ], "restriction-encrypted-media-unsupported-config.https.html": [ "6a5cc0e89a3a0a0f4fd4dc90f5f1100bfac43903", [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/animation/color-interpolation-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-color/animation/color-interpolation-expected.txt new file mode 100644 index 0000000..7801d19 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-color/animation/color-interpolation-expected.txt
@@ -0,0 +1,196 @@ +This is a testharness.js-based test. +Found 192 tests; 120 PASS, 72 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS CSS Transitions: property <color> from neutral to [green] at (-0.3) should be [rgb(255, 255, 0)] +PASS CSS Transitions: property <color> from neutral to [green] at (0) should be [rgb(255, 255, 0)] +PASS CSS Transitions: property <color> from neutral to [green] at (0.3) should be [rgb(179, 217, 0)] +PASS CSS Transitions: property <color> from neutral to [green] at (0.6) should be [rgb(102, 179, 0)] +PASS CSS Transitions: property <color> from neutral to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Transitions: property <color> from neutral to [green] at (1.5) should be [rgb(0, 65, 0)] +PASS CSS Transitions with transition: all: property <color> from neutral to [green] at (-0.3) should be [rgb(255, 255, 0)] +PASS CSS Transitions with transition: all: property <color> from neutral to [green] at (0) should be [rgb(255, 255, 0)] +PASS CSS Transitions with transition: all: property <color> from neutral to [green] at (0.3) should be [rgb(179, 217, 0)] +PASS CSS Transitions with transition: all: property <color> from neutral to [green] at (0.6) should be [rgb(102, 179, 0)] +PASS CSS Transitions with transition: all: property <color> from neutral to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Transitions with transition: all: property <color> from neutral to [green] at (1.5) should be [rgb(0, 65, 0)] +PASS CSS Animations: property <color> from neutral to [green] at (-0.3) should be [rgb(255, 255, 0)] +PASS CSS Animations: property <color> from neutral to [green] at (0) should be [rgb(255, 255, 0)] +PASS CSS Animations: property <color> from neutral to [green] at (0.3) should be [rgb(179, 217, 0)] +PASS CSS Animations: property <color> from neutral to [green] at (0.6) should be [rgb(102, 179, 0)] +PASS CSS Animations: property <color> from neutral to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Animations: property <color> from neutral to [green] at (1.5) should be [rgb(0, 65, 0)] +PASS Web Animations: property <color> from neutral to [green] at (-0.3) should be [rgb(255, 255, 0)] +PASS Web Animations: property <color> from neutral to [green] at (0) should be [rgb(255, 255, 0)] +PASS Web Animations: property <color> from neutral to [green] at (0.3) should be [rgb(179, 217, 0)] +PASS Web Animations: property <color> from neutral to [green] at (0.6) should be [rgb(102, 179, 0)] +PASS Web Animations: property <color> from neutral to [green] at (1) should be [rgb(0, 128, 0)] +PASS Web Animations: property <color> from neutral to [green] at (1.5) should be [rgb(0, 65, 0)] +PASS CSS Transitions: property <color> from [initial] to [green] at (-0.3) should be [rgb(0, 0, 0)] +PASS CSS Transitions: property <color> from [initial] to [green] at (0) should be [rgb(0, 0, 0)] +PASS CSS Transitions: property <color> from [initial] to [green] at (0.3) should be [rgb(0, 38, 0)] +PASS CSS Transitions: property <color> from [initial] to [green] at (0.6) should be [rgb(0, 77, 0)] +PASS CSS Transitions: property <color> from [initial] to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Transitions: property <color> from [initial] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS CSS Transitions with transition: all: property <color> from [initial] to [green] at (-0.3) should be [rgb(0, 0, 0)] +PASS CSS Transitions with transition: all: property <color> from [initial] to [green] at (0) should be [rgb(0, 0, 0)] +PASS CSS Transitions with transition: all: property <color> from [initial] to [green] at (0.3) should be [rgb(0, 38, 0)] +PASS CSS Transitions with transition: all: property <color> from [initial] to [green] at (0.6) should be [rgb(0, 77, 0)] +PASS CSS Transitions with transition: all: property <color> from [initial] to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Transitions with transition: all: property <color> from [initial] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS CSS Animations: property <color> from [initial] to [green] at (-0.3) should be [rgb(0, 0, 0)] +PASS CSS Animations: property <color> from [initial] to [green] at (0) should be [rgb(0, 0, 0)] +PASS CSS Animations: property <color> from [initial] to [green] at (0.3) should be [rgb(0, 38, 0)] +PASS CSS Animations: property <color> from [initial] to [green] at (0.6) should be [rgb(0, 77, 0)] +PASS CSS Animations: property <color> from [initial] to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Animations: property <color> from [initial] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS Web Animations: property <color> from [initial] to [green] at (-0.3) should be [rgb(0, 0, 0)] +PASS Web Animations: property <color> from [initial] to [green] at (0) should be [rgb(0, 0, 0)] +PASS Web Animations: property <color> from [initial] to [green] at (0.3) should be [rgb(0, 38, 0)] +PASS Web Animations: property <color> from [initial] to [green] at (0.6) should be [rgb(0, 77, 0)] +PASS Web Animations: property <color> from [initial] to [green] at (1) should be [rgb(0, 128, 0)] +PASS Web Animations: property <color> from [initial] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS CSS Transitions: property <color> from [inherit] to [green] at (-0.3) should be [rgb(0, 0, 255)] +PASS CSS Transitions: property <color> from [inherit] to [green] at (0) should be [rgb(0, 0, 255)] +PASS CSS Transitions: property <color> from [inherit] to [green] at (0.3) should be [rgb(0, 38, 179)] +PASS CSS Transitions: property <color> from [inherit] to [green] at (0.6) should be [rgb(0, 77, 102)] +PASS CSS Transitions: property <color> from [inherit] to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Transitions: property <color> from [inherit] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS CSS Transitions with transition: all: property <color> from [inherit] to [green] at (-0.3) should be [rgb(0, 0, 255)] +PASS CSS Transitions with transition: all: property <color> from [inherit] to [green] at (0) should be [rgb(0, 0, 255)] +PASS CSS Transitions with transition: all: property <color> from [inherit] to [green] at (0.3) should be [rgb(0, 38, 179)] +PASS CSS Transitions with transition: all: property <color> from [inherit] to [green] at (0.6) should be [rgb(0, 77, 102)] +PASS CSS Transitions with transition: all: property <color> from [inherit] to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Transitions with transition: all: property <color> from [inherit] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS CSS Animations: property <color> from [inherit] to [green] at (-0.3) should be [rgb(0, 0, 255)] +PASS CSS Animations: property <color> from [inherit] to [green] at (0) should be [rgb(0, 0, 255)] +PASS CSS Animations: property <color> from [inherit] to [green] at (0.3) should be [rgb(0, 38, 179)] +PASS CSS Animations: property <color> from [inherit] to [green] at (0.6) should be [rgb(0, 77, 102)] +PASS CSS Animations: property <color> from [inherit] to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Animations: property <color> from [inherit] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS Web Animations: property <color> from [inherit] to [green] at (-0.3) should be [rgb(0, 0, 255)] +PASS Web Animations: property <color> from [inherit] to [green] at (0) should be [rgb(0, 0, 255)] +PASS Web Animations: property <color> from [inherit] to [green] at (0.3) should be [rgb(0, 38, 179)] +PASS Web Animations: property <color> from [inherit] to [green] at (0.6) should be [rgb(0, 77, 102)] +PASS Web Animations: property <color> from [inherit] to [green] at (1) should be [rgb(0, 128, 0)] +PASS Web Animations: property <color> from [inherit] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS CSS Transitions: property <color> from [unset] to [green] at (-0.3) should be [rgb(0, 0, 255)] +PASS CSS Transitions: property <color> from [unset] to [green] at (0) should be [rgb(0, 0, 255)] +PASS CSS Transitions: property <color> from [unset] to [green] at (0.3) should be [rgb(0, 38, 179)] +PASS CSS Transitions: property <color> from [unset] to [green] at (0.6) should be [rgb(0, 77, 102)] +PASS CSS Transitions: property <color> from [unset] to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Transitions: property <color> from [unset] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS CSS Transitions with transition: all: property <color> from [unset] to [green] at (-0.3) should be [rgb(0, 0, 255)] +PASS CSS Transitions with transition: all: property <color> from [unset] to [green] at (0) should be [rgb(0, 0, 255)] +PASS CSS Transitions with transition: all: property <color> from [unset] to [green] at (0.3) should be [rgb(0, 38, 179)] +PASS CSS Transitions with transition: all: property <color> from [unset] to [green] at (0.6) should be [rgb(0, 77, 102)] +PASS CSS Transitions with transition: all: property <color> from [unset] to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Transitions with transition: all: property <color> from [unset] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS CSS Animations: property <color> from [unset] to [green] at (-0.3) should be [rgb(0, 0, 255)] +PASS CSS Animations: property <color> from [unset] to [green] at (0) should be [rgb(0, 0, 255)] +PASS CSS Animations: property <color> from [unset] to [green] at (0.3) should be [rgb(0, 38, 179)] +PASS CSS Animations: property <color> from [unset] to [green] at (0.6) should be [rgb(0, 77, 102)] +PASS CSS Animations: property <color> from [unset] to [green] at (1) should be [rgb(0, 128, 0)] +PASS CSS Animations: property <color> from [unset] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS Web Animations: property <color> from [unset] to [green] at (-0.3) should be [rgb(0, 0, 255)] +PASS Web Animations: property <color> from [unset] to [green] at (0) should be [rgb(0, 0, 255)] +PASS Web Animations: property <color> from [unset] to [green] at (0.3) should be [rgb(0, 38, 179)] +PASS Web Animations: property <color> from [unset] to [green] at (0.6) should be [rgb(0, 77, 102)] +PASS Web Animations: property <color> from [unset] to [green] at (1) should be [rgb(0, 128, 0)] +PASS Web Animations: property <color> from [unset] to [green] at (1.5) should be [rgb(0, 192, 0)] +PASS CSS Transitions: property <color> from [black] to [orange] at (-0.3) should be [rgb(0, 0, 0)] +PASS CSS Transitions: property <color> from [black] to [orange] at (0) should be [rgb(0, 0, 0)] +PASS CSS Transitions: property <color> from [black] to [orange] at (0.3) should be [rgb(77, 50, 0)] +PASS CSS Transitions: property <color> from [black] to [orange] at (0.6) should be [rgb(153, 99, 0)] +PASS CSS Transitions: property <color> from [black] to [orange] at (1) should be [rgb(255, 165, 0)] +PASS CSS Transitions: property <color> from [black] to [orange] at (1.5) should be [rgb(255, 248, 0)] +PASS CSS Transitions with transition: all: property <color> from [black] to [orange] at (-0.3) should be [rgb(0, 0, 0)] +PASS CSS Transitions with transition: all: property <color> from [black] to [orange] at (0) should be [rgb(0, 0, 0)] +PASS CSS Transitions with transition: all: property <color> from [black] to [orange] at (0.3) should be [rgb(77, 50, 0)] +PASS CSS Transitions with transition: all: property <color> from [black] to [orange] at (0.6) should be [rgb(153, 99, 0)] +PASS CSS Transitions with transition: all: property <color> from [black] to [orange] at (1) should be [rgb(255, 165, 0)] +PASS CSS Transitions with transition: all: property <color> from [black] to [orange] at (1.5) should be [rgb(255, 248, 0)] +PASS CSS Animations: property <color> from [black] to [orange] at (-0.3) should be [rgb(0, 0, 0)] +PASS CSS Animations: property <color> from [black] to [orange] at (0) should be [rgb(0, 0, 0)] +PASS CSS Animations: property <color> from [black] to [orange] at (0.3) should be [rgb(77, 50, 0)] +PASS CSS Animations: property <color> from [black] to [orange] at (0.6) should be [rgb(153, 99, 0)] +PASS CSS Animations: property <color> from [black] to [orange] at (1) should be [rgb(255, 165, 0)] +PASS CSS Animations: property <color> from [black] to [orange] at (1.5) should be [rgb(255, 248, 0)] +PASS Web Animations: property <color> from [black] to [orange] at (-0.3) should be [rgb(0, 0, 0)] +PASS Web Animations: property <color> from [black] to [orange] at (0) should be [rgb(0, 0, 0)] +PASS Web Animations: property <color> from [black] to [orange] at (0.3) should be [rgb(77, 50, 0)] +PASS Web Animations: property <color> from [black] to [orange] at (0.6) should be [rgb(153, 99, 0)] +PASS Web Animations: property <color> from [black] to [orange] at (1) should be [rgb(255, 165, 0)] +PASS Web Animations: property <color> from [black] to [orange] at (1.5) should be [rgb(255, 248, 0)] +FAIL CSS Transitions: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL CSS Transitions: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL CSS Transitions: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Transitions: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Transitions with transition: all: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions with transition: all: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions with transition: all: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL CSS Transitions with transition: all: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL CSS Transitions with transition: all: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Transitions with transition: all: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL CSS Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL CSS Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL Web Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL Web Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL Web Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL Web Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL Web Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL Web Animations: property <color> from [rgb(0 0 0)] to [color(srgb 1 1 1)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [rgb(255 255 255)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Transitions: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Transitions with transition: all: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL CSS Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (-0.3) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0) should be [oklab(0 0 0)] assert_equals: expected "oklab ( 0 % 0 0 ) " but got "rgb ( 0 , 0 , 0 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0.3) should be [oklab(0.3 0 0)] assert_equals: expected "oklab ( 0.3 % 0 0 ) " but got "rgb ( 77 , 77 , 77 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (0.6) should be [oklab(0.6 0 0)] assert_equals: expected "oklab ( 0.6 % 0 0 ) " but got "rgb ( 153 , 153 , 153 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (1) should be [oklab(1 0 0)] assert_equals: expected "oklab ( 1 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +FAIL Web Animations: property <color> from [color(srgb 0 0 0)] to [color(srgb 1 1 1)] at (1.5) should be [oklab(1.5 0 0)] assert_equals: expected "oklab ( 1.5 % 0 0 ) " but got "rgb ( 255 , 255 , 255 ) " +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/animation/color-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-color/animation/color-interpolation.html index 4b39fdcf..7bda888 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-color/animation/color-interpolation.html +++ b/third_party/blink/web_tests/external/wpt/css/css-color/animation/color-interpolation.html
@@ -91,4 +91,43 @@ {at: 1, expect: 'rgb(255, 165, 0)'}, {at: 1.5, expect: 'rgb(255, 248, 0)'}, ]); + +test_interpolation({ + property: 'color', + from: 'rgb(0 0 0)', + to: 'color(srgb 1 1 1)', +}, [ + {at: -0.3, expect: 'oklab(0 0 0)'}, + {at: 0, expect: 'oklab(0 0 0)'}, + {at: 0.3, expect: 'oklab(0.3 0 0)'}, + {at: 0.6, expect: 'oklab(0.6 0 0)'}, + {at: 1, expect: 'oklab(1 0 0)'}, + {at: 1.5, expect: 'oklab(1.5 0 0)'}, +]); + +test_interpolation({ + property: 'color', + from: 'color(srgb 0 0 0)', + to: 'rgb(255 255 255)', +}, [ + {at: -0.3, expect: 'oklab(0 0 0)'}, + {at: 0, expect: 'oklab(0 0 0)'}, + {at: 0.3, expect: 'oklab(0.3 0 0)'}, + {at: 0.6, expect: 'oklab(0.6 0 0)'}, + {at: 1, expect: 'oklab(1 0 0)'}, + {at: 1.5, expect: 'oklab(1.5 0 0)'}, +]); + +test_interpolation({ + property: 'color', + from: 'color(srgb 0 0 0)', + to: 'color(srgb 1 1 1)', +}, [ + {at: -0.3, expect: 'oklab(0 0 0)'}, + {at: 0, expect: 'oklab(0 0 0)'}, + {at: 0.3, expect: 'oklab(0.3 0 0)'}, + {at: 0.6, expect: 'oklab(0.6 0 0)'}, + {at: 1, expect: 'oklab(1 0 0)'}, + {at: 1.5, expect: 'oklab(1.5 0 0)'}, +]); </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt index 3823a752..eeed0df 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 60 tests; 59 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 61 tests; 60 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS <length> values computed are correctly via var()-reference PASS <length> values computed are correctly via var()-reference when font-size is inherited PASS <length> values are computed correctly when font-size is inherited [14em] @@ -60,5 +60,6 @@ PASS <resolution> values are computed correctly [1dppx] PASS <resolution> values are computed correctly [96dpi] FAIL <resolution> values are computed correctly [calc(1dppx + 96dpi)] assert_equals: expected "2dppx" but got "0dppx" +PASS * values are computed correctly [url(why)] Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html index f03b257..1684952 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html +++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html
@@ -167,4 +167,6 @@ test_computed_value('<resolution>', '96dpi', '1dppx'); test_computed_value('<resolution>', 'calc(1dppx + 96dpi)', '2dppx'); +test_computed_value('*', 'url(why)', 'url(why)'); + </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-crossorigin-change.sub.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-crossorigin-change.sub.html index 83e61d8..84efc7b0 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-crossorigin-change.sub.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-crossorigin-change.sub.html
@@ -28,7 +28,7 @@ img.promise .then(t.unreached_func("The image should not load.")) - .catch(t.step_func_done()); + .catch(t.step_func(() => { img.element().onload = t.step_func_done(); img.element().src = 'resources/image.png'; })); }, "Test that when deferred image is loaded, it uses the latest crossorigin attribute."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-data-url-to-https-ref.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-data-url-to-https-ref.html new file mode 100644 index 0000000..05a60034 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-data-url-to-https-ref.html
@@ -0,0 +1,2 @@ +<!DOCTYPE html> +<img src="resources/image.png">
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-data-url-to-https.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-data-url-to-https.html new file mode 100644 index 0000000..809068dd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-data-url-to-https.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<head> + <title>Lazy loaded Images with data url placeholders can be overwritten by a src change</title> + <link rel="help" href="https://html.spec.whatwg.org/multipage/images.html#update-the-image-data"> + <link rel="match" href="image-loading-lazy-data-url-to-https-ref.html"> + <script src="/common/reftest-wait.js"></script> +</head> + +<body> + <img id="image" loading="lazy" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 872 490' width='872' height='490' style='background: green' %3E%3C/svg%3E"> + +<script> + const image = document.querySelector('#image'); + + window.onload = function() { + // trigger intersection observer through forced layout. + image.offsetWidth; + image.setAttribute("src", 'resources/image.png'); + setTimeout(() => { takeScreenshot(); }, 100); + }; +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-empty-src.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-empty-src.html new file mode 100644 index 0000000..2a0aefe --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-empty-src.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> +<title>Lazy loaded Images handle correctly when setting src to empty</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/images.html#update-the-image-data"> +<div id=log></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<img id="image" loading="lazy" src="resources/image.png"> + +<script> + const image = document.querySelector('#image'); + +async_test(function(t) { + image.onerror = t.step_func(function(e) { + assert_equals(e.type, "error", "null image source check failed"); + image.onload = t.step_func(function() { + t.done(); + }); + image.src = "resources/image.png"; + }); + image.src = ""; +}, "lazy loaded image and empty src"); + +</script>
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js index c46f99c9..60396dd 100644 --- a/third_party/closure_compiler/externs/file_manager_private.js +++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -764,6 +764,8 @@ /** @enum {string} */ chrome.fileManagerPrivate.DlpLevel = { + REPORT: 'report', + WARN: 'warn', BLOCK: 'block', ALLOW: 'allow', }; @@ -1551,13 +1553,6 @@ chrome.fileManagerPrivate.openManageSyncSettings = function() {}; /** - * Returns color via `callback` for Files app foreground window frame. - * @param {function(string): void} callback |color| String containing the color - * of the title bar. - */ -chrome.fileManagerPrivate.getFrameColor = function(callback) {}; - -/** * Parses the supplied .trashinfo files and returns the successfully parsed * data. * @param {!Array<!Entry>} entries
diff --git a/tools/determinism/compare_build_artifacts.py b/tools/determinism/compare_build_artifacts.py index d811d3db..2fa4ea3 100755 --- a/tools/determinism/compare_build_artifacts.py +++ b/tools/determinism/compare_build_artifacts.py
@@ -5,6 +5,7 @@ """Compare the artifacts from two builds.""" +from __future__ import division from __future__ import print_function import ast @@ -103,7 +104,7 @@ """Returns a compact binary diff if the diff is small enough.""" BLOCK_SIZE = 8192 CHUNK_SIZE = 32 - NUM_CHUNKS_IN_BLOCK = BLOCK_SIZE / CHUNK_SIZE + NUM_CHUNKS_IN_BLOCK = BLOCK_SIZE // CHUNK_SIZE MAX_STREAMS = 10 num_diffs = 0 streams = []
diff --git a/tools/determinism/compare_build_artifacts_test.py b/tools/determinism/compare_build_artifacts_test.py new file mode 100755 index 0000000..8d9dd75 --- /dev/null +++ b/tools/determinism/compare_build_artifacts_test.py
@@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import tempfile +import unittest +import os + +import compare_build_artifacts + + +class Test(unittest.TestCase): + def test_diff_binary(self): + with tempfile.TemporaryDirectory() as dir: + filea = os.path.join(dir, 'a') + fileb = os.path.join(dir, 'b') + + with open(filea, 'wb') as f: + f.write(b'a') + + with open(fileb, 'wb') as f: + f.write(b'b') + + self.assertEqual( + compare_build_artifacts.diff_binary(filea, fileb, 1), + """1 out of 1 bytes are different (100.00%) + 0x0 : 61 'a' + 62 'b' + 62 'b""") + + +if __name__ == '__main__': + unittest.main()
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index b13138d..2817ea5 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -2934,11 +2934,11 @@ ], 'ios_catalyst_debug_static_bot_compile_only_libfuzzer_asan_no_dsyms_no_remoting': [ - 'compile_only', 'debug_static_bot', 'ios', 'ios_catalyst', 'ios_cpu_x64', 'ios_disable_xcode_project_generation', 'asan', 'libfuzzer', 'no_dsyms', 'no_remoting', 'no_hermetic_swift', + 'compile_only', 'debug_static_bot', 'ios', 'ios_catalyst', 'ios_cpu_x64', 'ios_disable_xcode_project_generation', 'asan', 'libfuzzer', 'no_dsyms', 'no_remoting', ], 'ios_catalyst_debug_static_bot_compile_only_libfuzzer_asan_no_dsyms_no_remoting_reclient': [ - 'compile_only', 'debug_static_bot_reclient', 'ios', 'ios_catalyst', 'ios_cpu_x64', 'ios_disable_xcode_project_generation', 'asan', 'libfuzzer', 'no_dsyms', 'no_remoting', 'no_hermetic_swift' + 'compile_only', 'debug_static_bot_reclient', 'ios', 'ios_catalyst', 'ios_cpu_x64', 'ios_disable_xcode_project_generation', 'asan', 'libfuzzer', 'no_dsyms', 'no_remoting', ], 'ios_clang_device_tot_xctest': [ @@ -4398,10 +4398,6 @@ 'gn_args': 'use_goma=false', }, - 'no_hermetic_swift': { - 'gn_args': 'swift_toolchain_path=""', - }, - 'no_keystone_registration_framework': { 'gn_args': 'enable_keystone_registration_framework=false', },
diff --git a/tools/mb/mb_config_expectations/chromium.fuzz.json b/tools/mb/mb_config_expectations/chromium.fuzz.json index e21360db..d087d09f 100644 --- a/tools/mb/mb_config_expectations/chromium.fuzz.json +++ b/tools/mb/mb_config_expectations/chromium.fuzz.json
@@ -397,7 +397,6 @@ "is_asan": true, "is_component_build": false, "is_debug": true, - "swift_toolchain_path": "", "symbol_level": 1, "target_cpu": "x64", "target_environment": "catalyst",
diff --git a/tools/mb/mb_config_expectations/chromium.mac.json b/tools/mb/mb_config_expectations/chromium.mac.json index 7b4fe47..7e8ea1c 100644 --- a/tools/mb/mb_config_expectations/chromium.mac.json +++ b/tools/mb/mb_config_expectations/chromium.mac.json
@@ -29,7 +29,6 @@ "is_asan": true, "is_component_build": false, "is_debug": true, - "swift_toolchain_path": "", "symbol_level": 1, "target_cpu": "x64", "target_environment": "catalyst",
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.mac.json b/tools/mb/mb_config_expectations/tryserver.chromium.mac.json index f28b90c4..734ee8c5 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.mac.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.mac.json
@@ -210,7 +210,6 @@ "is_asan": true, "is_component_build": false, "is_debug": true, - "swift_toolchain_path": "", "symbol_level": 1, "target_cpu": "x64", "target_environment": "catalyst",
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index f30c3dd7..40dd4f1 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -15729,6 +15729,11 @@ </description> </action> +<action name="LensUnifiedSidePanel.RemoveLensEntry_SearchEngineChanged"> + <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <description>Please enter the description of the metric.</description> +</action> + <action name="LensUnifiedSidePanel.ResultLinkClick"> <owner>stanfield@google.com</owner> <owner>benwgold@google.com</owner> @@ -24533,6 +24538,14 @@ </description> </action> +<action name="PasswordProtection.Gaia.HashedPasswordSaved"> + <owner>nwokedi@chromium.org</owner> + <owner>chrome-counter-abuse-alerts@google.com</owner> + <description> + Reported when a user's hashed gaia password is saved. + </description> +</action> + <action name="PasswordProtection.Gmail.ChangePasswordButtonClicked"> <owner>nwokedi@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> @@ -24595,6 +24608,14 @@ </description> </action> +<action name="PasswordProtection.NonGaiaEnterprise.HashedPasswordSaved"> + <owner>nwokedi@chromium.org</owner> + <owner>chrome-counter-abuse-alerts@google.com</owner> + <description> + Reported when a user's hashed non-gaia-enterprise password is saved. + </description> +</action> + <action name="PasswordProtection.PageInfo.ChangePasswordButtonClicked"> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 2249dc188..2a12faa 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -103291,7 +103291,10 @@ <int value="-1569772500" label="/manageAccessibility/tts"/> <int value="-1555301506" label="/content/notifications"/> <int value="-1484929503" label="/manageAccessibility/switchAccess"/> + <int value="-1435300306" label="/passwords/view"/> + <int value="-1402547108" label="/passwords/device"/> <int value="-1381133263" label="/passwords/check"/> + <int value="-1334017282" label="/spellCheck"/> <int value="-1312744606" label="/knownNetworks"/> <int value="-1297176639" label="/fonts"/> <int value="-1283080115" label="/content/backgroundSync"/> @@ -103315,6 +103318,7 @@ <int value="-916174295" label="/internet"/> <int value="-907780721" label="/certificates"/> <int value="-898481268" label="/multidevice/features"/> + <int value="-876839853" label="/content/windowPlacement"/> <int value="-842548379" label="/apps"/> <int value="-809146474" label="/content/location"/> <int value="-794215283" label="/content/images"/> @@ -103323,6 +103327,7 @@ <int value="-655433489" label="/payments"/> <int value="-590688273" label="/content/sensors"/> <int value="-570956986" label="/personalization"/> + <int value="-565073397" label="/performance"/> <int value="-512116630" label="/search"/> <int value="-482801316" label="/appearance"/> <int value="-469021167" label="/resetProfileSettings"/> @@ -103337,18 +103342,24 @@ <int value="-237154443" label="/manageAccessibility/tts/googleTtsEngine"/> <int value="-230959653" label="/syncSetup"/> <int value="-210069062" label="/content"/> + <int value="-191557146" label="/content/bluetoothDevices"/> <int value="-189314307" label="/crostini/exportImport"/> <int value="-152132510" label="/captions"/> <int value="-146134264" label="/content/protectedContent"/> + <int value="-141168426" label="/passkeys"/> + <int value="-74938958" label="/content/federatedIdentityApi"/> + <int value="-68849649" label="/securityKeys/phones"/> <int value="-59332819" label="/accountManager"/> <int value="-44267040" label="/bluetoothDevices"/> <int value="-23311755" label="/content/vr"/> <int value="-14666765" label="/accounts"/> + <int value="4710857" label="/content/hidDevices"/> <int value="8030578" label="/crostini/sharedUsbDevices"/> <int value="8530592" label="/syncSetup/advanced"/> <int value="16287984" label="/languages/details"/> <int value="53341592" label="/privacySandbox"/> <int value="60238454" label="/content/ads"/> + <int value="91791837" label="/content/localFonts"/> <int value="104900992" label="/content/insecureContent"/> <int value="223791833" label="/help/about"/> <int value="254445609" label="/content/filesystem"/> @@ -103382,6 +103393,7 @@ <int value="1225485397" label="/content/unsandboxedPlugins"/> <int value="1258785570" label="/crostini/sharedPaths"/> <int value="1300569861" label="/keyboard-overlay"/> + <int value="1338599766" label="/content/idleDetection"/> <int value="1364454971" label="/androidApps"/> <int value="1384165448" label="/stylus"/> <int value="1462185522" label="/dateTime"/>
diff --git a/tools/metrics/histograms/metadata/ash_clipboard/histograms.xml b/tools/metrics/histograms/metadata/ash_clipboard/histograms.xml index c42051a8..64bb979 100644 --- a/tools/metrics/histograms/metadata/ash_clipboard/histograms.xml +++ b/tools/metrics/histograms/metadata/ash_clipboard/histograms.xml
@@ -195,7 +195,6 @@ ToFeaturePasteTime and ToFeatureOpenTime histograms. </summary> <token key="NudgeType"> - <variant name="NewFeatureBadge" summary="new feature badge"/> <variant name="OnboardingNudge" summary="onboarding nudge"/> <variant name="ScreenshotNotificationNudge" summary="screenshot notification nudge"/> @@ -213,7 +212,6 @@ used to measure the conversion rate by comparing it to ShownCount histogram </summary> <token key="NudgeType"> - <variant name="NewFeatureBadge" summary="new feature badge"/> <variant name="OnboardingNudge" summary="onboarding nudge"/> <variant name="ScreenshotNotificationNudge" summary="screenshot notification nudge"/>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml index 959a6e87..2822aab 100644 --- a/tools/metrics/histograms/metadata/autofill/histograms.xml +++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -2782,6 +2782,20 @@ </summary> </histogram> +<histogram name="Autofill.ProfileImport.NewProfileWithIgnoredCountryDecision" + enum="AutofillProfileImportDecision" expires_after="2023-02-26"> + <owner>fleimgruber@google.com</owner> + <owner>chrome-autofill-team@google.com</owner> + <summary> + Logs the user's decision for storing a new address profile observed in a + form submission. The profile was only considered an import candidate after + an invalid country was ignored. This metric is emitted at the end of an + import process once the user-provided import decision is final. It is + collected in addition to Autofill.ProfileImport.NewProfileDecision and only + if kAutofillIgnoreInvalidCountryOnImport is enabled. + </summary> +</histogram> + <histogram name="Autofill.ProfileImport.NewProfileWithRemovedPhoneNumberDecision" enum="AutofillProfileImportDecision" expires_after="2023-02-12"> @@ -2993,6 +3007,22 @@ </histogram> <histogram + name="Autofill.ProfileImport.UpdateProfileWithIgnoredCountryDecision" + enum="AutofillProfileImportDecision" expires_after="2023-02-26"> + <owner>fleimgruber@google.com</owner> + <owner>chrome-autofill-team@google.com</owner> + <summary> + Logs the user's decision for editing an already existing address after a + similar profile was observed in a form submission. The profile was only + considered an import candidate after an invalid country was ignored. This + metric is emitted at the end of an import process once the user-provided + import decision is final. It is collected in addition to + Autofill.ProfileImport.UpdateProfileDecision and only if + kAutofillIgnoreInvalidCountryOnImport is enabled. + </summary> +</histogram> + +<histogram name="Autofill.ProfileImport.UpdateProfileWithRemovedPhoneNumberDecision" enum="AutofillProfileImportDecision" expires_after="2023-03-05"> <owner>fleimgruber@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/memory/histograms.xml b/tools/metrics/histograms/metadata/memory/histograms.xml index ff5149a..ea85a37 100644 --- a/tools/metrics/histograms/metadata/memory/histograms.xml +++ b/tools/metrics/histograms/metadata/memory/histograms.xml
@@ -874,81 +874,6 @@ </summary> </histogram> -<histogram - name="Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter10secs2" - units="MB" expires_after="2019-7-31"> - <owner>yuzus@chromium.org</owner> - <owner>keishi@chromium.org</owner> - <summary> - Reduced amount of blink usage after 10 seconds of intervention. This reports - positive numbers when reduced. - </summary> -</histogram> - -<histogram - name="Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter20secs2" - units="MB" expires_after="2019-7-31"> - <owner>yuzus@chromium.org</owner> - <owner>keishi@chromium.org</owner> - <summary> - Reduced amount of blink usage after 20 seconds of intervention. This reports - positive numbers when reduced. - </summary> -</histogram> - -<histogram - name="Memory.Experimental.OomIntervention.ReducedBlinkUsageAfter30secs2" - units="MB" expires_after="2019-7-31"> - <owner>yuzus@chromium.org</owner> - <owner>keishi@chromium.org</owner> - <summary> - Reduced amount of blink usage after 30 seconds of intervention. This reports - positive numbers when reduced. - </summary> -</histogram> - -<histogram - name="Memory.Experimental.OomIntervention.ReducedRendererPMFAfter10secs2" - units="MB" expires_after="2019-7-31"> - <owner>yuzus@chromium.org</owner> - <owner>keishi@chromium.org</owner> - <summary> - Reduced amount of renderer pmf after 10 seconds of intervention. This - reports positive numbers when reduced. - </summary> -</histogram> - -<histogram - name="Memory.Experimental.OomIntervention.ReducedRendererPMFAfter20secs2" - units="MB" expires_after="2019-7-31"> - <owner>yuzus@chromium.org</owner> - <owner>keishi@chromium.org</owner> - <summary> - Reduced amount of renderer pmf after 20 seconds of intervention. This - reports positive numbers when reduced. - </summary> -</histogram> - -<histogram - name="Memory.Experimental.OomIntervention.ReducedRendererPMFAfter30secs2" - units="MB" expires_after="2019-7-31"> - <owner>yuzus@chromium.org</owner> - <owner>keishi@chromium.org</owner> - <summary> - Reduced amount of renderer pmf after 30 seconds of intervention. This - reports positive numbers when reduced. - </summary> -</histogram> - -<histogram name="Memory.Experimental.OomIntervention.RendererBlinkUsage" - units="MB" expires_after="M85"> - <owner>yuzus@chromium.org</owner> - <summary> - The renderer process's memory usage reported every second when OOM - intervention is enabled. - </summary> -</histogram> - <histogram name="Memory.Experimental.OomIntervention.RendererBlinkUsageAtOOM" units="MB" expires_after="M77"> <owner>ssid@chromium.org</owner> @@ -960,16 +885,6 @@ </histogram> <histogram - name="Memory.Experimental.OomIntervention.RendererPrivateMemoryFootprint" - units="MB" expires_after="2020-06-07"> - <owner>yuzus@chromium.org</owner> - <summary> - The renderer process's PMF size reported every second when OOM intervention - is enabled. - </summary> -</histogram> - -<histogram name="Memory.Experimental.OomIntervention.RendererPrivateMemoryFootprintAtOOM" units="MB" expires_after="M85"> <owner>ssid@chromium.org</owner> @@ -981,15 +896,6 @@ </summary> </histogram> -<histogram name="Memory.Experimental.OomIntervention.RendererSwapFootPrint" - units="MB" expires_after="M85"> - <owner>yuzus@chromium.org</owner> - <summary> - The renderer process's swap size reported every second when OOM intervention - is enabled. - </summary> -</histogram> - <histogram name="Memory.Experimental.OomIntervention.RendererSwapFootprintAtOOM" units="MB" expires_after="M85"> @@ -1036,15 +942,6 @@ </summary> </histogram> -<histogram name="Memory.Experimental.OomIntervention.RendererVMSize" units="MB" - expires_after="M85"> - <owner>yuzus@chromium.org</owner> - <summary> - The renderer process's virtual memory usage reported every second when OOM - intervention is enabled. - </summary> -</histogram> - <histogram name="Memory.Experimental.OomIntervention.RendererVmSizeAtOOMLarge" units="MB" expires_after="M85"> <owner>ssid@chromium.org</owner> @@ -1056,34 +953,6 @@ </summary> </histogram> -<histogram name="Memory.Experimental.OomIntervention.V8UsageAfter10secs" - units="MB" expires_after="M85"> - <owner>keishi@chromium.org</owner> - <owner>yuzus@chromium.org</owner> - <summary>V8 memory usage 10 seconds after intervention.</summary> -</histogram> - -<histogram name="Memory.Experimental.OomIntervention.V8UsageAfter20secs" - units="MB" expires_after="M85"> - <owner>keishi@chromium.org</owner> - <owner>yuzus@chromium.org</owner> - <summary>V8 memory usage 20 seconds after intervention.</summary> -</histogram> - -<histogram name="Memory.Experimental.OomIntervention.V8UsageAfter30secs" - units="MB" expires_after="2020-02-02"> - <owner>keishi@chromium.org</owner> - <owner>yuzus@chromium.org</owner> - <summary>V8 memory usage 30 seconds after intervention.</summary> -</histogram> - -<histogram name="Memory.Experimental.OomIntervention.V8UsageBefore" units="MB" - expires_after="M85"> - <owner>keishi@chromium.org</owner> - <owner>yuzus@chromium.org</owner> - <summary>V8 memory usage right before intervention.</summary> -</histogram> - <histogram base="true" name="Memory.Experimental.Renderer" units="MB" expires_after="2021-04-18"> <!-- Name completed by histogram_suffixes name="RendererMemoryAllocator" --> @@ -2675,6 +2544,34 @@ </summary> </histogram> +<histogram name="Memory.Total.PrivateMemoryFootprintExcludingWaivedRenderers" + units="MB" expires_after="2022-12-11"> + <owner>ckitagawa@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + A rough estimate of the private memory footprint of all processes on Android + ignoring Renderers with only Waived process bindings. + + Recorded at Poisson sampled time intervals with a mean of 5 minutes on + Android. + </summary> +</histogram> + +<histogram + name="Memory.Total.PrivateMemoryFootprintVisiblePriorityOrHigherRenderers" + units="MB" expires_after="2022-12-11"> + <owner>ckitagawa@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + A rough estimate of the private memory footprint of all visible or higher + importance processes on Android. This ignores Renderers with Waived or Not + Perceptible effective process bindings. + + Recorded at Poisson sampled time intervals with a mean of 5 minutes on + Android. + </summary> +</histogram> + <histogram name="Memory.Total.RendererMalloc" units="MB" expires_after="2022-10-01"> <owner>keishi@chromium.org</owner> @@ -2705,6 +2602,34 @@ </summary> </histogram> +<histogram name="Memory.Total.RendererPrivateMemoryFootprintExcludingWaived" + units="MB" expires_after="2022-12-11"> + <owner>ckitagawa@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + A rough estimate of the private memory footprint of all renderer processes + on Android ignoring Renderers with only Waived process bindings. + + Recorded at Poisson sampled time intervals with a mean of 5 minutes on + Android. + </summary> +</histogram> + +<histogram + name="Memory.Total.RendererPrivateMemoryFootprintVisiblePriorityOrHigher" + units="MB" expires_after="2022-12-11"> + <owner>ckitagawa@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + A rough estimate of the private memory footprint of all renderer processes + with visible or higher importance on Android. This ignores Renderers with + Waived or Not Perceptible effective process bindings. + + Recorded at Poisson sampled time intervals with a mean of 5 minutes on + Android. + </summary> +</histogram> + <histogram name="Memory.Total.ResidentSet" units="MiB" expires_after="never"> <!-- expires-never: Generic system health metric used to diagnose various performance issues. -->
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index 2ba41158..343ee73 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -4663,7 +4663,7 @@ </histogram> <histogram name="DirectSockets.PermissionDeniedFailures" - enum="DirectSocketPermissionFailureType" expires_after="2022-10-26"> + enum="DirectSocketPermissionFailureType" expires_after="2023-09-13"> <owner>ericwilligers@chromium.org</owner> <owner>glenrob@chromium.org</owner> <owner>greengrape@google.com</owner> @@ -4676,7 +4676,7 @@ </histogram> <histogram name="DirectSockets.TCPNetworkFailures" enum="NetErrorCodes" - expires_after="2022-10-26"> + expires_after="2023-09-13"> <owner>ericwilligers@chromium.org</owner> <owner>greengrape@google.com</owner> <summary> @@ -4685,7 +4685,7 @@ </histogram> <histogram name="DirectSockets.UDPNetworkFailures" enum="NetErrorCodes" - expires_after="2022-10-26"> + expires_after="2023-09-13"> <owner>ericwilligers@chromium.org</owner> <owner>greengrape@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml index 584f88e..186816db 100644 --- a/tools/metrics/histograms/metadata/password/histograms.xml +++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -124,7 +124,7 @@ </histogram> <histogram name="KeyboardAccessory.AccessorySheetSuggestionCount" units="count" - expires_after="2022-10-23"> + expires_after="2023-02-26"> <owner>fhorschig@chromium.org</owner> <owner>ioanap@chromium.org</owner> <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index c9366c7..c56cc61 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@ "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell" }, "win": { - "hash": "894f030a50957e00771af5c7e845974572aa61fd", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/42b38904956e25c127f558979c0286e7c70115b9/trace_processor_shell.exe" + "hash": "fc85de9a5ac19a3eb9bce8cbdc261d08e30cbdbf", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/b910084bb46109fc40ac3eb3719d455bc53e9611/trace_processor_shell.exe" }, "linux_arm": { "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893", @@ -21,8 +21,8 @@ "full_remote_path": "perfetto-luci-artifacts/v25.0/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "2def3da0a17075c1ac61fc6c21a0189e3510a43b", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/42b38904956e25c127f558979c0286e7c70115b9/trace_processor_shell" + "hash": "14ca6d14472d3a41d9f5f56e33bdfafc8a13a8d1", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/b910084bb46109fc40ac3eb3719d455bc53e9611/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/ui/base/ime/ash/input_method_util.cc b/ui/base/ime/ash/input_method_util.cc index 679b838..fcea804 100644 --- a/ui/base/ime/ash/input_method_util.cc +++ b/ui/base/ime/ash/input_method_util.cc
@@ -269,6 +269,7 @@ {"__MSG_KEYBOARD_GUJARATI_PHONETIC__", IDS_IME_NAME_KEYBOARD_GUJARATI_PHONETIC}, {"__MSG_KEYBOARD_HEBREW__", IDS_IME_NAME_KEYBOARD_HEBREW}, + {"__MSG_KEYBOARD_HINDI_INSCRIPT__", IDS_IME_NAME_KEYBOARD_HINDI_INSCRIPT}, {"__MSG_KEYBOARD_HUNGARIAN_QWERTY__", IDS_IME_NAME_KEYBOARD_HUNGARIAN_QWERTY}, {"__MSG_KEYBOARD_HUNGARIAN__", IDS_IME_NAME_KEYBOARD_HUNGARIAN},
diff --git a/ui/chromeos/ui_chromeos_strings.grd b/ui/chromeos/ui_chromeos_strings.grd index 4201e91..a65b382 100644 --- a/ui/chromeos/ui_chromeos_strings.grd +++ b/ui/chromeos/ui_chromeos_strings.grd
@@ -1273,6 +1273,9 @@ <message name="IDS_IME_NAME_TRANSLITERATION_HI" desc="Input method name, shown in system tray menu, settings page, etc. following this template: “|language| (|variant|) |IME| with |layout| keyboard” which means “an input method that supports typing in the |variant| of |language|, using |IME| and a keyboard with |layout|. When a part in this template is unambiguous, it’s dropped for brevity. Translations should strive for similar consistency in structure among input method names. Note: On ChromeOS, an “input method” is a suite of all input functionalities. |IME| in the template refers to an optional aspect of an “input method” on ChromeOS, i.e. sophisticated transforms into text in |language| when using a keyboard layout not designed for |language|." meaning="Input method name"> Hindi </message> + <message name="IDS_IME_NAME_KEYBOARD_HINDI_INSCRIPT" desc="Input method name, shown in system tray menu, settings page, etc. following this template: “|language| (|variant|) |IME| with |layout| keyboard” which means “an input method that supports typing in the |variant| of |language|, using |IME| and a keyboard with |layout|. When a part in this template is unambiguous, it’s dropped for brevity. Translations should strive for similar consistency in structure among input method names. Note: On ChromeOS, an “input method” is a suite of all input functionalities. |IME| in the template refers to an optional aspect of an “input method” on ChromeOS, i.e. sophisticated transforms into text in |language| when using a keyboard layout not designed for |language|." meaning="Input method name"> + Hindi with InScript keyboard + </message> <message name="IDS_IME_NAME_TRANSLITERATION_KN" desc="Input method name, shown in system tray menu, settings page, etc. following this template: “|language| (|variant|) |IME| with |layout| keyboard” which means “an input method that supports typing in the |variant| of |language|, using |IME| and a keyboard with |layout|. When a part in this template is unambiguous, it’s dropped for brevity. Translations should strive for similar consistency in structure among input method names. Note: On ChromeOS, an “input method” is a suite of all input functionalities. |IME| in the template refers to an optional aspect of an “input method” on ChromeOS, i.e. sophisticated transforms into text in |language| when using a keyboard layout not designed for |language|." meaning="Input method name"> Kannada Transliteration </message>
diff --git a/ui/chromeos/ui_chromeos_strings_grd/IDS_IME_NAME_KEYBOARD_HINDI_INSCRIPT.png.sha1 b/ui/chromeos/ui_chromeos_strings_grd/IDS_IME_NAME_KEYBOARD_HINDI_INSCRIPT.png.sha1 new file mode 100644 index 0000000..2c2f1332 --- /dev/null +++ b/ui/chromeos/ui_chromeos_strings_grd/IDS_IME_NAME_KEYBOARD_HINDI_INSCRIPT.png.sha1
@@ -0,0 +1 @@ +3ac344ead17350ea3fb424d347639f50ae634286 \ No newline at end of file
diff --git a/ui/file_manager/file_manager/background/js/BUILD.gn b/ui/file_manager/file_manager/background/js/BUILD.gn index 46b272c..3e0cbbef 100644 --- a/ui/file_manager/file_manager/background/js/BUILD.gn +++ b/ui/file_manager/file_manager/background/js/BUILD.gn
@@ -40,7 +40,6 @@ js_type_check("closure_compile_jsmodules") { deps = [ ":app_window_wrapper", - ":app_windows", ":crostini", ":drive_sync_handler", ":entry_location_impl", @@ -96,16 +95,12 @@ js_library("app_window_wrapper") { visibility += related_apps deps = [ - ":app_windows", "//ui/file_manager/file_manager/common/js:api", "//ui/file_manager/file_manager/common/js:async_util", "//ui/file_manager/file_manager/common/js:files_app_state", ] } -js_library("app_windows") { -} - js_library("file_manager_base") { deps = [ ":crostini", @@ -369,7 +364,6 @@ visibility += [ "//ui/file_manager/integration_tests:remote_call" ] deps = [ - ":app_windows", ":file_operation_util", ":volume_manager_factory", "//ui/file_manager/file_manager/common/js:error_counter", @@ -379,7 +373,6 @@ "//ui/file_manager/file_manager/externs/background:file_manager_base", "//ui/webui/resources/js:assert.m", ] - externs_list = [ "$externs_path/webview_tag.js" ] } js_library("volume_info_impl") {
diff --git a/ui/file_manager/file_manager/background/js/app_window_wrapper.js b/ui/file_manager/file_manager/background/js/app_window_wrapper.js index cb8b353a..33c4ca2 100644 --- a/ui/file_manager/file_manager/background/js/app_window_wrapper.js +++ b/ui/file_manager/file_manager/background/js/app_window_wrapper.js
@@ -2,37 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import './app_windows.js'; - import {openWindow} from '../../common/js/api.js'; import {AsyncUtil} from '../../common/js/async_util.js'; import {FilesAppState} from '../../common/js/files_app_state.js'; -/** - * Wrapper for an app window. - * - * Expects the following from the app scripts: - * 1. The page load handler should initialize the app using |window.appState| - * and call |appUtil.saveAppState|. - * 2. Every time the app state changes the app should update |window.appState| - * and call |appUtil.saveAppState| . - * 3. The app may have |unload| function to persist the app state that does not - * fit into |window.appState|. - */ +/** Coordinates the creation of new windows for Files app. */ export class AppWindowWrapper { /** * @param {string} url App window content url. - * @param {string} id App window id. - * @param {Object} options Options object to create it. */ - constructor(url, id, options) { + constructor(url) { this.url_ = url; - this.id_ = id; - // Do deep copy for the template of options to assign customized params - // later. - this.options_ = /** @type {!chrome.app.window.CreateWindowOptions} */ ( - JSON.parse(JSON.stringify(options))); - this.window_ = null; /** @private {?FilesAppState} */ this.appState_ = null; this.openingOrOpened_ = false; @@ -42,22 +22,6 @@ } /** - * @return {chrome.app.window.AppWindow} Wrapped application window. - */ - get rawAppWindow() { - return this.window_; - } - - /** - * Sets the icon of the window. - * @param {string} iconPath Path of the icon. - */ - setIcon(iconPath) { - this.window_.setIcon(iconPath); - } - - - /** * Gets the launch lock, used to synchronize the asynchronous initialization * steps. * @@ -86,7 +50,7 @@ // Save application state. this.appState_ = appState; - return this.launchSWA_(); + return this.launch_(); } /** @@ -95,10 +59,10 @@ * @return {Promise} Resolved when the window is launched. * @private */ - async launchSWA_() { + async launch_() { const unlock = await this.getLaunchLock(); try { - await this.createWindowSWA_(); + await this.createWindow_(); } catch (error) { console.error(error); } finally { @@ -110,7 +74,7 @@ * @return {Promise} Resolved when the new window is opened. * @private */ - async createWindowSWA_() { + async createWindow_() { const url = this.appState_.currentDirectoryURL || ''; const result = await openWindow({ currentDirectoryURL: url, @@ -122,26 +86,3 @@ } } } - -/** - * Key for getting and storing the last window state (maximized or not). - * @const - * @private - */ -AppWindowWrapper.MAXIMIZED_KEY_ = 'isMaximized'; - -/** - * Make a key of window geometry preferences for the given initial URL. - * @param {string} url Initialize URL that the window has. - * @return {string} Key of window geometry preferences. - */ -AppWindowWrapper.makeGeometryKey = url => { - return 'windowGeometry:' + url; -}; - -/** - * Shift distance to avoid overlapping windows. - * @type {number} - * @const - */ -AppWindowWrapper.SHIFT_DISTANCE = 40;
diff --git a/ui/file_manager/file_manager/background/js/app_windows.js b/ui/file_manager/file_manager/background/js/app_windows.js deleted file mode 100644 index ad53c66b..0000000 --- a/ui/file_manager/file_manager/background/js/app_windows.js +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * Map of all currently open file dialogs. The key is an app ID. - * @type {!Object<!chrome.app.window.AppWindow>} - */ -window.appWindows = window.appWindows || {}; - -/** - * Gets similar windows, it means with the same initial url. - * @param {string} url URL that the obtained windows have. - * @return {Array<chrome.app.window.AppWindow>} List of similar windows. - */ -window.getSimilarWindows = url => { - const result = []; - for (const appID in window.appWindows) { - if (window.appWindows[appID].contentWindow.appInitialURL === url) { - result.push(window.appWindows[appID]); - } - } - return result; -};
diff --git a/ui/file_manager/file_manager/background/js/file_manager_base.js b/ui/file_manager/file_manager/background/js/file_manager_base.js index a7d2b5e..6933834 100644 --- a/ui/file_manager/file_manager/background/js/file_manager_base.js +++ b/ui/file_manager/file_manager/background/js/file_manager_base.js
@@ -23,13 +23,10 @@ import {FileOperationHandler} from './file_operation_handler.js'; import {FileOperationManagerImpl} from './file_operation_manager.js'; import {fileOperationUtil} from './file_operation_util.js'; -import {FILES_ID_PATTERN, launcher, LaunchType, nextFileManagerWindowID} from './launcher.js'; +import {launcher} from './launcher.js'; import {ProgressCenterImpl} from './progress_center.js'; import {volumeManagerFactory} from './volume_manager_factory.js'; -/** @typedef {function(!Array<string>):!Promise} */ -let LaunchHandler; - /** * Root class of the former background page. * @implements {FileManagerBaseInterface} @@ -59,11 +56,6 @@ }); }); - /** @private {?LaunchHandler} */ - this.launchHandler_ = null; - - this.setLaunchHandler(this.launch_); - /** * Progress center of the background page. * @type {!ProgressCenter} @@ -131,14 +123,6 @@ } /** - * Set a handler which is called when an app is launched. - * @param {!LaunchHandler} handler Function to be called. - */ - setLaunchHandler(handler) { - this.launchHandler_ = handler; - } - - /** * Register callback to be invoked after initialization. * If the initialization is already done, the callback is invoked immediately. * @@ -176,8 +160,7 @@ * Launches a new File Manager window. * * @param {!FilesAppState=} appState App state. - * @return {!Promise<chrome.app.window.AppWindow|string>} Resolved with the - * App ID. + * @return {!Promise<void>} Resolved when the new window is opened. */ async launchFileManager(appState = {}) { return launcher.launchFileManager(appState); @@ -313,8 +296,7 @@ */ directory => { launcher.launchFileManager( - {currentDirectoryURL: directory.toURL()}, - /* App ID */ undefined, LaunchType.FOCUS_SAME_OR_CREATE); + {currentDirectoryURL: directory.toURL()}); }); } @@ -339,61 +321,6 @@ } /** - * Launches the app. - * @private - * @param {!Array<string>|undefined} urls - */ - launch_(urls) { - return this.initializationPromise_.then(() => { - if (nextFileManagerWindowID == 0) { - // The app just launched. Remove unneeded window state records. - xfm.storage.local.get(null, items => { - for (const key in items) { - if (items.hasOwnProperty(key)) { - if (key.match(FILES_ID_PATTERN)) { - xfm.storage.local.remove(key); - } - } - } - }); - } - const appState = {}; - let launchType = LaunchType.FOCUS_ANY_OR_CREATE; - if (urls) { - appState.selectionURL = urls[0]; - launchType = LaunchType.FOCUS_SAME_OR_CREATE; - } - launcher.launchFileManager(appState, undefined, launchType).then(() => { - metrics.recordInterval('Load.BackgroundLaunch'); - }); - }); - } - - /** - * Looks for a focused window. - * - * @return {!Promise<?string>} Promise fulfilled with a key of the focused - * window, or null if not found. - * @private - */ - findFocusedWindow_() { - return new Promise((fulfill, reject) => { - for (const key in window.appWindows) { - try { - if (window.appWindows[key].contentWindow.isFocused()) { - fulfill(key); - return; - } - } catch (ignore) { - // The isFocused method may not be defined during initialization. - // Therefore, wrapped with a try-catch block. - } - } - fulfill(null); - }); - } - - /** * Handles mounted FSP volumes and fires the Files app. This is a quick fix * for crbug.com/456648. * @param {!Object} event Event details. @@ -410,23 +337,15 @@ * @private */ onMountCompletedInternal_(event) { - // If there is no focused window, then create a new one opened on the - // mounted volume. - this.findFocusedWindow_() - .then(key => { - const statusOK = event.status === 'success' || - event.status === 'error_path_already_mounted'; - const volumeTypeOK = event.volumeMetadata.volumeType === - VolumeManagerCommon.VolumeType.PROVIDED && - event.volumeMetadata.source === VolumeManagerCommon.Source.FILE; - if (key === null && event.eventType === 'mount' && statusOK && - event.volumeMetadata.mountContext === 'user' && volumeTypeOK) { - this.navigateToVolumeWhenReady_(event.volumeMetadata.volumeId); - } - }) - .catch(error => { - console.warn(error.stack || error); - }); + const statusOK = event.status === 'success' || + event.status === 'error_path_already_mounted'; + const volumeTypeOK = event.volumeMetadata.volumeType === + VolumeManagerCommon.VolumeType.PROVIDED && + event.volumeMetadata.source === VolumeManagerCommon.Source.FILE; + if (event.eventType === 'mount' && statusOK && + event.volumeMetadata.mountContext === 'user' && volumeTypeOK) { + this.navigateToVolumeWhenReady_(event.volumeMetadata.volumeId); + } } }
diff --git a/ui/file_manager/file_manager/background/js/launcher.js b/ui/file_manager/file_manager/background/js/launcher.js index 64315c0a..3eeb444 100644 --- a/ui/file_manager/file_manager/background/js/launcher.js +++ b/ui/file_manager/file_manager/background/js/launcher.js
@@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {getFrameColor} from '../../common/js/api.js'; import {FilesAppState} from '../../common/js/files_app_state.js'; import {util} from '../../common/js/util.js'; @@ -15,46 +14,12 @@ const launcher = {}; /** - * Type of a Files app's instance launch. - * @enum {number} - */ -export const LaunchType = { - ALWAYS_CREATE: 0, - FOCUS_ANY_OR_CREATE: 1, - FOCUS_SAME_OR_CREATE: 2, -}; - -/** * Prefix for the file manager window ID. * @const {string} */ const FILES_ID_PREFIX = 'files#'; /** - * Value of the next file manager window ID. - * @type {number} - */ -export let nextFileManagerWindowID = 0; - -/** - * File manager window create options. - * @const {!Object} - */ -const FILE_MANAGER_WINDOW_CREATE_OPTIONS = { - bounds: { - left: Math.round(window.screen.availWidth * 0.1), - top: Math.round(window.screen.availHeight * 0.1), - // We choose 1000px as default window width to fit 4 columns in grid view, - // as long as the width doesn't exceed 80% of the screen width. - width: Math.min(Math.round(window.screen.availWidth * 0.8), 1000), - height: Math.min(Math.round(window.screen.availHeight * 0.8), 600), - }, - frame: {color: '#ffffff'}, - minWidth: 480, - minHeight: 300, -}; - -/** * Regexp matching a file manager window ID. * @const {!RegExp} */ @@ -74,14 +39,9 @@ /** * @param {!FilesAppState=} appState App state. * @param {number=} id Window id. - * @param {!LaunchType=} type Launch type. Default: ALWAYS_CREATE. - * @return {!Promise<chrome.app.window.AppWindow|string>} Resolved with the App - * ID. + * @return {!Promise<void>} Resolved when the window is launched. */ -launcher.launchFileManager = async ( - appState = undefined, id = undefined, type = LaunchType.ALWAYS_CREATE) => { - type = type || LaunchType.ALWAYS_CREATE; - +launcher.launchFileManager = async (appState = undefined, id = undefined) => { // Serialize concurrent calls to launchFileManager. if (!launcher.initializationPromise_) { throw new Error('Missing launcher.initializationPromise'); @@ -89,25 +49,9 @@ await launcher.initializationPromise_; - // Create a new instance in case of ALWAYS_CREATE type, or as a fallback - // for other types. - id = id || nextFileManagerWindowID; - nextFileManagerWindowID = Math.max(nextFileManagerWindowID, id + 1); - const appId = FILES_ID_PREFIX + id; - - const windowCreateOptions = FILE_MANAGER_WINDOW_CREATE_OPTIONS; - windowCreateOptions.frame.color = await getFrameColor(); - - const appWindow = - new AppWindowWrapper('main.html', appId, windowCreateOptions); + const appWindow = new AppWindowWrapper('main.html'); await appWindow.launch(appState || {}, false); - if (!appWindow.rawAppWindow) { - return null; - } - - appWindow.rawAppWindow.focus(); - return appId; }; export {launcher};
diff --git a/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js b/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js index 676f596..cd4bbe7 100644 --- a/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js +++ b/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js
@@ -122,56 +122,11 @@ } /** - * Obtains window information. - * - * @return {Object<{innerWidth:number, innerHeight:number}>} Map window - * ID and window information. - */ -test.util.sync.getWindows = () => { - const windows = {}; - for (const id in window.appWindows) { - const windowWrapper = window.appWindows[id]; - windows[id] = { - outerWidth: windowWrapper.contentWindow.outerWidth, - outerHeight: windowWrapper.contentWindow.outerHeight, - }; - } - for (const id in window.background.dialogs) { - windows[id] = { - outerWidth: window.background.dialogs[id].outerWidth, - outerHeight: window.background.dialogs[id].outerHeight, - }; - } - return windows; -}; - -/** - * Closes the specified window. - * - * @param {string} appId AppId of window to be closed. - * @return {boolean} Result: True if success, false otherwise. - */ -test.util.sync.closeWindow = appId => { - if (appId in window.appWindows && window.appWindows[appId].contentWindow) { - window.appWindows[appId].close(); - return true; - } - return false; -}; - -/** * Gets total Javascript error count from background page and each app window. * @return {number} Error count. */ test.util.sync.getErrorCount = () => { - let totalCount = window.JSErrorCount; - for (const appId in window.appWindows) { - const contentWindow = window.appWindows[appId].contentWindow; - if (contentWindow.JSErrorCount) { - totalCount += contentWindow.JSErrorCount; - } - } - return totalCount; + return window.JSErrorCount; }; /** @@ -285,31 +240,6 @@ }; /** - * Executes a script in the context of the first <webview> element contained in - * the window, including shadow DOM subtrees if given, and returns the script - * result via the callback. - * - * @param {Window} contentWindow Window to be tested. - * @param {!Array<string>} targetQuery Query for the <webview> element. - * |targetQuery[0]| specifies the first element. |targetQuery[1]| specifies - * an element inside the shadow DOM of the first element, etc. The last - * targetQuery item must return the <webview> element. - * @param {string} script Javascript code to be executed within the <webview>. - * @param {function(*)} callback Callback function to be called with the - * result of the |script|. - */ -test.util.async.deepExecuteScriptInWebView = - (contentWindow, targetQuery, script, callback) => { - const webviews = test.util.sync.deepQuerySelectorAll_( - contentWindow.document, targetQuery); - if (!webviews || webviews.length !== 1) { - throw new Error('<webview> not found: [' + targetQuery.join(',') + ']'); - } - const webview = /** @type {WebView} */ (webviews[0]); - webview.executeScript({code: script}, callback); - }; - -/** * Gets the information of the active element. * * @param {Window} contentWindow Window to be tested. @@ -1106,16 +1036,8 @@ if (request.appId) { if (request.contentWindow) { // request.contentWindow is present if this function was called via - // test.swaTestMessageListener, an alternative code path used by the test - // harness to send messages directly to Files SWA. Test code uses - // request.contentWindow only, thus by setting it, we avoid having to - // change the test.utils functions to check for contentWindow || window, - // just to support SWA files app. + // test.swaTestMessageListener. args.unshift(request.contentWindow); - } else if (window.appWindows[request.appId]) { - args.unshift(window.appWindows[request.appId].contentWindow); - } else if (window.background.dialogs[request.appId]) { - args.unshift(window.background.dialogs[request.appId]); } else { console.error('Specified window not found: ' + request.appId); return false;
diff --git a/ui/file_manager/file_manager/common/js/api.js b/ui/file_manager/file_manager/common/js/api.js index 50594c6..1082b76f 100644 --- a/ui/file_manager/file_manager/common/js/api.js +++ b/ui/file_manager/file_manager/common/js/api.js
@@ -140,6 +140,19 @@ } /** + * Retrieves Data Leak Prevention (DLP) restriction details. + * @param {string} sourceUrl Source URL of the file for which to retrieve the + * details. + * @return {!Promise<!Array<!chrome.fileManagerPrivate.DlpRestrictionDetails>>} + * list of DlpRestrictionDetails containing summarized restriction + * information about the file. + */ +export async function getDlpRestrictionDetails(sourceUrl) { + return promisify( + chrome.fileManagerPrivate.getDlpRestrictionDetails, sourceUrl); +} + +/** * Lists Guest OSs which support having their files mounted. * @return {!Promise<!Array<!chrome.fileManagerPrivate.MountableGuest>>} */ @@ -219,19 +232,6 @@ } /** - * Returns the color to be used by frames of each foreground window. - * @returns {Promise<!string>} - */ -export async function getFrameColor() { - try { - return await promisify(chrome.fileManagerPrivate.getFrameColor); - } catch (e) { - console.error('Failed to get frame color.', e); - return '#ffffff'; - } -} - -/** * Starts an IOTask of `type` and returns a taskId that can be used to cancel * or identify the ongoing IO operation. * @param {!chrome.fileManagerPrivate.IOTaskType} type
diff --git a/ui/file_manager/file_manager/externs/app_window_common.js b/ui/file_manager/file_manager/externs/app_window_common.js index afad4aa..5704a1f 100644 --- a/ui/file_manager/file_manager/externs/app_window_common.js +++ b/ui/file_manager/file_manager/externs/app_window_common.js
@@ -20,18 +20,6 @@ Window.prototype.reload = function() {}; /** - * - * Created by HTML imports polyfill. - * @type {!Object} - */ -Window.prototype.HTMLImports; - -/** - * @type {function(function())} - */ -Window.prototype.HTMLImports.whenReady; - -/** * True if in test: set by ash/webui/file_manager/resources/init_globals.js. * * @type {boolean}
diff --git a/ui/file_manager/file_manager/externs/background/file_manager_base.js b/ui/file_manager/file_manager/externs/background/file_manager_base.js index b427478..8b18060 100644 --- a/ui/file_manager/file_manager/externs/background/file_manager_base.js +++ b/ui/file_manager/file_manager/externs/background/file_manager_base.js
@@ -10,9 +10,6 @@ import {FileOperationManager} from './file_operation_manager.js'; import {ProgressCenter} from './progress_center.js'; -/** @typedef {function(!Array<string>):!Promise} */ -export let LaunchHandler; - /** * @interface */ @@ -48,12 +45,6 @@ this.crostini; } - /** - * Set a handler which is called when an app is launched. - * @param {!LaunchHandler} handler Function to be called. - */ - setLaunchHandler(handler) {} - /** @return {!Promise<!VolumeManager>} */ getVolumeManager() {} @@ -84,8 +75,7 @@ * Launches a new File Manager window. * * @param {!FilesAppState=} appState App state. - * @return {!Promise<chrome.app.window.AppWindow|string>} Resolved with the - * App ID. + * @return {!Promise<void>} Resolved when the new window is opened. */ async launchFileManager(appState = {}) {} }
diff --git a/ui/file_manager/file_manager/externs/chrome_file_browser_handler.js b/ui/file_manager/file_manager/externs/chrome_file_browser_handler.js deleted file mode 100644 index 393f2a7..0000000 --- a/ui/file_manager/file_manager/externs/chrome_file_browser_handler.js +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @typedef {{ - * entries: Array, - * tab_id: (number|undefined) - * }} - * @see https://developer.chrome.com/extensions/fileBrowserHandler#type-FileHandlerExecuteEventDetails - */ -let FileHandlerExecuteEventDetails; - -/** - * @namespace - */ -chrome.fileBrowserHandler = {}; - -/** - * @param {!Object} selectionParams - * @param {Function} callback - * @see https://developer.chrome.com/extensions/fileBrowserHandler#method-selectFile - */ -chrome.fileBrowserHandler.selectFile = function(selectionParams, callback) {}; - -/** @type {!ChromeEvent} */ -chrome.fileBrowserHandler.onExecute;
diff --git a/ui/file_manager/file_manager/externs/html_menu_item_element.js b/ui/file_manager/file_manager/externs/html_menu_item_element.js deleted file mode 100644 index 72782c43..0000000 --- a/ui/file_manager/file_manager/externs/html_menu_item_element.js +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem - */ -class HTMLMenuItemElement extends HTMLElement { - constructor() { - /** - * @type {string} - * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem#attr-type - */ - this.type; - - /** - * @type {string} - * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem#attr-label - */ - this.label; - - /** - * @type {string} - * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem#attr-icon - */ - this.icon; - - /** - * @type {boolean} - * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem#attr-disabled - */ - this.disabled; - - /** - * @type {boolean} - * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem#attr-checked - */ - this.checked; - - /** - * @type {string} - * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem#attr-radiogroup - */ - this.radiogroup; - - /** - * @type {boolean} - * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem#attr-default - */ - this.default; - - /** - * @type {HTMLElement|undefined} - * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem#attr-command - */ - this.command; - } -}
diff --git a/ui/file_manager/file_manager/externs/menu_item_update_event.js b/ui/file_manager/file_manager/externs/menu_item_update_event.js deleted file mode 100644 index 0504cae..0000000 --- a/ui/file_manager/file_manager/externs/menu_item_update_event.js +++ /dev/null
@@ -1,12 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -class MenuItemUpdateEvent extends Event { - constructor() { - /** - * @type {!cr.ui.MenuButton} - */ - this.menuButton; - } -}
diff --git a/ui/file_manager/file_manager/externs/platform_worker.js b/ui/file_manager/file_manager/externs/platform_worker.js deleted file mode 100644 index 54ed8fc..0000000 --- a/ui/file_manager/file_manager/externs/platform_worker.js +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Externs which are common for all worker of chrome packaged apps. - -/** - * @param {string} url - * @param {function(!Entry)} successCallback - * @param {function(!FileError)=} opt_errorCallback - */ -function webkitResolveLocalFileSystemURL( - url, successCallback, opt_errorCallback) {}
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js index bbc93eb..34ae74d8 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -6,10 +6,8 @@ import 'chrome://resources/cr_elements/cr_input/cr_input.js'; import {assert} from 'chrome://resources/js/assert.m.js'; -import {Command} from './ui/command.js'; -import {contextMenuHandler} from './ui/context_menu_handler.js'; -import {getHoldingSpaceState, startIOTask} from '../../common/js/api.js'; +import {getDlpRestrictionDetails, getHoldingSpaceState, startIOTask} from '../../common/js/api.js'; import {DialogType} from '../../common/js/dialog_type.js'; import {FileOperationProgressEvent} from '../../common/js/file_operation_common.js'; import {FileType} from '../../common/js/file_type.js'; @@ -23,6 +21,7 @@ import {FakeEntry, FilesAppDirEntry, FilesAppEntry} from '../../externs/files_app_entry_interfaces.js'; import {VolumeInfo} from '../../externs/volume_info.js'; import {VolumeManager} from '../../externs/volume_manager.js'; +import {XfDlpRestrictionDetailsDialog} from '../../widgets/xf_dlp_restriction_details_dialog.js'; import {ActionsModel} from './actions_model.js'; import {constants} from './constants.js'; @@ -31,6 +30,8 @@ import {FileTasks} from './file_tasks.js'; import {HoldingSpaceUtil} from './holding_space_util.js'; import {PathComponent} from './path_component.js'; +import {Command} from './ui/command.js'; +import {contextMenuHandler} from './ui/context_menu_handler.js'; import {DirectoryItem, DirectoryTree} from './ui/directory_tree.js'; import {FilesConfirmDialog} from './ui/files_confirm_dialog.js'; import {List} from './ui/list.js'; @@ -1974,16 +1975,27 @@ */ CommandHandler.COMMANDS_['dlp-restriction-details'] = new (class extends FilesCommand { - execute(event, fileManager) { + async executeImpl_(event, fileManager) { const entries = fileManager.getSelection().entries; const metadata = fileManager.metadataModel.getCache(entries, ['sourceUrl']); - if (!metadata || metadata.length !== 1) { + if (!metadata || metadata.length !== 1 || !metadata[0].sourceUrl) { return; } - // TODO(crbug.com/1346254): Get the details and show the modal with the - // returned information. + + const sourceUrl = /** @type {!string} */ (metadata[0].sourceUrl); + try { + const details = await getDlpRestrictionDetails(sourceUrl); + fileManager.ui.dlpRestrictionDetailsDialog + .showDlpRestrictionDetailsDialog(details); + } catch (e) { + console.warn(`Error showing DLP restriction details `, e); + } + } + + execute(event, fileManager) { + this.executeImpl_(event, fileManager); } /** @override */
diff --git a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn index 368c2465..80c5053 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn +++ b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
@@ -505,8 +505,6 @@ ] } -# TODO(tapted): Move this into //ui/file_manager/base. - js_library("files_alert_dialog") { deps = [ ":dialogs", @@ -514,8 +512,6 @@ ] } -# TODO(tapted): Move this into //ui/file_manager/base. - js_library("files_confirm_dialog") { deps = [ ":dialogs",
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js index e955385..9d8fc6a 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -4,15 +4,13 @@ import {assertInstanceof} from 'chrome://resources/js/assert.m.js'; import {decorate, define as crUiDefine} from 'chrome://resources/js/cr/ui.js'; -import {contextMenuHandler} from './context_menu_handler.js'; -import {Menu} from './menu.js'; -import {MenuItem} from './menu_item.js'; import {DialogType} from '../../../common/js/dialog_type.js'; import {str, strf, util} from '../../../common/js/util.js'; import {AllowedPaths} from '../../../common/js/volume_manager_types.js'; import {BreadcrumbContainer} from '../../../containers/breadcrumb_container.js'; import {VolumeManager} from '../../../externs/volume_manager.js'; +import {XfDlpRestrictionDetailsDialog} from '../../../widgets/xf_dlp_restriction_details_dialog.js'; import {FilesPasswordDialog} from '../../elements/files_password_dialog.js'; import {FilesToast} from '../../elements/files_toast.js'; import {FilesTooltip} from '../../elements/files_tooltip.js'; @@ -24,6 +22,7 @@ import {ActionModelUI} from './action_model_ui.js'; import {ActionsSubmenu} from './actions_submenu.js'; import {ComboButton} from './combobutton.js'; +import {contextMenuHandler} from './context_menu_handler.js'; import {DefaultTaskDialog} from './default_task_dialog.js'; import {DialogFooter} from './dialog_footer.js'; import {BaseDialog} from './dialogs.js'; @@ -37,6 +36,8 @@ import {ImportCrostiniImageDialog} from './import_crostini_image_dialog.js'; import {InstallLinuxPackageDialog} from './install_linux_package_dialog.js'; import {ListContainer} from './list_container.js'; +import {Menu} from './menu.js'; +import {MenuItem} from './menu_item.js'; import {MultiMenu} from './multi_menu.js'; import {MultiMenuButton} from './multi_menu_button.js'; import {ProgressCenterPanel} from './progress_center_panel.js'; @@ -150,6 +151,12 @@ this.passwordDialog_ = null; /** + * Dialog for DLP (Data Leak Prevention) restriction details. + * @type {?XfDlpRestrictionDetailsDialog} + */ + this.dlpRestrictionDetailsDialog_ = null; + + /** * The container element of the dialog. * @type {!HTMLElement} */ @@ -437,6 +444,24 @@ } /** + * Gets the DlpRestrictionDetails dialog. + * @return {?XfDlpRestrictionDetailsDialog} + */ + get dlpRestrictionDetailsDialog() { + if (!util.isDlpEnabled()) { + return null; + } + if (this.dlpRestrictionDetailsDialog_) { + return this.dlpRestrictionDetailsDialog_; + } + this.dlpRestrictionDetailsDialog_ = + /** @type {!XfDlpRestrictionDetailsDialog} */ ( + document.createElement('xf-dlp-restriction-details-dialog')); + this.element.appendChild(this.dlpRestrictionDetailsDialog_); + return this.dlpRestrictionDetailsDialog_; + } + + /** * Initializes here elements, which are expensive or hidden in the beginning. * * @param {!FileTable} table
diff --git a/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog.html b/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog.html new file mode 100644 index 0000000..28633e9 --- /dev/null +++ b/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog.html
@@ -0,0 +1,75 @@ +<style include="cr-shared-style"> + [slot='title'] { + --cr-primary-text-color: var(--cros-text-color-primary); + } + + [slot='body'] > div { + --cr-secondary-text-color: var(--cros-text-color-secondary); + margin-bottom: var(--cr-form-field-bottom-spacing); + } + + cr-dialog::part(dialog) { + background-color: var(--cros-bg-color-elevation-3); + border-radius: 12px; + box-shadow: var(--cros-elevation-3-shadow); + width: 512px; + } + + cr-dialog::part(dialog) { + max-height: 480px; + } + + cr-dialog::part(dialog)::backdrop { + background-color: var(--cros-app-shield-60); + } + + cr-dialog::part(wrapper) { + /* subtract the internal padding in <cr-dialog> */ + padding: calc(24px - 20px); + } +</style> + +<cr-dialog id="dialog" + consume-keydown-event show-close-button> + <div slot="title"> + Restriction details + </div> + <div slot="body"> + <div id="message" cr-dialog-text></div> + <div id="details-container"> + <span id="block-details" hidden=true> + <label>Administrator policy prevents:</label> + <ul id="block-list"> + <li id="block-li-urls" hidden=true> + <label id="block-urls"></label> + </li> + <li id="block-li-components" hidden=true> + <label id="block-components"></label> + </li> + </ul> + </span> + <span id="warn-details" hidden=true> + <label>Administrator policy doesn't recommend:</label> + <ul id="warn-list"> + <li id="warn-li-urls" hidden=true> + <label id="warn-urls"></label> + </li> + <li id="warn-li-components" hidden=true> + <label id="warn-components"></label> + </li> + </ul> + </span> + <span id="report-details" hidden=true> + <label>Administrator monitors:</label> + <ul id="report-list"> + <li id="report-li-urls" hidden=true> + <label id="report-urls"></label> + </li> + <li id="report-li-components" hidden=true> + <label id="report-components"></label> + </li> + </ul> + </span> + </div> + </div> +</cr-dialog>
diff --git a/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog.ts b/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog.ts new file mode 100644 index 0000000..9a259fe5 --- /dev/null +++ b/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog.ts
@@ -0,0 +1,200 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; + +import {getTemplate} from './xf_dlp_restriction_details_dialog.html.js'; + +/** + * Dialog to show Data Leak Prevention (DLP) restriction details about a file. + */ +export class XfDlpRestrictionDetailsDialog extends HTMLElement { + // TODO(crbug.com/1351739): Add translation strings instead of hardcoded + // values. + private dialog: CrDialogElement; + private messageContainer: HTMLDivElement; + private details: chrome.fileManagerPrivate.DlpRestrictionDetails[] = []; + + constructor() { + super(); + + // Create element content. + const template = document.createElement('template'); + template.innerHTML = getTemplate() as unknown as string; + const fragment = template.content.cloneNode(true); + this.attachShadow({mode: 'open'}).appendChild(fragment); + + this.dialog = this.shadowRoot!.querySelector('#dialog')! as CrDialogElement; + this.messageContainer = + this.shadowRoot?.querySelector('#message')! as HTMLDivElement; + } + + /** + * Shows the dialog. + * @param details DLP restriction details. Should not be empty and should + * contain at most one element per level (only the first one will be + * used). + */ + showDlpRestrictionDetailsDialog( + details: chrome.fileManagerPrivate.DlpRestrictionDetails[]) { + if (details.length === 0) { + console.error(`No DLP restriction details to display.`); + return; + } + this.details = details; + // Add the general text. + const message = 'This file is confidential and subject to restrictions ' + + 'by administrator policy. The following file access and ' + + 'transfer actions are enforced.'; + this.messageContainer.innerHTML = message; + // Add a section for each restriction level. + this.showDetailsForLevel(chrome.fileManagerPrivate.DlpLevel.BLOCK); + this.showDetailsForLevel(chrome.fileManagerPrivate.DlpLevel.WARN); + this.showDetailsForLevel(chrome.fileManagerPrivate.DlpLevel.REPORT); + + this.dialog.showModal(); + } + + /** + * Renders restriction details for the given level. + * @param level DLP level. Must be one of BLOCK, WARN, REPORT. + */ + private showDetailsForLevel(level: chrome.fileManagerPrivate.DlpLevel) { + if (level === chrome.fileManagerPrivate.DlpLevel.ALLOW) { + console.warn('Should not be called for ALLOW.'); + return; + } + + const details = this.details.find((d) => d.level === level); + const detailsContainer: HTMLSpanElement = + this.shadowRoot?.querySelector(`#${level}-details`)! as HTMLSpanElement; + if (!details || + (details.urls.length === 0 && details.components.length === 0)) { + detailsContainer.toggleAttribute('hidden', true); + return; + } + detailsContainer.toggleAttribute('hidden', false); + this.showUrlsForLevel(details.urls, level); + this.showComponentsForLevel(details.components, level); + } + + /** + * If `urls` is not empty, creates a formatted string with the restricted + * destination URLs and shows it in the label designated for `level`. If + * `urls` is empty, hides the corresponding element in the dialog. Expects + * that `level` is one of BLOCK, WARN, REPORT. + * + * If the restricted list includes a wildcard, then instead of a list "all + * urls" is used. In that case, if there's a level with higher priority than + * the one being rendered, "all urls except..." is used. + * + * @param urls List of restricted URLs. + * @param level DLP level. Must be one of BLOCK, WARN, REPORT. + */ + private showUrlsForLevel( + urls: string[], level: chrome.fileManagerPrivate.DlpLevel) { + if (level === chrome.fileManagerPrivate.DlpLevel.ALLOW) { + console.warn('Should not be called for ALLOW.'); + return; + } + + const urlsListItem = + this.shadowRoot?.querySelector(`#${level}-li-urls`)! as HTMLLIElement; + if (urls.length === 0) { + urlsListItem.toggleAttribute('hidden', true); + return; + } + urlsListItem.toggleAttribute('hidden', false); + + const urlsLabel = + this.shadowRoot?.querySelector(`#${level}-urls`)! as HTMLLabelElement; + + const wildcardIdx = urls.indexOf('*'); + if (wildcardIdx !== -1) { + const excludedUrls = []; + // Append "except" all higher levels. + const higherLevels = this.getHigherLevels(level); + for (const level of higherLevels) { + const exceptDetails = this.details.find((d) => d.level === level); + if (exceptDetails && exceptDetails.urls.length > 0) { + excludedUrls.push(exceptDetails.urls); + } + } + if (excludedUrls.length === 0) { + urlsLabel.textContent = 'File access by all urls'; + } else { + urlsLabel.textContent = + 'File access by all urls except ' + excludedUrls.join(', '); + } + } else { + urlsLabel.textContent = 'File access by ' + urls.join(', '); + } + } + + /** + * @param level Level to be checked. + * @returns List of levels, if any, with higher priority. + */ + private getHigherLevels(level: chrome.fileManagerPrivate.DlpLevel): + chrome.fileManagerPrivate.DlpLevel[] { + switch (level) { + case chrome.fileManagerPrivate.DlpLevel.BLOCK: + return [chrome.fileManagerPrivate.DlpLevel.ALLOW]; + case chrome.fileManagerPrivate.DlpLevel.WARN: + return [ + chrome.fileManagerPrivate.DlpLevel.ALLOW, + chrome.fileManagerPrivate.DlpLevel.BLOCK, + ]; + case chrome.fileManagerPrivate.DlpLevel.REPORT: + return [ + chrome.fileManagerPrivate.DlpLevel.ALLOW, + chrome.fileManagerPrivate.DlpLevel.BLOCK, + chrome.fileManagerPrivate.DlpLevel.WARN, + ]; + case chrome.fileManagerPrivate.DlpLevel.ALLOW: + default: + return []; + } + } + + /** + * If `components` is not empty, creates a formatted string with the + * restricted components and shows it in the label designated for `level`. If + * `components` is empty, hides the corresponding element in the dialog. + * Expects that `level` is one of BLOCK, WARN, REPORT. + * + * @param components List of restricted components. + * @param level DLP level. Must be one of BLOCK, WARN, REPORT. + */ + private showComponentsForLevel( + components: string[], level: chrome.fileManagerPrivate.DlpLevel) { + if (level === chrome.fileManagerPrivate.DlpLevel.ALLOW) { + console.warn('Should not be called for ALLOW.'); + return; + } + + const componentsListItem: HTMLLIElement = + this.shadowRoot?.querySelector(`#${level}-li-components`)! as + HTMLLIElement; + if (components.length === 0) { + componentsListItem.toggleAttribute('hidden', true); + return; + } + componentsListItem.toggleAttribute('hidden', false); + + const componentsLabel: HTMLLabelElement = + this.shadowRoot?.querySelector(`#${level}-components`)! as + HTMLLabelElement; + componentsLabel.textContent = 'File transfer to ' + components.join(', '); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'xf-dlp-restriction-details-dialog': XfDlpRestrictionDetailsDialog; + } +} + +window.customElements.define( + 'xf-dlp-restriction-details-dialog', XfDlpRestrictionDetailsDialog);
diff --git a/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog_unittest.ts b/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog_unittest.ts new file mode 100644 index 0000000..b04a5d8a --- /dev/null +++ b/ui/file_manager/file_manager/widgets/xf_dlp_restriction_details_dialog_unittest.ts
@@ -0,0 +1,335 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import './xf_dlp_restriction_details_dialog.js'; + +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; + +import {installMockChrome} from '../common/js/mock_chrome.js'; + +import {XfDlpRestrictionDetailsDialog} from './xf_dlp_restriction_details_dialog.js'; + +/** + * Creates new <xf-dlp-restriction-details-dialog> element for each test. + */ +export function setUp() { + document.body.innerHTML = '<xf-dlp-restriction-details-dialog>' + + '</xf-dlp-restriction-details-dialog>'; + + const mockChrome = { + fileManagerPrivate: { + DlpLevel: + {BLOCK: 'block', WARN: 'warn', REPORT: 'report', ALLOW: 'allow'}, + }, + runtime: {}, + }; + installMockChrome(mockChrome); +} + +/** Returns the <xf-dlp-restriction-details-dialog> element. */ +function getDialog(): XfDlpRestrictionDetailsDialog { + const dialog = document.querySelector('xf-dlp-restriction-details-dialog')!; + assertNotEquals(dialog, null); + assertNotEquals('none', window.getComputedStyle(dialog).display); + assertFalse(dialog.hasAttribute('hidden')); + return dialog; +} + +/** Returns the block details span element of the dialog. */ +function getBlockDetails(): HTMLSpanElement { + const details = getDialog().shadowRoot!.querySelector('#block-details')! as + HTMLSpanElement; + assertNotEquals(details, null); + return details; +} + +/** Returns the warn details span element of the dialog. */ +function getWarnDetails(): HTMLSpanElement { + const details = getDialog().shadowRoot!.querySelector('#warn-details')! as + HTMLSpanElement; + assertNotEquals(details, null); + return details; +} + +/** Returns the report details span element of the dialog. */ +function getReportDetails(): HTMLSpanElement { + const details = getDialog().shadowRoot!.querySelector('#report-details')! as + HTMLSpanElement; + assertNotEquals(details, null); + return details; +} + +/** + * Checks that the surronding list element for `level` is not hidden and returns + * the `destinations` label of the dialog. + * @level DLP level used to get the right elements. One of 'block', 'warn', + * 'report'. + * @destinations One of 'urls' or 'components'. + */ +function getDestinationsLabelForLevel( + level: string, destinations: string): HTMLLabelElement { + assertFalse( + getDialog().shadowRoot!.querySelector(`#${level}-li-${ + destinations}`)!.hasAttribute('hidden')); + return getDialog().shadowRoot!.querySelector(`#${level}-${destinations}`)! as + HTMLLabelElement; +} + +/** + * Checks that the "block-li-urls" element is not hidden and returns the + * corresponding "block-urls" label of the dialog. + */ +function getBlockUrls() { + return getDestinationsLabelForLevel('block', 'urls'); +} + +/** + * Checks that the "warn-li-urls" element is not hidden and returns the + * corresponding "warn-urls" label of the dialog. + */ +function getWarnUrls() { + return getDestinationsLabelForLevel('warn', 'urls'); +} + +/** + * Checks that the "report-li-urls" element is not hidden and returns the + * corresponding "report-urls" label of the dialog. + */ +function getReportUrls() { + return getDestinationsLabelForLevel('report', 'urls'); +} + +/** + * Checks that the "block-li-components" element is not hidden and returns the + * corresponding "block-components" label of the dialog. + */ +function getBlockComponents() { + return getDestinationsLabelForLevel('block', 'components'); +} + +/** + * Checks that the "warn-li-components" element is not hidden and returns the + * corresponding "warn-components" label of the dialog. + */ +function getWarnComponents() { + return getDestinationsLabelForLevel('warn', 'components'); +} + +/** + * Checks that the "report-li-components" element is not hidden and returns the + * corresponding "report-components" label of the dialog. + */ +function getReportComponents() { + return getDestinationsLabelForLevel('report', 'components'); +} + +/** Closes the dialog. */ +function close() { + const crDialog = + getDialog().shadowRoot!.querySelector('#dialog') as CrDialogElement; + crDialog.close(); +} + +/** + * Tests that only the URL section for the block section is shown. + */ +export async function testBlockUrls(done: () => void) { + const dialog = getDialog(); + const blockDetails = getBlockDetails(); + assertTrue(blockDetails.hasAttribute('hidden')); + + const details: chrome.fileManagerPrivate.DlpRestrictionDetails[] = [{ + level: chrome.fileManagerPrivate.DlpLevel.BLOCK, + urls: ['https://external.com', 'https://example.com'], + components: [], + }]; + dialog.showDlpRestrictionDetailsDialog(details); + assertFalse(blockDetails.hasAttribute('hidden')); + assertFalse( + blockDetails.querySelector('#block-li-urls')!.hasAttribute('hidden')); + assertEquals( + blockDetails.querySelector('#block-urls')!.textContent, + 'File access by https://external.com, https://example.com'); + // Components should still be hidden. + assertTrue(blockDetails.querySelector('#block-li-components')!.hasAttribute( + 'hidden')); + + // Other restriction levels should still be hidden. + assertTrue(getWarnDetails().hasAttribute('hidden')); + assertTrue(getReportDetails().hasAttribute('hidden')); + + done(); +} + +/** + * Tests that wildcard is shown as "all urls", any other specific URLs + * listed along the wildcard are ignored, and components are not affected by the + * wildcard. + */ +export async function testBlockAllUrls(done: () => void) { + const dialog = getDialog(); + const blockDetails = getBlockDetails(); + assertTrue(blockDetails.hasAttribute('hidden')); + + const details: chrome.fileManagerPrivate.DlpRestrictionDetails[] = [{ + level: chrome.fileManagerPrivate.DlpLevel.BLOCK, + urls: ['https://external.com', '*'], + components: ['drive'], + }]; + dialog.showDlpRestrictionDetailsDialog(details); + assertFalse(blockDetails.hasAttribute('hidden')); + assertEquals(getBlockUrls().textContent, 'File access by all urls'); + assertEquals(getBlockComponents().textContent, 'File transfer to drive'); + + // Other restriction levels should still be hidden. + assertTrue(getWarnDetails().hasAttribute('hidden')); + assertTrue(getReportDetails().hasAttribute('hidden')); + + done(); +} + +/** + * Tests that wildcard is shown as "all urls except..." if there are some URLs + * with a higher restriction level. + */ +export async function testBlockAllUrlsExcept(done: () => void) { + const dialog = getDialog(); + const blockDetails = getBlockDetails(); + assertTrue(blockDetails.hasAttribute('hidden')); + + const details: chrome.fileManagerPrivate.DlpRestrictionDetails[] = [ + { + level: chrome.fileManagerPrivate.DlpLevel.BLOCK, + urls: ['*'], + components: [], + }, + { + level: chrome.fileManagerPrivate.DlpLevel.ALLOW, + urls: ['https://internal.com'], + components: [], + }, + ]; + dialog.showDlpRestrictionDetailsDialog(details); + assertFalse(blockDetails.hasAttribute('hidden')); + assertEquals( + getBlockUrls().textContent, + 'File access by all urls except https://internal.com'); + // Components should still be hidden. + assertTrue(blockDetails.querySelector('#block-li-components')!.hasAttribute( + 'hidden')); + + // Other restriction levels should still be hidden. + assertTrue(getWarnDetails().hasAttribute('hidden')); + assertTrue(getReportDetails().hasAttribute('hidden')); + + done(); +} + +/** + * Tests that only the components section for the block section is shown. + */ +export async function testBlockComponents(done: () => void) { + const dialog = getDialog(); + const blockDetails = getBlockDetails(); + assertTrue(blockDetails.hasAttribute('hidden')); + + const details: chrome.fileManagerPrivate.DlpRestrictionDetails[] = [{ + level: chrome.fileManagerPrivate.DlpLevel.BLOCK, + urls: [], + components: ['drive', 'removable'], + }]; + dialog.showDlpRestrictionDetailsDialog(details); + assertFalse(blockDetails.hasAttribute('hidden')); + // Urls should still be hidden. + assertTrue( + blockDetails.querySelector('#block-li-urls')!.hasAttribute('hidden')); + assertEquals( + getBlockComponents().textContent, 'File transfer to drive, removable'); + + // Other restriction levels should still be hidden. + assertTrue(getWarnDetails().hasAttribute('hidden')); + assertTrue(getReportDetails().hasAttribute('hidden')); + + done(); +} + +/** + * Tests that showing the dialog multiple times in a row still shows correct + * data. + */ +export async function testMultipleDialogs(done: () => void) { + const dialog = getDialog(); + const blockDetails = getBlockDetails(); + const warnDetails = getWarnDetails(); + const reportDetails = getReportDetails(); + assertTrue(blockDetails.hasAttribute('hidden')); + + + const details1: chrome.fileManagerPrivate.DlpRestrictionDetails[] = [{ + level: chrome.fileManagerPrivate.DlpLevel.BLOCK, + urls: ['https://external.com'], + components: ['drive'], + }]; + dialog.showDlpRestrictionDetailsDialog(details1); + assertFalse(blockDetails.hasAttribute('hidden')); + assertEquals( + getBlockUrls().textContent, 'File access by https://external.com'); + assertEquals(getBlockComponents().textContent, 'File transfer to drive'); + + // Other restriction levels should still be hidden. + assertTrue(warnDetails.hasAttribute('hidden')); + assertTrue(reportDetails.hasAttribute('hidden')); + + close(); + + const details2: chrome.fileManagerPrivate.DlpRestrictionDetails[] = [ + { + level: chrome.fileManagerPrivate.DlpLevel.WARN, + urls: ['https://example.com'], + components: ['drive', 'removable'], + }, + { + level: chrome.fileManagerPrivate.DlpLevel.REPORT, + urls: ['https://external.com'], + components: [], + }, + ]; + dialog.showDlpRestrictionDetailsDialog(details2); + assertFalse(warnDetails.hasAttribute('hidden')); + assertEquals(getWarnUrls().textContent, 'File access by https://example.com'); + assertEquals( + getWarnComponents().textContent, 'File transfer to drive, removable'); + assertFalse(reportDetails.hasAttribute('hidden')); + assertEquals( + getReportUrls().textContent, 'File access by https://external.com'); + assertTrue(reportDetails.querySelector('#report-li-components')!.hasAttribute( + 'hidden')); + + // Block section should now be hidden. + assertTrue(blockDetails.hasAttribute('hidden')); + + close(); + + const details3: chrome.fileManagerPrivate.DlpRestrictionDetails[] = [ + { + level: chrome.fileManagerPrivate.DlpLevel.REPORT, + urls: [], + components: ['drive', 'removable'], + }, + ]; + dialog.showDlpRestrictionDetailsDialog(details3); + // Report urls should now be hidden. + assertFalse(reportDetails.hasAttribute('hidden')); + assertTrue( + reportDetails.querySelector('#report-li-urls')!.hasAttribute('hidden')); + assertEquals( + getReportComponents().textContent, 'File transfer to drive, removable'); + + // Block and warn sections should now be hidden. + assertTrue(blockDetails.hasAttribute('hidden')); + assertTrue(warnDetails.hasAttribute('hidden')); + + done(); +}
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni index 0746c90..d275afa 100644 --- a/ui/file_manager/file_names.gni +++ b/ui/file_manager/file_names.gni
@@ -14,7 +14,6 @@ static_js_files = [ # Background: "file_manager/background/js/app_window_wrapper.js", - "file_manager/background/js/app_windows.js", "file_manager/background/js/crostini.js", "file_manager/background/js/drive_sync_handler.js", "file_manager/background/js/entry_location_impl.js", @@ -259,10 +258,14 @@ "file_manager/state/file_key.ts", "file_manager/widgets/xf_breadcrumb.ts", "file_manager/containers/breadcrumb_container.ts", + "file_manager/widgets/xf_dlp_restriction_details_dialog.ts", ] # HTML template files that are used to generate the ".html.ts" -ts_templates = [ "file_manager/widgets/xf_breadcrumb.html" ] +ts_templates = [ + "file_manager/widgets/xf_breadcrumb.html", + "file_manager/widgets/xf_dlp_restriction_details_dialog.html", +] ts_test_files = [ # Lib: @@ -275,6 +278,7 @@ # Widgets: "file_manager/widgets/xf_breadcrumb_unittest.ts", + "file_manager/widgets/xf_dlp_restriction_details_dialog_unittest.ts", ] ts_generated_templates = []
diff --git a/ui/file_manager/integration_tests/file_manager/drive_specific.js b/ui/file_manager/integration_tests/file_manager/drive_specific.js index 7df0b35b..0972c17 100644 --- a/ui/file_manager/integration_tests/file_manager/drive_specific.js +++ b/ui/file_manager/integration_tests/file_manager/drive_specific.js
@@ -918,9 +918,6 @@ // Open the Enable Docs Offline dialog. await openAndWaitForEnableDocsOfflineDialog(appId); - // Close Files App. - await remoteCall.closeWindowAndWait(appId); - // Check: the last dialog result should be 3 (dismiss). await waitForLastDriveDialogResult('3'); };
diff --git a/ui/file_manager/integration_tests/file_manager/metrics.js b/ui/file_manager/integration_tests/file_manager/metrics.js index 2f5c1dc..b8859748 100644 --- a/ui/file_manager/integration_tests/file_manager/metrics.js +++ b/ui/file_manager/integration_tests/file_manager/metrics.js
@@ -72,7 +72,6 @@ await getHistogramSum('FileBrowser.DirectoryListLoad.my_files.10'); chrome.test.assertTrue( tenFilesSum > 0, 'Load time for 10 files must exceed 0'); - await remoteCall.closeWindowAndWait(appId); // Open Files app on Downloads with 27 files loaded. // Histogram sum is cumulative so given 27 falls outside the buckets (and @@ -85,7 +84,6 @@ chrome.test.assertEq( tenFilesSum, histogramSum, 'Load time for 27 files must equal same load time as previous'); - await remoteCall.closeWindowAndWait(appId); // Open Files app on Downloads with 100 files loaded. // Expect a non-zero load time in the appropriate histogram. @@ -94,7 +92,6 @@ await getHistogramSum('FileBrowser.DirectoryListLoad.my_files.100'); chrome.test.assertTrue( hundredFilesSum > 0, 'Load time for 100 files must exceed 0'); - await remoteCall.closeWindowAndWait(appId); }; // Test that the UpdateAvailableApps UMA is appropriately recorded.
diff --git a/ui/file_manager/integration_tests/file_manager/transfer.js b/ui/file_manager/integration_tests/file_manager/transfer.js index f40aa49..90a7402d7 100644 --- a/ui/file_manager/integration_tests/file_manager/transfer.js +++ b/ui/file_manager/integration_tests/file_manager/transfer.js
@@ -1117,9 +1117,6 @@ const primaryText = panel.attributes['primary-text']; const secondaryText = panel.attributes['secondary-text']; - // Close the Files app window. - await remoteCall.closeWindowAndWait(appId); - // Open a Files app window again. appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS); @@ -1225,9 +1222,6 @@ 'fakeMouseClick', appId, [['#progress-panel', 'xf-panel-item', 'xf-button#secondary-action']])); - // Close the Files app window. - await remoteCall.closeWindowAndWait(appId); - // Open a Files app window again. appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, [entry], []);
diff --git a/ui/file_manager/integration_tests/remote_call.js b/ui/file_manager/integration_tests/remote_call.js index 7ed2310..6e90df3 100644 --- a/ui/file_manager/integration_tests/remote_call.js +++ b/ui/file_manager/integration_tests/remote_call.js
@@ -152,36 +152,6 @@ } /** - * Closes a window and waits until the window is closed. - * - * @param {string} appId App window Id. - * @return {Promise} promise Promise to be fulfilled with the result (true: - * success, false: failed). - */ - async closeWindowAndWait(appId) { - const caller = getCaller(); - - // Closes the window. - if (!await this.callRemoteTestUtil('closeWindow', null, [appId])) { - // Returns false when the closing is failed. - return false; - } - - return repeatUntil(async () => { - const windows = await this.callRemoteTestUtil('getWindows', null, []); - for (const id in windows) { - if (id === appId) { - // Window is still available. Continues waiting. - return pending( - caller, 'Window with the prefix %s is not found.', appId); - } - } - // Window is not available. Closing is done successfully. - return true; - }); - } - - /** * Waits until the window turns to the given size. * @param {string} appId App window Id. * @param {number} width Requested width in pixels.
diff --git a/ui/ozone/platform/wayland/host/wayland_keyboard.cc b/ui/ozone/platform/wayland/host/wayland_keyboard.cc index 33164b2..f57fbf33 100644 --- a/ui/ozone/platform/wayland/host/wayland_keyboard.cc +++ b/ui/ozone/platform/wayland/host/wayland_keyboard.cc
@@ -54,6 +54,7 @@ void AckKey(uint32_t serial, bool handled) { zcr_extended_keyboard_v1_ack_key(obj_.get(), serial, handled); + keyboard_->connection_->Flush(); } // Returns true if connected object will send zcr_extended_keyboard::peek_key.
diff --git a/ui/ozone/platform/wayland/host/wayland_pointer.cc b/ui/ozone/platform/wayland/host/wayland_pointer.cc index feabbc7..582ec833 100644 --- a/ui/ozone/platform/wayland/host/wayland_pointer.cc +++ b/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -18,8 +18,8 @@ namespace { -// Remove this method when Compositors other than Exo comply with -// `wl_pointer.frame`. +// TODO(https://crbug.com/1353873): Remove this method when Compositors other +// than Exo comply with `wl_pointer.frame`. wl::EventDispatchPolicy EventDispatchPolicyForPlatform() { return #if BUILDFLAG(IS_CHROMEOS_LACROS) @@ -70,7 +70,7 @@ pointer->delegate_->OnPointerFocusChanged( window, pointer->connection_->MaybeConvertLocation(location, window), - wl::EventDispatchPolicy::kOnFrame); + EventDispatchPolicyForPlatform()); } // static
diff --git a/ui/ozone/platform/wayland/host/wayland_touch.cc b/ui/ozone/platform/wayland/host/wayland_touch.cc index afacef7..a160ead 100644 --- a/ui/ozone/platform/wayland/host/wayland_touch.cc +++ b/ui/ozone/platform/wayland/host/wayland_touch.cc
@@ -17,6 +17,25 @@ namespace ui { +namespace { + +// TODO(https://crbug.com/1353873): Remove this method when Compositors other +// than Exo comply with `wl_touch.frame`. +// +// For instance, on Gnome/Wayland, KDE and Weston compositors a wl_touch.up does +// not come accompanied by a respective wl_touch.frame event. On these scenarios +// be conservative and always dispatch the events immediately. +wl::EventDispatchPolicy EventDispatchPolicyForPlatform() { + return +#if BUILDFLAG(IS_CHROMEOS_LACROS) + wl::EventDispatchPolicy::kOnFrame; +#else + wl::EventDispatchPolicy::kImmediate; +#endif +} + +} // namespace + WaylandTouch::WaylandTouch(wl_touch* touch, WaylandConnection* connection, Delegate* delegate) @@ -56,7 +75,7 @@ gfx::PointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), window); base::TimeTicks timestamp = base::TimeTicks() + base::Milliseconds(time); touch->delegate_->OnTouchPressEvent(window, location, timestamp, id, - wl::EventDispatchPolicy::kOnFrame); + EventDispatchPolicyForPlatform()); } void WaylandTouch::Up(void* data, @@ -67,19 +86,9 @@ auto* touch = static_cast<WaylandTouch*>(data); DCHECK(touch); - // TODO(https://crbug.com/1353873): Gnome/Wayland, KDE and Weston compositors - // have a bug where wl_touch.up does not come accompanied by a respective - // wl_touch.frame event. On these particular set ups, dispatch the event - // immediately. - auto event_dispatch_policy = -#if BUILDFLAG(IS_CHROMEOS_LACROS) - wl::EventDispatchPolicy::kOnFrame; -#else - wl::EventDispatchPolicy::kImmediate; -#endif - base::TimeTicks timestamp = base::TimeTicks() + base::Milliseconds(time); - touch->delegate_->OnTouchReleaseEvent(timestamp, id, event_dispatch_policy); + touch->delegate_->OnTouchReleaseEvent(timestamp, id, + EventDispatchPolicyForPlatform()); } void WaylandTouch::Motion(void* data, @@ -100,7 +109,7 @@ gfx::PointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), target); base::TimeTicks timestamp = base::TimeTicks() + base::Milliseconds(time); touch->delegate_->OnTouchMotionEvent(location, timestamp, id, - wl::EventDispatchPolicy::kOnFrame); + EventDispatchPolicyForPlatform()); } void WaylandTouch::Cancel(void* data, wl_touch* obj) {
diff --git a/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts b/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts index 043dc22..219ac9cb 100644 --- a/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts +++ b/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts
@@ -180,6 +180,7 @@ bubble.buttons = params.buttons; if (params.timeout) { bubble.timeoutMs = Number(params.timeout!.microseconds / 1000n); + assert(bubble.timeoutMs > 0); } assert(
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java index 10ad02f..87332f0 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java
@@ -15,7 +15,7 @@ * * @see WebLayer#isAvailable() */ - int MAX_SKEW = 7; + int MAX_SKEW = 9; /** * Minimum version of client and implementation.
diff --git a/weblayer/browser/overlay_popup_ad_intervention_browsertest.cc b/weblayer/browser/overlay_popup_ad_intervention_browsertest.cc index 4455d2ba..5b7e2e86 100644 --- a/weblayer/browser/overlay_popup_ad_intervention_browsertest.cc +++ b/weblayer/browser/overlay_popup_ad_intervention_browsertest.cc
@@ -56,8 +56,16 @@ base::test::ScopedFeatureList feature_list_; }; +// TODO(https://crbug.com/1199860): Fails on Linux MSan. +#if BUILDFLAG(IS_LINUX) && defined(MEMORY_SANITIZER) +#define MAYBE_NoOverlayPopupAd_AdInterventionNotTriggered \ + DISABLED_NoOverlayPopupAd_AdInterventionNotTriggered +#else +#define MAYBE_NoOverlayPopupAd_AdInterventionNotTriggered \ + NoOverlayPopupAd_AdInterventionNotTriggered +#endif IN_PROC_BROWSER_TEST_F(OverlayPopupAdViolationBrowserTest, - NoOverlayPopupAd_AdInterventionNotTriggered) { + MAYBE_NoOverlayPopupAd_AdInterventionNotTriggered) { base::HistogramTester histogram_tester; GURL url = embedded_test_server()->GetURL(