diff --git a/AUTHORS b/AUTHORS index b5dae31..9f62dd35 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -1038,6 +1038,7 @@ Minjeong Kim <deoxyribonucleicacid150@gmail.com> Minjeong Lee <apenr1234@gmail.com> Minseok Koo <kei98301@gmail.com> +Minseong Kim <jja08111@gmail.com> Minseop Choi <minsubb13@gmail.com> Minsoo Max Koo <msu.koo@samsung.com> Minsung Jin <m4ushold@gmail.com> @@ -1416,12 +1417,14 @@ Sudarshan Parthasarathy <sudarshan.p@samsung.com> Sujae Jo <sujae33.jo@gmail.com> Sujith S S <sujiths.s@samsung.com> +Sukyung Byun <dev.suu3@gmail.com> Sumaid Syed <sumaidsyed@gmail.com> Sunchang Li <johnstonli@tencent.com> Sundoo Kim <nerdooit@gmail.com> Sundoo Kim <0xd00d00b@gmail.com> Suneel Kota <suneel.kota@samsung.com> Sung Lee <sung.lee@amd.com> +Sungboo Park <seongbooopark@gmail.com> Sungguk Lim <limasdf@gmail.com> Sunghyeok Kang <sh0528.kang@samsung.com> Sungmann Cho <sungmann.cho@gmail.com>
diff --git a/DEPS b/DEPS index 3da2fb8..66259542 100644 --- a/DEPS +++ b/DEPS
@@ -273,7 +273,7 @@ 'screen_ai_windows_386': 'version:138.00', # siso CIPD package version. - 'siso_version': 'git_revision:17b491ae74e86312a96239ff88e852acee83c135', + 'siso_version': 'git_revision:04b22e60e2aae70fa9d51141c91bf4554d8c5239', # download libaom test data 'download_libaom_testdata': False, @@ -299,15 +299,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': '0feee17aeacab6b88ac8be3d8b35ae4c940eeea4', + 'skia_revision': '9f9e1f37917e8c2c2a7832325a9caddef8920625', # 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': '1beea5ff6680e267f28e29054239ebcdd4ccb861', + 'v8_revision': '91514ffc9addb26e0bd78df8e28a668abd045cf1', # 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': 'db33baf4eb0d7954f0110cddc30acb9cdc12e2d4', + 'angle_revision': '8aa29250983893ebc940d0285f6d5fa2199fc63a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -391,7 +391,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': 'c049d058ae5973f47a21fb1e4eb7a224174ef032', + 'devtools_frontend_revision': '3a15a39f336401af3597c00cc975b2a323e7e0d2', # 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. @@ -415,7 +415,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': '606e03a22bfe5686be18fcc934555f55f987c1e9', + 'dawn_revision': '7fda3b6896dfd60d7d07f486da449420b01d9e54', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -499,7 +499,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. - 'libunwind_revision': '4acde988c52e6a325e3ce2ac761284f295f2ab39', + 'libunwind_revision': '09f6f7b1685888b16c0fe52a7a68f9dff8b8d60e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -1486,7 +1486,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '687392ba3de05f6fae3002d7b7435b231d048dce', + 'aafe4fa62195c0fd6b7395c85e2d4769300f8c76', 'condition': 'checkout_android and checkout_src_internal', }, @@ -1645,7 +1645,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '1jSxEkUFGSfsQTosCWjXFmS0h3Lk_BRPBBLwBNosOVYC', + 'version': 'wfVeehXfOqVwC9E4j9U8ghXvt7eeTMgZsdBUBB5fVRkC', }, ], 'condition': 'checkout_android and non_git_source', @@ -2526,7 +2526,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '6ffe623d283575c00047cf9abf90c3659505a592', + Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '11cd406514a8212d3568448b2207d2925d5ca202', 'src/base/tracing/test/data': { 'bucket': 'perfetto', @@ -2703,7 +2703,7 @@ 'packages': [ { 'package': 'chromium/third_party/r8', - 'version': 'UDiEQW04Q7U0lSlAQAik0xbIV-AdjAnCHl7GcecroU4C', + 'version': 'QhYGRVpYYKZmt3f_Zb2HoJ9LIBEnWaeeLXRNei47Z30C', }, ], 'condition': 'checkout_android and non_git_source', @@ -2840,16 +2840,16 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@72604f04b9576fcda814d388673d7530d95a9a5a', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@0f00b76ecd36ec3d2df74e7705ed6efbc1fb89f6', 'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@963588074b26326ff0426c8953c1235213309bdb', 'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3', 'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@6d0784e9f1ab92c17eeea94821b2465c14a52be9', - 'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@f06e0f3d2e5acfe4b14e714e4103dd1ccdb237e5', - 'src/third_party/vulkan-headers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Headers@9c77de5c3dd216f28e407eec65ed9c0a296c1f74', - 'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@fefd7ed96ef9994f0080dbd078822b07d8637918', - 'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@ba13d38d06830f714a93c5bb159e6e4bacacf0bc', - 'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@be40e67892c83d4752ccfbee7ce690ea88087d2b', - 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@6ae58a2b17b2bcebdc5377995007391b85ffa10f', + 'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@feba06f44f682e17e0efcd412dff8de74a23d63a', + 'src/third_party/vulkan-headers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Headers@75ad707a587e1469fb53a901b9b68fe9f6fbc11f', + 'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@a8bec310845ce80af5c00342243ae972cbe95e3b', + 'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@60b640cb931814fcc6dabe4fc61f4738c56579f6', + 'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@4f628210460c4df62029959cc7fb237ac75f7189', + 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@ff0450c7bccfb78f9c7117f1ecd17f7321535cad', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21', @@ -3016,7 +3016,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/boca_app/app', - 'version': 'sRBJTTmwZylqoIAy7UWy24wqp8cJ1FiE285X8AJs380C', + 'version': '4rIcnAZG8n0o36G3bDtLpFEflf6VI7sHbs9dXlr0bkMC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3027,7 +3027,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'qkyNFsVICJ-JrYiVUpRoWnxS6Xd23XJc21-bNMkItnwC', + 'version': 'EP0sLhelvD2I201hVxCpuMu0AJFQol9D7Wqmuab_IeIC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3038,7 +3038,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'X5yA3jmrsEHnTqTsWR9XOg42AJNxWOOD5f41r5SO58QC', + 'version': 'Dj7HVt9YVi22nMFZeP86VbkcHwznu3bQT-WUBgL9IDoC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java index 087b36c..bc3eb0e 100644 --- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -243,6 +243,9 @@ AutofillFeatures.AUTOFILL_ACCEPT_DOM_MUTATION_AFTER_AUTOFILL_SUBMISSION, "Accepts DOM_MUTATION_AFTER_AUTOFILL submissions detected on password forms."), Flag.baseFeature( + AutofillFeatures.AUTOFILL_AND_PASSWORDS_IN_SAME_SURFACE, + "Changes how password requests are passed to the embedder. Ideally a noop."), + Flag.baseFeature( AutofillFeatures.AUTOFILL_BETTER_LOCAL_HEURISTIC_PLACEHOLDER_SUPPORT, "Treats placeholders as a separate signal for Autofill local heuristics"), Flag.baseFeature(
diff --git a/ash/display/touch_calibrator_view.cc b/ash/display/touch_calibrator_view.cc index b6c24ac..7fc90bed 100644 --- a/ash/display/touch_calibrator_view.cc +++ b/ash/display/touch_calibrator_view.cc
@@ -583,8 +583,11 @@ tap_label_ = touch_point_view_->AddChildView(std::make_unique<views::Label>( rb.GetLocalizedString(IDS_DISPLAY_TOUCH_CALIBRATION_TAP_HERE_LABEL), views::Label::CustomFont{rb.GetFontListWithDelta(6)})); - tap_label_->SetBounds(0, kThrobberCircleViewWidth, kTapLabelWidth, - kTapLabelHeight); + gfx::Size preferred_label_size = tap_label_->GetPreferredSize(); + const int x = std::max( + (touch_point_view_->width() - preferred_label_size.width()) / 2, 0); + tap_label_->SetBounds(x, kThrobberCircleViewWidth, + preferred_label_size.width(), kTapLabelHeight); tap_label_->SetEnabledColor(kTapHereLabelColor); tap_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER); tap_label_->SetAutoColorReadabilityEnabled(false);
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index c3a3bf4..66a885e 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -381,7 +381,10 @@ } if (is_apple) { - default_compiler_configs += [ "//build/config/compiler:enable_arc" ] + default_compiler_configs += [ + "//build/config/compiler:enable_arc", + "//build/config/compiler:assign_property_warning", + ] } if (is_posix) {
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 07c881e..e05a815 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -1756,9 +1756,7 @@ from_build_root = rebase_path(clang_warning_suppression_file, root_build_dir) inputs = [ clang_warning_suppression_file ] - cflags = [ - "--warning-suppression-mappings=" + from_build_root, - ] + cflags = [ "--warning-suppression-mappings=" + from_build_root ] } } @@ -3236,6 +3234,12 @@ cflags_objc = common_flags cflags_objcc = common_flags } + + config("assign_property_warning") { + common_flags = [ "-Wobjc-property-assign-on-object-type" ] + cflags_objc = common_flags + cflags_objcc = common_flags + } } if (is_android) {
diff --git a/cc/mojo_embedder/viz_layer_context.cc b/cc/mojo_embedder/viz_layer_context.cc index 20228ac..96f0443 100644 --- a/cc/mojo_embedder/viz_layer_context.cc +++ b/cc/mojo_embedder/viz_layer_context.cc
@@ -117,6 +117,7 @@ wire->will_change_transform = new_node.will_change_transform; wire->visible_frame_element_id = new_node.visible_frame_element_id; wire->damage_reasons_bit_mask = new_node.damage_reasons().ToEnumBitmask(); + wire->moved_by_safe_area_bottom = new_node.moved_by_safe_area_bottom; container.push_back(std::move(wire)); }
diff --git a/chrome/VERSION b/chrome/VERSION index 86c1d06..8e29cb8 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=138 MINOR=0 -BUILD=7173 +BUILD=7176 PATCH=0
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java index d456d96..a9783c4 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
@@ -1108,6 +1108,7 @@ TextView titleView = (TextView) mHeaderView.findViewById(R.id.header_title); if (titleView != null) { titleView.setText(headerText); + titleView.setContentDescription(headerText); } } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninManagerIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninManagerIntegrationTest.java index 640a39a..2749182 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninManagerIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninManagerIntegrationTest.java
@@ -28,6 +28,7 @@ import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DoNotBatch; +import org.chromium.base.test.util.Features; import org.chromium.base.test.util.HistogramWatcher; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.ProfileManager; @@ -38,6 +39,7 @@ import org.chromium.chrome.test.util.browser.signin.SigninTestUtil; import org.chromium.components.signin.AccountManagerFacade; import org.chromium.components.signin.AccountManagerFacadeProvider; +import org.chromium.components.signin.SigninFeatures; import org.chromium.components.signin.base.AccountInfo; import org.chromium.components.signin.base.CoreAccountInfo; import org.chromium.components.signin.identitymanager.ConsentLevel; @@ -58,6 +60,7 @@ */ @RunWith(BaseJUnit4ClassRunner.class) @DoNotBatch(reason = "Integration test suite that changes the list of accounts") +@Features.EnableFeatures(SigninFeatures.MAKE_ACCOUNTS_AVAILABLE_IN_IDENTITY_MANAGER) public class SigninManagerIntegrationTest { @Rule public final SigninTestRule mSigninTestRule = new SigninTestRule(); @@ -104,7 +107,8 @@ @Test @MediumTest - public void testUpdateAccountListOneAccountsRegisteredAndNoSignedInUser() { + @Features.DisableFeatures(SigninFeatures.MAKE_ACCOUNTS_AVAILABLE_IN_IDENTITY_MANAGER) + public void testUpdateAccountListOneAccountsRegisteredAndNoSignedInUserLegacy() { mSigninTestRule.addAccount(TestAccounts.ACCOUNT1); ThreadUtils.runOnUiThreadBlocking( @@ -118,6 +122,21 @@ @Test @MediumTest + public void testUpdateAccountListOneAccountsRegisteredAndNoSignedInUser() { + mSigninTestRule.addAccount(TestAccounts.ACCOUNT1); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertArrayEquals( + "Accounts should be available without being signed-in", + new CoreAccountInfo[] {TestAccounts.ACCOUNT1}, + mIdentityManager.getAccountsWithRefreshTokens()); + }); + } + + @Test + @MediumTest + @Features.DisableFeatures(SigninFeatures.MAKE_ACCOUNTS_AVAILABLE_IN_IDENTITY_MANAGER) public void testUpdateAccountListOneAccountsRegisteredSignedIn() { mSigninTestRule.addAccountThenSignin(TestAccounts.ACCOUNT1); @@ -133,6 +152,32 @@ @Test @MediumTest public void testUpdateAccountListSingleAccountThenAddOne() { + mSigninTestRule.addAccount(TestAccounts.ACCOUNT1); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertArrayEquals( + "One account available", + new CoreAccountInfo[] {TestAccounts.ACCOUNT1}, + mIdentityManager.getAccountsWithRefreshTokens()); + }); + + // Add another account. + mSigninTestRule.addAccount(TestAccounts.ACCOUNT2); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertArrayEquals( + "Two accounts available", + new CoreAccountInfo[] {TestAccounts.ACCOUNT1, TestAccounts.ACCOUNT2}, + mIdentityManager.getAccountsWithRefreshTokens()); + }); + } + + @Test + @MediumTest + @Features.DisableFeatures(SigninFeatures.MAKE_ACCOUNTS_AVAILABLE_IN_IDENTITY_MANAGER) + public void testUpdateAccountListSingleSignedInAccountThenAddOne() { mSigninTestRule.addAccountThenSignin(TestAccounts.ACCOUNT1); ThreadUtils.runOnUiThreadBlocking( @@ -148,32 +193,53 @@ ThreadUtils.runOnUiThreadBlocking( () -> { - Assert.assertEquals( + Assert.assertArrayEquals( "Signed in and two accounts available", - new HashSet<>( - Arrays.asList(TestAccounts.ACCOUNT1, TestAccounts.ACCOUNT2)), - new HashSet<>( - Arrays.asList( - mIdentityManager.getAccountsWithRefreshTokens()))); + new CoreAccountInfo[] {TestAccounts.ACCOUNT1, TestAccounts.ACCOUNT2}, + mIdentityManager.getAccountsWithRefreshTokens()); }); } @Test @MediumTest - public void testUpdateAccountListTwoAccountsThenRemoveOne() { + public void testUpdateAccountListTwoAccountsThenRemoveSignedInOne() { // Add accounts. mSigninTestRule.addAccountThenSignin(TestAccounts.ACCOUNT1); mSigninTestRule.addAccount(TestAccounts.ACCOUNT2); ThreadUtils.runOnUiThreadBlocking( () -> { - Assert.assertEquals( + Assert.assertArrayEquals( "Signed in and two accounts available", - new HashSet<>( - Arrays.asList(TestAccounts.ACCOUNT1, TestAccounts.ACCOUNT2)), - new HashSet<>( - Arrays.asList( - mIdentityManager.getAccountsWithRefreshTokens()))); + new CoreAccountInfo[] {TestAccounts.ACCOUNT1, TestAccounts.ACCOUNT2}, + mIdentityManager.getAccountsWithRefreshTokens()); + }); + + mSigninTestRule.signOut(); + mSigninTestRule.removeAccount(TestAccounts.ACCOUNT1.getId()); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertArrayEquals( + "Only one account available, account1 should not be returned anymore", + new CoreAccountInfo[] {TestAccounts.ACCOUNT2}, + mIdentityManager.getAccountsWithRefreshTokens()); + }); + } + + @Test + @MediumTest + public void testUpdateAccountListTwoAccountsThenRemoveNonSignedInOne() { + // Add accounts. + mSigninTestRule.addAccountThenSignin(TestAccounts.ACCOUNT1); + mSigninTestRule.addAccount(TestAccounts.ACCOUNT2); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertArrayEquals( + "Signed in and two accounts available", + new CoreAccountInfo[] {TestAccounts.ACCOUNT1, TestAccounts.ACCOUNT2}, + mIdentityManager.getAccountsWithRefreshTokens()); }); mSigninTestRule.removeAccount(TestAccounts.ACCOUNT2.getId()); @@ -196,13 +262,10 @@ ThreadUtils.runOnUiThreadBlocking( () -> { - Assert.assertEquals( + Assert.assertArrayEquals( "Signed in and two accounts available", - new HashSet<>( - Arrays.asList(TestAccounts.ACCOUNT1, TestAccounts.ACCOUNT2)), - new HashSet<>( - Arrays.asList( - mIdentityManager.getAccountsWithRefreshTokens()))); + new CoreAccountInfo[] {TestAccounts.ACCOUNT1, TestAccounts.ACCOUNT2}, + mIdentityManager.getAccountsWithRefreshTokens()); }); // Remove all. @@ -220,6 +283,32 @@ @Test @MediumTest + public void testUpdateAccountListTwoAccountsThenSignOut() { + // Add accounts. + mSigninTestRule.addAccountThenSignin(TestAccounts.ACCOUNT1); + mSigninTestRule.addAccount(TestAccounts.ACCOUNT2); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertArrayEquals( + "Signed in and two accounts available", + new CoreAccountInfo[] {TestAccounts.ACCOUNT1, TestAccounts.ACCOUNT2}, + mIdentityManager.getAccountsWithRefreshTokens()); + }); + + mSigninTestRule.signOut(); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertArrayEquals( + "Two accounts available", + new CoreAccountInfo[] {TestAccounts.ACCOUNT1, TestAccounts.ACCOUNT2}, + mIdentityManager.getAccountsWithRefreshTokens()); + }); + } + + @Test + @MediumTest @DisableIf.Build(sdk_equals = Build.VERSION_CODES.S_V2, message = "crbug.com/41486307") public void testUpdateAccountListTwoAccountsThenRemoveAllSignOut() { // Add accounts. @@ -252,25 +341,6 @@ @Test @MediumTest - public void testUpdateAccountListTwoAccountsRegisteredAndOneSignedIn() { - // Add accounts. - mSigninTestRule.addAccountThenSignin(TestAccounts.ACCOUNT1); - mSigninTestRule.addAccount(TestAccounts.ACCOUNT2); - - ThreadUtils.runOnUiThreadBlocking( - () -> { - Assert.assertEquals( - "Signed in and two accounts available", - new HashSet<>( - Arrays.asList(TestAccounts.ACCOUNT1, TestAccounts.ACCOUNT2)), - new HashSet<>( - Arrays.asList( - mIdentityManager.getAccountsWithRefreshTokens()))); - }); - } - - @Test - @MediumTest public void testPrimaryAccountRemoval_signsOut() { mSigninTestRule.addAccount(TestAccounts.ACCOUNT1); SigninTestUtil.signin(TestAccounts.ACCOUNT1); @@ -376,7 +446,8 @@ @Test @MediumTest - public void testSignoutWhenAccountsNotAvailable() { + @Features.DisableFeatures(SigninFeatures.MAKE_ACCOUNTS_AVAILABLE_IN_IDENTITY_MANAGER) + public void testSignoutWhenAccountsNotAvailableLegacy() { HistogramWatcher signoutWatcher = HistogramWatcher.newSingleRecordWatcher("Signin.SignOut.Completed"); mSigninTestRule.addAccountThenSignin(TestAccounts.ACCOUNT1); @@ -407,7 +478,7 @@ // Unblocks the updates. blocker.close(); - // Check that the account is still signed out and that is has been removed from the + // Check that the account is still signed out and that it has been removed from the // IdentityManager. Assert.assertFalse(mIdentityManager.hasPrimaryAccount(ConsentLevel.SIGNIN)); ThreadUtils.runOnUiThreadBlocking( @@ -419,4 +490,50 @@ }); signoutWatcher.assertExpected(); } + + @Test + @MediumTest + public void testSignoutWhenAccountsNotAvailable() { + HistogramWatcher signoutWatcher = + HistogramWatcher.newSingleRecordWatcher("Signin.SignOut.Completed"); + mSigninTestRule.addAccountThenSignin(TestAccounts.ACCOUNT1); + // Blocks updated the accounts list and ensures that {@link #getCoreAccountInfos} returns an + // unfulfilled promise. + FakeAccountManagerFacade.UpdateBlocker blocker = + mSigninTestRule.blockGetCoreAccountInfosUpdate(/* populateCache= */ false); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertTrue(mIdentityManager.hasPrimaryAccount(ConsentLevel.SIGNIN)); + Assert.assertFalse(mAccountManagerFacade.getCoreAccountInfos().isFulfilled()); + Assert.assertFalse(mAccountManagerFacade.getAccounts().isFulfilled()); + Assert.assertArrayEquals( + new CoreAccountInfo[] {TestAccounts.ACCOUNT1}, + mIdentityManager.getAccountsWithRefreshTokens()); + + // Sign-out should be allowed even if the list of accounts isn't available yet. + mSigninManager.signOut(SignoutReason.TEST); + + // Check the account is signed out + Assert.assertFalse(mIdentityManager.hasPrimaryAccount(ConsentLevel.SIGNIN)); + }); + + // Wait for the operation to have completed. + verify(mSignInStateObserverMock, timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL).times(1)) + .onSignedOut(); + + // Unblocks the updates. + blocker.close(); + // Check that the account is still signed out but the account is available in identity + // manager. + Assert.assertFalse(mIdentityManager.hasPrimaryAccount(ConsentLevel.SIGNIN)); + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertArrayEquals( + "Accounts are available", + new CoreAccountInfo[] {TestAccounts.ACCOUNT1}, + mIdentityManager.getAccountsWithRefreshTokens()); + }); + signoutWatcher.assertExpected(); + } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java index af707273..ee9da18 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java
@@ -1900,4 +1900,32 @@ DisplayMode.UNDEFINED, dataProvider.getResolvedDisplayMode()); } + + @Test + public void uiTypePopup_hasNoToolbarButtons() { + Intent intent = + new Intent() + .putExtra( + CustomTabsIntent.EXTRA_SHARE_STATE, CustomTabsIntent.SHARE_STATE_ON) + .putExtra(CustomTabsIntent.EXTRA_CLOSE_BUTTON_ENABLED, true) + .putExtra( + CustomTabIntentDataProvider.EXTRA_UI_TYPE, CustomTabsUiType.POPUP); + IntentUtils.setForceIsTrustedIntentForTesting(true); + + CustomTabIntentDataProvider dataProvider = + new CustomTabIntentDataProvider(intent, mContext, COLOR_SCHEME_LIGHT); + + // If there are no custom buttons defined, then the share button is added to the set of + // custom toolbar buttons. Otherwise it gets punted to menu. + // The open in browser button can be presented only by being added to the set of custom + // toolbar buttons. + assertEquals( + "There should be no buttons on toolbar", + 0, + dataProvider.getCustomButtonsOnToolbar().size()); + + assertFalse("The close button should be disabled", dataProvider.isCloseButtonEnabled()); + + IntentUtils.setForceIsTrustedIntentForTesting(false); + } }
diff --git a/chrome/browser/ash/app_mode/kiosk_troubleshooting_tools_browsertest.cc b/chrome/browser/ash/app_mode/kiosk_troubleshooting_tools_browsertest.cc index 5d966226..873ac0c2 100644 --- a/chrome/browser/ash/app_mode/kiosk_troubleshooting_tools_browsertest.cc +++ b/chrome/browser/ash/app_mode/kiosk_troubleshooting_tools_browsertest.cc
@@ -7,10 +7,7 @@ #include "ash/shell.h" #include "base/run_loop.h" #include "base/test/metrics/histogram_tester.h" -#include "chrome/browser/ash/app_mode/kiosk_controller.h" -#include "chrome/browser/ash/app_mode/kiosk_system_session.h" #include "chrome/browser/ash/app_mode/test/kiosk_test_utils.h" -#include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h" #include "chrome/browser/ash/login/app_mode/test/web_kiosk_base_test.h" #include "chrome/browser/chromeos/app_mode/kiosk_browser_window_handler.h" #include "chrome/browser/devtools/devtools_window_testing.h" @@ -31,6 +28,8 @@ #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" +using ash::kiosk::test::CreatePopupBrowser; +using ash::kiosk::test::CreateRegularBrowser; using ash::kiosk::test::DidKioskCloseNewWindow; using policy::DeveloperToolsPolicyHandler::Availability::kAllowed; using policy::DeveloperToolsPolicyHandler::Availability::kDisallowed; @@ -120,16 +119,12 @@ /*alt=*/true, /*command=*/false); } - Browser* OpenForAppPopupBrowser() const { + Browser& OpenForAppPopupBrowser() const { profile()->GetPrefs()->SetBoolean(prefs::kNewWindowsInKioskAllowed, true); - Browser::CreateParams params = Browser::CreateParams::CreateForAppPopup( - /*app_name=*/kiosk_app_browser()->app_name(), /*trusted_source=*/true, - /*window_bounds=*/gfx::Rect(), /*profile=*/profile(), - /*user_gesture=*/true); - Browser* new_browser = Browser::Create(params); - new_browser->window()->Show(); + Browser& browser = + CreatePopupBrowser(*profile(), kiosk_app_browser()->app_name()); EXPECT_FALSE(DidKioskCloseNewWindow()); - return new_browser; + return browser; } bool IsLactActiveBrowserResizable() { @@ -264,7 +259,7 @@ ExpectOnlyKioskAppOpen(); // Explicitly open a new window to make sure it will be closed. - Browser::Create(Browser::CreateParams(profile(), /*user_gesture=*/true)); + CreateRegularBrowser(*profile()); EXPECT_TRUE(DidKioskCloseNewWindow()); histogram.ExpectBucketCount( @@ -363,22 +358,22 @@ // Enable another feature to allow opening two popup browsers to make sure // that switching between windows is still not available if the // troubleshooting policy is disabled. - Browser* new_browser = OpenForAppPopupBrowser(); + Browser& new_browser = OpenForAppPopupBrowser(); // When new window is opened, it becomes active. - EXPECT_TRUE(new_browser->window()->IsActive()); + EXPECT_TRUE(new_browser.window()->IsActive()); EXPECT_FALSE(main_browser->window()->IsActive()); EmulateSwitchWindowsForwardShortcutPressed(); // Active window remains the same. - EXPECT_TRUE(new_browser->window()->IsActive()); + EXPECT_TRUE(new_browser.window()->IsActive()); EXPECT_FALSE(main_browser->window()->IsActive()); EmulateSwitchWindowsBackwardShortcutPressed(); // Active window remains the same. - EXPECT_TRUE(new_browser->window()->IsActive()); + EXPECT_TRUE(new_browser.window()->IsActive()); EXPECT_FALSE(main_browser->window()->IsActive()); }
diff --git a/chrome/browser/ash/app_mode/test/kiosk_test_utils.cc b/chrome/browser/ash/app_mode/test/kiosk_test_utils.cc index c70cf926..56b15aa 100644 --- a/chrome/browser/ash/app_mode/test/kiosk_test_utils.cc +++ b/chrome/browser/ash/app_mode/test/kiosk_test_utils.cc
@@ -40,6 +40,7 @@ #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/webui/ash/login/app_launch_splash_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/error_screen_handler.h" +#include "chrome/browser/web_applications/web_app_helpers.h" #include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h" #include "chromeos/ash/components/policy/device_local_account/device_local_account_type.h" #include "components/policy/core/common/cloud/cloud_policy_constants.h" @@ -58,6 +59,8 @@ namespace { +const char kTestUrl[] = "https://www.test.com"; + const extensions::Extension* FindInExtensionRegistry(Profile& profile, std::string_view app_id) { return extensions::ExtensionRegistry::Get(&profile)->GetInstalledExtension( @@ -90,6 +93,25 @@ observation_{this}; }; +content::WebContents* GetActiveWebContents(const Browser& browser) { + return browser.tab_strip_model()->GetActiveWebContents(); +} + +void AddWebContentsToBrowser(Browser& browser, Profile& profile) { + std::unique_ptr<content::WebContents> web_contents = + content::WebContents::Create( + content::WebContents::CreateParams(&profile)); + + browser.tab_strip_model()->AddWebContents(std::move(web_contents), -1, + ui::PAGE_TRANSITION_FIRST, + AddTabTypes::ADD_ACTIVE); +} + +void TriggerNavigation(content::WebContents* web_contents) { + web_contents->GetController().LoadURLWithParams( + content::NavigationController::LoadURLParams(GURL(kTestUrl))); +} + } // namespace KioskApp AutoLaunchKioskApp() { @@ -317,4 +339,30 @@ policy::GenerateDeviceLocalAccountUserId(account_id, type))); } +Browser& CreateRegularBrowser(Profile& profile) { + Browser::CreateParams params(&profile, /*user_gesture=*/true); + Browser& browser = CHECK_DEREF(Browser::Create(params)); + browser.window()->Show(); + + AddWebContentsToBrowser(browser, profile); + TriggerNavigation(GetActiveWebContents(browser)); + + return browser; +} + +Browser& CreatePopupBrowser(Profile& profile, const std::string& app_name) { + Browser::CreateParams params = Browser::CreateParams::CreateForAppPopup( + app_name, + /*trusted_source=*/true, + /*window_bounds=*/gfx::Rect(), &profile, + /*user_gesture=*/true); + Browser& browser = CHECK_DEREF(Browser::Create(params)); + browser.window()->Show(); + + AddWebContentsToBrowser(browser, profile); + TriggerNavigation(GetActiveWebContents(browser)); + + return browser; +} + } // namespace ash::kiosk::test
diff --git a/chrome/browser/ash/app_mode/test/kiosk_test_utils.h b/chrome/browser/ash/app_mode/test/kiosk_test_utils.h index ee6093e..97e08163b 100644 --- a/chrome/browser/ash/app_mode/test/kiosk_test_utils.h +++ b/chrome/browser/ash/app_mode/test/kiosk_test_utils.h
@@ -129,6 +129,13 @@ // of a Kiosk app of the given `type` to a Chrome `AccountId`. AccountId CreateDeviceLocalAccountId(std::string_view account_id, policy::DeviceLocalAccountType type); + +// Opens a new browser window including navigation to a test url. +Browser& CreateRegularBrowser(Profile& profile); + +// opens a new popup browser window belonging to the provided `app_name`. +Browser& CreatePopupBrowser(Profile& profile, const std::string& app_name); + } // namespace ash::kiosk::test #endif // CHROME_BROWSER_ASH_APP_MODE_TEST_KIOSK_TEST_UTILS_H_
diff --git a/chrome/browser/ash/app_mode/test/new_windows_in_kiosk_allowed_browsertest.cc b/chrome/browser/ash/app_mode/test/new_windows_in_kiosk_allowed_browsertest.cc index 2063ec2..50a46409 100644 --- a/chrome/browser/ash/app_mode/test/new_windows_in_kiosk_allowed_browsertest.cc +++ b/chrome/browser/ash/app_mode/test/new_windows_in_kiosk_allowed_browsertest.cc
@@ -3,14 +3,12 @@ // found in the LICENSE file. #include <cstddef> -#include <optional> #include <string> #include <string_view> #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "base/check_deref.h" -#include "chrome/browser/ash/app_mode/kiosk_app.h" #include "chrome/browser/ash/app_mode/kiosk_controller.h" #include "chrome/browser/ash/app_mode/load_profile.h" #include "chrome/browser/ash/app_mode/test/kiosk_mixin.h" @@ -18,7 +16,6 @@ #include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h" #include "chrome/browser/ash/ownership/fake_owner_settings_service.h" #include "chrome/browser/chromeos/app_mode/kiosk_web_app_install_util.h" -#include "chrome/browser/ui/ash/login/login_display_host.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/test/test_browser_closed_waiter.h" @@ -33,12 +30,13 @@ #include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/cloud/test/policy_builder.h" #include "content/public/test/browser_test.h" -#include "extensions/browser/app_window/app_window.h" #include "testing/gtest/include/gtest/gtest.h" namespace ash { using kiosk::test::CachePolicy; +using kiosk::test::CreatePopupBrowser; +using kiosk::test::CreateRegularBrowser; using kiosk::test::CurrentProfile; using kiosk::test::DidKioskCloseNewWindow; using kiosk::test::TheKioskWebApp; @@ -58,24 +56,6 @@ return web_app::GenerateApplicationNameFromAppId(app_id.value()); } -Browser& OpenRegularBrowser(Profile& profile) { - Browser::CreateParams params(&profile, /*user_gesture=*/true); - Browser& browser = CHECK_DEREF(Browser::Create(params)); - browser.window()->Show(); - return browser; -} - -Browser& OpenPopupBrowser(Profile& profile, const KioskApp& app) { - Browser::CreateParams params = Browser::CreateParams::CreateForAppPopup( - WebAppWindowName(app), - /*trusted_source=*/true, - /*window_bounds=*/gfx::Rect(), &profile, - /*user_gesture=*/true); - Browser& browser = CHECK_DEREF(Browser::Create(params)); - browser.window()->Show(); - return browser; -} - KioskMixin::DefaultServerWebAppOption WebAppInConfig() { return KioskMixin::SimpleWebAppOption(); } @@ -145,7 +125,8 @@ ASSERT_EQ(BrowserList::GetInstance()->size(), 1u); Browser& initial_browser = CHECK_DEREF(BrowserList::GetInstance()->get(0)); - Browser& popup = OpenPopupBrowser(profile, TheKioskWebApp()); + Browser& popup = + CreatePopupBrowser(profile, WebAppWindowName(TheKioskWebApp())); ASSERT_FALSE(DidKioskCloseNewWindow()); EXPECT_EQ(BrowserList::GetInstance()->size(), 2u); @@ -161,7 +142,7 @@ ASSERT_TRUE(GetPolicyValueInPrefs(CurrentProfile())); ASSERT_EQ(BrowserList::GetInstance()->size(), 1u); - Browser& browser = OpenRegularBrowser(CurrentProfile()); + Browser& browser = CreateRegularBrowser(CurrentProfile()); ASSERT_TRUE(TestBrowserClosedWaiter(&browser).WaitUntilClosed()); EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); } @@ -189,11 +170,12 @@ ASSERT_EQ(BrowserList::GetInstance()->size(), 1u); - Browser& browser = OpenRegularBrowser(CurrentProfile()); + Browser& browser = CreateRegularBrowser(CurrentProfile()); ASSERT_TRUE(TestBrowserClosedWaiter(&browser).WaitUntilClosed()); EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); - Browser& popup = OpenPopupBrowser(CurrentProfile(), TheKioskWebApp()); + Browser& popup = + CreatePopupBrowser(CurrentProfile(), WebAppWindowName(TheKioskWebApp())); ASSERT_TRUE(TestBrowserClosedWaiter(&popup).WaitUntilClosed()); EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); }
diff --git a/chrome/browser/background/background_contents.cc b/chrome/browser/background/background_contents.cc index c457e25..aac8034 100644 --- a/chrome/browser/background/background_contents.cc +++ b/chrome/browser/background/background_contents.cc
@@ -43,6 +43,7 @@ site_instance->GetBrowserContext()); WebContents::CreateParams create_params(profile_, std::move(site_instance)); + create_params.is_never_composited = true; create_params.opener_render_process_id = opener ? opener->GetProcess()->GetDeprecatedID() : MSG_ROUTING_NONE; create_params.opener_render_frame_id = @@ -121,12 +122,6 @@ return nullptr; } -bool BackgroundContents::IsNeverComposited(content::WebContents* web_contents) { - DCHECK_EQ(extensions::mojom::ViewType::kBackgroundContents, - extensions::GetViewType(web_contents)); - return true; -} - void BackgroundContents::PrimaryMainFrameRenderProcessGone( base::TerminationStatus status) { delegate_->OnBackgroundContentsTerminated(this);
diff --git a/chrome/browser/background/background_contents.h b/chrome/browser/background/background_contents.h index 963fe38..63cfb2b6 100644 --- a/chrome/browser/background/background_contents.h +++ b/chrome/browser/background/background_contents.h
@@ -91,7 +91,6 @@ const blink::mojom::WindowFeatures& window_features, bool user_gesture, bool* was_blocked) override; - bool IsNeverComposited(content::WebContents* web_contents) override; // content::WebContentsObserver implementation: void PrimaryMainFrameRenderProcessGone(
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc index ad5a3fbc..1fb479c 100644 --- a/chrome/browser/chrome_browser_interface_binders.cc +++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -69,6 +69,7 @@ #include "third_party/blink/public/mojom/loader/navigation_predictor.mojom.h" #include "third_party/blink/public/mojom/payments/payment_request.mojom.h" #include "third_party/blink/public/mojom/payments/secure_payment_confirmation_service.mojom.h" +#include "third_party/blink/public/mojom/persistent_renderer_prefs.mojom.h" #include "third_party/blink/public/mojom/prerender/prerender.mojom.h" #include "third_party/blink/public/public_buildflags.h" #include "ui/accessibility/accessibility_features.h" @@ -97,6 +98,7 @@ #else #include "chrome/browser/badging/badge_manager.h" #include "chrome/browser/payments/payment_request_factory.h" +#include "chrome/browser/prefs/persistent_renderer_prefs_manager.h" #include "chrome/browser/ui/views/side_panel/customize_chrome/customize_chrome_utils.h" #include "chrome/browser/web_applications/web_install_service_impl.h" #endif // BUILDFLAG(IS_ANDROID) @@ -475,6 +477,8 @@ #else map->Add<blink::mojom::BadgeService>( base::BindRepeating(&badging::BadgeManager::BindFrameReceiverIfAllowed)); + map->Add<blink::mojom::PersistentRendererPrefsService>( + base::BindRepeating(&PersistentRendererPrefsManager::BindFrameReceiver)); if (base::FeatureList::IsEnabled(features::kWebPayments)) { map->Add<payments::mojom::PaymentRequest>( base::BindRepeating(&payments::CreatePaymentRequest));
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 0b04c4e..5eeaf47 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -70,7 +70,6 @@ #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" #include "chrome/browser/data_saver/data_saver.h" -#include "chrome/browser/data_sharing/data_sharing_navigation_throttle.h" #include "chrome/browser/defaults.h" #include "chrome/browser/device_api/device_service_impl.h" #include "chrome/browser/device_api/managed_configuration_service.h" @@ -82,7 +81,6 @@ #include "chrome/browser/enterprise/util/managed_browser_utils.h" #include "chrome/browser/external_protocol/external_protocol_handler.h" #include "chrome/browser/favicon/favicon_utils.h" -#include "chrome/browser/first_party_sets/first_party_sets_navigation_throttle.h" #include "chrome/browser/font_family_cache.h" #include "chrome/browser/gpu/chrome_browser_main_extra_parts_gpu.h" #include "chrome/browser/headless/headless_mode_util.h" @@ -120,7 +118,6 @@ #include "chrome/browser/policy/profile_policy_connector.h" #include "chrome/browser/predictors/loading_predictor.h" #include "chrome/browser/predictors/loading_predictor_factory.h" -#include "chrome/browser/preloading/navigation_ablation_throttle.h" #include "chrome/browser/preloading/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.h" #include "chrome/browser/preloading/prefetch/no_state_prefetch/chrome_speculation_host_delegate.h" #include "chrome/browser/preloading/prefetch/no_state_prefetch/no_state_prefetch_manager_factory.h" @@ -159,7 +156,6 @@ #include "chrome/browser/ssl/chrome_security_blocking_page_factory.h" #include "chrome/browser/ssl/chrome_security_state_tab_helper.h" #include "chrome/browser/ssl/https_upgrades_interceptor.h" -#include "chrome/browser/ssl/https_upgrades_navigation_throttle.h" #include "chrome/browser/ssl/sct_reporting_service.h" #include "chrome/browser/ssl/ssl_client_certificate_selector.h" #include "chrome/browser/tab_group_sync/tab_group_sync_utils.h" @@ -175,7 +171,6 @@ #include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/chrome_select_file_policy.h" #include "chrome/browser/ui/color/chrome_color_id.h" -#include "chrome/browser/ui/lens/lens_overlay_side_panel_navigation_throttle.h" #include "chrome/browser/ui/login/http_auth_coordinator.h" #include "chrome/browser/ui/prefs/pref_watcher.h" #include "chrome/browser/ui/tab_contents/chrome_web_contents_view_delegate.h" @@ -242,7 +237,6 @@ #include "components/error_page/common/localized_error.h" #include "components/google/core/common/google_switches.h" #include "components/heap_profiling/in_process/heap_profiler_controller.h" -#include "components/history/content/browser/visited_link_navigation_throttle.h" #include "components/keep_alive_registry/keep_alive_types.h" #include "components/keep_alive_registry/scoped_keep_alive.h" #include "components/language/core/browser/pref_names.h" @@ -321,8 +315,6 @@ #include "content/public/browser/isolated_web_apps_policy.h" #include "content/public/browser/legacy_tech_cookie_issue_details.h" #include "content/public/browser/navigation_handle.h" -#include "content/public/browser/navigation_throttle.h" -#include "content/public/browser/navigation_throttle_registry.h" #include "content/public/browser/network_service_instance.h" #include "content/public/browser/overlay_window.h" #include "content/public/browser/permission_controller.h" @@ -409,9 +401,6 @@ #include "url/third_party/mozilla/url_parse.h" #include "url/url_constants.h" -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) -#include "chrome/browser/enterprise/platform_auth/platform_auth_navigation_throttle.h" -#endif #if BUILDFLAG(IS_WIN) #include "base/files/file_util.h" #include "base/strings/string_tokenizer.h" @@ -514,10 +503,7 @@ #if !BUILDFLAG(IS_ANDROID) #include "chrome/browser/digital_credentials/digital_identity_provider_desktop.h" #include "chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.h" -#include "chrome/browser/preloading/preview/preview_navigation_throttle.h" -#include "chrome/browser/ui/webui/ntp_microsoft_auth/ntp_microsoft_auth_response_capture_navigation_throttle.h" #include "chrome/browser/web_applications/isolated_web_apps/chrome_content_browser_client_isolated_web_apps_part.h" -#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_throttle.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h" #include "chrome/browser/web_applications/locks/app_lock.h" #include "chrome/browser/web_applications/proto/web_app_install_state.pb.h" @@ -530,7 +516,6 @@ #include "ash/multi_capture/multi_capture_service.h" #include "ash/shell.h" #include "base/debug/leak_annotations.h" -#include "chrome/browser/apps/app_service/app_install/app_install_navigation_throttle.h" #include "chrome/browser/chromeos/policy/dlp/dlp_scoped_file_access_delegate.h" #include "chrome/browser/chromeos/tablet_mode/chrome_content_browser_client_tablet_mode_part.h" #include "chrome/browser/file_system_access/cloud_identifier/cloud_identifier_util_cros.h" @@ -553,14 +538,12 @@ #include "chrome/browser/media/unified_autoplay_config.h" #include "chrome/browser/metrics/usage_scenario/chrome_responsiveness_calculator_delegate.h" #include "chrome/browser/new_tab_page/new_tab_page_util.h" -#include "chrome/browser/page_info/web_view_side_panel_throttle.h" #include "chrome/browser/search/instant_service.h" #include "chrome/browser/search/instant_service_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/chrome_pages.h" -#include "chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_navigation_throttle.h" #include "chrome/browser/ui/webui/chrome_content_browser_client_webui_part.h" #include "chrome/browser/ui/webui/webui_util_desktop.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_error_page.h" @@ -574,7 +557,6 @@ #include "chrome/browser/webauthn/chrome_authenticator_request_delegate.h" #include "chrome/grit/chrome_unscaled_resources.h" // nogncheck crbug.com/1125897 #include "components/commerce/core/commerce_feature_list.h" -#include "components/lens/lens_features.h" #include "components/password_manager/content/common/web_ui_constants.h" #include "components/password_manager/core/common/password_manager_features.h" #include "services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom.h" @@ -593,10 +575,6 @@ #include "chrome/browser/enterprise/chrome_browser_main_extra_parts_enterprise.h" #endif -#if BUILDFLAG(ENABLE_EXTENSIONS_CORE) -#include "chrome/browser/enterprise/incognito/incognito_navigation_throttle.h" -#endif // BUILDFLAG(ENABLE_EXTENSIONS_CORE) - #if defined(TOOLKIT_VIEWS) #include "chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h" #endif @@ -691,7 +669,6 @@ #endif #if BUILDFLAG(ENABLE_OFFLINE_PAGES) -#include "chrome/browser/offline_pages/offline_page_navigation_throttle.h" #include "chrome/browser/offline_pages/offline_page_tab_helper.h" #include "chrome/browser/offline_pages/offline_page_url_loader_request_interceptor.h" #endif @@ -1297,35 +1274,6 @@ return std::make_unique<ChromePopupNavigationDelegate>(std::move(params)); } -// NOTE: MaybeCreateVisitedLinkNavigationThrottleFor is defined here due to -// usage of Profile code which lives in chrome/. The rest of the -// VisitedLinkNavigationThrottle class lives in components/, which cannot access -// chrome/ code due to layering. -std::unique_ptr<VisitedLinkNavigationThrottle> -MaybeCreateVisitedLinkNavigationThrottleFor( - content::NavigationHandle* navigation_handle) { - if (!base::FeatureList::IsEnabled( - blink::features::kPartitionVisitedLinkDatabase) && - !base::FeatureList::IsEnabled( - blink::features::kPartitionVisitedLinkDatabaseWithSelfLinks)) { - return nullptr; - } - Profile* profile = Profile::FromBrowserContext( - navigation_handle->GetWebContents()->GetBrowserContext()); - // Off-the-record profiles do not record history or visited links. - if (profile->IsOffTheRecord()) { - return nullptr; - } - history::HistoryService* history_service = - HistoryServiceFactory::GetForProfile(profile, - ServiceAccessType::IMPLICIT_ACCESS); - if (!history_service) { - return nullptr; - } - return std::make_unique<VisitedLinkNavigationThrottle>( - std::move(navigation_handle), history_service); -} - ChromeContentBrowserClient::PopupNavigationDelegateFactory g_popup_navigation_delegate_factory = &CreatePopupNavigationDelegate; @@ -5275,110 +5223,6 @@ void ChromeContentBrowserClient::CreateThrottlesForNavigation( content::NavigationThrottleRegistry& registry) { CreateAndAddChromeThrottlesForNavigation(registry); - - content::NavigationHandle& handle = registry.GetNavigationHandle(); - Profile* profile = - Profile::FromBrowserContext(handle.GetWebContents()->GetBrowserContext()); - // TODO(https://crbug.com/412524375): Move the following code to - // CreateAndAddChromeThrottlesForNavigation(). - -#if !BUILDFLAG(IS_ANDROID) - registry.MaybeAddThrottle( - ReadAnythingSidePanelNavigationThrottle::CreateFor(&handle)); - - if (lens::features::IsLensOverlayEnabled()) { - if (profile) { - if (ThemeService* theme_service = - ThemeServiceFactory::GetForProfile(profile)) { - registry.MaybeAddThrottle( - lens::LensOverlaySidePanelNavigationThrottle::MaybeCreateFor( - &handle, theme_service)); - } - } - } - - registry.MaybeAddThrottle( - NtpMicrosoftAuthResponseCaptureNavigationThrottle::MaybeCreateThrottleFor( - &handle)); -#endif - -#if BUILDFLAG(ENABLE_OFFLINE_PAGES) - registry.MaybeAddThrottle( - offline_pages::OfflinePageNavigationThrottle::MaybeCreateThrottleFor( - &handle)); -#endif - - if (profile) { - registry.MaybeAddThrottle( - HttpsUpgradesNavigationThrottle::MaybeCreateThrottleFor( - &handle, std::make_unique<ChromeSecurityBlockingPageFactory>(), - profile)); - } - - registry.MaybeAddThrottle(MaybeCreateNavigationAblationThrottle(&handle)); - -#if !BUILDFLAG(IS_ANDROID) - MaybeCreateAndAddWebViewSidePanelThrottle(registry); -#endif - - auto* privacy_sandbox_settings = - PrivacySandboxSettingsFactory::GetForProfile(profile); - if (privacy_sandbox_settings && - privacy_sandbox_settings->AreRelatedWebsiteSetsEnabled()) { - registry.MaybeAddThrottle( - first_party_sets::FirstPartySetsNavigationThrottle:: - MaybeCreateNavigationThrottle(&handle)); - } - -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) - // Don't perform platform authentication in incognito and guest profiles. - if (profile && !profile->IsOffTheRecord()) { - registry.MaybeAddThrottle( - enterprise_auth::PlatformAuthNavigationThrottle::MaybeCreateThrottleFor( - &handle)); - } -#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) - -#if BUILDFLAG(IS_CHROMEOS) - // TODO(b:296844164) Handle captive portal signin properly. - if (profile && profile->IsIncognitoProfile() && profile->IsOffTheRecord() && - !profile->GetOTRProfileID().IsCaptivePortal()) { - registry.MaybeAddThrottle( - enterprise_incognito::IncognitoNavigationThrottle:: - MaybeCreateThrottleFor(&handle)); - } - - registry.MaybeAddThrottle( - apps::AppInstallNavigationThrottle::MaybeCreate(&handle)); -#endif // BUILDFLAG(IS_CHROMEOS) - -#if BUILDFLAG(ENABLE_EXTENSIONS_CORE) - if (profile && profile->IsIncognitoProfile() && profile->IsOffTheRecord()) { - registry.MaybeAddThrottle( - enterprise_incognito::IncognitoNavigationThrottle:: - MaybeCreateThrottleFor(&handle)); - } -#endif // BUILDFLAG(ENABLE_EXTENSIONS_CORE) - -#if !BUILDFLAG(IS_ANDROID) - registry.MaybeAddThrottle( - PreviewNavigationThrottle::MaybeCreateThrottleFor(&handle)); -#endif // !BUILDFLAG(IS_ANDROID) - - registry.MaybeAddThrottle( - MaybeCreateVisitedLinkNavigationThrottleFor(&handle)); - - registry.MaybeAddThrottle( - data_sharing::DataSharingNavigationThrottle::MaybeCreateThrottleFor( - &handle)); - -#if !BUILDFLAG(IS_ANDROID) - registry.MaybeAddThrottle( - web_app::IsolatedWebAppThrottle::MaybeCreateThrottleFor(&handle)); -#endif // !BUILDFLAG(IS_ANDROID) - - // Add new throttles in CreateAndAddChromeThrottlesForNavigation() rather than - // here. } std::vector<std::unique_ptr<content::CommitDeferringCondition>>
diff --git a/chrome/browser/chrome_content_browser_client_navigation_throttles.cc b/chrome/browser/chrome_content_browser_client_navigation_throttles.cc index ed54f03..71432f4 100644 --- a/chrome/browser/chrome_content_browser_client_navigation_throttles.cc +++ b/chrome/browser/chrome_content_browser_client_navigation_throttles.cc
@@ -9,15 +9,21 @@ #include "build/build_config.h" #include "build/buildflag.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/data_sharing/data_sharing_navigation_throttle.h" +#include "chrome/browser/first_party_sets/first_party_sets_navigation_throttle.h" +#include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/interstitials/enterprise_util.h" #include "chrome/browser/lookalikes/lookalike_url_navigation_throttle.h" #include "chrome/browser/plugins/pdf_iframe_navigation_throttle.h" #include "chrome/browser/policy/policy_util.h" +#include "chrome/browser/preloading/navigation_ablation_throttle.h" #include "chrome/browser/preloading/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.h" #include "chrome/browser/preloading/prefetch/no_state_prefetch/no_state_prefetch_navigation_throttle.h" +#include "chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ssl/chrome_security_blocking_page_factory.h" #include "chrome/browser/ssl/https_defaulted_callbacks.h" +#include "chrome/browser/ssl/https_upgrades_navigation_throttle.h" #include "chrome/browser/ssl/typed_navigation_upgrade_throttle.h" #include "chrome/browser/supervised_user/classify_url_navigation_throttle.h" #include "chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.h" @@ -34,10 +40,14 @@ #include "components/fingerprinting_protection_filter/browser/throttle_manager.h" #include "components/fingerprinting_protection_filter/common/fingerprinting_protection_filter_features.h" #include "components/guest_view/buildflags/buildflags.h" +#include "components/history/content/browser/visited_link_navigation_throttle.h" +#include "components/lens/lens_features.h" +#include "components/offline_pages/buildflags/buildflags.h" #include "components/omnibox/common/omnibox_features.h" #include "components/page_load_metrics/browser/metrics_navigation_throttle.h" #include "components/payments/content/payment_handler_navigation_throttle.h" #include "components/policy/content/policy_blocklist_navigation_throttle.h" +#include "components/privacy_sandbox/privacy_sandbox_settings.h" #include "components/safe_browsing/buildflags.h" #include "components/security_interstitials/content/insecure_form_navigation_throttle.h" #include "components/security_interstitials/content/ssl_error_handler.h" @@ -48,8 +58,9 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" #include "extensions/buildflags/buildflags.h" -#include "url/gurl.h" #include "pdf/buildflags.h" +#include "third_party/blink/public/common/features.h" +#include "url/gurl.h" #if BUILDFLAG(IS_ANDROID) #include "chrome/android/features/dev_ui/buildflags.h" @@ -64,12 +75,20 @@ #include "chrome/browser/apps/link_capturing/link_capturing_navigation_throttle.h" #include "chrome/browser/apps/link_capturing/web_app_link_capturing_delegate.h" #include "chrome/browser/devtools/devtools_window.h" +#include "chrome/browser/page_info/web_view_side_panel_throttle.h" +#include "chrome/browser/preloading/preview/preview_navigation_throttle.h" +#include "chrome/browser/themes/theme_service_factory.h" +#include "chrome/browser/ui/lens/lens_overlay_side_panel_navigation_throttle.h" #include "chrome/browser/ui/search/new_tab_page_navigation_throttle.h" +#include "chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_navigation_throttle.h" #include "chrome/browser/ui/web_applications/tabbed_web_app_navigation_throttle.h" #include "chrome/browser/ui/web_applications/webui_web_app_navigation_throttle.h" +#include "chrome/browser/ui/webui/ntp_microsoft_auth/ntp_microsoft_auth_response_capture_navigation_throttle.h" +#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_throttle.h" #endif // BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_CHROMEOS) +#include "chrome/browser/apps/app_service/app_install/app_install_navigation_throttle.h" #include "chrome/browser/apps/intent_helper/chromeos_disabled_apps_throttle.h" #include "chrome/browser/apps/link_capturing/chromeos_link_capturing_delegate.h" #include "chrome/browser/apps/link_capturing/chromeos_reimpl_navigation_capturing_throttle.h" @@ -115,13 +134,6 @@ #include "chrome/browser/ui/webui/app_settings/web_app_settings_navigation_throttle.h" #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) - -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || \ - BUILDFLAG(IS_CHROMEOS) -#include "chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h" -#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || - // BUILDFLAG(IS_CHROMEOS) - #if BUILDFLAG(SAFE_BROWSING_AVAILABLE) #include "chrome/browser/safe_browsing/delayed_warning_navigation_throttle.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" @@ -134,6 +146,21 @@ #include "chrome/browser/mac/auth_session_request.h" #endif // BUILDFLAG(IS_MAC) +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) +#include "chrome/browser/offline_pages/offline_page_navigation_throttle.h" +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) + +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) +#include "chrome/browser/enterprise/platform_auth/platform_auth_navigation_throttle.h" +#endif + +#if BUILDFLAG(ENABLE_EXTENSIONS_CORE) +#if !BUILDFLAG(IS_ANDROID) +#include "chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h" +#endif // !BUILDFLAG(IS_ANDROID) +#include "chrome/browser/enterprise/incognito/incognito_navigation_throttle.h" +#endif // BUILDFLAG(ENABLE_EXTENSIONS_CORE) + namespace { // Wrapper for SSLErrorHandler::HandleSSLError() that supplies //chrome-level @@ -195,8 +222,36 @@ return true; } -} // namespace +// NOTE: MaybeCreateVisitedLinkNavigationThrottleFor is defined here due to +// usage of Profile code which lives in chrome/. The rest of the +// VisitedLinkNavigationThrottle class lives in components/, which cannot access +// chrome/ code due to layering. +std::unique_ptr<VisitedLinkNavigationThrottle> +MaybeCreateVisitedLinkNavigationThrottleFor( + content::NavigationHandle* navigation_handle) { + if (!base::FeatureList::IsEnabled( + blink::features::kPartitionVisitedLinkDatabase) && + !base::FeatureList::IsEnabled( + blink::features::kPartitionVisitedLinkDatabaseWithSelfLinks)) { + return nullptr; + } + Profile* profile = Profile::FromBrowserContext( + navigation_handle->GetWebContents()->GetBrowserContext()); + // Off-the-record profiles do not record history or visited links. + if (profile->IsOffTheRecord()) { + return nullptr; + } + history::HistoryService* history_service = + HistoryServiceFactory::GetForProfile(profile, + ServiceAccessType::IMPLICIT_ACCESS); + if (!history_service) { + return nullptr; + } + return std::make_unique<VisitedLinkNavigationThrottle>( + std::move(navigation_handle), history_service); +} +} // namespace void CreateAndAddChromeThrottlesForNavigation( content::NavigationThrottleRegistry& registry) { @@ -474,5 +529,98 @@ prerender::NoStatePrefetchNavigationThrottle::MaybeCreateThrottleFor( &handle)); - // Add new throttles here. +#if !BUILDFLAG(IS_ANDROID) + registry.MaybeAddThrottle( + ReadAnythingSidePanelNavigationThrottle::CreateFor(&handle)); + + if (lens::features::IsLensOverlayEnabled()) { + if (profile) { + if (ThemeService* theme_service = + ThemeServiceFactory::GetForProfile(profile)) { + registry.MaybeAddThrottle( + lens::LensOverlaySidePanelNavigationThrottle::MaybeCreateFor( + &handle, theme_service)); + } + } + } + + registry.MaybeAddThrottle( + NtpMicrosoftAuthResponseCaptureNavigationThrottle::MaybeCreateThrottleFor( + &handle)); +#endif + +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) + registry.MaybeAddThrottle( + offline_pages::OfflinePageNavigationThrottle::MaybeCreateThrottleFor( + &handle)); +#endif + + if (profile) { + registry.MaybeAddThrottle( + HttpsUpgradesNavigationThrottle::MaybeCreateThrottleFor( + &handle, std::make_unique<ChromeSecurityBlockingPageFactory>(), + profile)); + } + + registry.MaybeAddThrottle(MaybeCreateNavigationAblationThrottle(&handle)); + +#if !BUILDFLAG(IS_ANDROID) + MaybeCreateAndAddWebViewSidePanelThrottle(registry); +#endif + + auto* privacy_sandbox_settings = + PrivacySandboxSettingsFactory::GetForProfile(profile); + if (privacy_sandbox_settings && + privacy_sandbox_settings->AreRelatedWebsiteSetsEnabled()) { + registry.MaybeAddThrottle( + first_party_sets::FirstPartySetsNavigationThrottle:: + MaybeCreateNavigationThrottle(&handle)); + } + +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) + // Don't perform platform authentication in incognito and guest profiles. + if (profile && !profile->IsOffTheRecord()) { + registry.MaybeAddThrottle( + enterprise_auth::PlatformAuthNavigationThrottle::MaybeCreateThrottleFor( + &handle)); + } +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) + +#if BUILDFLAG(IS_CHROMEOS) + // TODO(b:296844164) Handle captive portal signin properly. + if (profile && profile->IsIncognitoProfile() && profile->IsOffTheRecord() && + !profile->GetOTRProfileID().IsCaptivePortal()) { + registry.MaybeAddThrottle( + enterprise_incognito::IncognitoNavigationThrottle:: + MaybeCreateThrottleFor(&handle)); + } + + registry.MaybeAddThrottle( + apps::AppInstallNavigationThrottle::MaybeCreate(&handle)); +#endif // BUILDFLAG(IS_CHROMEOS) + +#if BUILDFLAG(ENABLE_EXTENSIONS_CORE) + if (profile && profile->IsIncognitoProfile() && profile->IsOffTheRecord()) { + registry.MaybeAddThrottle( + enterprise_incognito::IncognitoNavigationThrottle:: + MaybeCreateThrottleFor(&handle)); + } +#endif // BUILDFLAG(ENABLE_EXTENSIONS_CORE) + +#if !BUILDFLAG(IS_ANDROID) + registry.MaybeAddThrottle( + PreviewNavigationThrottle::MaybeCreateThrottleFor(&handle)); +#endif // !BUILDFLAG(IS_ANDROID) + + registry.MaybeAddThrottle( + MaybeCreateVisitedLinkNavigationThrottleFor(&handle)); + + registry.MaybeAddThrottle( + data_sharing::DataSharingNavigationThrottle::MaybeCreateThrottleFor( + &handle)); + +#if !BUILDFLAG(IS_ANDROID) + registry.MaybeAddThrottle( + web_app::IsolatedWebAppThrottle::MaybeCreateThrottleFor(&handle)); +#endif // !BUILDFLAG(IS_ANDROID) }
diff --git a/chrome/browser/chromeos/app_mode/kiosk_browser_window_handler.cc b/chrome/browser/chromeos/app_mode/kiosk_browser_window_handler.cc index 079655ee..c0dacc1 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_browser_window_handler.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_browser_window_handler.cc
@@ -9,22 +9,27 @@ #include <utility> #include "base/check_deref.h" +#include "base/functional/bind.h" +#include "base/functional/callback_forward.h" #include "base/functional/function_ref.h" +#include "base/location.h" #include "base/metrics/histogram_functions.h" #include "base/notreached.h" +#include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" -#include "base/timer/timer.h" #include "chrome/browser/chromeos/app_mode/kiosk_policies.h" #include "chrome/browser/chromeos/app_mode/kiosk_settings_navigation_throttle.h" -#include "chrome/browser/chromeos/app_mode/kiosk_troubleshooting_controller.h" +#include "chrome/browser/chromeos/app_mode/kiosk_troubleshooting_controller_ash.h" #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_window.h" -#include "kiosk_troubleshooting_controller_ash.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -34,6 +39,8 @@ constexpr base::TimeDelta kCloseBrowserTimeout = base::Seconds(2); +#define WINDOW_ALLOWED true + void MakeWindowResizable(BrowserWindow* window) { views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window->GetNativeWindow()); @@ -42,9 +49,12 @@ } } +content::WebContents* GetActiveWebContents(const Browser* browser) { + return browser->tab_strip_model()->GetActiveWebContents(); +} + std::string GetUrlOfActiveTab(const Browser* browser) { - content::WebContents* active_tab = - browser->tab_strip_model()->GetActiveWebContents(); + content::WebContents* active_tab = GetActiveWebContents(browser); return active_tab ? active_tab->GetVisibleURL().spec() : std::string(); } @@ -64,6 +74,48 @@ const char kKioskNewBrowserWindowHistogram[] = "Kiosk.NewBrowserWindow"; +class NavigationWaiter : content::WebContentsObserver { + public: + NavigationWaiter(Browser* browser, base::OnceClosure callback) + : browser_(browser), callback_(std::move(callback)) { + content::WebContents* web_contents = GetActiveWebContents(browser); + if (!web_contents) { + // If no WebContents is present, we'll continue to triaging without a url. + // This is more restrictive and will likely result in the browser window + // being closed. + // One known case of this is a picture-in-picture browser. + LOG(WARNING) << "New browser without WebContents detected."; + RunCallback(); + return; + } + + if (web_contents->GetVisibleURL().is_empty()) { + LOG(WARNING) + << "New browser with empty url detected, Waiting for navigation."; + Observe(GetActiveWebContents(browser)); + } else { + RunCallback(); + } + } + + NavigationWaiter(const NavigationWaiter&) = delete; + NavigationWaiter& operator=(const NavigationWaiter&) = delete; + + private: + // content::WebContentsObserver + void DidStartNavigation(content::NavigationHandle* navigation) override { + RunCallback(); + } + + void RunCallback() { + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, std::move(callback_)); + } + + raw_ptr<Browser> browser_; + base::OnceClosure callback_; +}; + KioskBrowserWindowHandler::KioskBrowserWindowHandler( Profile* profile, const std::optional<std::string>& web_app_name, @@ -91,7 +143,8 @@ BrowserList::RemoveObserver(this); } -void KioskBrowserWindowHandler::HandleNewBrowserWindow(Browser* browser) { +bool KioskBrowserWindowHandler::TriageNewBrowserWindow(Browser* browser) { + url_waiters_.erase(browser); std::string url_string = GetUrlOfActiveTab(browser); if (KioskSettingsNavigationThrottle::IsSettingsPage(url_string)) { @@ -99,7 +152,7 @@ KioskBrowserWindowType::kSettingsPage); HandleNewSettingsWindow(browser, url_string); on_browser_window_added_callback_.Run(/*is_closing=*/false); - return; + return WINDOW_ALLOWED; } if (IsNewBrowserWindowAllowed(browser)) { @@ -110,7 +163,7 @@ << ", url=" << url_string; chrome::ToggleFullscreenMode(browser, /*user_initiated=*/false); on_browser_window_added_callback_.Run(/*is_closing=*/false); - return; + return WINDOW_ALLOWED; } if (IsDevToolsAllowedBrowser(browser)) { @@ -119,7 +172,7 @@ kKioskNewBrowserWindowHistogram, KioskBrowserWindowType::kOpenedDevToolsBrowser); on_browser_window_added_callback_.Run(/*is_closing=*/false); - return; + return WINDOW_ALLOWED; } if (IsNormalTroubleshootingBrowserAllowed(browser)) { @@ -128,7 +181,7 @@ kKioskNewBrowserWindowHistogram, KioskBrowserWindowType::kOpenedTroubleshootingNormalBrowser); on_browser_window_added_callback_.Run(/*is_closing=*/false); - return; + return WINDOW_ALLOWED; } base::UmaHistogramEnumeration(kKioskNewBrowserWindowHistogram, @@ -137,6 +190,7 @@ << ", url=" << url_string; CloseBrowserAndSetTimer(browser); on_browser_window_added_callback_.Run(/*is_closing=*/true); + return !WINDOW_ALLOWED; } void KioskBrowserWindowHandler::HandleNewSettingsWindow( @@ -193,13 +247,32 @@ } void KioskBrowserWindowHandler::OnBrowserAdded(Browser* browser) { + // At this point no WebContents has been added to the browser, so we need to + // post once to ensure we have a WebContents. base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, - base::BindOnce(&KioskBrowserWindowHandler::HandleNewBrowserWindow, + base::BindOnce(&KioskBrowserWindowHandler::OnCompleteBrowserAdded, weak_ptr_factory_.GetWeakPtr(), browser)); } +void KioskBrowserWindowHandler::OnCompleteBrowserAdded(Browser* browser) { + // Hide the window until it is triaged. + browser->window()->Hide(); + + // At this point the URL being opened might still be unknown. + // This URL is required for our triaging, so we'll wait for it. + url_waiters_[browser] = std::make_unique<NavigationWaiter>( + browser, base::BindOnce( + [](KioskBrowserWindowHandler* self, Browser* browser) { + if (self->TriageNewBrowserWindow(browser)) { + browser->window()->Show(); + } + }, + base::Unretained(this), base::Unretained(browser))); +} + void KioskBrowserWindowHandler::OnBrowserRemoved(Browser* browser) { + url_waiters_.erase(browser); closing_browsers_.erase(browser); // Exit the kiosk session if the last browser was closed.
diff --git a/chrome/browser/chromeos/app_mode/kiosk_browser_window_handler.h b/chrome/browser/chromeos/app_mode/kiosk_browser_window_handler.h index 7fa1184..e393cfec 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_browser_window_handler.h +++ b/chrome/browser/chromeos/app_mode/kiosk_browser_window_handler.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_CHROMEOS_APP_MODE_KIOSK_BROWSER_WINDOW_HANDLER_H_ #include <map> +#include <memory> #include "base/functional/callback_forward.h" #include "base/memory/raw_ptr.h" @@ -19,6 +20,7 @@ namespace chromeos { class KioskTroubleshootingController; +class NavigationWaiter; extern const char kKioskNewBrowserWindowHistogram[]; @@ -63,7 +65,8 @@ Browser* GetSettingsBrowserForTesting() { return settings_browser_; } private: - void HandleNewBrowserWindow(Browser* browser); + void OnCompleteBrowserAdded(Browser* browser); + bool TriageNewBrowserWindow(Browser* browser); void HandleNewSettingsWindow(Browser* browser, const std::string& url_string); void CloseBrowserWindowsIf(base::FunctionRef<bool(const Browser&)> filter); @@ -119,6 +122,8 @@ // compromised. std::map<Browser*, base::OneShotTimer> closing_browsers_; + std::map<Browser*, std::unique_ptr<NavigationWaiter>> url_waiters_; + base::WeakPtrFactory<KioskBrowserWindowHandler> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/extensions/api/runtime/runtime_apitest.cc b/chrome/browser/extensions/api/runtime/runtime_apitest.cc index 68f8958b..fb50f03 100644 --- a/chrome/browser/extensions/api/runtime/runtime_apitest.cc +++ b/chrome/browser/extensions/api/runtime/runtime_apitest.cc
@@ -520,8 +520,18 @@ // Tests that when the last active tab in the window belongs to the extension // with an uninstall URL, uninstalling the extension does not close the current // browser. Regression test for crbug.com/362452856 -IN_PROC_BROWSER_TEST_P(RuntimeApiTest, - OpenUninstallUrlWhenExtensionPageIsTheOnlyActiveTab) { +// +// TODO(crbug.com/415617543): Test is flaky on Linux ASan. +#if BUILDFLAG(IS_LINUX) && defined(ADDRESS_SANITIZER) +#define MAYBE_OpenUninstallUrlWhenExtensionPageIsTheOnlyActiveTab \ + DISABLED_OpenUninstallUrlWhenExtensionPageIsTheOnlyActiveTab +#else +#define MAYBE_OpenUninstallUrlWhenExtensionPageIsTheOnlyActiveTab \ + OpenUninstallUrlWhenExtensionPageIsTheOnlyActiveTab +#endif +IN_PROC_BROWSER_TEST_P( + RuntimeApiTest, + MAYBE_OpenUninstallUrlWhenExtensionPageIsTheOnlyActiveTab) { ExtensionTestMessageListener ready_listener("ready"); // Load an extension that has set an uninstall url. scoped_refptr<const Extension> extension =
diff --git a/chrome/browser/extensions/bookmarks/bookmarks_helpers.cc b/chrome/browser/extensions/bookmarks/bookmarks_helpers.cc index 53f87ed..c1fa5f3 100644 --- a/chrome/browser/extensions/bookmarks/bookmarks_helpers.cc +++ b/chrome/browser/extensions/bookmarks/bookmarks_helpers.cc
@@ -78,7 +78,8 @@ const BookmarkNode* parent = node->parent(); if (parent) { out_bookmark_tree_node->parent_id = base::NumberToString(parent->id()); - size_t index = visible_index.value_or(GetAPIIndexOf(*model, *node)); + size_t index = + visible_index ? *visible_index : GetAPIIndexOf(*model, *node); out_bookmark_tree_node->index = base::FeatureList::IsEnabled(kEnforceBookmarkVisibilityOnExtensionsAPI) ? index
diff --git a/chrome/browser/extensions/extension_commands_global_registry.cc b/chrome/browser/extensions/extension_commands_global_registry.cc index e27c8933..afff0d6 100644 --- a/chrome/browser/extensions/extension_commands_global_registry.cc +++ b/chrome/browser/extensions/extension_commands_global_registry.cc
@@ -125,9 +125,8 @@ } } -void ExtensionCommandsGlobalRegistry::RemoveExtensionKeybindingImpl( - const ui::Accelerator& accelerator, - const std::string& command_name) { +void ExtensionCommandsGlobalRegistry::UnregisterAccelerator( + const ui::Accelerator& accelerator) { auto* instance = ui::GlobalAcceleratorListener::GetInstance(); if (!instance) { return;
diff --git a/chrome/browser/extensions/extension_commands_global_registry.h b/chrome/browser/extensions/extension_commands_global_registry.h index 6d63ab0..49d5863 100644 --- a/chrome/browser/extensions/extension_commands_global_registry.h +++ b/chrome/browser/extensions/extension_commands_global_registry.h
@@ -75,8 +75,7 @@ // Overridden from ExtensionKeybindingRegistry: void AddExtensionKeybindings(const Extension* extension, const std::string& command_name) override; - void RemoveExtensionKeybindingImpl(const ui::Accelerator& accelerator, - const std::string& command_name) override; + void UnregisterAccelerator(const ui::Accelerator& accelerator) override; void OnShortcutHandlingSuspended(bool suspended) override; // Called by the GlobalShortcutListener object when a shortcut this class has
diff --git a/chrome/browser/extensions/extension_keybinding_registry.cc b/chrome/browser/extensions/extension_keybinding_registry.cc index c217a4a..197e67f 100644 --- a/chrome/browser/extensions/extension_keybinding_registry.cc +++ b/chrome/browser/extensions/extension_keybinding_registry.cc
@@ -57,6 +57,38 @@ OnShortcutHandlingSuspended(suspended); } +void ExtensionKeybindingRegistry::AddExtensionKeybindings( + const Extension* extension, + const std::string& command_name) { + // This object only handles named commands, not toolbar action execution. + if (ShouldIgnoreCommand(command_name)) { + return; + } + + CommandService* command_service = CommandService::Get(browser_context()); + // Add all the active keybindings (except toolbar action executions, + // which are handled elsewhere). + ui::CommandMap commands; + if (!command_service->GetNamedCommands(extension->id(), + CommandService::ACTIVE, + CommandService::REGULAR, &commands)) { + return; + } + ui::CommandMap::const_iterator iter = commands.begin(); + for (; iter != commands.end(); ++iter) { + if (!command_name.empty() && + (iter->second.command_name() != command_name)) { + continue; + } + const ui::Accelerator& accelerator = iter->second.accelerator(); + if (!IsAcceleratorRegistered(accelerator)) { + RegisterAccelerator(accelerator); + } + + AddEventTarget(accelerator, extension->id(), iter->second.command_name()); + } +} + void ExtensionKeybindingRegistry::RemoveExtensionKeybinding( const Extension* extension, const std::string& command_name) { @@ -76,7 +108,7 @@ auto old = it++; if (target_list.empty()) { // Let each platform-specific implementation get a chance to clean up. - RemoveExtensionKeybindingImpl(old->first, command_name); + UnregisterAccelerator(old->first); if (old->first.IsMediaKey()) { any_media_keys_removed = true;
diff --git a/chrome/browser/extensions/extension_keybinding_registry.h b/chrome/browser/extensions/extension_keybinding_registry.h index e3d1638..e1bbe91 100644 --- a/chrome/browser/extensions/extension_keybinding_registry.h +++ b/chrome/browser/extensions/extension_keybinding_registry.h
@@ -74,19 +74,20 @@ // Add extension keybindings for the events defined by the `extension`. // `command_name` is optional, but if not blank then only the command // specified will be added. - virtual void AddExtensionKeybindings( - const Extension* extension, - const std::string& command_name) = 0; + virtual void AddExtensionKeybindings(const Extension* extension, + const std::string& command_name); // Remove extension bindings for `extension`. `command_name` is optional, // but if not blank then only the command specified will be removed. void RemoveExtensionKeybinding( const Extension* extension, const std::string& command_name); + + // Overridden by platform specific implementations to provide additional + // registration (which varies between platforms). + virtual void RegisterAccelerator(const ui::Accelerator& accelerator) {} // Overridden by platform specific implementations to provide additional // unregistration (which varies between platforms). - virtual void RemoveExtensionKeybindingImpl( - const ui::Accelerator& accelerator, - const std::string& command_name) = 0; + virtual void UnregisterAccelerator(const ui::Accelerator& accelerator) {} // Called when shortcut handling is suspended or resumed. virtual void OnShortcutHandlingSuspended(bool suspended) {}
diff --git a/chrome/browser/extensions/gpu_browsertest.cc b/chrome/browser/extensions/gpu_browsertest.cc index 0013954..0a6f653 100644 --- a/chrome/browser/extensions/gpu_browsertest.cc +++ b/chrome/browser/extensions/gpu_browsertest.cc
@@ -22,8 +22,7 @@ ProcessManager* manager = ProcessManager::Get(browser()->profile()); ExtensionHost* host = FindHostWithPath(manager, "/backgroundpage.html", 1); - ASSERT_TRUE(host->host_contents()->GetDelegate()->IsNeverComposited( - host->host_contents())); + ASSERT_TRUE(host->host_contents()->IsNeverComposited()); } } // namespace extensions
diff --git a/chrome/browser/extensions/offscreen_document_browsertest.cc b/chrome/browser/extensions/offscreen_document_browsertest.cc index b2038ec..f908e5d 100644 --- a/chrome/browser/extensions/offscreen_document_browsertest.cc +++ b/chrome/browser/extensions/offscreen_document_browsertest.cc
@@ -108,7 +108,7 @@ EXPECT_EQ(mojom::ViewType::kOffscreenDocument, GetViewType(contents)); // The offscreen document should be marked as never composited, excluding it // from certain a11y considerations. - EXPECT_TRUE(contents->GetDelegate()->IsNeverComposited(contents)); + EXPECT_TRUE(contents->IsNeverComposited()); { // Check the registration in the ProcessManager: the offscreen document
diff --git a/chrome/browser/facilitated_payments/BUILD.gn b/chrome/browser/facilitated_payments/BUILD.gn index e590b55..82eb60e8 100644 --- a/chrome/browser/facilitated_payments/BUILD.gn +++ b/chrome/browser/facilitated_payments/BUILD.gn
@@ -34,6 +34,7 @@ ":facilitated_payments", "//base", "//chrome/test:test_support", + "//components/facilitated_payments/core/browser", "//components/facilitated_payments/core/features", "//components/optimization_guide/core:test_support", ]
diff --git a/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client_unittest.cc b/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client_unittest.cc index 84e98fdc..58db397 100644 --- a/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client_unittest.cc +++ b/chrome/browser/facilitated_payments/ui/chrome_facilitated_payments_client_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "components/facilitated_payments/core/browser/pix_account_linking_manager.h" #include "components/facilitated_payments/core/features/features.h" #include "components/optimization_guide/core/mock_optimization_guide_decider.h" #include "testing/gmock/include/gmock/gmock.h" @@ -37,6 +38,14 @@ MOCK_METHOD(void, Dismiss, (), (override)); }; +class MockPixAccountLinkingManager + : public payments::facilitated::PixAccountLinkingManager { + public: + ~MockPixAccountLinkingManager() override = default; + + MOCK_METHOD(void, MaybeShowPixAccountLinkingPrompt, (), (override)); +}; + class ChromeFacilitatedPaymentsClientTest : public ChromeRenderViewHostTestHarness { public: @@ -48,6 +57,11 @@ std::make_unique<MockFacilitatedPaymentsController>(web_contents()); controller_ = controller.get(); client_->SetFacilitatedPaymentsControllerForTesting(std::move(controller)); + auto pix_account_linking_manager = + std::make_unique<MockPixAccountLinkingManager>(); + pix_account_linking_manager_ = pix_account_linking_manager.get(); + client_->SetPixAccountLinkingManagerForTesting( + std::move(pix_account_linking_manager)); } void TearDown() override { @@ -61,10 +75,15 @@ MockFacilitatedPaymentsController& controller() { return *controller_; } + MockPixAccountLinkingManager& pix_account_linking_manager() { + return *pix_account_linking_manager_; + } + protected: optimization_guide::MockOptimizationGuideDecider optimization_guide_decider_; std::unique_ptr<ChromeFacilitatedPaymentsClient> client_; raw_ptr<MockFacilitatedPaymentsController> controller_; + raw_ptr<MockPixAccountLinkingManager> pix_account_linking_manager_; }; TEST_F(ChromeFacilitatedPaymentsClientTest, GetPaymentsDataManager) { @@ -174,3 +193,11 @@ EXPECT_CALL(controller(), ShowForEwallet); base_client().ShowEwalletPaymentPrompt({}, base::DoNothing()); } + +// Test that the client forwards call to initiate Pix account linking flow to +// the Pix account linking manager. +TEST_F(ChromeFacilitatedPaymentsClientTest, InitPixAccountLinkingFlow) { + EXPECT_CALL(pix_account_linking_manager(), MaybeShowPixAccountLinkingPrompt); + + base_client().InitPixAccountLinkingFlow(); +}
diff --git a/chrome/browser/prefs/BUILD.gn b/chrome/browser/prefs/BUILD.gn index e77a1e19..330485b6 100644 --- a/chrome/browser/prefs/BUILD.gn +++ b/chrome/browser/prefs/BUILD.gn
@@ -31,8 +31,16 @@ "//components/sync_preferences", "//mojo/public/cpp/bindings", "//services/preferences/public/mojom", + "//third_party/blink/public/mojom:mojom_platform_headers", "//url", ] + + if (!is_android) { + sources += [ + "persistent_renderer_prefs_manager.h", + "persistent_renderer_prefs_manager_factory.h", + ] + } } source_set("impl") { @@ -288,6 +296,10 @@ "//components/live_caption", "//components/live_caption:live_translate", ] + sources += [ + "persistent_renderer_prefs_manager.cc", + "persistent_renderer_prefs_manager_factory.cc", + ] } if (enable_extensions) { @@ -433,6 +445,10 @@ "//ui/base", "//url", ] + + if (!is_android) { + sources += [ "persistent_renderer_prefs_unittest.cc" ] + } } if (!is_android) {
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 8a39797e..61746b09 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -2299,6 +2299,8 @@ registry->RegisterIntegerPref(prefs::kLensOverlayStartCount, 0); registry->RegisterDictionaryPref(prefs::kReportingEndpoints); + + registry->RegisterBooleanPref(prefs::kViewSourceLineWrappingEnabled, false); } void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
diff --git a/chrome/browser/prefs/persistent_renderer_prefs_manager.cc b/chrome/browser/prefs/persistent_renderer_prefs_manager.cc new file mode 100644 index 0000000..06bc61bc --- /dev/null +++ b/chrome/browser/prefs/persistent_renderer_prefs_manager.cc
@@ -0,0 +1,41 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/prefs/persistent_renderer_prefs_manager.h" + +#include "chrome/browser/prefs/persistent_renderer_prefs_manager_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" + +PersistentRendererPrefsManager::PersistentRendererPrefsManager( + PrefService& pref_service) + : pref_service_(pref_service) {} + +PersistentRendererPrefsManager::~PersistentRendererPrefsManager() = default; + +void PersistentRendererPrefsManager::SetViewSourceLineWrapping(bool value) { + pref_service_->SetBoolean(prefs::kViewSourceLineWrappingEnabled, value); +} + +void PersistentRendererPrefsManager::BindFrameReceiver( + content::RenderFrameHost* frame, + mojo::PendingReceiver<blink::mojom::PersistentRendererPrefsService> + receiver) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + auto* profile = Profile::FromBrowserContext(frame->GetBrowserContext()); + + auto* persistent_renderer_prefs_manager = + PersistentRendererPrefsManagerFactory::GetInstance()->GetForProfile( + profile); + if (!persistent_renderer_prefs_manager) { + return; + } + + persistent_renderer_prefs_manager->receivers_.Add( + persistent_renderer_prefs_manager, std::move(receiver)); +}
diff --git a/chrome/browser/prefs/persistent_renderer_prefs_manager.h b/chrome/browser/prefs/persistent_renderer_prefs_manager.h new file mode 100644 index 0000000..748157f9 --- /dev/null +++ b/chrome/browser/prefs/persistent_renderer_prefs_manager.h
@@ -0,0 +1,50 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PREFS_PERSISTENT_RENDERER_PREFS_MANAGER_H_ +#define CHROME_BROWSER_PREFS_PERSISTENT_RENDERER_PREFS_MANAGER_H_ + +#include "base/memory/raw_ref.h" +#include "components/keyed_service/core/keyed_service.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "third_party/blink/public/mojom/persistent_renderer_prefs.mojom.h" + +class PrefService; + +namespace content { +class RenderFrameHost; +} + +// This class is used for updating profile-specific renderer preferences +// from within blink. See +// third_party/blink/public/mojom/persistent_renderer_prefs.mojom for more +// details. +class PersistentRendererPrefsManager + : public KeyedService, + public blink::mojom::PersistentRendererPrefsService { + public: + explicit PersistentRendererPrefsManager(PrefService& pref_service); + + PersistentRendererPrefsManager(const PersistentRendererPrefsManager&) = + delete; + PersistentRendererPrefsManager& operator=( + const PersistentRendererPrefsManager&) = delete; + + ~PersistentRendererPrefsManager() override; + + static void BindFrameReceiver( + content::RenderFrameHost* frame, + mojo::PendingReceiver<blink::mojom::PersistentRendererPrefsService> + receiver); + + private: + friend class TestPersistentRendererPrefsManager; + + void SetViewSourceLineWrapping(bool value) override; + + const raw_ref<PrefService> pref_service_; + mojo::ReceiverSet<blink::mojom::PersistentRendererPrefsService> receivers_; +}; + +#endif // CHROME_BROWSER_PREFS_PERSISTENT_RENDERER_PREFS_MANAGER_H_
diff --git a/chrome/browser/prefs/persistent_renderer_prefs_manager_factory.cc b/chrome/browser/prefs/persistent_renderer_prefs_manager_factory.cc new file mode 100644 index 0000000..905eea6 --- /dev/null +++ b/chrome/browser/prefs/persistent_renderer_prefs_manager_factory.cc
@@ -0,0 +1,46 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/prefs/persistent_renderer_prefs_manager_factory.h" + +#include <memory> + +#include "base/memory/ptr_util.h" +#include "base/no_destructor.h" +#include "chrome/browser/prefs/persistent_renderer_prefs_manager.h" +#include "chrome/browser/profiles/profile.h" +#include "components/prefs/pref_service.h" + +// static +PersistentRendererPrefsManager* +PersistentRendererPrefsManagerFactory::GetForProfile(Profile* profile) { + return static_cast<PersistentRendererPrefsManager*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +// static +PersistentRendererPrefsManagerFactory* +PersistentRendererPrefsManagerFactory::GetInstance() { + static base::NoDestructor<PersistentRendererPrefsManagerFactory> instance; + return instance.get(); +} + +PersistentRendererPrefsManagerFactory::PersistentRendererPrefsManagerFactory() + : ProfileKeyedServiceFactory( + "PersistentRendererPrefsManager", + ProfileSelections::Builder() + .WithRegular(ProfileSelection::kRedirectedToOriginal) + .WithGuest(ProfileSelection::kOwnInstance) + .WithAshInternals(ProfileSelection::kOwnInstance) + .Build()) {} + +PersistentRendererPrefsManagerFactory:: + ~PersistentRendererPrefsManagerFactory() = default; + +std::unique_ptr<KeyedService> +PersistentRendererPrefsManagerFactory::BuildServiceInstanceForBrowserContext( + content::BrowserContext* context) const { + return std::make_unique<PersistentRendererPrefsManager>( + *Profile::FromBrowserContext(context)->GetPrefs()); +}
diff --git a/chrome/browser/prefs/persistent_renderer_prefs_manager_factory.h b/chrome/browser/prefs/persistent_renderer_prefs_manager_factory.h new file mode 100644 index 0000000..b48b070 --- /dev/null +++ b/chrome/browser/prefs/persistent_renderer_prefs_manager_factory.h
@@ -0,0 +1,44 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PREFS_PERSISTENT_RENDERER_PREFS_MANAGER_FACTORY_H_ +#define CHROME_BROWSER_PREFS_PERSISTENT_RENDERER_PREFS_MANAGER_FACTORY_H_ + +#include "chrome/browser/profiles/profile_keyed_service_factory.h" + +namespace base { +template <typename T> +class NoDestructor; +} + +class Profile; + +class PersistentRendererPrefsManager; + +// Singleton that provides access to Profile specific +// PersistentRendererPrefsManagers. +class PersistentRendererPrefsManagerFactory + : public ProfileKeyedServiceFactory { + public: + static PersistentRendererPrefsManager* GetForProfile(Profile* profile); + + static PersistentRendererPrefsManagerFactory* GetInstance(); + + PersistentRendererPrefsManagerFactory( + const PersistentRendererPrefsManagerFactory&) = delete; + PersistentRendererPrefsManagerFactory& operator=( + const PersistentRendererPrefsManagerFactory&) = delete; + + private: + friend base::NoDestructor<PersistentRendererPrefsManagerFactory>; + + PersistentRendererPrefsManagerFactory(); + ~PersistentRendererPrefsManagerFactory() override; + + // BrowserContextKeyedServiceFactory + std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext( + content::BrowserContext* profile) const override; +}; + +#endif // CHROME_BROWSER_PREFS_PERSISTENT_RENDERER_PREFS_MANAGER_FACTORY_H_
diff --git a/chrome/browser/prefs/persistent_renderer_prefs_unittest.cc b/chrome/browser/prefs/persistent_renderer_prefs_unittest.cc new file mode 100644 index 0000000..9e26bf43 --- /dev/null +++ b/chrome/browser/prefs/persistent_renderer_prefs_unittest.cc
@@ -0,0 +1,40 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/raw_ptr.h" +#include "chrome/browser/prefs/persistent_renderer_prefs_manager.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/testing_profile.h" +#include "components/prefs/pref_service.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +class TestPersistentRendererPrefsManager : PersistentRendererPrefsManager { + public: + explicit TestPersistentRendererPrefsManager(PrefService& pref_service) + : PersistentRendererPrefsManager(pref_service) {} + void TestSetViewSourceLineWrapping(bool value) { + SetViewSourceLineWrapping(value); + } +}; + +// Observe that changes made through the persistent renderer prefs service are +// reflected in the profile backing it. +TEST(PersistentRendererPrefsTest, ObservePrefChanges) { + content::BrowserTaskEnvironment task_environment; + TestingProfile profile; + TestPersistentRendererPrefsManager persistent_renderer_prefs_manager( + *profile.GetPrefs()); + + EXPECT_FALSE( + profile.GetPrefs()->GetBoolean(prefs::kViewSourceLineWrappingEnabled)); + + persistent_renderer_prefs_manager.TestSetViewSourceLineWrapping(true); + EXPECT_TRUE( + profile.GetPrefs()->GetBoolean(prefs::kViewSourceLineWrappingEnabled)); + persistent_renderer_prefs_manager.TestSetViewSourceLineWrapping(false); + EXPECT_FALSE( + profile.GetPrefs()->GetBoolean(prefs::kViewSourceLineWrappingEnabled)); +}
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index 7c400e0..f4e2485 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -324,6 +324,7 @@ #include "chrome/browser/new_tab_page/promos/promo_service_factory.h" #include "chrome/browser/passage_embeddings/passage_embeddings_coordinator_factory.h" #include "chrome/browser/payments/payment_request_display_manager_factory.h" +#include "chrome/browser/prefs/persistent_renderer_prefs_manager_factory.h" #include "chrome/browser/privacy_sandbox/privacy_sandbox_survey_desktop_controller_factory.h" #include "chrome/browser/profile_resetter/reset_report_uploader_factory.h" #include "chrome/browser/screen_ai/screen_ai_service_router_factory.h" @@ -1121,6 +1122,7 @@ PermissionActionsHistoryFactory::GetInstance(); PermissionDecisionAutoBlockerFactory::GetInstance(); #if !BUILDFLAG(IS_ANDROID) + PersistentRendererPrefsManagerFactory::GetInstance(); PinnedTabServiceFactory::GetInstance(); PinnedToolbarActionsModelFactory::GetInstance(); #endif
diff --git a/chrome/browser/renderer_preferences_util.cc b/chrome/browser/renderer_preferences_util.cc index 4679192..9d302c8 100644 --- a/chrome/browser/renderer_preferences_util.cc +++ b/chrome/browser/renderer_preferences_util.cc
@@ -226,6 +226,9 @@ #else prefs->focus_ring_color = SkColorSetRGB(0x10, 0x10, 0x10); #endif + + prefs->view_source_line_wrap_enabled = + pref_service->GetBoolean(prefs::kViewSourceLineWrappingEnabled); } } // namespace renderer_preferences_util
diff --git a/chrome/browser/resources/bookmarks/promo_card.css b/chrome/browser/resources/bookmarks/promo_card.css index 774885e..4422a540 100644 --- a/chrome/browser/resources/bookmarks/promo_card.css +++ b/chrome/browser/resources/bookmarks/promo_card.css
@@ -18,6 +18,7 @@ display: flex; flex-direction: row; padding: 12px 16px; + width: 100%; } #image {
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/autoclick/autoclick_test.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/autoclick/autoclick_test.js index f631d3f..074899a 100644 --- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/autoclick/autoclick_test.js +++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/autoclick/autoclick_test.js
@@ -38,6 +38,7 @@ #include "base/functional/bind.h" #include "base/functional/callback.h" #include "chrome/browser/ash/accessibility/accessibility_manager.h" +#include "ui/accessibility/accessibility_features.h" `); } @@ -52,6 +53,11 @@ super.testGenPreambleCommon('kAccessibilityCommonExtensionId'); } + /** @override */ + get featureList() { + return {enabled: ['features::kAccessibilityManifestV3AccessibilityCommon']}; + } + /** * Asserts that two rects are the same. * @param {!chrome.accessibilityPrivate.ScreenRect} first
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js index 6f5c4d77..a4b6e9f5 100644 --- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js +++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js
@@ -52,6 +52,7 @@ return { enabled: [ 'features::kAccessibilityMagnifierFollowsChromeVox', + 'features::kAccessibilityManifestV3AccessibilityCommon' ], }; } @@ -328,25 +329,30 @@ await typeWordsAssertBounds({left: 1200, top: 100, width: 0, height: 0}); }); -TEST_F('MagnifierE2ETest', 'ScreenMagnifierFocusFollowingPref', function() { - this.newCallback(async () => { - // Disable focus following for full screen magnifier, and verify prefs and - // state. - await this.setPref(Magnifier.Prefs.SCREEN_MAGNIFIER_FOCUS_FOLLOWING, false); - magnifier = accessibilityCommon.getMagnifierForTest(); - magnifier.setIsInitializingForTest(false); - assertEquals(magnifier.type, Magnifier.Type.FULL_SCREEN); - assertFalse(magnifier.shouldFollowFocus()); +// TODO(crbug.com/417066488): Test is flaky. +TEST_F( + 'MagnifierE2ETest', 'DISABLED_ScreenMagnifierFocusFollowingPref', + function() { + this.newCallback(async () => { + // Disable focus following for full screen magnifier, and verify prefs + // and state. + await this.setPref( + Magnifier.Prefs.SCREEN_MAGNIFIER_FOCUS_FOLLOWING, false); + magnifier = accessibilityCommon.getMagnifierForTest(); + magnifier.setIsInitializingForTest(false); + assertEquals(magnifier.type, Magnifier.Type.FULL_SCREEN); + assertFalse(magnifier.shouldFollowFocus()); - // Enable focus following for full screen magnifier, and verify prefs and - // state. - await this.setPref(Magnifier.Prefs.SCREEN_MAGNIFIER_FOCUS_FOLLOWING, true); - magnifier = accessibilityCommon.getMagnifierForTest(); - magnifier.setIsInitializingForTest(false); - assertEquals(magnifier.type, Magnifier.Type.FULL_SCREEN); - assertTrue(magnifier.shouldFollowFocus()); - })(); -}); + // Enable focus following for full screen magnifier, and verify prefs + // and state. + await this.setPref( + Magnifier.Prefs.SCREEN_MAGNIFIER_FOCUS_FOLLOWING, true); + magnifier = accessibilityCommon.getMagnifierForTest(); + magnifier.setIsInitializingForTest(false); + assertEquals(magnifier.type, Magnifier.Type.FULL_SCREEN); + assertTrue(magnifier.shouldFollowFocus()); + })(); + }); TEST_F( 'MagnifierE2ETest', 'ScreenMagnifierSelectToSpeakFollowingPref',
diff --git a/chrome/browser/screen_ai/optical_character_recognizer_browsertest.cc b/chrome/browser/screen_ai/optical_character_recognizer_browsertest.cc index 998cdd11..d3b8dcd4 100644 --- a/chrome/browser/screen_ai/optical_character_recognizer_browsertest.cc +++ b/chrome/browser/screen_ai/optical_character_recognizer_browsertest.cc
@@ -16,6 +16,7 @@ #include "base/strings/stringprintf.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_run_loop_timeout.h" #include "base/test/test_future.h" #include "build/build_config.h" #include "chrome/browser/profiles/profile.h" @@ -650,9 +651,9 @@ OpticalCharacterRecognizerResultsTest, testing::ValuesIn(kTestFilenames)); -// TODO(https://crbug.com/408145905): Flaky and failing on mac-osxbeta-rel and -// Linux Tests (dbg)(1). -#if BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_LINUX) && !defined(NDEBUG)) +// This test is slow and most probably failing on debug builds and ASAN builds +// which are slower than the other tests. +#if !defined(NDEBUG) || defined(ADDRESS_SANITIZER) #define MAYBE_PerformOCRLargeImage DISABLED_PerformOCRLargeImage #else #define MAYBE_PerformOCRLargeImage PerformOCRLargeImage @@ -661,6 +662,9 @@ MAYBE_PerformOCRLargeImage) { base::HistogramTester histograms; + // Since this test processes a huge image, it can be slow and overrun the + // timeout. + base::test::ScopedDisableRunLoopTimeout disable_timeout; base::ScopedAllowBlockingForTesting allow_blocking; ASSERT_TRUE(CreateAndInitOCR());
diff --git a/chrome/browser/signin/e2e_tests/live_sign_in_test.cc b/chrome/browser/signin/e2e_tests/live_sign_in_test.cc index aef69c9..d1fc3352 100644 --- a/chrome/browser/signin/e2e_tests/live_sign_in_test.cc +++ b/chrome/browser/signin/e2e_tests/live_sign_in_test.cc
@@ -172,8 +172,9 @@ accounts_in_cookie_jar_1.GetPotentiallyInvalidSignedInAccounts()[0]; EXPECT_TRUE(gaia::AreEmailsSame(test_account->user, account_1.email)); EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(account_1.id)); + // Web signin does not automatically propagate to Chrome. EXPECT_FALSE( - identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync)); + identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSignin)); std::optional<TestAccountSigninCredentials> test_account_2 = GetTestAccounts()->GetAccount("TEST_ACCOUNT_2"); @@ -195,7 +196,7 @@ EXPECT_TRUE(gaia::AreEmailsSame(test_account_2->user, account_2.email)); EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(account_2.id)); EXPECT_FALSE( - identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync)); + identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSignin)); sign_in_functions.SignOutFromWeb(); @@ -319,26 +320,33 @@ // See crbug.com/1025335. // Starts the sign in flow from the settings page, enters credentials on the // login page but cancels the Sync confirmation dialog. Checks that Sync is -// disabled and no account was added to Chrome. +// disabled but the account is still signed in to Chrome. IN_PROC_BROWSER_TEST_F(LiveSignInTest, MANUAL_CancelSync) { std::optional<TestAccountSigninCredentials> test_account = GetTestAccounts()->GetAccount("TEST_ACCOUNT_1"); CHECK(test_account.has_value()); sign_in_functions.SignInFromSettings(*test_account, 0); - SignInTestObserver observer(identity_manager(), account_reconcilor()); EXPECT_TRUE(login_ui_test_utils::CancelSyncConfirmationDialog( browser(), kDialogTimeout)); - observer.WaitForAccountChanges(0, PrimarySyncAccountWait::kWaitForCleared); + // The account is still signed in, but not syncing. + EXPECT_FALSE( + identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync)); + EXPECT_TRUE( + identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSignin)); const AccountsInCookieJarInfo& accounts_in_cookie_jar = identity_manager()->GetAccountsInCookieJar(); EXPECT_TRUE(accounts_in_cookie_jar.AreAccountsFresh()); - EXPECT_TRUE( - accounts_in_cookie_jar.GetPotentiallyInvalidSignedInAccounts().empty()); - EXPECT_TRUE(identity_manager()->GetAccountsWithRefreshTokens().empty()); - EXPECT_FALSE( - identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync)); + ASSERT_EQ( + 1u, + accounts_in_cookie_jar.GetPotentiallyInvalidSignedInAccounts().size()); + EXPECT_TRUE(accounts_in_cookie_jar.GetSignedOutAccounts().empty()); + const gaia::ListedAccount& account = + accounts_in_cookie_jar.GetPotentiallyInvalidSignedInAccounts()[0]; + EXPECT_TRUE(gaia::AreEmailsSame(test_account->user, account.email)); + EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(account.id)); + EXPECT_FALSE(sync_service()->IsSyncFeatureEnabled()); } // This test can pass. Marked as manual because it TIMED_OUT on Win7. @@ -487,8 +495,8 @@ // This test can pass. Marked as manual because it TIMED_OUT on Win7. // See crbug.com/1025335. // Enables and disables sync to account 1. Enables sync to account 2 and clicks -// on "Cancel" in the email confirmation dialog. Checks that the signin flow is -// canceled and no accounts are added to Chrome. +// on "Cancel" in the email confirmation dialog. Checks that the account is left +// signed in without syncing. IN_PROC_BROWSER_TEST_F(LiveSignInTest, MANUAL_SyncSecondAccount_CancelOnEmailConfirmation) { // Enable and disable sync for the first account. @@ -509,26 +517,35 @@ EXPECT_EQ(profile_manager->GetNumberOfProfiles(), 1U); EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U); - // Click "Cancel" on the email confirmation dialog and wait for an account to - // removed from Chrome. - SignInTestObserver observer(identity_manager(), account_reconcilor()); + // Click "Cancel" on the email confirmation dialog. EXPECT_TRUE(login_ui_test_utils::CompleteSigninEmailConfirmationDialog( browser(), kDialogTimeout, SigninEmailConfirmationDialog::CLOSE)); - observer.WaitForAccountChanges(0, PrimarySyncAccountWait::kWaitForCleared); // Check no profile was created. EXPECT_EQ(profile_manager->GetNumberOfProfiles(), 1U); EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U); - // Check Chrome has no accounts. + // The account is still signed in, but not syncing. + EXPECT_FALSE( + identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync)); + EXPECT_TRUE( + identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSignin)); + const AccountsInCookieJarInfo& accounts_in_cookie_jar = identity_manager()->GetAccountsInCookieJar(); EXPECT_TRUE(accounts_in_cookie_jar.AreAccountsFresh()); - EXPECT_TRUE( - accounts_in_cookie_jar.GetPotentiallyInvalidSignedInAccounts().empty()); - EXPECT_TRUE(identity_manager()->GetAccountsWithRefreshTokens().empty()); - EXPECT_FALSE( - identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync)); + ASSERT_EQ( + 1u, + accounts_in_cookie_jar.GetPotentiallyInvalidSignedInAccounts().size()); + ASSERT_EQ(1u, accounts_in_cookie_jar.GetSignedOutAccounts().size()); + EXPECT_TRUE(gaia::AreEmailsSame( + test_account_1->user, + accounts_in_cookie_jar.GetSignedOutAccounts()[0].email)); + const gaia::ListedAccount& account = + accounts_in_cookie_jar.GetPotentiallyInvalidSignedInAccounts()[0]; + EXPECT_TRUE(gaia::AreEmailsSame(test_account_2->user, account.email)); + EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(account.id)); + EXPECT_FALSE(sync_service()->IsSyncFeatureEnabled()); } IN_PROC_BROWSER_TEST_F(LiveSignInTest,
diff --git a/chrome/browser/ui/prefs/pref_watcher.cc b/chrome/browser/ui/prefs/pref_watcher.cc index 1871b2b0..1c7d3b2 100644 --- a/chrome/browser/ui/prefs/pref_watcher.cc +++ b/chrome/browser/ui/prefs/pref_watcher.cc
@@ -125,6 +125,9 @@ renderer_callback); #endif + profile_pref_change_registrar_.Add(prefs::kViewSourceLineWrappingEnabled, + renderer_callback); + PrefChangeRegistrar::NamedChangeCallback webkit_callback = base::BindRepeating(&PrefWatcher::OnWebPrefChanged, base::Unretained(this));
diff --git a/chrome/browser/ui/safety_hub/OWNERS b/chrome/browser/ui/safety_hub/OWNERS index 3b124853..95aa19f 100644 --- a/chrome/browser/ui/safety_hub/OWNERS +++ b/chrome/browser/ui/safety_hub/OWNERS
@@ -1,8 +1,7 @@ sideyilmaz@chromium.org msramek@chromium.org tov@chromium.org +olesiamarukhno@google.com -per-file disruptive_notification_permissions_manager*=olesiamarukhno@google.com per-file disruptive_notification_permissions_manager*=antoniosartori@chromium.org -per-file notification_wrapper_android*=olesiamarukhno@google.com per-file notification_wrapper_android*=antoniosartori@chromium.org
diff --git a/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.cc b/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.cc index 23d28c1..99295d41 100644 --- a/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.cc +++ b/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.cc
@@ -27,43 +27,14 @@ focus_manager_->UnregisterAccelerators(this); } -void ExtensionKeybindingRegistryViews::AddExtensionKeybindings( - const extensions::Extension* extension, - const std::string& command_name) { - // This object only handles named commands, not browser/page actions. - if (ShouldIgnoreCommand(command_name)) { - return; - } - - extensions::CommandService* command_service = - extensions::CommandService::Get(profile_); - // Add all the active keybindings (except page actions and browser actions, - // which are handled elsewhere). - ui::CommandMap commands; - if (!command_service->GetNamedCommands( - extension->id(), extensions::CommandService::ACTIVE, - extensions::CommandService::REGULAR, &commands)) { - return; - } - ui::CommandMap::const_iterator iter = commands.begin(); - for (; iter != commands.end(); ++iter) { - if (!command_name.empty() && - (iter->second.command_name() != command_name)) { - continue; - } - const ui::Accelerator& accelerator = iter->second.accelerator(); - if (!IsAcceleratorRegistered(accelerator)) { - focus_manager_->RegisterAccelerator(accelerator, - kExtensionAcceleratorPriority, this); - } - - AddEventTarget(accelerator, extension->id(), iter->second.command_name()); - } +void ExtensionKeybindingRegistryViews::RegisterAccelerator( + const ui::Accelerator& accelerator) { + focus_manager_->RegisterAccelerator(accelerator, + kExtensionAcceleratorPriority, this); } -void ExtensionKeybindingRegistryViews::RemoveExtensionKeybindingImpl( - const ui::Accelerator& accelerator, - const std::string& command_name) { +void ExtensionKeybindingRegistryViews::UnregisterAccelerator( + const ui::Accelerator& accelerator) { focus_manager_->UnregisterAccelerator(accelerator, this); }
diff --git a/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h b/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h index 52786fd..c27b4634 100644 --- a/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h +++ b/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h
@@ -5,8 +5,6 @@ #ifndef CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_VIEWS_H_ #define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_VIEWS_H_ -#include <string> - #include "base/memory/raw_ptr.h" #include "chrome/browser/extensions/extension_keybinding_registry.h" #include "ui/base/accelerators/accelerator.h" @@ -49,10 +47,8 @@ private: // Overridden from ExtensionKeybindingRegistry: - void AddExtensionKeybindings(const extensions::Extension* extension, - const std::string& command_name) override; - void RemoveExtensionKeybindingImpl(const ui::Accelerator& accelerator, - const std::string& command_name) override; + void RegisterAccelerator(const ui::Accelerator& accelerator) override; + void UnregisterAccelerator(const ui::Accelerator& accelerator) override; void OnShortcutHandlingSuspended(bool suspended) override; // Weak pointer to the our profile. Not owned by us.
diff --git a/chrome/browser/ui/views/frame/browser_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_view_browsertest.cc index b2d0d089..5c0d69f 100644 --- a/chrome/browser/ui/views/frame/browser_view_browsertest.cc +++ b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
@@ -264,7 +264,7 @@ EXPECT_EQ(full_bounds, contents_web_view()->bounds()); } -// Verifies that the side panel's rounded corner is being correctly layed out. +// Verifies that the side panel's rounded corner is being correctly laid out. IN_PROC_BROWSER_TEST_F(BrowserViewTest, SidePanelRoundedCornerLayout) { SidePanelCoordinator* coordinator = (browser())->GetFeatures().side_panel_coordinator(); @@ -272,7 +272,7 @@ coordinator->Show(SidePanelEntry::Id::kBookmarks); EXPECT_EQ(side_panel()->bounds().x(), side_panel_rounded_corner()->bounds().right()); - EXPECT_EQ(side_panel()->bounds().y(), + EXPECT_EQ(side_panel()->bounds().y() - views::Separator::kThickness, side_panel_rounded_corner()->bounds().y()); }
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc index f13479e0..e1f11e3e 100644 --- a/chrome/browser/ui/views/frame/browser_view_layout.cc +++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -85,6 +85,15 @@ constexpr int BrowserViewLayout::kMainBrowserContentsMinimumWidth; +struct BrowserViewLayout::ContentsContainerLayoutResult { + gfx::Rect contents_container_bounds; + gfx::Rect side_panel_bounds; + bool side_panel_visible; + bool side_panel_right_aligned; + bool contents_container_after_side_panel; + gfx::Rect separator_bounds; +}; + class BrowserViewLayout::WebContentsModalDialogHostViews : public WebContentsModalDialogHost, public views::WidgetObserver { @@ -112,13 +121,35 @@ observer_list_.Notify(&ModalDialogHostObserver::OnPositionRequiresUpdate); } - gfx::Point GetDialogPosition(const gfx::Size& size) override { + gfx::Point GetDialogPosition(const gfx::Size& dialog_size) override { // Horizontally places the dialog at the center of the content. + views::View* view = browser_view_layout_->contents_container_; - gfx::Rect rect = view->ConvertRectToWidget(view->GetLocalBounds()); - const int middle_x = rect.x() + rect.width() / 2; - const int top = browser_view_layout_->dialog_top_y_; - return gfx::Point(middle_x - size.width() / 2, top); + // Recalculate bounds of `contents_container_`. It may be stale due to + // pending layouts (from switching tabs, for example). The `top` and + // `bottom` parameters should not be relevant to the result, since we only + // care about the resulting width here. + BrowserViewLayout::ContentsContainerLayoutResult layout_result = + browser_view_layout_->CalculateContentsContainerLayout( + view->bounds().y(), view->bounds().bottom()); + + int leading_x; + if (base::i18n::IsRTL()) { + // Dialog coordinates are not flipped for RTL, but the View's coordinates + // are. Calculate the left edge of `contents_container_bounds`. + if (layout_result.contents_container_after_side_panel) { + leading_x = 0; + } else { + leading_x = browser_view_layout_->vertical_layout_rect_.width() - + layout_result.contents_container_bounds.width(); + } + } else { + leading_x = layout_result.contents_container_bounds.x(); + } + const int middle_x = + leading_x + layout_result.contents_container_bounds.width() / 2; + return gfx::Point(middle_x - dialog_size.width() / 2, + browser_view_layout_->dialog_top_y_); } bool ShouldActivateDialog() const override { @@ -613,10 +644,8 @@ return content_top; } -void BrowserViewLayout::LayoutContentsContainerView(int top, int bottom) { - TRACE_EVENT0("ui", "BrowserViewLayout::LayoutContentsContainerView"); - // |contents_container_| contains web page contents and devtools. - // See browser_view.h for details. +BrowserViewLayout::ContentsContainerLayoutResult +BrowserViewLayout::CalculateContentsContainerLayout(int top, int bottom) const { gfx::Rect contents_container_bounds(vertical_layout_rect_.x(), top, vertical_layout_rect_.width(), std::max(0, bottom - top)); @@ -627,47 +656,26 @@ gfx::Insets().set_bottom(-webui_tab_strip_->size().height())); } - LayoutSidePanelView(unified_side_panel_, contents_container_bounds); - - contents_container_->SetBoundsRect(contents_container_bounds); -} - -void BrowserViewLayout::LayoutSidePanelView( - views::View* side_panel, - gfx::Rect& contents_container_bounds) { - const bool side_panel_visible = side_panel && side_panel->GetVisible(); - // Update side panel rounded corner visibility to match side panel visibility. - SetViewVisibility(side_panel_rounded_corner_, side_panel_visible); - - if (left_aligned_side_panel_separator_) { - const bool side_panel_visible_on_left = - side_panel_visible && - !views::AsViewClass<SidePanel>(unified_side_panel_)->IsRightAligned(); - SetViewVisibility(left_aligned_side_panel_separator_, - side_panel_visible_on_left); + const bool side_panel_visible = + unified_side_panel_ && unified_side_panel_->GetVisible(); + if (!side_panel_visible) { + // The contents container takes all available space, and we're done. + return ContentsContainerLayoutResult{contents_container_bounds, + gfx::Rect(), + false, + false, + false, + gfx::Rect()}; } - if (right_aligned_side_panel_separator_) { - const bool side_panel_visible_on_right = - side_panel_visible && - views::AsViewClass<SidePanel>(unified_side_panel_)->IsRightAligned(); - SetViewVisibility(right_aligned_side_panel_separator_, - side_panel_visible_on_right); - } + SidePanel* side_panel = views::AsViewClass<SidePanel>(unified_side_panel_); - if (!side_panel || !side_panel->GetVisible()) { - return; - } - - DCHECK(side_panel == unified_side_panel_); - bool is_right_aligned = - views::AsViewClass<SidePanel>(side_panel)->IsRightAligned(); - + const bool side_panel_right_aligned = side_panel->IsRightAligned(); views::View* side_panel_separator = - is_right_aligned ? right_aligned_side_panel_separator_.get() - : left_aligned_side_panel_separator_.get(); - - DCHECK(side_panel_separator); + side_panel_right_aligned ? right_aligned_side_panel_separator_.get() + : left_aligned_side_panel_separator_.get(); + CHECK(side_panel_separator); + const int separator_width = side_panel_separator->GetPreferredSize().width(); // Side panel occupies some of the container's space. The side panel should // never occupy more space than is available in the content window, and @@ -677,16 +685,16 @@ // If necessary, cap the side panel width at 2/3rds of the contents container // width as long as the side panel remains at or above its minimum width. - if (views::AsViewClass<SidePanel>(side_panel)->ShouldRestrictMaxWidth()) { + if (side_panel->ShouldRestrictMaxWidth()) { side_panel_bounds.set_width( std::max(std::min(side_panel->GetPreferredSize().width(), contents_container_bounds.width() * 2 / 3), side_panel->GetMinimumSize().width())); } else { - side_panel_bounds.set_width( - std::min(side_panel->GetPreferredSize().width(), - contents_container_bounds.width() - GetMinWebContentsWidth() - - side_panel_separator->GetPreferredSize().width())); + side_panel_bounds.set_width(std::min(side_panel->GetPreferredSize().width(), + contents_container_bounds.width() - + GetMinWebContentsWidth() - + separator_width)); } double side_panel_visible_width = @@ -694,23 +702,21 @@ views::AsViewClass<SidePanel>(unified_side_panel_)->GetAnimationValue(); // Shrink container bounds to fit the side panel. - contents_container_bounds.set_width( - contents_container_bounds.width() - side_panel_visible_width - - side_panel_separator->GetPreferredSize().width()); + contents_container_bounds.set_width(contents_container_bounds.width() - + side_panel_visible_width - + separator_width); // In LTR, the point (0,0) represents the top left of the browser. // In RTL, the point (0,0) represents the top right of the browser. - const bool is_container_after_side_panel = - (base::i18n::IsRTL() && is_right_aligned) || - (!base::i18n::IsRTL() && !is_right_aligned); + const bool contents_container_after_side_panel = + (base::i18n::IsRTL() && side_panel_right_aligned) || + (!base::i18n::IsRTL() && !side_panel_right_aligned); - if (is_container_after_side_panel) { + if (contents_container_after_side_panel) { // When the side panel should appear before the main content area relative // to the ui direction, move `contents_container_bounds` after the side // panel. Also leave space for the separator. - contents_container_bounds.set_x( - side_panel_visible_width + - side_panel_separator->GetPreferredSize().width()); + contents_container_bounds.set_x(side_panel_visible_width + separator_width); side_panel_bounds.set_x(side_panel_bounds.x() - (side_panel_bounds.width() - side_panel_visible_width)); } else { @@ -718,47 +724,79 @@ // the ui direction, move `side_panel_bounds` after the main content area. // Also leave space for the separator. side_panel_bounds.set_x(contents_container_bounds.right() + - side_panel_separator->GetPreferredSize().width()); + separator_width); } - side_panel->SetBoundsRect(side_panel_bounds); - // Adjust the side panel separator bounds based on the side panel bounds // calculated above. - gfx::Rect side_panel_separator_bounds = side_panel_bounds; + gfx::Rect separator_bounds = side_panel_bounds; // TODO (https://crbug.com/389972209): Adding 1px to the width as a bandaid // fix. This covers a case with subpixeling where a thin line of the // background finds its way to the front. - side_panel_separator_bounds.set_width( - side_panel_separator->GetPreferredSize().width() + 1); - + separator_bounds.set_width(separator_width + 1); // If the side panel appears before `contents_container_bounds`, place the // separator immediately after the side panel but before the container bounds. // If the side panel appears after `contents_container_bounds`, place the // separator immediately after the contents bounds but before the side panel. - side_panel_separator_bounds.set_x(is_container_after_side_panel - ? side_panel_bounds.right() - : contents_container_bounds.right()); + separator_bounds.set_x(contents_container_after_side_panel + ? side_panel_bounds.right() + : contents_container_bounds.right()); - side_panel_separator->SetBoundsRect(side_panel_separator_bounds); + return BrowserViewLayout::ContentsContainerLayoutResult{ + contents_container_bounds, + side_panel_bounds, + side_panel_visible, + side_panel_right_aligned, + contents_container_after_side_panel, + separator_bounds}; +} - // Adjust the side panel rounded corner bounds based on the side panel bounds - // calculated above. +void BrowserViewLayout::LayoutContentsContainerView(int top, int bottom) { + TRACE_EVENT0("ui", "BrowserViewLayout::LayoutContentsContainerView"); + // |contents_container_| contains web page contents and devtools. + // See browser_view.h for details. + + BrowserViewLayout::ContentsContainerLayoutResult layout_result = + CalculateContentsContainerLayout(top, bottom); + + contents_container_->SetBoundsRect(layout_result.contents_container_bounds); + + if (unified_side_panel_) { + unified_side_panel_->SetBoundsRect(layout_result.side_panel_bounds); + } + if (right_aligned_side_panel_separator_) { + SetViewVisibility(right_aligned_side_panel_separator_, + layout_result.side_panel_visible && + layout_result.side_panel_right_aligned); + right_aligned_side_panel_separator_->SetBoundsRect( + layout_result.separator_bounds); + } + if (left_aligned_side_panel_separator_) { + SetViewVisibility(left_aligned_side_panel_separator_, + layout_result.side_panel_visible && + !layout_result.side_panel_right_aligned); + left_aligned_side_panel_separator_->SetBoundsRect( + layout_result.separator_bounds); + } + + SetViewVisibility(side_panel_rounded_corner_, + layout_result.side_panel_visible); + // Adjust the side panel rounded corner bounds based on the side panel bounds. const float corner_radius = side_panel_rounded_corner_->GetLayoutProvider()->GetCornerRadiusMetric( views::ShapeContextTokens::kSidePanelPageContentRadius); - if (is_container_after_side_panel) { + const float corner_size = corner_radius + views::Separator::kThickness; + if (layout_result.contents_container_after_side_panel) { side_panel_rounded_corner_->SetBounds( - side_panel_bounds.right(), - side_panel_bounds.y() - views::Separator::kThickness, - corner_radius + views::Separator::kThickness, - corner_radius + views::Separator::kThickness); + layout_result.side_panel_bounds.right(), + layout_result.side_panel_bounds.y() - views::Separator::kThickness, + corner_size, corner_size); } else { side_panel_rounded_corner_->SetBounds( - side_panel_bounds.x() - corner_radius - views::Separator::kThickness, - side_panel_bounds.y() - views::Separator::kThickness, - corner_radius + views::Separator::kThickness, - corner_radius + views::Separator::kThickness); + layout_result.side_panel_bounds.x() - corner_radius - + views::Separator::kThickness, + layout_result.side_panel_bounds.y() - views::Separator::kThickness, + corner_size, corner_size); } }
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.h b/chrome/browser/ui/views/frame/browser_view_layout.h index a4602bd..493d444 100644 --- a/chrome/browser/ui/views/frame/browser_view_layout.h +++ b/chrome/browser/ui/views/frame/browser_view_layout.h
@@ -133,16 +133,18 @@ int LayoutBookmarkBar(int top); int LayoutInfoBar(int top); + // Helper struct and function for LayoutContentsContainerView that calculates + // bounds for |contents_container_| and |unified_side_panel_|. + struct ContentsContainerLayoutResult; + ContentsContainerLayoutResult CalculateContentsContainerLayout( + int top, + int bottom) const; + // Layout the |contents_container_| view between the coordinates |top| and // |bottom|. See browser_view.h for details of the relationship between - // |contents_container_| and other views. + // |contents_container_| and other views. Also lays out |unified_side_panel_|. void LayoutContentsContainerView(int top, int bottom); - // Layout the `side_panel`. This updates the passed in - // `contents_container_bounds` to accommodate the side panel. - void LayoutSidePanelView(views::View* side_panel, - gfx::Rect& contents_container_bounds); - // Updates |top_container_|'s bounds. The new bounds depend on the size of // the bookmark bar and the toolbar. void UpdateTopContainerBounds();
diff --git a/chrome/browser/ui/views/media_picker_utils.cc b/chrome/browser/ui/views/media_picker_utils.cc index 6b2d00c7..83c05e80 100644 --- a/chrome/browser/ui/views/media_picker_utils.cc +++ b/chrome/browser/ui/views/media_picker_utils.cc
@@ -14,8 +14,7 @@ #include "ui/views/window/dialog_delegate.h" bool MediaPickerCanShowAsWebModal(content::WebContents* web_contents) { - return web_contents && - !web_contents->GetDelegate()->IsNeverComposited(web_contents) && + return web_contents && !web_contents->IsNeverComposited() && web_modal::WebContentsModalDialogManager::FromWebContents( web_contents); }
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc index d4c52b491..b58c85eb 100644 --- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc +++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc
@@ -1289,6 +1289,32 @@ // TODO(crbug.com/331746545): Check the flaky test issue on Windows. #if BUILDFLAG(IS_WIN) +#define MAYBE_CollapsesOnSyncTurnedOn DISABLED_CollapsesOnSyncTurnedOn +#else +#define MAYBE_CollapsesOnSyncTurnedOn CollapsesOnSyncTurnedOn +#endif +IN_PROC_BROWSER_TEST_P(AvatarToolbarButtonHistorySyncOptinWithParamBrowserTest, + MAYBE_CollapsesOnSyncTurnedOn) { + AvatarToolbarButton* avatar = GetAvatarToolbarButton(browser()); + // Normal state. + ASSERT_TRUE(avatar->GetText().empty()); + const std::u16string email(u"test@gmail.com"); + const std::u16string account_name(u"Account name"); + const AccountInfo account_info = SigninWithImage(email, account_name); + EXPECT_EQ(avatar->GetText(), l10n_util::GetStringFUTF16( + IDS_AVATAR_BUTTON_GREETING, account_name)); + avatar->TriggerTimeoutForTesting(AvatarDelayType::kNameGreeting); + // The greeting should be followed by the history sync opt-in entry point. + EXPECT_EQ( + avatar->GetText(), + l10n_util::GetStringUTF16(GetParam().expected_history_sync_message_id)); + EnableSync(email, account_name); + // Once sync is turned on, the button should return to the normal state. + EXPECT_TRUE(avatar->GetText().empty()); +} + +// TODO(crbug.com/331746545): Check the flaky test issue on Windows. +#if BUILDFLAG(IS_WIN) #define MAYBE_HistorySyncOptinShowsAfterGreetingAndOnInactivity \ DISABLED_HistorySyncOptinShowsAfterGreetingAndOnInactivity #else
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc index c46d045..a7392a3 100644 --- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc +++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
@@ -510,7 +510,8 @@ #if BUILDFLAG(ENABLE_DICE_SUPPORT) class HistorySyncOptinCoordinator : public base::SupportsUserData::Data, - public StateManagerObserver { + public StateManagerObserver, + public signin::IdentityManager::Observer { public: static HistorySyncOptinCoordinator& GetOrCreateForProfile(Profile& profile) { HistorySyncOptinCoordinator* coordinator = @@ -593,6 +594,22 @@ } } + // IdentityManager::Observer: + void OnPrimaryAccountChanged( + const signin::PrimaryAccountChangeEvent& event) override { + if (event.GetEventTypeFor(signin::ConsentLevel::kSync) == + signin::PrimaryAccountChangeEvent::Type::kSet) { + // Needed to prevent the promo from showing when it is already triggered + // and the user turns on sync from a different entry point (e.g. + // settings). + Collapse(); + } + } + + void OnIdentityManagerShutdown(signin::IdentityManager*) override { + identity_manager_observation_.Reset(); + } + private: constexpr static const void* const kHistorySyncOptinCoordinatorKey = &kHistorySyncOptinCoordinatorKey; @@ -609,6 +626,8 @@ // This is safe because `HistorySyncOptinCoordinator` // owns `CallbackListSubscription`. base::Unretained(this))); + identity_manager_observation_.Observe( + IdentityManagerFactory::GetForProfile(&profile)); } void Trigger(signin_metrics::AccessPoint access_point) { @@ -708,6 +727,10 @@ // Callbacks to be triggered when the history sync opt-in state (`triggered_`) // changes. base::RepeatingCallbackList<void()> state_changed_callbacks; + + base::ScopedObservation<signin::IdentityManager, + signin::IdentityManager::Observer> + identity_manager_observation_{this}; }; class HistorySyncOptinStateProvider : public StateProvider { @@ -1685,6 +1708,7 @@ guest_window_count)); text = l10n_util::GetPluralStringFUTF16(IDS_AVATAR_BUTTON_GUEST, guest_window_count); + color = color_provider->GetColor(kColorAvatarButtonHighlightNormal); break; } case ButtonState::kManagement: { @@ -1780,13 +1804,13 @@ case ButtonState::kPassphraseError: case ButtonState::kSyncPaused: case ButtonState::kExplicitTextShowing: - case ButtonState::kGuestSession: case ButtonState::kShowIdentityName: #if BUILDFLAG(ENABLE_DICE_SUPPORT) case ButtonState::kHistorySyncOptin: #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) return color_provider->GetColor( kColorAvatarButtonHighlightDefaultForeground); + case ButtonState::kGuestSession: case ButtonState::kNormal: return color_provider->GetColor( kColorAvatarButtonHighlightNormalForeground); @@ -1919,6 +1943,7 @@ bool AvatarToolbarButtonDelegate::ShouldPaintBorder() const { switch (state_manager_->GetButtonActiveState()) { case ButtonState::kGuestSession: + return true; case ButtonState::kShowIdentityName: case ButtonState::kNormal: #if BUILDFLAG(ENABLE_DICE_SUPPORT)
diff --git a/chrome/browser/ui/webid/identity_dialog_controller.cc b/chrome/browser/ui/webid/identity_dialog_controller.cc index 1f8262d..c209ddb3 100644 --- a/chrome/browser/ui/webid/identity_dialog_controller.cc +++ b/chrome/browser/ui/webid/identity_dialog_controller.cc
@@ -371,6 +371,10 @@ segmentation_platform::kFedCmLikelyToSignin, segmentation_platform::processing::ProcessedValue( metadata.likely_to_signin())); + input_context->metadata_args.emplace( + segmentation_platform::kFedCmLikelyInsufficientData, + segmentation_platform::processing::ProcessedValue( + metadata.likely_insufficient_data())); segmentation_platform_service_->GetClassificationResult( segmentation_platform::kFedCmUserKey, prediction_options, input_context, std::move(callback));
diff --git a/chrome/browser/ui/webid/identity_dialog_controller.h b/chrome/browser/ui/webid/identity_dialog_controller.h index a6503a4f..46326bc 100644 --- a/chrome/browser/ui/webid/identity_dialog_controller.h +++ b/chrome/browser/ui/webid/identity_dialog_controller.h
@@ -51,11 +51,12 @@ // values at the end. This enum should be kept in sync with FedCmUserAction in // tools/metrics/histograms/enums.xml. enum class UserAction { - kSuccess = 0, + // kSuccess = 0, // Deprecated. kIgnored = 1, kClosed = 2, + kSuccess = 3, - kMaxValue = kClosed + kMaxValue = kSuccess }; // content::IdentityRequestDelegate
diff --git a/chrome/browser/ui/webid/identity_dialog_controller_unittest.cc b/chrome/browser/ui/webid/identity_dialog_controller_unittest.cc index 8d1bd23d..621b9bf 100644 --- a/chrome/browser/ui/webid/identity_dialog_controller_unittest.cc +++ b/chrome/browser/ui/webid/identity_dialog_controller_unittest.cc
@@ -48,6 +48,7 @@ constexpr float kPerClientClickthroughRate = 0.2; constexpr float kPerImpressionClickthroughRate = 0.3; constexpr float kLikelyToSignin = 0.4; +constexpr float kLikelyInsufficientData = 0.5; // Mock version of AccountSelectionView for injection during tests. class MockAccountSelectionView : public AccountSelectionView { @@ -240,6 +241,11 @@ kLikelyToSignin), input_context->GetMetadataArgument( segmentation_platform::kFedCmLikelyToSignin)); + ASSERT_EQ( + segmentation_platform::processing::ProcessedValue( + kLikelyInsufficientData), + input_context->GetMetadataArgument( + segmentation_platform::kFedCmLikelyInsufficientData)); } base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), result) @@ -276,6 +282,8 @@ fedcm_metadata.set_per_impression_clickthrough_rate( kPerImpressionClickthroughRate); fedcm_metadata.set_likely_to_signin(kLikelyToSignin); + fedcm_metadata.set_likely_insufficient_data( + kLikelyInsufficientData); metadata->SetAnyMetadataForTesting(fedcm_metadata); return optimization_guide::OptimizationGuideDecision::kTrue; });
diff --git a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc index d7a9cff6..476b993 100644 --- a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc +++ b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
@@ -296,7 +296,7 @@ continue; } // Ignore views that are never user-visible, like background pages. - if (delegate->IsNeverComposited(web_contents)) { + if (web_contents->IsNeverComposited()) { continue; } content::BrowserContext* context = rvh->GetProcess()->GetBrowserContext();
diff --git a/chrome/browser/ui/webui/bookmarks/bookmarks_message_handler.cc b/chrome/browser/ui/webui/bookmarks/bookmarks_message_handler.cc index 8abf7ad7..a2811b47 100644 --- a/chrome/browser/ui/webui/bookmarks/bookmarks_message_handler.cc +++ b/chrome/browser/ui/webui/bookmarks/bookmarks_message_handler.cc
@@ -45,7 +45,10 @@ GaiaId GetPrimaryAccountGaiaId(Profile* profile) { signin::IdentityManager* identity_manager = IdentityManagerFactory::GetForProfile(profile); - CHECK(identity_manager); + // Identity manager is null in incognito mode. + if (!identity_manager) { + return GaiaId(); + } return identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin) .gaia; } @@ -172,9 +175,14 @@ base::BindRepeating(&BookmarksMessageHandler::UpdateCanEditBookmarks, base::Unretained(this))); - identity_manager_observation_.Observe( - IdentityManagerFactory::GetForProfile(profile)); - sync_service_observation_.Observe(SyncServiceFactory::GetForProfile(profile)); + // Identity manager is null in incognito mode. + if (auto* identtiy_manager = IdentityManagerFactory::GetForProfile(profile)) { + identity_manager_observation_.Observe(identtiy_manager); + } + // Sync Service is null in incognito mode. + if (auto* sync_service = SyncServiceFactory::GetForProfile(profile)) { + sync_service_observation_.Observe(sync_service); + } bookmark_model_observation_.Observe( BookmarkModelFactory::GetForBrowserContext(profile)); }
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index 3b0bf2ffd1..668f19f7 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -396,6 +396,8 @@ "isolated_web_apps/commands/cleanup_bundle_cache_command.h", "isolated_web_apps/commands/copy_bundle_to_cache_command.cc", "isolated_web_apps/commands/copy_bundle_to_cache_command.h", + "isolated_web_apps/commands/get_bundle_cache_path_command.cc", + "isolated_web_apps/commands/get_bundle_cache_path_command.h", "isolated_web_apps/policy/isolated_web_app_cache_client.cc", "isolated_web_apps/policy/isolated_web_app_cache_client.h", "isolated_web_apps/policy/isolated_web_app_cache_manager.cc", @@ -988,6 +990,7 @@ "chromeos_web_app_experiments_unittest.cc", "isolated_web_apps/commands/cleanup_bundle_cache_command_unittest.cc", "isolated_web_apps/commands/copy_bundle_to_cache_command_unittest.cc", + "isolated_web_apps/commands/get_bundle_cache_path_command_unittest.cc", "isolated_web_apps/policy/isolated_web_app_cache_client_unittest.cc", "os_integration/web_app_run_on_os_login_chromeos_unittest.cc", "web_app_run_on_os_login_manager_unittest.cc",
diff --git a/chrome/browser/web_applications/isolated_web_apps/commands/cleanup_bundle_cache_command_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/commands/cleanup_bundle_cache_command_unittest.cc index 0ecd64c..0254cfe 100644 --- a/chrome/browser/web_applications/isolated_web_apps/commands/cleanup_bundle_cache_command_unittest.cc +++ b/chrome/browser/web_applications/isolated_web_apps/commands/cleanup_bundle_cache_command_unittest.cc
@@ -16,7 +16,6 @@ #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/web_app_command_scheduler.h" -#include "chrome/common/chrome_features.h" #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h" #include "testing/gtest/include/gtest/gtest.h" @@ -114,8 +113,6 @@ SessionType GetSessionType() { return GetParam(); } private: - base::test::ScopedFeatureList scoped_feature_list_{ - features::kIsolatedWebAppBundleCache}; base::ScopedTempDir cache_root_dir_; std::unique_ptr<base::ScopedPathOverride> cache_root_dir_override_; };
diff --git a/chrome/browser/web_applications/isolated_web_apps/commands/copy_bundle_to_cache_command_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/commands/copy_bundle_to_cache_command_unittest.cc index 68dc415..c33e20c5 100644 --- a/chrome/browser/web_applications/isolated_web_apps/commands/copy_bundle_to_cache_command_unittest.cc +++ b/chrome/browser/web_applications/isolated_web_apps/commands/copy_bundle_to_cache_command_unittest.cc
@@ -9,7 +9,6 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/test/gmock_expected_support.h" -#include "base/test/scoped_feature_list.h" #include "base/test/scoped_path_override.h" #include "base/test/test_future.h" #include "base/version.h" @@ -20,7 +19,6 @@ #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/web_app_command_scheduler.h" -#include "chrome/common/chrome_features.h" #include "components/web_package/signed_web_bundles/signed_web_bundle_id.h" #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" #include "testing/gmock/include/gmock/gmock.h" @@ -123,8 +121,6 @@ SessionType GetSessionType() { return GetParam(); } private: - base::test::ScopedFeatureList scoped_feature_list_{ - features::kIsolatedWebAppBundleCache}; base::ScopedTempDir cache_root_dir_; std::unique_ptr<base::ScopedPathOverride> cache_root_dir_override_; data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
diff --git a/chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command.cc b/chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command.cc new file mode 100644 index 0000000..797e9ed --- /dev/null +++ b/chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command.cc
@@ -0,0 +1,151 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command.h" + +#include "base/files/file_enumerator.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/task/thread_pool.h" +#include "base/types/expected.h" +#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h" +#include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.h" + +namespace web_app { + +using SessionType = IwaCacheClient::SessionType; + +namespace { + +base::FilePath GetBundleFullName( + const base::FilePath& cache_dir, + const web_package::SignedWebBundleId& web_bundle_id, + const base::Version& version) { + return IwaCacheClient::GetBundleFullName( + IwaCacheClient::GetCacheDirectoryForBundleWithVersion( + cache_dir, web_bundle_id, version)); +} + +// Expects the following bundle path: +// "/var/cache/device_local_account_iwa/<mgs|kiosk>/<bundle_id>/<version>/" + +// "main.swbn" +// Returns `std::nullopt` if version cannot be parsed. +std::optional<base::Version> ExtractVersionFromCacheBundlePath( + const base::FilePath& file) { + static constexpr int kVersionOffsetInPath = 2; + + std::vector<base::FilePath::StringType> components = file.GetComponents(); + if (components.size() >= kVersionOffsetInPath && + file.Extension() == ".swbn") { + base::Version version = + base::Version(components[components.size() - kVersionOffsetInPath]); + if (version.IsValid()) { + return version; + } + } + LOG(ERROR) << "Cannot extract bundle version from path: " << file; + return std::nullopt; +} + +// This function is blocking. It should be called by +// `GetBundleCachePathCommand::StartWithLock`. +GetBundleCachePathResult GetBundleCachePathImpl( + const web_package::SignedWebBundleId& web_bundle_id, + const std::optional<base::Version>& version, + SessionType session_type) { + const base::FilePath cache_dir = + IwaCacheClient::GetCacheBaseDirectoryForSessionType(session_type); + + if (version) { + base::FilePath expected_file_path = + GetBundleFullName(cache_dir, web_bundle_id, version.value()); + if (base::PathIsReadable(expected_file_path)) { + return GetBundleCachePathSuccess(std::move(expected_file_path), + std::move(version.value())); + } + return base::unexpected(GetBundleCachePathError::kProvidedVersionNotFound); + } + // When `version` is not provided, take the latest cached version. + base::FilePath bundle_dir = + IwaCacheClient::GetCacheDirectoryForBundle(cache_dir, web_bundle_id); + base::FileEnumerator bundle_files_iter(bundle_dir, /*recursive=*/true, + base::FileEnumerator::FILES); + + std::optional<base::FilePath> newest_version_path = std::nullopt; + std::optional<base::Version> newest_version = std::nullopt; + bundle_files_iter.ForEach([&newest_version_path, &newest_version]( + const base::FilePath& current_path) { + std::optional<base::Version> current_version = + ExtractVersionFromCacheBundlePath(current_path); + + if (newest_version < current_version) { + newest_version = current_version; + newest_version_path = current_path; + } + }); + + if (!newest_version_path) { + return base::unexpected(GetBundleCachePathError::kIwaNotCached); + } + + return GetBundleCachePathSuccess(std::move(newest_version_path.value()), + std::move(newest_version.value())); +} + +} // namespace + +std::string GetBundleCachePathErrorToString(GetBundleCachePathError error) { + switch (error) { + case GetBundleCachePathError::kSystemShutdown: + return "System shutdown"; + case GetBundleCachePathError::kProvidedVersionNotFound: + return "Provided version of IWA not found in cache"; + case GetBundleCachePathError::kIwaNotCached: + return "IWA not cached"; + } +} + +GetBundleCachePathCommand::GetBundleCachePathCommand( + const IsolatedWebAppUrlInfo& url_info, + const std::optional<base::Version>& version, + SessionType session_type, + Callback callback) + : WebAppCommand<AppLock, GetBundleCachePathResult>( + "GetBundleCachePathCommand", + AppLockDescription(url_info.app_id()), + std::move(callback), + /*args_for_shutdown=*/ + base::unexpected(GetBundleCachePathError{ + GetBundleCachePathError::kSystemShutdown})), + url_info_(url_info), + version_(version), + session_type_(session_type) {} + +GetBundleCachePathCommand::~GetBundleCachePathCommand() = default; + +void GetBundleCachePathCommand::StartWithLock(std::unique_ptr<AppLock> lock) { + CHECK(lock); + lock_ = std::move(lock); + + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, + {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, + base::BindOnce(&GetBundleCachePathImpl, url_info_.web_bundle_id(), + version_, session_type_), + base::BindOnce(&GetBundleCachePathCommand::CommandComplete, + weak_ptr_factory_.GetWeakPtr())); +} + +void GetBundleCachePathCommand::CommandComplete( + const GetBundleCachePathResult& result) { + if (!result.has_value()) { + LOG(ERROR) << "Get IWA bundle from cache failed: " + << GetBundleCachePathErrorToString(result.error()); + } + CompleteAndSelfDestruct( + result.has_value() ? CommandResult::kSuccess : CommandResult::kFailure, + result); +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command.h b/chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command.h new file mode 100644 index 0000000..9b5bd16 --- /dev/null +++ b/chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command.h
@@ -0,0 +1,90 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_COMMANDS_GET_BUNDLE_CACHE_PATH_COMMAND_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_COMMANDS_GET_BUNDLE_CACHE_PATH_COMMAND_H_ + +#include <optional> + +#include "base/functional/callback.h" +#include "base/types/expected.h" +#include "base/version.h" +#include "chrome/browser/web_applications/commands/web_app_command.h" +#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h" +#include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.h" +#include "chrome/browser/web_applications/locks/app_lock.h" + +namespace web_app { + +class GetBundleCachePathSuccess { + public: + GetBundleCachePathSuccess(const base::FilePath& cached_bundle_path, + const base::Version& cached_version) + : cached_bundle_path_(cached_bundle_path), + cached_version_(cached_version) {} + + GetBundleCachePathSuccess(const GetBundleCachePathSuccess&) = default; + ~GetBundleCachePathSuccess() = default; + + bool operator==(const GetBundleCachePathSuccess& other) const = default; + + const base::FilePath& cached_bundle_path() const { + return cached_bundle_path_; + } + + const base::Version& cached_version() const { return cached_version_; } + + private: + base::FilePath cached_bundle_path_; + base::Version cached_version_; +}; + +enum class GetBundleCachePathError { + kSystemShutdown = 0, + kProvidedVersionNotFound = 1, + kIwaNotCached = 2, +}; + +std::string GetBundleCachePathErrorToString(GetBundleCachePathError error); + +using GetBundleCachePathResult = + base::expected<GetBundleCachePathSuccess, GetBundleCachePathError>; + +// Gets IWA bundle path from cache if available. If `version` is provided, +// return the bundle with specified version or `kProvidedVersionNotFound` error. +// If `version` is empty, the function returns the bundle path with the newest +// cached version or `kIwaNotCached` error. This class takes `AppLock` for the +// bundle. +class GetBundleCachePathCommand + : public WebAppCommand<AppLock, GetBundleCachePathResult> { + public: + using Callback = base::OnceCallback<void(GetBundleCachePathResult)>; + + GetBundleCachePathCommand(const IsolatedWebAppUrlInfo& url_info, + const std::optional<base::Version>& version, + IwaCacheClient::SessionType session_type, + Callback callback); + GetBundleCachePathCommand(const GetBundleCachePathCommand&) = delete; + GetBundleCachePathCommand& operator=(const GetBundleCachePathCommand&) = + delete; + ~GetBundleCachePathCommand() override; + + protected: + // WebAppCommand: + void StartWithLock(std::unique_ptr<AppLock> lock) override; + + private: + void CommandComplete(const GetBundleCachePathResult& result); + + std::unique_ptr<AppLock> lock_; + const IsolatedWebAppUrlInfo url_info_; + const std::optional<base::Version> version_; + const IwaCacheClient::SessionType session_type_; + + base::WeakPtrFactory<GetBundleCachePathCommand> weak_ptr_factory_{this}; +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_COMMANDS_GET_BUNDLE_CACHE_PATH_COMMAND_H_
diff --git a/chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command_unittest.cc new file mode 100644 index 0000000..f8bbff9 --- /dev/null +++ b/chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command_unittest.cc
@@ -0,0 +1,205 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command.h" + +#include "ash/constants/ash_paths.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/test/gmock_expected_support.h" +#include "base/test/scoped_path_override.h" +#include "base/test/test_future.h" +#include "base/version.h" +#include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.h" +#include "chrome/browser/web_applications/isolated_web_apps/test/test_signed_web_bundle_builder.h" +#include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" +#include "chrome/browser/web_applications/test/web_app_test.h" +#include "chrome/browser/web_applications/web_app_command_scheduler.h" +#include "components/web_package/signed_web_bundles/signed_web_bundle_id.h" +#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace web_app { + +namespace { + +using base::test::ErrorIs; +using base::test::TestFuture; +using base::test::ValueIs; +using web_package::SignedWebBundleId; +using SessionType = IwaCacheClient::SessionType; + +const SignedWebBundleId kMainBundleId = test::GetDefaultEd25519WebBundleId(); +const web_package::test::Ed25519KeyPair kPublicKeyPair = + test::GetDefaultEd25519KeyPair(); +SignedWebBundleId kBundleId2 = test::GetDefaultEcdsaP256WebBundleId(); +const base::Version kVersion1 = base::Version("0.0.1"); +const base::Version kVersion2 = base::Version("0.0.2"); +const base::Version kVersion3 = base::Version("0.0.3"); +const base::Version kVersion4 = base::Version("1.0.0"); + +} // namespace + +class GetBundleCachePathCommandTest + : public WebAppTest, + public testing::WithParamInterface<SessionType> { + public: + void SetUp() override { + WebAppTest::SetUp(); + test::AwaitStartWebAppProviderAndSubsystems(profile()); + + ASSERT_TRUE(cache_root_dir_.CreateUniqueTempDir()); + cache_root_dir_override_ = std::make_unique<base::ScopedPathOverride>( + ash::DIR_DEVICE_LOCAL_ACCOUNT_IWA_CACHE, cache_root_dir_.GetPath()); + } + + base::FilePath CreateBundleInCacheDir(const SignedWebBundleId& bundle_id, + const base::Version& version) { + base::FilePath bundle_directory_path = + GetBundleDirWithVersion(bundle_id, version); + EXPECT_TRUE(base::CreateDirectory(bundle_directory_path)); + + base::FilePath temp_file; + EXPECT_TRUE(base::CreateTemporaryFileInDir(CacheRootPath(), &temp_file)); + base::FilePath bundle_path = + IwaCacheClient::GetBundleFullName(bundle_directory_path); + EXPECT_TRUE(base::CopyFile(temp_file, bundle_path)); + return bundle_path; + } + + base::FilePath GetBundleDirWithVersion(const SignedWebBundleId& bundle_id, + const base::Version& version) { + auto session_cache_dir = + IwaCacheClient::GetCacheBaseDirectoryForSessionType(GetSessionType(), + CacheRootPath()); + return IwaCacheClient::GetCacheDirectoryForBundleWithVersion( + session_cache_dir, bundle_id, version); + } + + void ScheduleCommand( + const web_package::SignedWebBundleId& web_bundle_id, + const std::optional<base::Version>& version, + base::OnceCallback<void(GetBundleCachePathResult)> callback) { + auto url_info = + IsolatedWebAppUrlInfo::CreateFromSignedWebBundleId(web_bundle_id); + fake_provider().scheduler().GetIsolatedWebAppBundleCachePath( + url_info, version, GetSessionType(), std::move(callback)); + } + + private: + const base::FilePath& CacheRootPath() { return cache_root_dir_.GetPath(); } + + SessionType GetSessionType() { return GetParam(); } + + base::ScopedTempDir cache_root_dir_; + std::unique_ptr<base::ScopedPathOverride> cache_root_dir_override_; + data_decoder::test::InProcessDataDecoder in_process_data_decoder_; +}; + +TEST_P(GetBundleCachePathCommandTest, NoCachedPathToFetch) { + TestFuture<GetBundleCachePathResult> get_bundle_future; + ScheduleCommand(kMainBundleId, /*version=*/std::nullopt, + get_bundle_future.GetCallback()); + + EXPECT_THAT(get_bundle_future.Get(), + ErrorIs(GetBundleCachePathError::kIwaNotCached)); +} + +TEST_P(GetBundleCachePathCommandTest, RequiredVersionFound) { + base::FilePath bundle_path = CreateBundleInCacheDir(kMainBundleId, kVersion1); + + TestFuture<GetBundleCachePathResult> get_bundle_future; + ScheduleCommand(kMainBundleId, kVersion1, get_bundle_future.GetCallback()); + + EXPECT_THAT(get_bundle_future.Get(), + ValueIs(GetBundleCachePathSuccess{bundle_path, kVersion1})); +} + +TEST_P(GetBundleCachePathCommandTest, ProvidedVersionNotFound) { + base::FilePath bundle_path = CreateBundleInCacheDir(kMainBundleId, kVersion1); + + TestFuture<GetBundleCachePathResult> get_bundle_future; + ScheduleCommand(kMainBundleId, kVersion2, get_bundle_future.GetCallback()); + + EXPECT_THAT(get_bundle_future.Get(), + ErrorIs(GetBundleCachePathError::kProvidedVersionNotFound)); +} + +TEST_P(GetBundleCachePathCommandTest, NoVersionProvided) { + base::FilePath bundle_path = CreateBundleInCacheDir(kMainBundleId, kVersion1); + + TestFuture<GetBundleCachePathResult> get_bundle_future; + ScheduleCommand(kMainBundleId, /*version=*/std::nullopt, + get_bundle_future.GetCallback()); + + EXPECT_THAT(get_bundle_future.Get(), + ValueIs(GetBundleCachePathSuccess{bundle_path, kVersion1})); +} + +TEST_P(GetBundleCachePathCommandTest, GetNewestVersionWhenVersionNotProvided) { + base::FilePath bundle_path_v1 = + CreateBundleInCacheDir(kMainBundleId, kVersion1); + base::FilePath bundle_path_v3 = + CreateBundleInCacheDir(kMainBundleId, kVersion3); + base::FilePath bundle_path_v4 = + CreateBundleInCacheDir(kMainBundleId, kVersion4); + base::FilePath bundle_path_v2 = + CreateBundleInCacheDir(kMainBundleId, kVersion2); + + TestFuture<GetBundleCachePathResult> get_bundle_future; + ScheduleCommand(kMainBundleId, /*version=*/std::nullopt, + get_bundle_future.GetCallback()); + + EXPECT_THAT(get_bundle_future.Get(), + ValueIs(GetBundleCachePathSuccess{bundle_path_v4, kVersion4})); +} + +TEST_P(GetBundleCachePathCommandTest, GetCorrectVersion) { + base::FilePath bundle_path_v2 = + CreateBundleInCacheDir(kMainBundleId, kVersion2); + base::FilePath bundle_path_v1 = + CreateBundleInCacheDir(kMainBundleId, kVersion1); + base::FilePath bundle_path_v3 = + CreateBundleInCacheDir(kMainBundleId, kVersion3); + + TestFuture<GetBundleCachePathResult> get_bundle_future; + ScheduleCommand(kMainBundleId, kVersion1, get_bundle_future.GetCallback()); + + EXPECT_THAT(get_bundle_future.Get(), + ValueIs(GetBundleCachePathSuccess{bundle_path_v1, kVersion1})); +} + +TEST_P(GetBundleCachePathCommandTest, GetCorrectIwa) { + base::FilePath bundle_path1 = + CreateBundleInCacheDir(kMainBundleId, kVersion1); + base::FilePath bundle_path2 = CreateBundleInCacheDir(kBundleId2, kVersion1); + + TestFuture<GetBundleCachePathResult> get_bundle_future; + ScheduleCommand(kBundleId2, kVersion1, get_bundle_future.GetCallback()); + + EXPECT_THAT(get_bundle_future.Get(), + ValueIs(GetBundleCachePathSuccess{bundle_path2, kVersion1})); +} + +TEST_P(GetBundleCachePathCommandTest, IncorrectVersionParsed) { + base::FilePath bundle_path1 = + CreateBundleInCacheDir(kMainBundleId, base::Version("aaaaa")); + + TestFuture<GetBundleCachePathResult> get_bundle_future; + ScheduleCommand(kMainBundleId, /*version=*/std::nullopt, + get_bundle_future.GetCallback()); + + EXPECT_THAT(get_bundle_future.Get(), + ErrorIs(GetBundleCachePathError::kIwaNotCached)); +} + +INSTANTIATE_TEST_SUITE_P( + /* no prefix */, + GetBundleCachePathCommandTest, + testing::Values(SessionType::kKiosk, SessionType::kManagedGuestSession)); + +} // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.cc b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.cc index 73b4d88b..fdc2a0d5 100644 --- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.cc +++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.cc
@@ -28,98 +28,8 @@ namespace web_app { -namespace { - using SessionType = IwaCacheClient::SessionType; -base::FilePath GetBundleFullName( - const base::FilePath& cache_dir, - const web_package::SignedWebBundleId& web_bundle_id, - const base::Version& version) { - return IwaCacheClient::GetBundleFullName( - IwaCacheClient::GetCacheDirectoryForBundleWithVersion( - cache_dir, web_bundle_id, version)); -} - -// Expects the following bundle path: -// "/var/cache/device_local_account_iwa/<mgs|kiosk>/<bundle_id>/<version>/" + -// "main.swbn" -// Returns `std::nullopt` if version cannot be parsed. -std::optional<base::Version> ExtractVersionFromCacheBundlePath( - const base::FilePath& file) { - static constexpr int kVersionOffsetInPath = 2; - - std::vector<base::FilePath::StringType> components = file.GetComponents(); - if (components.size() >= kVersionOffsetInPath && - file.Extension() == ".swbn") { - base::Version version = - base::Version(components[components.size() - kVersionOffsetInPath]); - if (version.IsValid()) { - return version; - } - } - return std::nullopt; -} - -// This function is blocking. It should be called by -// `GetCacheFilePath`. -std::optional<IwaCacheClient::CachedBundleData> GetCacheFilePathImpl( - const web_package::SignedWebBundleId& web_bundle_id, - const std::optional<base::Version>& version, - const base::FilePath& cache_dir) { - if (version) { - base::FilePath expected_file_path = - GetBundleFullName(cache_dir, web_bundle_id, version.value()); - if (base::PathIsReadable(expected_file_path)) { - return IwaCacheClient::CachedBundleData(std::move(expected_file_path), - std::move(version.value())); - } else { - return std::nullopt; - } - } - // When `version` is not provided, take the latest cached version. - base::FilePath bundle_dir = - IwaCacheClient::GetCacheDirectoryForBundle(cache_dir, web_bundle_id); - base::FileEnumerator bundle_files_iter(bundle_dir, /*recursive=*/true, - base::FileEnumerator::FILES); - - std::optional<base::FilePath> newest_version_path = std::nullopt; - std::optional<base::Version> newest_version = std::nullopt; - bundle_files_iter.ForEach([&newest_version_path, &newest_version]( - const base::FilePath& current_path) { - std::optional<base::Version> current_version = - ExtractVersionFromCacheBundlePath(current_path); - - if (newest_version < current_version) { - newest_version = current_version; - newest_version_path = current_path; - } - }); - - if (!newest_version_path) { - return std::nullopt; - } - - return IwaCacheClient::CachedBundleData( - std::move(newest_version_path.value()), - std::move(newest_version.value())); -} - -base::FilePath GetIwaCacheDirectoryForCurrentSession( - const base::FilePath& base = base::PathService::CheckedGet( - ash::DIR_DEVICE_LOCAL_ACCOUNT_IWA_CACHE)) { - if (chromeos::IsKioskSession()) { - return IwaCacheClient::GetCacheBaseDirectoryForSessionType( - SessionType::kKiosk, base); - } else if (chromeos::IsManagedGuestSession()) { - return IwaCacheClient::GetCacheBaseDirectoryForSessionType( - SessionType::kManagedGuestSession, base); - } - NOTREACHED() << "Unsupported session type for IWA caching"; -} - -} // namespace - bool IsIwaBundleCacheEnabled() { return base::FeatureList::IsEnabled(features::kIsolatedWebAppBundleCache) && (chromeos::IsManagedGuestSession() || chromeos::IsKioskSession()); @@ -137,27 +47,6 @@ << "IwaCacheClient supports only kiosk and Managed Guest Session."; } -IwaCacheClient::IwaCacheClient() - : cache_dir_(GetIwaCacheDirectoryForCurrentSession()) { - CHECK(IsIwaBundleCacheEnabled()) - << "IwaCacheClient should only be created " - "inside mgs or kiosk sessions and when the feature is enabled"; -} - -void IwaCacheClient::GetCacheFilePath( - const web_package::SignedWebBundleId& web_bundle_id, - const std::optional<base::Version>& version, - base::OnceCallback<void(std::optional<CachedBundleData>)> callback) { - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, {base::MayBlock()}, - base::BindOnce(&GetCacheFilePathImpl, web_bundle_id, version, cache_dir_), - std::move(callback)); -} - -void IwaCacheClient::SetCacheDirForTesting(const base::FilePath& cache_dir) { - cache_dir_ = GetIwaCacheDirectoryForCurrentSession(cache_dir); -} - // static base::FilePath IwaCacheClient::GetCacheBaseDirectoryForSessionType( IwaCacheClient::SessionType session_type,
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.h b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.h index e4b705a..2d24c9c 100644 --- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.h +++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.h
@@ -25,6 +25,8 @@ // This class should be used only when `IsIwaBundleCacheEnabled()` returns // true. This is checked in the constructor. This class can be created // multiple times even for the same IWA. +// TODO(crbug.com/416006853): refactor this class, probably delete it and make +// iwa_bundle_cache namespace instead. class IwaCacheClient { public: enum class SessionType { @@ -34,31 +36,11 @@ static SessionType GetCurrentSessionType(); - struct CachedBundleData { - base::FilePath path; - base::Version version; - }; - - IwaCacheClient(); + IwaCacheClient() = default; IwaCacheClient(const IwaCacheClient&) = delete; IwaCacheClient& operator=(const IwaCacheClient&) = delete; ~IwaCacheClient() = default; - // Calls `callback` with the path of the cached bundle and it's version. - // If the IWA is not cached, returns `std::nullopt`. - // `version` may be empty, which means the function returns the bundle path - // with the newest cached version. - // If `version` is provided, return the bundle with specified version. If this - // version is not cached, returns `std::nullopt`. - void GetCacheFilePath( - const web_package::SignedWebBundleId& web_bundle_id, - const std::optional<base::Version>& version, - base::OnceCallback<void(std::optional<CachedBundleData>)> callback); - - // TODO(crbug.com/392069400): clean cache for old IWA versions. - - void SetCacheDirForTesting(const base::FilePath& cache_dir); - static base::FilePath GetCacheBaseDirectoryForSessionType( IwaCacheClient::SessionType session_type, const base::FilePath& base = base::PathService::CheckedGet( @@ -80,9 +62,6 @@ static constexpr base::FilePath::CharType kMgsDirName[] = "mgs"; static constexpr base::FilePath::CharType kKioskDirName[] = "kiosk"; - - private: - base::FilePath cache_dir_; }; } // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client_unittest.cc index 215cc72fc..89b6693e 100644 --- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client_unittest.cc +++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client_unittest.cc
@@ -32,29 +32,9 @@ namespace web_app { -namespace { +using SessionType = IwaCacheClient::SessionType; -using base::test::TestFuture; -using Bundle = IwaCacheClient::CachedBundleData; -using base::test::ErrorIs; -using base::test::ValueIs; -using testing::Field; -using web_package::SignedWebBundleId; - -const SignedWebBundleId kBundleId = test::GetDefaultEd25519WebBundleId(); -const base::Version kVersion1 = base::Version("0.0.1"); -const base::Version kVersion2 = base::Version("0.0.2"); -const base::Version kVersion3 = base::Version("0.0.3"); -const base::Version kVersion4 = base::Version("1.0.0"); - -} // namespace - -enum SessionType { - kMgs = 0, - kKiosk = 1, - kUser = 2, -}; - +// TODO(crbug.com/416006853): refactor tests to cover static functions. class IwaCacheClientTest : public ::testing::TestWithParam<SessionType> { public: IwaCacheClientTest() = default; @@ -67,66 +47,25 @@ std::make_unique<user_manager::FakeUserManager>(local_state_.Get())); switch (GetSessionType()) { - case kMgs: + case SessionType::kKiosk: + chromeos::SetUpFakeKioskSession(); + break; + case SessionType::kManagedGuestSession: test_managed_guest_session_ = std::make_unique< profiles::testing::ScopedTestManagedGuestSession>(); break; - case kKiosk: - chromeos::SetUpFakeKioskSession(); - break; - case kUser: - NOTREACHED(); } ASSERT_TRUE(cache_root_dir_.CreateUniqueTempDir()); cache_root_dir_override_ = std::make_unique<base::ScopedPathOverride>( ash::DIR_DEVICE_LOCAL_ACCOUNT_IWA_CACHE, cache_root_dir_.GetPath()); - - // `IwaCacheClient` should be created after kiosk or MGS setup. - cache_client_ = std::make_unique<IwaCacheClient>(); - } - - IwaCacheClient* cache_client() { return cache_client_.get(); } - - base::FilePath CreateBundleInCacheDir(const SignedWebBundleId& bundle_id, - const base::Version& version) { - base::FilePath bundle_directory_path = - GetBundleDirWithVersion(bundle_id, version); - EXPECT_TRUE(base::CreateDirectory(bundle_directory_path)); - - base::FilePath temp_file; - EXPECT_TRUE(base::CreateTemporaryFileInDir(CacheRootPath(), &temp_file)); - - base::FilePath bundle_path = - bundle_directory_path.AppendASCII(kMainSwbnFileName); - EXPECT_TRUE(base::CopyFile(temp_file, bundle_path)); - return bundle_path; - } - - private: - base::FilePath GetBundleDirWithVersion(const SignedWebBundleId& bundle_id, - const base::Version& version) { - base::FilePath bundle_directory_path = CacheRootPath(); - switch (GetSessionType()) { - case SessionType::kMgs: - bundle_directory_path = - bundle_directory_path.AppendASCII(IwaCacheClient::kMgsDirName); - break; - case SessionType::kKiosk: - bundle_directory_path = - bundle_directory_path.AppendASCII(IwaCacheClient::kKioskDirName); - break; - case kUser: - NOTREACHED() << "Caching is not supported in user session"; - } - return bundle_directory_path.AppendASCII(bundle_id.id()) - .AppendASCII(version.GetString()); } const base::FilePath& CacheRootPath() { return cache_root_dir_.GetPath(); } SessionType GetSessionType() { return GetParam(); } + private: base::test::ScopedFeatureList scoped_feature_list_{ features::kIsolatedWebAppBundleCache}; ScopedTestingLocalState local_state_{TestingBrowserProcess::GetGlobal()}; @@ -135,201 +74,10 @@ user_manager::ScopedUserManager user_manager_; base::ScopedTempDir cache_root_dir_; std::unique_ptr<base::ScopedPathOverride> cache_root_dir_override_; - std::unique_ptr<IwaCacheClient> cache_client_; // This is set only for MGS session. std::unique_ptr<profiles::testing::ScopedTestManagedGuestSession> test_managed_guest_session_; }; -TEST_P(IwaCacheClientTest, NoCachedPathToFetch) { - TestFuture<std::optional<Bundle>> bundle_future; - cache_client()->GetCacheFilePath(kBundleId, - /*version=*/std::nullopt, - bundle_future.GetCallback()); - - EXPECT_FALSE(bundle_future.Get()); -} - -TEST_P(IwaCacheClientTest, GetCachedPathWithRequiredVersion) { - base::FilePath bundle_path = CreateBundleInCacheDir(kBundleId, kVersion1); - - TestFuture<std::optional<Bundle>> bundle_future; - cache_client()->GetCacheFilePath(kBundleId, kVersion1, - bundle_future.GetCallback()); - - EXPECT_EQ(bundle_future.Get()->path, bundle_path); - EXPECT_EQ(bundle_future.Get()->version, kVersion1); -} - -TEST_P(IwaCacheClientTest, NoCachedPathWhenVersionNotCached) { - base::FilePath bundle_path = CreateBundleInCacheDir(kBundleId, kVersion1); - - TestFuture<std::optional<Bundle>> bundle_future; - cache_client()->GetCacheFilePath(kBundleId, kVersion2, - bundle_future.GetCallback()); - - EXPECT_FALSE(bundle_future.Get()); -} - -TEST_P(IwaCacheClientTest, GetCachedPathNoVersionProvided) { - base::FilePath bundle_path = CreateBundleInCacheDir(kBundleId, kVersion1); - - TestFuture<std::optional<Bundle>> bundle_future; - cache_client()->GetCacheFilePath(kBundleId, /*version=*/std::nullopt, - bundle_future.GetCallback()); - - EXPECT_EQ(bundle_future.Get()->path, bundle_path); - EXPECT_EQ(bundle_future.Get()->version, kVersion1); -} - -TEST_P(IwaCacheClientTest, GetNewestVersionWhenVersionNotProvided) { - base::FilePath bundle_path_v1 = CreateBundleInCacheDir(kBundleId, kVersion1); - base::FilePath bundle_path_v3 = CreateBundleInCacheDir(kBundleId, kVersion3); - base::FilePath bundle_path_v2 = CreateBundleInCacheDir(kBundleId, kVersion2); - base::FilePath bundle_path_v4 = CreateBundleInCacheDir(kBundleId, kVersion4); - - TestFuture<std::optional<Bundle>> bundle_future; - cache_client()->GetCacheFilePath(kBundleId, /*version=*/std::nullopt, - bundle_future.GetCallback()); - - EXPECT_EQ(bundle_future.Get()->path, bundle_path_v4); - EXPECT_EQ(bundle_future.Get()->version, kVersion4); -} - -TEST_P(IwaCacheClientTest, GetCorrectVersion) { - base::FilePath bundle_path_v2 = CreateBundleInCacheDir(kBundleId, kVersion2); - base::FilePath bundle_path_v1 = CreateBundleInCacheDir(kBundleId, kVersion1); - base::FilePath bundle_path_v3 = CreateBundleInCacheDir(kBundleId, kVersion3); - - TestFuture<std::optional<Bundle>> bundle_future; - cache_client()->GetCacheFilePath(kBundleId, kVersion1, - bundle_future.GetCallback()); - - EXPECT_EQ(bundle_future.Get()->path, bundle_path_v1); - EXPECT_EQ(bundle_future.Get()->version, kVersion1); -} - -TEST_P(IwaCacheClientTest, GetCorrectBundle) { - SignedWebBundleId web_bundle_id2 = test::GetDefaultEcdsaP256WebBundleId(); - - base::FilePath bundle_path1 = CreateBundleInCacheDir(kBundleId, kVersion1); - base::FilePath bundle_path2 = - CreateBundleInCacheDir(web_bundle_id2, kVersion1); - - TestFuture<std::optional<Bundle>> bundle_future; - cache_client()->GetCacheFilePath(web_bundle_id2, kVersion1, - bundle_future.GetCallback()); - - EXPECT_EQ(bundle_future.Get()->path, bundle_path2); - EXPECT_EQ(bundle_future.Get()->version, kVersion1); -} - -TEST_P(IwaCacheClientTest, IncorrectVersionParsed) { - base::FilePath bundle_path1 = - CreateBundleInCacheDir(kBundleId, base::Version("aaaaa")); - - TestFuture<std::optional<Bundle>> bundle_future; - cache_client()->GetCacheFilePath(kBundleId, /*version=*/std::nullopt, - bundle_future.GetCallback()); - - EXPECT_FALSE(bundle_future.Get()); -} - -INSTANTIATE_TEST_SUITE_P( - /* no prefix */, - IwaCacheClientTest, - testing::Values(kMgs, kKiosk)); - -struct IwaCacheClientDeathTestParam { - SessionType session_type; - bool feature_enabled; - bool should_crash; -}; - -class IwaCacheClientDeathTest - : public ::testing::TestWithParam<IwaCacheClientDeathTestParam> { - public: - IwaCacheClientDeathTest() { - if (GetParam().feature_enabled) { - scoped_feature_list_.InitAndEnableFeature( - {features::kIsolatedWebAppBundleCache}); - } - } - IwaCacheClientDeathTest(const IwaCacheClientDeathTest&) = delete; - IwaCacheClientDeathTest& operator=(const IwaCacheClientDeathTest&) = delete; - ~IwaCacheClientDeathTest() override = default; - - void SetUp() override { - user_manager_.Reset( - std::make_unique<user_manager::FakeUserManager>(local_state_.Get())); - - switch (GetParam().session_type) { - case kMgs: - test_managed_guest_session_ = std::make_unique< - profiles::testing::ScopedTestManagedGuestSession>(); - break; - case kKiosk: - chromeos::SetUpFakeKioskSession(); - break; - case kUser: - break; - } - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; - - ScopedTestingLocalState local_state_{TestingBrowserProcess::GetGlobal()}; - user_manager::ScopedUserManager user_manager_; - - // This is set only for MGS session. - std::unique_ptr<profiles::testing::ScopedTestManagedGuestSession> - test_managed_guest_session_; -}; - -TEST_P(IwaCacheClientDeathTest, CreateClient) { - if (GetParam().should_crash) { - EXPECT_DEATH(IwaCacheClient(), ""); - } else { - IwaCacheClient(); - } -} - -INSTANTIATE_TEST_SUITE_P( - /* no prefix */, - IwaCacheClientDeathTest, - testing::ValuesIn(std::vector<IwaCacheClientDeathTestParam>{ - { - .session_type = kMgs, - .feature_enabled = true, - .should_crash = false, - }, - { - .session_type = kKiosk, - .feature_enabled = true, - .should_crash = false, - }, - { - .session_type = kMgs, - .feature_enabled = false, - .should_crash = true, - }, - { - .session_type = kKiosk, - .feature_enabled = false, - .should_crash = true, - }, - { - .session_type = kUser, - .feature_enabled = true, - .should_crash = true, - }, - { - .session_type = kUser, - .feature_enabled = false, - .should_crash = true, - }, - })); - } // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer.cc b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer.cc index e142792..a2140f8f 100644 --- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer.cc +++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer.cc
@@ -26,6 +26,7 @@ #if BUILDFLAG(IS_CHROMEOS) #include "chrome/browser/web_applications/isolated_web_apps/commands/copy_bundle_to_cache_command.h" +#include "chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command.h" #include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.h" #include "chromeos/components/mgs/managed_guest_session_utils.h" #endif // BUILDFLAG(IS_CHROMEOS) @@ -181,10 +182,17 @@ // Install IWA from cache if possible, otherwise install it from the // Internet. log_->Append(base::Value(u"looking for cached bundle")); - cache_client_->GetCacheFilePath( - install_options_.web_bundle_id(), install_options_.pinned_version(), - base::BindOnce(&IwaInstaller::OnGetCacheFilePath, - weak_factory_.GetWeakPtr())); + + IsolatedWebAppUrlInfo url_info = + IsolatedWebAppUrlInfo::CreateFromSignedWebBundleId( + install_options_.web_bundle_id()); + CHECK_DEREF(provider_.get()) + .scheduler() + .GetIsolatedWebAppBundleCachePath( + url_info, install_options_.pinned_version(), + IwaCacheClient::GetCurrentSessionType(), + base::BindOnce(&IwaInstaller::OnBundleCachePathReceived, + weak_factory_.GetWeakPtr())); return; } #endif // BUILDFLAG(IS_CHROMEOS) @@ -193,13 +201,12 @@ } #if BUILDFLAG(IS_CHROMEOS) -void IwaInstaller::OnGetCacheFilePath( - std::optional<IwaCacheClient::CachedBundleData> cached_bundle) { - if (cached_bundle) { +void IwaInstaller::OnBundleCachePathReceived(GetBundleCachePathResult result) { + if (result.has_value()) { log_->Append(base::Value("cached bundle is available, version: " + - cached_bundle->version.GetString() + - ", path: " + cached_bundle->path.MaybeAsASCII())); - InstallFromCache(cached_bundle->path, cached_bundle->version); + result->cached_version().GetString() + ", path: " + + result->cached_bundle_path().MaybeAsASCII())); + InstallFromCache(result->cached_bundle_path(), result->cached_version()); return; }
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer.h b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer.h index 3f3cecf..9787429 100644 --- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer.h +++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer.h
@@ -21,6 +21,7 @@ #if BUILDFLAG(IS_CHROMEOS) #include "chrome/browser/web_applications/isolated_web_apps/commands/copy_bundle_to_cache_command.h" +#include "chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command.h" #include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.h" #endif // BUILDFLAG(IS_CHROMEOS) @@ -124,8 +125,7 @@ private: #if BUILDFLAG(IS_CHROMEOS) - void OnGetCacheFilePath( - std::optional<IwaCacheClient::CachedBundleData> cached_bundle); + void OnBundleCachePathReceived(GetBundleCachePathResult result); // Installing of the IWA using the cached bundle. void InstallFromCache(const base::FilePath& cache_file,
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer_unittest.cc index f9f9a64..50fd640 100644 --- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer_unittest.cc +++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_installer_unittest.cc
@@ -38,6 +38,7 @@ #if BUILDFLAG(IS_CHROMEOS) #include "ash/constants/ash_paths.h" +#include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.h" #endif // BUILDFLAG(IS_CHROMEOS) namespace web_app { @@ -386,6 +387,7 @@ testing::Values(kUser, kMgs)); #if BUILDFLAG(IS_CHROMEOS) +// IWA cache installation tests for Managed Guest Session (MGS). class IwaMgsCachingInstallerTest : public IwaInstallerBaseTest { public: IwaMgsCachingInstallerTest() : IwaInstallerBaseTest(kMgs) {} @@ -398,35 +400,36 @@ void OverrideCacheDir() { ASSERT_TRUE(cache_root_dir_.CreateUniqueTempDir()); cache_root_dir_override_ = std::make_unique<base::ScopedPathOverride>( - ash::DIR_DEVICE_LOCAL_ACCOUNT_IWA_CACHE, cache_root_dir_.GetPath()); + ash::DIR_DEVICE_LOCAL_ACCOUNT_IWA_CACHE, CacheRootPath()); } - base::FilePath GetBundleDirPathWithVersion( - const web_package::SignedWebBundleId& bundle_id, - const base::Version& version) { - return cache_root_dir_.GetPath() - .AppendASCII(IwaCacheClient::kMgsDirName) - .AppendASCII(bundle_id.id()) - .AppendASCII(version.GetString()); + base::FilePath GetBundleDirWithVersion(const SignedWebBundleId& bundle_id, + const base::Version& version) { + auto session_cache_dir = + IwaCacheClient::GetCacheBaseDirectoryForSessionType( + IwaCacheClient::SessionType::kManagedGuestSession, CacheRootPath()); + return IwaCacheClient::GetCacheDirectoryForBundleWithVersion( + session_cache_dir, bundle_id, version); } - base::FilePath GetFullBundlePath( - const web_package::SignedWebBundleId& bundle_id, - const base::Version& version) { - return GetBundleDirPathWithVersion(bundle_id, version) - .AppendASCII(kMainSwbnFileName); + base::FilePath GetFullBundlePath(const SignedWebBundleId& bundle_id, + const base::Version& version) { + return IwaCacheClient::GetBundleFullName( + GetBundleDirWithVersion(bundle_id, version)); } void CopyBundleToCache(const web_package::SignedWebBundleId& web_bundle_id, const base::Version& version, const base::FilePath& bundle_to_copy) { - ASSERT_TRUE(base::CreateDirectory( - GetBundleDirPathWithVersion(web_bundle_id, version))); + ASSERT_TRUE( + base::CreateDirectory(GetBundleDirWithVersion(web_bundle_id, version))); ASSERT_TRUE(base::CopyFile(bundle_to_copy, GetFullBundlePath(web_bundle_id, version))); } protected: + const base::FilePath& CacheRootPath() { return cache_root_dir_.GetPath(); } + base::ScopedTempDir cache_root_dir_; std::unique_ptr<base::ScopedPathOverride> cache_root_dir_override_; base::test::ScopedFeatureList scoped_feature_list_{
diff --git a/chrome/browser/web_applications/web_app_command_scheduler.cc b/chrome/browser/web_applications/web_app_command_scheduler.cc index 2ee2a7d..10c899d 100644 --- a/chrome/browser/web_applications/web_app_command_scheduler.cc +++ b/chrome/browser/web_applications/web_app_command_scheduler.cc
@@ -91,6 +91,7 @@ #if BUILDFLAG(IS_CHROMEOS) #include "chrome/browser/web_applications/isolated_web_apps/commands/cleanup_bundle_cache_command.h" #include "chrome/browser/web_applications/isolated_web_apps/commands/copy_bundle_to_cache_command.h" +#include "chrome/browser/web_applications/isolated_web_apps/commands/get_bundle_cache_path_command.h" #include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_cache_client.h" #else // !BUILDFLAG(IS_CHROMEOS) #include "chrome/browser/web_applications/jobs/link_capturing.h" @@ -380,6 +381,19 @@ } #if BUILDFLAG(IS_CHROMEOS) +void WebAppCommandScheduler::GetIsolatedWebAppBundleCachePath( + const IsolatedWebAppUrlInfo& url_info, + const std::optional<base::Version>& version, + IwaCacheClient::SessionType session_type, + base::OnceCallback<void(base::expected<GetBundleCachePathSuccess, + GetBundleCachePathError>)> callback, + const base::Location& call_location) { + provider_->command_manager().ScheduleCommand( + std::make_unique<GetBundleCachePathCommand>( + url_info, version, session_type, std::move(callback)), + call_location); +} + void WebAppCommandScheduler::CopyIsolatedWebAppBundleToCache( const IsolatedWebAppUrlInfo& url_info, IwaCacheClient::SessionType session_type,
diff --git a/chrome/browser/web_applications/web_app_command_scheduler.h b/chrome/browser/web_applications/web_app_command_scheduler.h index 1ea7cea..1f1a111f 100644 --- a/chrome/browser/web_applications/web_app_command_scheduler.h +++ b/chrome/browser/web_applications/web_app_command_scheduler.h
@@ -82,6 +82,8 @@ class CleanupBundleCacheError; class CopyBundleToCacheSuccess; enum class CopyBundleToCacheError; +class GetBundleCachePathSuccess; +enum class GetBundleCachePathError; #endif // BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_MAC) @@ -303,7 +305,20 @@ const base::Location& call_location = FROM_HERE); #if BUILDFLAG(IS_CHROMEOS) - // Copies IWA bundle file to the cache for `session_type`. + // Schedules a command that gets IWA bundle path from cache for + // `session_type`. If `version` is not provided, returns the newest cached + // version. + void GetIsolatedWebAppBundleCachePath( + const IsolatedWebAppUrlInfo& url_info, + const std::optional<base::Version>& version, + IwaCacheClient::SessionType session_type, + base::OnceCallback<void( + base::expected<GetBundleCachePathSuccess, GetBundleCachePathError>)> + callback, + const base::Location& call_location = FROM_HERE); + + // Schedules a command that copies IWA bundle file to the cache for + // `session_type`. void CopyIsolatedWebAppBundleToCache( const IsolatedWebAppUrlInfo& url_info, IwaCacheClient::SessionType session_type, @@ -311,8 +326,8 @@ CopyBundleToCacheError>)> callback, const base::Location& call_location = FROM_HERE); - // Cleans all IWA cached bundles for `session_type` which are not in the - // `iwas_to_keep_in_cache`. + // Schedules a command that cleans all IWA cached bundles for `session_type` + // which are not in the `iwas_to_keep_in_cache`. void CleanupIsolatedWebAppBundleCache( const std::vector<web_package::SignedWebBundleId>& iwas_to_keep_in_cache, IwaCacheClient::SessionType session_type, @@ -337,7 +352,7 @@ callback, const base::Location& location = FROM_HERE); - // Scheduler a command that installs a web app from sync. + // Schedules a command that installs a web app from sync. void InstallFromSync(const WebApp& web_app, OnceInstallCallback callback, const base::Location& location = FROM_HERE);
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_controller.cc b/chrome/browser/webauthn/authenticator_request_dialog_controller.cc index 80bfe4c6..b55a5d17 100644 --- a/chrome/browser/webauthn/authenticator_request_dialog_controller.cc +++ b/chrome/browser/webauthn/authenticator_request_dialog_controller.cc
@@ -2039,8 +2039,9 @@ password_manager::PasskeyCredential::DisplayName( credential.user.display_name.value_or(""))); if (credential.provider_name) { - passkey.SetAuthenticatorLabel( - base::UTF8ToUTF16(*credential.provider_name)); + passkey.SetAuthenticatorLabel(l10n_util::GetStringFUTF16( + IDS_PASSWORD_MANAGER_PASSKEY_FROM_PROVIDER, + base::UTF8ToUTF16(*credential.provider_name))); } else if (credential.source == AuthenticatorType::kPhone) { passkey.SetAuthenticatorLabel(l10n_util::GetStringFUTF16( IDS_PASSWORD_MANAGER_PASSKEY_FROM_PHONE, *priority_phone_name));
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc index 2da5ead7..0b9a7c1 100644 --- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc +++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -99,11 +99,14 @@ return l10n_util::GetStringFUTF16(IDS_WEBAUTHN_SOURCE_PHONE, base::UTF8ToUTF16(*phone_name)); } + bool immediate_mode = UIPresentation::kModalImmediate == ui_presentation; if (cred.provider_name) { - return base::UTF8ToUTF16(*cred.provider_name); + return immediate_mode ? l10n_util::GetStringFUTF16( + IDS_PASSWORD_MANAGER_PASSKEY_FROM_PROVIDER, + base::UTF8ToUTF16(*cred.provider_name)) + : base::UTF8ToUTF16(*cred.provider_name); } int message; - bool immediate_mode = UIPresentation::kModalImmediate == ui_presentation; switch (cred.source) { case device::AuthenticatorType::kWinNative: message = immediate_mode ? IDS_PASSWORD_MANAGER_PASSKEY_FROM_WINDOWS_HELLO
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc index e8f514b6..fd2c4cc 100644 --- a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc +++ b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
@@ -3046,7 +3046,9 @@ delegate->GetPasskeys().value(); ASSERT_TRUE(autofill_passkeys); EXPECT_EQ(autofill_passkeys->size(), 1u); - EXPECT_EQ(autofill_passkeys->at(0).GetAuthenticatorLabel(), u"Bitwarden"); + EXPECT_THAT( + base::UTF16ToUTF8(autofill_passkeys->at(0).GetAuthenticatorLabel()), + testing::HasSubstr("Bitwarden")); } TEST_F(AuthenticatorRequestDialogControllerTest, MechanismsFromUserAccounts) {
diff --git a/chrome/browser/webid/proto/fedcm_clickthrough_rate_metadata.proto b/chrome/browser/webid/proto/fedcm_clickthrough_rate_metadata.proto index f8fbb8e..207b55c4 100644 --- a/chrome/browser/webid/proto/fedcm_clickthrough_rate_metadata.proto +++ b/chrome/browser/webid/proto/fedcm_clickthrough_rate_metadata.proto
@@ -20,4 +20,8 @@ // Likelihood of FedCM sign-ins. Value is between 0 and 1. float likely_to_signin = 4; + + // Likelihood of data being used to compute the above fields is insufficient. + // e.g. Low data volume. Value is between 0 and 1. + float likely_insufficient_data = 5; }
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index d3789d2..e607377 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1746853952-1bd319a1e9a5519b40c220be6ac3c6775850864a-443628585681dafc55c69a328e9f421a1c78cd58.profdata +chrome-android32-main-1747029142-6e56a058419345ff9dc4e563c81fc62c0692a93f-6e9453de1be37ab16eb07df5f5381a853f5d5390.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index 3905338..d7fb2a4 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1746856966-bbfd9ead94ad300041664043c74a8d0fd7003e09-fd3c9752f640f74e4e050f351a86d1d24a99d465.profdata +chrome-android64-main-1747036366-c2131c3c68511c20492cdd22446fd8ebf59f6691-2f6c50e530a1787effec74a34da173489562d059.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 2ca63eb..c37cf58 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1746813443-bd2bc40ff4ac2cf081e86bacffa605f70c6389f5-4cac03e32f70f02cbf11d96b5da54e629616b531.profdata +chrome-linux-main-1747007673-68e52f875aacc6f3724621726c0344be3862321e-7ec6dd136868a0188ec2230417d1c1a4b84db68b.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index f20f5a9..1b5a958 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1746853952-316cdb8201abcfb50caace1a04955bb0ec2f657f-443628585681dafc55c69a328e9f421a1c78cd58.profdata +chrome-mac-arm-main-1747036388-7577336db2baa3628af02328bb04d685eb7de7fc-6839328ba05c2600629ce83fbf784b29574f9b4c.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index eca1de4a..1fc4ed0 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1746791612-b7c5d963afdadff5d75fc3f86a645bdd7da79669-4852d4ffeefa31265675175f00edcf84c5e30ecd.profdata +chrome-mac-main-1747029142-e2474329ecfaff735404a5e7de6aa2c31ca2c90a-6e9453de1be37ab16eb07df5f5381a853f5d5390.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index 08d1e0cf..a1dcb6c1 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1746834836-8f54c968cd61e3c72144519df91694e9f9b6e63e-3179e5ae5e5290f009d4ec21dba738788dc2aa8b.profdata +chrome-win-arm64-main-1747029142-3d7a02bf1395f4d9209d7bb03103505c0ad8d6e3-6e9453de1be37ab16eb07df5f5381a853f5d5390.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 2680aa24..a1b948e 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1746834836-e21ef60066ec33fd83f124ab95a09c9de7f0bced-3179e5ae5e5290f009d4ec21dba738788dc2aa8b.profdata +chrome-win32-main-1747018210-cae43c07cb16fafe686dc0f6f00516ded7439460-1a403232281b462d1ac30d380312c60357bd5fae.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index c5994bb0..f96a9e0d 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1746813443-d0177f3ef39a67571bea32758731e6d8f238d388-4cac03e32f70f02cbf11d96b5da54e629616b531.profdata +chrome-win64-main-1746996658-cbdba33d0b37a918ff65ae745bf0439d6a3d0650-6d18a511a4bd3fe7184e30d8ba793cbb4864e0b2.profdata
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index e027833..959e78c6 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -1995,6 +1995,11 @@ inline constexpr char kReportingEndpoints[] = "enterprise_reporting.reporting_endpoints"; +// A boolean indicating if the "Line wrap" checkbox on view source pages should +// be prepopulated. +inline constexpr char kViewSourceLineWrappingEnabled[] = + "view_source.line_wrapping_enabled"; + #if BUILDFLAG(IS_CHROMEOS) // The state of the SkyVault migration of local files to the cloud. inline constexpr char kSkyVaultMigrationState[] = "skyvault.migration_state";
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 0f49a8e..875bf0c5 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -16279.0.0-1068758 \ No newline at end of file +16281.0.0-1068809 \ No newline at end of file
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt index bd961538..80c93ba 100644 --- a/chromeos/profiles/arm.afdo.newest.txt +++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-none-138-7137.0-1746411594-benchmark-138.0.7166.0-r1-redacted.afdo.xz +chromeos-chrome-arm-none-138-7137.0-1746411594-benchmark-138.0.7171.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt index d7ce078..3e8c0da 100644 --- a/chromeos/profiles/atom.afdo.newest.txt +++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-atom-138-7137.0-1746412216-benchmark-138.0.7166.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-atom-138-7137.0-1746412216-benchmark-138.0.7171.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt index e78d7ba..b0c694c 100644 --- a/chromeos/profiles/bigcore.afdo.newest.txt +++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-bigcore-138-7137.0-1746414666-benchmark-138.0.7166.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-bigcore-138-7137.0-1746414666-benchmark-138.0.7171.0-r1-redacted.afdo.xz
diff --git a/clank b/clank index 687392b..aafe4fa 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 687392ba3de05f6fae3002d7b7435b231d048dce +Subproject commit aafe4fa62195c0fd6b7395c85e2d4769300f8c76
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc index 2d5fb9c..0c61559 100644 --- a/components/autofill/content/renderer/autofill_agent.cc +++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -496,7 +496,11 @@ const std::optional<PasswordSuggestionRequest>& password_request) override { DeferMsg(&mojom::AutofillDriver::AskForValuesToFill, form, field_id, - caret_bounds, trigger_source, std::nullopt); + caret_bounds, trigger_source, + base::FeatureList::IsEnabled( + features::kAutofillAndPasswordsInSameSurface) + ? password_request + : std::nullopt); } void HidePopup() override { DeferMsg(&mojom::AutofillDriver::HidePopup); } void FocusOnNonFormField() override { @@ -876,11 +880,14 @@ // Show suggestions empty password fields or for username fields with // matching suggestions - even if non-empty. if (is_password_field && !is_field_empty) { - if (auto* autofill_driver = unsafe_autofill_driver()) { - autofill_driver->HidePopup(); - is_popup_possibly_visible_ = false; - return false; - } + HidePopup(); + return false; + } + + if (base::FeatureList::IsEnabled( + features::kAutofillAndPasswordsInSameSurface)) { + // No update to `is_popup_possibly_visible_` yet: it could still be open. + return false; } if (password_request) {
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc index 3348ca2ce2b..6d2ea0c 100644 --- a/components/autofill/core/common/autofill_features.cc +++ b/components/autofill/core/common/autofill_features.cc
@@ -142,6 +142,12 @@ const base::FeatureParam<int> kAutofillAiWithDataSchemaServerExperimentId{ &kAutofillAiWithDataSchema, "autofill_ai_server_experiment_id", 0}; +// Guards the refactoring to allow showing Autofill and Password suggestions in +// the same surface instead of being mutually exclusive. +BASE_FEATURE(kAutofillAndPasswordsInSameSurface, + "AutofillAndPasswordsInSameSurface", + base::FEATURE_DISABLED_BY_DEFAULT); + // Same as `kAutofillAddressUserPerceptionSurvey` but for credit card forms. BASE_FEATURE(kAutofillCreditCardUserPerceptionSurvey, "AutofillCreditCardUserPerceptionSurvey",
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h index 964412b..369c111 100644 --- a/components/autofill/core/common/autofill_features.h +++ b/components/autofill/core/common/autofill_features.h
@@ -54,6 +54,8 @@ extern const base::FeatureParam<int> kAutofillAiWithDataSchemaServerExperimentId; COMPONENT_EXPORT(AUTOFILL) +BASE_DECLARE_FEATURE(kAutofillAndPasswordsInSameSurface); +COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillCreditCardUserPerceptionSurvey); COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillAddressUserDeclinedSuggestionSurvey);
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json index 92eae0b..2714512e 100644 --- a/components/certificate_transparency/data/log_list.json +++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@ { - "version": "53.38", - "log_list_timestamp": "2025-05-09T12:53:32Z", + "version": "53.41", + "log_list_timestamp": "2025-05-11T12:55:05Z", "operators": [ { "name": "Google",
diff --git a/components/facilitated_payments/core/browser/BUILD.gn b/components/facilitated_payments/core/browser/BUILD.gn index f78e0c4..4895488 100644 --- a/components/facilitated_payments/core/browser/BUILD.gn +++ b/components/facilitated_payments/core/browser/BUILD.gn
@@ -23,6 +23,8 @@ "network_api/facilitated_payments_network_interface.h", "network_api/multiple_request_facilitated_payments_network_interface.cc", "network_api/multiple_request_facilitated_payments_network_interface.h", + "pix_account_linking_manager.cc", + "pix_account_linking_manager.h", "pix_manager.cc", "pix_manager.h", "strike_databases/payment_link_suggestion_strike_database.h",
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_client.cc b/components/facilitated_payments/core/browser/facilitated_payments_client.cc index cf3aa29..0836291 100644 --- a/components/facilitated_payments/core/browser/facilitated_payments_client.cc +++ b/components/facilitated_payments/core/browser/facilitated_payments_client.cc
@@ -4,14 +4,22 @@ #include "components/facilitated_payments/core/browser/facilitated_payments_client.h" +#include <memory> +#include <utility> + #include "base/containers/span.h" #include "base/functional/callback.h" #include "components/autofill/core/browser/data_model/payments/bank_account.h" #include "components/autofill/core/browser/data_model/payments/ewallet.h" +#include "components/facilitated_payments/core/browser/pix_account_linking_manager.h" #include "components/facilitated_payments/core/utils/facilitated_payments_ui_utils.h" namespace payments::facilitated { +FacilitatedPaymentsClient::FacilitatedPaymentsClient() { + pix_account_linking_manager_ = std::make_unique<PixAccountLinkingManager>(); +} + FacilitatedPaymentsClient::~FacilitatedPaymentsClient() = default; void FacilitatedPaymentsClient::ShowPixPaymentPrompt( @@ -31,4 +39,13 @@ void FacilitatedPaymentsClient::SetUiEventListener( base::RepeatingCallback<void(UiEvent)> ui_event_listener) {} +void FacilitatedPaymentsClient::InitPixAccountLinkingFlow() { + pix_account_linking_manager_->MaybeShowPixAccountLinkingPrompt(); +} + +void FacilitatedPaymentsClient::SetPixAccountLinkingManagerForTesting( + std::unique_ptr<PixAccountLinkingManager> pix_account_linking_manager) { + pix_account_linking_manager_ = std::move(pix_account_linking_manager); +} + } // namespace payments::facilitated
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_client.h b/components/facilitated_payments/core/browser/facilitated_payments_client.h index 4a7d321..2d6163e 100644 --- a/components/facilitated_payments/core/browser/facilitated_payments_client.h +++ b/components/facilitated_payments/core/browser/facilitated_payments_client.h
@@ -6,6 +6,7 @@ #define COMPONENTS_FACILITATED_PAYMENTS_CORE_BROWSER_FACILITATED_PAYMENTS_CLIENT_H_ #include <cstdint> +#include <memory> #include <optional> #include "base/containers/span.h" @@ -27,6 +28,7 @@ namespace payments::facilitated { +class PixAccountLinkingManager; class FacilitatedPaymentsNetworkInterface; class MultipleRequestFacilitatedPaymentsNetworkInterface; @@ -34,6 +36,7 @@ // A cross-platform client interface for showing UI for non-form based FOPs. class FacilitatedPaymentsClient : public autofill::RiskDataLoader { public: + FacilitatedPaymentsClient(); ~FacilitatedPaymentsClient() override; // Gets the `PaymentsDataManager` instance associated with the Chrome profile. @@ -109,6 +112,15 @@ // Gets the StrikeDatabase associated with the client. Note: Nullptr may be // returned so check before use. virtual autofill::StrikeDatabase* GetStrikeDatabase() = 0; + + // Virtual so it can be overridden in tests. + virtual void InitPixAccountLinkingFlow(); + + void SetPixAccountLinkingManagerForTesting( + std::unique_ptr<PixAccountLinkingManager> pix_account_linking_manager); + + private: + std::unique_ptr<PixAccountLinkingManager> pix_account_linking_manager_; }; } // namespace payments::facilitated
diff --git a/components/facilitated_payments/core/browser/mock_facilitated_payments_client.h b/components/facilitated_payments/core/browser/mock_facilitated_payments_client.h index fe4a340..5247613f 100644 --- a/components/facilitated_payments/core/browser/mock_facilitated_payments_client.h +++ b/components/facilitated_payments/core/browser/mock_facilitated_payments_client.h
@@ -71,6 +71,7 @@ MOCK_METHOD(void, ShowErrorScreen, (), (override)); MOCK_METHOD(void, DismissPrompt, (), (override)); MOCK_METHOD(autofill::StrikeDatabase*, GetStrikeDatabase, (), (override)); + MOCK_METHOD(void, InitPixAccountLinkingFlow, (), (override)); }; } // namespace payments::facilitated
diff --git a/components/facilitated_payments/core/browser/pix_account_linking_manager.cc b/components/facilitated_payments/core/browser/pix_account_linking_manager.cc new file mode 100644 index 0000000..1c56f2cf --- /dev/null +++ b/components/facilitated_payments/core/browser/pix_account_linking_manager.cc
@@ -0,0 +1,11 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/facilitated_payments/core/browser/pix_account_linking_manager.h" + +namespace payments::facilitated { + +void PixAccountLinkingManager::MaybeShowPixAccountLinkingPrompt() {} + +} // namespace payments::facilitated
diff --git a/components/facilitated_payments/core/browser/pix_account_linking_manager.h b/components/facilitated_payments/core/browser/pix_account_linking_manager.h new file mode 100644 index 0000000..c761d93 --- /dev/null +++ b/components/facilitated_payments/core/browser/pix_account_linking_manager.h
@@ -0,0 +1,29 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_FACILITATED_PAYMENTS_CORE_BROWSER_PIX_ACCOUNT_LINKING_MANAGER_H_ +#define COMPONENTS_FACILITATED_PAYMENTS_CORE_BROWSER_PIX_ACCOUNT_LINKING_MANAGER_H_ + +namespace payments::facilitated { + +// A cross-platform interface that manages the Pix account linking flow. It is +// owned by `FacilitatedPaymentsClient`. There is 1 instance of this class per +// tab. Its lifecycle is same as that of `FacilitatedPaymentsClient`. + +// The Pix account linking prompt is shown after the user has paid on their bank +// app and returned to Chrome. Some merchants show the order status causing page +// navigations. To overcome such cases, the manager should be associated with +// the tab, and not a single frame. +class PixAccountLinkingManager { + public: + virtual ~PixAccountLinkingManager() = default; + + // Initialize the Pix account linking flow. Virtual so it can be overridden in + // tests. + virtual void MaybeShowPixAccountLinkingPrompt(); +}; + +} // namespace payments::facilitated + +#endif // COMPONENTS_FACILITATED_PAYMENTS_CORE_BROWSER_PIX_ACCOUNT_LINKING_MANAGER_H_
diff --git a/components/facilitated_payments/core/browser/pix_manager.cc b/components/facilitated_payments/core/browser/pix_manager.cc index 940f1e9..a0967a5f 100644 --- a/components/facilitated_payments/core/browser/pix_manager.cc +++ b/components/facilitated_payments/core/browser/pix_manager.cc
@@ -139,6 +139,9 @@ if (!payments_data_manager->HasMaskedBankAccounts()) { LogPixFlowExitedReason(PixFlowExitedReason::kNoLinkedAccount); + if (base::FeatureList::IsEnabled(kEnablePixAccountLinking)) { + client_->InitPixAccountLinkingFlow(); + } return; }
diff --git a/components/facilitated_payments/core/browser/pix_manager.h b/components/facilitated_payments/core/browser/pix_manager.h index 7e684b6f..8921f12a 100644 --- a/components/facilitated_payments/core/browser/pix_manager.h +++ b/components/facilitated_payments/core/browser/pix_manager.h
@@ -124,6 +124,12 @@ PayflowExitedReason_CodeValidatorFailed); FRIEND_TEST_ALL_PREFIXES(PixManagerTest, PayflowExitedReason_InvalidCode); FRIEND_TEST_ALL_PREFIXES(PixManagerTest, PayflowExitedReason_NoLinkedAccount); + FRIEND_TEST_ALL_PREFIXES( + PixManagerTest, + NoLinkedAccount_AccountLinkingFlagDisabled_AccountLinkingFlowNotTriggered); + FRIEND_TEST_ALL_PREFIXES( + PixManagerTest, + NoLinkedAccount_AccountLinkingFlagEnabled_AccountLinkingFlowTriggered); FRIEND_TEST_ALL_PREFIXES(PixManagerTest, PayflowExitedReason_RiskDataEmpty); FRIEND_TEST_ALL_PREFIXES(PixManagerTest, PayflowExitedReason_UserOptedOut); FRIEND_TEST_ALL_PREFIXES(PixManagerTest,
diff --git a/components/facilitated_payments/core/browser/pix_manager_unittest.cc b/components/facilitated_payments/core/browser/pix_manager_unittest.cc index 0c49e09..c241fb67 100644 --- a/components/facilitated_payments/core/browser/pix_manager_unittest.cc +++ b/components/facilitated_payments/core/browser/pix_manager_unittest.cc
@@ -531,6 +531,31 @@ /*expected_bucket_count=*/1); } +TEST_F( + PixManagerTest, + NoLinkedAccount_AccountLinkingFlagDisabled_AccountLinkingFlowNotTriggered) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(kEnablePixAccountLinking); + + EXPECT_CALL(*client_, InitPixAccountLinkingFlow).Times(0); + + pix_manager_->OnPixCodeValidated(/*pix_code=*/std::string(), + base::TimeTicks::Now(), + /*is_pix_code_valid=*/true); +} + +TEST_F(PixManagerTest, + NoLinkedAccount_AccountLinkingFlagEnabled_AccountLinkingFlowTriggered) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(kEnablePixAccountLinking); + + EXPECT_CALL(*client_, InitPixAccountLinkingFlow); + + pix_manager_->OnPixCodeValidated(/*pix_code=*/std::string(), + base::TimeTicks::Now(), + /*is_pix_code_valid=*/true); +} + // If the validation utility process has disconnected (e.g., due to a crash in // the validation code), then the manager does not check the API for // availability.
diff --git a/components/offline_pages/content/background_loader/background_loader_contents.cc b/components/offline_pages/content/background_loader/background_loader_contents.cc index 9dcf196..14f2758 100644 --- a/components/offline_pages/content/background_loader/background_loader_contents.cc +++ b/components/offline_pages/content/background_loader/background_loader_contents.cc
@@ -21,8 +21,10 @@ // CreateParams::initially_hidden == false, and that we never change the // visibility after that. If we did change it, then background throttling // could kill the background offliner while it was running. - web_contents_ = content::WebContents::Create( - content::WebContents::CreateParams(browser_context_)); + content::WebContents::CreateParams create_params(browser_context_); + // Background, so not user-visible. + create_params.is_never_composited = true; + web_contents_ = content::WebContents::Create(create_params); web_contents_->SetOwnerLocationForDebug(FROM_HERE); web_contents_->SetAudioMuted(true); web_contents_->SetDelegate(this); @@ -46,12 +48,6 @@ delegate_ = delegate; } -bool BackgroundLoaderContents::IsNeverComposited( - content::WebContents* web_contents) { - // Background, so not user-visible. - return true; -} - void BackgroundLoaderContents::CloseContents(content::WebContents* source) { // Do nothing. Other pages should not be able to close a background page. //
diff --git a/components/offline_pages/content/background_loader/background_loader_contents.h b/components/offline_pages/content/background_loader/background_loader_contents.h index b3fef77c..b969f1d9 100644 --- a/components/offline_pages/content/background_loader/background_loader_contents.h +++ b/components/offline_pages/content/background_loader/background_loader_contents.h
@@ -54,7 +54,6 @@ content::WebContents* web_contents() { return web_contents_.get(); } // content::WebContentsDelegate implementation: - bool IsNeverComposited(content::WebContents* web_contents) override; void CloseContents(content::WebContents* source) override; bool ShouldSuppressDialogs(content::WebContents* source) override; bool ShouldFocusPageAfterCrash(content::WebContents* source) override;
diff --git a/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc b/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc index 00e0635f..159a3ef 100644 --- a/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc +++ b/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
@@ -107,10 +107,6 @@ waiter_.Signal(); } -TEST_F(BackgroundLoaderContentsTest, NotVisible) { - ASSERT_TRUE(contents()->IsNeverComposited(nullptr)); -} - TEST_F(BackgroundLoaderContentsTest, SuppressDialogs) { ASSERT_TRUE(contents()->ShouldSuppressDialogs(nullptr)); }
diff --git a/components/password_manager_strings.grdp b/components/password_manager_strings.grdp index 1bc64af..82ccd947 100644 --- a/components/password_manager_strings.grdp +++ b/components/password_manager_strings.grdp
@@ -110,6 +110,9 @@ <message name="IDS_PASSWORD_MANAGER_PASSKEY_FROM_PHONE" desc="Text that appears in the password autofill popup, for a passkey from a phone that the user owns. When the user clicks on this option, Chrome will ask the user to verify their identity on their phone (e.g. by tapping the fingerprint sensor). Refer to Glossary for the meaning of 'passkey'; do not translate it as 'password'."> Passkey • "<ph name="PHONE_NAME">$1<ex>Pixel 7</ex></ph>" </message> + <message name="IDS_PASSWORD_MANAGER_PASSKEY_FROM_PROVIDER" desc="Text that appears in the password autofill popup, for a passkey in a provider on the OS. When the user clicks on this option, Chrome will invoke the provider to continue the authentication ceremony. Refer to Glossary for the meaning of 'passkey'; do not translate it as 'password'."> + Passkey • <ph name="PROVIDER_NAME">$1<ex>Apple Passwords</ex></ph> + </message> <message name="IDS_PASSWORD_MANAGER_PASSWORD_FROM_GOOGLE_PASSWORD_MANAGER" desc="Text that appears for a password on a dialog that can display both passwords and passkeys for the user to select."> Password • Google Password Manager </message>
diff --git a/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_PASSKEY_FROM_PROVIDER.png.sha1 b/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_PASSKEY_FROM_PROVIDER.png.sha1 new file mode 100644 index 0000000..610e144 --- /dev/null +++ b/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_PASSKEY_FROM_PROVIDER.png.sha1
@@ -0,0 +1 @@ +0b2fe2ef7576f83322418bc91e68b250ac71a066 \ No newline at end of file
diff --git a/components/segmentation_platform/embedder/default_model/fedcm_user_segment.cc b/components/segmentation_platform/embedder/default_model/fedcm_user_segment.cc index cd7b7a7..158ddf5 100644 --- a/components/segmentation_platform/embedder/default_model/fedcm_user_segment.cc +++ b/components/segmentation_platform/embedder/default_model/fedcm_user_segment.cc
@@ -21,7 +21,8 @@ using proto::SegmentId; // Default parameters for FedCM user model. -constexpr SegmentId kFedCmUserSegmentId = SegmentId::FEDCM_USER; +constexpr SegmentId kFedCmUserSegmentId = + SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_FEDCM_USER; // Store 28 buckets of input data (28 days). constexpr int64_t kFedCmUserSignalStorageLength = 28; // Collect signals immediately.
diff --git a/components/segmentation_platform/public/constants.h b/components/segmentation_platform/public/constants.h index 5ecb8f2..9e00bff 100644 --- a/components/segmentation_platform/public/constants.h +++ b/components/segmentation_platform/public/constants.h
@@ -264,6 +264,7 @@ const char kFedCmPerImpressionClickthroughRate[] = "per_impression_clickthrough_rate"; const char kFedCmLikelyToSignin[] = "likely_to_signin"; +const char kFedCmLikelyInsufficientData[] = "likely_insufficient_data"; } // namespace segmentation_platform
diff --git a/components/segmentation_platform/public/proto/segmentation_platform.proto b/components/segmentation_platform/public/proto/segmentation_platform.proto index 4eb047b..ea0212a 100644 --- a/components/segmentation_platform/public/proto/segmentation_platform.proto +++ b/components/segmentation_platform/public/proto/segmentation_platform.proto
@@ -115,5 +115,5 @@ // Test model for EPHEMERAL_HOME_MODULE_BACKEND. EPHEMERAL_HOME_MODULE_BACKEND_TEST = 1012; // Segment for users who use FedCM. - FEDCM_USER = 1013; + // FEDCM_USER = 1013; // Deprecated. };
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.cc index a1b65f82..5a0ce259 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.cc +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.cc
@@ -179,6 +179,12 @@ DVLOG(1) << "ProfileOAuth2TokenServiceDelegateAndroid::RefreshTokenIsAvailable" << " account= " << account_id; + if (base::FeatureList::IsEnabled( + switches::kMakeAccountsAvailableInIdentityManager)) { + std::vector<CoreAccountId> accounts = GetValidAccounts(); + return base::Contains(accounts, account_id); + } + std::string account_name = MapAccountIdToAccountName(account_id); if (account_name.empty()) { // This corresponds to the case when the account with id |account_id| is not @@ -203,7 +209,7 @@ } std::vector<CoreAccountId> -ProfileOAuth2TokenServiceDelegateAndroid::GetValidAccounts() { +ProfileOAuth2TokenServiceDelegateAndroid::GetValidAccounts() const { std::vector<CoreAccountId> ids; for (const CoreAccountId& id : GetAccounts()) { if (ValidateAccountId(id)) { @@ -321,7 +327,9 @@ std::vector<CoreAccountId>* refreshed_ids, std::vector<CoreAccountId>* revoked_ids) { bool keep_accounts = - signed_in_id.has_value() && base::Contains(curr_ids, *signed_in_id); + base::FeatureList::IsEnabled( + switches::kMakeAccountsAvailableInIdentityManager) || + (signed_in_id.has_value() && base::Contains(curr_ids, *signed_in_id)); if (keep_accounts) { // Revoke token for ids that have been removed from the device. for (const CoreAccountId& prev_id : prev_ids) {
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.h b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.h index c287468..5c53f6b 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.h +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.h
@@ -109,7 +109,7 @@ std::vector<CoreAccountId>* refreshed_ids, std::vector<CoreAccountId>* revoked_ids); // As |GetAccounts| but with only validated account IDs. - std::vector<CoreAccountId> GetValidAccounts(); + std::vector<CoreAccountId> GetValidAccounts() const; // Set accounts that have been advertised by OnRefreshTokenAvailable. virtual void SetAccounts(const std::vector<CoreAccountId>& accounts);
diff --git a/components/signin/public/base/signin_feature_map.cc b/components/signin/public/base/signin_feature_map.cc index 3e678809..31ed27c 100644 --- a/components/signin/public/base/signin_feature_map.cc +++ b/components/signin/public/base/signin_feature_map.cc
@@ -28,6 +28,7 @@ &switches::kUseHostedDomainForManagementCheckOnSignin, &switches::kSyncEnableBookmarksInTransportMode, &switches::kHistoryOptInEducationalTip, + &switches::kMakeAccountsAvailableInIdentityManager, }; // static
diff --git a/components/signin/public/base/signin_switches.cc b/components/signin/public/base/signin_switches.cc index d23fefb4..f29cf40 100644 --- a/components/signin/public/base/signin_switches.cc +++ b/components/signin/public/base/signin_switches.cc
@@ -54,6 +54,10 @@ BASE_FEATURE(kUseHostedDomainForManagementCheckOnSignin, "UseHostedDomainForManagementCheckOnSignin", base::FEATURE_DISABLED_BY_DEFAULT); + +BASE_FEATURE(kMakeAccountsAvailableInIdentityManager, + "MakeAccountsAvailableInIdentityManager", + base::FEATURE_DISABLED_BY_DEFAULT); #endif #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
diff --git a/components/signin/public/base/signin_switches.h b/components/signin/public/base/signin_switches.h index 061e2da..b7119248 100644 --- a/components/signin/public/base/signin_switches.h +++ b/components/signin/public/base/signin_switches.h
@@ -50,6 +50,9 @@ COMPONENT_EXPORT(SIGNIN_SWITCHES) BASE_DECLARE_FEATURE(kUseHostedDomainForManagementCheckOnSignin); + +COMPONENT_EXPORT(SIGNIN_SWITCHES) +BASE_DECLARE_FEATURE(kMakeAccountsAvailableInIdentityManager); #endif #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
diff --git a/components/signin/public/identity_manager/identity_mutator.cc b/components/signin/public/identity_manager/identity_mutator.cc index ea35807..5e22bb0b 100644 --- a/components/signin/public/identity_manager/identity_mutator.cc +++ b/components/signin/public/identity_manager/identity_mutator.cc
@@ -16,6 +16,7 @@ #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "components/signin/public/android/jni_headers/IdentityMutator_jni.h" +#include "components/signin/public/base/signin_switches.h" #include "components/signin/public/identity_manager/account_info.h" #endif @@ -46,12 +47,20 @@ return static_cast<jint>(error); } +// TODO(crbug.com/373290337): Rename this method after feature launch. bool JniIdentityMutator::ClearPrimaryAccount(JNIEnv* env, jint source_metric) { PrimaryAccountMutator* primary_account_mutator = identity_mutator_->GetPrimaryAccountMutator(); DCHECK(primary_account_mutator); - return primary_account_mutator->ClearPrimaryAccount( - static_cast<signin_metrics::ProfileSignout>(source_metric)); + if (base::FeatureList::IsEnabled( + switches::kMakeAccountsAvailableInIdentityManager)) { + // If the feature is enabled we will not clear the accounts. + return primary_account_mutator->RemovePrimaryAccountButKeepTokens( + static_cast<signin_metrics::ProfileSignout>(source_metric)); + } else { + return primary_account_mutator->ClearPrimaryAccount( + static_cast<signin_metrics::ProfileSignout>(source_metric)); + } } void JniIdentityMutator::RevokeSyncConsent(JNIEnv* env, jint source_metric) {
diff --git a/components/viz/service/layers/layer_context_impl.cc b/components/viz/service/layers/layer_context_impl.cc index 8165498..b0a2569 100644 --- a/components/viz/service/layers/layer_context_impl.cc +++ b/components/viz/service/layers/layer_context_impl.cc
@@ -158,6 +158,7 @@ cc::DamageReasonSet::FromEnumBitmask(wire.damage_reasons_bit_mask))) { return base::unexpected("Invalid damage_reasons_bit_mask"); } + node.moved_by_safe_area_bottom = wire.moved_by_safe_area_bottom; return base::ok(); }
diff --git a/content/app/content_main.cc b/content/app/content_main.cc index ffc5c37..36248b2a 100644 --- a/content/app/content_main.cc +++ b/content/app/content_main.cc
@@ -86,6 +86,12 @@ #endif #endif // BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_IOS_TVOS) +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "content/shell/common/shell_switches.h" +#endif + namespace content { namespace { @@ -314,6 +320,15 @@ #if BUILDFLAG(IS_IOS_TVOS) // Set tvOS to single-process mode by default. command_line->AppendSwitch(switches::kSingleProcess); + + // On tvOS, local storage is limited and data cannot be written anywhere + // other than the cache directory, so `base::DIR_CACHE` is used for + // the user data directory. + base::FilePath path; + if (base::PathService::Get(base::DIR_CACHE, &path) && !path.empty()) { + command_line->AppendSwitchASCII(switches::kContentShellUserDataDir, + path.MaybeAsASCII()); + } #endif #endif
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index b40575d6..4c02b0a 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -2547,6 +2547,8 @@ "compute_pressure/web_contents_pressure_manager_proxy.cc", "compute_pressure/web_contents_pressure_manager_proxy.h", ] + + deps += [ "//services/device/public/cpp/compute_pressure" ] } if (use_viz_debugger) {
diff --git a/content/browser/compute_pressure/pressure_client_impl.cc b/content/browser/compute_pressure/pressure_client_impl.cc index 7846491..1b8c314 100644 --- a/content/browser/compute_pressure/pressure_client_impl.cc +++ b/content/browser/compute_pressure/pressure_client_impl.cc
@@ -6,6 +6,7 @@ #include "content/browser/compute_pressure/pressure_service_base.h" #include "services/device/public/mojom/pressure_update.mojom.h" +#include "third_party/blink/public/mojom/compute_pressure/web_pressure_update.mojom.h" namespace content { @@ -21,7 +22,17 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (service_->ShouldDeliverUpdate()) { - client_associated_remote_->OnPressureUpdated(std::move(update)); + device::mojom::PressureState state; + switch (update->source) { + case device::mojom::PressureSource::kCpu: + state = service_->CalculateState(update->data->cpu_utilization); + break; + default: + NOTREACHED(); + } + client_associated_remote_->OnPressureUpdated( + blink::mojom::WebPressureUpdate::New(update->source, state, + update->timestamp)); } } @@ -60,7 +71,7 @@ // Bind PressureClient pendingRemote from Blink. void PressureClientImpl::BindPendingAssociatedRemote( - mojo::PendingAssociatedRemote<device::mojom::PressureClient> + mojo::PendingAssociatedRemote<blink::mojom::WebPressureClient> pending_associated_remote) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/content/browser/compute_pressure/pressure_client_impl.h b/content/browser/compute_pressure/pressure_client_impl.h index 4249094..6b2e495 100644 --- a/content/browser/compute_pressure/pressure_client_impl.h +++ b/content/browser/compute_pressure/pressure_client_impl.h
@@ -13,6 +13,7 @@ #include "mojo/public/cpp/bindings/receiver.h" #include "services/device/public/mojom/pressure_manager.mojom.h" #include "services/device/public/mojom/pressure_update.mojom-forward.h" +#include "third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom.h" namespace content { @@ -47,7 +48,7 @@ // Binds the associated remote from the Blink-side. void BindPendingAssociatedRemote( - mojo::PendingAssociatedRemote<device::mojom::PressureClient>); + mojo::PendingAssociatedRemote<blink::mojom::WebPressureClient>); // Create pending remote endpoint to //services. mojo::PendingAssociatedRemote<device::mojom::PressureClient> @@ -87,7 +88,7 @@ sequence_checker_) client_associated_receiver_{this}; // Blink side. - mojo::AssociatedRemote<device::mojom::PressureClient> + mojo::AssociatedRemote<blink::mojom::WebPressureClient> client_associated_remote_ GUARDED_BY_CONTEXT(sequence_checker_); };
diff --git a/content/browser/compute_pressure/pressure_service_base.cc b/content/browser/compute_pressure/pressure_service_base.cc index f2e0d101..0902b3f2 100644 --- a/content/browser/compute_pressure/pressure_service_base.cc +++ b/content/browser/compute_pressure/pressure_service_base.cc
@@ -7,6 +7,7 @@ #include <algorithm> #include <utility> +#include "base/feature_list.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" @@ -14,6 +15,7 @@ #include "content/public/browser/video_picture_in_picture_window_controller.h" #include "mojo/public/cpp/bindings/message.h" #include "mojo/public/cpp/bindings/pending_receiver.h" +#include "services/device/public/cpp/device_features.h" namespace { @@ -34,7 +36,14 @@ namespace content { PressureServiceBase::PressureServiceBase() - : source_to_client_{PressureClientImpl(this)} {} + : source_to_client_{PressureClientImpl(this)} { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (base::FeatureList::IsEnabled( + features::kComputePressureBreakCalibrationMitigation)) { + converter_.EnableStateRandomizationMitigation(); + } +} PressureServiceBase::~PressureServiceBase() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -114,6 +123,11 @@ focused_frame->GetLastCommittedOrigin()); } +device::mojom::PressureState PressureServiceBase::CalculateState( + double pressure_value) { + return converter_.CalculateState(pressure_value); +} + bool PressureServiceBase::CanCallAddClient() const { return true; } @@ -144,7 +158,7 @@ void PressureServiceBase::AddClient( device::mojom::PressureSource source, - mojo::PendingAssociatedRemote<device::mojom::PressureClient> client, + mojo::PendingAssociatedRemote<blink::mojom::WebPressureClient> client, AddClientCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/content/browser/compute_pressure/pressure_service_base.h b/content/browser/compute_pressure/pressure_service_base.h index 1ac5e0e..c59d7af 100644 --- a/content/browser/compute_pressure/pressure_service_base.h +++ b/content/browser/compute_pressure/pressure_service_base.h
@@ -10,6 +10,7 @@ #include "base/functional/callback.h" #include "base/memory/weak_ptr.h" +#include "base/process/process_metrics.h" #include "base/sequence_checker.h" #include "base/thread_annotations.h" #include "base/unguessable_token.h" @@ -19,6 +20,7 @@ #include "mojo/public/cpp/bindings/pending_associated_remote.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" +#include "services/device/public/cpp/compute_pressure/cpu_pressure_converter.h" #include "services/device/public/mojom/pressure_manager.mojom.h" #include "third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom.h" @@ -50,7 +52,7 @@ // blink::mojom::WebPressureManager implementation. void AddClient( device::mojom::PressureSource source, - mojo::PendingAssociatedRemote<device::mojom::PressureClient> client, + mojo::PendingAssociatedRemote<blink::mojom::WebPressureClient> client, AddClientCallback callback) override; // WebContentsPressureManagerProxy::Observer implementation. @@ -59,6 +61,7 @@ // Verifies if the data should be delivered according to focus status. virtual bool ShouldDeliverUpdate() const = 0; + device::mojom::PressureState CalculateState(double cpu_utilization); // Returns a token for use with automation calls when one is set. virtual std::optional<base::UnguessableToken> GetTokenFor( @@ -98,6 +101,10 @@ AddClientCallback client_callback, device::mojom::PressureManagerAddClientResult); + // Handles break calibration mitigation and conversion from + // cpu_utilization to PressureState. + device::CpuPressureConverter converter_; + // Services side. mojo::Remote<device::mojom::PressureManager> manager_remote_ GUARDED_BY_CONTEXT(sequence_checker_);
diff --git a/content/browser/compute_pressure/pressure_service_browsertest.cc b/content/browser/compute_pressure/pressure_service_browsertest.cc index fdd55c52..bb16a4d 100644 --- a/content/browser/compute_pressure/pressure_service_browsertest.cc +++ b/content/browser/compute_pressure/pressure_service_browsertest.cc
@@ -26,6 +26,7 @@ namespace content { +using device::mojom::PressureData; using device::mojom::PressureSource; using device::mojom::PressureState; using device::mojom::PressureUpdate; @@ -149,7 +150,8 @@ // Deliver update. const base::TimeTicks time = base::TimeTicks::Now(); - PressureUpdate update(PressureSource::kCpu, PressureState::kNominal, time); + auto data = PressureData::New(/*cpu_utilization=*/0.30); + PressureUpdate update(PressureSource::kCpu, std::move(data), time); pressure_manager_overrider_.UpdateClients(std::move(update)); ASSERT_TRUE(ExecJs(shell(), "datasets.frame.waitForUpdates(1);")); @@ -180,7 +182,8 @@ // Deliver update. const base::TimeTicks time = base::TimeTicks::Now(); - PressureUpdate update(PressureSource::kCpu, PressureState::kNominal, time); + auto data = PressureData::New(/*cpu_utilization=*/0.30); + PressureUpdate update(PressureSource::kCpu, std::move(data), time); pressure_manager_overrider_.UpdateClients(std::move(update)); ASSERT_TRUE(ExecJs(shell(), "datasets.frame.waitForUpdates(1);")); @@ -211,7 +214,8 @@ // Deliver update. const base::TimeTicks time1 = base::TimeTicks::Now(); - PressureUpdate update1(PressureSource::kCpu, PressureState::kNominal, time1); + auto data1 = PressureData::New(/*cpu_utilization=*/0.30); + PressureUpdate update1(PressureSource::kCpu, std::move(data1), time1); pressure_manager_overrider_.UpdateClients(std::move(update1)); // Focus on main frame, observers can receive updates again. @@ -219,7 +223,8 @@ // Deliver update. const base::TimeTicks time2 = time1 + base::Seconds(2); - PressureUpdate update2(PressureSource::kCpu, PressureState::kFair, time2); + auto data2 = PressureData::New(/*cpu_utilization=*/0.70); + PressureUpdate update2(PressureSource::kCpu, std::move(data2), time2); pressure_manager_overrider_.UpdateClients(std::move(update2)); ASSERT_TRUE(ExecJs(shell(), "datasets.frame.waitForUpdates(1);")); @@ -258,7 +263,8 @@ // Deliver update. const base::TimeTicks time1 = base::TimeTicks::Now(); - PressureUpdate update1(PressureSource::kCpu, PressureState::kNominal, time1); + auto data1 = PressureData::New(/*cpu_utilization=*/0.30); + PressureUpdate update1(PressureSource::kCpu, std::move(data1), time1); pressure_manager_overrider_.UpdateClients(std::move(update1)); ASSERT_TRUE(ExecJs(shell(), "datasets.frame.waitForUpdates(1);")); @@ -281,7 +287,8 @@ // Deliver update. const base::TimeTicks time2 = time1 + base::Seconds(2); - PressureUpdate update2(PressureSource::kCpu, PressureState::kFair, time2); + auto data2 = PressureData::New(/*cpu_utilization=*/0.85); + PressureUpdate update2(PressureSource::kCpu, std::move(data2), time2); pressure_manager_overrider_.UpdateClients(std::move(update2)); // Focus on main frame, observers can receive updates again. @@ -289,7 +296,8 @@ // Deliver update. const base::TimeTicks time3 = time2 + base::Seconds(2); - PressureUpdate update3(PressureSource::kCpu, PressureState::kSerious, time3); + auto data3 = PressureData::New(/*cpu_utilization=*/0.85); + PressureUpdate update3(PressureSource::kCpu, std::move(data3), time3); pressure_manager_overrider_.UpdateClients(std::move(update3)); ASSERT_TRUE(ExecJs(shell(), "datasets.frame.waitForUpdates(2);")); @@ -324,7 +332,8 @@ // Deliver update. const base::TimeTicks time1 = base::TimeTicks::Now(); - PressureUpdate update1(PressureSource::kCpu, PressureState::kNominal, time1); + auto data1 = PressureData::New(/*cpu_utilization=*/0.30); + PressureUpdate update1(PressureSource::kCpu, std::move(data1), time1); pressure_manager_overrider_.UpdateClients(std::move(update1)); ASSERT_TRUE(ExecJs(shell(), "datasets.frame.waitForUpdates(1);")); @@ -346,7 +355,8 @@ // Deliver update. const base::TimeTicks time2 = time1 + base::Seconds(2); - PressureUpdate update2(PressureSource::kCpu, PressureState::kFair, time2); + auto data2 = PressureData::New(/*cpu_utilization=*/0.70); + PressureUpdate update2(PressureSource::kCpu, std::move(data2), time2); pressure_manager_overrider_.UpdateClients(std::move(update2)); // Focus on main frame, observers can receive updates again. @@ -354,7 +364,8 @@ // Deliver update. const base::TimeTicks time3 = time2 + base::Seconds(2); - PressureUpdate update3(PressureSource::kCpu, PressureState::kSerious, time3); + auto data3 = PressureData::New(/*cpu_utilization=*/0.85); + PressureUpdate update3(PressureSource::kCpu, std::move(data3), time3); pressure_manager_overrider_.UpdateClients(std::move(update3)); ASSERT_TRUE(ExecJs(shell(), "datasets.frame.waitForUpdates(2);"));
diff --git a/content/browser/compute_pressure/pressure_service_for_frame_unittest.cc b/content/browser/compute_pressure/pressure_service_for_frame_unittest.cc index e29fb1ff..e7699bd 100644 --- a/content/browser/compute_pressure/pressure_service_for_frame_unittest.cc +++ b/content/browser/compute_pressure/pressure_service_for_frame_unittest.cc
@@ -30,10 +30,13 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom.h" +#include "third_party/blink/public/mojom/compute_pressure/web_pressure_update.mojom.h" #include "url/gurl.h" namespace content { +using blink::mojom::WebPressureUpdate; +using device::mojom::PressureData; using device::mojom::PressureManagerAddClientResult; using device::mojom::PressureSource; using device::mojom::PressureState; @@ -42,7 +45,7 @@ namespace { // Test double for PressureClient that records all updates. -class FakePressureClient : public device::mojom::PressureClient { +class FakePressureClient : public blink::mojom::WebPressureClient { public: FakePressureClient() : associated_receiver_(this) {} ~FakePressureClient() override { @@ -52,18 +55,18 @@ FakePressureClient(const FakePressureClient&) = delete; FakePressureClient& operator=(const FakePressureClient&) = delete; - // device::mojom::PressureClient implementation. - void OnPressureUpdated(device::mojom::PressureUpdatePtr state) override { + // blink::mojom::WebPressureClient implementation. + void OnPressureUpdated(blink::mojom::WebPressureUpdatePtr update) override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - updates_.push_back(*state); + updates_.push_back(*update); if (update_callback_) { std::move(update_callback_).Run(); update_callback_.Reset(); } } - std::vector<PressureUpdate>& updates() { + std::vector<WebPressureUpdate>& updates() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return updates_; } @@ -94,19 +97,19 @@ run_loop.Run(); } - mojo::AssociatedReceiver<device::mojom::PressureClient>& receiver() { + mojo::AssociatedReceiver<blink::mojom::WebPressureClient>& receiver() { return associated_receiver_; } private: SEQUENCE_CHECKER(sequence_checker_); - std::vector<PressureUpdate> updates_ GUARDED_BY_CONTEXT(sequence_checker_); + std::vector<WebPressureUpdate> updates_ GUARDED_BY_CONTEXT(sequence_checker_); // Used to implement WaitForUpdate(). base::OnceClosure update_callback_ GUARDED_BY_CONTEXT(sequence_checker_); - mojo::AssociatedReceiver<device::mojom::PressureClient> associated_receiver_ + mojo::AssociatedReceiver<blink::mojom::WebPressureClient> associated_receiver_ GUARDED_BY_CONTEXT(sequence_checker_); }; @@ -178,11 +181,15 @@ device::mojom::PressureManagerAddClientResult::kOk); const base::TimeTicks time = base::TimeTicks::Now(); - PressureUpdate update(PressureSource::kCpu, PressureState::kNominal, time); + auto data = PressureData::New(/*cpu_utilization=*/0.4); + PressureUpdate update(PressureSource::kCpu, std::move(data), time); pressure_manager_overrider_->UpdateClients(update); client.WaitForUpdate(); + ASSERT_EQ(client.updates().size(), 1u); - EXPECT_EQ(client.updates()[0], update); + EXPECT_EQ(client.updates()[0].source, update.source); + EXPECT_EQ(client.updates()[0].state, device::mojom::PressureState::kNominal); + EXPECT_EQ(client.updates()[0].timestamp, update.timestamp); } TEST_F(PressureServiceForFrameTest, WebContentPressureManagerProxyTest) {
diff --git a/content/browser/compute_pressure/pressure_service_for_worker_unittest.cc b/content/browser/compute_pressure/pressure_service_for_worker_unittest.cc index 82fe16e2..ed0f543 100644 --- a/content/browser/compute_pressure/pressure_service_for_worker_unittest.cc +++ b/content/browser/compute_pressure/pressure_service_for_worker_unittest.cc
@@ -33,10 +33,13 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/tokens/tokens.h" #include "third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom.h" +#include "third_party/blink/public/mojom/compute_pressure/web_pressure_update.mojom.h" #include "url/gurl.h" namespace content { +using blink::mojom::WebPressureUpdate; +using device::mojom::PressureData; using device::mojom::PressureManagerAddClientResult; using device::mojom::PressureSource; using device::mojom::PressureState; @@ -45,7 +48,7 @@ namespace { // Test double for PressureClient that records all updates. -class FakePressureClient : public device::mojom::PressureClient { +class FakePressureClient : public blink::mojom::WebPressureClient { public: FakePressureClient() : associated_receiver_(this) {} ~FakePressureClient() override { @@ -55,18 +58,18 @@ FakePressureClient(const FakePressureClient&) = delete; FakePressureClient& operator=(const FakePressureClient&) = delete; - // device::mojom::PressureClient implementation. - void OnPressureUpdated(device::mojom::PressureUpdatePtr state) override { + // blink::mojom::WebPressureClient implementation. + void OnPressureUpdated(blink::mojom::WebPressureUpdatePtr update) override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - updates_.push_back(*state); + updates_.push_back(*update); if (update_callback_) { std::move(update_callback_).Run(); update_callback_.Reset(); } } - std::vector<PressureUpdate>& updates() { + std::vector<WebPressureUpdate>& updates() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return updates_; } @@ -97,19 +100,19 @@ run_loop.Run(); } - mojo::AssociatedReceiver<device::mojom::PressureClient>& receiver() { + mojo::AssociatedReceiver<blink::mojom::WebPressureClient>& receiver() { return associated_receiver_; } private: SEQUENCE_CHECKER(sequence_checker_); - std::vector<PressureUpdate> updates_ GUARDED_BY_CONTEXT(sequence_checker_); + std::vector<WebPressureUpdate> updates_ GUARDED_BY_CONTEXT(sequence_checker_); // Used to implement WaitForUpdate(). base::OnceClosure update_callback_ GUARDED_BY_CONTEXT(sequence_checker_); - mojo::AssociatedReceiver<device::mojom::PressureClient> associated_receiver_ + mojo::AssociatedReceiver<blink::mojom::WebPressureClient> associated_receiver_ GUARDED_BY_CONTEXT(sequence_checker_); }; @@ -182,11 +185,14 @@ ASSERT_EQ(future.Get(), device::mojom::PressureManagerAddClientResult::kOk); const base::TimeTicks time = base::TimeTicks::Now(); - PressureUpdate update(PressureSource::kCpu, PressureState::kNominal, time); + auto data = PressureData::New(/*cpu_utilization=*/0.2); + PressureUpdate update(PressureSource::kCpu, std::move(data), time); pressure_manager_overrider_->UpdateClients(update); client.WaitForUpdate(); ASSERT_EQ(client.updates().size(), 1u); - EXPECT_EQ(client.updates()[0], update); + EXPECT_EQ(client.updates()[0].source, update.source); + EXPECT_EQ(client.updates()[0].state, device::mojom::PressureState::kNominal); + EXPECT_EQ(client.updates()[0].timestamp, update.timestamp); } TEST_F(PressureServiceForDedicatedWorkerTest, @@ -323,11 +329,14 @@ ASSERT_EQ(future.Get(), device::mojom::PressureManagerAddClientResult::kOk); const base::TimeTicks time = base::TimeTicks::Now(); - PressureUpdate update(PressureSource::kCpu, PressureState::kNominal, time); + auto data = PressureData::New(/*cpu_utilization=*/0.4); + PressureUpdate update(PressureSource::kCpu, std::move(data), time); pressure_manager_overrider_->UpdateClients(update); client.WaitForUpdate(); ASSERT_EQ(client.updates().size(), 1u); - EXPECT_EQ(client.updates()[0], update); + EXPECT_EQ(client.updates()[0].source, update.source); + EXPECT_EQ(client.updates()[0].state, device::mojom::PressureState::kNominal); + EXPECT_EQ(client.updates()[0].timestamp, update.timestamp); } TEST_F(PressureServiceForSharedWorkerTest, WebContentPressureManagerProxyTest) {
diff --git a/content/browser/media/media_devices_util.cc b/content/browser/media/media_devices_util.cc index d1c18cf..b31c5a31 100644 --- a/content/browser/media/media_devices_util.cc +++ b/content/browser/media/media_devices_util.cc
@@ -148,9 +148,7 @@ bool has_focus = frame_host->GetView() && frame_host->GetView()->HasFocus(); std::optional<ukm::SourceId> source_id = frame_host->GetPageUkmSourceId(); WebContents* web_contents = WebContents::FromRenderFrameHost(frame_host); - bool is_background = - web_contents && web_contents->GetDelegate() && - web_contents->GetDelegate()->IsNeverComposited(web_contents); + bool is_background = web_contents && web_contents->IsNeverComposited(); std::string frame_salt = frame_host->GetMediaDeviceIDSaltBase(); GetContentClient()->browser()->GetMediaDeviceIDSalt(
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 6e6d9a3e..1654ffb 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -765,10 +765,6 @@ return is_active(); } -bool RenderViewHostImpl::IsNeverComposited() { - return GetDelegate()->IsNeverComposited(); -} - blink::web_pref::WebPreferences RenderViewHostImpl::GetWebkitPreferencesForWidget() { if (!delegate_)
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h index f9dc4c4..6eade0d 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -349,7 +349,6 @@ bool ShouldContributePriorityToProcess() override; void SetBackgroundOpaque(bool opaque) override; bool IsMainFrameActive() override; - bool IsNeverComposited() override; blink::web_pref::WebPreferences GetWebkitPreferencesForWidget() override; // IPC message handlers.
diff --git a/content/browser/renderer_host/render_widget_host_owner_delegate.h b/content/browser/renderer_host/render_widget_host_owner_delegate.h index 70e387b..3fe4efa 100644 --- a/content/browser/renderer_host/render_widget_host_owner_delegate.h +++ b/content/browser/renderer_host/render_widget_host_owner_delegate.h
@@ -56,10 +56,6 @@ // Returns true if the main frame is active, false if it is swapped out. virtual bool IsMainFrameActive() = 0; - // Returns true if all widgets will never be user-visible, and thus do not - // need to generate pixels for display. - virtual bool IsNeverComposited() = 0; - // Returns the WebkitPreferences for the page. The preferences are shared // between all widgets for the page. virtual blink::web_pref::WebPreferences GetWebkitPreferencesForWidget() = 0;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index c7e153a0..8a0128a 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3912,6 +3912,7 @@ renderer_preferences_.uses_platform_autofill = params.initially_use_platform_autofill; + is_never_composited_ = params.is_never_composited; is_in_preview_mode_ = params.preview_mode; creator_location_ = params.creator_location; #if BUILDFLAG(IS_ANDROID) @@ -8986,10 +8987,7 @@ } bool WebContentsImpl::IsNeverComposited() { - if (!delegate_) { - return false; - } - return delegate_->IsNeverComposited(this); + return is_never_composited_; } RenderViewHostDelegateView* WebContentsImpl::GetDelegateView() {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 08497c5..05a401f 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -2259,6 +2259,10 @@ // use the observer list then. WebContentsObserverList observers_; + // True if the WebContents is never user-visible, thus the renderer need never + // produce pixels for display. + bool is_never_composited_ = false; + // True if this tab was opened by another window. This is true even if the tab // is opened with "noopener", and won't be unset if the opener is closed. bool opened_by_another_window_;
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index ea5856a..560e005 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -207,6 +207,10 @@ // True if the contents should be initially hidden. bool initially_hidden = false; + // Returns true if the WebContents is never user-visible, thus the renderer + // need never produce pixels for display. + bool is_never_composited = false; + // True if newly created WebContents should defer all autofill to the // platform. bool initially_use_platform_autofill = false; @@ -432,6 +436,10 @@ // Returns a weak pointer. virtual base::WeakPtr<WebContents> GetWeakPtr() = 0; + // Returns true if the WebContents is never user-visible and thus never need + // to generate pixels for display. + virtual bool IsNeverComposited() = 0; + // Gets the URL that is currently being displayed, if there is one. // This method is deprecated. DO NOT USE! Pick either |GetVisibleURL| or // |GetLastCommittedURL| as appropriate.
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc index aabcebe..f42be2a 100644 --- a/content/public/browser/web_contents_delegate.cc +++ b/content/public/browser/web_contents_delegate.cc
@@ -341,10 +341,6 @@ return gfx::Size(); } -bool WebContentsDelegate::IsNeverComposited(WebContents* web_contents) { - return false; -} - bool WebContentsDelegate::GuestSaveFrame(WebContents* guest_web_contents) { return false; }
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h index a9be46f..d332749 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h
@@ -654,10 +654,6 @@ // used. virtual gfx::Size GetSizeForNewRenderView(WebContents* web_contents); - // Returns true if the WebContents is never user-visible, thus the renderer - // never needs to produce pixels for display. - virtual bool IsNeverComposited(WebContents* web_contents); - // Askss |guest_web_contents| to perform the same. If this returns true, the // default behavior is suppressed. virtual bool GuestSaveFrame(WebContents* guest_web_contents);
diff --git a/content/public/test/content_browser_test.cc b/content/public/test/content_browser_test.cc index 9bfcb519d..c961c5a 100644 --- a/content/public/test/content_browser_test.cc +++ b/content/public/test/content_browser_test.cc
@@ -23,7 +23,7 @@ #include "content/public/test/test_browser_context.h" #include "content/shell/browser/shell.h" #include "content/shell/browser/shell_browser_context.h" -#include "content/shell/browser/shell_paths.h" +#include "content/shell/common/shell_paths.h" #include "content/shell/common/shell_switches.h" #include "content/test/test_content_client.h" #include "ui/events/platform/platform_event_source.h"
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index 86e25ae8..1695856 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -194,8 +194,6 @@ "browser/shell_javascript_dialog.h", "browser/shell_javascript_dialog_manager.cc", "browser/shell_javascript_dialog_manager.h", - "browser/shell_paths.cc", - "browser/shell_paths.h", "browser/shell_permission_manager.cc", "browser/shell_permission_manager.h", "browser/shell_platform_data_aura.cc", @@ -214,6 +212,8 @@ "common/shell_content_client.h", "common/shell_origin_trial_policy.cc", "common/shell_origin_trial_policy.h", + "common/shell_paths.cc", + "common/shell_paths.h", "common/shell_switches.cc", "common/shell_switches.h", "gpu/shell_content_gpu_client.cc",
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc index 5d6872df..d2abc51 100644 --- a/content/shell/app/shell_main_delegate.cc +++ b/content/shell/app/shell_main_delegate.cc
@@ -32,8 +32,8 @@ #include "content/public/common/url_constants.h" #include "content/shell/app/shell_crash_reporter_client.h" #include "content/shell/browser/shell_content_browser_client.h" -#include "content/shell/browser/shell_paths.h" #include "content/shell/common/shell_content_client.h" +#include "content/shell/common/shell_paths.h" #include "content/shell/common/shell_switches.h" #include "content/shell/gpu/shell_content_gpu_client.h" #include "content/shell/renderer/shell_content_renderer_client.h"
diff --git a/content/shell/browser/shell_browser_context.cc b/content/shell/browser/shell_browser_context.cc index f6fe21a8..0323671 100644 --- a/content/shell/browser/shell_browser_context.cc +++ b/content/shell/browser/shell_browser_context.cc
@@ -11,7 +11,6 @@ #include "base/environment.h" #include "base/files/file_util.h" #include "base/functional/bind.h" -#include "base/logging.h" #include "base/path_service.h" #include "base/threading/thread.h" #include "build/build_config.h" @@ -30,8 +29,8 @@ #include "content/shell/browser/shell_content_browser_client.h" #include "content/shell/browser/shell_content_index_provider.h" #include "content/shell/browser/shell_download_manager_delegate.h" -#include "content/shell/browser/shell_paths.h" #include "content/shell/browser/shell_permission_manager.h" +#include "content/shell/common/shell_paths.h" #include "content/shell/common/shell_switches.h" #include "content/test/mock_background_sync_controller.h" #include "content/test/mock_reduce_accept_language_controller_delegate.h" @@ -74,24 +73,6 @@ if (cmd_line->HasSwitch(switches::kIgnoreCertificateErrors)) ignore_certificate_errors_ = true; - if (cmd_line->HasSwitch(switches::kContentShellUserDataDir)) { - path_ = cmd_line->GetSwitchValuePath(switches::kContentShellUserDataDir); - if (base::DirectoryExists(path_) || base::CreateDirectory(path_)) { - // BrowserContext needs an absolute path, which we would normally get via - // PathService. In this case, manually ensure the path is absolute. - if (!path_.IsAbsolute()) - path_ = base::MakeAbsoluteFilePath(path_); - if (!path_.empty()) { - FinishInitWhileIOAllowed(); - base::PathService::OverrideAndCreateIfNeeded( - SHELL_DIR_USER_DATA, path_, /*is_absolute=*/true, /*create=*/false); - return; - } - } else { - LOG(WARNING) << "Unable to create data-path directory: " << path_.value(); - } - } - CHECK(base::PathService::Get(SHELL_DIR_USER_DATA, &path_)); FinishInitWhileIOAllowed();
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc index ab42138..a907bcc 100644 --- a/content/shell/browser/shell_content_browser_client.cc +++ b/content/shell/browser/shell_content_browser_client.cc
@@ -74,9 +74,9 @@ #include "content/shell/browser/shell_browser_context.h" #include "content/shell/browser/shell_browser_main_parts.h" #include "content/shell/browser/shell_devtools_manager_delegate.h" -#include "content/shell/browser/shell_paths.h" #include "content/shell/browser/shell_web_contents_view_delegate_creator.h" #include "content/shell/common/shell_controller.test-mojom.h" +#include "content/shell/common/shell_paths.h" #include "content/shell/common/shell_switches.h" #include "media/mojo/buildflags.h" #include "media/mojo/mojom/media_service.mojom.h"
diff --git a/content/shell/browser/shell_paths.cc b/content/shell/common/shell_paths.cc similarity index 71% rename from content/shell/browser/shell_paths.cc rename to content/shell/common/shell_paths.cc index 284b910..4552a44 100644 --- a/content/shell/browser/shell_paths.cc +++ b/content/shell/common/shell_paths.cc
@@ -2,14 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/shell/browser/shell_paths.h" +#include "content/shell/common/shell_paths.h" #include "base/base_paths.h" +#include "base/command_line.h" #include "base/environment.h" #include "base/files/file_util.h" +#include "base/logging.h" #include "base/path_service.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" +#include "content/shell/common/shell_switches.h" #if BUILDFLAG(IS_FUCHSIA) #include "base/fuchsia/file_utils.h" @@ -52,19 +55,36 @@ public: static void CreateDir(const base::FilePath& path) { base::ScopedAllowBlocking allow_io; - if (!base::PathExists(path)) + if (!base::PathExists(path)) { base::CreateDirectory(path); + } } }; bool ShellPathProvider(int key, base::FilePath* result) { - base::FilePath cur; - switch (key) { case SHELL_DIR_USER_DATA: { + base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); + if (cmd_line->HasSwitch(switches::kContentShellUserDataDir)) { + base::FilePath path = + cmd_line->GetSwitchValuePath(switches::kContentShellUserDataDir); + if (base::DirectoryExists(path) || base::CreateDirectory(path)) { + if (!path.IsAbsolute()) { + path = base::MakeAbsoluteFilePath(path); + } + if (!path.empty()) { + *result = path; + return true; + } + } else { + LOG(WARNING) << "Unable to create data-path directory: " + << path.value(); + } + } bool rv = GetDefaultUserDataDirectory(result); - if (rv) + if (rv) { ShellPathProvider::CreateDir(*result); + } return rv; } default:
diff --git a/content/shell/browser/shell_paths.h b/content/shell/common/shell_paths.h similarity index 80% rename from content/shell/browser/shell_paths.h rename to content/shell/common/shell_paths.h index 1c1c269..299c274e 100644 --- a/content/shell/browser/shell_paths.h +++ b/content/shell/common/shell_paths.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_SHELL_BROWSER_SHELL_PATHS_H_ -#define CONTENT_SHELL_BROWSER_SHELL_PATHS_H_ +#ifndef CONTENT_SHELL_COMMON_SHELL_PATHS_H_ +#define CONTENT_SHELL_COMMON_SHELL_PATHS_H_ #include "build/build_config.h" @@ -26,4 +26,4 @@ } // namespace content -#endif // CONTENT_SHELL_BROWSER_SHELL_PATHS_H_ +#endif // CONTENT_SHELL_COMMON_SHELL_PATHS_H_
diff --git a/content/test/stub_render_widget_host_owner_delegate.cc b/content/test/stub_render_widget_host_owner_delegate.cc index 5b760b7..295a1af 100644 --- a/content/test/stub_render_widget_host_owner_delegate.cc +++ b/content/test/stub_render_widget_host_owner_delegate.cc
@@ -21,10 +21,6 @@ return true; } -bool StubRenderWidgetHostOwnerDelegate::IsNeverComposited() { - return false; -} - blink::web_pref::WebPreferences StubRenderWidgetHostOwnerDelegate::GetWebkitPreferencesForWidget() { return {};
diff --git a/content/test/stub_render_widget_host_owner_delegate.h b/content/test/stub_render_widget_host_owner_delegate.h index e696044..ac57d8f 100644 --- a/content/test/stub_render_widget_host_owner_delegate.h +++ b/content/test/stub_render_widget_host_owner_delegate.h
@@ -20,7 +20,6 @@ bool ShouldContributePriorityToProcess() override; void SetBackgroundOpaque(bool opaque) override {} bool IsMainFrameActive() override; - bool IsNeverComposited() override; blink::web_pref::WebPreferences GetWebkitPreferencesForWidget() override; };
diff --git a/docs/android_native_libraries.md b/docs/android_native_libraries.md index 656dba7..13c4db1 100644 --- a/docs/android_native_libraries.md +++ b/docs/android_native_libraries.md
@@ -132,7 +132,7 @@ **How we use them:** * We disable unwind information (search for [`exclude_unwind_tables`](https://cs.chromium.org/search/?q=exclude_unwind_tables+file:%5C.gn&type=cs)). * For all architectures except arm64, we disable frame pointers in order to reduce binary size (search for [`enable_frame_pointers`](https://cs.chromium.org/search/?q=enable_frame_pointers+file:%5C.gn&type=cs)). - * Crashes are unwound offline using `minidump_stackwalk`, which can create a stack trace given a snapshot of stack memory and the unstripped library (see [//docs/testing/using_breakpad_with_content_shell.md](testing/using_breakpad_with_content_shell.md)) + * Crashes are unwound offline using `minidump_stackwalk`, which can create a stack trace given a snapshot of stack memory and the unstripped library (see [//docs/testing/using_crashpad_with_content_shell.md](testing/using_crashpad_with_content_shell.md)) * To facilitate heap profiling, we ship unwind information to arm32 canary & dev channels as a separate file: `assets/unwind_cfi_32` ## JNI Native Methods Resolution
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc index d2806ca..ebf91361 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -1529,6 +1529,9 @@ scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + TRACE_EVENT("extensions", + "WebRequestProxyingURLLoaderFactory::StartProxying"); + auto proxy = std::make_unique<WebRequestProxyingURLLoaderFactory>( browser_context, render_process_id, frame_routing_id, view_routing_id, request_id_generator, std::move(navigation_ui_data),
diff --git a/extensions/browser/extension_host.cc b/extensions/browser/extension_host.cc index 8a7db042..a513075 100644 --- a/extensions/browser/extension_host.cc +++ b/extensions/browser/extension_host.cc
@@ -152,8 +152,11 @@ // associated with the ExtensionHost. CHECK_EQ(browser_context_, site_instance->GetBrowserContext()); } - host_contents_ = WebContents::Create( - WebContents::CreateParams(browser_context_, site_instance)); + WebContents::CreateParams create_params(browser_context_, site_instance); + create_params.is_never_composited = + host_type == mojom::ViewType::kExtensionBackgroundPage || + host_type == mojom::ViewType::kOffscreenDocument; + host_contents_ = WebContents::Create(create_params); host_contents_->SetOwnerLocationForDebug(FROM_HERE); content::WebContentsObserver::Observe(host_contents_.get()); host_contents_->SetDelegate(this); @@ -632,12 +635,6 @@ render_frame_host, security_origin, type, extension()); } -bool ExtensionHost::IsNeverComposited(content::WebContents* web_contents) { - mojom::ViewType view_type = extensions::GetViewType(web_contents); - return view_type == mojom::ViewType::kExtensionBackgroundPage || - view_type == mojom::ViewType::kOffscreenDocument; -} - content::PictureInPictureResult ExtensionHost::EnterPictureInPicture( content::WebContents* web_contents) { return delegate_->EnterPictureInPicture(web_contents);
diff --git a/extensions/browser/extension_host.h b/extensions/browser/extension_host.h index 502ee36..8f4cb2ea 100644 --- a/extensions/browser/extension_host.h +++ b/extensions/browser/extension_host.h
@@ -163,7 +163,6 @@ bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host, const url::Origin& security_origin, blink::mojom::MediaStreamType type) override; - bool IsNeverComposited(content::WebContents* web_contents) override; content::PictureInPictureResult EnterPictureInPicture( content::WebContents* web_contents) override; void ExitPictureInPicture() override;
diff --git a/extensions/shell/app/shell_main_delegate.cc b/extensions/shell/app/shell_main_delegate.cc index e3d0e105..372536b2 100644 --- a/extensions/shell/app/shell_main_delegate.cc +++ b/extensions/shell/app/shell_main_delegate.cc
@@ -14,6 +14,7 @@ #include "components/nacl/common/buildflags.h" #include "content/public/browser/browser_main_runner.h" #include "content/public/common/content_switches.h" +#include "content/shell/common/shell_paths.h" #include "content/shell/common/shell_switches.h" #include "extensions/common/extension_paths.h" #include "extensions/shell/browser/default_shell_browser_main_delegate.h" @@ -140,6 +141,7 @@ nacl::RegisterPathProvider(); #endif extensions::RegisterPathProvider(); + content::RegisterShellPathProvider(); return std::nullopt; }
diff --git a/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.cc b/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.cc index a64ff86..c692efc 100644 --- a/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.cc +++ b/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.cc
@@ -52,10 +52,10 @@ const gfx::Size& size, gfx::BufferFormat format, DestructionCallback callback, - IOSurfaceRef io_surface, + base::apple::ScopedCFTypeRef<IOSurfaceRef> io_surface, uint32_t lock_flags) : GpuMemoryBufferImpl(id, size, format, std::move(callback)), - io_surface_(io_surface), + io_surface_(std::move(io_surface)), lock_flags_(lock_flags) {} GpuMemoryBufferImplIOSurface::~GpuMemoryBufferImplIOSurface() {} @@ -91,7 +91,7 @@ } return base::WrapUnique(new GpuMemoryBufferImplIOSurface( - handle.id, size, format, std::move(callback), io_surface.release(), + handle.id, size, format, std::move(callback), std::move(io_surface), LockFlags(usage))); }
diff --git a/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.h b/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.h index a70a9921..ac635a8e 100644 --- a/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.h +++ b/gpu/ipc/common/gpu_memory_buffer_impl_io_surface.h
@@ -53,12 +53,13 @@ gfx::GpuMemoryBufferHandle CloneHandle() const override; private: - GpuMemoryBufferImplIOSurface(gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - DestructionCallback callback, - IOSurfaceRef io_surface, - uint32_t lock_flags); + GpuMemoryBufferImplIOSurface( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + DestructionCallback callback, + base::apple::ScopedCFTypeRef<IOSurfaceRef> io_surface, + uint32_t lock_flags); base::apple::ScopedCFTypeRef<IOSurfaceRef> io_surface_; uint32_t lock_flags_;
diff --git a/headless/lib/browser/DEPS b/headless/lib/browser/DEPS index 9dbaed3..1375c21 100644 --- a/headless/lib/browser/DEPS +++ b/headless/lib/browser/DEPS
@@ -15,6 +15,7 @@ "+third_party/skia/include", "+third_party/blink/public/mojom/quota", "+third_party/blink/public/mojom/badging", + "+third_party/blink/public/mojom/persistent_renderer_prefs.mojom.h", "+third_party/blink/public/common/bluetooth/web_bluetooth_device_id.h", "+third_party/blink/public/common/client_hints/enabled_client_hints.h", "+third_party/blink/public/common/renderer_preferences/renderer_preferences.h",
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc index bf1cebd..26f73ac1 100644 --- a/headless/lib/browser/headless_content_browser_client.cc +++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -149,6 +149,31 @@ mojo::ReceiverSet<blink::mojom::BadgeService> receivers_; }; +// As with the above stub BadgeService, a stub implementation of a +// PersistentRendererPrefsService is needed since the service is +// implemented in chrome, and thus won't be available here. +class HeadlessContentBrowserClient::StubPersistentRendererPrefsService + : public blink::mojom::PersistentRendererPrefsService { + public: + StubPersistentRendererPrefsService() = default; + StubPersistentRendererPrefsService( + const StubPersistentRendererPrefsService&) = delete; + StubPersistentRendererPrefsService& operator=( + const StubPersistentRendererPrefsService&) = delete; + ~StubPersistentRendererPrefsService() override = default; + + void Bind(mojo::PendingReceiver<blink::mojom::PersistentRendererPrefsService> + receiver) { + receivers_.Add(this, std::move(receiver)); + } + + // blink::mojom::PersistentRendererPrefsService: + void SetViewSourceLineWrapping(bool value) override {} + + private: + mojo::ReceiverSet<blink::mojom::PersistentRendererPrefsService> receivers_; +}; + HeadlessContentBrowserClient::HeadlessContentBrowserClient( HeadlessBrowserImpl* browser) : browser_(browser) {} @@ -179,6 +204,9 @@ mojo::BinderMapWithContext<content::RenderFrameHost*>* map) { map->Add<blink::mojom::BadgeService>(base::BindRepeating( &HeadlessContentBrowserClient::BindBadgeService, base::Unretained(this))); + map->Add<blink::mojom::PersistentRendererPrefsService>(base::BindRepeating( + &HeadlessContentBrowserClient::BindPersistentRendererPrefsService, + base::Unretained(this))); } void HeadlessContentBrowserClient:: @@ -428,6 +456,18 @@ stub_badge_service_->Bind(std::move(receiver)); } +void HeadlessContentBrowserClient::BindPersistentRendererPrefsService( + content::RenderFrameHost* render_frame_host, + mojo::PendingReceiver<blink::mojom::PersistentRendererPrefsService> + receiver) { + if (!stub_persistent_renderer_prefs_service_) { + stub_persistent_renderer_prefs_service_ = + std::make_unique<StubPersistentRendererPrefsService>(); + } + + stub_persistent_renderer_prefs_service_->Bind(std::move(receiver)); +} + bool HeadlessContentBrowserClient::CanAcceptUntrustedExchangesIfNeeded() { // We require --user-data-dir flag too so that no dangerous changes are made // in the user's regular profile.
diff --git a/headless/lib/browser/headless_content_browser_client.h b/headless/lib/browser/headless_content_browser_client.h index 9a23173..4234c12 100644 --- a/headless/lib/browser/headless_content_browser_client.h +++ b/headless/lib/browser/headless_content_browser_client.h
@@ -15,6 +15,7 @@ #include "headless/public/headless_browser.h" #include "services/network/network_service.h" #include "third_party/blink/public/mojom/badging/badging.mojom.h" +#include "third_party/blink/public/mojom/persistent_renderer_prefs.mojom.h" namespace headless { @@ -156,10 +157,17 @@ private: class StubBadgeService; + class StubPersistentRendererPrefsService; + void BindBadgeService( content::RenderFrameHost* render_frame_host, mojo::PendingReceiver<blink::mojom::BadgeService> receiver); + void BindPersistentRendererPrefsService( + content::RenderFrameHost* render_frame_host, + mojo::PendingReceiver<blink::mojom::PersistentRendererPrefsService> + receiver); + void HandleExplicitlyAllowedPorts( ::network::mojom::NetworkService* network_service); void SetEncryptionKey(::network::mojom::NetworkService* network_service); @@ -168,6 +176,9 @@ std::unique_ptr<StubBadgeService> stub_badge_service_; + std::unique_ptr<StubPersistentRendererPrefsService> + stub_persistent_renderer_prefs_service_; + std::unique_ptr<HeadlessBluetoothDelegate> bluetooth_delegate_; };
diff --git a/headless/test/data/protocol/sanity/data-uri-iframe-expected.txt b/headless/test/data/protocol/sanity/data-uri-iframe-expected.txt new file mode 100644 index 0000000..36ad933 --- /dev/null +++ b/headless/test/data/protocol/sanity/data-uri-iframe-expected.txt
@@ -0,0 +1,5 @@ +Tests protocol events for a data-URI iframes +requested url: http://a.com/index.html +Page.frameRequestedNavigation data:text/html,<body></body> +Page.frameStartedNavigating data:text/html,<body></body> +Page.frameNavigated data:text/html,<body></body> \ No newline at end of file
diff --git a/headless/test/data/protocol/sanity/data-uri-iframe.js b/headless/test/data/protocol/sanity/data-uri-iframe.js new file mode 100644 index 0000000..66760e3 --- /dev/null +++ b/headless/test/data/protocol/sanity/data-uri-iframe.js
@@ -0,0 +1,41 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +(async function(testRunner) { + const {session, dp} = await testRunner.startBlank( + 'Tests protocol events for a data-URI iframes'); + + const {sessionId} = + (await testRunner.browserP().Target.attachToBrowserTarget({})).result; + const bp = (new TestRunner.Session(testRunner, sessionId)).protocol; + + const HttpInterceptor = + await testRunner.loadScriptAbsolute('../resources/http-interceptor.js'); + const httpInterceptor = await (new HttpInterceptor(testRunner, bp)).init(); + + httpInterceptor.addResponse('http://a.com/index.html', `<html></html>`); + await session.navigate('http://a.com/index.html'); + + dp.Page.enable(); + function logEvent(e) { + const url = e.params.url || e.params.frame?.url || ""; + testRunner.log(`${e.method} ${url}`); + } + dp.Page.onFrameRequestedNavigation(logEvent); + dp.Page.onFrameStartedNavigating(logEvent); + dp.Page.onFrameDetached(() => { + testRunner.log(`FAIL: ${e.method}`); + }); + dp.Page.onFrameNavigated(logEvent); + + session.evaluate(` + const iframe = document.createElement('iframe'); + iframe.src = 'data:text/html,<body></body>'; + document.body.appendChild(iframe); + `); + + await dp.Page.onceFrameNavigated(); + + testRunner.completeTest(); +})
diff --git a/headless/test/headless_protocol_browsertest.cc b/headless/test/headless_protocol_browsertest.cc index 2b675b67..0683dfa0 100644 --- a/headless/test/headless_protocol_browsertest.cc +++ b/headless/test/headless_protocol_browsertest.cc
@@ -663,6 +663,8 @@ SitePerProcess, "sanity/site-per-process.js") +HEADLESS_PROTOCOL_TEST(DataURIIframe, "sanity/data-uri-iframe.js") + // The test brlow requires beginFrameControl which is currently not supported // on Mac. #if BUILDFLAG(IS_MAC)
diff --git a/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json b/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json index 1d18010..bee8fdf1 100644 --- a/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json +++ b/infra/config/generated/builders/ci/Linux ASan LSan Builder/targets/chromium.memory.json
@@ -1264,7 +1264,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 7 + "shards": 8 }, "test": "sync_integration_tests", "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
diff --git "a/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json" "b/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json" index 1d18010..bee8fdf1 100644 --- "a/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json" +++ "b/infra/config/generated/builders/ci/Linux ASan LSan Tests \0501\051/targets/chromium.memory.json"
@@ -1264,7 +1264,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 7 + "shards": 8 }, "test": "sync_integration_tests", "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
diff --git a/infra/config/generated/builders/ci/Linux Builder/targets/chromium.linux.json b/infra/config/generated/builders/ci/Linux Builder/targets/chromium.linux.json index 3f36661f..6447a56 100644 --- a/infra/config/generated/builders/ci/Linux Builder/targets/chromium.linux.json +++ b/infra/config/generated/builders/ci/Linux Builder/targets/chromium.linux.json
@@ -233,7 +233,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 36 + "shards": 39 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/" @@ -721,7 +721,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 9 + "shards": 10 }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
diff --git a/infra/config/generated/builders/ci/Linux Tests/targets/chromium.linux.json b/infra/config/generated/builders/ci/Linux Tests/targets/chromium.linux.json index 5834b55..6058103 100644 --- a/infra/config/generated/builders/ci/Linux Tests/targets/chromium.linux.json +++ b/infra/config/generated/builders/ci/Linux Tests/targets/chromium.linux.json
@@ -202,7 +202,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 36 + "shards": 39 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/" @@ -690,7 +690,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 9 + "shards": 10 }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
diff --git a/infra/config/generated/builders/ci/android-15-x64-rel/targets/chromium.android.json b/infra/config/generated/builders/ci/android-15-x64-rel/targets/chromium.android.json index 590a9705..2f8beec 100644 --- a/infra/config/generated/builders/ci/android-15-x64-rel/targets/chromium.android.json +++ b/infra/config/generated/builders/ci/android-15-x64-rel/targets/chromium.android.json
@@ -944,7 +944,7 @@ } }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 + "shards": 3 }, "test": "components_browsertests", "test_id_prefix": "ninja://components:components_browsertests/"
diff --git a/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json b/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json index dcba9d6..c297eb0 100644 --- a/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json +++ b/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json
@@ -50,7 +50,7 @@ } }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 75 + "shards": 114 }, "test": "android_browsertests", "test_id_prefix": "ninja://chrome/test:android_browsertests/" @@ -199,7 +199,7 @@ } }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 3 + "shards": 4 }, "test": "unit_tests", "test_id_prefix": "ninja://chrome/test:unit_tests/"
diff --git a/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json b/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json index 067a1be8..836dd9a 100644 --- a/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json +++ b/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json
@@ -45,7 +45,7 @@ } }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 75 + "shards": 114 }, "test": "android_browsertests", "test_id_prefix": "ninja://chrome/test:android_browsertests/" @@ -194,7 +194,7 @@ } }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 3 + "shards": 4 }, "test": "unit_tests", "test_id_prefix": "ninja://chrome/test:unit_tests/"
diff --git a/infra/config/generated/builders/try/android-15-x64-rel/targets/chromium.android.json b/infra/config/generated/builders/try/android-15-x64-rel/targets/chromium.android.json index 590a9705..2f8beec 100644 --- a/infra/config/generated/builders/try/android-15-x64-rel/targets/chromium.android.json +++ b/infra/config/generated/builders/try/android-15-x64-rel/targets/chromium.android.json
@@ -944,7 +944,7 @@ } }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 + "shards": 3 }, "test": "components_browsertests", "test_id_prefix": "ninja://components:components_browsertests/"
diff --git a/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json b/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json index dcba9d6..c297eb0 100644 --- a/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json +++ b/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json
@@ -50,7 +50,7 @@ } }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 75 + "shards": 114 }, "test": "android_browsertests", "test_id_prefix": "ninja://chrome/test:android_browsertests/" @@ -199,7 +199,7 @@ } }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 3 + "shards": 4 }, "test": "unit_tests", "test_id_prefix": "ninja://chrome/test:unit_tests/"
diff --git a/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json b/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json index dcba9d6..c297eb0 100644 --- a/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json +++ b/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json
@@ -50,7 +50,7 @@ } }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 75 + "shards": 114 }, "test": "android_browsertests", "test_id_prefix": "ninja://chrome/test:android_browsertests/" @@ -199,7 +199,7 @@ } }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 3 + "shards": 4 }, "test": "unit_tests", "test_id_prefix": "ninja://chrome/test:unit_tests/"
diff --git a/infra/config/generated/builders/try/android-x64-rel/targets/chromium.android.json b/infra/config/generated/builders/try/android-x64-rel/targets/chromium.android.json index 1670a01..7ae20c9 100644 --- a/infra/config/generated/builders/try/android-x64-rel/targets/chromium.android.json +++ b/infra/config/generated/builders/try/android-x64-rel/targets/chromium.android.json
@@ -1001,7 +1001,7 @@ } }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 + "shards": 3 }, "test": "components_browsertests", "test_id_prefix": "ninja://components:components_browsertests/"
diff --git a/infra/config/generated/builders/try/linux-dcheck-off-rel/targets/chromium.linux.json b/infra/config/generated/builders/try/linux-dcheck-off-rel/targets/chromium.linux.json index 53ae1ec..b913685f 100644 --- a/infra/config/generated/builders/try/linux-dcheck-off-rel/targets/chromium.linux.json +++ b/infra/config/generated/builders/try/linux-dcheck-off-rel/targets/chromium.linux.json
@@ -233,7 +233,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 36 + "shards": 39 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/" @@ -721,7 +721,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 9 + "shards": 10 }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
diff --git a/infra/config/generated/builders/try/linux-full-remote-rel/targets/chromium.linux.json b/infra/config/generated/builders/try/linux-full-remote-rel/targets/chromium.linux.json index 53ae1ec..b913685f 100644 --- a/infra/config/generated/builders/try/linux-full-remote-rel/targets/chromium.linux.json +++ b/infra/config/generated/builders/try/linux-full-remote-rel/targets/chromium.linux.json
@@ -233,7 +233,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 36 + "shards": 39 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/" @@ -721,7 +721,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 9 + "shards": 10 }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
diff --git a/infra/config/generated/builders/try/linux-rel-test-selection/targets/chromium.linux.json b/infra/config/generated/builders/try/linux-rel-test-selection/targets/chromium.linux.json index 53ae1ec..b913685f 100644 --- a/infra/config/generated/builders/try/linux-rel-test-selection/targets/chromium.linux.json +++ b/infra/config/generated/builders/try/linux-rel-test-selection/targets/chromium.linux.json
@@ -233,7 +233,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 36 + "shards": 39 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/" @@ -721,7 +721,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 9 + "shards": 10 }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
diff --git a/infra/config/generated/builders/try/linux-rel/targets/chromium.linux.json b/infra/config/generated/builders/try/linux-rel/targets/chromium.linux.json index 53ae1ec..b913685f 100644 --- a/infra/config/generated/builders/try/linux-rel/targets/chromium.linux.json +++ b/infra/config/generated/builders/try/linux-rel/targets/chromium.linux.json
@@ -233,7 +233,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 36 + "shards": 39 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/" @@ -721,7 +721,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 9 + "shards": 10 }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
diff --git a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json index 1d18010..bee8fdf1 100644 --- a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json +++ b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/targets/chromium.memory.json
@@ -1264,7 +1264,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 7 + "shards": 8 }, "test": "sync_integration_tests", "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
diff --git a/infra/config/generated/builders/try/linux_chromium_compile_rel_ng/targets/chromium.linux.json b/infra/config/generated/builders/try/linux_chromium_compile_rel_ng/targets/chromium.linux.json index 3f36661f..6447a56 100644 --- a/infra/config/generated/builders/try/linux_chromium_compile_rel_ng/targets/chromium.linux.json +++ b/infra/config/generated/builders/try/linux_chromium_compile_rel_ng/targets/chromium.linux.json
@@ -233,7 +233,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 36 + "shards": 39 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/" @@ -721,7 +721,7 @@ "os": "Ubuntu-22.04" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 9 + "shards": 10 }, "test": "interactive_ui_tests", "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
diff --git a/infra/config/targets/autoshard_exceptions.json b/infra/config/targets/autoshard_exceptions.json index 2c8949ef..87d173d 100644 --- a/infra/config/targets/autoshard_exceptions.json +++ b/infra/config/targets/autoshard_exceptions.json
@@ -12,7 +12,7 @@ "try_builder": "android-x64-rel" }, "components_browsertests": { - "shards": 2, + "shards": 3, "try_builder": "android-x64-rel" } }, @@ -42,11 +42,11 @@ "chromium.android.desktop": { "android-desktop-x64-rel-15-tests": { "android_browsertests": { - "shards": 75, + "shards": 114, "try_builder": "android-desktop-x64-rel" }, "unit_tests": { - "shards": 3, + "shards": 4, "try_builder": "android-desktop-x64-rel" } } @@ -128,7 +128,7 @@ "try_builder": "linux-rel" }, "browser_tests": { - "shards": 36, + "shards": 39, "try_builder": "linux-rel" }, "components_unittests": { @@ -140,7 +140,7 @@ "try_builder": "linux-rel" }, "interactive_ui_tests": { - "shards": 9, + "shards": 10, "try_builder": "linux-rel" }, "not_site_per_process_blink_wpt_tests": { @@ -168,7 +168,7 @@ "try_builder": "linux_chromium_asan_rel_ng" }, "sync_integration_tests": { - "shards": 7, + "shards": 8, "try_builder": "linux_chromium_asan_rel_ng" }, "unit_tests": {
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_coordinator.mm b/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_coordinator.mm index 90871b4..b07b3ed 100644 --- a/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_coordinator.mm +++ b/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_coordinator.mm
@@ -84,6 +84,8 @@ accessPoint:accessPoint]; if (self) { CHECK(continuationProvider); + CHECK(viewController, base::NotFatalUntil::M140); + CHECK(browser, base::NotFatalUntil::M140); _continuationProvider = continuationProvider; _signinIntent = signinIntent; _promoAction = promoAction;
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_manager.mm b/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_manager.mm index d590288..0b10a6a 100644 --- a/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_manager.mm +++ b/ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_manager.mm
@@ -74,6 +74,10 @@ (id<SystemIdentityInteractionManager>)identityInteractionManager { self = [super init]; if (self) { + CHECK(baseViewController, base::NotFatalUntil::M140); + CHECK(prefService, base::NotFatalUntil::M140); + CHECK(identityManager, base::NotFatalUntil::M140); + CHECK(identityInteractionManager, base::NotFatalUntil::M140); _baseViewController = baseViewController; _prefService = prefService; _identityManager = identityManager;
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/signin_coordinator.mm b/ios/chrome/browser/authentication/ui_bundled/signin/signin_coordinator.mm index 15257613..1c58906a 100644 --- a/ios/chrome/browser/authentication/ui_bundled/signin/signin_coordinator.mm +++ b/ios/chrome/browser/authentication/ui_bundled/signin/signin_coordinator.mm
@@ -236,6 +236,8 @@ continuationProvider: (const ChangeProfileContinuationProvider&) continuationProvider { + CHECK(viewController, base::NotFatalUntil::M140); + CHECK(browser, base::NotFatalUntil::M140); CHECK(continuationProvider); return [[AddAccountSigninCoordinator alloc] initWithBaseViewController:viewController @@ -261,6 +263,8 @@ (const ChangeProfileContinuationProvider&) continuationProvider { CHECK(continuationProvider); + CHECK(viewController, base::NotFatalUntil::M140); + CHECK(browser, base::NotFatalUntil::M140); return [[AddAccountSigninCoordinator alloc] initWithBaseViewController:viewController browser:browser @@ -285,6 +289,8 @@ (const ChangeProfileContinuationProvider&) continuationProvider { CHECK(continuationProvider); + CHECK(viewController, base::NotFatalUntil::M140); + CHECK(browser, base::NotFatalUntil::M140); return [[AddAccountSigninCoordinator alloc] initWithBaseViewController:viewController browser:browser
diff --git a/ios/chrome/browser/collaboration/model/messaging/infobar/collaboration_group_infobar_delegate.mm b/ios/chrome/browser/collaboration/model/messaging/infobar/collaboration_group_infobar_delegate.mm index d48fc19c..98c7ab5 100644 --- a/ios/chrome/browser/collaboration/model/messaging/infobar/collaboration_group_infobar_delegate.mm +++ b/ios/chrome/browser/collaboration/model/messaging/infobar/collaboration_group_infobar_delegate.mm
@@ -226,14 +226,20 @@ id<ShareKitAvatarPrimitive> CollaborationGroupInfoBarDelegate::GetAvatarPrimitive() { - // Only return an avatar primitive if there is one affected user. - if (instant_message_.attributions.size() != 1 || - !instant_message_.attributions.front().triggering_user.has_value()) { + const auto& attributions = instant_message_.attributions; + if (attributions.size() != 1) { + // No avatar primitive if not exactly one affected user. return nil; } - data_sharing::GroupMember user = - instant_message_.attributions.front().triggering_user.value(); + const auto& attribution = attributions.front(); + const auto& opt_triggering_user = attribution.triggering_user; + if (!opt_triggering_user) { + // No avatar primitive if no triggering user. + return nil; + } + + data_sharing::GroupMember user = opt_triggering_user.value(); ShareKitService* share_kit_service = ShareKitServiceFactory::GetForProfile(profile_);
diff --git a/ios/chrome/browser/settings/model/sync/utils/sync_util.h b/ios/chrome/browser/settings/model/sync/utils/sync_util.h index ab12e1ac..2d0bea0 100644 --- a/ios/chrome/browser/settings/model/sync/utils/sync_util.h +++ b/ios/chrome/browser/settings/model/sync/utils/sync_util.h
@@ -18,6 +18,13 @@ class WebState; } +// Indicates what event triggered displaying the sync error infobar. For now the +// enum itself is not logged and is just used to identify histogram's suffix. +enum class SyncErrorInfoBarTrigger { + kNewTabOpened, + kPasswordFormParsed, +}; + // Gets the top-level description message associated with the sync error state // of `syncService`. Returns nil if there is no sync error. NSString* GetSyncErrorDescriptionForSyncService( @@ -43,7 +50,8 @@ // Returns true if an infobar was brought up. bool DisplaySyncErrors(ProfileIOS* profile, web::WebState* web_state, - id<SyncPresenter> presenter); + id<SyncPresenter> presenter, + SyncErrorInfoBarTrigger trigger); // Logs sync error infobar dismissal metric for a given `error`. void LogSyncErrorInfobarDismissed(
diff --git a/ios/chrome/browser/settings/model/sync/utils/sync_util.mm b/ios/chrome/browser/settings/model/sync/utils/sync_util.mm index 03d30245..f532903 100644 --- a/ios/chrome/browser/settings/model/sync/utils/sync_util.mm +++ b/ios/chrome/browser/settings/model/sync/utils/sync_util.mm
@@ -6,6 +6,7 @@ #import "base/metrics/histogram_functions.h" #import "base/notreached.h" +#import "base/strings/strcat.h" #import "base/strings/utf_string_conversions.h" #import "components/infobars/core/infobar_manager.h" #import "components/signin/public/identity_manager/account_info.h" @@ -29,6 +30,9 @@ namespace { +constexpr char kSyncErrorInfobarDisplayedHistogramName[] = + "Sync.SyncErrorInfobarDisplayed2"; + // Enumerated constants for logging when a sign-in error infobar was shown // to the user. This was added for crbug/265352 to quantify how often this // bug shows up in the wild. The logged histogram count should be interpreted @@ -152,6 +156,17 @@ } } +std::string GetSyncErrorInfobarHistogramSuffix( + SyncErrorInfoBarTrigger trigger) { + switch (trigger) { + case SyncErrorInfoBarTrigger::kNewTabOpened: + return ".NewTab"; + case SyncErrorInfoBarTrigger::kPasswordFormParsed: + return ".PasswordForm"; + } + NOTREACHED(); +} + } // namespace NSString* GetSyncErrorDescriptionForSyncService( @@ -283,7 +298,8 @@ bool DisplaySyncErrors(ProfileIOS* profile, web::WebState* web_state, - id<SyncPresenter> presenter) { + id<SyncPresenter> presenter, + SyncErrorInfoBarTrigger trigger) { // Avoid displaying sync errors on incognito tabs. if (profile->IsOffTheRecord()) { return false; @@ -328,10 +344,13 @@ SyncErrorInfoBarDelegate::Create(infoBarManager, profile, presenter); if (infobar_displayed) { // Logs when an infobar is shown to user. See crbug.com/265352. - base::UmaHistogramEnumeration("Sync.SyncErrorInfobarDisplayed2", + base::UmaHistogramEnumeration(kSyncErrorInfobarDisplayedHistogramName, *infobarSyncError); + base::UmaHistogramEnumeration( + base::StrCat({kSyncErrorInfobarDisplayedHistogramName, + GetSyncErrorInfobarHistogramSuffix(trigger)}), + *infobarSyncError); } - return infobar_displayed; }
diff --git a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm index 7612806..4f9f6c9e 100644 --- a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm +++ b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
@@ -1809,6 +1809,7 @@ << "self.signinCoordinator: " << base::SysNSStringToUTF8([self.signinCoordinator description]); Browser* browser = self.mainInterface.browser; + [self stopSigninCoordinatorAnimated:NO fromExternalTrigger:NO]; self.signinCoordinator = [SigninCoordinator upgradeSigninPromoCoordinatorWithBaseViewController:self.mainInterface .viewController @@ -2167,6 +2168,7 @@ return; } Browser* mainBrowser = self.mainInterface.browser; + [self stopSigninCoordinatorAnimated:NO fromExternalTrigger:NO]; self.signinCoordinator = [SigninCoordinator signinCoordinatorWithCommand:command browser:mainBrowser @@ -2191,6 +2193,8 @@ anchorView:nil accessPoint:accessPoint URL:url]; + + [self stopSigninCoordinatorAnimated:NO fromExternalTrigger:NO]; self.signinCoordinator = accountMenuCoordinator; // TODO(crbug.com/336719423): Record signin metrics based on the // selected action from the account switcher. @@ -2216,6 +2220,7 @@ }; ChangeProfileContinuationProvider provider = base::BindRepeating(&CreateChangeProfileOpensURLContinuation, url); + [self stopSigninCoordinatorAnimated:NO fromExternalTrigger:NO]; self.signinCoordinator = [SigninCoordinator consistencyPromoSigninCoordinatorWithBaseViewController:baseViewController browser:self.mainInterface
diff --git a/ios/chrome/browser/signin/model/fake_system_identity_interaction_manager.mm b/ios/chrome/browser/signin/model/fake_system_identity_interaction_manager.mm index d145d5a..5388fe8 100644 --- a/ios/chrome/browser/signin/model/fake_system_identity_interaction_manager.mm +++ b/ios/chrome/browser/signin/model/fake_system_identity_interaction_manager.mm
@@ -147,7 +147,8 @@ - (void)startAuthActivityWithViewController:(UIViewController*)viewController userEmail:(NSString*)userEmail completion:(SigninCompletionBlock)completion { - DCHECK(completion); + CHECK(completion, base::NotFatalUntil::M140); + CHECK(viewController, base::NotFatalUntil::M140); _lastStartAuthActivityUserEmail = userEmail; if (userEmail.length) { [FakeSystemIdentityInteractionManager
diff --git a/ios/chrome/browser/sync/model/sync_error_browser_agent.mm b/ios/chrome/browser/sync/model/sync_error_browser_agent.mm index 7f8649c..8bdb39f4 100644 --- a/ios/chrome/browser/sync/model/sync_error_browser_agent.mm +++ b/ios/chrome/browser/sync/model/sync_error_browser_agent.mm
@@ -209,7 +209,8 @@ UserActionRequiredToFixPasswordSyncError(profile) && base::FeatureList::IsEnabled( syncer::kSyncTrustedVaultInfobarImprovements)) { - DisplaySyncErrors(profile, active_web_state, sync_presenter_provider_); + DisplaySyncErrors(profile, active_web_state, sync_presenter_provider_, + SyncErrorInfoBarTrigger::kPasswordFormParsed); } } @@ -249,7 +250,8 @@ CreateConfirmInfoBar(std::move(delegate))); return; } - DisplaySyncErrors(profile, web_state, sync_presenter_provider_); + DisplaySyncErrors(profile, web_state, sync_presenter_provider_, + SyncErrorInfoBarTrigger::kNewTabOpened); } void SyncErrorBrowserAgent::AddPasswordFormManagerObserver(
diff --git a/ios/chrome/browser/sync/model/sync_error_browser_agent_unittest.mm b/ios/chrome/browser/sync/model/sync_error_browser_agent_unittest.mm index 20b3309..74fb040 100644 --- a/ios/chrome/browser/sync/model/sync_error_browser_agent_unittest.mm +++ b/ios/chrome/browser/sync/model/sync_error_browser_agent_unittest.mm
@@ -4,6 +4,7 @@ #import "ios/chrome/browser/sync/model/sync_error_browser_agent.h" +#import "base/test/metrics/histogram_tester.h" #import "base/test/scoped_feature_list.h" #import "components/password_manager/core/browser/mock_password_form_cache.h" #import "components/password_manager/core/browser/mock_password_manager.h" @@ -68,6 +69,7 @@ TEST_F(SyncErrorBrowserAgentTest, InfobarDisplayedOnPasswordFormParsedWithPasswordSyncError) { + base::HistogramTester histogram_tester; base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( syncer::kSyncTrustedVaultInfobarImprovements); @@ -84,4 +86,12 @@ SyncErrorBrowserAgent::FromBrowser(browser_.get())) ->OnPasswordFormParsed(/*form_manager=*/nullptr); EXPECT_THAT(infobar_manager->infobars(), SizeIs(1)); + + constexpr int kSyncNeedsPassphraseBucket = 3; + histogram_tester.ExpectUniqueSample("Sync.SyncErrorInfobarDisplayed2", + kSyncNeedsPassphraseBucket, /*count=*/1); + histogram_tester.ExpectUniqueSample( + "Sync.SyncErrorInfobarDisplayed2.PasswordForm", + kSyncNeedsPassphraseBucket, + /*count=*/1); }
diff --git a/ios/third_party/material_components_ios/BUILD.gn b/ios/third_party/material_components_ios/BUILD.gn index 9fa1362..d59f3e8 100644 --- a/ios/third_party/material_components_ios/BUILD.gn +++ b/ios/third_party/material_components_ios/BUILD.gn
@@ -1574,6 +1574,8 @@ ] configs -= [ + # TODO(crbug.com/415770863): Remove `assign_property_warning` once the warning is fixed. + "//build/config/compiler:assign_property_warning", "//build/config/compiler:chromium_code", "//build/config/gcc:symbol_visibility_hidden", ]
diff --git a/ios/web/public/test/fakes/fake_web_state.mm b/ios/web/public/test/fakes/fake_web_state.mm index ab282f01..1c48f35 100644 --- a/ios/web/public/test/fakes/fake_web_state.mm +++ b/ios/web/public/test/fakes/fake_web_state.mm
@@ -56,6 +56,7 @@ for (auto& observer : policy_deciders_) { observer.ResetWebState(); } + ClearAllUserData(); } void FakeWebState::SerializeToProto(proto::WebStateStorage& storage) const {}
diff --git a/media/formats/hls/tag_name.cc b/media/formats/hls/tag_name.cc index 9d2307f..ddea153 100644 --- a/media/formats/hls/tag_name.cc +++ b/media/formats/hls/tag_name.cc
@@ -125,7 +125,7 @@ } std::string_view TagNameToString(TagName name) { - for (auto entry : kTagNames) { + for (const auto& entry : kTagNames) { if (name == entry.second) { return entry.first; }
diff --git a/net/http/http_stream_pool_attempt_manager.cc b/net/http/http_stream_pool_attempt_manager.cc index 4241d96..eea2ca3a 100644 --- a/net/http/http_stream_pool_attempt_manager.cc +++ b/net/http/http_stream_pool_attempt_manager.cc
@@ -240,8 +240,6 @@ job->enable_alternative_services()); dict.Set("quic_version", quic::ParsedQuicVersionToString(job->quic_version())); - dict.Set("create_to_resume_ms", - static_cast<int>(job->CreateToResumeTime().InMilliseconds())); job->net_log().source().AddToEventParameters(dict); return dict; }); @@ -1439,6 +1437,13 @@ CancelQuicAttempt(final_error_to_notify_jobs()); NotifyPreconnectsComplete(final_error_to_notify_jobs()); NotifyJobOfFailure(); + + CHECK(tcp_based_attempts_.empty()); + CHECK(jobs_.empty()); + CHECK(preconnect_jobs_.empty()); + CHECK(!quic_attempt_); + + group_->OnAttemptManagerShuttingDown(this); // `this` may be deleted. } @@ -2079,7 +2084,7 @@ FROM_HERE, std::move(on_complete_callback_for_testing_)); } - group_->OnAttemptManagerComplete(); + group_->OnAttemptManagerComplete(this); // `this` is deleted. }
diff --git a/net/http/http_stream_pool_attempt_manager.h b/net/http/http_stream_pool_attempt_manager.h index 30b19941..3cd2fbb5 100644 --- a/net/http/http_stream_pool_attempt_manager.h +++ b/net/http/http_stream_pool_attempt_manager.h
@@ -189,6 +189,10 @@ return quic_attempt_result_; } + base::WeakPtr<AttemptManager> GetWeakPtrForTesting() { + return weak_ptr_factory_.GetWeakPtr(); + } + void SetIsFailingForTest(bool is_failing) { is_failing_ = is_failing; } QuicAttempt* quic_attempt_for_testing() const { return quic_attempt_.get(); }
diff --git a/net/http/http_stream_pool_attempt_manager_unittest.cc b/net/http/http_stream_pool_attempt_manager_unittest.cc index 4ac4add..1606a03 100644 --- a/net/http/http_stream_pool_attempt_manager_unittest.cc +++ b/net/http/http_stream_pool_attempt_manager_unittest.cc
@@ -4176,37 +4176,42 @@ StreamRequester requester1(stream_key); requester1.RequestStream(pool()); + Group* group = pool().GetGroupForTesting(stream_key); + // This AttemptManager will fail. + base::WeakPtr<AttemptManager> first_attempt_manager = + group->attempt_manager()->GetWeakPtrForTesting(); + requester1.WaitForResult(); EXPECT_THAT(requester1.result(), Optional(IsError(ERR_CONNECTION_RESET))); + EXPECT_TRUE(first_attempt_manager->is_failing()); - // The first request isn't destroyed yet so the failing attempt manager is - // still alive. A request that comes during a failure should be paused. + // The first request isn't destroyed yet so the failing AttemptManager is + // still alive. A request that comes during a failure should use a new + // AttemptManager. StreamRequester requester2(stream_key); HttpStreamRequest* request2 = requester2.RequestStream(pool()); ASSERT_FALSE(requester2.result().has_value()); - EXPECT_EQ(request2->GetLoadState(), LOAD_STATE_IDLE); - EXPECT_EQ(pool().GetGroupForTesting(stream_key)->PausedJobCount(), 1u); + ASSERT_NE(first_attempt_manager.get(), group->attempt_manager()); + ASSERT_EQ(group->attempt_manager()->TcpBasedAttemptCount(), 1u); + EXPECT_EQ(request2->GetLoadState(), LOAD_STATE_CONNECTING); - // Preconnect during the failing mode is paused. + // Preconnect should succeed immediately as the active AttemptManager has + // a TcpBasedAttempt. Preconnector preconnector1(kDestination); - EXPECT_THAT(preconnector1.Preconnect(pool()), IsError(ERR_IO_PENDING)); + EXPECT_THAT(preconnector1.Preconnect(pool()), IsOk()); - // Destroy the failed request. This should destroy the failing attempt manager - // and should create a new one. + // Destroy the failed request. This should destroy the failing attempt + // manager. requester1.ResetRequest(); - WaitForAttemptManagerComplete( - pool().GetGroupForTesting(stream_key)->attempt_manager()); - ASSERT_FALSE( - pool().GetGroupForTesting(stream_key)->attempt_manager()->is_failing()); + WaitForAttemptManagerComplete(first_attempt_manager.get()); + ASSERT_FALSE(first_attempt_manager); - // The paused request should succeed now. + // The second request should succeed. requester2.WaitForResult(); EXPECT_THAT(requester2.result(), Optional(IsOk())); - // Preconnects (one already paused, one scheduled after creating a new attempt - // manager) should also succeed. + // Another reconnect should also succeed. Preconnector preconnector2(kDestination); - EXPECT_THAT(preconnector1.WaitForResult(), IsOk()); EXPECT_THAT(preconnector2.Preconnect(pool()), IsOk()); } @@ -4260,15 +4265,12 @@ } } -TEST_F(HttpStreamPoolAttemptManagerTest, ResumeMultiplePausedJobsAndFailAgain) { - constexpr size_t kNumPausedJobs = 3; - // Delay between requests. Used to ensure that paused jobs are sorted by - // time. - constexpr base::TimeDelta kDelayBetweenRequests = base::Milliseconds(10); +TEST_F(HttpStreamPoolAttemptManagerTest, MultipleJobsFailAgain) { + constexpr size_t kNumJobsAfterFailure = 3; // Add fake DNS resolutions since we will create at least three attempt // managers. +2 is for the first two failed attempts. - for (size_t i = 0; i < kNumPausedJobs + 2; ++i) { + for (size_t i = 0; i < kNumJobsAfterFailure + 2; ++i) { base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = resolver()->AddFakeRequest(); endpoint_request @@ -4291,22 +4293,29 @@ // The first request fails. StreamRequester failing_requester1(stream_key); failing_requester1.RequestStream(pool()); + Group* group = pool().GetGroupForTesting(stream_key); + base::WeakPtr<AttemptManager> first_attempt_manager = + group->attempt_manager()->GetWeakPtrForTesting(); failing_requester1.WaitForResult(); EXPECT_THAT(failing_requester1.result(), Optional(IsError(ERR_CONNECTION_RESET))); + EXPECT_THAT(group->ShuttingDownAttemptManagerCount(), 1u); - // The second request (that also fails) should be paused. + // The second request also fails. StreamRequester failing_requester2(stream_key); failing_requester2.RequestStream(pool()); - ASSERT_FALSE(failing_requester2.result().has_value()); - EXPECT_EQ(pool().GetGroupForTesting(stream_key)->PausedJobCount(), 1u); - FastForwardBy(kDelayBetweenRequests); + base::WeakPtr<AttemptManager> second_attempt_manager = + group->attempt_manager()->GetWeakPtrForTesting(); + EXPECT_NE(first_attempt_manager.get(), second_attempt_manager.get()); + failing_requester2.WaitForResult(); + EXPECT_THAT(failing_requester2.result(), + Optional(IsError(ERR_CONNECTION_RESET))); + EXPECT_THAT(group->ShuttingDownAttemptManagerCount(), 2u); - // Subsequent requests (that also fails) should be paused too. + // Subsequent requests also fails. std::vector<std::unique_ptr<SequencedSocketData>> datas; std::vector<std::unique_ptr<StreamRequester>> requesters; - for (size_t i = 0; i < kNumPausedJobs; ++i) { - FastForwardBy(kDelayBetweenRequests); + for (size_t i = 0; i < kNumJobsAfterFailure; ++i) { auto data = std::make_unique<SequencedSocketData>(); data->set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_RESET)); socket_factory()->AddSocketDataProvider(data.get()); @@ -4318,44 +4327,36 @@ raw_requester->RequestStream(pool()); ASSERT_FALSE(raw_requester->result().has_value()); } - EXPECT_EQ(pool().GetGroupForTesting(stream_key)->PausedJobCount(), - kNumPausedJobs + 1u); - // Destroy the first request. This should resume paused requests. + // Destroy the first request. It should destroy the first AttemptManager. failing_requester1.ResetRequest(); - WaitForAttemptManagerComplete( - pool().GetGroupForTesting(stream_key)->attempt_manager()); - ASSERT_FALSE( - pool().GetGroupForTesting(stream_key)->attempt_manager()->is_failing()); + WaitForAttemptManagerComplete(first_attempt_manager.get()); + ASSERT_FALSE(first_attempt_manager); - // Complete and destroy the second request. The group should enter failing - // mode again. - failing_requester2.WaitForResult(); - EXPECT_THAT(failing_requester2.result(), - Optional(IsError(ERR_CONNECTION_RESET))); - ASSERT_TRUE( - pool().GetGroupForTesting(stream_key)->attempt_manager()->is_failing()); + // Destroy the second request. It should destroy the second AttemptManager. failing_requester2.ResetRequest(); + WaitForAttemptManagerComplete(second_attempt_manager.get()); + ASSERT_FALSE(second_attempt_manager); - // Complete subsequent requests. These requests could be associated with - // either the second failing attempt manager or other attempt managers that - // will also fail, depending on when resume tasks are invoked. We couldn't - // have concrete expectations for these requests because we use many PostTasks - // in attempt manager and group so the task ordering is hard to predict. Also - // we may modify the task ordering in the future for fixing bugs and improving - // task scheduling. Anyway, all attempt managers fail with the same error. - for (size_t i = 0; i < kNumPausedJobs; ++i) { + // Complete subsequent requests. + for (size_t i = 0; i < kNumJobsAfterFailure; ++i) { SCOPED_TRACE(i); requesters[i]->WaitForResult(); EXPECT_THAT(requesters[i]->result(), Optional(IsError(ERR_CONNECTION_RESET))); requesters[i]->ResetRequest(); } + + // Ensure the group is destroyed. + // TODO(crbug.com/416088643): Add test callback to wait for Group's + // completion. + FastForwardUntilNoTasksRemain(); + ASSERT_FALSE(pool().GetGroupForTesting(stream_key)); } -// Regression test for crbug.com/406932139. When a request (job) is resumed, -// it should handle an existing SpdySession if exists. -TEST_F(HttpStreamPoolAttemptManagerTest, ResumePausedJobExistingSpdySession) { +// Test that after a request fails and an SPDY session becomes available later, +// subsequent request/preconnect should succeed with the session. +TEST_F(HttpStreamPoolAttemptManagerTest, SpdySessionAvailableAfterFailure) { resolver() ->AddFakeRequest() ->add_endpoint(ServiceEndpointBuilder().add_v6("2001:db8::1").endpoint()) @@ -4370,90 +4371,50 @@ // The first request fails. StreamRequester failing_requester(stream_key); failing_requester.RequestStream(pool()); + Group* group = pool().GetGroupForTesting(stream_key); + base::WeakPtr<AttemptManager> attempt_manager = + group->attempt_manager()->GetWeakPtrForTesting(); failing_requester.WaitForResult(); EXPECT_THAT(failing_requester.result(), Optional(IsError(ERR_CONNECTION_RESET))); - // These request/preconnect are paused as the previous request failed and - // isn't destroyed yet. + // Simulate creating a SpdySession before another request/preconnect. + CreateFakeSpdySession(stream_key); + + // These request/preconnect use the existing SPDY session without + // AttemptManager. StreamRequester requester(stream_key); requester.RequestStream(pool()); ASSERT_FALSE(requester.result().has_value()); Preconnector preconnector(stream_key); - preconnector.Preconnect(pool()); - ASSERT_FALSE(preconnector.result().has_value()); + // Preconnect succeeds immediately since there is an existing SPDY session. + EXPECT_THAT(preconnector.Preconnect(pool()), IsOk()); + ASSERT_FALSE(group->attempt_manager()); - // Simulate creating a SpdySession before resuming the paused - // request/preconnect. - CreateFakeSpdySession(stream_key); - - // Destroy the first request to resume the paused request/preconnect. + // Destroy the first request. It will destroy the first AttemptManager. failing_requester.ResetRequest(); + WaitForAttemptManagerComplete(attempt_manager.get()); + ASSERT_FALSE(attempt_manager); + // Ensure the second request succeeds. requester.WaitForResult(); EXPECT_THAT(requester.result(), Optional(IsOk())); EXPECT_EQ(requester.negotiated_protocol(), NextProto::kProtoHTTP2); - preconnector.WaitForResult(); - EXPECT_THAT(preconnector.result(), Optional(IsOk())); -} -// Regression test for crbug.com/411879984. Group must outlive a Job when a -// resumed request (job) used an existing SPDY session if exists. -TEST_F(HttpStreamPoolAttemptManagerTest, - ResumePausedJobExistingSpdySessionGroupOutliveJob) { - resolver() - ->AddFakeRequest() - ->add_endpoint(ServiceEndpointBuilder().add_v6("2001:db8::1").endpoint()) - .CompleteStartSynchronously(OK); - - auto failed_data = std::make_unique<SequencedSocketData>(); - failed_data->set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_RESET)); - socket_factory()->AddSocketDataProvider(failed_data.get()); - - HttpStreamKey stream_key = StreamKeyBuilder(kDefaultDestination).Build(); - - // The first request fails. - StreamRequester failing_requester(stream_key); - failing_requester.RequestStream(pool()); - failing_requester.WaitForResult(); - EXPECT_THAT(failing_requester.result(), - Optional(IsError(ERR_CONNECTION_RESET))); - - // This second request is paused as the previous request failed and isn't - // destroyed yet. - StreamRequester requester(stream_key); - requester.RequestStream(pool()); - ASSERT_FALSE(requester.result().has_value()); - - // Simulate creating a SPDY session before resuming the paused request. - CreateFakeSpdySession(stream_key); - - // Destroy the first request to resume the second request. - failing_requester.ResetRequest(); - - // The second request should complete with the existing SPDY session. - requester.WaitForResult(); - EXPECT_THAT(requester.result(), Optional(IsOk())); - EXPECT_EQ(requester.negotiated_protocol(), NextProto::kProtoHTTP2); - // The Group should not create an AttemptManager since the second request used - // the existing SPDY session. - ASSERT_FALSE(pool().GetGroupForTesting(stream_key)->attempt_manager()); - - // Close the SPDY session so that the Group can complete. The Group should not - // be destroyed yet since the second request isn't destroyed yet. + // Close the SPDY session so that the Group can complete. The Group should be + // destroyed immediately because the second request completed without + // AttemptManager so the Group can immediately complete. http_network_session()->CloseAllConnections(ERR_ABORTED, "For testing"); FastForwardUntilNoTasksRemain(); - ASSERT_TRUE(pool().GetGroupForTesting(stream_key)); - - // Destroy the second request. The Group should complete immediately. - requester.ResetRequest(); ASSERT_FALSE(pool().GetGroupForTesting(stream_key)); } -// When a request (job) is resumed, it should handle an existing QUIC session if -// exists. This test uses an HTTP/3 Origin frame to make a session usable for +// This test uses an HTTP/3 Origin frame to make a session usable for // the destination. -TEST_F(HttpStreamPoolAttemptManagerTest, ResumePausedJobExistingQuicSession) { +// TODO(crbug.com/416364483): Fix this test. We need to support out-of-band +// QUIC session arrival to fix this test. +TEST_F(HttpStreamPoolAttemptManagerTest, + DISABLED_QuicSessionAvailableAfterFailure) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(net::features::kAsyncQuicSession); @@ -4471,18 +4432,24 @@ // The first request fails. StreamRequester failing_requester(stream_key); failing_requester.RequestStream(pool()); + Group* group = pool().GetGroupForTesting(stream_key); + base::WeakPtr<AttemptManager> attempt_manager = + group->attempt_manager()->GetWeakPtrForTesting(); failing_requester.WaitForResult(); EXPECT_THAT(failing_requester.result(), Optional(IsError(ERR_CONNECTION_RESET))); - // These request/preconnect are paused as the previous request failed and - // isn't destroyed yet. + // These request/preconnect uses a new AttemptManager as the previous + // AttemptManager is failing. + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester(stream_key); requester.RequestStream(pool()); ASSERT_FALSE(requester.result().has_value()); Preconnector preconnector(stream_key); preconnector.Preconnect(pool()); ASSERT_FALSE(preconnector.result().has_value()); + ASSERT_NE(attempt_manager.get(), group->attempt_manager()); // Simulate creating a QUIC session that can be used for kDefaultDestination // before resuming the paused request/preconnect. The QUIC session is created @@ -4522,9 +4489,11 @@ alt_session->OnOriginFrame(origin_frame); } // End of creating an existing QUIC session. - // Destroy the first request to resume the paused request/preconnect. + // Destroy the first request. failing_requester.ResetRequest(); + // TODO(crbug.com/416364483): Currently the following WaitForResult()s time + // out. Support out-of-band QUIC session arrival. requester.WaitForResult(); EXPECT_THAT(requester.result(), Optional(IsOk())); EXPECT_EQ(requester.negotiated_protocol(), NextProto::kProtoQUIC); @@ -4554,7 +4523,13 @@ // Create an active HttpStream. StreamRequester requester1; + const HttpStreamKey stream_key = requester1.GetStreamKey(); requester1.set_destination(kDestination).RequestStream(pool()); + base::WeakPtr<AttemptManager> attempt_manager = + pool() + .GetGroupForTesting(stream_key) + ->attempt_manager() + ->GetWeakPtrForTesting(); requester1.WaitForResult(); EXPECT_THAT(requester1.result(), Optional(IsOk())); @@ -4578,11 +4553,9 @@ stream1.reset(); // Reset the requests. The manager should complete. - HttpStreamKey stream_key = requester1.GetStreamKey(); requester1.ResetRequest(); requester2.ResetRequest(); - WaitForAttemptManagerComplete( - pool().GetGroupForTesting(stream_key)->attempt_manager()); + WaitForAttemptManagerComplete(attempt_manager.get()); ASSERT_FALSE(pool().GetOrCreateGroupForTesting(stream_key).attempt_manager()); } @@ -4630,23 +4603,17 @@ StreamRequester requester_a; requester_a.set_destination(kDestinationA).RequestStream(pool()); - RunUntilIdle(); + requester_a.WaitForResult(); EXPECT_THAT(requester_a.result(), Optional(IsError(ERR_CONNECTION_RESET))); StreamRequester requester_b; requester_b.set_destination(kDestinationB).RequestStream(pool()); - RunUntilIdle(); + requester_b.WaitForResult(); EXPECT_THAT(requester_b.result(), Optional(IsOk())); - // Release the connection for B. It triggers processing pending requests in - // group/attempt manager for A. The group/attempt manager for A is still alive - // because we don't release `requester_a` yet. The group/attempt manager - // should not be treated as stalled because these are failing. + // Release the connection for B to try to process pending requests, but there + // are no pending requests so it should do nothing. requester_b.ReleaseStream().reset(); - EXPECT_FALSE(pool() - .GetOrCreateGroupForTesting(requester_a.GetStreamKey()) - .attempt_manager() - ->IsStalledByPoolLimit()); } // Tests that when an AttemptManager has a SPDY session, it's not treated as @@ -4904,6 +4871,10 @@ requester.set_destination(kDefaultDestination) .set_quic_version(quic_version()) .RequestStream(pool()); + Group* group = pool().GetGroupForTesting(requester.GetStreamKey()); + // This AttemptManager will fail later. + base::WeakPtr<AttemptManager> attempt_manager = + group->attempt_manager()->GetWeakPtrForTesting(); ASSERT_FALSE(requester.result().has_value()); // Simulate a network change event to fail the AttemptManager. The @@ -4914,19 +4885,13 @@ requester.WaitForResult(); EXPECT_THAT(requester.result(), Optional(IsError(ERR_NETWORK_CHANGED))); - ASSERT_TRUE(pool() - .GetGroupForTesting(requester.GetStreamKey()) - ->attempt_manager() - ->is_failing()); - ASSERT_FALSE(pool() - .GetGroupForTesting(requester.GetStreamKey()) - ->attempt_manager() - ->GetQuicAttemptResultForTesting()); + ASSERT_FALSE(group->attempt_manager()); + ASSERT_EQ(group->ShuttingDownAttemptManagerCount(), 1u); // Ensure that the attempt manager completes after the request is destroyed. requester.ResetRequest(); - WaitForAttemptManagerComplete( - pool().GetGroupForTesting(requester.GetStreamKey())->attempt_manager()); + ASSERT_TRUE(attempt_manager); + WaitForAttemptManagerComplete(attempt_manager.get()); } // Tests that QUIC is not attempted when marked broken. @@ -5030,6 +4995,9 @@ requester.set_destination(kDefaultDestination) .set_quic_version(quic_version()) .RequestStream(pool()); + Group* group = pool().GetGroupForTesting(requester.GetStreamKey()); + base::WeakPtr<AttemptManager> attempt_manager = + group->attempt_manager()->GetWeakPtrForTesting(); ASSERT_FALSE(requester.result().has_value()); tls_completer.Complete(ERR_SOCKET_NOT_CONNECTED); @@ -5039,10 +5007,7 @@ quic_completer.Complete(ERR_CONNECTION_REFUSED); requester.WaitForResult(); - EXPECT_THAT(pool() - .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .attempt_manager() - ->GetQuicAttemptResultForTesting(), + EXPECT_THAT(attempt_manager->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_CONNECTION_REFUSED))); EXPECT_THAT(requester.result(), Optional(IsError(ERR_CONNECTION_REFUSED))); @@ -6639,7 +6604,7 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, FlushWithErrorPendingJobs) { - constexpr size_t kNumPausedJobs = 3; + constexpr size_t kNumRequestsAfterFailure = 3; const HttpStreamKey stream_key = StreamKeyBuilder().Build(); // (Preparation) The first request fails. The group enters the failing mode. @@ -6653,30 +6618,38 @@ StreamRequester failing_requester(stream_key); failing_requester.RequestStream(pool()); + Group* group = pool().GetGroupForTesting(stream_key); + base::WeakPtr<AttemptManager> attempt_manager1 = + group->attempt_manager()->GetWeakPtrForTesting(); failing_requester.WaitForResult(); EXPECT_THAT(failing_requester.result(), Optional(IsError(ERR_CONNECTION_REFUSED))); - EXPECT_TRUE( - pool().GetGroupForTesting(stream_key)->attempt_manager()->is_failing()); + EXPECT_FALSE(group->attempt_manager()); + EXPECT_TRUE(attempt_manager1->is_failing()); - // Subsequent requests (jobs) are paused until the first request is destroyed. + // Subsequent requests (jobs) uses a new AttemptManager. Thsese requests are + // blocked by DNS resolution. + resolver()->AddFakeRequest(); std::vector<std::unique_ptr<StreamRequester>> requesters; - for (size_t i = 0; i < kNumPausedJobs; ++i) { + for (size_t i = 0; i < kNumRequestsAfterFailure; ++i) { auto requester = std::make_unique<StreamRequester>(stream_key); StreamRequester* raw_requester = requester.get(); requesters.emplace_back(std::move(requester)); raw_requester->RequestStream(pool()); ASSERT_FALSE(raw_requester->result().has_value()); } - EXPECT_EQ(pool().GetGroupForTesting(stream_key)->PausedJobCount(), - kNumPausedJobs); + base::WeakPtr<AttemptManager> attempt_manager2 = + group->attempt_manager()->GetWeakPtrForTesting(); + EXPECT_NE(attempt_manager1.get(), attempt_manager2.get()); + // Abort requests. The second AttemptManager also fails. pool().FlushWithError(ERR_ABORTED, StreamSocketCloseReason::kUnspecified, "for testing"); for (auto& requester : requesters) { requester->WaitForResult(); EXPECT_THAT(requester->result(), Optional(IsError(ERR_ABORTED))); } + EXPECT_TRUE(attempt_manager2->is_failing()); // Destroy the first request. This should result in attempting to delete the // group. The group should be still alive since we don't destroy all requests @@ -6688,8 +6661,12 @@ for (auto& requester : requesters) { requester->ResetRequest(); } - WaitForAttemptManagerComplete( - pool().GetGroupForTesting(stream_key)->attempt_manager()); + + // Ensure the group is destroyed. Waiting for completion of one failing + // AttemptManager is sufficient to destroy the group. + WaitForAttemptManagerComplete(attempt_manager1.get()); + ASSERT_FALSE(attempt_manager1.get()); + ASSERT_FALSE(attempt_manager2.get()); EXPECT_FALSE(pool().GetGroupForTesting(stream_key)); EXPECT_EQ(pool().TotalActiveStreamCount(), 0u); } @@ -7328,6 +7305,11 @@ .RequestStream(pool()); ASSERT_FALSE(requester.result().has_value()); + Group* group = pool().GetGroupForTesting(requester.GetStreamKey()); + // This AttemptManager will fail. + base::WeakPtr<AttemptManager> first_attempt_manager = + group->attempt_manager()->GetWeakPtrForTesting(); + NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); FastForwardUntilNoTasksRemain(); @@ -7335,13 +7317,16 @@ requester.WaitForResult(); EXPECT_THAT(requester.result(), Optional(IsError(ERR_NETWORK_CHANGED))); - AttemptManager* manager = - pool() - .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .attempt_manager(); - EXPECT_THAT(manager->TcpBasedAttemptCount(), 0u); - EXPECT_THAT(manager->GetQuicAttemptResultForTesting(), + // The group should not have active AttemptManager. + EXPECT_FALSE(group->attempt_manager()); + EXPECT_THAT(first_attempt_manager->TcpBasedAttemptCount(), 0u); + EXPECT_THAT(first_attempt_manager->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_NETWORK_CHANGED))); + + // Ensure that the group is destroyed after the request is destroyed. + requester.ResetRequest(); + WaitForAttemptManagerComplete(first_attempt_manager.get()); + ASSERT_FALSE(pool().GetGroupForTesting(requester.GetStreamKey())); } // Regression test for crbug.com/384965448 @@ -7373,6 +7358,11 @@ requester.set_destination(kDefaultDestination) .set_quic_version(quic_version()) .RequestStream(pool()); + base::WeakPtr<AttemptManager> attempt_manager = + pool() + .GetGroupForTesting(requester.GetStreamKey()) + ->attempt_manager() + ->GetWeakPtrForTesting(); ASSERT_FALSE(requester.result().has_value()); // Notifies partial endpoint results. Triggers QuicAttempt to start. @@ -7385,12 +7375,8 @@ requester.WaitForResult(); EXPECT_THAT(requester.result(), Optional(IsError(ERR_NAME_NOT_RESOLVED))); - AttemptManager* manager = - pool() - .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .attempt_manager(); - EXPECT_THAT(manager->TcpBasedAttemptCount(), 0u); - EXPECT_THAT(manager->GetQuicAttemptResultForTesting(), + EXPECT_THAT(attempt_manager->TcpBasedAttemptCount(), 0u); + EXPECT_THAT(attempt_manager->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_NAME_NOT_RESOLVED))); } @@ -7423,18 +7409,19 @@ requester.set_destination(kDefaultDestination) .set_quic_version(quic_version()) .RequestStream(pool()); + base::WeakPtr<AttemptManager> attempt_manager = + pool() + .GetOrCreateGroupForTesting(requester.GetStreamKey()) + .attempt_manager() + ->GetWeakPtrForTesting(); ASSERT_FALSE(requester.result().has_value()); requester.WaitForResult(); EXPECT_THAT(requester.result(), Optional(IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED))); quic_completer.Complete(OK); - AttemptManager* manager = - pool() - .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .attempt_manager(); - EXPECT_THAT(manager->TcpBasedAttemptCount(), 0u); - EXPECT_THAT(manager->GetQuicAttemptResultForTesting(), + EXPECT_THAT(attempt_manager->TcpBasedAttemptCount(), 0u); + EXPECT_THAT(attempt_manager->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED))); } @@ -7463,17 +7450,18 @@ requester.set_destination(kDefaultDestination) .set_quic_version(quic_version()) .RequestStream(pool()); + base::WeakPtr<AttemptManager> attempt_manager = + pool() + .GetGroupForTesting(requester.GetStreamKey()) + ->attempt_manager() + ->GetWeakPtrForTesting(); ASSERT_FALSE(requester.result().has_value()); requester.WaitForResult(); EXPECT_THAT(requester.result(), Optional(IsError(ERR_CERT_DATE_INVALID))); quic_completer.Complete(OK); - AttemptManager* manager = - pool() - .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .attempt_manager(); - EXPECT_THAT(manager->TcpBasedAttemptCount(), 0u); - EXPECT_THAT(manager->GetQuicAttemptResultForTesting(), + EXPECT_THAT(attempt_manager->TcpBasedAttemptCount(), 0u); + EXPECT_THAT(attempt_manager->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_CERT_DATE_INVALID))); }
diff --git a/net/http/http_stream_pool_group.cc b/net/http/http_stream_pool_group.cc index 7161ac7..1824506 100644 --- a/net/http/http_stream_pool_group.cc +++ b/net/http/http_stream_pool_group.cc
@@ -75,14 +75,6 @@ HttpStreamPool::Group::IdleStreamSocket::~IdleStreamSocket() = default; -bool HttpStreamPool::Group::PausedJobComparator::operator()(Job* a, - Job* b) const { - if (a->create_time() == b->create_time()) { - return a < b; - } - return a->create_time() < b->create_time(); -} - HttpStreamPool::Group::Group( HttpStreamPool* pool, HttpStreamKey stream_key, @@ -123,23 +115,7 @@ request_net_log); } -bool HttpStreamPool::Group::CanStartJob(Job* job) { - if (IsFailing()) { - auto [_, inserted] = paused_jobs_.emplace(job); - CHECK(inserted); - // `job` will be resumed once the current AttemptManager completes with a - // new AttemptManager. - return false; - } - - EnsureAttemptManager(); - return true; -} - void HttpStreamPool::Group::OnJobComplete(Job* job) { - paused_jobs_.erase(job); - resumed_jobs_.erase(job); - if (attempt_manager_) { attempt_manager_->OnJobComplete(job); // `this` may be deleted. @@ -334,35 +310,38 @@ } void HttpStreamPool::Group::CancelJobs(int error) { - if (!paused_jobs_.empty()) { - CancelPausedJob(error); - } if (attempt_manager_) { attempt_manager_->CancelJobs(error); } } -void HttpStreamPool::Group::EnsureAttemptManager() { - if (attempt_manager_) { - return; +HttpStreamPool::AttemptManager* HttpStreamPool::Group::EnsureAttemptManager() { + if (!attempt_manager_) { + attempt_manager_ = std::make_unique<AttemptManager>( + this, http_network_session()->net_log()); } - attempt_manager_ = - std::make_unique<AttemptManager>(this, http_network_session()->net_log()); + return attempt_manager_.get(); } -void HttpStreamPool::Group::OnAttemptManagerComplete() { - CHECK(attempt_manager_); +void HttpStreamPool::Group::OnAttemptManagerShuttingDown( + AttemptManager* attempt_manager) { + CHECK_EQ(attempt_manager_.get(), attempt_manager); + shutting_down_attempt_managers_.emplace(std::move(attempt_manager_)); + CHECK(!attempt_manager_.get()); +} - const bool should_resume_paused_job = - attempt_manager_->is_failing() && !paused_jobs_.empty(); - - attempt_manager_.reset(); - - if (should_resume_paused_job) { - ResumePausedJob(); +void HttpStreamPool::Group::OnAttemptManagerComplete( + AttemptManager* attempt_manager) { + auto it = shutting_down_attempt_managers_.find(attempt_manager); + if (it != shutting_down_attempt_managers_.end()) { + CHECK_NE(attempt_manager_.get(), attempt_manager); + shutting_down_attempt_managers_.erase(it); } else { - MaybeComplete(); + CHECK_EQ(attempt_manager_.get(), attempt_manager); + attempt_manager_.reset(); } + + MaybeComplete(); } base::Value::Dict HttpStreamPool::Group::GetInfoAsValue() const { @@ -371,25 +350,11 @@ dict.Set("idle_socket_count", static_cast<int>(IdleStreamSocketCount())); dict.Set("handed_out_socket_count", static_cast<int>(HandedOutStreamSocketCount())); - dict.Set("paused_job_count", static_cast<int>(PausedJobCount())); - dict.Set("resumed_job_count", static_cast<int>(resumed_jobs_.size())); dict.Set("attempt_manager_alive", !!attempt_manager_); if (attempt_manager_) { dict.Set("attempt_state", attempt_manager_->GetInfoAsValue()); } - if (!paused_jobs_.empty()) { - base::Value::List paused_jobs; - for (const auto job : paused_jobs_) { - base::Value::Dict job_dict; - job_dict.Set( - "create_to_resume_ms", - static_cast<int>(job->CreateToResumeTime().InMilliseconds())); - paused_jobs.Append(std::move(job_dict)); - } - dict.Set("paused_jobs", std::move(paused_jobs)); - } - return dict; } @@ -404,54 +369,6 @@ return attempt_manager_ && attempt_manager_->is_failing(); } -void HttpStreamPool::Group::ResumePausedJob() { - // The current AttemptManager could be failing again while resuming jobs. - if (IsFailing()) { - return; - } - - raw_ptr<Job> job = ExtractOnePausedJob(); - if (!job) { - return; - } - - // Using PostTask() to resume the remaining paused jobs to avoid reentrancy. - base::SequencedTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, - base::BindOnce(&Group::ResumePausedJob, weak_ptr_factory_.GetWeakPtr())); - - job->Resume(); -} - -void HttpStreamPool::Group::CancelPausedJob(int error) { - Job* job = ExtractOnePausedJob(); - if (!job) { - // Try to complete asynchronously because this method can be called in the - // middle of CancelJobs() and `this` must be alive until CancelJobs() - // completes. - MaybeCompleteLater(); - return; - } - - base::SequencedTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, base::BindOnce(&Group::CancelPausedJob, - weak_ptr_factory_.GetWeakPtr(), error)); - - job->OnStreamFailed(error, NetErrorDetails(), ResolveErrorInfo()); -} - -HttpStreamPool::Job* HttpStreamPool::Group::ExtractOnePausedJob() { - if (paused_jobs_.empty()) { - return nullptr; - } - - raw_ptr<Job> job = - std::move(paused_jobs_.extract(paused_jobs_.begin())).value(); - Job* job_raw_ptr = job.get(); - resumed_jobs_.emplace(std::move(job)); - return job_raw_ptr; -} - void HttpStreamPool::Group::CleanupIdleStreamSockets( CleanupMode mode, std::string_view net_log_close_reason_utf8) { @@ -479,8 +396,8 @@ } bool HttpStreamPool::Group::CanComplete() const { - return ActiveStreamSocketCount() == 0 && paused_jobs_.empty() && - resumed_jobs_.empty() && !attempt_manager_; + return ActiveStreamSocketCount() == 0 && !attempt_manager_ && + shutting_down_attempt_managers_.empty(); } void HttpStreamPool::Group::MaybeComplete() {
diff --git a/net/http/http_stream_pool_group.h b/net/http/http_stream_pool_group.h index 6339a188..07015af 100644 --- a/net/http/http_stream_pool_group.h +++ b/net/http/http_stream_pool_group.h
@@ -39,11 +39,10 @@ // creates an HttpStreamPool::AttemptManager and starts connection attempts for // streams. // -// Keeps incoming jobs (called paused jobs) when the current AttemptManager is -// "failing", i.e., AttemptManager is notifying the failure to associated jobs -// and waiting for completions of these jobs. Once the failing AttemptManager -// completes, this starts a new AttemptManager and pass paused jobs to the new -// AttemptManager. +// When an active AttemptManager starts shutting down (e.g. the AttemptManager +// fails), creates a new AttemptManager for subsequent stream requests (Jobs). +// AttemptManagers need to outlive all associated Jobs. Keeps shutting down +// AttemptManager(s) until these are ready to destroy. // // Owned by an HttpStreamPool, keyed by HttpStreamKey. Destroyed when all // streams associated with this group are completed. @@ -82,8 +81,13 @@ return pool_->http_network_session(); } + // TODO(crbug.com/416088643): Rename to `active_attempt_manager()`. AttemptManager* attempt_manager() const { return attempt_manager_.get(); } + size_t ShuttingDownAttemptManagerCount() const { + return shutting_down_attempt_managers_.size(); + } + const NetLogWithSource& net_log() { return net_log_; } bool force_quic() const { return force_quic_; } @@ -97,9 +101,6 @@ NextProto expected_protocol, const NetLogWithSource& request_net_log); - // Called by `job` to see whether `job` can start. - bool CanStartJob(Job* job); - // Called when `job` is going to be destroyed. void OnJobComplete(Job* job); @@ -154,9 +155,6 @@ // True when the number of active streams reached the group limit. bool ReachedMaxStreamLimit() const; - // Returns the number of paused jobs. See the comment of `paused_jobs_`. - size_t PausedJobCount() const { return paused_jobs_.size(); } - // Returns the highest pending request priority if the group is stalled due to // the per-pool limit, not the per-group limit. std::optional<RequestPriority> GetPriorityIfStalledByPoolLimit() const; @@ -178,10 +176,13 @@ void CancelJobs(int error); // Create an AttemptManager if needed. - void EnsureAttemptManager(); + AttemptManager* EnsureAttemptManager(); - // Called when the attempt manager has completed. - void OnAttemptManagerComplete(); + // Called when the active AttemptManager is shutting down. + void OnAttemptManagerShuttingDown(AttemptManager* attempt_manager); + + // Called when an AttemptManager has completed. + void OnAttemptManagerComplete(AttemptManager* attempt_manager); // Retrieves information on the current state of the group as a base::Value. base::Value::Dict GetInfoAsValue() const; @@ -215,28 +216,11 @@ kForce, }; - // Compares jobs based on their creation time. Used for `paused_jobs_`. - struct PausedJobComparator { - bool operator()(Job* a, Job* b) const; - }; - - using PausedJobSet = std::set<raw_ptr<Job>, PausedJobComparator>; - static base::expected<void, std::string_view> IsIdleStreamSocketUsable( const IdleStreamSocket& idle); bool IsFailing() const; - // Resumes a paused job. Schedules another task if more paused jobs exist. - void ResumePausedJob(); - - // Cancels a paused job. Schedules another task if more paused jobs exist. - void CancelPausedJob(int error); - - // Extracts a paused job from `paused_jobs_`. The ownership of the raw_ptr of - // the job is moved to `notified_paused_jobs_`. - HttpStreamPool::Job* ExtractOnePausedJob(); - void CleanupIdleStreamSockets(CleanupMode mode, std::string_view net_log_close_reason_utf8); @@ -258,16 +242,9 @@ std::unique_ptr<AttemptManager> attempt_manager_; - // Keeps jobs that are created while the current AttemptManager is failing. - // Once the AttemptManager completes notifying the failure to its jobs, we - // create a new AttemptManager and pass these jobs to the new AttemptManager. - // We call these jobs "paused". Note that there are another type of jobs that - // are called "pending". Pending jobs are associated with an AttemptManager - // but haven't attempted connections yet. - PausedJobSet paused_jobs_; - // Keeps jobs that are previously paused and already resumed. We need to keep - // them to avoid dangling pointers. - PausedJobSet resumed_jobs_; + // Keeps AttemptManagers that are shutting down. + std::set<std::unique_ptr<AttemptManager>, base::UniquePtrComparator> + shutting_down_attempt_managers_; base::WeakPtrFactory<Group> weak_ptr_factory_{this}; };
diff --git a/net/http/http_stream_pool_group_unittest.cc b/net/http/http_stream_pool_group_unittest.cc index ea4a2fe..3e0d380 100644 --- a/net/http/http_stream_pool_group_unittest.cc +++ b/net/http/http_stream_pool_group_unittest.cc
@@ -488,34 +488,4 @@ /*enable_alternative_services=*/true)); } -TEST_F(HttpStreamPoolGroupTest, ComparePausedJobSet) { - Group& group = GetOrCreateTestGroup(); - group.EnsureAttemptManager(); - group.attempt_manager_->SetIsFailingForTest(true); - - std::unique_ptr<TestJobDelegate> delegate1 = - std::make_unique<TestJobDelegate>(group.stream_key()); - delegate1->CreateAndStartJob(pool()); - - FastForwardBy(base::Milliseconds(10)); - - // Create two jobs at the same time. - std::unique_ptr<TestJobDelegate> delegate2 = - std::make_unique<TestJobDelegate>(group.stream_key()); - delegate2->CreateAndStartJob(pool()); - - std::unique_ptr<TestJobDelegate> delegate3 = - std::make_unique<TestJobDelegate>(group.stream_key()); - delegate3->CreateAndStartJob(pool()); - - ASSERT_EQ(group.PausedJobCount(), 3u); - - // Ensure that the group is deleted after all delegates are destroyed. - delegate1.reset(); - delegate2.reset(); - delegate3.reset(); - WaitForAttemptManagerComplete(GetTestGroup()->attempt_manager()); - ASSERT_FALSE(GetTestGroup()); -} - } // namespace net
diff --git a/net/http/http_stream_pool_job.cc b/net/http/http_stream_pool_job.cc index 1c8dc7c..4f3dadb 100644 --- a/net/http/http_stream_pool_job.cc +++ b/net/http/http_stream_pool_job.cc
@@ -85,10 +85,10 @@ const NetLogWithSource& request_net_log, size_t num_streams) : delegate_(delegate), - group_(group), - quic_version_(CalculateQuicVersion(quic_version, group_)), + attempt_manager_(group->EnsureAttemptManager()), + quic_version_(CalculateQuicVersion(quic_version, group)), allowed_alpns_( - CalculateAllowedAlpns(delegate_, group_, expected_protocol)), + CalculateAllowedAlpns(delegate_, group, expected_protocol)), request_net_log_(request_net_log), job_net_log_( NetLogWithSource::Make(request_net_log.net_log(), @@ -99,7 +99,7 @@ expected_protocol != NextProto::kProtoHTTP11); job_net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_POOL_JOB_ALIVE, [&] { base::Value::Dict dict; - dict.Set("stream_key", group_->stream_key().ToValue()); + dict.Set("stream_key", group->stream_key().ToValue()); dict.Set("quic_version", quic::ParsedQuicVersionToString(quic_version)); base::Value::List allowed_alpn_list; for (const auto alpn : allowed_alpns_) { @@ -116,7 +116,7 @@ } HttpStreamPool::Job::~Job() { - CHECK(group_); + CHECK(attempt_manager_); // Record histograms only when `this` has a result. If `this` doesn't have a // result that means JobController destroyed `this` since another job @@ -124,23 +124,15 @@ if (result_.has_value()) { constexpr std::string_view kCompleteTimeHistogramName = "Net.HttpStreamPool.JobCompleteTime2."; - constexpr std::string_view kResumeTimeHistogramName = - "Net.HttpStreamPool.JobCreateToResumeTime2."; - base::TimeDelta complete_time = base::TimeTicks::Now() - create_time_; - base::TimeDelta resume_time = CreateToResumeTime(); if (*result_ == OK) { const std::string_view protocol = NegotiatedProtocolToHistogramSuffix( negotiated_protocol_.value_or(NextProto::kProtoUnknown)); base::UmaHistogramTimes( base::StrCat({kCompleteTimeHistogramName, protocol}), complete_time); - base::UmaHistogramTimes( - base::StrCat({kResumeTimeHistogramName, protocol}), resume_time); } else { base::UmaHistogramTimes( base::StrCat({kCompleteTimeHistogramName, "Failure"}), complete_time); - base::UmaHistogramTimes( - base::StrCat({kResumeTimeHistogramName, "Failure"}), resume_time); base::UmaHistogramSparse("Net.HttpStreamPool.JobErrorCode", -*result_); } } @@ -158,91 +150,31 @@ return dict; }); - // `group_` may be deleted after this call. - group_.ExtractAsDangling()->OnJobComplete(this); + // `attempt_manager_` may be deleted after this call. + attempt_manager_.ExtractAsDangling()->OnJobComplete(this); } void HttpStreamPool::Job::Start() { - CHECK(group_); + CHECK(attempt_manager_); + CHECK(!attempt_manager_->is_failing()); - if (!group_->CanStartJob(this)) { - job_net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_POOL_JOB_PAUSED); - group_->net_log().AddEventReferencingSource( - NetLogEventType::HTTP_STREAM_POOL_GROUP_JOB_PAUSED, - job_net_log_.source()); - return; + if (IsPreconnect()) { + attempt_manager_->Preconnect(this); + } else { + attempt_manager_->StartJob(this); } - - StartInternal(); -} - -void HttpStreamPool::Job::Resume() { - resume_time_ = base::TimeTicks::Now(); - job_net_log_.EndEvent(NetLogEventType::HTTP_STREAM_POOL_JOB_PAUSED); - group_->net_log().AddEvent( - NetLogEventType::HTTP_STREAM_POOL_GROUP_JOB_RESUMED, [&] { - base::Value::Dict dict; - base::TimeDelta elapsed = resume_time_ - create_time_; - dict.Set("elapsed_ms", elapsed.InMillisecondsF()); - job_net_log_.source().AddToEventParameters(dict); - return dict; - }); - - // There might be existing QUIC/SPDY sessions after resuming `this`. - - QuicChromiumClientSession* quic_session = - group_->pool() - ->http_network_session() - ->quic_session_pool() - ->FindExistingSession(group_->quic_session_alias_key().session_key(), - group_->quic_session_alias_key().destination()); - if (quic_session) { - if (IsPreconnect()) { - CallOnPreconnectCompleteLater(OK); - } else { - auto http_stream = std::make_unique<QuicHttpStream>( - quic_session->CreateHandle( - group_->quic_session_alias_key().destination()), - quic_session->GetDnsAliasesForSessionKey( - group_->quic_session_alias_key().session_key())); - delegate_->OnStreamReady(this, std::move(http_stream), - NextProto::kProtoQUIC); - } - return; - } - - base::WeakPtr spdy_session = group_->pool()->FindAvailableSpdySession( - group_->stream_key(), group_->spdy_session_key(), - delegate_->enable_ip_based_pooling(), request_net_log_); - if (spdy_session) { - if (IsPreconnect()) { - CallOnPreconnectCompleteLater(OK); - } else { - auto http_stream = std::make_unique<SpdyHttpStream>( - spdy_session, request_net_log_.source(), - group_->http_network_session() - ->spdy_session_pool() - ->GetDnsAliasesForSessionKey(group_->spdy_session_key())); - delegate_->OnStreamReady(this, std::move(http_stream), - NextProto::kProtoHTTP2); - } - return; - } - - group_->EnsureAttemptManager(); - StartInternal(); } LoadState HttpStreamPool::Job::GetLoadState() const { - if (!attempt_manager()) { + if (!attempt_manager_) { return LOAD_STATE_IDLE; } - return attempt_manager()->GetLoadState(); + return attempt_manager_->GetLoadState(); } void HttpStreamPool::Job::SetPriority(RequestPriority priority) { - if (attempt_manager()) { - attempt_manager()->SetJobPriority(this, priority); + if (attempt_manager_) { + attempt_manager_->SetJobPriority(this, priority); } } @@ -258,6 +190,7 @@ CHECK(delegate_); CHECK(!result_.has_value()); CHECK(!negotiated_protocol_); + CHECK(attempt_manager_); int result = OK; if (!allowed_alpns_.Has(negotiated_protocol)) { @@ -278,8 +211,10 @@ result_ = OK; negotiated_protocol_ = negotiated_protocol; - group_->http_network_session()->proxy_resolution_service()->ReportSuccess( - delegate_->proxy_info()); + attempt_manager_->group() + ->http_network_session() + ->proxy_resolution_service() + ->ReportSuccess(delegate_->proxy_info()); delegate_->OnStreamReady(this, std::move(stream), negotiated_protocol); } @@ -322,27 +257,4 @@ weak_ptr_factory_.GetWeakPtr(), status)); } -base::TimeDelta HttpStreamPool::Job::CreateToResumeTime() const { - if (resume_time_.is_null()) { - return base::TimeDelta(); - } - return resume_time_ - create_time_; -} - -HttpStreamPool::AttemptManager* HttpStreamPool::Job::attempt_manager() const { - CHECK(group_); - return group_->attempt_manager(); -} - -void HttpStreamPool::Job::StartInternal() { - CHECK(attempt_manager()); - CHECK(!attempt_manager()->is_failing()); - - if (IsPreconnect()) { - attempt_manager()->Preconnect(this); - } else { - attempt_manager()->StartJob(this); - } -} - } // namespace net
diff --git a/net/http/http_stream_pool_job.h b/net/http/http_stream_pool_job.h index ac78dfa..d689075 100644 --- a/net/http/http_stream_pool_job.h +++ b/net/http/http_stream_pool_job.h
@@ -100,10 +100,6 @@ // Starts this job. void Start(); - // Resumes this job. Must be called only when Group::CanStartJob() returns - // false. - void Resume(); - // Returns the LoadState of this job. LoadState GetLoadState() const; @@ -178,22 +174,16 @@ base::TimeTicks create_time() const { return create_time_; } - base::TimeDelta CreateToResumeTime() const; - private: - AttemptManager* attempt_manager() const; - - void StartInternal(); - const raw_ptr<Delegate> delegate_; - raw_ptr<Group> group_; + raw_ptr<AttemptManager> attempt_manager_; + const quic::ParsedQuicVersion quic_version_; const NextProtoSet allowed_alpns_; const NetLogWithSource request_net_log_; const NetLogWithSource job_net_log_; const size_t num_streams_; const base::TimeTicks create_time_; - base::TimeTicks resume_time_; std::optional<int> result_; std::optional<NextProto> negotiated_protocol_;
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h index 85620de..e8a39a2 100644 --- a/net/log/net_log_event_type_list.h +++ b/net/log/net_log_event_type_list.h
@@ -1479,9 +1479,6 @@ // } EVENT_TYPE(HTTP_STREAM_POOL_JOB_ALIVE) -// Marks the start/end of a pause of an HttpStreamPool::Job. -EVENT_TYPE(HTTP_STREAM_POOL_JOB_PAUSED) - // Marks the start/end of a HttpStreamPool::Group. // The following parameters are attached: // { @@ -1490,16 +1487,6 @@ // } EVENT_TYPE(HTTP_STREAM_POOL_GROUP_ALIVE) -// Emitted when an HttpStreamPool::Job is paused in an HttpStreamPool::Group. -EVENT_TYPE(HTTP_STREAM_POOL_GROUP_JOB_PAUSED) - -// Emitted when an HttpStreamPool::Job is resumed in an HttpStreamPool::Group. -// The following parameters are attached: -// { -// "elapsed_ms": <Time taken for the job to resume in milliseconds>, -// } -EVENT_TYPE(HTTP_STREAM_POOL_GROUP_JOB_RESUMED) - // Emitted when an HttpStreamPool::AttemptManager is created. Used to add a // reference to HttpStreamPool::Group's net log. EVENT_TYPE(HTTP_STREAM_POOL_GROUP_ATTEMPT_MANAGER_CREATED)
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc index c7d634fa..3d32da87 100644 --- a/net/quic/quic_chromium_client_session.cc +++ b/net/quic/quic_chromium_client_session.cc
@@ -1646,7 +1646,7 @@ // when we have an outstanding request in flight. We want to send PINGs when // there is an outstanding request or if `enable_periodic_ping_` has been // set to keep the connection alive when idle. - return enable_periodic_ping_ || + return (enable_periodic_ping_ && crypto_handshake_complete_) || quic::QuicSpdyClientSessionBase::ShouldKeepConnectionAlive(); } @@ -3805,6 +3805,15 @@ UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime", handshake_confirmed_time); + // Indicate that the handshake is complete so that we can safely send pings + // to the peer. + crypto_handshake_complete_ = true; + // We explicitly kick off pings here, since we do not want to ping when there + // are no available encrypters available. + if (enable_periodic_ping_) { + connection()->SendPing(); + } + // Also record the handshake time when ECH was advertised in DNS. The ECH // experiment does not change DNS behavior, so this measures the same servers // in both experiment and control groups.
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h index 1a156c08..241ec52 100644 --- a/net/quic/quic_chromium_client_session.h +++ b/net/quic/quic_chromium_client_session.h
@@ -1256,6 +1256,8 @@ // does not have any outstanding requests. bool enable_periodic_ping_ = false; + bool crypto_handshake_complete_ = false; + base::WeakPtrFactory<QuicChromiumClientSession> weak_factory_{this}; };
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc index 25d6bc3..9cca305 100644 --- a/net/quic/quic_chromium_client_session_test.cc +++ b/net/quic/quic_chromium_client_session_test.cc
@@ -2508,8 +2508,10 @@ quic::QuicTime::Delta::FromSeconds(10)); // Set connection keep alive true. session_->SetPeriodicConnectionKeepAlive(true); - CompleteCryptoHandshake(); + EXPECT_TRUE(ping_alarm_.has_value()); + EXPECT_FALSE(ping_alarm_->IsSet()); + CompleteCryptoHandshake(); // Check that we do not have any outstanding streams, but have the alarm set. EXPECT_EQ(0u, session_->GetNumActiveStreams());
diff --git a/services/device/BUILD.gn b/services/device/BUILD.gn index 52ede10..f98c62a 100644 --- a/services/device/BUILD.gn +++ b/services/device/BUILD.gn
@@ -193,6 +193,7 @@ sources += [ "compute_pressure/cpu_probe_manager_unittest.cc", "compute_pressure/pressure_manager_impl_unittest.cc", + "public/cpp/compute_pressure/cpu_pressure_converter_unittest.cc", ] deps += [ "//services/device/compute_pressure" ] }
diff --git a/services/device/compute_pressure/BUILD.gn b/services/device/compute_pressure/BUILD.gn index a3a3dd8f..a2768b75 100644 --- a/services/device/compute_pressure/BUILD.gn +++ b/services/device/compute_pressure/BUILD.gn
@@ -22,7 +22,10 @@ configs += [ "//build/config/compiler:wexit_time_destructors" ] - public_deps = [ "//services/device/public/mojom" ] + public_deps = [ + "//services/device/public/cpp/compute_pressure", + "//services/device/public/mojom", + ] deps = [ "//base",
diff --git a/services/device/compute_pressure/cpu_probe_manager.cc b/services/device/compute_pressure/cpu_probe_manager.cc index 80fe85327..a15b515 100644 --- a/services/device/compute_pressure/cpu_probe_manager.cc +++ b/services/device/compute_pressure/cpu_probe_manager.cc
@@ -24,62 +24,39 @@ using system_cpu::CpuProbe; using system_cpu::CpuSample; -// Delta for the state decision hysteresis. -constexpr double kThresholdDelta = 0.03; - -// |randomization_timer_| boundaries in second. -constexpr uint64_t kMinRandomizationTimeInSeconds = 120; -constexpr uint64_t kMaxRandomizationTimeInSeconds = 240; - -// Thresholds to use with no randomization. -constexpr std::array<double, - static_cast<size_t>(mojom::PressureState::kMaxValue) + 1> - kStateBaseThresholds = {0.6, // kNominal - 0.75, // kFair - 0.9, // kSerious - 1.0}; // kCritical - -// Thresholds to use during randomization. -constexpr std::array<double, - static_cast<size_t>(mojom::PressureState::kMaxValue) + 1> - kStateRandomizedThresholds = {0.5, // kNominal - 0.8, // kFair - 0.85, // kSerious - 1.0}; // kCritical - } // namespace // static std::unique_ptr<CpuProbeManager> CpuProbeManager::Create( base::TimeDelta sampling_interval, - base::RepeatingCallback<void(mojom::PressureState)> sampling_callback) { + base::RepeatingCallback<void(mojom::PressureDataPtr)> sampling_callback) { std::unique_ptr<CpuProbe> system_cpu_probe = CpuProbe::Create(); if (!system_cpu_probe) { return nullptr; } return base::WrapUnique(new CpuProbeManager( - std::move(system_cpu_probe), sampling_interval, sampling_callback)); + sampling_interval, sampling_callback, std::move(system_cpu_probe))); } // static std::unique_ptr<CpuProbeManager> CpuProbeManager::CreateForTesting( - std::unique_ptr<CpuProbe> system_cpu_probe, base::TimeDelta sampling_interval, - base::RepeatingCallback<void(mojom::PressureState)> sampling_callback) { + base::RepeatingCallback<void(mojom::PressureDataPtr)> sampling_callback, + std::unique_ptr<CpuProbe> system_cpu_probe) { if (!system_cpu_probe) { return nullptr; } return base::WrapUnique(new CpuProbeManager( - std::move(system_cpu_probe), sampling_interval, sampling_callback)); + sampling_interval, sampling_callback, std::move(system_cpu_probe))); } CpuProbeManager::CpuProbeManager( - std::unique_ptr<CpuProbe> system_cpu_probe, base::TimeDelta sampling_interval, - base::RepeatingCallback<void(mojom::PressureState)> sampling_callback) - : system_cpu_probe_(std::move(system_cpu_probe)), - sampling_interval_(sampling_interval), - sampling_callback_(std::move(sampling_callback)) { + base::RepeatingCallback<void(mojom::PressureDataPtr)> sampling_callback, + std::unique_ptr<CpuProbe> system_cpu_probe) + : sampling_interval_(sampling_interval), + sampling_callback_(std::move(sampling_callback)), + system_cpu_probe_(std::move(system_cpu_probe)) { CHECK(system_cpu_probe_); CHECK(sampling_callback_); } @@ -107,27 +84,12 @@ &CpuProbe::RequestSample, system_cpu_probe_->GetWeakPtr(), base::BindRepeating(&CpuProbeManager::OnCpuSampleAvailable, weak_factory_.GetWeakPtr()))); - - if (base::FeatureList::IsEnabled( - features::kComputePressureBreakCalibrationMitigation)) { - randomization_time_ = base::Seconds(base::RandInt( - kMinRandomizationTimeInSeconds, kMaxRandomizationTimeInSeconds)); - - randomization_timer_.Start( - FROM_HERE, randomization_time_, - base::BindRepeating(&CpuProbeManager::ToggleStateRandomization, - weak_factory_.GetWeakPtr())); - } } void CpuProbeManager::Stop() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); timer_.Stop(); - randomization_timer_.Stop(); - state_randomization_requested_ = false; - // Drop the replies to any RequestSample calls that were posted before the - // timer stopped. weak_factory_.InvalidateWeakPtrs(); } @@ -136,29 +98,6 @@ return system_cpu_probe_.get(); } -const std::array<double, - static_cast<size_t>(mojom::PressureState::kMaxValue) + 1>& -CpuProbeManager::state_thresholds() const { - return state_randomization_requested_ ? kStateRandomizedThresholds - : kStateBaseThresholds; -} - -double CpuProbeManager::hysteresis_threshold_delta() const { - return kThresholdDelta; -} - -void CpuProbeManager::ToggleStateRandomization() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - state_randomization_requested_ = !state_randomization_requested_; - randomization_time_ = base::Seconds(base::RandInt( - kMinRandomizationTimeInSeconds, kMaxRandomizationTimeInSeconds)); - randomization_timer_.Start( - FROM_HERE, randomization_time_, - base::BindRepeating(&CpuProbeManager::ToggleStateRandomization, - weak_factory_.GetWeakPtr())); -} - void CpuProbeManager::OnCpuSampleAvailable(std::optional<CpuSample> sample) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -166,37 +105,11 @@ // by InvalidateWeakPtrs(). CHECK(timer_.IsRunning()); if (sample.has_value()) { - sampling_callback_.Run(CalculateState(sample.value())); + sampling_callback_.Run( + mojom::PressureData::New(sample.value().cpu_utilization)); } } -mojom::PressureState CpuProbeManager::CalculateState(const CpuSample& sample) { - // TODO(crbug.com/40231044): A more advanced algorithm that calculates - // PressureState using CpuSample needs to be determined. - // At this moment the algorithm is the simplest possible - // with thresholds defining the state. - const auto& kStateThresholds = state_thresholds(); - - auto it = std::ranges::lower_bound(kStateThresholds, sample.cpu_utilization); - if (it == kStateThresholds.end()) { - NOTREACHED() << "unexpected value: " << sample.cpu_utilization; - } - - size_t state_index = std::distance(kStateThresholds.begin(), it); - - // Hysteresis to avoid flip-flop between state. - // Threshold needs to drop by level and - // cpu_utilization needs a drop of kThresholdDelta below the state - // threshold to be validated as a lower pressure state. - if (last_state_index_ - state_index != 1 || - kStateThresholds[state_index] - sample.cpu_utilization >= - kThresholdDelta) { - last_state_index_ = state_index; - } - - return static_cast<mojom::PressureState>(last_state_index_); -} - void CpuProbeManager::SetCpuProbeForTesting( std::unique_ptr<system_cpu::CpuProbe> cpu_probe) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/services/device/compute_pressure/cpu_probe_manager.h b/services/device/compute_pressure/cpu_probe_manager.h index 8d9ca47..a17ecf47 100644 --- a/services/device/compute_pressure/cpu_probe_manager.h +++ b/services/device/compute_pressure/cpu_probe_manager.h
@@ -14,7 +14,7 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "components/system_cpu/cpu_sample.h" -#include "services/device/public/mojom/pressure_update.mojom-shared.h" +#include "services/device/public/mojom/pressure_update.mojom.h" namespace system_cpu { class CpuProbe; @@ -42,13 +42,13 @@ // Returns nullptr if no suitable implementation exists. static std::unique_ptr<CpuProbeManager> Create( base::TimeDelta sampling_interval, - base::RepeatingCallback<void(mojom::PressureState)> sampling_callback); + base::RepeatingCallback<void(mojom::PressureDataPtr)> sampling_callback); // Instantiates CpuProbeManager with a supplied CpuProbe. static std::unique_ptr<CpuProbeManager> CreateForTesting( - std::unique_ptr<system_cpu::CpuProbe> system_cpu_probe, base::TimeDelta sampling_interval, - base::RepeatingCallback<void(mojom::PressureState)> sampling_callback); + base::RepeatingCallback<void(mojom::PressureDataPtr)> sampling_callback, + std::unique_ptr<system_cpu::CpuProbe> system_cpu_probe); CpuProbeManager(const CpuProbeManager&) = delete; CpuProbeManager& operator=(const CpuProbeManager&) = delete; @@ -64,28 +64,25 @@ // Stop the timer. void Stop(); - base::TimeDelta GetRandomizationTimeForTesting() const { - return randomization_time_; - } - void SetCpuProbeForTesting(std::unique_ptr<system_cpu::CpuProbe>); protected: - CpuProbeManager(std::unique_ptr<system_cpu::CpuProbe> system_cpu_probe, - base::TimeDelta, - base::RepeatingCallback<void(mojom::PressureState)>); + SEQUENCE_CHECKER(sequence_checker_); + + CpuProbeManager(base::TimeDelta, + base::RepeatingCallback<void(mojom::PressureDataPtr)>, + std::unique_ptr<system_cpu::CpuProbe> system_cpu_probe); system_cpu::CpuProbe* cpu_probe(); - // Returns the current thresholds being used for each mojom::PressureState, - // taking state randomization into account. - const std::array<double, - static_cast<size_t>(mojom::PressureState::kMaxValue) + 1>& - state_thresholds() const; + // Drive repeated sampling. + base::RepeatingTimer timer_ GUARDED_BY_CONTEXT(sequence_checker_); + const base::TimeDelta sampling_interval_ + GUARDED_BY_CONTEXT(sequence_checker_); - // Returns the hysteresis threshold delta value used - // to prevent state flip-flopping. - double hysteresis_threshold_delta() const; + // Called with each sample reading. + base::RepeatingCallback<void(mojom::PressureDataPtr)> sampling_callback_ + GUARDED_BY_CONTEXT(sequence_checker_); private: friend class CpuProbeManagerTest; @@ -93,44 +90,12 @@ CalculateStateValueTooLarge); FRIEND_TEST_ALL_PREFIXES(CpuProbeManagerTest, CreateCpuProbeExists); - // Implements the "break calibration" mitigation by toggling the - // |state_randomization_requested_| flag every |randomization_time_| - // interval. - void ToggleStateRandomization(); - // Called periodically while the CpuProbe is running. - void OnCpuSampleAvailable(std::optional<system_cpu::CpuSample>); - - // Calculate PressureState based on optional CpuSample. - mojom::PressureState CalculateState(const system_cpu::CpuSample&); - - SEQUENCE_CHECKER(sequence_checker_); + virtual void OnCpuSampleAvailable(std::optional<system_cpu::CpuSample>); std::unique_ptr<system_cpu::CpuProbe> system_cpu_probe_ GUARDED_BY_CONTEXT(sequence_checker_); - // Variable storing |randomization_timer_| time. - base::TimeDelta randomization_time_; - - // Last state stored as index instead of value. - size_t last_state_index_ = - static_cast<size_t>(mojom::PressureState::kNominal); - - // Drive repeated sampling. - base::RepeatingTimer timer_ GUARDED_BY_CONTEXT(sequence_checker_); - const base::TimeDelta sampling_interval_ - GUARDED_BY_CONTEXT(sequence_checker_); - - // Drive randomization interval by invoking `ToggleStateRandomization()`. - base::OneShotTimer randomization_timer_ GUARDED_BY_CONTEXT(sequence_checker_); - - // Flag to indicate that state randomization has been requested. - bool state_randomization_requested_ = false; - - // Called with each sample reading. - base::RepeatingCallback<void(mojom::PressureState)> sampling_callback_ - GUARDED_BY_CONTEXT(sequence_checker_); - base::WeakPtrFactory<CpuProbeManager> weak_factory_{this}; };
diff --git a/services/device/compute_pressure/cpu_probe_manager_unittest.cc b/services/device/compute_pressure/cpu_probe_manager_unittest.cc index f526f16..636afd3 100644 --- a/services/device/compute_pressure/cpu_probe_manager_unittest.cc +++ b/services/device/compute_pressure/cpu_probe_manager_unittest.cc
@@ -68,10 +68,11 @@ public: CpuProbeManagerTest() : cpu_probe_manager_(CpuProbeManager::CreateForTesting( - std::make_unique<FakeCpuProbe>(GetResponseDelayDelta(GetParam())), TestTimeouts::tiny_timeout(), base::BindRepeating(&CpuProbeManagerTest::CollectorCallback, - base::Unretained(this)))) {} + base::Unretained(this)), + std::make_unique<FakeCpuProbe>( + GetResponseDelayDelta(GetParam())))) {} void WaitForUpdate() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -79,9 +80,9 @@ task_environment_.RunUntilQuit(); } - void CollectorCallback(mojom::PressureState sample) { + void CollectorCallback(mojom::PressureDataPtr data) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - samples_.push_back(sample); + samples_.push_back(data->cpu_utilization); if (update_callback_) { std::move(update_callback_).Run(); update_callback_.Reset(); @@ -108,9 +109,8 @@ // so it can be replaced inside tests. std::unique_ptr<CpuProbeManager> cpu_probe_manager_; - // The samples reported by the callback. - std::vector<mojom::PressureState> samples_ - GUARDED_BY_CONTEXT(sequence_checker_); + // The samples of cpu_utilization reported by the callback. + std::vector<double> samples_ GUARDED_BY_CONTEXT(sequence_checker_); private: void SetNextUpdateCallback(base::OnceClosure callback) { @@ -124,7 +124,6 @@ base::OnceClosure update_callback_ GUARDED_BY_CONTEXT(sequence_checker_); }; -using CpuProbeManagerDeathTest = CpuProbeManagerTest; using CpuProbeManagerDelayedResponseTest = CpuProbeManagerTest; // Most tests won't include a response delay. @@ -132,10 +131,6 @@ CpuProbeManagerTest, ::testing::Values(ResponseDelay::kNone)); -INSTANTIATE_TEST_SUITE_P(NoResponseDelay, - CpuProbeManagerDeathTest, - ::testing::Values(ResponseDelay::kNone)); - INSTANTIATE_TEST_SUITE_P( AllResponseDelays, CpuProbeManagerDelayedResponseTest, @@ -161,8 +156,7 @@ cpu_probe_manager_->EnsureStarted(); WaitForUpdate(); - EXPECT_THAT(samples_, ::testing::ElementsAre(mojom::PressureState( - mojom::PressureState::kSerious))); + EXPECT_THAT(samples_, ::testing::ElementsAre(0.9)); } TEST_P(CpuProbeManagerTest, InvalidSampleIsIgnored) { @@ -182,8 +176,7 @@ SetProbeSample(CpuSample{0.9}); WaitForUpdate(); - EXPECT_THAT(samples_, ::testing::ElementsAre(mojom::PressureState( - mojom::PressureState::kSerious))); + EXPECT_THAT(samples_, ::testing::ElementsAre(0.9)); } TEST_P(CpuProbeManagerTest, EnsureStartedSkipsFirstSample) { @@ -203,197 +196,7 @@ cpu_probe_manager_->EnsureStarted(); task_environment_.RunUntilQuit(); - EXPECT_THAT(samples_, ::testing::ElementsAre( - mojom::PressureState{mojom::PressureState::kFair})); -} - -TEST_P(CpuProbeManagerDeathTest, CalculateStateValueTooLarge) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - EXPECT_DCHECK_DEATH_WITH(cpu_probe_manager_->CalculateState(CpuSample{1.1}), - "unexpected value: 1.1"); -} - -TEST_P(CpuProbeManagerTest, EnsureStartedCheckBreakCalibrationMitigation) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - SetProbeSample(CpuSample{0.86}); - cpu_probe_manager_->EnsureStarted(); - WaitForUpdate(); - EXPECT_THAT(samples_.back(), - mojom::PressureState(mojom::PressureState::kSerious)); - - cpu_probe_manager_->Stop(); - samples_.clear(); - - SetProbeSample(CpuSample{0.86}); - cpu_probe_manager_->EnsureStarted(); - WaitForUpdate(); - // First toggling. - task_environment_.FastForwardBy( - cpu_probe_manager_->GetRandomizationTimeForTesting()); - EXPECT_THAT(samples_.back(), - mojom::PressureState(mojom::PressureState::kCritical)); - // Second toggling. - task_environment_.FastForwardBy( - cpu_probe_manager_->GetRandomizationTimeForTesting()); - EXPECT_THAT(samples_.back(), - mojom::PressureState(mojom::PressureState::kSerious)); -} - -TEST_P(CpuProbeManagerTest, EnsureStartedCheckCalculateStateHysteresisUp) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - std::vector<CpuSample> samples = { - // Value right after construction. - CpuSample{0.6}, - // Value after first Update(), should be discarded. - CpuSample{0.9}, - // kNominal value after should be reported. - CpuSample{0.3}, - // kFair value should be reported. - CpuSample{0.7}, - // kSerious value should be reported. - CpuSample{0.8}, - // kCritical value should be reported. - CpuSample{1.0}, - }; - - cpu_probe_manager_->SetCpuProbeForTesting(std::make_unique<StreamingCpuProbe>( - std::move(samples), task_environment_.QuitClosure())); - cpu_probe_manager_->EnsureStarted(); - task_environment_.RunUntilQuit(); - - EXPECT_THAT(samples_, - ::testing::ElementsAre( - mojom::PressureState{mojom::PressureState::kNominal}, - mojom::PressureState{mojom::PressureState::kFair}, - mojom::PressureState{mojom::PressureState::kSerious}, - mojom::PressureState{mojom::PressureState::kCritical})); -} - -TEST_P(CpuProbeManagerTest, EnsureStartedCheckCalculateStateHysteresisDown) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - std::vector<CpuSample> samples = { - // Value right after construction. - CpuSample{1.0}, - // Value after first Update(), should be discarded. - CpuSample{0.85}, - // kCritical value after should be reported. - CpuSample{1.0}, - // kSerious value should be reported. - CpuSample{0.85}, - // kFair value should be reported. - CpuSample{0.70}, - // kNominal value should be reported. - CpuSample{0.55}, - }; - - cpu_probe_manager_->SetCpuProbeForTesting(std::make_unique<StreamingCpuProbe>( - std::move(samples), task_environment_.QuitClosure())); - cpu_probe_manager_->EnsureStarted(); - task_environment_.RunUntilQuit(); - - EXPECT_THAT(samples_, - ::testing::ElementsAre( - mojom::PressureState{mojom::PressureState::kCritical}, - mojom::PressureState{mojom::PressureState::kSerious}, - mojom::PressureState{mojom::PressureState::kFair}, - mojom::PressureState{mojom::PressureState::kNominal})); -} - -TEST_P(CpuProbeManagerTest, - EnsureStartedCheckCalculateStateHysteresisDownByDelta) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - std::vector<CpuSample> samples = { - // Value right after construction. - CpuSample{1.0}, - // Value after first Update(), should be discarded. - CpuSample{1.0}, - // kCritical value after should be reported. - CpuSample{0.95}, - // kCritical value should be reported due to hysteresis. - CpuSample{0.88}, - // kFair value should be reported. - CpuSample{0.73}, - // kNominal value should be reported. - CpuSample{0.56}, - }; - - cpu_probe_manager_->SetCpuProbeForTesting(std::make_unique<StreamingCpuProbe>( - std::move(samples), task_environment_.QuitClosure())); - cpu_probe_manager_->EnsureStarted(); - task_environment_.RunUntilQuit(); - - EXPECT_THAT(samples_, - ::testing::ElementsAre( - mojom::PressureState{mojom::PressureState::kCritical}, - mojom::PressureState{mojom::PressureState::kCritical}, - mojom::PressureState{mojom::PressureState::kFair}, - mojom::PressureState{mojom::PressureState::kNominal})); -} - -TEST_P(CpuProbeManagerTest, - EnsureStartedCheckCalculateStateHysteresisDownByDeltaTwoState) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - std::vector<CpuSample> samples = { - // Value right after construction. - CpuSample{1.0}, - // Value after first Update(), should be discarded. - CpuSample{1.0}, - // kCritical value after should be reported. - CpuSample{0.95}, - // kFair value should be reported. - CpuSample{0.73}, - // kFair value should be reported due to hysteresis. - CpuSample{0.58}, - }; - - cpu_probe_manager_->SetCpuProbeForTesting(std::make_unique<StreamingCpuProbe>( - std::move(samples), task_environment_.QuitClosure())); - cpu_probe_manager_->EnsureStarted(); - task_environment_.RunUntilQuit(); - - EXPECT_THAT(samples_, - ::testing::ElementsAre( - mojom::PressureState{mojom::PressureState::kCritical}, - mojom::PressureState{mojom::PressureState::kFair}, - mojom::PressureState{mojom::PressureState::kFair})); -} - -TEST_P(CpuProbeManagerTest, - EnsureStartedCheckCalculateStateHysteresisUpByDelta) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - std::vector<CpuSample> samples = { - // Value right after construction. - CpuSample{1.0}, - // Value after first Update(), should be discarded. - CpuSample{1.0}, - // kNominal value after should be reported. - CpuSample{0.6}, - // kFair value should be reported due to hysteresis. - CpuSample{0.62}, - // kSerious value should be reported. - CpuSample{0.77}, - // kCritical value should be reported. - CpuSample{0.91}, - }; - - cpu_probe_manager_->SetCpuProbeForTesting(std::make_unique<StreamingCpuProbe>( - std::move(samples), task_environment_.QuitClosure())); - cpu_probe_manager_->EnsureStarted(); - task_environment_.RunUntilQuit(); - - EXPECT_THAT(samples_, - ::testing::ElementsAre( - mojom::PressureState{mojom::PressureState::kNominal}, - mojom::PressureState{mojom::PressureState::kFair}, - mojom::PressureState{mojom::PressureState::kSerious}, - mojom::PressureState{mojom::PressureState::kCritical})); + EXPECT_THAT(samples_, ::testing::ElementsAre(0.65)); } TEST_P(CpuProbeManagerDelayedResponseTest, StopDelayedEnsureStartedImmediate) { @@ -409,8 +212,7 @@ cpu_probe_manager_->EnsureStarted(); WaitForUpdate(); - EXPECT_THAT(samples_, ::testing::ElementsAre(mojom::PressureState( - mojom::PressureState::kSerious))); + EXPECT_THAT(samples_, ::testing::ElementsAre(0.9)); } TEST_P(CpuProbeManagerDelayedResponseTest, StopDelayedEnsureStartedDelayed) { @@ -426,8 +228,7 @@ task_environment_.FastForwardBy(TestTimeouts::action_timeout()); cpu_probe_manager_->EnsureStarted(); WaitForUpdate(); - EXPECT_THAT(samples_, ::testing::ElementsAre(mojom::PressureState( - mojom::PressureState::kSerious))); + EXPECT_THAT(samples_, ::testing::ElementsAre(0.9)); } TEST_P(CpuProbeManagerDelayedResponseTest, @@ -443,8 +244,7 @@ cpu_probe_manager_->EnsureStarted(); WaitForUpdate(); - EXPECT_THAT(samples_, ::testing::ElementsAre(mojom::PressureState( - mojom::PressureState::kSerious))); + EXPECT_THAT(samples_, ::testing::ElementsAre(0.9)); } TEST_P(CpuProbeManagerDelayedResponseTest, StopImmediateEnsureStartedDelayed) { @@ -460,8 +260,7 @@ task_environment_.FastForwardBy(TestTimeouts::action_timeout()); cpu_probe_manager_->EnsureStarted(); WaitForUpdate(); - EXPECT_THAT(samples_, ::testing::ElementsAre(mojom::PressureState( - mojom::PressureState::kSerious))); + EXPECT_THAT(samples_, ::testing::ElementsAre(0.9)); } TEST_P(CpuProbeManagerDelayedResponseTest, StopEnsureStartedNoRace) { @@ -489,8 +288,7 @@ // The 0.9 sample was sent before Stop(), so it should NOT be included in the // pressure calculation. - EXPECT_THAT(samples_, ::testing::ElementsAre( - mojom::PressureState(mojom::PressureState::kFair))); + EXPECT_THAT(samples_, ::testing::ElementsAre(0.65)); } } // namespace device
diff --git a/services/device/compute_pressure/pressure_manager_impl_unittest.cc b/services/device/compute_pressure/pressure_manager_impl_unittest.cc index 93e8038d..e98d508 100644 --- a/services/device/compute_pressure/pressure_manager_impl_unittest.cc +++ b/services/device/compute_pressure/pressure_manager_impl_unittest.cc
@@ -47,15 +47,17 @@ FakePressureClient& operator=(const FakePressureClient&) = delete; // device::mojom::PressureClient implementation. - void OnPressureUpdated(device::mojom::PressureUpdatePtr update) override { - updates_.emplace_back(*update); + void OnPressureUpdated(mojom::PressureUpdatePtr update) override { + updates_.push_back(std::move(update)); if (update_callback_) { std::move(update_callback_).Run(); update_callback_.Reset(); } } - const std::vector<mojom::PressureUpdate>& updates() const { return updates_; } + const std::vector<mojom::PressureUpdatePtr>& updates() const { + return updates_; + } void SetNextUpdateCallback(base::OnceClosure callback) { CHECK(!update_callback_) << " already called before update received"; @@ -85,8 +87,8 @@ bool is_bound() const { return client_.is_bound(); } private: - // Used to save PressureState. - std::vector<mojom::PressureUpdate> updates_; + // Used to save pressure updates. + std::vector<mojom::PressureUpdatePtr> updates_; // Used to implement WaitForUpdate(). base::OnceClosure update_callback_; @@ -109,13 +111,12 @@ manager_impl_ = PressureManagerImpl::Create(TestTimeouts::tiny_timeout()); auto fake_cpu_probe = std::make_unique<system_cpu::FakeCpuProbe>(); - // CpuSample = 0.63 is converted to PressureState::kFair fake_cpu_probe->SetLastSample(system_cpu::CpuSample{0.63}); auto* probes_manager = manager_impl_->GetProbesManagerForTesting(); probes_manager->set_cpu_probe_manager(CpuProbeManager::CreateForTesting( - std::move(fake_cpu_probe), probes_manager->sampling_interval_for_testing(), - probes_manager->cpu_probe_sampling_callback())); + probes_manager->cpu_probe_sampling_callback(), + std::move(fake_cpu_probe))); manager_.reset(); manager_impl_->Bind(manager_.BindNewPipeAndPassReceiver()); } @@ -176,9 +177,9 @@ client.WaitForUpdate(); ASSERT_EQ(client.updates().size(), 1u); - EXPECT_EQ(client.updates()[0].source, mojom::PressureSource::kCpu); - // In SetUp() CpuSample = 0.63, which is translated to PressureState::kFair. - EXPECT_EQ(client.updates()[0].state, mojom::PressureState::kFair); + EXPECT_EQ(client.updates()[0]->source, mojom::PressureSource::kCpu); + // In SetUp() CpuSample = 0.63. + EXPECT_EQ(client.updates()[0]->data->cpu_utilization, 0.63); } TEST_F(PressureManagerImplTest, ThreeClients) { @@ -192,17 +193,17 @@ ASSERT_EQ(AddPressureClient(&client3, mojom::PressureSource::kCpu), mojom::PressureManagerAddClientResult::kOk); - // In SetUp() CpuSample = 0.63, which is translated to PressureState::kFair. + // In SetUp() CpuSample = 0.63. FakePressureClient::WaitForUpdates({&client1, &client2, &client3}); ASSERT_EQ(client1.updates().size(), 1u); - EXPECT_EQ(client1.updates()[0].source, mojom::PressureSource::kCpu); - EXPECT_EQ(client1.updates()[0].state, mojom::PressureState::kFair); + EXPECT_EQ(client1.updates()[0]->source, mojom::PressureSource::kCpu); + EXPECT_EQ(client1.updates()[0]->data->cpu_utilization, 0.63); ASSERT_EQ(client2.updates().size(), 1u); - EXPECT_EQ(client2.updates()[0].source, mojom::PressureSource::kCpu); - EXPECT_EQ(client2.updates()[0].state, mojom::PressureState::kFair); + EXPECT_EQ(client2.updates()[0]->source, mojom::PressureSource::kCpu); + EXPECT_EQ(client2.updates()[0]->data->cpu_utilization, 0.63); ASSERT_EQ(client3.updates().size(), 1u); - EXPECT_EQ(client3.updates()[0].source, mojom::PressureSource::kCpu); - EXPECT_EQ(client3.updates()[0].state, mojom::PressureState::kFair); + EXPECT_EQ(client3.updates()[0]->source, mojom::PressureSource::kCpu); + EXPECT_EQ(client3.updates()[0]->data->cpu_utilization, 0.63); } TEST_F(PressureManagerImplTest, AddClientNoProbe) { @@ -284,19 +285,20 @@ FakePressureClient::WaitForUpdates({&client, &virtual_client}); ASSERT_EQ(client.updates().size(), 1u); - EXPECT_EQ(client.updates()[0].source, mojom::PressureSource::kCpu); - // In SetUp() system_cpu::CpuSample is set to 0.63, which will be converted to - // PressureState::kFair. - EXPECT_EQ(client.updates()[0].state, mojom::PressureState::kFair); + EXPECT_EQ(client.updates()[0]->source, mojom::PressureSource::kCpu); + // In SetUp() system_cpu::CpuSample is set to 0.63. + EXPECT_EQ(client.updates()[0]->data->cpu_utilization, 0.63); // Virtual probes run faster than real ones, so we might have more than one // update. - ASSERT_FALSE(virtual_client.updates().empty()); - for (const auto& update : virtual_client.updates()) { - EXPECT_EQ(update.source, mojom::PressureSource::kCpu); - EXPECT_EQ(update.state, mojom::PressureState::kCritical); - EXPECT_NE(client.updates()[0].timestamp, update.timestamp); + ASSERT_FALSE(virtual_client.updates().empty()); + + for (const auto& update : virtual_client.updates()) { + EXPECT_EQ(update->source, mojom::PressureSource::kCpu); + // Critical = 1.0 - kThreshold. + EXPECT_EQ(update->data->cpu_utilization, 0.97); + EXPECT_NE(client.updates()[0]->timestamp, update->timestamp); } } @@ -327,6 +329,14 @@ AddPressureClient(&virtual_client, token, mojom::PressureSource::kCpu), mojom::PressureManagerAddClientResult::kOk); + // Values - hysteresis. + const std::array<double, + static_cast<size_t>(mojom::PressureState::kMaxValue) + 1> + base_thresholds = {0.57, // kNominal + 0.72, // kFair + 0.87, // kSerious + 0.97}; // kCritical + // Test that all PressureState values are reported correctly. for (size_t i = 0; i < static_cast<size_t>(mojom::PressureState::kMaxValue); ++i) { @@ -337,8 +347,9 @@ virtual_client.WaitForUpdate(); ASSERT_EQ(virtual_client.updates().size(), i + 1); - EXPECT_EQ(virtual_client.updates()[i].source, mojom::PressureSource::kCpu); - EXPECT_EQ(virtual_client.updates()[i].state, state); + EXPECT_EQ(virtual_client.updates()[i]->source, mojom::PressureSource::kCpu); + EXPECT_EQ(virtual_client.updates()[i]->data->cpu_utilization, + base_thresholds[i]); } const size_t update_count = virtual_client.updates().size(); @@ -372,10 +383,10 @@ virtual_client.WaitForUpdate(); ASSERT_EQ(virtual_client.updates().size(), 2U); - EXPECT_EQ(virtual_client.updates()[1].state, - virtual_client.updates()[0].state); - EXPECT_GT(virtual_client.updates()[1].timestamp, - virtual_client.updates()[0].timestamp); + EXPECT_EQ(virtual_client.updates()[1]->data->cpu_utilization, + virtual_client.updates()[0]->data->cpu_utilization); + EXPECT_GT(virtual_client.updates()[1]->timestamp, + virtual_client.updates()[0]->timestamp); } TEST_F(PressureManagerImplTest, SameStateUpdatesAreNotDropped) { @@ -403,10 +414,10 @@ virtual_client.WaitForUpdate(); ASSERT_EQ(virtual_client.updates().size(), 2U); - EXPECT_EQ(virtual_client.updates()[1].state, - virtual_client.updates()[0].state); - EXPECT_GT(virtual_client.updates()[1].timestamp, - virtual_client.updates()[0].timestamp); + EXPECT_EQ(virtual_client.updates()[1]->data->cpu_utilization, + virtual_client.updates()[0]->data->cpu_utilization); + EXPECT_GT(virtual_client.updates()[1]->timestamp, + virtual_client.updates()[0]->timestamp); } TEST_F(PressureManagerImplTest, VirtualPressureSourceNotAvailable) {
diff --git a/services/device/compute_pressure/probes_manager.cc b/services/device/compute_pressure/probes_manager.cc index 8a6ff75..dc1f417 100644 --- a/services/device/compute_pressure/probes_manager.cc +++ b/services/device/compute_pressure/probes_manager.cc
@@ -68,11 +68,11 @@ } void ProbesManager::UpdateClients(mojom::PressureSource source, - mojom::PressureState state) { + mojom::PressureDataPtr data) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); const base::TimeTicks timestamp = base::TimeTicks::Now(); - mojom::PressureUpdate update(source, state, timestamp); + mojom::PressureUpdate update(source, std::move(data), timestamp); for (auto& client : associated_clients_[source]) { client->OnPressureUpdated(update.Clone()); } @@ -106,7 +106,7 @@ cpu_probe_manager_ = std::move(cpu_probe_manager); } -const base::RepeatingCallback<void(mojom::PressureState)>& +const base::RepeatingCallback<void(mojom::PressureDataPtr)>& ProbesManager::cpu_probe_sampling_callback() const { return cpu_probe_sampling_callback_; }
diff --git a/services/device/compute_pressure/probes_manager.h b/services/device/compute_pressure/probes_manager.h index 1768a70..4b9989e6 100644 --- a/services/device/compute_pressure/probes_manager.h +++ b/services/device/compute_pressure/probes_manager.h
@@ -14,7 +14,7 @@ #include "base/time/time.h" #include "mojo/public/cpp/bindings/remote_set.h" #include "services/device/public/mojom/pressure_manager.mojom-forward.h" -#include "services/device/public/mojom/pressure_update.mojom-shared.h" +#include "services/device/public/mojom/pressure_update.mojom.h" namespace device { @@ -44,7 +44,7 @@ void set_cpu_probe_manager( std::unique_ptr<CpuProbeManager> cpu_probe_manager); - const base::RepeatingCallback<void(mojom::PressureState)>& + const base::RepeatingCallback<void(mojom::PressureDataPtr)>& cpu_probe_sampling_callback() const; private: @@ -52,7 +52,7 @@ FRIEND_TEST_ALL_PREFIXES(PressureManagerImplTest, AddClientNoProbe); // Called periodically by probe for each PressureSource. - void UpdateClients(mojom::PressureSource source, mojom::PressureState state); + void UpdateClients(mojom::PressureSource source, mojom::PressureDataPtr); // Stop corresponding probe once there is no client. void OnClientRemoteDisconnected(mojom::PressureSource source, @@ -62,7 +62,7 @@ const base::TimeDelta sampling_interval_; - const base::RepeatingCallback<void(mojom::PressureState)> + const base::RepeatingCallback<void(mojom::PressureDataPtr)> cpu_probe_sampling_callback_; // Probe for retrieving the compute pressure state for CPU.
diff --git a/services/device/compute_pressure/virtual_cpu_probe_manager.cc b/services/device/compute_pressure/virtual_cpu_probe_manager.cc index e389436..663c5b8 100644 --- a/services/device/compute_pressure/virtual_cpu_probe_manager.cc +++ b/services/device/compute_pressure/virtual_cpu_probe_manager.cc
@@ -69,29 +69,42 @@ // static std::unique_ptr<VirtualCpuProbeManager> VirtualCpuProbeManager::Create( base::TimeDelta sampling_interval, - base::RepeatingCallback<void(mojom::PressureState)> sampling_callback) { + base::RepeatingCallback<void(mojom::PressureDataPtr)> sampling_callback) { return base::WrapUnique(new VirtualCpuProbeManager( sampling_interval, std::move(sampling_callback))); } VirtualCpuProbeManager::VirtualCpuProbeManager( base::TimeDelta sampling_interval, - base::RepeatingCallback<void(mojom::PressureState)> sampling_callback) - : CpuProbeManager(std::make_unique<VirtualCpuProbe>(), - sampling_interval, - std::move(sampling_callback)) {} + base::RepeatingCallback<void(mojom::PressureDataPtr)> sampling_callback) + : CpuProbeManager(sampling_interval, + std::move(sampling_callback), + std::make_unique<VirtualCpuProbe>()) {} VirtualCpuProbeManager::~VirtualCpuProbeManager() = default; +void VirtualCpuProbeManager::OnCpuSampleAvailable( + std::optional<system_cpu::CpuSample> sample) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // If the timer was stopped, OnCpuSampleAvailable should have been cancelled + // by InvalidateWeakPtrs(). + CHECK(timer_.IsRunning()); + if (sample.has_value()) { + mojom::PressureData data(sample.value().cpu_utilization); + sampling_callback_.Run(data.Clone()); + } +} + void VirtualCpuProbeManager::SetPressureState( mojom::PressureState desired_state) { double cpu_utilization = - state_thresholds().at(static_cast<size_t>(desired_state)); + converter_.state_thresholds().at(static_cast<size_t>(desired_state)); // If the new `desired_state` is one state below the previously set // `desired_state`, its setting will be under the effect of `threshold_delta` // used to prevent state flip-flopping, therefore the hysteresis threshold // delta needs to be applied to validate the state change. - cpu_utilization -= hysteresis_threshold_delta(); + cpu_utilization -= converter_.hysteresis_threshold_delta(); static_cast<VirtualCpuProbe*>(cpu_probe()) ->SetSample(system_cpu::CpuSample{cpu_utilization}); }
diff --git a/services/device/compute_pressure/virtual_cpu_probe_manager.h b/services/device/compute_pressure/virtual_cpu_probe_manager.h index 1529b99..945d019 100644 --- a/services/device/compute_pressure/virtual_cpu_probe_manager.h +++ b/services/device/compute_pressure/virtual_cpu_probe_manager.h
@@ -10,6 +10,7 @@ #include "base/functional/callback_forward.h" #include "base/time/time.h" #include "services/device/compute_pressure/cpu_probe_manager.h" +#include "services/device/public/cpp/compute_pressure/cpu_pressure_converter.h" #include "services/device/public/mojom/pressure_update.mojom-shared.h" namespace device { @@ -20,10 +21,12 @@ public: static std::unique_ptr<VirtualCpuProbeManager> Create( base::TimeDelta sampling_interval, - base::RepeatingCallback<void(mojom::PressureState)> sampling_callback); + base::RepeatingCallback<void(mojom::PressureDataPtr)> sampling_callback); ~VirtualCpuProbeManager() final; + void OnCpuSampleAvailable(std::optional<system_cpu::CpuSample>) override; + // Creates a system_cpu::CpuSample that corresponds to |desired_state| and // provides it to this class' custom CpuProbe. The CpuSample instance will // eventually reach CpuProbeManager::OnCpuSampleAvailable() and cause @@ -33,7 +36,11 @@ private: VirtualCpuProbeManager( base::TimeDelta sampling_interval, - base::RepeatingCallback<void(mojom::PressureState)> sampling_callback); + base::RepeatingCallback<void(mojom::PressureDataPtr)> sampling_callback); + + // Handles break calibration mitigation and conversion from PressureSample + // to PressureState. + device::CpuPressureConverter converter_; }; } // namespace device
diff --git a/services/device/public/cpp/compute_pressure/BUILD.gn b/services/device/public/cpp/compute_pressure/BUILD.gn index 3f2dacc..125a3d1e 100644 --- a/services/device/public/cpp/compute_pressure/BUILD.gn +++ b/services/device/public/cpp/compute_pressure/BUILD.gn
@@ -9,3 +9,11 @@ header = "buildflags.h" flags = [ "ENABLE_COMPUTE_PRESSURE=$enable_compute_pressure" ] } + +source_set("compute_pressure") { + sources = [ + "cpu_pressure_converter.cc", + "cpu_pressure_converter.h", + ] + public_deps = [ "//services/device/public/mojom" ] +}
diff --git a/services/device/public/cpp/compute_pressure/cpu_pressure_converter.cc b/services/device/public/cpp/compute_pressure/cpu_pressure_converter.cc new file mode 100644 index 0000000..fca47cb --- /dev/null +++ b/services/device/public/cpp/compute_pressure/cpu_pressure_converter.cc
@@ -0,0 +1,105 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/device/public/cpp/compute_pressure/cpu_pressure_converter.h" + +#include "base/rand_util.h" + +namespace device { + +namespace { + +// Delta for the state decision hysteresis. +constexpr double kThresholdDelta = 0.03; + +// |randomization_timer_| boundaries in second. +constexpr uint64_t kMinRandomizationTimeInSeconds = 120; +constexpr uint64_t kMaxRandomizationTimeInSeconds = 240; + +// Thresholds to use with no randomization. +constexpr std::array<double, + static_cast<size_t>(mojom::PressureState::kMaxValue) + 1> + kStateBaseThresholds = {0.6, // kNominal + 0.75, // kFair + 0.9, // kSerious + 1.0}; // kCritical + +// Thresholds to use during randomization. +constexpr std::array<double, + static_cast<size_t>(mojom::PressureState::kMaxValue) + 1> + kStateRandomizedThresholds = {0.5, // kNominal + 0.8, // kFair + 0.85, // kSerious + 1.0}; // kCritical + +} // namespace + +const std::array<double, + static_cast<size_t>(mojom::PressureState::kMaxValue) + 1>& +CpuPressureConverter::state_thresholds() const { + return state_randomization_requested_ ? kStateRandomizedThresholds + : kStateBaseThresholds; +} + +double CpuPressureConverter::hysteresis_threshold_delta() const { + return kThresholdDelta; +} + +void CpuPressureConverter::EnableStateRandomizationMitigation() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + randomization_time_ = base::Seconds(base::RandInt( + kMinRandomizationTimeInSeconds, kMaxRandomizationTimeInSeconds)); + randomization_timer_.Start( + FROM_HERE, randomization_time_, + base::BindRepeating(&CpuPressureConverter::ToggleStateRandomization, + base::Unretained(this))); +} + +void CpuPressureConverter::DisableStateRandomizationMigitation() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + randomization_timer_.Stop(); + state_randomization_requested_ = false; +} + +void CpuPressureConverter::ToggleStateRandomization() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + state_randomization_requested_ = !state_randomization_requested_; + randomization_time_ = base::Seconds(base::RandInt( + kMinRandomizationTimeInSeconds, kMaxRandomizationTimeInSeconds)); + randomization_timer_.Start( + FROM_HERE, randomization_time_, + base::BindRepeating(&CpuPressureConverter::ToggleStateRandomization, + base::Unretained(this))); +} + +mojom::PressureState CpuPressureConverter::CalculateState( + const double cpu_utilization) { + // TODO(crbug.com/40231044): A more advanced algorithm that calculates + // PressureState using PressureSample needs to be determined. + // At this moment the algorithm is the simplest possible + // with thresholds defining the state. + const auto& kStateThresholds = state_randomization_requested_ + ? kStateRandomizedThresholds + : kStateBaseThresholds; + + auto it = std::ranges::lower_bound(kStateThresholds, cpu_utilization); + if (it == kStateThresholds.end()) { + NOTREACHED() << "unexpected value: " << cpu_utilization; + } + + size_t state_index = std::distance(kStateThresholds.begin(), it); + // Hysteresis to avoid flip-flop between state. + // Threshold needs to drop by level and + // cpu_utilization needs a drop of kThresholdDelta below the state + // threshold to be validated as a lower pressure state. + if (last_state_index_ - state_index != 1 || + kStateThresholds[state_index] - cpu_utilization >= kThresholdDelta) { + last_state_index_ = state_index; + } + + return static_cast<mojom::PressureState>(last_state_index_); +} + +} // namespace device
diff --git a/services/device/public/cpp/compute_pressure/cpu_pressure_converter.h b/services/device/public/cpp/compute_pressure/cpu_pressure_converter.h new file mode 100644 index 0000000..4918178 --- /dev/null +++ b/services/device/public/cpp/compute_pressure/cpu_pressure_converter.h
@@ -0,0 +1,68 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_DEVICE_PUBLIC_CPP_COMPUTE_PRESSURE_CPU_PRESSURE_CONVERTER_H_ +#define SERVICES_DEVICE_PUBLIC_CPP_COMPUTE_PRESSURE_CPU_PRESSURE_CONVERTER_H_ + +#include "base/timer/timer.h" +#include "services/device/public/mojom/pressure_update.mojom-shared.h" + +namespace device { + +class CpuPressureConverter final { + public: + CpuPressureConverter() = default; + + CpuPressureConverter(const CpuPressureConverter&) = delete; + CpuPressureConverter& operator=(const CpuPressureConverter&) = delete; + + ~CpuPressureConverter() = default; + + // Returns the current thresholds being used for each mojom::PressureState, + // taking state randomization into account. + const std::array<double, + static_cast<size_t>(mojom::PressureState::kMaxValue) + 1>& + state_thresholds() const; + + // Returns the hysteresis threshold delta value used + // to prevent state flip-flopping. + double hysteresis_threshold_delta() const; + + void EnableStateRandomizationMitigation(); + + void DisableStateRandomizationMigitation(); + + base::TimeDelta GetRandomizationTimeForTesting() const { + return randomization_time_; + } + + // Calculate PressureState based on cpu_utilization. + // The range is between 0.0 and 1.0. + mojom::PressureState CalculateState(const double cpu_utilization); + + private: + // Implements the "break calibration" mitigation by toggling the + // |state_randomization_requested_| flag every |randomization_time_| + // interval. + void ToggleStateRandomization(); + + SEQUENCE_CHECKER(sequence_checker_); + + // Variable storing |randomization_timer_| time. + base::TimeDelta randomization_time_; + + // Drive randomization interval by invoking `ToggleStateRandomization()`. + base::OneShotTimer randomization_timer_ GUARDED_BY_CONTEXT(sequence_checker_); + + // Flag to indicate that state randomization has been requested. + bool state_randomization_requested_ = false; + + // Last state stored as index instead of value. + size_t last_state_index_ = + static_cast<size_t>(mojom::PressureState::kNominal); +}; + +} // namespace device + +#endif // SERVICES_DEVICE_PUBLIC_CPP_COMPUTE_PRESSURE_CPU_PRESSURE_CONVERTER_H_
diff --git a/services/device/public/cpp/compute_pressure/cpu_pressure_converter_unittest.cc b/services/device/public/cpp/compute_pressure/cpu_pressure_converter_unittest.cc new file mode 100644 index 0000000..95c8b0a --- /dev/null +++ b/services/device/public/cpp/compute_pressure/cpu_pressure_converter_unittest.cc
@@ -0,0 +1,175 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/device/public/cpp/compute_pressure/cpu_pressure_converter.h" + +#include "base/sequence_checker.h" +#include "base/test/gtest_util.h" +#include "base/test/task_environment.h" +#include "base/test/test_timeouts.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest-spi.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace device { + +class CpuPressureConverterTest : public ::testing::Test { + public: + CpuPressureConverterTest(const CpuPressureConverterTest&) = delete; + CpuPressureConverterTest& operator=(const CpuPressureConverterTest&) = delete; + + protected: + CpuPressureConverterTest() {} + ~CpuPressureConverterTest() override {} + + base::test::TaskEnvironment task_environment_{ + base::test::TaskEnvironment::TimeSource::MOCK_TIME}; + + CpuPressureConverter converter_; +}; + +TEST_F(CpuPressureConverterTest, CalculateStateValueTooLarge) { + EXPECT_DCHECK_DEATH_WITH(converter_.CalculateState(1.1), + "unexpected value: 1.1"); +} + +TEST_F(CpuPressureConverterTest, CheckCalculateStateHysteresisUp) { + std::array<double, 4> samples = {// kNominal value should be reported. + 0.3, + // kFair value should be reported. + 0.7, + // kSerious value should be reported. + 0.8, + // kCritical value should be reported. + 1.0}; + + std::array<mojom::PressureState, 4> states; + for (size_t i = 0; + i < static_cast<size_t>(mojom::PressureState::kMaxValue) + 1; i++) { + states[i] = converter_.CalculateState(samples[i]); + } + + EXPECT_THAT(states, + ::testing::ElementsAre( + mojom::PressureState{mojom::PressureState::kNominal}, + mojom::PressureState{mojom::PressureState::kFair}, + mojom::PressureState{mojom::PressureState::kSerious}, + mojom::PressureState{mojom::PressureState::kCritical})); +} + +TEST_F(CpuPressureConverterTest, CheckCalculateStateHysteresisDown) { + const size_t samples_count = 4; + std::array<double, samples_count> samples = { + // kCritical value should be reported. + 1.0, + // kSerious value should be reported. + 0.85, + // kFair value should be reported. + 0.70, + // kNominal value should be reported. + 0.55}; + std::array<mojom::PressureState, samples_count> states; + + for (size_t i = 0; i < samples_count; i++) { + states[i] = converter_.CalculateState(samples[i]); + } + + EXPECT_THAT(states, + ::testing::ElementsAre( + mojom::PressureState{mojom::PressureState::kCritical}, + mojom::PressureState{mojom::PressureState::kSerious}, + mojom::PressureState{mojom::PressureState::kFair}, + mojom::PressureState{mojom::PressureState::kNominal})); +} + +TEST_F(CpuPressureConverterTest, CheckCalculateStateHysteresisDownByDelta) { + const size_t samples_count = 4; + std::array<double, samples_count> samples = { + // kCritical value should be reported. + 0.95, + // kCritical value should be reported due to hysteresis. + 0.88, + // kFair value should be reported. + 0.73, + // kNominal value should be reported. + 0.56}; + + std::array<mojom::PressureState, samples_count> states; + for (size_t i = 0; i < samples_count; i++) { + states[i] = converter_.CalculateState(samples[i]); + } + + EXPECT_THAT(states, + ::testing::ElementsAre( + mojom::PressureState{mojom::PressureState::kCritical}, + mojom::PressureState{mojom::PressureState::kCritical}, + mojom::PressureState{mojom::PressureState::kFair}, + mojom::PressureState{mojom::PressureState::kNominal})); +} + +TEST_F(CpuPressureConverterTest, + CheckCalculateStateHysteresisDownByDeltaTwoStates) { + const size_t samples_count = 3; + std::array<double, samples_count> samples = { + // kCritical value should be reported. + 0.95, + // kFair should be reported. + 0.73, + // kFair value should be reported due to hysteresis. + 0.58}; + + std::array<mojom::PressureState, samples_count> states; + for (size_t i = 0; i < samples_count; i++) { + states[i] = converter_.CalculateState(samples[i]); + } + + EXPECT_THAT(states, ::testing::ElementsAre( + mojom::PressureState{mojom::PressureState::kCritical}, + mojom::PressureState{mojom::PressureState::kFair}, + mojom::PressureState{mojom::PressureState::kFair})); +} + +TEST_F(CpuPressureConverterTest, + CheckCalculateStateHysteresisUpByDeltaTwoStates) { + const size_t samples_count = 4; + std::array<double, samples_count> samples = { + // kNominal value should be reported. + 0.6, + // kFair should be reported. + 0.62, + // kSerious value should be reported. + 0.77, + // kCritical value should be reported. + 0.91}; + + std::array<mojom::PressureState, samples_count> states; + for (size_t i = 0; i < samples_count; i++) { + states[i] = converter_.CalculateState(samples[i]); + } + + EXPECT_THAT(states, + ::testing::ElementsAre( + mojom::PressureState{mojom::PressureState::kNominal}, + mojom::PressureState{mojom::PressureState::kFair}, + mojom::PressureState{mojom::PressureState::kSerious}, + mojom::PressureState{mojom::PressureState::kCritical})); +} + +TEST_F(CpuPressureConverterTest, CheckBreakCalibrationMitigation) { + converter_.EnableStateRandomizationMitigation(); + + EXPECT_THAT(converter_.CalculateState(0.86), + mojom::PressureState(mojom::PressureState::kSerious)); + + // First toggling. + task_environment_.FastForwardBy(converter_.GetRandomizationTimeForTesting()); + EXPECT_THAT(converter_.CalculateState(0.86), + mojom::PressureState(mojom::PressureState::kCritical)); + // Second toggling. + task_environment_.FastForwardBy(converter_.GetRandomizationTimeForTesting()); + EXPECT_THAT(converter_.CalculateState(0.86), + mojom::PressureState(mojom::PressureState::kSerious)); +} + +} // namespace device
diff --git a/services/device/public/mojom/pressure_update.mojom b/services/device/public/mojom/pressure_update.mojom index 03d4369..9ea62a2c 100644 --- a/services/device/public/mojom/pressure_update.mojom +++ b/services/device/public/mojom/pressure_update.mojom
@@ -31,6 +31,13 @@ // Represents availability of compute resources. struct PressureUpdate { PressureSource source; - PressureState state; + PressureData data; mojo_base.mojom.TimeTicks timestamp; }; + +// Encapsulate raw pressure data. +struct PressureData { + // global cpu_utilization from probe from 0.0 to 1.0 + double cpu_utilization = 0; + // TODO(crbug.com/402033762): Add ownContributionEstimate +};
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn index 98f6038..35a32bb95 100644 --- a/services/network/BUILD.gn +++ b/services/network/BUILD.gn
@@ -153,6 +153,8 @@ "session_cleanup_cookie_store.h", "shared_dictionary/shared_dictionary_access_checker.cc", "shared_dictionary/shared_dictionary_access_checker.h", + "shared_dictionary/shared_dictionary_cache.cc", + "shared_dictionary/shared_dictionary_cache.h", "shared_dictionary/shared_dictionary_constants.cc", "shared_dictionary/shared_dictionary_constants.h", "shared_dictionary/shared_dictionary_data_pipe_writer.cc",
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc index ff18b7c..f8f2435f 100644 --- a/services/network/public/cpp/features.cc +++ b/services/network/public/cpp/features.cc
@@ -605,4 +605,18 @@ /*name=*/"url_patterns", /*default_value=*/""); +BASE_FEATURE(kSharedDictionaryCache, + "SharedDictionaryCache", + base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE_PARAM(size_t, + kSharedDictionaryCacheSize, + &kSharedDictionaryCache, + /*name=*/"cache_size", + 1); +BASE_FEATURE_PARAM(size_t, + kSharedDictionaryCacheMaxSizeBytes, + &kSharedDictionaryCache, + /*name=*/"max_size", + 1'000'000); + } // namespace network::features
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h index 19eeced..5d996246 100644 --- a/services/network/public/cpp/features.h +++ b/services/network/public/cpp/features.h
@@ -332,6 +332,18 @@ COMPONENT_EXPORT(NETWORK_CPP_FLAGS_AND_SWITCHES) BASE_DECLARE_FEATURE_PARAM(std::string, kPervasiveScriptURLPatterns); +// When enabled, disk-based shared dictionaries will use a memory cache to +// keep frequently used dictionaries in memory. +COMPONENT_EXPORT(NETWORK_CPP_FLAGS_AND_SWITCHES) +BASE_DECLARE_FEATURE(kSharedDictionaryCache); + +COMPONENT_EXPORT(NETWORK_CPP_FLAGS_AND_SWITCHES) +BASE_DECLARE_FEATURE_PARAM(size_t, kSharedDictionaryCacheSize); + +// Maximum size of dictionaries that are allowed to be stored in the cache. +COMPONENT_EXPORT(NETWORK_CPP_FLAGS_AND_SWITCHES) +BASE_DECLARE_FEATURE_PARAM(size_t, kSharedDictionaryCacheMaxSizeBytes); + } // namespace network::features #endif // SERVICES_NETWORK_PUBLIC_CPP_FEATURES_H_
diff --git a/services/network/shared_dictionary/shared_dictionary_cache.cc b/services/network/shared_dictionary/shared_dictionary_cache.cc new file mode 100644 index 0000000..62ac8cc --- /dev/null +++ b/services/network/shared_dictionary/shared_dictionary_cache.cc
@@ -0,0 +1,47 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/shared_dictionary/shared_dictionary_cache.h" + +#include "base/feature_list.h" +#include "base/memory/ref_counted.h" +#include "net/shared_dictionary/shared_dictionary.h" +#include "services/network/public/cpp/features.h" +#include "services/network/public/cpp/request_destination.h" + +namespace network { + +SharedDictionaryCache::SharedDictionaryCache() + : cache_(features::kSharedDictionaryCacheSize.Get()) {} + +SharedDictionaryCache::~SharedDictionaryCache() = default; + +scoped_refptr<net::SharedDictionary> SharedDictionaryCache::Get( + const base::UnguessableToken& cache_key) { + auto it = cache_.Get(cache_key); + if (it != cache_.end()) { + return it->second.get(); + } + return nullptr; +} + +void SharedDictionaryCache::Put( + const base::UnguessableToken& cache_key, + mojom::RequestDestination destination, + scoped_refptr<net::SharedDictionary> dictionary) { + if (base::FeatureList::IsEnabled(features::kSharedDictionaryCache) && + dictionary->size() <= + features::kSharedDictionaryCacheMaxSizeBytes.Get() && + (destination == mojom::RequestDestination::kDocument || + destination == mojom::RequestDestination::kFrame || + destination == mojom::RequestDestination::kIframe)) { + cache_.Put(cache_key, dictionary); + } +} + +void SharedDictionaryCache::Clear() { + cache_.Clear(); +} + +} // namespace network
diff --git a/services/network/shared_dictionary/shared_dictionary_cache.h b/services/network/shared_dictionary/shared_dictionary_cache.h new file mode 100644 index 0000000..04a9b40 --- /dev/null +++ b/services/network/shared_dictionary/shared_dictionary_cache.h
@@ -0,0 +1,51 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_CACHE_H_ +#define SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_CACHE_H_ + +#include "base/component_export.h" +#include "base/containers/lru_cache.h" +#include "base/memory/ref_counted.h" +#include "base/unguessable_token.h" +#include "services/network/public/cpp/request_destination.h" + +namespace net { +class SharedDictionary; +} // namespace net + +namespace network { + +// This class is a ref-counted LRU memory cache for storing SharedDictionary +// instances. This is currently limited to document-like requests which tend to +// be used several times in a session but usually not simultaneously. +// TODO (crbug.com/411711704): Explore options to include non-document +// requests. +class COMPONENT_EXPORT(NETWORK_SERVICE) SharedDictionaryCache + : public base::RefCounted<SharedDictionaryCache> { + public: + SharedDictionaryCache(); + + SharedDictionaryCache(const SharedDictionaryCache&) = delete; + SharedDictionaryCache& operator=(const SharedDictionaryCache&) = delete; + + scoped_refptr<net::SharedDictionary> Get( + const base::UnguessableToken& cache_key); + void Put(const base::UnguessableToken& cache_key, + mojom::RequestDestination destination, + scoped_refptr<net::SharedDictionary> dictionary); + void Clear(); + + protected: + friend class base::RefCounted<SharedDictionaryCache>; + virtual ~SharedDictionaryCache(); + + private: + base::LRUCache<base::UnguessableToken, scoped_refptr<net::SharedDictionary>> + cache_; +}; + +} // namespace network + +#endif // SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_CACHE_H_
diff --git a/services/network/shared_dictionary/shared_dictionary_manager_on_disk.cc b/services/network/shared_dictionary/shared_dictionary_manager_on_disk.cc index 65fb0afd..8c0668a 100644 --- a/services/network/shared_dictionary/shared_dictionary_manager_on_disk.cc +++ b/services/network/shared_dictionary/shared_dictionary_manager_on_disk.cc
@@ -18,6 +18,7 @@ #include "net/disk_cache/disk_cache.h" #include "services/network/public/cpp/network_switches.h" #include "services/network/public/cpp/request_destination.h" +#include "services/network/shared_dictionary/shared_dictionary_cache.h" #include "services/network/shared_dictionary/shared_dictionary_storage_on_disk.h" #include "services/network/shared_dictionary/simple_url_pattern_matcher.h" @@ -490,6 +491,11 @@ cleanup_task_disabled_for_testing_( base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableSharedDictionaryStorageCleanupForTesting)) { + dictionary_cache_ = base::MakeRefCounted<SharedDictionaryCache>(); + memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>( + FROM_HERE, + base::BindRepeating(&SharedDictionaryManagerOnDisk::OnMemoryPressure, + weak_factory_.GetWeakPtr())); disk_cache_.Initialize(cache_directory_path, #if BUILDFLAG(IS_ANDROID) app_status_listener_getter, @@ -510,7 +516,8 @@ weak_factory_.GetWeakPtr(), isolation_key, base::ScopedClosureRunner( base::BindOnce(&SharedDictionaryManager::OnStorageDeleted, - GetWeakPtr(), isolation_key))); + GetWeakPtr(), isolation_key)), + dictionary_cache_); } void SharedDictionaryManagerOnDisk::SetCacheMaxSize(uint64_t cache_max_size) { @@ -806,4 +813,11 @@ weak_factory_.GetWeakPtr()))); } +void SharedDictionaryManagerOnDisk::OnMemoryPressure( + base::MemoryPressureListener::MemoryPressureLevel level) { + if (level != base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) { + dictionary_cache_->Clear(); + } +} + } // namespace network
diff --git a/services/network/shared_dictionary/shared_dictionary_manager_on_disk.h b/services/network/shared_dictionary/shared_dictionary_manager_on_disk.h index aa831ed..523e433 100644 --- a/services/network/shared_dictionary/shared_dictionary_manager_on_disk.h +++ b/services/network/shared_dictionary/shared_dictionary_manager_on_disk.h
@@ -36,6 +36,7 @@ enum class RequestDestination : int32_t; } // namespace mojom +class SharedDictionaryCache; class SharedDictionaryStorage; // A SharedDictionaryManager which persists dictionary information on disk. @@ -172,12 +173,16 @@ return writing_disk_cache_key_tokens_; } + void OnMemoryPressure( + base::MemoryPressureListener::MemoryPressureLevel level); + uint64_t cache_max_size() const { return cache_max_size_; } uint64_t cache_max_count() const { return cache_max_count_; } uint64_t cache_max_size_; const uint64_t cache_max_count_; SharedDictionaryDiskCache disk_cache_; + scoped_refptr<SharedDictionaryCache> dictionary_cache_; net::SQLitePersistentSharedDictionaryStore metadata_store_; std::unique_ptr<SerializedTask> running_serialized_task_; @@ -190,6 +195,7 @@ bool expired_entry_deletion_task_queued_ = false; bool cleanup_task_disabled_for_testing_ = false; + std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_; base::WeakPtrFactory<SharedDictionaryManagerOnDisk> weak_factory_{this}; };
diff --git a/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc b/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc index ec146ea..49d677a 100644 --- a/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc +++ b/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc
@@ -15,6 +15,7 @@ #include "base/strings/stringprintf.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/test/test_file_util.h" #include "base/time/time.h" @@ -276,6 +277,9 @@ }; TEST_F(SharedDictionaryManagerOnDiskTest, ReusingRefCountedSharedDictionary) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(features::kSharedDictionaryCache); + base::HistogramTester histogram_tester; std::unique_ptr<SharedDictionaryManager> manager = CreateSharedDictionaryManager(); net::SharedDictionaryIsolationKey isolation_key(url::Origin::Create(kUrl), @@ -292,7 +296,7 @@ // Check the returned dictionary from GetDictionarySync(). scoped_refptr<net::SharedDictionary> dict1 = storage->GetDictionarySync(GURL("https://origin.test/testfile?1"), - mojom::RequestDestination::kEmpty); + mojom::RequestDestination::kDocument); ASSERT_TRUE(dict1); { base::RunLoop run_loop; @@ -305,7 +309,7 @@ } scoped_refptr<net::SharedDictionary> dict2 = storage->GetDictionarySync(GURL("https://origin.test/testfile?2"), - mojom::RequestDestination::kEmpty); + mojom::RequestDestination::kDocument); ASSERT_TRUE(dict2); // `dict2` shares the same RefCountedSharedDictionary with `dict1`. So // ReadAll() must synchronously return OK. @@ -318,6 +322,198 @@ EXPECT_EQ(kTestData1, std::string(reinterpret_cast<const char*>(dict1->data()->data()), dict1->size())); + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Network.SharedDictionary.DocumentRequestCacheResult"), + testing::ElementsAre( + base::Bucket( + static_cast<int>( + SharedDictionaryStorageOnDisk::CacheResult::kCacheMiss), + 1), + base::Bucket( + static_cast<int>( + SharedDictionaryStorageOnDisk::CacheResult::kCacheHitActive), + 1))); +} + +TEST_F(SharedDictionaryManagerOnDiskTest, + ReusingRefCountedSharedDictionaryWithLRU) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kSharedDictionaryCache); + base::HistogramTester histogram_tester; + std::unique_ptr<SharedDictionaryManager> manager = + CreateSharedDictionaryManager(); + net::SharedDictionaryIsolationKey isolation_key(url::Origin::Create(kUrl), + kSite); + scoped_refptr<SharedDictionaryStorage> storage = + manager->GetStorage(isolation_key); + ASSERT_TRUE(storage); + + WriteDictionary(storage.get(), GURL("https://origin.test/dict"), "testfile*", + kTestData1); + WriteDictionary(storage.get(), GURL("https://origin.test/dict"), + "othertestfile*", kTestData1); + + FlushCacheTasks(); + + // Check the returned dictionary from GetDictionarySync(). + scoped_refptr<net::SharedDictionary> dict1 = + storage->GetDictionarySync(GURL("https://origin.test/testfile?1"), + mojom::RequestDestination::kDocument); + ASSERT_TRUE(dict1); + { + base::RunLoop run_loop; + EXPECT_EQ(net::ERR_IO_PENDING, + dict1->ReadAll(base::BindLambdaForTesting([&](int rv) { + EXPECT_EQ(net::OK, rv); + run_loop.Quit(); + }))); + run_loop.Run(); + } + // Request a second dictionary to push the first one out of the LRU cache + // so it will fall back to the ref-counted cache. + scoped_refptr<net::SharedDictionary> unused_dict = + storage->GetDictionarySync(GURL("https://origin.test/othertestfile?1"), + mojom::RequestDestination::kDocument); + scoped_refptr<net::SharedDictionary> dict2 = + storage->GetDictionarySync(GURL("https://origin.test/testfile?2"), + mojom::RequestDestination::kDocument); + ASSERT_TRUE(dict2); + // `dict2` shares the same RefCountedSharedDictionary with `dict1`. So + // ReadAll() must synchronously return OK. + EXPECT_EQ(net::OK, dict2->ReadAll(base::BindLambdaForTesting( + [&](int rv) { NOTREACHED(); }))); + // `dict2` shares the same IOBuffer with `dict1`. + EXPECT_EQ(dict1->data(), dict2->data()); + EXPECT_EQ(dict1->size(), dict2->size()); + EXPECT_EQ(dict1->hash(), dict2->hash()); + EXPECT_EQ(kTestData1, + std::string(reinterpret_cast<const char*>(dict1->data()->data()), + dict1->size())); + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Network.SharedDictionary.DocumentRequestCacheResult"), + testing::ElementsAre( + base::Bucket( + static_cast<int>( + SharedDictionaryStorageOnDisk::CacheResult::kCacheMiss), + 2), + base::Bucket( + static_cast<int>( + SharedDictionaryStorageOnDisk::CacheResult::kCacheHitActive), + 1))); +} + +TEST_F(SharedDictionaryManagerOnDiskTest, DeletingRefCountedSharedDictionary) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(features::kSharedDictionaryCache); + base::HistogramTester histogram_tester; + std::unique_ptr<SharedDictionaryManager> manager = + CreateSharedDictionaryManager(); + net::SharedDictionaryIsolationKey isolation_key(url::Origin::Create(kUrl), + kSite); + scoped_refptr<SharedDictionaryStorage> storage = + manager->GetStorage(isolation_key); + ASSERT_TRUE(storage); + + WriteDictionary(storage.get(), GURL("https://origin.test/dict"), "testfile*", + kTestData1); + + FlushCacheTasks(); + + // dict1 should be released when it goes out of scope which should trigger + // the removal of the underlying cached RefCountedSharedDictionary. + { + scoped_refptr<net::SharedDictionary> dict1 = + storage->GetDictionarySync(GURL("https://origin.test/testfile?1"), + mojom::RequestDestination::kDocument); + ASSERT_TRUE(dict1); + { + base::RunLoop run_loop; + EXPECT_EQ(net::ERR_IO_PENDING, + dict1->ReadAll(base::BindLambdaForTesting([&](int rv) { + EXPECT_EQ(net::OK, rv); + run_loop.Quit(); + }))); + run_loop.Run(); + } + } + scoped_refptr<net::SharedDictionary> dict2 = + storage->GetDictionarySync(GURL("https://origin.test/testfile?2"), + mojom::RequestDestination::kDocument); + ASSERT_TRUE(dict2); + EXPECT_THAT(histogram_tester.GetAllSamples( + "Network.SharedDictionary.DocumentRequestCacheResult"), + testing::ElementsAre(base::Bucket( + static_cast<int>( + SharedDictionaryStorageOnDisk::CacheResult::kCacheMiss), + 2))); + // `dict2` should not share the same RefCountedSharedDictionary with `dict1`. + // So ReadAll() must synchronously return ERR_IO_PENDING. + EXPECT_EQ(net::ERR_IO_PENDING, dict2->ReadAll(base::BindLambdaForTesting( + [&](int rv) { NOTREACHED(); }))); + EXPECT_THAT(histogram_tester.GetAllSamples( + "Network.SharedDictionary.DocumentRequestCacheResult"), + testing::ElementsAre(base::Bucket( + static_cast<int>( + SharedDictionaryStorageOnDisk::CacheResult::kCacheMiss), + 2))); +} + +TEST_F(SharedDictionaryManagerOnDiskTest, ReusingLRUCachedSharedDictionary) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kSharedDictionaryCache); + base::HistogramTester histogram_tester; + std::unique_ptr<SharedDictionaryManager> manager = + CreateSharedDictionaryManager(); + net::SharedDictionaryIsolationKey isolation_key(url::Origin::Create(kUrl), + kSite); + scoped_refptr<SharedDictionaryStorage> storage = + manager->GetStorage(isolation_key); + ASSERT_TRUE(storage); + + WriteDictionary(storage.get(), GURL("https://origin.test/dict"), "testfile*", + kTestData1); + + FlushCacheTasks(); + + // dict1 should not be released when it goes out of scope since it will also + // be kept in the LRU cache for document requests. + { + scoped_refptr<net::SharedDictionary> dict1 = + storage->GetDictionarySync(GURL("https://origin.test/testfile?1"), + mojom::RequestDestination::kDocument); + ASSERT_TRUE(dict1); + { + base::RunLoop run_loop; + EXPECT_EQ(net::ERR_IO_PENDING, + dict1->ReadAll(base::BindLambdaForTesting([&](int rv) { + EXPECT_EQ(net::OK, rv); + run_loop.Quit(); + }))); + run_loop.Run(); + } + } + scoped_refptr<net::SharedDictionary> dict2 = + storage->GetDictionarySync(GURL("https://origin.test/testfile?2"), + mojom::RequestDestination::kDocument); + ASSERT_TRUE(dict2); + // `dict2` should share the same RefCountedSharedDictionary with `dict1`. + // So ReadAll() must synchronously return OK. + EXPECT_EQ(net::OK, dict2->ReadAll(base::BindLambdaForTesting( + [&](int rv) { NOTREACHED(); }))); + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Network.SharedDictionary.DocumentRequestCacheResult"), + testing::ElementsAre( + base::Bucket( + static_cast<int>( + SharedDictionaryStorageOnDisk::CacheResult::kCacheMiss), + 1), + base::Bucket( + static_cast<int>( + SharedDictionaryStorageOnDisk::CacheResult::kCacheHitLRU), + 1))); } TEST_F(SharedDictionaryManagerOnDiskTest,
diff --git a/services/network/shared_dictionary/shared_dictionary_storage_on_disk.cc b/services/network/shared_dictionary/shared_dictionary_storage_on_disk.cc index f8972888..abae881a 100644 --- a/services/network/shared_dictionary/shared_dictionary_storage_on_disk.cc +++ b/services/network/shared_dictionary/shared_dictionary_storage_on_disk.cc
@@ -20,6 +20,7 @@ #include "net/base/io_buffer.h" #include "services/network/public/cpp/request_destination.h" #include "services/network/public/mojom/shared_dictionary_error.mojom.h" +#include "services/network/shared_dictionary/shared_dictionary_cache.h" #include "services/network/shared_dictionary/shared_dictionary_manager_on_disk.h" #include "services/network/shared_dictionary/shared_dictionary_on_disk.h" #include "services/network/shared_dictionary/shared_dictionary_writer_on_disk.h" @@ -28,6 +29,9 @@ namespace network { +constexpr char kCacheResultHistogramName[] = + "Network.SharedDictionary.DocumentRequestCacheResult"; + namespace { void RecordMetadataReadTimeMetrics( @@ -84,10 +88,16 @@ SharedDictionaryStorageOnDisk::SharedDictionaryStorageOnDisk( base::WeakPtr<SharedDictionaryManagerOnDisk> manager, const net::SharedDictionaryIsolationKey& isolation_key, - base::ScopedClosureRunner on_deleted_closure_runner) + base::ScopedClosureRunner on_deleted_closure_runner, + scoped_refptr<SharedDictionaryCache> dictionary_cache) : manager_(manager), isolation_key_(isolation_key), - on_deleted_closure_runner_(std::move(on_deleted_closure_runner)) { + on_deleted_closure_runner_(std::move(on_deleted_closure_runner)), + dictionary_cache_(dictionary_cache) { + memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>( + FROM_HERE, + base::BindRepeating(&SharedDictionaryStorageOnDisk::OnMemoryPressure, + weak_factory_.GetWeakPtr())); manager_->metadata_store().GetDictionaries( isolation_key_, base::BindOnce( @@ -133,13 +143,36 @@ manager_->UpdateDictionaryLastUsedTime(*info); + // Use the LRU cache before the active-dictionary cache so that the + // recentness of the hit will be counted for currently-active dictionaries. + scoped_refptr<net::SharedDictionary> dictionary = + dictionary_cache_->Get(info->disk_cache_key_token()); + if (dictionary) { + CHECK_EQ(info->size(), dictionary->size()); + CHECK(info->hash() == dictionary->hash()); + if (destination == mojom::RequestDestination::kDocument) { + base::UmaHistogramEnumeration(kCacheResultHistogramName, + CacheResult::kCacheHitLRU); + } + return dictionary; + } + auto it = dictionaries_.find(info->disk_cache_key_token()); if (it != dictionaries_.end()) { CHECK_EQ(info->size(), it->second->size()); CHECK(info->hash() == it->second->hash()); + if (destination == mojom::RequestDestination::kDocument) { + base::UmaHistogramEnumeration(kCacheResultHistogramName, + CacheResult::kCacheHitActive); + } return it->second.get(); } + if (destination == mojom::RequestDestination::kDocument) { + base::UmaHistogramEnumeration(kCacheResultHistogramName, + CacheResult::kCacheMiss); + } + auto shared_dictionary = base::MakeRefCounted<SharedDictionaryOnDisk>( info->size(), info->hash(), info->id(), info->disk_cache_key_token(), manager_->disk_cache(), @@ -150,6 +183,13 @@ &SharedDictionaryStorageOnDisk::OnSharedDictionaryDeleted, weak_factory_.GetWeakPtr(), info->disk_cache_key_token()))); dictionaries_.emplace(info->disk_cache_key_token(), shared_dictionary.get()); + + if (memory_pressure_level_ == + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) { + dictionary_cache_->Put(info->disk_cache_key_token(), destination, + shared_dictionary); + } + return shared_dictionary; } @@ -272,4 +312,9 @@ [](const auto& it) { return it.second.empty(); }); } +void SharedDictionaryStorageOnDisk::OnMemoryPressure( + base::MemoryPressureListener::MemoryPressureLevel level) { + memory_pressure_level_ = level; +} + } // namespace network
diff --git a/services/network/shared_dictionary/shared_dictionary_storage_on_disk.h b/services/network/shared_dictionary/shared_dictionary_storage_on_disk.h index c2e2e26..ee520f9 100644 --- a/services/network/shared_dictionary/shared_dictionary_storage_on_disk.h +++ b/services/network/shared_dictionary/shared_dictionary_storage_on_disk.h
@@ -12,6 +12,7 @@ #include "base/containers/unique_ptr_adapters.h" #include "base/functional/callback.h" #include "base/functional/callback_helpers.h" +#include "base/memory/memory_pressure_listener.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -28,6 +29,7 @@ namespace network { +class SharedDictionaryCache; class SharedDictionaryManagerOnDisk; class SimpleUrlPatternMatcher; @@ -54,10 +56,20 @@ std::set<mojom::RequestDestination> match_dest_; }; + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + enum class CacheResult { + kCacheMiss = 0, + kCacheHitLRU = 1, + kCacheHitActive = 2, + kMaxValue = kCacheHitActive, + }; + SharedDictionaryStorageOnDisk( base::WeakPtr<SharedDictionaryManagerOnDisk> manager, const net::SharedDictionaryIsolationKey& isolation_key, - base::ScopedClosureRunner on_deleted_closure_runner); + base::ScopedClosureRunner on_deleted_closure_runner, + scoped_refptr<SharedDictionaryCache> dictionary_cache); SharedDictionaryStorageOnDisk(const SharedDictionaryStorageOnDisk&) = delete; SharedDictionaryStorageOnDisk& operator=( @@ -110,6 +122,9 @@ void OnSharedDictionaryDeleted( const base::UnguessableToken& disk_cache_key_token); + void OnMemoryPressure( + base::MemoryPressureListener::MemoryPressureLevel level); + const std::map< url::SchemeHostPort, std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>, @@ -127,9 +142,14 @@ WrappedDictionaryInfo>> dictionary_info_map_; + scoped_refptr<SharedDictionaryCache> dictionary_cache_; std::map<base::UnguessableToken, raw_ptr<net::SharedDictionary>> dictionaries_; + std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_; + base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level_ = + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; + bool get_dictionary_called_ = false; bool is_metadata_ready_ = false;
diff --git a/services/viz/public/mojom/compositing/layer.mojom b/services/viz/public/mojom/compositing/layer.mojom index 5dfb257..0857b2ff 100644 --- a/services/viz/public/mojom/compositing/layer.mojom +++ b/services/viz/public/mojom/compositing/layer.mojom
@@ -279,6 +279,11 @@ // cc::DamageReasonsSet bit mask tracking the damage reasons for changes to // this node. uint64 damage_reasons_bit_mask; + + // Used by the compositor to determine which layers need to be repositioned by + // the compositor as a result of safe area inset bottom before Blink + // repositions the fixed layers. + bool moved_by_safe_area_bottom; }; // Details about a new or updated node within a clip property tree.
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle index 17d7c9e6..780e93ab 100644 --- a/third_party/androidx/build.gradle +++ b/third_party/androidx/build.gradle
@@ -304,7 +304,7 @@ google() maven { // This URL is generated by the fetch_all_androidx.py script. - url 'https://androidx.dev/snapshots/builds/13474078/artifacts/repository' + url 'https://androidx.dev/snapshots/builds/13478656/artifacts/repository' } mavenCentral() }
diff --git a/third_party/angle b/third_party/angle index db33baf..8aa2925 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit db33baf4eb0d7954f0110cddc30acb9cdc12e2d4 +Subproject commit 8aa29250983893ebc940d0285f6d5fa2199fc63a
diff --git a/third_party/blink/common/BUILD.gn b/third_party/blink/common/BUILD.gn index 4a5ab36..231cdbd 100644 --- a/third_party/blink/common/BUILD.gn +++ b/third_party/blink/common/BUILD.gn
@@ -267,6 +267,7 @@ "use_counter/use_counter_feature.cc", "use_counter/use_counter_feature_tracker.cc", "user_agent/user_agent_metadata.cc", + "view_source/rendering_preferences.cc", "web_package/signed_exchange_consts.cc", "web_package/web_package_request_matcher.cc", "web_preferences/web_preferences.cc",
diff --git a/third_party/blink/common/renderer_preferences/renderer_preferences_mojom_traits.cc b/third_party/blink/common/renderer_preferences/renderer_preferences_mojom_traits.cc index 5e233d6..c13dfd7 100644 --- a/third_party/blink/common/renderer_preferences/renderer_preferences_mojom_traits.cc +++ b/third_party/blink/common/renderer_preferences/renderer_preferences_mojom_traits.cc
@@ -130,6 +130,8 @@ out->canvas_noise_token = data.canvas_noise_token(); + out->view_source_line_wrap_enabled = data.view_source_line_wrap_enabled(); + return true; }
diff --git a/third_party/blink/common/view_source/rendering_preferences.cc b/third_party/blink/common/view_source/rendering_preferences.cc new file mode 100644 index 0000000..d06fb211 --- /dev/null +++ b/third_party/blink/common/view_source/rendering_preferences.cc
@@ -0,0 +1,23 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/public/common/view_source/rendering_preferences.h" + +namespace blink { + +namespace { +bool preference = false; +} // namespace + +// static +void ViewSourceLineWrappingPreference::Set(bool value) { + preference = value; +} + +// static +bool ViewSourceLineWrappingPreference::Get() { + return preference; +} + +} // namespace blink
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn index 8c84566..bd4191586 100644 --- a/third_party/blink/public/common/BUILD.gn +++ b/third_party/blink/public/common/BUILD.gn
@@ -303,6 +303,7 @@ "use_counter/use_counter_feature_tracker.h", "user_agent/user_agent_brand_version_type.h", "user_agent/user_agent_metadata.h", + "view_source/rendering_preferences.h", "web_cache/web_cache_resource_type_stats.h", "web_package/signed_exchange_consts.h", "web_package/web_package_request_matcher.h",
diff --git a/third_party/blink/public/common/renderer_preferences/renderer_preferences.h b/third_party/blink/public/common/renderer_preferences/renderer_preferences.h index ff84a20..75acd69 100644 --- a/third_party/blink/public/common/renderer_preferences/renderer_preferences.h +++ b/third_party/blink/public/common/renderer_preferences/renderer_preferences.h
@@ -92,6 +92,9 @@ bool uses_platform_autofill{false}; std::vector<uint16_t> explicitly_allowed_network_ports; uint64_t canvas_noise_token{0}; + // The default value must be false to avoid performance problems on very large + // source pages. + bool view_source_line_wrap_enabled{false}; RendererPreferences(); RendererPreferences(const RendererPreferences& other);
diff --git a/third_party/blink/public/common/renderer_preferences/renderer_preferences_mojom_traits.h b/third_party/blink/public/common/renderer_preferences/renderer_preferences_mojom_traits.h index c88ddaf..defe40d 100644 --- a/third_party/blink/public/common/renderer_preferences/renderer_preferences_mojom_traits.h +++ b/third_party/blink/public/common/renderer_preferences/renderer_preferences_mojom_traits.h
@@ -280,6 +280,11 @@ return data.canvas_noise_token; } + static bool view_source_line_wrap_enabled( + const ::blink::RendererPreferences& data) { + return data.view_source_line_wrap_enabled; + } + static bool Read(blink::mojom::RendererPreferencesDataView, ::blink::RendererPreferences* out); };
diff --git a/third_party/blink/public/common/view_source/rendering_preferences.h b/third_party/blink/public/common/view_source/rendering_preferences.h new file mode 100644 index 0000000..809e7a29 --- /dev/null +++ b/third_party/blink/public/common/view_source/rendering_preferences.h
@@ -0,0 +1,21 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_VIEW_SOURCE_RENDERING_PREFERENCES_H_ +#define THIRD_PARTY_BLINK_PUBLIC_COMMON_VIEW_SOURCE_RENDERING_PREFERENCES_H_ + +#include "third_party/blink/public/common/common_export.h" + +namespace blink { + +// A static class that stores a per-renderer process line wrapping preference +// for view source pages, as sent by the browser. +class BLINK_COMMON_EXPORT ViewSourceLineWrappingPreference final { + public: + static void Set(bool value); + static bool Get(); +}; +} // namespace blink + +#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_VIEW_SOURCE_RENDERING_PREFERENCES_H_
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn index 0ed3524..012809d6f 100644 --- a/third_party/blink/public/mojom/BUILD.gn +++ b/third_party/blink/public/mojom/BUILD.gn
@@ -57,6 +57,7 @@ "close_watcher/close_listener.mojom", "commit_result/commit_result.mojom", "compute_pressure/web_pressure_manager.mojom", + "compute_pressure/web_pressure_update.mojom", "confidence_level.mojom", "content_extraction/ai_page_content.mojom", "content_extraction/inner_html.mojom", @@ -186,6 +187,7 @@ "permissions_policy/document_policy_feature.mojom", "permissions_policy/policy_disposition.mojom", "permissions_policy/policy_value.mojom", + "persistent_renderer_prefs.mojom", "picture_in_picture/picture_in_picture.mojom", "picture_in_picture_window_options/picture_in_picture_window_options.mojom", "plugins/plugin_registry.mojom",
diff --git a/third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom b/third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom index cdc791d..5c073a68 100644 --- a/third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom +++ b/third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom
@@ -6,13 +6,27 @@ import "services/device/public/mojom/pressure_manager.mojom"; import "services/device/public/mojom/pressure_update.mojom"; +import "third_party/blink/public/mojom/compute_pressure/web_pressure_update.mojom"; -// Partial view into the device.mojom.PressureManager Mojo interface. +// PressureObserverManager in Blink uses this interface to make a +// PressureClient subscribe to notification about OnPressureUpdated. +// It is a partial view into the device.mojom.PressureManager Mojo interface. // This interface does not expose the privileged automation-related methods // that the device.mojom version does. interface WebPressureManager { // See PressureManager.AddClient()'s documentation for more details. AddClient(device.mojom.PressureSource source, - pending_associated_remote<device.mojom.PressureClient> client) => + pending_associated_remote<blink.mojom.WebPressureClient> client) => (device.mojom.PressureManagerAddClientResult result); }; + +// Interface that client of the PressureManager interface must +// implement to receive PressureUpdate. +// +// This interface is implemented by PressureObserverManager in Blink. +// PressureManagerImpl uses this interface to deliver PressureUpdate to +// its client. +interface WebPressureClient { + // Interface used to deliver PressureUpdate. + OnPressureUpdated(WebPressureUpdate update); +};
diff --git a/third_party/blink/public/mojom/compute_pressure/web_pressure_update.mojom b/third_party/blink/public/mojom/compute_pressure/web_pressure_update.mojom new file mode 100644 index 0000000..4f6ffa95 --- /dev/null +++ b/third_party/blink/public/mojom/compute_pressure/web_pressure_update.mojom
@@ -0,0 +1,17 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module blink.mojom; + +import "mojo/public/mojom/base/time.mojom"; +import "services/device/public/mojom/pressure_update.mojom"; + +// This version of device.mojom.PressureUpdate Mojo interface only provides +// values required by Blink that can be exposed to a potentially compromised +// renderer process. +struct WebPressureUpdate { + device.mojom.PressureSource source; + device.mojom.PressureState state; + mojo_base.mojom.TimeTicks timestamp; +};
diff --git a/third_party/blink/public/mojom/persistent_renderer_prefs.mojom b/third_party/blink/public/mojom/persistent_renderer_prefs.mojom new file mode 100644 index 0000000..647c83a --- /dev/null +++ b/third_party/blink/public/mojom/persistent_renderer_prefs.mojom
@@ -0,0 +1,15 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module blink.mojom; + +// Interface for notifying the browser about changes to renderer +// preferences. Please only expose new preferences after carefully +// considering if it would be problematic if these preferences were to be +// modified by a compromised renderer process. +interface PersistentRendererPrefsService { + // Asks the browser process to remember the current line wrapping + // preference. + SetViewSourceLineWrapping(bool value); +};
diff --git a/third_party/blink/public/mojom/renderer_preferences.mojom b/third_party/blink/public/mojom/renderer_preferences.mojom index 65766b9..f8361faf6 100644 --- a/third_party/blink/public/mojom/renderer_preferences.mojom +++ b/third_party/blink/public/mojom/renderer_preferences.mojom
@@ -205,4 +205,7 @@ // A randomized 64 bit token that is generated per browser session, // used for canvas noising. uint64 canvas_noise_token = 0; + + // Whether line wrapping should be enabled by default in view source pages. + bool view_source_line_wrap_enabled = false; };
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom index 6d828c85..a9f2141 100644 --- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom +++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -4869,6 +4869,8 @@ kProofreader_Proofread = 5565, kProofreader_Availability = 5566, kProofreader_Create = 5567, + kDataUrlDedicatedWorker = 5568, + kDataUrlSharedWorker = 5569, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots. Also don't add extra
diff --git a/third_party/blink/renderer/core/animation/css_percentage_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_percentage_interpolation_type.cc index ceab5a7e8..dc1be7d 100644 --- a/third_party/blink/renderer/core/animation/css_percentage_interpolation_type.cc +++ b/third_party/blink/renderer/core/animation/css_percentage_interpolation_type.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/core/animation/css_percentage_interpolation_type.h" #include "third_party/blink/renderer/core/animation/number_property_functions.h" +#include "third_party/blink/renderer/core/animation/tree_counting_checker.h" #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h" #include "third_party/blink/renderer/core/css/resolver/style_builder.h" #include "third_party/blink/renderer/core/css/resolver/style_resolver.h" @@ -84,15 +85,16 @@ InterpolationValue CSSPercentageInterpolationType::MaybeConvertValue( const CSSValue& value, const StyleResolverState& state, - ConversionCheckers&) const { + ConversionCheckers& conversion_checkers) const { const auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value); if (!primitive_value || !primitive_value->IsPercentage()) { return nullptr; } - // TODO(crbug.com/415626999): Create a TreeCountingChecker for sibling-index() - // and sibling-count() if necessary. // TODO(crbug.com/415572412): Create a LengthUnitsChecker for relative units // if necessary. + if (primitive_value->IsElementDependent()) { + conversion_checkers.push_back(TreeCountingChecker::Create(state)); + } return CreatePercentageValue( primitive_value->ComputePercentage(state.CssToLengthConversionData())); }
diff --git a/third_party/blink/renderer/core/css/container_query_evaluator.cc b/third_party/blink/renderer/core/css/container_query_evaluator.cc index 767e185..692bd21 100644 --- a/third_party/blink/renderer/core/css/container_query_evaluator.cc +++ b/third_party/blink/renderer/core/css/container_query_evaluator.cc
@@ -850,21 +850,16 @@ const ComputedStyle& new_style, bool style_changed) { StyleRecalcChange recalc_change = child_change; - if (RuntimeEnabledFeatures::CSSStickyContainerQueriesEnabled() || - RuntimeEnabledFeatures::CSSSnapContainerQueriesEnabled() || - RuntimeEnabledFeatures::CSSScrollableContainerQueriesEnabled() || - RuntimeEnabledFeatures::CSSScrollDirectionContainerQueriesEnabled()) { - switch (ApplyScrollState()) { - case ContainerQueryEvaluator::Change::kNone: - break; - case ContainerQueryEvaluator::Change::kNearestContainer: - recalc_change = recalc_change.ForceRecalcScrollStateContainer(); - break; - case ContainerQueryEvaluator::Change::kDescendantContainers: - recalc_change = - recalc_change.ForceRecalcDescendantScrollStateContainers(); - break; - } + switch (ApplyScrollState()) { + case ContainerQueryEvaluator::Change::kNone: + break; + case ContainerQueryEvaluator::Change::kNearestContainer: + recalc_change = recalc_change.ForceRecalcScrollStateContainer(); + break; + case ContainerQueryEvaluator::Change::kDescendantContainers: + recalc_change = + recalc_change.ForceRecalcDescendantScrollStateContainers(); + break; } if (!style_changed) { @@ -906,21 +901,16 @@ } } if (invalidate_for_writing_direction) { - if (RuntimeEnabledFeatures::CSSStickyContainerQueriesEnabled() || - RuntimeEnabledFeatures::CSSSnapContainerQueriesEnabled() || - RuntimeEnabledFeatures::CSSScrollableContainerQueriesEnabled() || - RuntimeEnabledFeatures::CSSScrollDirectionContainerQueriesEnabled()) { - switch (StyleAffectingScrollStateChanged()) { - case ContainerQueryEvaluator::Change::kNone: - break; - case ContainerQueryEvaluator::Change::kNearestContainer: - recalc_change = recalc_change.ForceRecalcScrollStateContainer(); - break; - case ContainerQueryEvaluator::Change::kDescendantContainers: - recalc_change = - recalc_change.ForceRecalcDescendantScrollStateContainers(); - break; - } + switch (StyleAffectingScrollStateChanged()) { + case ContainerQueryEvaluator::Change::kNone: + break; + case ContainerQueryEvaluator::Change::kNearestContainer: + recalc_change = recalc_change.ForceRecalcScrollStateContainer(); + break; + case ContainerQueryEvaluator::Change::kDescendantContainers: + recalc_change = + recalc_change.ForceRecalcDescendantScrollStateContainers(); + break; } } if (!base::ValuesEquivalent(old_style.InheritedVariables(),
diff --git a/third_party/blink/renderer/core/css/css_image_value.cc b/third_party/blink/renderer/core/css/css_image_value.cc index 5fc264f7..0e4815bb 100644 --- a/third_party/blink/renderer/core/css/css_image_value.cc +++ b/third_party/blink/renderer/core/css/css_image_value.cc
@@ -167,13 +167,6 @@ return UrlData().IsLocal(document); } -CSSImageValue* CSSImageValue::ComputedCSSValueMaybeLocal() const { - if (UrlData().UnresolvedUrl().StartsWith('#')) { - return Clone(); - } - return ComputedCSSValue(); -} - AtomicString CSSImageValue::NormalizedFragmentIdentifier() const { // Always use KURL's FragmentIdentifier to ensure that we're handling the // fragment in a consistent manner.
diff --git a/third_party/blink/renderer/core/css/css_image_value.h b/third_party/blink/renderer/core/css/css_image_value.h index 41fa958b..d2188598f 100644 --- a/third_party/blink/renderer/core/css/css_image_value.h +++ b/third_party/blink/renderer/core/css/css_image_value.h
@@ -68,10 +68,9 @@ bool Equals(const CSSImageValue&) const; CSSImageValue* ComputedCSSValue() const { - return MakeGarbageCollected<CSSImageValue>(*UrlData().MakeAbsolute(), + return MakeGarbageCollected<CSSImageValue>(*UrlData().MakeComputed(), cached_image_.Get()); } - CSSImageValue* ComputedCSSValueMaybeLocal() const; CSSImageValue* Clone() const { return MakeGarbageCollected<CSSImageValue>(*UrlData().MakeWithoutReferrer(),
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5 index cc8657b..9836a4b 100644 --- a/third_party/blink/renderer/core/css/css_properties.json5 +++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -4468,35 +4468,19 @@ name: "overflow", resolver: "inline", }, - runtime_flag: "CSSLogicalOverflow", // See comment on overflow-x. supports_incremental_style: false, }, { - name: "-internal-overflow-inline", - logical_property_group: { - name: "overflow", - resolver: "inline", - }, - }, - { name: "overflow-block", logical_property_group: { name: "overflow", resolver: "block", }, - runtime_flag: "CSSLogicalOverflow", // See comment on overflow-x. supports_incremental_style: false, }, { - name: "-internal-overflow-block", - logical_property_group: { - name: "overflow", - resolver: "block", - }, - }, - { name: "overflow-clip-margin", property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"], field_template: "external",
diff --git a/third_party/blink/renderer/core/css/css_property_equality.cc b/third_party/blink/renderer/core/css/css_property_equality.cc index ff1cc33..936bd39e 100644 --- a/third_party/blink/renderer/core/css/css_property_equality.cc +++ b/third_party/blink/renderer/core/css/css_property_equality.cc
@@ -1167,8 +1167,6 @@ case CSSPropertyID::kInsetInlineEnd: case CSSPropertyID::kInsetBlockStart: case CSSPropertyID::kInsetBlockEnd: - case CSSPropertyID::kInternalOverflowBlock: - case CSSPropertyID::kInternalOverflowInline: case CSSPropertyID::kOverflowBlock: case CSSPropertyID::kOverflowInline: case CSSPropertyID::kOverscrollBehaviorBlock:
diff --git a/third_party/blink/renderer/core/css/css_relative_color_value_test.cc b/third_party/blink/renderer/core/css/css_relative_color_value_test.cc index ddf4300..d595a2b 100644 --- a/third_party/blink/renderer/core/css/css_relative_color_value_test.cc +++ b/third_party/blink/renderer/core/css/css_relative_color_value_test.cc
@@ -13,9 +13,6 @@ namespace blink { TEST(CSSRelativeColorValueTest, Equals) { - ScopedCSSRelativeColorSupportsCurrentcolorForTest scoped_feature_for_test( - true); - const CSSParserContext* context = MakeGarbageCollected<CSSParserContext>( kHTMLStandardMode, SecureContextMode::kInsecureContext); @@ -34,9 +31,6 @@ } TEST(CSSRelativeColorValueTest, CustomCSSText) { - ScopedCSSRelativeColorSupportsCurrentcolorForTest scoped_feature_for_test( - true); - const CSSParserContext* context = MakeGarbageCollected<CSSParserContext>( kHTMLStandardMode, SecureContextMode::kInsecureContext);
diff --git a/third_party/blink/renderer/core/css/css_url_data.cc b/third_party/blink/renderer/core/css/css_url_data.cc index 289521d..aa904a4a 100644 --- a/third_party/blink/renderer/core/css/css_url_data.cc +++ b/third_party/blink/renderer/core/css/css_url_data.cc
@@ -35,9 +35,9 @@ : relative_url_(unresolved_url), absolute_url_(resolved_url.GetString()), referrer_(referrer), + is_local_(unresolved_url.StartsWith('#')), is_from_origin_clean_style_sheet_(is_from_origin_clean_style_sheet), is_ad_related_(is_ad_related), - is_local_(unresolved_url.StartsWith('#')), potentially_dangling_markup_(resolved_url.PotentiallyDanglingMarkup()) {} CSSUrlData::CSSUrlData(base::PassKey<CSSUrlData>, @@ -51,9 +51,9 @@ : relative_url_(unresolved_url), absolute_url_(resolved_url), referrer_(referrer), + is_local_(is_local), is_from_origin_clean_style_sheet_(is_from_origin_clean_style_sheet), is_ad_related_(is_ad_related), - is_local_(is_local), potentially_dangling_markup_(potentially_dangling_markup) {} CSSUrlData::CSSUrlData(const AtomicString& resolved_url) @@ -98,8 +98,8 @@ return true; } -const CSSUrlData* CSSUrlData::MakeAbsolute() const { - if (relative_url_.empty()) { +const CSSUrlData* CSSUrlData::MakeComputed() const { + if (relative_url_.empty() || is_local_ || absolute_url_.empty()) { return this; } return MakeGarbageCollected<CSSUrlData>(
diff --git a/third_party/blink/renderer/core/css/css_url_data.h b/third_party/blink/renderer/core/css/css_url_data.h index 8867cde..3ffdb9e 100644 --- a/third_party/blink/renderer/core/css/css_url_data.h +++ b/third_party/blink/renderer/core/css/css_url_data.h
@@ -65,8 +65,8 @@ // Document. Returns true if the resolved URL changed, otherwise false. bool ReResolveUrl(const Document&) const; - // Returns an absolutized copy of this URL data (suitable for computed value). - const CSSUrlData* MakeAbsolute() const; + // Returns a copy of this URL data suitable for computed value. + const CSSUrlData* MakeComputed() const; // Returns a copy where the unresolved URL has been resolved against // `base_url` (using `charset` encoding if valid). @@ -110,6 +110,9 @@ mutable AtomicString absolute_url_; const Referrer referrer_; + // The 'local url flag': https://drafts.csswg.org/css-values/#local-urls + const bool is_local_; + // Whether the stylesheet that requested this image is origin-clean: // https://drafts.csswg.org/cssom-1/#concept-css-style-sheet-origin-clean-flag const bool is_from_origin_clean_style_sheet_; @@ -117,8 +120,6 @@ // Whether this was created by an ad-related CSSParserContext. const bool is_ad_related_; - const bool is_local_; - // The url passed into the constructor had the PotentiallyDanglingMarkup flag // set. That information needs to be passed on to the fetch code to block such // resources from loading.
diff --git a/third_party/blink/renderer/core/css/media_query_exp.cc b/third_party/blink/renderer/core/css/media_query_exp.cc index 67af324..735a0d56 100644 --- a/third_party/blink/renderer/core/css/media_query_exp.cc +++ b/third_party/blink/renderer/core/css/media_query_exp.cc
@@ -170,22 +170,20 @@ ident == CSSValueID::kSlow; } - if (RuntimeEnabledFeatures::CSSStickyContainerQueriesEnabled()) { - if (media_feature == media_feature_names::kStuckMediaFeature) { - switch (ident) { - case CSSValueID::kNone: - case CSSValueID::kTop: - case CSSValueID::kLeft: - case CSSValueID::kBottom: - case CSSValueID::kRight: - case CSSValueID::kBlockStart: - case CSSValueID::kBlockEnd: - case CSSValueID::kInlineStart: - case CSSValueID::kInlineEnd: - return true; - default: - return false; - } + if (media_feature == media_feature_names::kStuckMediaFeature) { + switch (ident) { + case CSSValueID::kNone: + case CSSValueID::kTop: + case CSSValueID::kLeft: + case CSSValueID::kBottom: + case CSSValueID::kRight: + case CSSValueID::kBlockStart: + case CSSValueID::kBlockEnd: + case CSSValueID::kInlineStart: + case CSSValueID::kInlineEnd: + return true; + default: + return false; } } @@ -194,42 +192,38 @@ ident == CSSValueID::kNone; } - if (RuntimeEnabledFeatures::CSSSnapContainerQueriesEnabled()) { - if (media_feature == media_feature_names::kSnappedMediaFeature) { - switch (ident) { - case CSSValueID::kNone: - case CSSValueID::kBlock: - case CSSValueID::kInline: - case CSSValueID::kX: - case CSSValueID::kY: - case CSSValueID::kBoth: - return true; - default: - return false; - } + if (media_feature == media_feature_names::kSnappedMediaFeature) { + switch (ident) { + case CSSValueID::kNone: + case CSSValueID::kBlock: + case CSSValueID::kInline: + case CSSValueID::kX: + case CSSValueID::kY: + case CSSValueID::kBoth: + return true; + default: + return false; } } - if (RuntimeEnabledFeatures::CSSScrollableContainerQueriesEnabled()) { - if (media_feature == media_feature_names::kScrollableMediaFeature) { - switch (ident) { - case CSSValueID::kNone: - case CSSValueID::kTop: - case CSSValueID::kLeft: - case CSSValueID::kBottom: - case CSSValueID::kRight: - case CSSValueID::kBlockStart: - case CSSValueID::kBlockEnd: - case CSSValueID::kInlineStart: - case CSSValueID::kInlineEnd: - case CSSValueID::kBlock: - case CSSValueID::kInline: - case CSSValueID::kX: - case CSSValueID::kY: - return true; - default: - return false; - } + if (media_feature == media_feature_names::kScrollableMediaFeature) { + switch (ident) { + case CSSValueID::kNone: + case CSSValueID::kTop: + case CSSValueID::kLeft: + case CSSValueID::kBottom: + case CSSValueID::kRight: + case CSSValueID::kBlockStart: + case CSSValueID::kBlockEnd: + case CSSValueID::kInlineStart: + case CSSValueID::kInlineEnd: + case CSSValueID::kBlock: + case CSSValueID::kInline: + case CSSValueID::kX: + case CSSValueID::kY: + return true; + default: + return false; } }
diff --git a/third_party/blink/renderer/core/css/parser/container_query_parser.cc b/third_party/blink/renderer/core/css/parser/container_query_parser.cc index 701f598..bcb4f78 100644 --- a/third_party/blink/renderer/core/css/parser/container_query_parser.cc +++ b/third_party/blink/renderer/core/css/parser/container_query_parser.cc
@@ -91,12 +91,9 @@ public: bool IsAllowed(const AtomicString& feature) const override { - return (RuntimeEnabledFeatures::CSSStickyContainerQueriesEnabled() && - feature == media_feature_names::kStuckMediaFeature) || - (RuntimeEnabledFeatures::CSSSnapContainerQueriesEnabled() && - feature == media_feature_names::kSnappedMediaFeature) || - (RuntimeEnabledFeatures::CSSScrollableContainerQueriesEnabled() && - feature == media_feature_names::kScrollableMediaFeature) || + return feature == media_feature_names::kStuckMediaFeature || + feature == media_feature_names::kSnappedMediaFeature || + feature == media_feature_names::kScrollableMediaFeature || (RuntimeEnabledFeatures:: CSSScrollDirectionContainerQueriesEnabled() && feature == media_feature_names::kScrollDirectionMediaFeature); @@ -182,8 +179,7 @@ stream.ConsumeWhitespace(); return MediaQueryExpNode::Function(query, AtomicString("style")); } - } else if (RuntimeEnabledFeatures::CSSScrollStateContainerQueriesEnabled() && - stream.Peek().GetType() == kFunctionToken && + } else if (stream.Peek().GetType() == kFunctionToken && stream.Peek().FunctionId() == CSSValueID::kScrollState) { // scroll-state(stuck: [ none | top | right | bottom | left | block-start | // inline-start | block-end | inline-end ] )
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc b/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc index 3ff69df..6cb1028d 100644 --- a/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc +++ b/third_party/blink/renderer/core/css/parser/css_parser_fast_paths.cc
@@ -1303,8 +1303,6 @@ return value_id == CSSValueID::kNormal || value_id == CSSValueID::kBreakWord || value_id == CSSValueID::kAnywhere; - case CSSPropertyID::kInternalOverflowBlock: - case CSSPropertyID::kInternalOverflowInline: case CSSPropertyID::kOverflowBlock: case CSSPropertyID::kOverflowInline: case CSSPropertyID::kOverflowX: @@ -1752,8 +1750,6 @@ CSSPropertyID::kGapRulePaintOrder, CSSPropertyID::kHyphens, CSSPropertyID::kImageRendering, - CSSPropertyID::kInternalOverflowBlock, - CSSPropertyID::kInternalOverflowInline, CSSPropertyID::kInterpolateSize, CSSPropertyID::kListStylePosition, CSSPropertyID::kMaskType,
diff --git a/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc b/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc index 5715427..311cc50a 100644 --- a/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc +++ b/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc
@@ -222,9 +222,6 @@ const CSSParserContext& context) { // [from <color>]? if (css_parsing_utils::ConsumeIdent<CSSValueID::kFrom>(stream)) { - if (!RuntimeEnabledFeatures::CSSRelativeColorEnabled()) { - return false; - } unresolved_origin_color_ = css_parsing_utils::ConsumeColor(stream, context); if (!unresolved_origin_color_) { return false; @@ -282,11 +279,6 @@ {CSSValueID::kAlpha, origin_color_->Alpha()}, }; } else { - if (!origin_color_.has_value() && - !RuntimeEnabledFeatures:: - CSSRelativeColorSupportsCurrentcolorEnabled()) { - return false; - } // If the origin color is not resolvable at parse time, fill out the map // with just the valid channel names. We still need that information to // parse the remainder of the color function.
diff --git a/third_party/blink/renderer/core/css/properties/css_color_function_parser_test.cc b/third_party/blink/renderer/core/css/properties/css_color_function_parser_test.cc index 615b093..76f4e1f 100644 --- a/third_party/blink/renderer/core/css/properties/css_color_function_parser_test.cc +++ b/third_party/blink/renderer/core/css/properties/css_color_function_parser_test.cc
@@ -84,26 +84,7 @@ EXPECT_EQ(result, nullptr); } -TEST(ColorFunctionParserTest, RelativeColorWithCurrentcolorBase_Disabled) { - ScopedCSSRelativeColorSupportsCurrentcolorForTest scoped_feature_for_test( - false); - - const String test_case = "rgb(from currentcolor r g b)"; - CSSParserTokenStream stream(test_case); - - const CSSParserContext* context = MakeGarbageCollected<CSSParserContext>( - kHTMLStandardMode, SecureContextMode::kInsecureContext); - - ColorFunctionParser parser; - const CSSValue* result = - parser.ConsumeFunctionalSyntaxColor(stream, *context); - EXPECT_EQ(result, nullptr); -} - TEST(ColorFunctionParserTest, RelativeColorWithCurrentcolorBase_NoAlpha) { - ScopedCSSRelativeColorSupportsCurrentcolorForTest scoped_feature_for_test( - true); - const String test_case = "rgb(from currentcolor 1 calc(g) b)"; CSSParserTokenStream stream(test_case); @@ -140,9 +121,6 @@ } TEST(ColorFunctionParserTest, RelativeColorWithCurrentcolorBase_CalcAlpha) { - ScopedCSSRelativeColorSupportsCurrentcolorForTest scoped_feature_for_test( - true); - const String test_case = "rgb(from currentcolor 1 calc(g) b / calc(alpha / 2))"; CSSParserTokenStream stream(test_case); @@ -182,9 +160,6 @@ } TEST(ColorFunctionParserTest, RelativeColorWithCurrentcolorBase_NoneKeyword) { - ScopedCSSRelativeColorSupportsCurrentcolorForTest scoped_feature_for_test( - true); - const String test_case = "rgb(from currentcolor none none none / none)"; CSSParserTokenStream stream(test_case); @@ -223,9 +198,6 @@ } TEST(ColorFunctionParserTest, RelativeColorWithColorMixWithCurrentColorBase) { - ScopedCSSRelativeColorSupportsCurrentcolorForTest scoped_feature_for_test( - true); - const String test_case = "rgb(from color-mix(in srgb, currentColor 50%, green) r g b)"; CSSParserTokenStream stream(test_case);
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc index c1521e3..f82c9d5 100644 --- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc +++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -8139,8 +8139,7 @@ continue; } } - if (!scroll_state_value && - RuntimeEnabledFeatures::CSSScrollStateContainerQueriesEnabled()) { + if (!scroll_state_value) { scroll_state_value = ConsumeIdent<CSSValueID::kScrollState>(stream); if (scroll_state_value) { context.Count(WebDXFeature::kContainerScrollStateQueries);
diff --git a/third_party/blink/renderer/core/css/properties/css_property_test.cc b/third_party/blink/renderer/core/css/properties/css_property_test.cc index ac7e76e..b974079d 100644 --- a/third_party/blink/renderer/core/css/properties/css_property_test.cc +++ b/third_party/blink/renderer/core/css/properties/css_property_test.cc
@@ -477,28 +477,6 @@ ComputedValue("max-height", "anchor-size(width, 0px)", context)); } -TEST_F(CSSPropertyTest, AnchorSizeInsetsMarginsDisabled) { - ScopedCSSAnchorSizeInsetsMarginsForTest enabled(false); - - String anchor_size_value("anchor-size(width)"); - EXPECT_EQ(Parse("top", anchor_size_value), nullptr); - EXPECT_EQ(Parse("left", anchor_size_value), nullptr); - EXPECT_EQ(Parse("bottom", anchor_size_value), nullptr); - EXPECT_EQ(Parse("right", anchor_size_value), nullptr); - EXPECT_EQ(Parse("inset-block-start", anchor_size_value), nullptr); - EXPECT_EQ(Parse("inset-block-end", anchor_size_value), nullptr); - EXPECT_EQ(Parse("inset-inline-start", anchor_size_value), nullptr); - EXPECT_EQ(Parse("inset-inline-end", anchor_size_value), nullptr); - EXPECT_EQ(Parse("margin-top", anchor_size_value), nullptr); - EXPECT_EQ(Parse("margin-left", anchor_size_value), nullptr); - EXPECT_EQ(Parse("margin-bottom", anchor_size_value), nullptr); - EXPECT_EQ(Parse("margin-right", anchor_size_value), nullptr); - EXPECT_EQ(Parse("margin-block-start", anchor_size_value), nullptr); - EXPECT_EQ(Parse("margin-block-end", anchor_size_value), nullptr); - EXPECT_EQ(Parse("margin-inline-start", anchor_size_value), nullptr); - EXPECT_EQ(Parse("margin-inline-end", anchor_size_value), nullptr); -} - struct DirectionAwarePropertyData { CSSPropertyID physical; CSSPropertyID logical;
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc index cefbbeb..d2ed8d5 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -1841,13 +1841,10 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext& local_context) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? kCSSAnchorQueryTypesAll - : static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchor); return css_parsing_utils::ConsumeMarginOrOffset( stream, context, - css_parsing_utils::UnitlessUnlessShorthand(local_context), anchor_types); + css_parsing_utils::UnitlessUnlessShorthand(local_context), + kCSSAnchorQueryTypesAll); } bool Bottom::IsLayoutDependent(const ComputedStyle* style, @@ -5232,12 +5229,9 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? kCSSAnchorQueryTypesAll - : static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchor); return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kForbid, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kForbid, + kCSSAnchorQueryTypesAll); } bool InsetBlockEnd::IsLayoutDependent(const ComputedStyle* style, @@ -5249,12 +5243,9 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? kCSSAnchorQueryTypesAll - : static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchor); return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kForbid, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kForbid, + kCSSAnchorQueryTypesAll); } bool InsetBlockStart::IsLayoutDependent(const ComputedStyle* style, @@ -5266,12 +5257,9 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? kCSSAnchorQueryTypesAll - : static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchor); return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kForbid, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kForbid, + kCSSAnchorQueryTypesAll); } bool InsetInlineEnd::IsLayoutDependent(const ComputedStyle* style, @@ -5283,12 +5271,9 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? kCSSAnchorQueryTypesAll - : static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchor); return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kForbid, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kForbid, + kCSSAnchorQueryTypesAll); } bool InsetInlineStart::IsLayoutDependent(const ComputedStyle* style, @@ -6055,13 +6040,10 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext& local_context) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? kCSSAnchorQueryTypesAll - : static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchor); return css_parsing_utils::ConsumeMarginOrOffset( stream, context, - css_parsing_utils::UnitlessUnlessShorthand(local_context), anchor_types); + css_parsing_utils::UnitlessUnlessShorthand(local_context), + kCSSAnchorQueryTypesAll); } bool Left::IsLayoutDependent(const ComputedStyle* style, @@ -6305,12 +6287,9 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize) - : kCSSAnchorQueryTypesNone; return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kForbid, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kForbid, + static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize)); } bool MarginBlockStart::IsLayoutDependent(const ComputedStyle* style, @@ -6322,24 +6301,18 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize) - : kCSSAnchorQueryTypesNone; return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kForbid, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kForbid, + static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize)); } const CSSValue* MarginBottom::ParseSingleValue( CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize) - : kCSSAnchorQueryTypesNone; return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kAllow, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kAllow, + static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize)); } bool MarginBottom::IsLayoutDependent(const ComputedStyle* style, @@ -6370,12 +6343,9 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize) - : kCSSAnchorQueryTypesNone; return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kForbid, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kForbid, + static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize)); } bool MarginInlineStart::IsLayoutDependent(const ComputedStyle* style, @@ -6387,24 +6357,18 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize) - : kCSSAnchorQueryTypesNone; return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kForbid, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kForbid, + static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize)); } const CSSValue* MarginLeft::ParseSingleValue( CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize) - : kCSSAnchorQueryTypesNone; return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kAllow, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kAllow, + static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize)); } bool MarginLeft::IsLayoutDependent(const ComputedStyle* style, @@ -6431,12 +6395,9 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize) - : kCSSAnchorQueryTypesNone; return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kAllow, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kAllow, + static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize)); } bool MarginRight::IsLayoutDependent(const ComputedStyle* style, @@ -6463,12 +6424,9 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize) - : kCSSAnchorQueryTypesNone; return css_parsing_utils::ConsumeMarginOrOffset( - stream, context, css_parsing_utils::UnitlessQuirk::kAllow, anchor_types); + stream, context, css_parsing_utils::UnitlessQuirk::kAllow, + static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchorSize)); } bool MarginTop::IsLayoutDependent(const ComputedStyle* style, @@ -8124,13 +8082,10 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext& local_context) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? kCSSAnchorQueryTypesAll - : static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchor); return css_parsing_utils::ConsumeMarginOrOffset( stream, context, - css_parsing_utils::UnitlessUnlessShorthand(local_context), anchor_types); + css_parsing_utils::UnitlessUnlessShorthand(local_context), + kCSSAnchorQueryTypesAll); } bool Right::IsLayoutDependent(const ComputedStyle* style, @@ -9826,13 +9781,10 @@ CSSParserTokenStream& stream, const CSSParserContext& context, const CSSParserLocalContext& local_context) const { - CSSAnchorQueryTypes anchor_types = - RuntimeEnabledFeatures::CSSAnchorSizeInsetsMarginsEnabled() - ? kCSSAnchorQueryTypesAll - : static_cast<CSSAnchorQueryTypes>(CSSAnchorQueryType::kAnchor); return css_parsing_utils::ConsumeMarginOrOffset( stream, context, - css_parsing_utils::UnitlessUnlessShorthand(local_context), anchor_types); + css_parsing_utils::UnitlessUnlessShorthand(local_context), + kCSSAnchorQueryTypesAll); } bool Top::IsLayoutDependent(const ComputedStyle* style,
diff --git a/third_party/blink/renderer/core/css/style_color.cc b/third_party/blink/renderer/core/css/style_color.cc index 7a55229..2b29c385 100644 --- a/third_party/blink/renderer/core/css/style_color.cc +++ b/third_party/blink/renderer/core/css/style_color.cc
@@ -296,13 +296,8 @@ /*is_legacy_syntax=*/false, color_interpolation_space_, params, param_alpha); - Color result = Color::FromColorSpace(color_interpolation_space_, params[0], - params[1], params[2], param_alpha); - if (Color::IsLegacyColorSpace(result.GetColorSpace()) && - !RuntimeEnabledFeatures::CSSRelativeColorPreserveNoneEnabled()) { - result.ConvertToColorSpace(Color::ColorSpace::kSRGB); - } - return result; + return Color::FromColorSpace(color_interpolation_space_, params[0], params[1], + params[2], param_alpha); } bool StyleColor::UnresolvedRelativeColor::operator==(
diff --git a/third_party/blink/renderer/core/editing/commands/delete_selection_command.cc b/third_party/blink/renderer/core/editing/commands/delete_selection_command.cc index 712b6622..5e6b8a1 100644 --- a/third_party/blink/renderer/core/editing/commands/delete_selection_command.cc +++ b/third_party/blink/renderer/core/editing/commands/delete_selection_command.cc
@@ -45,6 +45,7 @@ #include "third_party/blink/renderer/core/editing/visible_units.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/html/forms/html_input_element.h" +#include "third_party/blink/renderer/core/html/forms/text_control_element.h" #include "third_party/blink/renderer/core/html/html_br_element.h" #include "third_party/blink/renderer/core/html/html_hr_element.h" #include "third_party/blink/renderer/core/html/html_link_element.h" @@ -623,6 +624,11 @@ }); } + const ShouldAssumeContentIsAlwaysEditable always_editable = + RuntimeEnabledFeatures::EditingFastDeleteEnabled() && + EnclosingTextControl(node) + ? kAssumeContentIsAlwaysEditable + : kDoNotAssumeContentIsAlwaysEditable; // Actually remove the nodes in |nodes_to_be_removed|. for (Node* node_to_be_removed : nodes_to_be_removed) { if (!downstream_end_.AnchorNode()->IsDescendantOf(node_to_be_removed)) { @@ -678,7 +684,7 @@ ending_position_ = ComputePositionForNodeRemoval(ending_position_, *node_to_be_removed); CompositeEditCommand::RemoveNode(node_to_be_removed, editing_state, - kDoNotAssumeContentIsAlwaysEditable); + always_editable); if (editing_state->IsAborted()) return; } @@ -719,7 +725,10 @@ return; } Node* node = range->FirstNode(); - while (node && node != range->PastLastNode()) { + Node* past_last = range->PastLastNode(); + while (node && node != (RuntimeEnabledFeatures::EditingFastDeleteEnabled() + ? past_last + : range->PastLastNode())) { Node* next_node = NodeTraversal::Next(*node); if (IsA<HTMLStyleElement>(*node) || IsA<HTMLLinkElement>(*node)) { next_node = NodeTraversal::NextSkippingChildren(*node);
diff --git a/third_party/blink/renderer/core/editing/commands/remove_node_command.cc b/third_party/blink/renderer/core/editing/commands/remove_node_command.cc index aa961ce..0f53a8f4 100644 --- a/third_party/blink/renderer/core/editing/commands/remove_node_command.cc +++ b/third_party/blink/renderer/core/editing/commands/remove_node_command.cc
@@ -47,11 +47,25 @@ void RemoveNodeCommand::DoApply(EditingState* editing_state) { ContainerNode* parent = node_->parentNode(); - GetDocument().UpdateStyleAndLayoutTree(); - if (!parent || (should_assume_content_is_always_editable_ == - kDoNotAssumeContentIsAlwaysEditable && - !IsEditable(*parent) && parent->InActiveDocument())) + if (!parent) { return; + } + if (RuntimeEnabledFeatures::EditingFastDeleteEnabled()) { + if (should_assume_content_is_always_editable_ == + kDoNotAssumeContentIsAlwaysEditable) { + GetDocument().UpdateStyleAndLayoutTree(); + if (!IsEditable(*parent) && parent->InActiveDocument()) { + return; + } + } + } else { + GetDocument().UpdateStyleAndLayoutTree(); + if (should_assume_content_is_always_editable_ == + kDoNotAssumeContentIsAlwaysEditable && + !IsEditable(*parent) && parent->InActiveDocument()) { + return; + } + } DCHECK(IsEditable(*parent) || !parent->InActiveDocument()) << parent; parent_ = parent;
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.cc index 9489f92..9cf98d8 100644 --- a/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.cc +++ b/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.cc
@@ -80,18 +80,14 @@ } void TextIteratorTextState::AppendTextToStringBuilder( - StringBuilder& builder, - unsigned position, - unsigned max_length) const { - SECURITY_DCHECK(position <= this->length()); - unsigned length_to_append = std::min(length() - position, max_length); - if (!length_to_append) + StringBuilder& builder) const { + if (!text_length_) { return; + } if (single_character_buffer_) { - DCHECK_EQ(position, 0u); builder.Append(single_character_buffer_); } else { - builder.Append(text_, text_start_offset_ + position, length_to_append); + builder.Append(text_, text_start_offset_, text_length_); } }
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h b/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h index dd4f0f9..8bb06d3 100644 --- a/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h +++ b/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h
@@ -57,9 +57,7 @@ UChar CharacterAt(unsigned index) const; // TODO(xiaochengh): Rename to |GetText()| as it's used in production code. String GetTextForTesting() const; - void AppendTextToStringBuilder(WTF::StringBuilder&, - unsigned position = 0, - unsigned max_length = UINT_MAX) const; + void AppendTextToStringBuilder(WTF::StringBuilder&) const; // Emits code unit relative to |node|. void EmitChar16AfterNode(UChar code_unit, const Node& node);
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc index 73f25b18..feba963 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -56,6 +56,7 @@ #include "third_party/blink/public/common/page/page_zoom.h" #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h" #include "third_party/blink/public/common/switches.h" +#include "third_party/blink/public/common/view_source/rendering_preferences.h" #include "third_party/blink/public/common/web_preferences/web_preferences.h" #include "third_party/blink/public/mojom/frame/frame_replication_state.mojom-blink.h" #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h" @@ -3566,6 +3567,8 @@ #endif CanvasNoiseToken::Set(renderer_preferences_.canvas_noise_token); + ViewSourceLineWrappingPreference::Set( + renderer_preferences_.view_source_line_wrap_enabled); MaybePreloadSystemFonts(GetPage()); }
diff --git a/third_party/blink/renderer/core/html/canvas/image_element_base.cc b/third_party/blink/renderer/core/html/canvas/image_element_base.cc index 3a6e86d..6ea2fc4 100644 --- a/third_party/blink/renderer/core/html/canvas/image_element_base.cc +++ b/third_party/blink/renderer/core/html/canvas/image_element_base.cc
@@ -134,7 +134,7 @@ if (!GetImageLoader().ImageComplete() || !image_content) return false; Image* image = image_content->GetImage(); - return image->CurrentFrameKnownToBeOpaque(); + return image->IsOpaque(); } static bool HasDimensionsForImage(SVGImage& svg_image,
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_registry.cc b/third_party/blink/renderer/core/html/custom/custom_element_registry.cc index 8d80866..8a91b74 100644 --- a/third_party/blink/renderer/core/html/custom/custom_element_registry.cc +++ b/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
@@ -29,6 +29,7 @@ #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" namespace blink { @@ -57,7 +58,7 @@ return false; exception_state.ThrowDOMException( DOMExceptionCode::kSyntaxError, - "\"" + name + "\" is not a valid custom element name"); + WTF::StrCat({"\"", name, "\" is not a valid custom element name"})); return true; } @@ -68,7 +69,7 @@ return false; exception_state.ThrowDOMException( DOMExceptionCode::kNotSupportedError, - "\"" + name + "\" is a valid custom element name"); + WTF::StrCat({"\"", name, "\" is a valid custom element name"})); return true; } @@ -136,7 +137,8 @@ if (NameIsDefined(name)) { exception_state.ThrowDOMException( DOMExceptionCode::kNotSupportedError, - "the name \"" + name + "\" has already been used with this registry"); + WTF::StrCat({"the name \"", name, + "\" has already been used with this registry"})); return nullptr; } @@ -163,7 +165,7 @@ HTMLElementType::kHTMLUnknownElement) { exception_state.ThrowDOMException( DOMExceptionCode::kNotSupportedError, - "\"" + extends + "\" is an HTMLUnknownElement"); + WTF::StrCat({"\"", extends, "\" is an HTMLUnknownElement"})); return nullptr; } // 7.3. Set localName to extends
diff --git a/third_party/blink/renderer/core/html/fenced_frame/html_fenced_frame_element.cc b/third_party/blink/renderer/core/html/fenced_frame/html_fenced_frame_element.cc index 392d8b2b..e6987f5 100644 --- a/third_party/blink/renderer/core/html/fenced_frame/html_fenced_frame_element.cc +++ b/third_party/blink/renderer/core/html/fenced_frame/html_fenced_frame_element.cc
@@ -43,6 +43,7 @@ #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" namespace blink { @@ -344,8 +345,8 @@ GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( mojom::blink::ConsoleMessageSource::kOther, mojom::blink::ConsoleMessageLevel::kError, - "Error while parsing the 'sandbox' attribute: " + - String::FromUTF8(parsed.error_message))); + WTF::StrCat({"Error while parsing the 'sandbox' attribute: ", + String::FromUTF8(parsed.error_message)}))); } } SetSandboxFlags(current_flags); @@ -440,10 +441,10 @@ GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( mojom::blink::ConsoleMessageSource::kRendering, mojom::blink::ConsoleMessageLevel::kWarning, - "Cannot create a fenced frame with mode '" + - DeprecatedFencedFrameModeToString(GetDeprecatedMode()) + - "' nested in a fenced frame with mode '" + - DeprecatedFencedFrameModeToString(parent_mode) + "'.")); + WTF::StrCat({"Cannot create a fenced frame with mode '", + DeprecatedFencedFrameModeToString(GetDeprecatedMode()), + "' nested in a fenced frame with mode '", + DeprecatedFencedFrameModeToString(parent_mode), "'."}))); RecordFencedFrameCreationOutcome( FencedFrameCreationOutcome::kIncompatibleMode); return;
diff --git a/third_party/blink/renderer/core/html/forms/base_text_input_type.cc b/third_party/blink/renderer/core/html/forms/base_text_input_type.cc index f7252de..de4ca5c 100644 --- a/third_party/blink/renderer/core/html/forms/base_text_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/base_text_input_type.cc
@@ -32,6 +32,7 @@ #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/platform/bindings/script_regexp.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" namespace blink { @@ -114,14 +115,14 @@ MakeGarbageCollected<ConsoleMessage>( mojom::blink::ConsoleMessageSource::kRendering, mojom::blink::ConsoleMessageLevel::kError, - "Pattern attribute value " + raw_pattern + - " is not a valid regular expression: " + - raw_regexp->ExceptionMessage())); + WTF::StrCat({"Pattern attribute value ", raw_pattern, + " is not a valid regular expression: ", + raw_regexp->ExceptionMessage()}))); regexp_ = raw_regexp; pattern_for_regexp_ = raw_pattern; return false; } - String pattern = "^(?:" + raw_pattern + ")$"; + String pattern = WTF::StrCat({"^(?:", raw_pattern, ")$"}); regexp_ = MakeGarbageCollected<ScriptRegexp>( isolate, pattern, kTextCaseSensitive, MultilineMode::kMultilineDisabled, unicode_mode);
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type.cc b/third_party/blink/renderer/core/html/forms/file_input_type.cc index 2e9fe75..808f36b 100644 --- a/third_party/blink/renderer/core/html/forms/file_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/file_input_type.cc
@@ -49,6 +49,7 @@ #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/text/platform_locale.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -276,7 +277,7 @@ // decided to try to parse the value by looking for backslashes // (because that's what Windows file paths use). To be compatible // with that code, we make up a fake path for the file. - return "C:\\fakepath\\" + file_list_->item(0)->name(); + return WTF::StrCat({"C:\\fakepath\\", file_list_->item(0)->name()}); } void FileInputType::SetValue(const String&,
diff --git a/third_party/blink/renderer/core/html/forms/html_form_element.cc b/third_party/blink/renderer/core/html/forms/html_form_element.cc index a39b1ed..6ae8d6b 100644 --- a/third_party/blink/renderer/core/html/forms/html_form_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_form_element.cc
@@ -74,6 +74,7 @@ #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" namespace blink { @@ -303,13 +304,14 @@ if (GetExecutionContext()->IsSandboxed( network::mojom::blink::WebSandboxFlags::kForms)) { - GetExecutionContext()->AddConsoleMessage( - MakeGarbageCollected<ConsoleMessage>( - mojom::blink::ConsoleMessageSource::kSecurity, - mojom::blink::ConsoleMessageLevel::kError, - "Blocked form submission to '" + attributes_.Action() + - "' because the form's frame is sandboxed and the 'allow-forms' " - "permission is not set.")); + GetExecutionContext()->AddConsoleMessage(MakeGarbageCollected< + ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kSecurity, + mojom::blink::ConsoleMessageLevel::kError, + WTF::StrCat( + {"Blocked form submission to '", attributes_.Action(), + "' because the form's frame is sandboxed and the 'allow-forms' " + "permission is not set."}))); return; } @@ -324,14 +326,11 @@ GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( mojom::ConsoleMessageSource::kSecurity, mojom::ConsoleMessageLevel::kError, - "Form submission failed, as the <" + tag_name + - "> element named " - "'" + - element->GetName() + - "' was implicitly closed by reaching " - "the end of the file. Please add an explicit end tag " - "('</" + - tag_name + ">')")); + WTF::StrCat({"Form submission failed, as the <", tag_name, + "> element named '", element->GetName(), + "' was implicitly closed by reaching the end of the " + "file. Please add an explicit end tag ('</", + tag_name, ">')"}))); DispatchEvent(*Event::Create(event_type_names::kError)); return; } @@ -513,14 +512,15 @@ network::mojom::blink::WebSandboxFlags::kForms)) { // FIXME: This message should be moved off the console once a solution to // https://bugs.webkit.org/show_bug.cgi?id=103274 exists. - GetExecutionContext()->AddConsoleMessage( - MakeGarbageCollected<ConsoleMessage>( - mojom::blink::ConsoleMessageSource::kSecurity, - mojom::blink::ConsoleMessageLevel::kError, - "Blocked form submission to '" + - form_submission->Action().ElidedString() + - "' because the form's frame is sandboxed and the 'allow-forms' " - "permission is not set.")); + GetExecutionContext()->AddConsoleMessage(MakeGarbageCollected< + ConsoleMessage>( + mojom::blink::ConsoleMessageSource::kSecurity, + mojom::blink::ConsoleMessageLevel::kError, + WTF::StrCat( + {"Blocked form submission to '", + form_submission->Action().ElidedString(), + "' because the form's frame is sandboxed and the 'allow-forms' " + "permission is not set."}))); return; }
diff --git a/third_party/blink/renderer/core/html/forms/html_input_element.cc b/third_party/blink/renderer/core/html/forms/html_input_element.cc index d5ede9a..04b83f4 100644 --- a/third_party/blink/renderer/core/html/forms/html_input_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_input_element.cc
@@ -98,6 +98,7 @@ #include "third_party/blink/renderer/platform/text/platform_locale.h" #include "third_party/blink/renderer/platform/text/text_break_iterator.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" #include "ui/base/ui_base_features.h" namespace blink { @@ -690,8 +691,9 @@ if (!input_type_->SupportsSelectionAPI()) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, - "The input element's type ('" + input_type_->FormControlTypeAsString() + - "') does not support selection."); + WTF::StrCat({"The input element's type ('", + input_type_->FormControlTypeAsString(), + "') does not support selection."})); return; } TextControlElement::setSelectionStart(start.value_or(0)); @@ -703,8 +705,9 @@ if (!input_type_->SupportsSelectionAPI()) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, - "The input element's type ('" + input_type_->FormControlTypeAsString() + - "') does not support selection."); + WTF::StrCat({"The input element's type ('", + input_type_->FormControlTypeAsString(), + "') does not support selection."})); return; } TextControlElement::setSelectionEnd(end.value_or(0)); @@ -716,8 +719,9 @@ if (!input_type_->SupportsSelectionAPI()) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, - "The input element's type ('" + input_type_->FormControlTypeAsString() + - "') does not support selection."); + WTF::StrCat({"The input element's type ('", + input_type_->FormControlTypeAsString(), + "') does not support selection."})); return; } TextControlElement::setSelectionDirection(direction); @@ -730,8 +734,9 @@ if (!input_type_->SupportsSelectionAPI()) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, - "The input element's type ('" + input_type_->FormControlTypeAsString() + - "') does not support selection."); + WTF::StrCat({"The input element's type ('", + input_type_->FormControlTypeAsString(), + "') does not support selection."})); return; } TextControlElement::setSelectionRangeForBinding(start, end); @@ -745,8 +750,9 @@ if (!input_type_->SupportsSelectionAPI()) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, - "The input element's type ('" + input_type_->FormControlTypeAsString() + - "') does not support selection."); + WTF::StrCat({"The input element's type ('", + input_type_->FormControlTypeAsString(), + "') does not support selection."})); return; } TextControlElement::setSelectionRangeForBinding(start, end, direction); @@ -762,8 +768,9 @@ if (FormControlType() != FormControlType::kInputNumber) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, - "The input element's type ('" + input_type_->FormControlTypeAsString() + - "') is not a number input."); + WTF::StrCat({"The input element's type ('", + input_type_->FormControlTypeAsString(), + "') is not a number input."})); } TextControlElement::setSelectionRangeForBinding(start, end); } @@ -2162,8 +2169,9 @@ if (!input_type_->SupportsSelectionAPI()) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, - "The input element's type ('" + input_type_->FormControlTypeAsString() + - "') does not support selection."); + WTF::StrCat({"The input element's type ('", + input_type_->FormControlTypeAsString(), + "') does not support selection."})); return; } @@ -2178,8 +2186,9 @@ if (!input_type_->SupportsSelectionAPI()) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, - "The input element's type ('" + input_type_->FormControlTypeAsString() + - "') does not support selection."); + WTF::StrCat({"The input element's type ('", + input_type_->FormControlTypeAsString(), + "') does not support selection."})); return; }
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element_test.cc b/third_party/blink/renderer/core/html/forms/html_select_element_test.cc index e152ec0..14f9ddc 100644 --- a/third_party/blink/renderer/core/html/forms/html_select_element_test.cc +++ b/third_party/blink/renderer/core/html/forms/html_select_element_test.cc
@@ -1205,29 +1205,4 @@ ASSERT_FALSE(select->IsInDialogMode()); } -class HTMLSelectElementUATest : public HTMLSelectElementTest, - public testing::WithParamInterface<bool>, - public ScopedCSSLogicalOverflowForTest { - public: - HTMLSelectElementUATest() : ScopedCSSLogicalOverflowForTest(GetParam()) {} -}; - -TEST_P(HTMLSelectElementUATest, OverflowStyle) { - CSSDefaultStyleSheets::Instance().PrepareForLeakDetection(); - SetHtmlInnerHTML(R"HTML( - <select id="target" multiple></select> - )HTML"); - - HTMLSelectElement* select = To<HTMLSelectElement>(GetElementById("target")); - if (select->UsesMenuList()) { - // The UA styles won't apply when the menu list rendering is delegated. - return; - } - GetDocument().UpdateStyleAndLayoutTree(); - EXPECT_EQ(select->ComputedStyleRef().OverflowX(), EOverflow::kHidden); - EXPECT_EQ(select->ComputedStyleRef().OverflowY(), EOverflow::kScroll); -} - -INSTANTIATE_TEST_SUITE_P(All, HTMLSelectElementUATest, ::testing::Bool()); - } // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/html_text_area_element.cc b/third_party/blink/renderer/core/html/forms/html_text_area_element.cc index 8618718a..2bdd4c9 100644 --- a/third_party/blink/renderer/core/html/forms/html_text_area_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_text_area_element.cc
@@ -364,6 +364,7 @@ } void HTMLTextAreaElement::SubtreeHasChanged() { + AdjustPlaceholderBreakElement(); #if DCHECK_IS_ON() // The innerEditor should have either Text nodes or a placeholder break // element. If we see other nodes, it's a bug in editing code and we should @@ -382,7 +383,6 @@ } } #endif - AddPlaceholderBreakElementIfNecessary(); SetValueBeforeFirstUserEditIfNotSet(); UpdateValue(); CheckIfValueWasReverted(Value());
diff --git a/third_party/blink/renderer/core/html/forms/html_text_area_element_test.cc b/third_party/blink/renderer/core/html/forms/html_text_area_element_test.cc index 9eb85de..560e6d7 100644 --- a/third_party/blink/renderer/core/html/forms/html_text_area_element_test.cc +++ b/third_party/blink/renderer/core/html/forms/html_text_area_element_test.cc
@@ -7,6 +7,8 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/dom/text.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" +#include "third_party/blink/renderer/core/testing/mock_clipboard_host.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" namespace blink { @@ -15,12 +17,29 @@ public: HTMLTextAreaElementTest() = default; + void SetUp() override { + RenderingTest::SetUp(); + clipboard_provider_ = + std::make_unique<PageTestBase::MockClipboardHostProvider>( + GetFrame().GetBrowserInterfaceBroker()); + } + void TearDown() override { + clipboard_provider_.reset(); + RenderingTest::TearDown(); + } + protected: HTMLTextAreaElement& TestElement() { Element* element = GetDocument().getElementById(AtomicString("test")); DCHECK(element); return To<HTMLTextAreaElement>(*element); } + + mojom::blink::ClipboardHost* ClipboardHost() { + return clipboard_provider_->clipboard_host(); + } + + std::unique_ptr<PageTestBase::MockClipboardHostProvider> clipboard_provider_; }; TEST_F(HTMLTextAreaElementTest, SanitizeUserInputValue) { @@ -128,4 +147,30 @@ EXPECT_EQ(String(), textarea.DefaultToolTip()); } +TEST_F(HTMLTextAreaElementTest, PlaceholderBreakAfterUndo) { + Document& doc = GetDocument(); + SetBodyContent("<textarea id=test>foo\n</textarea>"); + HTMLTextAreaElement& textarea = TestElement(); + textarea.Focus(); + + // Setup for clipboard commands. + GetFrame().GetSettings()->SetJavaScriptCanAccessClipboard(true); + GetFrame().GetSettings()->SetDOMPasteAllowed(true); + GetFrame().SetHadUserInteraction(true); + + // Cut all. + // Unlike the initial empty value, this leaves the placeholder break element. + doc.execCommand("selectall", false, "", ASSERT_NO_EXCEPTION); + ASSERT_TRUE(doc.execCommand("cut", false, "", ASSERT_NO_EXCEPTION)); + + // Paste text with the trailing \n. It removes the placeholder break element. + ClipboardHost()->WriteText("foo\n"); + ASSERT_TRUE(doc.execCommand("paste", false, "", ASSERT_NO_EXCEPTION)); + + // The undo command re-add the placeholder break element. + doc.execCommand("undo", false, "", ASSERT_NO_EXCEPTION); + // The test passes if no DCHECK failure. + GetFrame().SetHadUserInteraction(false); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc b/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc index 3061cf8..924c192 100644 --- a/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc +++ b/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
@@ -43,6 +43,7 @@ #include "third_party/blink/renderer/platform/fonts/font_selector_client.h" #include "third_party/blink/renderer/platform/text/platform_locale.h" #include "third_party/blink/renderer/platform/wtf/shared_buffer.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" #include "ui/base/ui_base_features.h" #include "ui/gfx/geometry/rect.h" @@ -334,8 +335,8 @@ owner_element, owner_element.GetComputedStyle(), temp_scrollbar, target.first); if (part_style) { - AppendOwnerElementPseudoStyles(target.second + ":hover", data, - *part_style); + AppendOwnerElementPseudoStyles(WTF::StrCat({target.second, ":hover"}), + data, *part_style); } } }
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element.cc b/third_party/blink/renderer/core/html/forms/text_control_element.cc index 630d974..cd92ff9 100644 --- a/third_party/blink/renderer/core/html/forms/text_control_element.cc +++ b/third_party/blink/renderer/core/html/forms/text_control_element.cc
@@ -66,6 +66,7 @@ #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" namespace blink { @@ -377,9 +378,9 @@ if (start > end) { exception_state.ThrowDOMException( DOMExceptionCode::kIndexSizeError, - "The provided start value (" + String::Number(start) + - ") is larger than the provided end value (" + String::Number(end) + - ")."); + WTF::StrCat({"The provided start value (", String::Number(start), + ") is larger than the provided end value (", + String::Number(end), ")."})); return; } if (OpenShadowRoot()) @@ -917,17 +918,24 @@ shadow_element_names::kIdPlaceholderBreak; } -void TextControlElement::AddPlaceholderBreakElementIfNecessary() { +void TextControlElement::AdjustPlaceholderBreakElement() { HTMLElement* inner_editor = InnerEditorElement(); if (inner_editor->GetLayoutObject() && inner_editor->GetLayoutObject()->Style()->ShouldCollapseBreaks()) { return; } - const Node* last_child = inner_editor->lastChild(); + Node* last_child = inner_editor->lastChild(); if (RuntimeEnabledFeatures::TextareaLineEndingsAsBrEnabled() && - IsA<HTMLBRElement>(last_child) && - !IsPlaceholderBreakElement(last_child)) { - inner_editor->AppendChild(CreatePlaceholderBreakElement()); + IsA<HTMLBRElement>(last_child)) { + if (!IsPlaceholderBreakElement(last_child)) { + inner_editor->AppendChild(CreatePlaceholderBreakElement()); + } else if (IsPlaceholderBreakElement(last_child->previousSibling())) { + // Some editing commands removes the placeholder break, and this removal + // operation is recorded to UndoStack. If an undo is executed, the + // placeholder break is added back even if another placeholder break + // exists. + last_child->remove(); + } return; } auto* last_child_text_node = DynamicTo<Text>(last_child); @@ -968,7 +976,7 @@ // Add a placeholder <br> so that we can put the caret at the next line of // the last newline. - AddPlaceholderBreakElementIfNecessary(); + AdjustPlaceholderBreakElement(); if (text_is_changed && GetLayoutObject()) { if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element.h b/third_party/blink/renderer/core/html/forms/text_control_element.h index e8c18e4..0432b96 100644 --- a/third_party/blink/renderer/core/html/forms/text_control_element.h +++ b/third_party/blink/renderer/core/html/forms/text_control_element.h
@@ -195,7 +195,7 @@ virtual void SubtreeHasChanged() = 0; void SetLastChangeWasNotUserEdit() { last_change_was_user_edit_ = false; } - void AddPlaceholderBreakElementIfNecessary(); + void AdjustPlaceholderBreakElement(); String ValueWithHardLineBreaks() const; void CloneNonAttributePropertiesFrom(const Element&,
diff --git a/third_party/blink/renderer/core/html/html_frame_element_base.cc b/third_party/blink/renderer/core/html/html_frame_element_base.cc index 85009e5..59ef151d 100644 --- a/third_party/blink/renderer/core/html/html_frame_element_base.cc +++ b/third_party/blink/renderer/core/html/html_frame_element_base.cc
@@ -47,6 +47,7 @@ #include "third_party/blink/renderer/core/page/focus_controller.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" namespace blink { @@ -79,8 +80,8 @@ MakeGarbageCollected<ConsoleMessage>( mojom::ConsoleMessageSource::kRendering, mojom::ConsoleMessageLevel::kWarning, - "Invalid relative frame source URL (" + url_ + - ") within data URL.")); + WTF::StrCat({"Invalid relative frame source URL (", url_, + ") within data URL."}))); } LoadOrRedirectSubframe(url, frame_name_, replace_current_item); }
diff --git a/third_party/blink/renderer/core/html/html_iframe_element.cc b/third_party/blink/renderer/core/html/html_iframe_element.cc index 4941d03..d79aa26 100644 --- a/third_party/blink/renderer/core/html/html_iframe_element.cc +++ b/third_party/blink/renderer/core/html/html_iframe_element.cc
@@ -56,6 +56,7 @@ #include "third_party/blink/renderer/platform/json/json_parser.h" #include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" namespace blink { @@ -260,7 +261,7 @@ GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( mojom::blink::ConsoleMessageSource::kOther, mojom::blink::ConsoleMessageLevel::kError, - "'csp' attribute is invalid: " + value)); + WTF::StrCat({"'csp' attribute is invalid: ", value}))); } else if (value && value.length() > kMaxLengthCSPAttribute) { // TODO(antoniosartori): It would be safer to block loading iframes with // invalid 'csp' attribute. @@ -557,9 +558,10 @@ GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( mojom::blink::ConsoleMessageSource::kOther, mojom::blink::ConsoleMessageLevel::kError, - "iframe trusttoken attribute was invalid JSON: " + parse_error.message + - String::Format(" (line %d, col %d)", parse_error.line, - parse_error.column))); + WTF::StrCat({"iframe trusttoken attribute was invalid JSON: ", + parse_error.message, " (line ", + String::Number(parse_error.line), ", col ", + String::Number(parse_error.column), ")"}))); return nullptr; }
diff --git a/third_party/blink/renderer/core/html/html_marquee_element.cc b/third_party/blink/renderer/core/html/html_marquee_element.cc index 55f5f0f..c28f3f1 100644 --- a/third_party/blink/renderer/core/html/html_marquee_element.cc +++ b/third_party/blink/renderer/core/html/html_marquee_element.cc
@@ -50,6 +50,7 @@ #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" namespace blink { @@ -177,10 +178,10 @@ void HTMLMarqueeElement::setLoop(int value, ExceptionState& exception_state) { if (value <= 0 && value != -1) { - exception_state.ThrowDOMException(DOMExceptionCode::kIndexSizeError, - "The provided value (" + - String::Number(value) + - ") is neither positive nor -1."); + exception_state.ThrowDOMException( + DOMExceptionCode::kIndexSizeError, + WTF::StrCat({"The provided value (", String::Number(value), + ") is neither positive nor -1."})); return; } SetIntegralAttribute(html_names::kLoopAttr, value);
diff --git a/third_party/blink/renderer/core/html/html_plugin_element.cc b/third_party/blink/renderer/core/html/html_plugin_element.cc index d9a7fbd..2c1be4d 100644 --- a/third_party/blink/renderer/core/html/html_plugin_element.cc +++ b/third_party/blink/renderer/core/html/html_plugin_element.cc
@@ -67,6 +67,7 @@ #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" namespace blink { @@ -867,10 +868,9 @@ MakeGarbageCollected<ConsoleMessage>( mojom::blink::ConsoleMessageSource::kSecurity, mojom::blink::ConsoleMessageLevel::kError, - "Failed to load '" + url.ElidedString() + - "' as a plugin, because the " - "frame into which the plugin " - "is loading is sandboxed.")); + WTF::StrCat({"Failed to load '", url.ElidedString(), + "' as a plugin, because the frame into which the " + "plugin is loading is sandboxed."}))); return false; } return true;
diff --git a/third_party/blink/renderer/core/html/html_table_element.cc b/third_party/blink/renderer/core/html/html_table_element.cc index 4d0bafa..9e258563 100644 --- a/third_party/blink/renderer/core/html/html_table_element.cc +++ b/third_party/blink/renderer/core/html/html_table_element.cc
@@ -49,6 +49,7 @@ #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/weborigin/referrer.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" namespace blink { @@ -233,7 +234,8 @@ if (index < -1) { exception_state.ThrowDOMException( DOMExceptionCode::kIndexSizeError, - "The index provided (" + String::Number(index) + ") is less than -1."); + WTF::StrCat({"The index provided (", String::Number(index), + ") is less than -1."})); return; } @@ -253,9 +255,9 @@ if (!row) { exception_state.ThrowDOMException( DOMExceptionCode::kIndexSizeError, - "The index provided (" + String::Number(index) + - ") is greater than the number of rows in the table (" + - String::Number(i) + ")."); + WTF::StrCat({"The index provided (", String::Number(index), + ") is greater than the number of rows in the table (", + String::Number(i), ")."})); return; } row->remove(exception_state);
diff --git a/third_party/blink/renderer/core/html/html_view_source_document.cc b/third_party/blink/renderer/core/html/html_view_source_document.cc index 065d54a..f484a92 100644 --- a/third_party/blink/renderer/core/html/html_view_source_document.cc +++ b/third_party/blink/renderer/core/html/html_view_source_document.cc
@@ -24,6 +24,8 @@ #include "third_party/blink/renderer/core/html/html_view_source_document.h" +#include "third_party/blink/public/common/view_source/rendering_preferences.h" +#include "third_party/blink/public/mojom/persistent_renderer_prefs.mojom-blink.h" #include "third_party/blink/public/strings/grit/blink_strings.h" #include "third_party/blink/renderer/core/css/css_value_id_mappings.h" #include "third_party/blink/renderer/core/dom/events/event.h" @@ -54,16 +56,32 @@ namespace blink { +static const char* const kLineWrapClass = "line-wrap"; + class ViewSourceEventListener : public NativeEventListener { public: ViewSourceEventListener(HTMLTableElement* table, HTMLInputElement* checkbox) : table_(table), checkbox_(checkbox) {} - void Invoke(ExecutionContext*, Event* event) override { + void Invoke(ExecutionContext* execution_context, Event* event) override { DCHECK_EQ(event->type(), event_type_names::kChange); - table_->setAttribute(html_names::kClassAttr, checkbox_->Checked() - ? AtomicString("line-wrap") - : g_empty_atom); + table_->setAttribute( + html_names::kClassAttr, + checkbox_->Checked() ? AtomicString(kLineWrapClass) : g_empty_atom); + +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA) + // TODO(crbug.com/40255878): The service is implemented in Chrome, so it may + // not be provided in other embedders. Ensure that case is handled properly. + // TODO(crbug.com/415945840): Implement the PersistentRendererPrefsService + // for Android WebViews, and remove the Android part of the above guard. + mojo::Remote<mojom::blink::PersistentRendererPrefsService> + persistent_renderer_prefs_service; + execution_context->GetBrowserInterfaceBroker().GetInterface( + persistent_renderer_prefs_service.BindNewPipeAndPassReceiver()); + DCHECK(persistent_renderer_prefs_service); + persistent_renderer_prefs_service->SetViewSourceLineWrapping( + checkbox_->Checked()); +#endif } void Trace(Visitor* visitor) const override { @@ -124,6 +142,12 @@ /*use_capture=*/false); checkbox->setAttribute(html_names::kAriaLabelAttr, WTF::AtomicString(Locale::DefaultLocale().QueryString( IDS_VIEW_SOURCE_LINE_WRAP))); + + if (ViewSourceLineWrappingPreference::Get()) { + table->setAttribute(html_names::kClassAttr, AtomicString(kLineWrapClass)); + checkbox->SetChecked(true); + } + auto* label = MakeGarbageCollected<HTMLLabelElement>(*this); label->ParserAppendChild( Text::Create(*this, WTF::AtomicString(Locale::DefaultLocale().QueryString(
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc index 87d3407..b98d99ae 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element.cc +++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -122,6 +122,7 @@ #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/functional.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" #include "third_party/blink/renderer/platform/wtf/vector.h" #include "ui/accessibility/accessibility_features.h" #include "ui/display/screen_info.h" @@ -205,8 +206,9 @@ if (url.GetString().length() < kMaximumURLLengthForLogging) return url.GetString(); - return url.GetString().GetString().Substring(0, kMaximumURLLengthForLogging) + - "..."; + return WTF::StrCat( + {url.GetString().GetString().Substring(0, kMaximumURLLengthForLogging), + "..."}); } DocumentElementSetMap& DocumentToElementSetMap() { @@ -2785,8 +2787,8 @@ // DOMException and don't update the value. exception_state.ThrowDOMException( DOMExceptionCode::kNotSupportedError, - "The provided playback rate (" + String::Number(rate) + - ") is not in the " + "supported playback range."); + WTF::StrCat({"The provided playback rate (", String::Number(rate), + ") is not in the supported playback range."})); // Do not update |playback_rate_|. return;
diff --git a/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc b/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc index 1b0b8e51..7d0eb82 100644 --- a/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc +++ b/third_party/blink/renderer/core/html/parser/html_srcset_parser.cc
@@ -48,7 +48,7 @@ #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/text/character_visitor.h" #include "third_party/blink/renderer/platform/wtf/text/parsing_utilities.h" -#include "third_party/blink/renderer/platform/wtf/text/string_builder.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" #include "third_party/blink/renderer/platform/wtf/text/string_to_number.h" namespace blink { @@ -203,13 +203,12 @@ static void SrcsetError(Document* document, String message) { if (document && document->GetFrame()) { - StringBuilder warning_message; - warning_message.Append("Failed parsing 'srcset' attribute value since "); - warning_message.Append(message); document->GetFrame()->Console().AddMessage( MakeGarbageCollected<ConsoleMessage>( mojom::ConsoleMessageSource::kOther, - mojom::ConsoleMessageLevel::kWarning, warning_message.ToString())); + mojom::ConsoleMessageLevel::kWarning, + WTF::StrCat( + {"Failed parsing 'srcset' attribute value since ", message}))); } } @@ -341,10 +340,11 @@ MakeGarbageCollected<ConsoleMessage>( mojom::ConsoleMessageSource::kOther, mojom::ConsoleMessageLevel::kWarning, - String("Dropped srcset candidate ") + - JSONValue::QuoteString(String(attribute_span.subspan( - image_url_start, - image_url_end - image_url_start))))); + WTF::StrCat( + {"Dropped srcset candidate ", + JSONValue::QuoteString(String(attribute_span.subspan( + image_url_start, + image_url_end - image_url_start)))}))); } } continue;
diff --git a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc index 3e2fe10..0a2de968 100644 --- a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc +++ b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
@@ -62,6 +62,7 @@ #include "third_party/blink/renderer/platform/text/platform_locale.h" #include "third_party/blink/renderer/platform/wtf/text/character_names.h" #include "third_party/blink/renderer/platform/wtf/text/character_visitor.h" +#include "third_party/blink/renderer/platform/wtf/text/strcat.h" #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h" namespace blink { @@ -611,7 +612,8 @@ for (size_t i = 0; i < names.size(); ++i) { const QualifiedName& name = *names[i]; const AtomicString& local_name = name.LocalName(); - AtomicString prefix_colon_local_name = prefix + ':' + local_name; + AtomicString prefix_colon_local_name = + AtomicString(WTF::StrCat({prefix, ":", local_name})); QualifiedName name_with_prefix(prefix, local_name, name.NamespaceURI()); map->insert(prefix_colon_local_name, name_with_prefix); } @@ -1599,11 +1601,13 @@ tree_.OpenElements()->TopNode()->AddConsoleMessage( mojom::blink::ConsoleMessageSource::kJavaScript, mojom::blink::ConsoleMessageLevel::kWarning, - "A " + token->GetName() + - " tag was parsed inside of a <select> which caused a " - "</select> to be inserted before this tag. " - "This is not valid HTML and the behavior may be changed in " - "future versions of chrome."); + WTF::StrCat( + {"A ", token->GetName(), + " tag was parsed inside of a <select> which caused a " + "</select> to be inserted before this tag. " + "This is not valid HTML and the behavior may be changed " + "in " + "future versions of chrome."})); } return; } @@ -1646,11 +1650,12 @@ tree_.OpenElements()->TopNode()->AddConsoleMessage( mojom::blink::ConsoleMessageSource::kJavaScript, mojom::blink::ConsoleMessageLevel::kWarning, - "A " + token->GetName() + - " tag was parsed inside of a <select> which was not " - "inserted into the document. This is not valid HTML and " - "the behavior may be changed in future versions of " - "chrome."); + WTF::StrCat( + {"A ", token->GetName(), + " tag was parsed inside of a <select> which was not " + "inserted into the document. This is not valid HTML and " + "the behavior may be changed in future versions of " + "chrome."})); } break; }
diff --git a/third_party/blink/renderer/core/html/resources/html.css b/third_party/blink/renderer/core/html/resources/html.css index 4ad8b8a..f1747b3 100644 --- a/third_party/blink/renderer/core/html/resources/html.css +++ b/third_party/blink/renderer/core/html/resources/html.css
@@ -974,10 +974,6 @@ select:-internal-list-box { appearance: auto; align-items: flex-start; - @supports not blink-feature(CSSLogicalOverflow) { - -internal-overflow-inline: hidden; - -internal-overflow-block: scroll; - } overflow-inline: hidden; overflow-block: scroll; vertical-align: text-bottom;
diff --git a/third_party/blink/renderer/core/inspector/inspector_ghost_rules.cc b/third_party/blink/renderer/core/inspector/inspector_ghost_rules.cc index 5c7a0a5..e594d66 100644 --- a/third_party/blink/renderer/core/inspector/inspector_ghost_rules.cc +++ b/third_party/blink/renderer/core/inspector/inspector_ghost_rules.cc
@@ -122,18 +122,20 @@ CSSRule& rule, wtf_size_t index) { if (IsA<CSSStyleRule>(rule)) { - return To<CSSStyleRule>(rule).QuietlyInsertRule(&execution_context, - "--dummy:1", index); + To<CSSStyleRule>(rule).QuietlyInsertRule(&execution_context, "--dummy:1", + index); + } else { + To<CSSGroupingRule>(rule).QuietlyInsertRule(&execution_context, "--dummy:1", + index); } - return To<CSSGroupingRule>(rule).QuietlyInsertRule(&execution_context, - "--dummy:1", index); } void QuietlyDeleteRule(CSSRule& rule, wtf_size_t index) { if (IsA<CSSStyleRule>(rule)) { - return To<CSSStyleRule>(rule).QuietlyDeleteRule(index); + To<CSSStyleRule>(rule).QuietlyDeleteRule(index); + } else { + To<CSSGroupingRule>(rule).QuietlyDeleteRule(index); } - return To<CSSGroupingRule>(rule).QuietlyDeleteRule(index); } wtf_size_t NumItems(CSSRule& rule) {
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 06d4ccd..49fa8f6 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -1045,6 +1045,22 @@ return ClientHeight(); } +LayoutUnit LayoutBox::OffsetWidth() const { + NOT_DESTROYED(); + if (RuntimeEnabledFeatures::LayoutBoxVisualLocationEnabled()) { + return LayoutBoxModelObject::OffsetWidth(); + } + return Size().width; +} + +LayoutUnit LayoutBox::OffsetHeight() const { + NOT_DESTROYED(); + if (RuntimeEnabledFeatures::LayoutBoxVisualLocationEnabled()) { + return LayoutBoxModelObject::OffsetHeight(); + } + return Size().height; +} + bool LayoutBox::UsesOverlayScrollbars() const { NOT_DESTROYED(); if (StyleRef().HasCustomScrollbarStyle(DynamicTo<Element>(GetNode()))) { @@ -4504,6 +4520,33 @@ location_container ? location_container : LocationContainer()); } +PhysicalRect LayoutBox::BoundingBoxRelativeToFirstFragment() const { + NOT_DESTROYED(); + PhysicalRect bounding_rect; + const PhysicalBoxFragment* first_fragment = nullptr; + for (const PhysicalBoxFragment& fragment : PhysicalFragments()) { + PhysicalOffset offset; + if (!first_fragment) { + first_fragment = &fragment; + } else { + offset = fragment.OffsetFromRootFragmentationContext() - + first_fragment->OffsetFromRootFragmentationContext(); + } + PhysicalRect fragment_rect(offset, fragment.Size()); + bounding_rect.UniteEvenIfEmpty(fragment_rect); + + if (const BlockBreakToken* break_token = fragment.GetBreakToken()) { + if (break_token->IsAtBlockEnd()) { + // Ignore subsequent fragments that are just there to hold overflowing + // children. + break; + } + } + } + + return bounding_rect; +} + bool LayoutBox::IsReadingFlowContainer() const { NOT_DESTROYED(); if (!RuntimeEnabledFeatures::CSSReadingFlowEnabled()) {
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h index 40c10b80..ece8679 100644 --- a/third_party/blink/renderer/core/layout/layout_box.h +++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -455,14 +455,8 @@ // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines // (LayoutFlow) to return the remaining width on a given line (and the height // of a single line). - LayoutUnit OffsetWidth() const final { - NOT_DESTROYED(); - return Size().width; - } - LayoutUnit OffsetHeight() const final { - NOT_DESTROYED(); - return Size().height; - } + LayoutUnit OffsetWidth() const final; + LayoutUnit OffsetHeight() const final; bool UsesOverlayScrollbars() const; @@ -917,6 +911,8 @@ virtual PhysicalOffset PhysicalLocation( const LayoutBox* location_container = nullptr) const; + PhysicalRect BoundingBoxRelativeToFirstFragment() const override; + bool HasSelfVisualOverflow() const { NOT_DESTROYED(); return VisualOverflowIsSet() &&
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc index db71514..c067ca7 100644 --- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc +++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -349,6 +349,18 @@ SetNeedsPaintPropertyUpdate(); } +LayoutUnit LayoutBoxModelObject::OffsetWidth() const { + NOT_DESTROYED(); + DCHECK(RuntimeEnabledFeatures::LayoutBoxVisualLocationEnabled()); + return BoundingBoxRelativeToFirstFragment().size.width; +} + +LayoutUnit LayoutBoxModelObject::OffsetHeight() const { + NOT_DESTROYED(); + DCHECK(RuntimeEnabledFeatures::LayoutBoxVisualLocationEnabled()); + return BoundingBoxRelativeToFirstFragment().size.height; +} + bool LayoutBoxModelObject::HasSelfPaintingLayer() const { NOT_DESTROYED(); return Layer() && Layer()->IsSelfPaintingLayer();
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.h b/third_party/blink/renderer/core/layout/layout_box_model_object.h index ec149a5..4ea00d6 100644 --- a/third_party/blink/renderer/core/layout/layout_box_model_object.h +++ b/third_party/blink/renderer/core/layout/layout_box_model_object.h
@@ -140,8 +140,14 @@ // height of a single line). virtual LayoutUnit OffsetLeft(const Element*) const = 0; virtual LayoutUnit OffsetTop(const Element*) const = 0; - virtual LayoutUnit OffsetWidth() const = 0; - virtual LayoutUnit OffsetHeight() const = 0; + // TODO(crbug.com/40855022): These two don't need to be virtual when the + // legacy code is gone. + virtual LayoutUnit OffsetWidth() const; + virtual LayoutUnit OffsetHeight() const; + + // Return the bounding box of all fragments generated by this box, relatively + // to the top/left of the first fragment. + virtual PhysicalRect BoundingBoxRelativeToFirstFragment() const = 0; bool HasSelfPaintingLayer() const; PaintLayer* Layer() const {
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc index 10eb7ce..7b9e9fd 100644 --- a/third_party/blink/renderer/core/layout/layout_image.cc +++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -332,7 +332,7 @@ DEVTOOLS_TIMELINE_TRACE_EVENT_WITH_CATEGORIES( TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage", inspector_paint_image_event::Data, this, *image_content); - return image_content->GetImage()->CurrentFrameKnownToBeOpaque(); + return image_content->GetImage()->IsOpaque(); } bool LayoutImage::ComputeBackgroundIsKnownToBeObscured() const {
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc index c3f0f9ce..1a3e9ce 100644 --- a/third_party/blink/renderer/core/layout/layout_inline.cc +++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -601,14 +601,41 @@ LayoutUnit LayoutInline::OffsetWidth() const { NOT_DESTROYED(); + if (RuntimeEnabledFeatures::LayoutBoxVisualLocationEnabled()) { + return LayoutBoxModelObject::OffsetWidth(); + } return PhysicalLinesBoundingBox().Width(); } LayoutUnit LayoutInline::OffsetHeight() const { NOT_DESTROYED(); + if (RuntimeEnabledFeatures::LayoutBoxVisualLocationEnabled()) { + return LayoutBoxModelObject::OffsetHeight(); + } return PhysicalLinesBoundingBox().Height(); } +PhysicalRect LayoutInline::BoundingBoxRelativeToFirstFragment() const { + NOT_DESTROYED(); + DCHECK(RuntimeEnabledFeatures::LayoutBoxVisualLocationEnabled()); + DCHECK(IsInLayoutNGInlineFormattingContext()); + InlineCursor cursor; + cursor.MoveToIncludingCulledInline(*this); + PhysicalRect bounding_box; + std::optional<PhysicalOffset> first_fragment_offset; + for (; cursor; cursor.MoveToNextForSameLayoutObject()) { + PhysicalRect rect = cursor.CurrentRectInFirstContainerFragment(); + if (!first_fragment_offset) { + // All fragment rectangles need to be relative to the first container + // fragment. + first_fragment_offset = rect.offset; + } + rect.offset -= *first_fragment_offset; + bounding_box.UniteIfNonZero(rect); + } + return bounding_box; +} + static LayoutUnit ComputeMargin(const LayoutInline* layout_object, const Length& margin) { if (margin.IsFixed()) @@ -762,6 +789,9 @@ InlineCursor cursor; cursor.MoveToIncludingCulledInline(*this); PhysicalRect bounding_box; + // TODO(layout-dev): Current().RectInContainerFragment() is unsuitable when + // there are multiple container fragments (block fragmentation). Use + // CurrentRectInFirstContainerFragment() instead. for (; cursor; cursor.MoveToNextForSameLayoutObject()) bounding_box.UniteIfNonZero(cursor.Current().RectInContainerFragment()); return bounding_box; @@ -775,6 +805,9 @@ PhysicalRect result; InlineCursor cursor; cursor.MoveToIncludingCulledInline(*this); + // TODO(layout-dev): Current().OffsetInContainerFragment() is unsuitable + // when there are multiple container fragments (block fragmentation). Use + // CurrentOffsetInFirstContainerFragment() instead. for (; cursor; cursor.MoveToNextForSameLayoutObject()) { PhysicalRect child_rect = cursor.Current().InkOverflowRect(); child_rect.offset += cursor.Current().OffsetInContainerFragment();
diff --git a/third_party/blink/renderer/core/layout/layout_inline.h b/third_party/blink/renderer/core/layout/layout_inline.h index e071cb3..371524e 100644 --- a/third_party/blink/renderer/core/layout/layout_inline.h +++ b/third_party/blink/renderer/core/layout/layout_inline.h
@@ -302,6 +302,8 @@ LayoutUnit OffsetWidth() const final; LayoutUnit OffsetHeight() const final; + PhysicalRect BoundingBoxRelativeToFirstFragment() const final; + bool MapToVisualRectInAncestorSpaceInternal( const LayoutBoxModelObject* ancestor, TransformState&,
diff --git a/third_party/blink/renderer/core/layout/table/layout_table_column.cc b/third_party/blink/renderer/core/layout/table/layout_table_column.cc index b88fe93b..299cedcda 100644 --- a/third_party/blink/renderer/core/layout/table/layout_table_column.cc +++ b/third_party/blink/renderer/core/layout/table/layout_table_column.cc
@@ -243,6 +243,29 @@ return offset; } +PhysicalRect LayoutTableColumn::BoundingBoxRelativeToFirstFragment() const { + NOT_DESTROYED(); + DCHECK(RuntimeEnabledFeatures::LayoutBoxVisualLocationEnabled()); + std::optional<PhysicalOffset> first_offset_from_fragmentation_context_root; + PhysicalRect bounding_rect; + + ForAllSynthesizedFragments([&](const SynthesizedFragment& fragment) -> bool { + PhysicalOffset offset = + fragment.additional_offset_from_table_fragment + fragment.rect.offset + + fragment.table_fragment.OffsetFromRootFragmentationContext(); + if (!first_offset_from_fragmentation_context_root) { + first_offset_from_fragmentation_context_root = offset; + } + // Make offsets relative to the first fragment. + offset -= *first_offset_from_fragmentation_context_root; + PhysicalRect rect(offset, fragment.rect.size); + bounding_rect.UniteEvenIfEmpty(rect); + return true; + }); + + return bounding_rect; +} + void LayoutTableColumn::QuadsInAncestorInternal( Vector<gfx::QuadF>& quads, const LayoutBoxModelObject* ancestor,
diff --git a/third_party/blink/renderer/core/layout/table/layout_table_column.h b/third_party/blink/renderer/core/layout/table/layout_table_column.h index 16b8079..d81eeb4 100644 --- a/third_party/blink/renderer/core/layout/table/layout_table_column.h +++ b/third_party/blink/renderer/core/layout/table/layout_table_column.h
@@ -42,6 +42,7 @@ PhysicalSize Size() const override; PhysicalOffset PhysicalLocation(const LayoutBox*) const override; + PhysicalRect BoundingBoxRelativeToFirstFragment() const override; void QuadsInAncestorInternal(Vector<gfx::QuadF>&, const LayoutBoxModelObject* ancestor,
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc index de6b6b3..0427ebe3 100644 --- a/third_party/blink/renderer/core/loader/base_fetch_context.cc +++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -260,7 +260,10 @@ return ResourceRequestBlockedReason::kCSP; } - if (!IntegrityPolicy::AllowRequest(GetExecutionContext(), request_destination, + CHECK(!GetResourceFetcherProperties().IsDetached() || + resource_request.GetKeepalive() || redirect_info.has_value()); + if (RuntimeEnabledFeatures::IntegrityPolicyScriptEnabled() && + !IntegrityPolicy::AllowRequest(GetExecutionContext(), request_destination, request_mode, options.integrity_metadata, url)) { return ResourceRequestBlockedReason::kIntegrity;
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc index 43aac37..f0747f6 100644 --- a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc +++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
@@ -668,7 +668,7 @@ } bool ImageResourceContent::IsPaintedFirstFrame() const { - return IsAnimatedImage() && image_->CurrentFrameIsComplete(); + return IsAnimatedImage() && image_->FirstFrameIsComplete(); } bool ImageResourceContent::TimingAllowPassed() const {
diff --git a/third_party/blink/renderer/core/page/drag_image_test.cc b/third_party/blink/renderer/core/page/drag_image_test.cc index 35f7275..d8122805 100644 --- a/third_party/blink/renderer/core/page/drag_image_test.cc +++ b/third_party/blink/renderer/core/page/drag_image_test.cc
@@ -62,7 +62,7 @@ return gfx::Size(image_->width(), image_->height()); } - bool CurrentFrameKnownToBeOpaque() override { return false; } + bool IsOpaque() override { return false; } void DestroyDecodedData() override { // Image pure virtual stub.
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc index cacb6ca..ef575f1 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -3243,10 +3243,6 @@ void PaintLayerScrollableArea:: UpdateSnappedTargetsAndEnqueueScrollSnapChange() { - if (!RuntimeEnabledFeatures::CSSScrollSnapChangeEventEnabled() && - !RuntimeEnabledFeatures::CSSSnapContainerQueriesEnabled()) { - return; - } const cc::SnapContainerData* container_data = GetSnapContainerData(); if (!container_data) { return; @@ -3390,9 +3386,6 @@ void PaintLayerScrollableArea::CreateAndSetSnappedQueryScrollSnapshotIfNeeded( cc::TargetSnapAreaElementIds ids) { - if (!RuntimeEnabledFeatures::CSSSnapContainerQueriesEnabled()) { - return; - } Element* target_x = nullptr; if (ids.x) { target_x = DynamicTo<Element>(
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index 2b3ffbd..489d8790 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -90,6 +90,7 @@ #include "third_party/blink/renderer/platform/geometry/path.h" #include "third_party/blink/renderer/platform/geometry/path_builder.h" #include "third_party/blink/renderer/platform/graphics/graphics_context.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/text/capitalize.h" #include "third_party/blink/renderer/platform/text/character.h" #include "third_party/blink/renderer/platform/text/quotes_data.h" @@ -1947,8 +1948,14 @@ switch (TextTransform()) { case ETextTransform::kNone: return text; - case ETextTransform::kCapitalize: + case ETextTransform::kCapitalize: { + if (RuntimeEnabledFeatures::ICUCapitalizationEnabled()) { + const LayoutLocale* locale = GetFontDescription().Locale(); + CaseMap case_map(locale ? locale->CaseMapLocale() : CaseMap::Locale()); + return case_map.ToTitle(text, offset_map, previous_character); + } return Capitalize(text, previous_character); + } case ETextTransform::kUppercase: { const LayoutLocale* locale = GetFontDescription().Locale(); CaseMap case_map(locale ? locale->CaseMapLocale() : CaseMap::Locale());
diff --git a/third_party/blink/renderer/core/style/style_fetched_image.cc b/third_party/blink/renderer/core/style/style_fetched_image.cc index 1f6bba7..19a3e2b8 100644 --- a/third_party/blink/renderer/core/style/style_fetched_image.cc +++ b/third_party/blink/renderer/core/style/style_fetched_image.cc
@@ -97,7 +97,7 @@ CSSValue* StyleFetchedImage::CssValue() const { return MakeGarbageCollected<CSSImageValue>( - *url_data_->MakeAbsolute(), const_cast<StyleFetchedImage*>(this)); + *url_data_->MakeComputed(), const_cast<StyleFetchedImage*>(this)); } CSSValue* StyleFetchedImage::ComputedCSSValue(const ComputedStyle&, @@ -255,7 +255,7 @@ bool StyleFetchedImage::KnownToBeOpaque(const Document&, const ComputedStyle&) const { - return image_->GetImage()->CurrentFrameKnownToBeOpaque(); + return image_->GetImage()->IsOpaque(); } void StyleFetchedImage::LoadDeferredImage(const Document& document) {
diff --git a/third_party/blink/renderer/core/style/style_mask_source_image.cc b/third_party/blink/renderer/core/style/style_mask_source_image.cc index a7767757..9ce12d3 100644 --- a/third_party/blink/renderer/core/style/style_mask_source_image.cc +++ b/third_party/blink/renderer/core/style/style_mask_source_image.cc
@@ -36,7 +36,7 @@ const ComputedStyle& style, bool allow_visited_style, CSSValuePhase value_phase) const { - return resource_css_value_->ComputedCSSValueMaybeLocal(); + return resource_css_value_->ComputedCSSValue(); } bool StyleMaskSourceImage::CanRender() const {
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image.h b/third_party/blink/renderer/core/svg/graphics/svg_image.h index 6c4b2b4..e857e7b 100644 --- a/third_party/blink/renderer/core/svg/graphics/svg_image.h +++ b/third_party/blink/renderer/core/svg/graphics/svg_image.h
@@ -171,8 +171,7 @@ // to prune because these functions are not implemented yet. void DestroyDecodedData() override {} - // FIXME: Implement this to be less conservative. - bool CurrentFrameKnownToBeOpaque() override { return false; } + bool IsOpaque() override { return false; } class DrawInfo { STACK_ALLOCATED();
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h b/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h index 3fa2bee..8be66df 100644 --- a/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h +++ b/third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h
@@ -132,7 +132,7 @@ const ImageDrawOptions&) override; // FIXME: Implement this to be less conservative. - bool CurrentFrameKnownToBeOpaque() override { return false; } + bool IsOpaque() override { return false; } PaintImage PaintImageForCurrentFrame() override;
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.cc b/third_party/blink/renderer/core/workers/dedicated_worker.cc index 776fc5d..109afb8d 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker.cc +++ b/third_party/blink/renderer/core/workers/dedicated_worker.cc
@@ -291,6 +291,10 @@ /*is_top_level_navigation=*/false); } + if (script_request_url_.ProtocolIs("data")) { + GetExecutionContext()->CountUse(WebFeature::kDataUrlDedicatedWorker); + } + factory_client_->CreateWorkerHost( token_, script_request_url_, credentials_mode, WebFetchClientSettingsObject(*outside_fetch_client_settings_object_),
diff --git a/third_party/blink/renderer/core/workers/shared_worker.cc b/third_party/blink/renderer/core/workers/shared_worker.cc index daac3f1..dd8e0cb 100644 --- a/third_party/blink/renderer/core/workers/shared_worker.cc +++ b/third_party/blink/renderer/core/workers/shared_worker.cc
@@ -153,6 +153,10 @@ /*is_top_level_navigation=*/false); } + if (script_url.ProtocolIs("data")) { + context->CountUse(WebFeature::kDataUrlSharedWorker); + } + auto options = mojom::blink::WorkerOptions::New(); // The same_site_cookies setting defaults to kAll for first-party contexts // (allowing access to SameSite Lax and String cookies) and kNone in
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc index 34727f3..72d0573 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -1829,6 +1829,28 @@ } TEST_P(CanvasRenderingContext2DTestAccelerated, + ReleaseLostTransferableResource) { + CreateContext(kNonOpaque); + + ASSERT_TRUE(CanvasElement().GetOrCreateCanvasResourceProvider()); + + // Invoking PrepareTransferableResource() has a precondition that a CC layer + // is present. + ASSERT_TRUE(CanvasElement().GetOrCreateCcLayerIfNeeded()); + + Context2D()->fillRect(3, 3, 1, 1); + + // Prepare a TransferableResource, then report the resource as lost. + // This test passes by not crashing and not triggering assertions. + viz::TransferableResource resource; + viz::ReleaseCallback release_callback; + ASSERT_TRUE(CanvasElement().PrepareTransferableResource(&resource, + &release_callback)); + bool lost_resource = true; + std::move(release_callback).Run(gpu::SyncToken(), lost_resource); +} + +TEST_P(CanvasRenderingContext2DTestAccelerated, NoRegenerationOfTransferableResourceWhenAlreadyInCcLayer) { CreateContext(kNonOpaque);
diff --git a/third_party/blink/renderer/modules/compute_pressure/pressure_client_impl.cc b/third_party/blink/renderer/modules/compute_pressure/pressure_client_impl.cc index 55bd3e4..ea446a8 100644 --- a/third_party/blink/renderer/modules/compute_pressure/pressure_client_impl.cc +++ b/third_party/blink/renderer/modules/compute_pressure/pressure_client_impl.cc
@@ -9,8 +9,9 @@ #include "base/notreached.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" -#include "services/device/public/mojom/pressure_manager.mojom-blink.h" #include "services/device/public/mojom/pressure_update.mojom-blink.h" +#include "third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom-blink.h" +#include "third_party/blink/public/mojom/compute_pressure/web_pressure_update.mojom-blink.h" #include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/timing/dom_window_performance.h" @@ -62,7 +63,7 @@ PressureClientImpl::~PressureClientImpl() = default; void PressureClientImpl::OnPressureUpdated( - device::mojom::blink::PressureUpdatePtr update) { + mojom::blink::WebPressureUpdatePtr update) { auto source = PressureSourceToV8PressureSource(update->source); // New observers may be created and added. Take a snapshot so as // to safely iterate. @@ -85,7 +86,7 @@ } } -mojo::PendingAssociatedRemote<device::mojom::blink::PressureClient> +mojo::PendingAssociatedRemote<mojom::blink::WebPressureClient> PressureClientImpl::BindNewEndpointAndPassRemote( scoped_refptr<base::SequencedTaskRunner> task_runner) { auto associated_pending_remote =
diff --git a/third_party/blink/renderer/modules/compute_pressure/pressure_client_impl.h b/third_party/blink/renderer/modules/compute_pressure/pressure_client_impl.h index 56a2be25..54ae056 100644 --- a/third_party/blink/renderer/modules/compute_pressure/pressure_client_impl.h +++ b/third_party/blink/renderer/modules/compute_pressure/pressure_client_impl.h
@@ -7,8 +7,8 @@ #include "base/time/time.h" #include "mojo/public/cpp/bindings/associated_receiver.h" -#include "services/device/public/mojom/pressure_manager.mojom-blink-forward.h" -#include "services/device/public/mojom/pressure_update.mojom-blink-forward.h" +#include "third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom-blink.h" +#include "third_party/blink/public/mojom/compute_pressure/web_pressure_update.mojom-blink.h" #include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" #include "third_party/blink/renderer/modules/compute_pressure/pressure_observer.h" @@ -31,7 +31,7 @@ class MODULES_EXPORT PressureClientImpl final : public GarbageCollected<PressureClientImpl>, public ExecutionContextClient, - public device::mojom::blink::PressureClient { + public mojom::blink::WebPressureClient { public: // kUninitialized: receiver_ is not bound. // kInitializing: receiver_ is bound but the remote side is not bound. @@ -44,8 +44,8 @@ PressureClientImpl(const PressureClientImpl&) = delete; PressureClientImpl& operator=(const PressureClientImpl&) = delete; - // device::mojom::blink::PressureClient implementation. - void OnPressureUpdated(device::mojom::blink::PressureUpdatePtr) override; + // mojom::WebPressureClient implementation. + void OnPressureUpdated(mojom::blink::WebPressureUpdatePtr) override; State state() const { return state_; } void set_state(State state) { state_ = state; } @@ -56,7 +56,7 @@ return observers_; } - mojo::PendingAssociatedRemote<device::mojom::blink::PressureClient> + mojo::PendingAssociatedRemote<mojom::blink::WebPressureClient> BindNewEndpointAndPassRemote(scoped_refptr<base::SequencedTaskRunner>); void Reset(); @@ -68,7 +68,7 @@ WeakMember<PressureObserverManager> manager_; - HeapMojoAssociatedReceiver<device::mojom::blink::PressureClient, + HeapMojoAssociatedReceiver<mojom::blink::WebPressureClient, PressureClientImpl> associated_receiver_;
diff --git a/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test.cc b/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test.cc index 921e7c5e..1e25631 100644 --- a/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test.cc +++ b/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test.cc
@@ -179,7 +179,7 @@ // they are all dispatched immediately even if we do not advance time. EXPECT_EQ(pressure_records.size(), i); const auto& state = kPressureStates[i]; - pressure_service.SendUpdate(device::mojom::blink::PressureUpdate::New( + pressure_service.SendUpdate(mojom::blink::WebPressureUpdate::New( device::mojom::blink::PressureSource::kCpu, state, base::TimeTicks::Now())); task_environment.FastForwardBy(base::Milliseconds(0)); @@ -209,7 +209,7 @@ // This update will not be sent immediately and will be queued by the rate // obfuscation code instead. - pressure_service.SendUpdate(device::mojom::blink::PressureUpdate::New( + pressure_service.SendUpdate(mojom::blink::WebPressureUpdate::New( device::mojom::blink::PressureSource::kCpu, PressureState::kNominal, base::TimeTicks::Now())); task_environment.FastForwardBy(base::Milliseconds(0)); @@ -222,7 +222,7 @@ // Test the what happens when an update is sent while we are already under // penalty: the new update must replace the previously queued one. - pressure_service.SendUpdate(device::mojom::blink::PressureUpdate::New( + pressure_service.SendUpdate(mojom::blink::WebPressureUpdate::New( device::mojom::blink::PressureSource::kCpu, PressureState::kFair, base::TimeTicks::Now())); // If we advance another 200ms, we are still 3600s short of the penalty @@ -252,7 +252,7 @@ const wtf_size_t original_callback_count = pressure_records.size(); // Send an update and verify it has been delivered with no delay again. - pressure_service.SendUpdate(device::mojom::blink::PressureUpdate::New( + pressure_service.SendUpdate(mojom::blink::WebPressureUpdate::New( device::mojom::blink::PressureSource::kCpu, PressureState::kSerious, base::TimeTicks::Now())); task_environment.FastForwardBy(base::Milliseconds(0)); @@ -293,7 +293,7 @@ // First update. task_environment.FastForwardBy(kDelayTime); - pressure_service.SendUpdate(device::mojom::blink::PressureUpdate::New( + pressure_service.SendUpdate(mojom::blink::WebPressureUpdate::New( device::mojom::blink::PressureSource::kCpu, PressureState::kCritical, base::TimeTicks::Now())); @@ -301,7 +301,7 @@ // Second update triggering the penalty. task_environment.FastForwardBy(kDelayTime); - pressure_service.SendUpdate(device::mojom::blink::PressureUpdate::New( + pressure_service.SendUpdate(mojom::blink::WebPressureUpdate::New( device::mojom::blink::PressureSource::kCpu, PressureState::kNominal, base::TimeTicks::Now())); // The number of seconds here should not exceed the penalty time, we just @@ -345,7 +345,7 @@ // First update. task_environment.FastForwardBy(kDelayTime); - pressure_service.SendUpdate(device::mojom::blink::PressureUpdate::New( + pressure_service.SendUpdate(mojom::blink::WebPressureUpdate::New( device::mojom::blink::PressureSource::kCpu, PressureState::kNominal, base::TimeTicks::Now())); @@ -353,7 +353,7 @@ // Second update triggering the penalty. task_environment.FastForwardBy(kDelayTime); - pressure_service.SendUpdate(device::mojom::blink::PressureUpdate::New( + pressure_service.SendUpdate(mojom::blink::WebPressureUpdate::New( device::mojom::blink::PressureSource::kCpu, PressureState::kCritical, base::TimeTicks::Now())); // The number of seconds here should not exceed the penalty time, we just
diff --git a/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test_utils.cc b/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test_utils.cc index 7c7c3c0..60dfff0 100644 --- a/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test_utils.cc +++ b/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test_utils.cc
@@ -7,6 +7,7 @@ #include "base/run_loop.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "services/device/public/mojom/pressure_update.mojom-blink.h" +#include "third_party/blink/public/mojom/compute_pressure/web_pressure_update.mojom-blink.h" #include "third_party/blink/public/platform/browser_interface_broker_proxy.h" #include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h" #include "third_party/blink/renderer/core/dom/document.h" @@ -29,7 +30,7 @@ void FakePressureService::AddClient( device::mojom::blink::PressureSource source, - mojo::PendingAssociatedRemote<device::mojom::blink::PressureClient> client, + mojo::PendingAssociatedRemote<mojom::blink::WebPressureClient> client, AddClientCallback callback) { client_remote_.Bind(std::move(client)); @@ -38,7 +39,7 @@ } void FakePressureService::SendUpdate( - device::mojom::blink::PressureUpdatePtr update) { + mojom::blink::WebPressureUpdatePtr update) { client_remote_->OnPressureUpdated(std::move(update)); }
diff --git a/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test_utils.h b/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test_utils.h index e43d39a..76ab034 100644 --- a/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test_utils.h +++ b/third_party/blink/renderer/modules/compute_pressure/pressure_observer_test_utils.h
@@ -10,6 +10,7 @@ #include "services/device/public/mojom/pressure_manager.mojom-blink.h" #include "services/device/public/mojom/pressure_update.mojom-blink-forward.h" #include "third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom-blink.h" +#include "third_party/blink/public/mojom/compute_pressure/web_pressure_update.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" namespace blink { @@ -25,13 +26,12 @@ void BindRequest(mojo::ScopedMessagePipeHandle handle); - void SendUpdate(device::mojom::blink::PressureUpdatePtr update); + void SendUpdate(mojom::blink::WebPressureUpdatePtr update); // mojom::blink::WebPressureManager implementation. void AddClient( device::mojom::blink::PressureSource source, - mojo::PendingAssociatedRemote<device::mojom::blink::PressureClient> - client, + mojo::PendingAssociatedRemote<mojom::blink::WebPressureClient> client, AddClientCallback callback) override; void Reset() { manager_receiver_.reset(); } @@ -39,7 +39,7 @@ private: void OnConnectionError(); - mojo::AssociatedRemote<device::mojom::blink::PressureClient> client_remote_; + mojo::AssociatedRemote<mojom::blink::WebPressureClient> client_remote_; mojo::Receiver<mojom::blink::WebPressureManager> manager_receiver_{this}; };
diff --git a/third_party/blink/renderer/modules/ml/BUILD.gn b/third_party/blink/renderer/modules/ml/BUILD.gn index 3729607f..8cd44900 100644 --- a/third_party/blink/renderer/modules/ml/BUILD.gn +++ b/third_party/blink/renderer/modules/ml/BUILD.gn
@@ -22,6 +22,10 @@ "webnn/ml_graph.h", "webnn/ml_graph_builder.cc", "webnn/ml_graph_builder.h", + "webnn/ml_graph_transform/ml_graph_transformer.cc", + "webnn/ml_graph_transform/ml_graph_transformer.h", + "webnn/ml_graph_transform/pipeline.cc", + "webnn/ml_graph_transform/pipeline.h", "webnn/ml_graph_type_converter.cc", "webnn/ml_graph_type_converter.h", "webnn/ml_graph_utils.cc",
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc index 94e1be7..e85dfb7 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
@@ -64,6 +64,7 @@ #include "third_party/blink/renderer/modules/ml/webnn/ml_constant_operand.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_error.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_graph.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/pipeline.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h" @@ -72,7 +73,6 @@ #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h" -#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/functional.h" @@ -1075,6 +1075,81 @@ return output; } +// Determines the input and output resources required for this computational +// graph by traversing the graph from `named_outputs` to its inputs. +// This may fail if the graph is not valid. +base::expected<std::pair<MLGraph::NamedOperandDescriptors, + MLGraph::NamedOperandDescriptors>, + String> +DetermineGraphConstraintsFromOutputs(const MLNamedOperands& named_outputs) { + // The outputs should not be empty. + if (named_outputs.empty()) { + return base::unexpected("At least one output needs to be provided."); + } + + // The queue and visited set of operators that help implement the + // breadth-first graph traversal: + // https://en.wikipedia.org/wiki/Breadth-first_search + HeapDeque<Member<const MLOperator>> operators_queue; + HeapHashSet<Member<const MLOperator>> visited_operators; + + MLGraph::NamedOperandDescriptors input_constraints; + MLGraph::NamedOperandDescriptors output_constraints; + + // Validate the named outputs, setup corresponding output resource info and + // initialize the queue and visited set with their dependent operators. + for (const auto& output : named_outputs) { + const auto& name = output.first; + const auto& operand = output.second; + if (operand->Kind() != blink_mojom::Operand::Kind::kOutput) { + return base::unexpected(String::Format( + "The operand with name \"%s\" is not an output operand.", + name.Utf8().c_str())); + } + // Setup resource info for this output operand. + output_constraints.insert(name, operand->Descriptor()); + visited_operators.insert(operand->Operator()); + operators_queue.push_back(operand->Operator()); + } + + // An input MLOperand may be used by more than one MLOperators. This set + // ensures an input MLOperand won't be validated multiple times. + HeapHashSet<Member<const MLOperand>> visited_input_operands; + while (operators_queue.size() > 0) { + const auto current_operator = operators_queue.TakeFirst(); + for (const auto& operand : current_operator->Inputs()) { + switch (operand->Kind()) { + case blink_mojom::Operand::Kind::kOutput: + if (!visited_operators.Contains(operand->Operator())) { + visited_operators.insert(operand->Operator()); + operators_queue.push_back(operand->Operator()); + } + break; + case blink_mojom::Operand::Kind::kInput: + if (visited_input_operands.Contains(operand)) { + continue; + } + visited_input_operands.insert(operand); + if (input_constraints.Contains(operand->Name())) { + return base::unexpected( + String::Format("The input name \"%s\" is duplicated.", + operand->Name().Utf8().c_str())); + } + input_constraints.insert(operand->Name(), operand->Descriptor()); + break; + case blink_mojom::Operand::Kind::kConstant: + if (visited_input_operands.Contains(operand)) { + continue; + } + visited_input_operands.insert(operand); + break; + } + } + } + return std::make_pair(std::move(input_constraints), + std::move(output_constraints)); +} + Vector<webnn::OperandId> GetInputs(const blink_mojom::Operation& operation) { switch (operation.which()) { case blink_mojom::Operation::Tag::kArgMinMax: @@ -1348,120 +1423,8 @@ } } -// Validate the graph and topologically sort operators by traversing the graph -// backwards from `named_outputs` to the inputs they depend on. If the graph is -// valid, the function returns a sorted list of operators and input/output -// constraints for the computational graph. Otherwise, it returns an error -// message. -base::expected<void, String> ValidateAndSortGraph( - const MLNamedOperands& named_outputs, - HeapVector<Member<const MLOperator>>& topo_sorted_operators, - MLGraph::NamedOperandDescriptors& input_constraints, - MLGraph::NamedOperandDescriptors& output_constraints) { - // A WebNN graph is represented by a directed acyclic graph (DAG) that has - // operators as vertices and operands as edges. The topological sorting is - // implemented by depth-first search (DFS) and visiting vertices in - // post-order. It means a vertex (operator) is visited (pushed to the back of - // the sorted list) after all its dependent vertices (operators) are visited. - // With that, it ensures operator 'j' appears before operator 'i' in the - // result, if 'i' depends on 'j'. The DFS algorithm is based on the - // non-recursive implementation of: - // https://en.wikipedia.org/wiki/Depth-first_search - - // An input MLOperand may be used by more than one MLOperators. This set - // ensures an input MLOperand won't be validated multiple times. - HeapHashSet<Member<const MLOperand>> visited_input_operands; - - // The to-visit stack and visited set for DFS graph traversal. - HeapDeque<Member<const MLOperator>> operators_to_visit; - HeapHashSet<Member<const MLOperator>> visited_operators; - // Enumerate output operands and initialize the to-visit stack with their - // dependent operators. - // The outputs should not be empty. - if (named_outputs.empty()) { - return base::unexpected("At least one output must be provided."); - } - for (const auto& output : named_outputs) { - const String& name = output.first; - const MLOperand* operand = output.second.Get(); - // Validate whether it is an output operand. - if (operand->Kind() != blink_mojom::Operand::Kind::kOutput) { - return base::unexpected(String::Format( - "The operand with name \"%s\" is not an output operand.", - name.Utf8().c_str())); - } - // Setup resource info for this output operand. - output_constraints.insert(name, operand->Descriptor()); - operators_to_visit.push_back(operand->Operator()); - } - while (operators_to_visit.size() > 0) { - // Get the current operator from the top of the to-visit stack. - const MLOperator* current_operator = operators_to_visit.back().Get(); - if (!visited_operators.Contains(current_operator)) { - // The current operator is not visited, check whether its dependent - // operators are visited or not. - bool skip_visit = false; - for (const auto& operand : current_operator->Inputs()) { - switch (operand->Kind()) { - case blink_mojom::Operand::Kind::kOutput: { - const MLOperator* dependent_operator = operand->Operator(); - CHECK(dependent_operator); - if (!visited_operators.Contains(dependent_operator)) { - // As there is an dependent operator is not visited, skip visiting - // this operator and push the dependent operator into the to-visit - // stack. - skip_visit = true; - operators_to_visit.push_back(dependent_operator); - } - break; - } - case blink_mojom::Operand::Kind::kInput: { - // If the operand has been validated, it doesn't need to be verified - // again. - if (visited_input_operands.Contains(operand)) { - continue; - } - visited_input_operands.insert(operand); - // If the operand is an input operand, validate its name is unique. - if (input_constraints.Contains(operand->Name())) { - return base::unexpected( - String::Format("The input name \"%s\" is duplicated.", - operand->Name().Utf8().c_str())); - } - // Setup resource info for this input operand. - input_constraints.insert(operand->Name(), operand->Descriptor()); - break; - } - case blink_mojom::Operand::Kind::kConstant: { - // If the operand has been validated, it doesn't need to be verified - // again. - if (visited_input_operands.Contains(operand)) { - continue; - } - visited_input_operands.insert(operand); - break; - } - } - } - if (!skip_visit) { - // When all dependent operators have been visited, visit the current - // operator and add it into the visited set. - topo_sorted_operators.push_back(current_operator); - visited_operators.insert(current_operator); - operators_to_visit.pop_back(); - } - } else { - // The current operator has already been visited. - operators_to_visit.pop_back(); - } - } - - return base::ok(); -} - base::expected<blink_mojom::GraphInfoPtr, String> BuildWebNNGraphInfo( const MLNamedOperands& named_outputs, - const HeapVector<Member<const MLOperator>>& topo_sorted_operators, const webnn::ContextProperties& context_properties) { // The `GraphInfo` represents an entire information of WebNN graph. auto graph_info = blink_mojom::GraphInfo::New(); @@ -1478,10 +1441,13 @@ operand_to_id_map.insert(operand, operand_id); } + HeapVector<Member<MLOperator>> topologically_sorted_operators = + GetOperatorsInTopologicalOrder(named_outputs); + // Visit the operators in topological order. For each operator, // 1, Create `mojo::Operand` for its input and output operands if needed. // 2, Create `mojo::Operator` with the id of input and output operands. - for (const auto& current_operator : topo_sorted_operators) { + for (const auto& current_operator : topologically_sorted_operators) { for (const auto& operand : current_operator->Inputs()) { if (operand_to_id_map.Contains(operand.Get())) { // The `mojo::Operand` is already converted with the MLOperand, skip it. @@ -1651,7 +1617,9 @@ MLContext* context, mojo::PendingAssociatedRemote<blink_mojom::WebNNGraphBuilder> pending_remote) - : ml_context_(context), remote_(execution_context) { + : execution_context_(execution_context), + ml_context_(context), + remote_(execution_context) { CHECK(base::FeatureList::IsEnabled( webnn::mojom::features::kWebMachineLearningNeuralNetwork)); @@ -1664,12 +1632,17 @@ MLGraphBuilder::~MLGraphBuilder() = default; void MLGraphBuilder::Trace(Visitor* visitor) const { + visitor->Trace(execution_context_); visitor->Trace(ml_context_); visitor->Trace(remote_); visitor->Trace(pending_resolver_); ScriptWrappable::Trace(visitor); } +ExecutionContext* MLGraphBuilder::GetExecutionContext() const { + return execution_context_.Get(); +} + MLContext* MLGraphBuilder::GetContext() const { return ml_context_.Get(); } @@ -1791,8 +1764,8 @@ HeapVector<Member<MLOperand>> inputs = {input, mean, variance}; // Adding the optional operands into inputs ensures the graph traversal - // algorithm ValidateAndSortGraph() works. For backends, the optional operands - // should be retrieved from the options instead of inputs. + // algorithm GetOperatorsInTopologicalOrder() works. For backends, the + // optional operands should be retrieved from the options instead of inputs. if (options->hasScale()) { inputs.push_back(options->scale()); } @@ -2372,8 +2345,8 @@ HeapVector<Member<MLOperand>> inputs = {input}; // Adding the optional operands into inputs ensures the graph traversal - // algorithm ValidateAndSortGraph() works. For backends, the optional operands - // should be retrieved from the options instead of inputs. + // algorithm GetOperatorsInTopologicalOrder() works. For backends, the + // optional operands should be retrieved from the options instead of inputs. if (options->hasScale()) { inputs.push_back(options->scale()); } @@ -2406,7 +2379,7 @@ HeapVector<Member<MLOperand>> inputs = {input}; // Adding the optional operands into inputs ensures the graph traversal - // algorithm ValidateAndSortGraph() works. For backends, the + // algorithm GetOperatorsInTopologicalOrder() works. For backends, the // optional operands should be retrieved from the options instead of inputs. if (options->hasScale()) { inputs.push_back(options->scale()); @@ -3225,10 +3198,9 @@ return output; } -ScriptPromise<MLGraph> MLGraphBuilder::build( - ScriptState* script_state, - const MLNamedOperands& named_outputs, - ExceptionState& exception_state) { +ScriptPromise<MLGraph> MLGraphBuilder::build(ScriptState* script_state, + MLNamedOperands& named_outputs, + ExceptionState& exception_state) { webnn::ScopedTrace scoped_trace("MLGraphBuilder::build"); base::expected<void, String> validation_result = ValidateGraphBuilderState(); if (!validation_result.has_value()) { @@ -3260,20 +3232,34 @@ return EmptyPromise(); } - scoped_trace.AddStep("ValidateAndSortGraph"); - // The topologically sorted operators. - HeapVector<Member<const MLOperator>> topo_sorted_operators; - // The input and output constraints for the computational graph. - MLGraph::NamedOperandDescriptors input_constraints; - MLGraph::NamedOperandDescriptors output_constraints; - THROW_AND_RETURN_TYPE_IF_ERROR( - ValidateAndSortGraph(named_outputs, topo_sorted_operators, - input_constraints, output_constraints), - ScriptPromise<MLGraph>()); + scoped_trace.AddStep("DetermineGraphConstraintsFromOutputs"); + auto graph_constraints = DetermineGraphConstraintsFromOutputs(named_outputs); + if (!graph_constraints.has_value()) { + exception_state.ThrowTypeError(graph_constraints.error()); + return EmptyPromise(); + } + + // MLGraphTransformPipeline may change the operators topological order and + // alter named outputs. BuildWebNNGraphInfo should sort the operators by + // itself again before serialization. + scoped_trace.AddStep("MLGraphTransformPipeline"); + auto* pipeline = MakeGarbageCollected<MLGraphTransformPipeline>(this); + pipeline->Run(named_outputs); + + // Check the named_outputs descriptors are equal to the original's + // descriptors. + const auto& output_constraints = graph_constraints->second; + CHECK_EQ(named_outputs.size(), output_constraints.size()); + for (const auto& [name, operand] : named_outputs) { + const auto& constraint = output_constraints.at(name); + // TODO(crbug.com/406666712): Change to `CHECK_EQ(operand->Descriptor(), + // *constraint)` once we fix the `webnn::OperandDescriptor`. + CHECK(operand->Descriptor() == *constraint); + } scoped_trace.AddStep("BuildWebNNGraphInfo"); - auto graph_info = BuildWebNNGraphInfo(named_outputs, topo_sorted_operators, - ml_context_->GetProperties()); + auto graph_info = + BuildWebNNGraphInfo(named_outputs, ml_context_->GetProperties()); if (!graph_info.has_value()) { // TODO(crbug.com/345271830): Move the platform-specific checks into the // respective synchronous operator builder methods, such that @@ -3301,8 +3287,7 @@ *std::move(graph_info), WTF::BindOnce(&MLGraphBuilder::DidCreateWebNNGraph, WrapPersistent(this), WrapPersistent(pending_resolver_.Get()), - std::make_pair(std::move(input_constraints), - std::move(output_constraints)))); + *std::move(graph_constraints))); return pending_resolver_->Promise(); }
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h index 6f6f934..bbdee03 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h
@@ -83,6 +83,8 @@ void Trace(Visitor* visitor) const override; + ExecutionContext* GetExecutionContext() const; + MLContext* GetContext() const; struct Size2D { @@ -510,7 +512,7 @@ ExceptionState& exception_state); ScriptPromise<MLGraph> build(ScriptState* script_state, - const MLNamedOperands& outputs, + MLNamedOperands& outputs, ExceptionState& exception_state); void OnConnectionError(); @@ -536,6 +538,8 @@ [[nodiscard]] base::expected<void, String> ValidateInputs( const HeapVector<Member<MLOperand>>& inputs); + Member<ExecutionContext> execution_context_; + Member<MLContext> ml_context_; HeapMojoAssociatedRemote<webnn::mojom::blink::WebNNGraphBuilder> remote_;
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc index ae6b2ee..099dd38e 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
@@ -2,13 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_transpose_options.h" #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/390223051): Remove C-library calls to fix the errors. #pragma allow_unsafe_libc_calls #endif -#include "third_party/blink/renderer/modules/ml/webnn/ml_graph.h" - #include <limits.h> #include <array> @@ -66,8 +65,10 @@ #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" #include "third_party/blink/renderer/modules/ml/ml.h" #include "third_party/blink/renderer/modules/ml/ml_context.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test_utils.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/ml_graph_transformer.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h" @@ -320,7 +321,7 @@ BuildResult BuildGraph(V8TestingScope& scope, MLGraphBuilder* builder, - const MLNamedOperands& named_operands) { + MLNamedOperands& named_operands) { ScriptPromise<MLGraph> build_promise = builder->build( scope.GetScriptState(), named_operands, scope.GetExceptionState()); // An empty promise will be returned if `build()` synchronously rejects. @@ -798,7 +799,8 @@ auto* output = builder->add(lhs_operand, rhs_operand, options, scope.GetExceptionState()); EXPECT_THAT(output, testing::NotNull()); - return builder->build(scope.GetScriptState(), {{"output", output}}, + MLNamedOperands named_outputs = {{"output", output}}; + return builder->build(scope.GetScriptState(), named_outputs, scope.GetExceptionState()); } @@ -886,7 +888,7 @@ auto [graph, error_name, error_message] = BuildGraph(scope, builder, named_outputs); EXPECT_EQ(error_name, "TypeError"); - EXPECT_EQ(error_message, "At least one output must be provided."); + EXPECT_EQ(error_message, "At least one output needs to be provided."); } { // Test throwing exception if the named output is an input operand. @@ -897,8 +899,12 @@ auto* input = BuildInput(scope.GetScriptState(), builder, "input", {3, 4, 5}, V8MLOperandDataType::Enum::kFloat32, exception_state); + MLNamedOperands named_outputs = {{ + "output", + input, + }}; auto [graph, error_name, error_message] = - BuildGraph(scope, builder, {{"output", input}}); + BuildGraph(scope, builder, named_outputs); EXPECT_EQ(error_name, "TypeError"); EXPECT_EQ(error_message, "The operand with name \"output\" is not an output operand."); @@ -917,8 +923,9 @@ auto* c = builder->add(a, b, options, exception_state); ASSERT_THAT(c, testing::NotNull()); + MLNamedOperands named_outputs = {{"c", c}}; auto [graph, error_name, error_message] = - BuildGraph(scope, builder, {{"c", c}}); + BuildGraph(scope, builder, named_outputs); EXPECT_EQ(error_name, "TypeError"); EXPECT_EQ(error_message, "The input name \"a\" is duplicated."); } @@ -940,8 +947,9 @@ const MLOperatorOptions* options = MLOperatorOptions::Create(); auto* output = builder->add(a, a, options, exception_state); ASSERT_THAT(output, testing::NotNull()); + MLNamedOperands named_outputs = {{"b", output}}; auto [graph, error_name, error_message] = - BuildGraph(scope, builder, {{"b", output}}); + BuildGraph(scope, builder, named_outputs); ASSERT_THAT(graph, testing::NotNull()); const auto& inputs = graph->GetInputConstraints(); EXPECT_EQ(inputs.size(), static_cast<uint32_t>(1)); @@ -968,8 +976,9 @@ ASSERT_THAT(b, testing::NotNull()); auto* c = builder->sigmoid(a, options, exception_state); ASSERT_THAT(c, testing::NotNull()); + MLNamedOperands named_outputs = {{"b", b}, {"c", c}}; auto [graph, error_name, error_message] = - BuildGraph(scope, builder, {{"b", b}, {"c", c}}); + BuildGraph(scope, builder, named_outputs); ASSERT_THAT(graph, testing::NotNull()); const auto& inputs = graph->GetInputConstraints(); EXPECT_EQ(inputs.size(), static_cast<uint32_t>(1)); @@ -992,8 +1001,9 @@ V8MLOperandDataType::Enum::kFloat32, exception_state); auto* c = BuildGemm(scope, builder, a, b); + MLNamedOperands named_outputs = {{"c", c}}; auto [graph, error_name, error_message] = - BuildGraph(scope, builder, {{"c", c}}); + BuildGraph(scope, builder, named_outputs); ASSERT_THAT(graph, testing::NotNull()); const auto& inputs = graph->GetInputConstraints(); EXPECT_EQ(inputs.size(), static_cast<uint32_t>(2)); @@ -1183,8 +1193,9 @@ auto* output_operand = BuildElementWiseBinary( scope, builder, webnn::mojom::blink::ElementWiseBinary::Kind::kAdd, lhs_operand, rhs_operand); + MLNamedOperands named_outputs = {{"output", output_operand}}; auto [graph, error_message, build_exception] = - BuildGraph(scope, builder, {{"output", output_operand}}); + BuildGraph(scope, builder, named_outputs); ASSERT_THAT(graph, testing::NotNull()); MLTensor* input_tensor = @@ -1257,8 +1268,9 @@ const MLOperatorOptions* options = MLOperatorOptions::Create(); auto* output_operand = builder->softmax(input_operand, options, scope.GetExceptionState()); + MLNamedOperands named_outputs = {{"output", output_operand}}; auto [graph, error_name, error_message] = - helper.BuildGraph(scope, builder, {{"output", output_operand}}); + helper.BuildGraph(scope, builder, named_outputs); ASSERT_THAT(graph, testing::NotNull()); auto graph_info = helper.GetGraphInfo(); @@ -1322,8 +1334,9 @@ auto* output_operand = builder->cast(input_operand, V8MLOperandDataType(output_data_type), options, scope.GetExceptionState()); + MLNamedOperands named_outputs = {{"output", output_operand}}; auto [graph, error_name, error_message] = - helper.BuildGraph(scope, builder, {{"output", output_operand}}); + helper.BuildGraph(scope, builder, named_outputs); ASSERT_THAT(graph, testing::NotNull()); auto graph_info = helper.GetGraphInfo(); @@ -1540,4 +1553,97 @@ } } +TEST_F(MLGraphTest, MLTransformTest) { + V8TestingScope scope; + // Bind fake WebNN Context in the service for testing. + ScopedWebNNServiceBinder scoped_setup_binder(*this, scope); + MLContext* context = CreateContext(scope, MLContextOptions::Create()); + + { + DummyExceptionStateForTesting exception_state; + auto* builder = MLGraphBuilder::Create(scope.GetScriptState(), context, + exception_state); + ASSERT_THAT(builder, testing::NotNull()); + + // [a] + // / \ + // \ / + // add + // | + // [b] + auto* a = BuildInput(scope.GetScriptState(), builder, "a", {3, 4, 5}, + V8MLOperandDataType::Enum::kFloat32, exception_state); + const MLOperatorOptions* options = MLOperatorOptions::Create(); + auto* b = builder->add(a, a, options, exception_state); + ASSERT_THAT(b, testing::NotNull()); + // Transform the graph to: + // [a] [c] + // \ / + // \ / + // add + // | + // [b] + + auto* c = + BuildConstant(scope.GetScriptState(), builder, {3, 4, 5}, + V8MLOperandDataType::Enum::kFloat32, exception_state); + ASSERT_THAT(c, testing::NotNull()); + MLGraphTransformer::Disconnect(a, b->Operator(), 1); + MLGraphTransformer::Connect(c, b->Operator(), 1); + EXPECT_EQ(b->Operator()->Inputs()[0], a); + EXPECT_EQ(b->Operator()->Inputs()[1], c); + // Build the transformed graph. + MLNamedOperands named_outputs = {{"b", b}}; + auto [graph, error_name, error_message] = + BuildGraph(scope, builder, named_outputs); + ASSERT_THAT(graph, testing::NotNull()); + const auto& inputs = graph->GetInputConstraints(); + EXPECT_EQ(inputs.size(), static_cast<uint32_t>(1)); + EXPECT_EQ(*inputs.at("a"), a->Descriptor()); + const auto& outputs = graph->GetOutputConstraints(); + EXPECT_EQ(outputs.size(), static_cast<uint32_t>(1)); + EXPECT_EQ(*outputs.at("b"), b->Descriptor()); + } + + { + DummyExceptionStateForTesting exception_state; + auto* builder = MLGraphBuilder::Create(scope.GetScriptState(), context, + exception_state); + ASSERT_THAT(builder, testing::NotNull()); + // [a] -> transpose -> [b] -> relu -> [c] + auto* a = BuildInput(scope.GetScriptState(), builder, "a", {3, 4, 5}, + V8MLOperandDataType::Enum::kFloat32, exception_state); + auto* transpose_options = MLTransposeOptions::Create(); + transpose_options->setPermutation({0, 2, 1}); + auto* b = builder->transpose(a, transpose_options, exception_state); + ASSERT_THAT(b, testing::NotNull()); + auto* relu_options = MLOperatorOptions::Create(); + auto* c = builder->relu(b, relu_options, exception_state); + ASSERT_THAT(c, testing::NotNull()); + + EXPECT_EQ(c->Shape(), std::vector<uint32_t>({3, 5, 4})); + // Transform the graph to: + // [a] -> relu -> [c] + MLGraphTransformer::Disconnect(a, b->Operator(), 0); + MLGraphTransformer::Disconnect(b, c->Operator(), 0); + MLGraphTransformer::Connect(a, c->Operator(), 0); + // update shape of c + auto* updated_c = + MLGraphTransformer::ReplaceOperandWithNewShape(c, {3, 4, 5}); + EXPECT_EQ(updated_c->Shape(), std::vector<uint32_t>({3, 4, 5})); + + // Build the transformed graph. + MLNamedOperands named_outputs = {{"c", updated_c}}; + auto [graph, error_name, error_message] = + BuildGraph(scope, builder, named_outputs); + ASSERT_THAT(graph, testing::NotNull()); + const auto& inputs = graph->GetInputConstraints(); + EXPECT_EQ(inputs.size(), static_cast<uint32_t>(1)); + EXPECT_EQ(*inputs.at("a"), a->Descriptor()); + const auto& outputs = graph->GetOutputConstraints(); + EXPECT_EQ(outputs.size(), static_cast<uint32_t>(1)); + EXPECT_EQ(*outputs.at("c"), updated_c->Descriptor()); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/ml_graph_transformer.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/ml_graph_transformer.cc new file mode 100644 index 0000000..bc35283 --- /dev/null +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/ml_graph_transformer.cc
@@ -0,0 +1,106 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/ml_graph_transformer.h" + +#include "third_party/blink/renderer/modules/ml/ml_context.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h" + +namespace blink { + +void MLGraphTransformer::Trace(Visitor* visitor) const { + visitor->Trace(graph_builder_); +} + +// static +wtf_size_t MLGraphTransformer::Disconnect(MLOperand* from, MLOperator* to) { + auto& dependent_operators = from->dependent_operators_; + + CHECK(dependent_operators.Contains(to)); + dependent_operators.erase(to); + + OperandIndex input_index = to->inputs_.Find(from); + CHECK(input_index != kNotFound); + to->inputs_[input_index] = nullptr; + return input_index; +} + +// static +void MLGraphTransformer::Disconnect(MLOperand* from, + MLOperator* to, + OperandIndex input_index) { + auto& dependent_operators = from->dependent_operators_; + + CHECK(dependent_operators.Contains(to)); + dependent_operators.erase(to); + + CHECK(to->inputs_[input_index] == from); + to->inputs_[input_index] = nullptr; +} + +// static +void MLGraphTransformer::Connect(MLOperand* from, + MLOperator* to, + OperandIndex input_index) { + CHECK(!from->dependent_operators_.Contains(to)); + from->AddDependentOperator(to); + + CHECK_EQ(to->inputs_[input_index], nullptr); + to->inputs_[input_index] = from; +} + +// static +MLOperand* MLGraphTransformer::CloneOperandAndResetShape( + const MLOperand* operand, + const Vector<uint32_t>& shape) { + auto descriptor = webnn::OperandDescriptor::Create( + operand->Builder()->GetContext()->GetProperties(), operand->DataType(), + shape, /*label=*/""); + CHECK(descriptor.has_value()); + CHECK_EQ(operand->NumberOfElements(), descriptor->NumberOfElements()); + + MLOperand* clone = MakeGarbageCollected<MLOperand>( + operand->Builder(), operand->Kind(), descriptor.value()); + + clone->operator_ = operand->Operator(); + clone->dependent_operators_ = operand->dependent_operators_; + return clone; +} + +// static +void MLGraphTransformer::ReplaceOperand(MLOperand* old_operand, + MLOperand* new_operand) { + auto* op = old_operand->Operator(); + for (auto& output : op->outputs_) { + if (output == old_operand) { + output = new_operand; + } + } + + auto& deps = old_operand->dependent_operators_; + for (auto& dep : deps) { + auto* dep_op = dep.Get(); + for (auto& input : dep_op->inputs_) { + if (input == old_operand) { + input = new_operand; + } + } + } +} + +// static +MLOperand* MLGraphTransformer::ReplaceOperandWithNewShape( + MLOperand* old_operand, + const Vector<uint32_t>& new_shape) { + auto* new_operand = CloneOperandAndResetShape(old_operand, new_shape); + ReplaceOperand(old_operand, new_operand); + return new_operand; +} + +const ExceptionState MLGraphTransformer::GetExceptionState() { + auto* isolate = graph_builder_->GetExecutionContext()->GetIsolate(); + return ExceptionState(isolate); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/ml_graph_transformer.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/ml_graph_transformer.h new file mode 100644 index 0000000..f98322e --- /dev/null +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/ml_graph_transformer.h
@@ -0,0 +1,57 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_TRANSFORM_ML_GRAPH_TRANSFORMER_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_TRANSFORM_ML_GRAPH_TRANSFORMER_H_ + +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h" + +namespace blink { + +using OperandIndex = wtf_size_t; + +class MODULES_EXPORT MLGraphTransformer + : public GarbageCollected<MLGraphTransformer> { + public: + explicit MLGraphTransformer(MLGraphBuilder* graph_builder) + : graph_builder_(graph_builder) {} + + virtual ~MLGraphTransformer() = default; + + virtual void Trace(Visitor* visitor) const; + + // Apply the transformation to the given graph. + virtual void Transform(MLNamedOperands& named_outputs) = 0; + + // The return value is the index of the disconnected input operand of "to" + static OperandIndex Disconnect(MLOperand* from, MLOperator* to); + + static void Disconnect(MLOperand* from, + MLOperator* to, + OperandIndex input_index); + + static void Connect(MLOperand* from, + MLOperator* to, + OperandIndex input_index); + + // The reshaped operand should have the same number of elements as the + // original operand + static MLOperand* ReplaceOperandWithNewShape( + MLOperand* old_operand, + const Vector<uint32_t>& new_shape); + + protected: + const ExceptionState GetExceptionState(); + + Member<MLGraphBuilder> graph_builder_; + + private: + static MLOperand* CloneOperandAndResetShape(const MLOperand* operand, + const Vector<uint32_t>& shape); + + static void ReplaceOperand(MLOperand* old_operand, MLOperand* new_operand); +}; + +} // namespace blink +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_TRANSFORM_ML_GRAPH_TRANSFORMER_H_
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/pipeline.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/pipeline.cc new file mode 100644 index 0000000..c7b4463c --- /dev/null +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/pipeline.cc
@@ -0,0 +1,28 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/pipeline.h" + +namespace blink { +MLGraphTransformPipeline::MLGraphTransformPipeline( + MLGraphBuilder* graph_builder) { + InitTransformers(graph_builder); +} + +void MLGraphTransformPipeline::Trace(Visitor* visitor) const { + visitor->Trace(transformers_); +} + +void MLGraphTransformPipeline::InitTransformers(MLGraphBuilder* graph_builder) { + // TODO(crbug.com/406666712): Add LayoutTransformer and + // TransposeEliminationTransformer to the pipeline. +} + +void MLGraphTransformPipeline::Run(MLNamedOperands& named_outputs) { + for (auto& transformer : transformers_) { + transformer->Transform(named_outputs); + } +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/pipeline.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/pipeline.h new file mode 100644 index 0000000..5901b246 --- /dev/null +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/pipeline.h
@@ -0,0 +1,29 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_TRANSFORM_PIPELINE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_TRANSFORM_PIPELINE_H_ + +#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_transform/ml_graph_transformer.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +namespace blink { + +class MLGraphTransformPipeline + : public GarbageCollected<MLGraphTransformPipeline> { + public: + explicit MLGraphTransformPipeline(MLGraphBuilder* graph_builder); + + void Trace(Visitor* visitor) const; + + void InitTransformers(MLGraphBuilder* graph_builder); + + void Run(MLNamedOperands& named_outputs); + + private: + HeapVector<Member<MLGraphTransformer>> transformers_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_TRANSFORM_PIPELINE_H_
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.cc index d151637..2519e47f 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.cc
@@ -11,10 +11,75 @@ #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h" +#include "third_party/blink/renderer/modules/ml/webnn/ml_operator.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h" namespace blink { +HeapVector<Member<MLOperator>> GetOperatorsInTopologicalOrder( + const MLNamedOperands& named_outputs) { + // A WebNN graph is represented by a directed acyclic graph (DAG) that has + // operators as vertices and operand as edges. The topological sorting is + // implemented by depth-first search (DFS) and visiting vertices in + // post-order. It means a vertex (operator) is visited (pushed to the back of + // the sorted list) after all its dependent vertices (operators) are visited. + // With that, it ensures operator 'j' appears before operator 'i' in the + // result, if 'i' depends on 'j'. The DFS algorithm is based on the + // non-recursive implementation of: + // https://en.wikipedia.org/wiki/Depth-first_search + + // The topologically sorted operators. + HeapVector<Member<MLOperator>> toposorted_operators; + + // The to-visit stack and visited set for DFS graph traversal. + HeapDeque<Member<MLOperator>> operators_to_visit; + HeapHashSet<Member<MLOperator>> visited_operators; + // Enumerate output operands and initialize the to-visit stack with their + // dependent operators. + for (const auto& output : named_outputs) { + const auto* operand = output.second.Get(); + operators_to_visit.push_back(operand->Operator()); + } + while (operators_to_visit.size() > 0) { + // Get the current operator from the top of the to-visit stack. + auto& current_operator = operators_to_visit.back(); + if (!visited_operators.Contains(current_operator.Get())) { + // The current operator is not visited, check whether its dependent + // operators are visited or not. + bool skip_visit = false; + for (const auto& operand : current_operator->Inputs()) { + if (operand->Kind() == webnn::mojom::blink::Operand::Kind::kOutput) { + auto* dependent_operator = operand->Operator(); + CHECK(dependent_operator); + if (!visited_operators.Contains(dependent_operator)) { + // As there is an dependent operator is not visited, skip visiting + // this operator and push the dependent operator into the to-visit + // stack. + skip_visit = true; + operators_to_visit.push_back(dependent_operator); + } + } + } + if (!skip_visit) { + // When all dependent operators have been visited, visit the current + // operator and add it into the visited set. + toposorted_operators.push_back(current_operator); + visited_operators.insert(current_operator); + // Pop the current operator from the to-visit stack. + operators_to_visit.pop_back(); + } + } else { + // The current operator is already visited, pop it and check the next + // one. + operators_to_visit.pop_back(); + } + } + return toposorted_operators; +} + DOMArrayBufferView::ViewType GetArrayBufferViewType( webnn::OperandDataType data_type) { switch (data_type) {
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h index 68b80ea..8901876 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h
@@ -16,12 +16,21 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_operand_descriptor.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h" #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h" +#include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { +class MLOperator; class ScriptState; +// Return the operators in topological order by searching from the named +// output operands. It ensures operator 'j' appears before operator 'i' in the +// result, if 'i' depends on 'j'. +MODULES_EXPORT HeapVector<Member<MLOperator>> GetOperatorsInTopologicalOrder( + const MLNamedOperands& named_outputs); + MODULES_EXPORT DOMArrayBufferView::ViewType GetArrayBufferViewType( webnn::OperandDataType data_type);
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_operand.cc b/third_party/blink/renderer/modules/ml/webnn/ml_operand.cc index e88197a..12d6313a 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_operand.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_operand.cc
@@ -52,7 +52,7 @@ // static MLOperand* MLOperand::CreateOutput(MLGraphBuilder* builder, webnn::OperandDescriptor descriptor, - const MLOperator* ml_operator) { + MLOperator* ml_operator) { CHECK(ml_operator); auto* output = MakeGarbageCollected<MLOperand>( @@ -82,13 +82,12 @@ return name_; } -const MLOperator* MLOperand::Operator() const { +MLOperator* MLOperand::Operator() const { CHECK_EQ(kind_, webnn::mojom::blink::Operand::Kind::kOutput); return operator_.Get(); } -const HeapHashSet<Member<const MLOperator>>& MLOperand::DependentOperators() - const { +HeapHashSet<Member<MLOperator>>& MLOperand::DependentOperators() { return dependent_operators_; } @@ -130,7 +129,7 @@ return static_cast<MLConstantOperand const*>(this); } -void MLOperand::AddDependentOperator(const MLOperator* ml_operator) { +void MLOperand::AddDependentOperator(MLOperator* ml_operator) { dependent_operators_.insert(ml_operator); }
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_operand.h b/third_party/blink/renderer/modules/ml/webnn/ml_operand.h index 3ef4b4b..819657f3 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_operand.h +++ b/third_party/blink/renderer/modules/ml/webnn/ml_operand.h
@@ -40,7 +40,7 @@ // skip the validation. static MLOperand* CreateOutput(MLGraphBuilder* builder, webnn::OperandDescriptor descriptor, - const MLOperator* ml_operator); + MLOperator* ml_operator); // The constructor shouldn't be called directly. The callers should use // Create* methods instead. @@ -58,8 +58,8 @@ MLGraphBuilder* Builder() const; webnn::mojom::blink::Operand::Kind Kind() const; const String& Name() const; - const MLOperator* Operator() const; - const HeapHashSet<Member<const MLOperator>>& DependentOperators() const; + MLOperator* Operator() const; + HeapHashSet<Member<MLOperator>>& DependentOperators(); // Convenience methods for accessing native types, which avoid a copy // compared to using the corresponding methods which return blink types. @@ -83,7 +83,7 @@ MLConstantOperand const* AsConstantOperand() const; - void AddDependentOperator(const MLOperator* ml_operator); + void AddDependentOperator(MLOperator* ml_operator); protected: Member<MLGraphBuilder> builder_; @@ -101,10 +101,11 @@ // The operator that produces the output operand. Only output operand has an // operator that produces the operand by an operator build method of // MLGraphBuilder interface. - Member<const MLOperator> operator_; + Member<MLOperator> operator_; // Operators that use this operand as an input. - HeapHashSet<Member<const MLOperator>> dependent_operators_; + HeapHashSet<Member<MLOperator>> dependent_operators_; + friend class MLGraphTransformer; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_operator.h b/third_party/blink/renderer/modules/ml/webnn/ml_operator.h index 80d5c95..8977f48 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_operator.h +++ b/third_party/blink/renderer/modules/ml/webnn/ml_operator.h
@@ -101,6 +101,7 @@ HeapVector<Member<MLOperand>> inputs_; HeapVector<Member<MLOperand>> outputs_; + friend class MLGraphTransformer; }; // TODO: crbug.com/325612086 - Remove all these subclasses. This information
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 f1d68bf..7281405 100644 --- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc +++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
@@ -704,14 +704,22 @@ void PeerConnectionTracker::StartDataChannelLog(int peer_connection_local_id) { DCHECK_CALLED_ON_VALID_THREAD(main_thread_); - // TODO(chromium:407785197): Start the DataChannel log on the PeerConnection - // specified by `peer_connection_local_id`. + for (auto& it : peer_connection_local_id_map_) { + if (it.value == peer_connection_local_id) { + it.key->StartDataChannelLog(); + return; + } + } } void PeerConnectionTracker::StopDataChannelLog(int peer_connection_local_id) { DCHECK_CALLED_ON_VALID_THREAD(main_thread_); - // TODO(chromium:407785197): Stop the DataChannel log on the PeerConnection - // specified by `peer_connection_local_id`. + for (auto& it : peer_connection_local_id_map_) { + if (it.value == peer_connection_local_id) { + it.key->StopDataChannelLog(); + return; + } + } } void PeerConnectionTracker::GetStandardStats() {
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h index fec4aa60..f96cba9 100644 --- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h +++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h
@@ -252,6 +252,16 @@ FRIEND_TEST_ALL_PREFIXES(PeerConnectionTrackerTest, OnThermalStateChange); FRIEND_TEST_ALL_PREFIXES(PeerConnectionTrackerTest, ReportInitialThermalState); + FRIEND_TEST_ALL_PREFIXES(PeerConnectionTrackerTest, + StartDataChannelLogCalled); + FRIEND_TEST_ALL_PREFIXES(PeerConnectionTrackerTest, StopDataChannelLogCalled); + FRIEND_TEST_ALL_PREFIXES( + PeerConnectionTrackerTest, + StartDataChannelLogNotCalledIfMismatchBetweenLidAndPeerConnection); + FRIEND_TEST_ALL_PREFIXES( + PeerConnectionTrackerTest, + StopDataChannelLogNotCalledIfMismatchBetweenLidAndPeerConnection); + FRIEND_TEST_ALL_PREFIXES(PeerConnectionTrackerTest, DataChannelLoggingWrite); PeerConnectionTracker( mojo::PendingRemote<mojom::blink::PeerConnectionTrackerHost> host,
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 a2fd415..ecd3e10 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
@@ -26,6 +26,10 @@ #include "third_party/blink/renderer/platform/testing/task_environment.h" using ::testing::_; +using ::testing::ElementsAre; +using ::testing::Invoke; + +using PeerConnectionInfoPtr = ::blink::mojom::blink::PeerConnectionInfoPtr; namespace blink { @@ -110,6 +114,8 @@ MakeGarbageCollected<MockRTCPeerConnectionHandlerClient>()) {} MOCK_METHOD0(CloseClientPeerConnection, void()); MOCK_METHOD1(OnThermalStateChange, void(mojom::blink::DeviceThermalState)); + MOCK_METHOD0(StartDataChannelLog, void()); + MOCK_METHOD0(StopDataChannelLog, void()); private: explicit MockPeerConnectionHandler( @@ -145,12 +151,19 @@ base::PassKey<PeerConnectionTrackerTest>()); } - void CreateAndRegisterPeerConnectionHandler() { + PeerConnectionInfoPtr CreateAndRegisterPeerConnectionHandler() { mock_handler_ = std::make_unique<MockPeerConnectionHandler>(); - EXPECT_CALL(*mock_host_, AddPeerConnection(_)); + PeerConnectionInfoPtr res; + base::RunLoop run_loop; + EXPECT_CALL(*mock_host_, AddPeerConnection) + .WillOnce(Invoke([&res, &run_loop](PeerConnectionInfoPtr info) { + res = std::move(info); + run_loop.Quit(); + })); tracker_->RegisterPeerConnection(mock_handler_.get(), DefaultConfig(), nullptr); - base::RunLoop().RunUntilIdle(); + run_loop.Run(); + return res; } protected: @@ -214,6 +227,54 @@ tracker_->OnThermalStateChange(mojom::blink::DeviceThermalState::kCritical); } +TEST_F(PeerConnectionTrackerTest, StartDataChannelLogCalled) { + CreateTrackerWithMocks(); + PeerConnectionInfoPtr info = CreateAndRegisterPeerConnectionHandler(); + + EXPECT_CALL(*mock_handler_, StartDataChannelLog); + tracker_->StartDataChannelLog(info->lid); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(PeerConnectionTrackerTest, + StartDataChannelLogNotCalledIfMismatchBetweenLidAndPeerConnection) { + CreateTrackerWithMocks(); + PeerConnectionInfoPtr info = CreateAndRegisterPeerConnectionHandler(); + + EXPECT_CALL(*mock_handler_, StartDataChannelLog).Times(0); + tracker_->StartDataChannelLog(info->lid + 1); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(PeerConnectionTrackerTest, StopDataChannelLogCalled) { + CreateTrackerWithMocks(); + PeerConnectionInfoPtr info = CreateAndRegisterPeerConnectionHandler(); + + EXPECT_CALL(*mock_handler_, StopDataChannelLog); + tracker_->StopDataChannelLog(info->lid); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(PeerConnectionTrackerTest, + StopDataChannelLogNotCalledIfMismatchBetweenLidAndPeerConnection) { + CreateTrackerWithMocks(); + PeerConnectionInfoPtr info = CreateAndRegisterPeerConnectionHandler(); + + EXPECT_CALL(*mock_handler_, StopDataChannelLog).Times(0); + tracker_->StopDataChannelLog(info->lid + 1); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(PeerConnectionTrackerTest, DataChannelLoggingWrite) { + CreateTrackerWithMocks(); + PeerConnectionInfoPtr info = CreateAndRegisterPeerConnectionHandler(); + + EXPECT_CALL(*mock_host_, + WebRtcDataChannelLogWrite(info->lid, ElementsAre(1, 2, 3))); + tracker_->TrackRtcDataChannelLogWrite(mock_handler_.get(), {1, 2, 3}); + base::RunLoop().RunUntilIdle(); +} + TEST_F(PeerConnectionTrackerTest, ReportInitialThermalState) { MockPeerConnectionHandler handler0; MockPeerConnectionHandler handler1;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc index b9333d5e..8841543 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
@@ -47,6 +47,7 @@ #include "third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.h" #include "third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/json/json_values.h" #include "third_party/blink/renderer/platform/mediastream/media_stream_component.h" #include "third_party/blink/renderer/platform/mediastream/media_stream_track_platform.h" #include "third_party/blink/renderer/platform/mediastream/webrtc_uma_histograms.h" @@ -66,6 +67,7 @@ #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_std.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/wtf/text/base64.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" #include "third_party/webrtc/api/data_channel_interface.h" @@ -449,6 +451,20 @@ bool is_rollback_; }; +// Generally, output from a PeerConnection will go through the +// `RTCPeerConnectionHandler::Observer`, which is a class declared in the +// protected section of `RTCPeerConnectionHandler`. For this reason a plain +// `Observer` can not be referenced by other classes, which is necessary since +// an instance of the `DataChannelEventObserverInterface` interface needs to be +// injected into the PeerConnection. +class RtcDataChannelEventSink : public GarbageCollectedMixin { + public: + virtual ~RtcDataChannelEventSink() = default; + + virtual void OnWebRtcDataChannelLogWrite( + const WTF::Vector<uint8_t>& output) = 0; +}; + // Receives notifications from a PeerConnection object about state changes. The // callbacks we receive here come on the webrtc signaling thread, so this class // takes care of delivering them to an RTCPeerConnectionHandler instance on the @@ -458,7 +474,8 @@ class RTCPeerConnectionHandler::Observer : public GarbageCollected<RTCPeerConnectionHandler::Observer>, public PeerConnectionObserver, - public RtcEventLogOutputSink { + public RtcEventLogOutputSink, + public RtcDataChannelEventSink { public: Observer(const base::WeakPtr<RTCPeerConnectionHandler>& handler, scoped_refptr<base::SingleThreadTaskRunner> task_runner) @@ -504,6 +521,18 @@ } } + void OnWebRtcDataChannelLogWrite(const Vector<uint8_t>& output) override { + if (!main_thread_->BelongsToCurrentThread()) { + PostCrossThreadTask( + *main_thread_.get(), FROM_HERE, + CrossThreadBindOnce( + &RTCPeerConnectionHandler::Observer::OnWebRtcDataChannelLogWrite, + WrapCrossThreadPersistent(this), output)); + } else if (handler_) { + handler_->OnWebRtcDataChannelLogWrite(output); + } + } + void Trace(Visitor* visitor) const override {} protected: @@ -709,6 +738,46 @@ native_peer_connection_; }; +class RtcDataChannelLogOutputSinkProxy + : public webrtc::DataChannelEventObserverInterface { + public: + using webrtc::DataChannelEventObserverInterface::Message; + + explicit RtcDataChannelLogOutputSinkProxy(RtcDataChannelEventSink* sink) + : sink_(sink) {} + + void OnMessage(const Message& message) override { + auto json = std::make_unique<JSONObject>(); + json->SetString("type", "message"); + // Write a double since a unix timestamp may overflow an int. + json->SetDouble("unix_timestamp_ms", message.unix_timestamp_ms()); + json->SetInteger("datachannel_id", message.datachannel_id()); + json->SetString("label", + WTF::String(base::span<const char>(message.label()))); + json->SetString( + "direction", + message.direction() == Message::Direction::kSend ? "send" : "receive"); + if (message.data_type() == Message::DataType::kString) { + json->SetString("data_type", "string"); + json->SetString( + "data", WTF::String(base::span<const unsigned char>(message.data()))); + } else { + json->SetString("data_type", "binary"); + json->SetString("data", WTF::Base64Encode(message.data())); + } + + StringBuilder string_builder; + json->WriteJSON(&string_builder); + string_builder.Append('\n'); + + sink_.Lock()->OnWebRtcDataChannelLogWrite( + Vector<uint8_t>(string_builder.Span8())); + } + + private: + const CrossThreadWeakPersistent<RtcDataChannelEventSink> sink_; +}; + RTCPeerConnectionHandler::RTCPeerConnectionHandler( RTCPeerConnectionHandlerClient* client, blink::PeerConnectionDependencyFactory* dependency_factory, @@ -1674,6 +1743,26 @@ } } +void RTCPeerConnectionHandler::StartDataChannelLog() { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + native_peer_connection_->SetDataChannelEventObserver( + std::make_unique<RtcDataChannelLogOutputSinkProxy>( + peer_connection_observer_)); +} + +void RTCPeerConnectionHandler::StopDataChannelLog() { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + native_peer_connection_->SetDataChannelEventObserver(nullptr); +} + +void RTCPeerConnectionHandler::OnWebRtcDataChannelLogWrite( + const Vector<uint8_t>& output) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + if (peer_connection_tracker_) { + peer_connection_tracker_->TrackRtcDataChannelLogWrite(this, output); + } +} + webrtc::scoped_refptr<DataChannelInterface> RTCPeerConnectionHandler::CreateDataChannel( const String& label,
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h index 60c71f8..38980a5 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h
@@ -219,6 +219,13 @@ // WebRTC event log fragments sent back from PeerConnection land here. void OnWebRtcEventLogWrite(const WTF::Vector<uint8_t>& output); + // Start recording a DataChannel log. + virtual void StartDataChannelLog(); + // Stop recording a DataChannel log. + virtual void StopDataChannelLog(); + + virtual void OnWebRtcDataChannelLogWrite(const WTF::Vector<uint8_t>& output); + // Virtual for testing purposes. virtual scoped_refptr<base::SingleThreadTaskRunner> signaling_thread() const;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc index b0da53e5..f06431b2 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc
@@ -72,12 +72,17 @@ static const char kDummySdpType[] = "dummy type"; using testing::_; +using testing::ElementsAre; using testing::Invoke; +using testing::IsNull; using testing::NiceMock; +using testing::NotNull; using testing::Ref; using testing::Return; using testing::SaveArg; +using testing::SaveArgByMove; using testing::WithArg; +using Message = webrtc::DataChannelEventObserverInterface::Message; namespace blink { @@ -163,6 +168,8 @@ const String& value)); MOCK_METHOD1(TrackOnRenegotiationNeeded, void(RTCPeerConnectionHandler* pc_handler)); + MOCK_METHOD2(TrackRtcDataChannelLogWrite, + void(RTCPeerConnectionHandler*, const WTF::Vector<uint8_t>&)); }; class DummyRTCVoidRequest final : public RTCVoidRequest { @@ -1023,6 +1030,80 @@ thermal_resource->SetResourceListener(nullptr); } +TEST_F(RTCPeerConnectionHandlerTest, StartDataChannelLog) { + EXPECT_CALL(*mock_peer_connection_, SetDataChannelEventObserver(NotNull())); + pc_handler_->StartDataChannelLog(); +} + +TEST_F(RTCPeerConnectionHandlerTest, StopDataChannelLog) { + EXPECT_CALL(*mock_peer_connection_, SetDataChannelEventObserver(IsNull())); + pc_handler_->StopDataChannelLog(); +} + +TEST_F(RTCPeerConnectionHandlerTest, OnWebRtcDataChannelLogWrite) { + EXPECT_CALL(*mock_tracker_, + TrackRtcDataChannelLogWrite(_, ElementsAre(1, 2, 3))); + pc_handler_->OnWebRtcDataChannelLogWrite({1, 2, 3}); +} + +class RTCPeerConnectionHandlerDataChannelOnMessageTest + : public RTCPeerConnectionHandlerTest, + public ::testing::WithParamInterface< + std::tuple<Message::Direction, Message::DataType>> { + public: + RTCPeerConnectionHandlerDataChannelOnMessageTest() + : direction_(std::get<0>(GetParam())), + data_type_(std::get<1>(GetParam())) {} + Message::Direction direction_; + Message::DataType data_type_; +}; + +TEST_P(RTCPeerConnectionHandlerDataChannelOnMessageTest, OnMessage) { + std::unique_ptr<webrtc::DataChannelEventObserverInterface> observer; + EXPECT_CALL(*mock_peer_connection_, SetDataChannelEventObserver) + .WillOnce(SaveArgByMove<0>(&observer)); + pc_handler_->StartDataChannelLog(); + + ASSERT_THAT(observer, NotNull()); + + const String direction_string = + direction_ == Message::Direction::kSend ? "send" : "receive"; + const String data_type_string = + data_type_ == Message::DataType::kString ? "string" : "binary"; + const String data_string = + data_type_ == Message::DataType::kString ? "Hello" : "SGVsbG8="; + + const String expected_string = + R"({"type":"message","unix_timestamp_ms":2147483648,)" + R"("datachannel_id":9,"label":"lbl","direction":")" + + direction_string + R"(","data_type":")" + data_type_string + + R"(","data":")" + data_string + R"("})" + "\n"; + EXPECT_CALL(*mock_tracker_, TrackRtcDataChannelLogWrite) + .WillOnce([&expected_string](auto, auto vec) { + // Comparing as string makes the output of a failed expectation useful. + EXPECT_EQ(expected_string, String(vec)); + }); + + Message msg; + const int64_t max_int32 = std::numeric_limits<int32_t>::max(); + msg.set_unix_timestamp_ms(max_int32 + 1); + msg.set_datachannel_id(9); + msg.set_label("lbl"); + msg.set_direction(direction_); + msg.set_data_type(data_type_); + uint8_t data[] = {'H', 'e', 'l', 'l', 'o'}; + msg.set_data(data); + observer->OnMessage(msg); +} + +INSTANTIATE_TEST_SUITE_P( + All, + RTCPeerConnectionHandlerDataChannelOnMessageTest, + ::testing::Combine(::testing::Values(Message::Direction::kSend, + Message::Direction::kReceive), + ::testing::Values(Message::DataType::kString, + Message::DataType::kBinary))); + TEST_F(RTCPeerConnectionHandlerTest, CandidatesIgnoredWheHandlerDeleted) { auto* observer = pc_handler_->observer(); std::unique_ptr<webrtc::IceCandidateInterface> native_candidate(
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc index 4554f4f..8b2f207 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -798,8 +798,7 @@ const gfx::Size default_display_size(coded_size); const bool has_undiscarded_unpremultiplied_alpha = sk_image_info.alphaType() == kUnpremul_SkAlphaType && - !image->CurrentFrameKnownToBeOpaque() && - !(init && init->alpha() == kAlphaDiscard); + !image->IsOpaque() && !(init && init->alpha() == kAlphaDiscard); sk_sp<SkImage> sk_image; scoped_refptr<media::VideoFrame> frame; @@ -808,7 +807,7 @@ DCHECK(image->IsStaticBitmapImage()); const auto format = media::VideoPixelFormatFromSkColorType( paint_image.GetColorType(), - image->CurrentFrameKnownToBeOpaque() || init->alpha() == kAlphaDiscard); + image->IsOpaque() || init->alpha() == kAlphaDiscard); ParsedVideoFrameInit parsed_init(init, format, coded_size, default_visible_rect, default_display_size,
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index 5a7c92d..c33ea22e 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -5620,8 +5620,9 @@ return nullptr; } - if (!image->CurrentFrameKnownToBeOpaque()) + if (!image->IsOpaque()) { resource_provider->Canvas().clear(SkColors::kTransparent); + } gfx::Rect src_rect(image->Size()); gfx::Rect dest_rect(0, 0, width, height);
diff --git a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc index fbc3907..1ca5961 100644 --- a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc +++ b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
@@ -442,7 +442,7 @@ DETACH_FROM_THREAD(thread_checker_); } -bool AcceleratedStaticBitmapImage::CurrentFrameKnownToBeOpaque() { +bool AcceleratedStaticBitmapImage::IsOpaque() { return SkAlphaTypeIsOpaque(GetAlphaType()) || !GetSharedImageFormat().HasAlpha(); }
diff --git a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h index 0e58e1f5..a37b04a 100644 --- a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h +++ b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h
@@ -78,7 +78,7 @@ const gfx::ColorSpace& color_space, base::OnceCallback<void(const gpu::SyncToken&)> release_callback); - bool CurrentFrameKnownToBeOpaque() override; + bool IsOpaque() override; bool IsTextureBacked() const override { return true; } void Draw(cc::PaintCanvas*,
diff --git a/third_party/blink/renderer/platform/graphics/bitmap_image.cc b/third_party/blink/renderer/platform/graphics/bitmap_image.cc index 02d3a2b..9275333 100644 --- a/third_party/blink/renderer/platform/graphics/bitmap_image.cc +++ b/third_party/blink/renderer/platform/graphics/bitmap_image.cc
@@ -415,15 +415,15 @@ return Image::ImageForDefaultFrame(); } -bool BitmapImage::CurrentFrameKnownToBeOpaque() { +bool BitmapImage::IsOpaque() { return decoder_ ? decoder_->AlphaType() == kOpaque_SkAlphaType : false; } -bool BitmapImage::CurrentFrameIsComplete() { +bool BitmapImage::FirstFrameIsComplete() { return decoder_ && decoder_->FrameIsReceivedAtIndex(0); } -bool BitmapImage::CurrentFrameIsLazyDecoded() { +bool BitmapImage::IsLazyDecoded() { // BitmapImage supports only lazy generated images. return true; }
diff --git a/third_party/blink/renderer/platform/graphics/bitmap_image.h b/third_party/blink/renderer/platform/graphics/bitmap_image.h index 9c602abb..190ecbb1 100644 --- a/third_party/blink/renderer/platform/graphics/bitmap_image.h +++ b/third_party/blink/renderer/platform/graphics/bitmap_image.h
@@ -87,11 +87,9 @@ scoped_refptr<Image> ImageForDefaultFrame() override; - // TODO(khushalsagar): These names are bogus, we don't know what the current - // frame is. - bool CurrentFrameKnownToBeOpaque() override; - bool CurrentFrameIsComplete() override; - bool CurrentFrameIsLazyDecoded() override; + bool IsOpaque() override; + bool FirstFrameIsComplete() override; + bool IsLazyDecoded() override; size_t FrameCount() override; PaintImage PaintImageForCurrentFrame() override; ImageOrientation CurrentFrameOrientation() const override;
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_host_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_host_test.cc index 0afc641..75f9c52 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_host_test.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_host_test.cc
@@ -29,29 +29,6 @@ bool IsGpuCompositingDisabled() const override { return false; } }; -TEST(CanvasResourceHostTest, ReleaseLostTransferableResource) { - test::TaskEnvironment task_environment; - ScopedTestingPlatformSupport<AcceleratedCompositingTestPlatform> - accelerated_compositing_scope; - scoped_refptr<TestContextProvider> context = TestContextProvider::Create(); - InitializeSharedGpuContextGLES2(context.get()); - - auto host = std::make_unique<FakeCanvasResourceHost>(gfx::Size(100, 100)); - host->GetOrCreateCanvasResourceProvider(); - host->GetOrCreateCcLayerIfNeeded(); - - // Prepare a TransferableResource, then report the resource as lost. - // This test passes by not crashing and not triggering assertions. - viz::TransferableResource resource; - viz::ReleaseCallback release_callback; - EXPECT_TRUE(host->PrepareTransferableResource(&resource, &release_callback)); - - bool lost_resource = true; - std::move(release_callback).Run(gpu::SyncToken(), lost_resource); - - SharedGpuContext::Reset(); -} - TEST(CanvasResourceHostTest, ReleaseLostTransferableResourceWithLostContext) { test::TaskEnvironment task_environment; ScopedTestingPlatformSupport<AcceleratedCompositingTestPlatform>
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc index 64b0f6a..1f47749 100644 --- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc +++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
@@ -76,8 +76,9 @@ // default frame is completely received. This will help get correct // classification results for incremental content received for the given // image. - if (!image->IsBitmapImage() || image->CurrentFrameIsComplete()) + if (!image->IsBitmapImage() || image->FirstFrameIsComplete()) { cache->Add(rounded_src, color_filter); + } } return color_filter; }
diff --git a/third_party/blink/renderer/platform/graphics/generated_image.h b/third_party/blink/renderer/platform/graphics/generated_image.h index d0377fd..4a641af 100644 --- a/third_party/blink/renderer/platform/graphics/generated_image.h +++ b/third_party/blink/renderer/platform/graphics/generated_image.h
@@ -72,7 +72,7 @@ const ImageDrawOptions& draw_options); // FIXME: Implement this to be less conservative. - bool CurrentFrameKnownToBeOpaque() override { return false; } + bool IsOpaque() override { return false; } GeneratedImage(const gfx::SizeF& size) : size_(size) {}
diff --git a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc index 440f557af..41e8992a 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
@@ -105,7 +105,7 @@ image_ = std::move(image); if (image_) { - const bool image_is_opaque = image_->CurrentFrameKnownToBeOpaque(); + const bool image_is_opaque = image_->IsOpaque(); if (is_opaque_) { // If we in opaque mode but image might have transparency we need to // ensure its opacity is not used.
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc index a9d6bd6..c0f64657 100644 --- a/third_party/blink/renderer/platform/graphics/graphics_context.cc +++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -672,13 +672,13 @@ InterpolationQuality resampling; if (printing_) { resampling = kInterpolationNone; - } else if (image.CurrentFrameIsLazyDecoded()) { + } else if (image.IsLazyDecoded()) { resampling = GetDefaultInterpolationQuality(); } else { resampling = ComputeInterpolationQuality( SkScalarToFloat(src.width()), SkScalarToFloat(src.height()), SkScalarToFloat(dest.width()), SkScalarToFloat(dest.height()), - image.CurrentFrameIsComplete()); + image.FirstFrameIsComplete()); if (resampling == kInterpolationNone) { // FIXME: This is to not break tests (it results in the filter bitmap flag
diff --git a/third_party/blink/renderer/platform/graphics/image.cc b/third_party/blink/renderer/platform/graphics/image.cc index ab62429..334e93b4 100644 --- a/third_party/blink/renderer/platform/graphics/image.cc +++ b/third_party/blink/renderer/platform/graphics/image.cc
@@ -323,7 +323,7 @@ StartAnimation(); - if (CurrentFrameIsLazyDecoded()) { + if (IsLazyDecoded()) { TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Draw LazyPixelRef", TRACE_EVENT_SCOPE_THREAD, "LazyPixelRef", image_id);
diff --git a/third_party/blink/renderer/platform/graphics/image.h b/third_party/blink/renderer/platform/graphics/image.h index 3f2538c..ee044ec1 100644 --- a/third_party/blink/renderer/platform/graphics/image.h +++ b/third_party/blink/renderer/platform/graphics/image.h
@@ -105,10 +105,10 @@ virtual bool IsBitmapImage() const { return false; } virtual bool IsStaticBitmapImage() const { return false; } - virtual bool CurrentFrameKnownToBeOpaque() = 0; + virtual bool IsOpaque() = 0; - virtual bool CurrentFrameIsComplete() { return false; } - virtual bool CurrentFrameIsLazyDecoded() { return false; } + virtual bool FirstFrameIsComplete() { return false; } + virtual bool IsLazyDecoded() { return false; } virtual size_t FrameCount() { return 0; } virtual bool IsTextureBacked() const { return false; }
diff --git a/third_party/blink/renderer/platform/graphics/static_bitmap_image.h b/third_party/blink/renderer/platform/graphics/static_bitmap_image.h index 6766a60..b1d3905 100644 --- a/third_party/blink/renderer/platform/graphics/static_bitmap_image.h +++ b/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
@@ -46,7 +46,7 @@ gfx::Size SizeWithConfig(SizeConfig) const final; // Methods have common implementation for all sub-classes - bool CurrentFrameIsComplete() override { return true; } + bool FirstFrameIsComplete() override { return true; } void DestroyDecodedData() override {} // Methods that have a default implementation, and overridden by only one
diff --git a/third_party/blink/renderer/platform/graphics/static_bitmap_image_to_video_frame_copier.cc b/third_party/blink/renderer/platform/graphics/static_bitmap_image_to_video_frame_copier.cc index 66b38df5..339c79e3 100644 --- a/third_party/blink/renderer/platform/graphics/static_bitmap_image_to_video_frame_copier.cc +++ b/third_party/blink/renderer/platform/graphics/static_bitmap_image_to_video_frame_copier.cc
@@ -91,8 +91,7 @@ auto& context_provider = context_provider_wrapper->ContextProvider(); // Readback to YUV is only used when result is opaque. - const bool result_is_opaque = - image->CurrentFrameKnownToBeOpaque() || can_discard_alpha_; + const bool result_is_opaque = image->IsOpaque() || can_discard_alpha_; const bool supports_yuv_readback = context_provider.GetCapabilities().supports_yuv_readback;
diff --git a/third_party/blink/renderer/platform/graphics/test/stub_image.h b/third_party/blink/renderer/platform/graphics/test/stub_image.h index 7b9d61a..4b6286b 100644 --- a/third_party/blink/renderer/platform/graphics/test/stub_image.h +++ b/third_party/blink/renderer/platform/graphics/test/stub_image.h
@@ -13,7 +13,7 @@ public: StubImage() = default; - bool CurrentFrameKnownToBeOpaque() override { return false; } + bool IsOpaque() override { return false; } gfx::Size SizeWithConfig(SizeConfig) const override { return gfx::Size(10, 10); }
diff --git a/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc index ca16604..d528a7a 100644 --- a/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc +++ b/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
@@ -73,7 +73,7 @@ } } -bool UnacceleratedStaticBitmapImage::CurrentFrameKnownToBeOpaque() { +bool UnacceleratedStaticBitmapImage::IsOpaque() { return paint_image_.IsOpaque(); }
diff --git a/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h b/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h index 5c951dae..ecc49e2 100644 --- a/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h +++ b/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h
@@ -27,7 +27,7 @@ PaintImage, ImageOrientation orientation = ImageOrientationEnum::kDefault); - bool CurrentFrameKnownToBeOpaque() override; + bool IsOpaque() override; void Draw(cc::PaintCanvas*, const cc::PaintFlags&,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 3cfbfea9..77d55e2 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1104,11 +1104,6 @@ status: "stable", }, { - // Support anchor-size() values in inset and margin properties. - name: "CSSAnchorSizeInsetsMargins", - status: "stable", - }, - { // Whether <image> values are allowed as counter style <symbol> name: "CSSAtRuleCounterStyleImageSymbols", }, @@ -1253,10 +1248,6 @@ depends_on: ["CSSLineClamp"], }, { - name: "CSSLogicalOverflow", - status: "stable", - }, - { name: "CSSMarkerNestedPseudoElement", status: "stable", }, @@ -1359,26 +1350,11 @@ depends_on: ["CSSReadingFlow"], }, { - // https://drafts.csswg.org/css-color-5/#relative-colors - name: "CSSRelativeColor", - status: "stable", - }, - { // crbug.com/359616070 name: "CSSRelativeColorLateResolveAlways", status: "stable", }, { - // crbug.com/365818844 - name: "CSSRelativeColorPreserveNone", - status: "stable", - }, - { - // crbug.com/325309578 - name: "CSSRelativeColorSupportsCurrentcolor", - status: "stable", - }, - { // Non-standard 'auto' keyword for the CSS resize property. Used for // selectively enable resize corner for textarea via UA stylesheet, but // unintentionally exposed to author sheets. UA rule is now using @@ -1399,10 +1375,6 @@ status: "experimental", }, { - name: "CSSScrollableContainerQueries", - status: "stable", - }, - { name: "CSSScrollDirectionContainerQueries", status: "test", }, @@ -1439,13 +1411,6 @@ status: "test", }, { - // Flag for supporting scroll-state() and container-type: scroll-state - // Implied by supporting at least one of the scroll-state query features. - name: "CSSScrollStateContainerQueries", - implied_by: ["CSSStickyContainerQueries", "CSSSnapContainerQueries", - "CSSScrollableContainerQueries", "CSSScrollDirectionContainerQueries"], - }, - { name: "CSSSelectorFragmentAnchor", status: "experimental", base_feature: "CssSelectorFragmentAnchor", @@ -1474,19 +1439,11 @@ status: "experimental", }, { - name: "CSSSnapContainerQueries", - status: "stable", - }, - { // Explainer: https://drafts.csswg.org/css-values/#round-func name: "CSSSteppedValueFunctions", status: "stable", }, { - name: "CSSStickyContainerQueries", - status: "stable", - }, - { name: "CSSSupportsAtRuleFunction", status: "experimental", }, @@ -1888,6 +1845,11 @@ }, { // crbug.com/341564372 + name: "EditingFastDelete", + status: "stable", + }, + { + // crbug.com/341564372 name: "EditingFastRichReplace", status: "stable", }, @@ -2548,6 +2510,10 @@ status: "stable", }, { + name: "ICUCapitalization", + status: "experimental", + }, + { name: "IgnoreLetterSpacingInCursiveScripts", status: "stable", },
diff --git a/third_party/blink/renderer/platform/wtf/text/case_map.cc b/third_party/blink/renderer/platform/wtf/text/case_map.cc index fd74eca..b3c3352 100644 --- a/third_party/blink/renderer/platform/wtf/text/case_map.cc +++ b/third_party/blink/renderer/platform/wtf/text/case_map.cc
@@ -9,6 +9,7 @@ #include "base/notreached.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" #include "third_party/blink/renderer/platform/wtf/text/character_names.h" +#include "third_party/blink/renderer/platform/wtf/text/string_buffer.h" #include "third_party/blink/renderer/platform/wtf/text/string_impl.h" #include "third_party/blink/renderer/platform/wtf/text/string_view.h" #include "third_party/blink/renderer/platform/wtf/text/text_offset_map.h" @@ -36,12 +37,35 @@ maybe_delimiter == '@'; } -enum class CaseMapType { kLower, kUpper }; +enum class CaseMapType { kLower, kUpper, kTitle }; + +icu::Edits DecreaseFirstEditLength(const icu::Edits& edits) { + icu::Edits new_edits; + UErrorCode error = U_ZERO_ERROR; + auto edit = edits.getFineIterator(); + + edit.next(error); + int32_t new_length = edit.oldLength() - 1; + if (new_length > 0) { + new_edits.addUnchanged(new_length); + } + + while (edit.next(error)) { + if (edit.hasChange()) { + new_edits.addReplace(edit.oldLength(), edit.newLength()); + } else { + new_edits.addUnchanged(edit.oldLength()); + } + } + DCHECK(U_SUCCESS(error)); + return new_edits; +} scoped_refptr<StringImpl> CaseConvert(CaseMapType type, StringImpl* source, const char* locale, - TextOffsetMap* offset_map = nullptr) { + TextOffsetMap* offset_map = nullptr, + UChar previous_character = 0) { DCHECK(source); CHECK_LE(source->length(), static_cast<wtf_size_t>(std::numeric_limits<int32_t>::max())); @@ -52,10 +76,10 @@ base::span<UChar> data16; scoped_refptr<StringImpl> output = StringImpl::CreateUninitialized(source16.size(), data16); + wtf_size_t target_length = 0; while (true) { UErrorCode status = U_ZERO_ERROR; icu::Edits edits; - wtf_size_t target_length; switch (type) { case CaseMapType::kLower: target_length = icu::CaseMap::toLower( @@ -71,6 +95,42 @@ reinterpret_cast<char16_t*>(data16.data()), data16.size(), &edits, status); break; + case CaseMapType::kTitle: { + unsigned source_length = source16.size(); + StringBuffer<UChar> string_buffer(source_length + 1); + base::span<UChar> string_with_previous = string_buffer.Span(); + bool is_previous_alpha = u_isalpha(previous_character); + // Use an 'A' as a previous character which is already capitalized to + // make sure the titlecasing with previous character. + string_with_previous[0] = is_previous_alpha ? u'A' : kSpaceCharacter; + string_with_previous.subspan(1u).copy_from(source16); + + // Add a space of the previous character at the start. + unsigned data_with_previous_length = + (target_length ? target_length : source_length) + 1; + StringBuffer<UChar> data_buffer(data_with_previous_length); + base::span<UChar> data_with_previous = data_buffer.Span(); + + target_length = icu::CaseMap::toTitle( + locale, U_TITLECASE_NO_LOWERCASE, /* iter */ nullptr, + reinterpret_cast<const char16_t*>(string_with_previous.data()), + string_with_previous.size(), + reinterpret_cast<char16_t*>(data_with_previous.data()), + data_with_previous.size(), &edits, status); + + if (U_FAILURE(status)) { + break; + } + + // Remove the space of the previous character at the start. + --target_length; + // Copy the result without the previous character. + data16.copy_from(data_with_previous.subspan(1u)); + // Since the text included the previous character, decrease length of + // the first edit entry. + edits = DecreaseFirstEditLength(edits); + break; + } } if (U_SUCCESS(status)) { if (!edits.hasChanges()) @@ -356,4 +416,16 @@ return String(); } +String CaseMap::ToTitle(const String& source, + TextOffsetMap* offset_map, + UChar previous_character) const { + DCHECK(!offset_map || offset_map->IsEmpty()); + + if (StringImpl* impl = source.Impl()) { + return CaseConvert(CaseMapType::kTitle, impl, case_map_locale_, offset_map, + previous_character); + } + return String(); +} + } // namespace WTF
diff --git a/third_party/blink/renderer/platform/wtf/text/case_map.h b/third_party/blink/renderer/platform/wtf/text/case_map.h index 886bf27..96077b1 100644 --- a/third_party/blink/renderer/platform/wtf/text/case_map.h +++ b/third_party/blink/renderer/platform/wtf/text/case_map.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_CASE_MAP_H_ #include "third_party/blink/renderer/platform/wtf/forward.h" +#include "third_party/blink/renderer/platform/wtf/text/unicode.h" #include "third_party/blink/renderer/platform/wtf/wtf_export.h" namespace WTF { @@ -47,6 +48,9 @@ TextOffsetMap* offset_map = nullptr) const; String ToUpper(const String& source, TextOffsetMap* offset_map = nullptr) const; + String ToTitle(const String& source, + TextOffsetMap* offset_map = nullptr, + UChar previous_character = 0) const; // Fast code path for simple cases, only for root locale. // TODO(crbug.com/627682): This should move to private, once
diff --git a/third_party/blink/renderer/platform/wtf/text/case_map_test.cc b/third_party/blink/renderer/platform/wtf/text/case_map_test.cc index 042f510..ff4567e 100644 --- a/third_party/blink/renderer/platform/wtf/text/case_map_test.cc +++ b/third_party/blink/renderer/platform/wtf/text/case_map_test.cc
@@ -30,44 +30,63 @@ const char* locale; const char16_t* lower_expected; const char16_t* upper_expected; + const char16_t* title_expected; std::vector<TextOffsetMap::Entry> lower_map = {}; std::vector<TextOffsetMap::Entry> upper_map = {}; + std::vector<TextOffsetMap::Entry> title_map = {}; } case_map_test_data[] = { // Empty string. - {nullptr, "", nullptr, nullptr}, - {u"", "", u"", u""}, + {nullptr, "", nullptr, nullptr, nullptr}, + {u"", "", u"", u"", u""}, // Non-letters - {u"123", "", u"123", u"123"}, + {u"123", "", u"123", u"123", u"123"}, // ASCII lower/uppercases. - {u"xyz", "", u"xyz", u"XYZ"}, - {u"XYZ", "", u"xyz", u"XYZ"}, - {u"Xyz", "", u"xyz", u"XYZ"}, - {u"xYz", "", u"xyz", u"XYZ"}, - // German eszett. Uppercasing makes the string longer. - {u"\u00DF", "", u"\u00DF", u"SS", {}, {{1, 2}}}, - {u"\u00DFz", "", u"\u00DFz", u"SSZ", {}, {{1, 2}}}, - {u"x\u00DF", "", u"x\u00DF", u"XSS", {}, {{2, 3}}}, - {u"x\u00DFz", "", u"x\u00DFz", u"XSSZ", {}, {{2, 3}}}, + {u"xyz", "", u"xyz", u"XYZ", u"Xyz"}, + {u"XYZ", "", u"xyz", u"XYZ", u"XYZ"}, + {u"Xyz", "", u"xyz", u"XYZ", u"Xyz"}, + {u"xYz", "", u"xyz", u"XYZ", u"XYz"}, + // No break space character. + {u"abc\u00A0def", "", u"abc\u00A0def", u"ABC\u00A0DEF", u"Abc\u00A0Def"}, + // German eszett. Uppercasing and Titlecasing make the string longer. + {u"\u00DF", "", u"\u00DF", u"SS", u"Ss", {}, {{1, 2}}, {{1, 2}}}, + {u"\u00DFz", "", u"\u00DFz", u"SSZ", u"Ssz", {}, {{1, 2}}, {{1, 2}}}, + {u"x\u00DF", "", u"x\u00DF", u"XSS", u"X\u00DF", {}, {{2, 3}}}, + {u"x\u00DFz", "", u"x\u00DFz", u"XSSZ", u"X\u00DFz", {}, {{2, 3}}}, // Turkish/Azeri. - {u"\u0130", "tr", u"\u0069", u"\u0130"}, + {u"\u0130", "tr", u"\u0069", u"\u0130", u"\u0130"}, // Turkish/Azeri. Lowercasing can make the string shorter. - {u"I\u0307", "tr", u"i", u"I\u0307", {{2, 1}}}, - // Lithuanian. Uppercasing can make the string shorter. - {u"i\u0307", "lt", u"i\u0307", u"I", {}, {{2, 1}}}, - {u"i\u0307z", "lt", u"i\u0307z", u"IZ", {}, {{2, 1}}}, - {u"xi\u0307", "lt", u"xi\u0307", u"XI", {}, {{3, 2}}}, - {u"xi\u0307z", "lt", u"xi\u0307z", u"XIZ", {}, {{3, 2}}}, + {u"I\u0307", "tr", u"i", u"I\u0307", u"I\u0307", {{2, 1}}}, + // Lithuanian. Uppercasing and Titlecasing can make the string shorter. + {u"i\u0307", "lt", u"i\u0307", u"I", u"I\u0307", {}, {{2, 1}}}, + {u"i\u0307z", "lt", u"i\u0307z", u"IZ", u"I\u0307z", {}, {{2, 1}}}, + {u"xi\u0307", "lt", u"xi\u0307", u"XI", u"Xi\u0307", {}, {{3, 2}}}, + {u"xi\u0307z", "lt", u"xi\u0307z", u"XIZ", u"Xi\u0307z", {}, {{3, 2}}}, // Lithuanian. Lowercasing can make the string longer. - {u"\u00CC", "lt", u"\u0069\u0307\u0300", u"\u00CC", {{1, 3}}}, + {u"\u00CC", "lt", u"\u0069\u0307\u0300", u"\u00CC", u"\u00CC", {{1, 3}}}, // Mix of longer ones and shorter ones. - {u"\u00DFi\u0307", "lt", u"\u00DFi\u0307", u"SSI", {}, {{1, 2}, {3, 3}}}, + {u"\u00DFi\u0307", + "lt", + u"\u00DFi\u0307", + u"SSI", + u"Ssi\u0307", + {}, + {{1, 2}, {3, 3}}, + {{1, 2}}}, {u"\u00DFyi\u0307z", "lt", u"\u00DFyi\u0307z", u"SSYIZ", + u"Ssyi\u0307z", {}, - {{1, 2}, {4, 4}}}, - {u"i\u0307\u00DF", "lt", u"i\u0307\u00DF", u"ISS", {}, {{2, 1}, {3, 3}}}, + {{1, 2}, {4, 4}}, + {{1, 2}}}, + {u"i\u0307\u00DF", + "lt", + u"i\u0307\u00DF", + u"ISS", + u"I\u0307\u00DF", + {}, + {{2, 1}, {3, 3}}}, }; std::ostream& operator<<(std::ostream& os, const CaseMapTestData& data) { @@ -97,6 +116,14 @@ EXPECT_EQ(upper, String(data.upper_expected)); } +TEST_P(CaseMapTest, ToTitleWithoutOffset) { + const auto data = GetParam(); + CaseMap case_map(AtomicString(data.locale)); + String source(data.source); + String title = case_map.ToTitle(source); + EXPECT_EQ(title, String(data.title_expected)); +} + TEST_P(CaseMapTest, ToLower) { const auto data = GetParam(); CaseMap case_map(AtomicString(data.locale)); @@ -117,6 +144,16 @@ EXPECT_THAT(offset_map.Entries(), ElementsAreArray(data.upper_map)); } +TEST_P(CaseMapTest, ToTitle) { + const auto data = GetParam(); + CaseMap case_map(AtomicString(data.locale)); + String source(data.source); + TextOffsetMap offset_map; + String title = case_map.ToTitle(source, &offset_map); + EXPECT_EQ(title, String(data.title_expected)); + EXPECT_THAT(offset_map.Entries(), ElementsAreArray(data.title_map)); +} + TEST_P(CaseMapTest, ToLower8Bit) { const auto data = GetParam(); String source(data.source); @@ -143,6 +180,20 @@ EXPECT_THAT(offset_map.Entries(), ElementsAreArray(data.upper_map)); } +TEST_P(CaseMapTest, ToTitle8Bit) { + const auto data = GetParam(); + String source(data.source); + source = To8BitOrNull(source); + if (!source) { + return; + } + CaseMap case_map(AtomicString(data.locale)); + TextOffsetMap offset_map; + String title = case_map.ToTitle(source, &offset_map); + EXPECT_EQ(title, String(data.title_expected)); + EXPECT_THAT(offset_map.Entries(), ElementsAreArray(data.title_map)); +} + struct CaseFoldingTestData { const char* source_description; const char* source; @@ -152,7 +203,7 @@ // \xC4\xB0 = U+0130 (capital dotted I) // \xC4\xB1 = U+0131 (lowercase dotless I) -const char* g_turkic_input = "Isi\xC4\xB0 \xC4\xB0s\xC4\xB1I"; +const char* g_turkic_input = "isI\xC4\xB0 \xC4\xB1s\xC4\xB0I"; const char* g_greek_input = "\xCE\x9F\xCE\x94\xCE\x8C\xCE\xA3 \xCE\x9F\xCE\xB4\xCF\x8C\xCF\x82 " "\xCE\xA3\xCE\xBF \xCE\xA3\xCE\x9F o\xCE\xA3 \xCE\x9F\xCE\xA3 \xCF\x83 " @@ -193,13 +244,13 @@ "Turkic input", g_turkic_input, g_turkic_locales, - "IS\xC4\xB0\xC4\xB0 \xC4\xB0SII", + "\xC4\xB0SI\xC4\xB0 IS\xC4\xB0I", }, { "Turkic input", g_turkic_input, g_non_turkic_locales, - "ISI\xC4\xB0 \xC4\xB0SII", + "ISI\xC4\xB0 IS\xC4\xB0I", }, { "Greek input", @@ -255,14 +306,14 @@ "Turkic input", g_turkic_input, g_turkic_locales, - "\xC4\xB1sii is\xC4\xB1\xC4\xB1", + "is\xC4\xB1i \xC4\xB1si\xC4\xB1", }, { "Turkic input", g_turkic_input, g_non_turkic_locales, // U+0130 is lowercased to U+0069 followed by U+0307 - "isii\xCC\x87 i\xCC\x87s\xC4\xB1i", + "isii\xCC\x87 \xC4\xB1si\xCC\x87i", }, { "Greek input", @@ -314,4 +365,94 @@ } } +TEST(CaseMapTest, ToTitleLocale) { + const auto test_data_list = std::to_array<CaseFoldingTestData>({ + { + "Turkic input", + g_turkic_input, + g_turkic_locales, + "\xC4\xB0sI\xC4\xB0 Is\xC4\xB0I", + }, + { + "Turkic input", + g_turkic_input, + g_non_turkic_locales, + "IsI\xC4\xB0 Is\xC4\xB0I", + }, + { + "Greek input", + g_greek_input, + g_greek_locales, + "\xCE\x9F\xCE\x94\xCE\x8C\xCE\xA3 \xCE\x9F\xCE\xB4\xCF\x8C\xCF\x82 " + "\xCE\xA3\xCE\xBF \xCE\xA3\xCE\x9F O\xCE\xA3 \xCE\x9F\xCE\xA3 " + "\xCE\xA3 \xE1\xBC\x9D\xCE\xBE", + }, + { + "Greek input", + g_greek_input, + g_non_greek_locales, + "\xCE\x9F\xCE\x94\xCE\x8C\xCE\xA3 \xCE\x9F\xCE\xB4\xCF\x8C\xCF\x82 " + "\xCE\xA3\xCE\xBF \xCE\xA3\xCE\x9F O\xCE\xA3 \xCE\x9F\xCE\xA3 " + "\xCE\xA3 \xE1\xBC\x9D\xCE\xBE", + }, + { + "Lithuanian input", + g_lithuanian_input, + g_lithuanian_locales, + "I \xC3\x8F J J\xCC\x88 \xC4\xAE \xC4\xAE\xCC\x88 \xC3\x8C \xC3\x8D " + "\xC4\xA8 Xi\xCC\x87\xCC\x88 Xj\xCC\x87\xCC\x88 " + "X\xC4\xAF\xCC\x87\xCC\x88 Xi\xCC\x87\xCC\x80 Xi\xCC\x87\xCC\x81 " + "Xi\xCC\x87\xCC\x83 XI X\xC3\x8F XJ XJ\xCC\x88 X\xC4\xAE " + "X\xC4\xAE\xCC\x88", + }, + { + "Lithuanian input", + g_lithuanian_input, + g_non_lithuanian_locales, + "I \xC3\x8F J J\xCC\x88 \xC4\xAE \xC4\xAE\xCC\x88 \xC3\x8C \xC3\x8D " + "\xC4\xA8 Xi\xCC\x87\xCC\x88 Xj\xCC\x87\xCC\x88 " + "X\xC4\xAF\xCC\x87\xCC\x88 Xi\xCC\x87\xCC\x80 Xi\xCC\x87\xCC\x81 " + "Xi\xCC\x87\xCC\x83 XI X\xC3\x8F XJ XJ\xCC\x88 X\xC4\xAE " + "X\xC4\xAE\xCC\x88", + }, + }); + + for (const auto& test_data : test_data_list) { + const char* expected = test_data.expected; + String source = String::FromUTF8(test_data.source); + for (const auto& locale : test_data.locale_list) { + CaseMap case_map{AtomicString(locale)}; + EXPECT_EQ(expected, case_map.ToTitle(source).Utf8()) + << test_data.source_description << "; locale=" << locale; + } + } +} + +TEST(CaseMapTest, ToTitleWithPreviousCharacter) { + CaseMap en_case_map(AtomicString("en")); + + String input1 = String::FromUTF8("bc def"); + String result1 = en_case_map.ToTitle(input1, nullptr, u'a'); + EXPECT_EQ(result1, String::FromUTF8("bc Def")); + + String input2 = String::FromUTF8("bc"); + String result2 = en_case_map.ToTitle(input2, nullptr, u'a'); + EXPECT_EQ(result2, String::FromUTF8("bc")); + + String input3 = String::FromUTF8("abc"); + String result3 = en_case_map.ToTitle(input3, nullptr, u'@'); + EXPECT_EQ(result3, String::FromUTF8("Abc")); + + CaseMap de_case_map(AtomicString("de")); + + // \xC3\x9F = U+00DF (Latin Small Letter Sharp S) + String input4 = String::FromUTF8("\xC3\x9F"); + String result4 = de_case_map.ToTitle(input4, nullptr, u'a'); + EXPECT_EQ(result4, String::FromUTF8("\xC3\x9F")); + + String input5 = String::FromUTF8("abc"); + String result5 = de_case_map.ToTitle(input5, nullptr, u'\u00DF'); + EXPECT_EQ(result5, String::FromUTF8("abc")); +} + } // namespace WTF
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index de85812..2ff9ceaa 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -314,6 +314,7 @@ crbug.com/1347984 fragmentation/table-row-dimensions-with-thead.html [ Failure ] crbug.com/1347984 fragmentation/table-row-dimensions.html [ Failure ] +crbug.com/394900337 fast/multicol/balance-float-in-inline.html [ Failure ] crbug.com/1225630 fast/multicol/flexbox/doubly-nested-with-zero-width-flexbox-and-forced-break-crash.html [ Skip Timeout ] crbug.com/1225630 fast/multicol/infinite-height-causing-fractional-row-height-crash.html [ Skip Timeout ] crbug.com/1225630 fast/multicol/infinitely-tall-content-in-outer-crash.html [ Skip Timeout ] @@ -2873,9 +2874,7 @@ [ Linux ] external/wpt/clear-site-data/clear-cache-partitioning.tentative.https.html [ Failure Pass Timeout ] crbug.com/411459672 external/wpt/css/css-sizing/min-content-le-max-content.tentative.html [ Failure ] -crbug.com/411723253 [ Win10.20h2 ] external/wpt/speech-api/SpeechRecognition-installOnDevice.https.html [ Timeout ] crbug.com/411576891 [ Linux ] external/wpt/webdriver/tests/classic/minimize_window/minimize.py [ Failure ] -crbug.com/411723253 [ Win10.20h2 ] virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechRecognition-installOnDevice.https.html [ Timeout ] crbug.com/409809138 [ Win11 ] external/wpt/custom-elements/revamped-scoped-registry/ShadowRoot-init-customElementRegistry.tentative.html [ Pass Timeout ] crbug.com/409850360 [ Linux ] external/wpt/webdriver/tests/bidi/browsing_context/user_prompt_opened/beforeunload.py [ Timeout ] crbug.com/408838124 [ Mac12 ] external/wpt/css/css-overflow/scroll-marker-contain-005.tentative.html [ Failure ] @@ -2888,8 +2887,8 @@ crbug.com/408039416 [ Mac12 ] virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechRecognition-onerror.https.html [ Timeout ] crbug.com/408039416 [ Mac12 ] virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechRecognition-onstart-onend.https.html [ Timeout ] [ Mac13 ] external/wpt/webrtc/RTCDataChannel-send-close.html [ Skip Timeout ] -crbug.com/407404837 [ Win11-arm64 ] external/wpt/speech-api/SpeechRecognition-installOnDevice.https.html [ Timeout ] -crbug.com/407404837 [ Win11-arm64 ] virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechRecognition-installOnDevice.https.html [ Timeout ] +crbug.com/407404837 [ Win ] external/wpt/speech-api/SpeechRecognition-installOnDevice.https.html [ Failure Timeout ] +crbug.com/407404837 [ Win ] virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechRecognition-installOnDevice.https.html [ Failure Timeout ] crbug.com/406805472 [ Mac12 ] external/wpt/import-maps/data-url-specifiers.sub.html [ Skip Timeout ] crbug.com/406805472 [ Mac13 ] virtual/speculation-rules-prerender-target-hint/external/wpt/speculation-rules/prerender/protocol-handler-register.https.html [ Skip Timeout ] crbug.com/406805472 [ Mac13 ] virtual/speculation-rules-prerender-target-hint/external/wpt/speculation-rules/prerender/protocol-handler-unregister.https.html [ Skip Timeout ] @@ -8662,25 +8661,6 @@ # backdrop-filter-mirror-edge crbug.com/904592 external/wpt/css/filter-effects/backdrop-filter-svg-blur.html [ Failure ] -# css-relative-currentcolor-disabled -# Failures without CSSRelativeColorSupportsCurrentcolor enabled -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-a98rgb-01.html [ Crash Failure Timeout ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-displayp3-01.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-hsl-01.html [ Crash Failure Timeout ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-hsl-02.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-hwb-01.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-lab-01.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-lch-01.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-oklab-01.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-oklch-01.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-prophoto-01.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-rec2020-01.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-rec2020-02.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-rgb-01.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-rgb-02.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-xyzd50-01.html [ Crash Failure ] -crbug.com/325309578 virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-xyzd65-01.html [ Crash Failure ] - # Branch Gardener 2024-04-10 crbug.com/333639341 [ Fuchsia ] fast/writing-mode/english-lr-text.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 0c5635b..c6993c5 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -4166,47 +4166,6 @@ "owners": ["masonf@chromium.org", "stephanie.zhang@microsoft.com", "sajos@microsoft.com"] }, { - "prefix": "css-relative-currentcolor-disabled", - "platforms": ["Linux"], - "bases": [ - "external/wpt/css/css-color/relative-currentcolor-a98rgb-01.html", - "external/wpt/css/css-color/relative-currentcolor-displayp3-01.html", - "external/wpt/css/css-color/relative-currentcolor-hsl-01.html", - "external/wpt/css/css-color/relative-currentcolor-hsl-02.html", - "external/wpt/css/css-color/relative-currentcolor-hwb-01.html", - "external/wpt/css/css-color/relative-currentcolor-lab-01.html", - "external/wpt/css/css-color/relative-currentcolor-lch-01.html", - "external/wpt/css/css-color/relative-currentcolor-oklab-01.html", - "external/wpt/css/css-color/relative-currentcolor-oklch-01.html", - "external/wpt/css/css-color/relative-currentcolor-prophoto-01.html", - "external/wpt/css/css-color/relative-currentcolor-rec2020-01.html", - "external/wpt/css/css-color/relative-currentcolor-rec2020-02.html", - "external/wpt/css/css-color/relative-currentcolor-rgb-01.html", - "external/wpt/css/css-color/relative-currentcolor-rgb-02.html", - "external/wpt/css/css-color/relative-currentcolor-visited-getcomputedstyle.html", - "external/wpt/css/css-color/relative-currentcolor-xyzd50-01.html", - "external/wpt/css/css-color/relative-currentcolor-xyzd65-01.html", - "external/wpt/css/css-color/parsing/color-computed-relative-color.html", - "external/wpt/css/css-color/parsing/color-invalid-relative-color.html", - "external/wpt/css/css-color/parsing/color-valid-relative-color.html", - "external/wpt/css/css-color/parsing/relative-color-out-of-gamut.html", - "external/wpt/css/css-properties-values-api/registered-property-computation.html" - ], - "args": ["--disable-blink-features=CSSRelativeColorSupportsCurrentcolor"], - "owners": ["kbabbitt@microsoft.com"], - "expires": "Jun 1, 2025" - }, - { - "prefix": "css-relative-preservenone-disabled", - "platforms": ["Linux"], - "bases": [ - "external/wpt/css/css-color/parsing/color-computed-relative-color.html" - ], - "args": ["--disable-blink-features=CSSRelativeColorPreserveNone"], - "owners": ["kbabbitt@microsoft.com"], - "expires": "Sep 1, 2025" - }, - { "prefix": "partitioned-popins-disabled", "platforms": ["Linux", "Mac", "Win"], "bases": ["external/wpt/partitioned-popins/"],
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsetheight.html b/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsetheight.html index 5bdc33b..cc49f339 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsetheight.html +++ b/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsetheight.html
@@ -19,11 +19,11 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> - test(()=> { assert_equals(table.offsetHeight, 120); }, "table"); - test(()=> { assert_equals(colgroup.offsetHeight, 100); }, "colgroup"); - test(()=> { assert_equals(col.offsetHeight, 100); }, "col"); - test(()=> { assert_equals(rowgroup.offsetHeight, 100); }, "rowgroup"); - test(()=> { assert_equals(row.offsetHeight, 100); }, "row"); - test(()=> { assert_equals(cell.offsetHeight, 100); }, "cell"); - test(()=> { assert_equals(content.offsetHeight, 100); }, "content"); + test(()=> { assert_equals(table.offsetHeight, 70); }, "table"); + test(()=> { assert_equals(colgroup.offsetHeight, 70); }, "colgroup"); + test(()=> { assert_equals(col.offsetHeight, 70); }, "col"); + test(()=> { assert_equals(rowgroup.offsetHeight, 70); }, "rowgroup"); + test(()=> { assert_equals(row.offsetHeight, 70); }, "row"); + test(()=> { assert_equals(cell.offsetHeight, 70); }, "cell"); + test(()=> { assert_equals(content.offsetHeight, 70); }, "content"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html index bdac1f4..77516a6 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html
@@ -39,103 +39,103 @@ test(() => { assert_equals(table.offsetTop, 8, "offsetTop"); assert_equals(table.offsetLeft, 8, "offsetLeft"); - assert_equals(table.offsetWidth, 177, "offsetWidth"); - assert_equals(table.offsetHeight, 184, "offsetHeight"); + assert_equals(table.offsetWidth, 70, "offsetWidth"); + assert_equals(table.offsetHeight, 584, "offsetHeight"); }, "table"); test(() => { assert_equals(colgroup.offsetTop, 18, "offsetTop"); assert_equals(colgroup.offsetLeft, 18, "offsetLeft"); - assert_equals(colgroup.offsetWidth, 157, "offsetWidth"); - assert_equals(colgroup.offsetHeight, 107, "offsetHeight"); + assert_equals(colgroup.offsetWidth, 70, "offsetWidth"); + assert_equals(colgroup.offsetHeight, 507, "offsetHeight"); }, "colgroup"); test(() => { assert_equals(col.offsetTop, 18, "offsetTop"); assert_equals(col.offsetLeft, 18, "offsetLeft"); - assert_equals(col.offsetWidth, 157, "offsetWidth"); - assert_equals(col.offsetHeight, 50, "offsetHeight"); + assert_equals(col.offsetWidth, 70, "offsetWidth"); + assert_equals(col.offsetHeight, 450, "offsetHeight"); }, "col"); test(() => { assert_equals(col2.offsetTop, 75, "offsetTop"); assert_equals(col2.offsetLeft, 18, "offsetLeft"); - assert_equals(col2.offsetWidth, 157, "offsetWidth"); - assert_equals(col2.offsetHeight, 50, "offsetHeight"); + assert_equals(col2.offsetWidth, 70, "offsetWidth"); + assert_equals(col2.offsetHeight, 450, "offsetHeight"); }, "col2"); test(() => { assert_equals(colgroup2.offsetTop, 132, "offsetTop"); assert_equals(colgroup2.offsetLeft, 18, "offsetLeft"); - assert_equals(colgroup2.offsetWidth, 157, "offsetWidth"); - assert_equals(colgroup2.offsetHeight, 50, "offsetHeight"); + assert_equals(colgroup2.offsetWidth, 70, "offsetWidth"); + assert_equals(colgroup2.offsetHeight, 450, "offsetHeight"); }, "colgroup2"); test(() => { assert_equals(col3.offsetTop, 132, "offsetTop"); assert_equals(col3.offsetLeft, 18, "offsetLeft"); - assert_equals(col3.offsetWidth, 157, "offsetWidth"); - assert_equals(col3.offsetHeight, 50, "offsetHeight"); + assert_equals(col3.offsetWidth, 70, "offsetWidth"); + assert_equals(col3.offsetHeight, 450, "offsetHeight"); }, "col3"); test(() => { assert_equals(rowgroup.offsetTop, 18, "offsetTop"); assert_equals(rowgroup.offsetLeft, 18, "offsetLeft"); - assert_equals(rowgroup.offsetWidth, 157, "offsetWidth"); - assert_equals(rowgroup.offsetHeight, 164, "offsetHeight"); + assert_equals(rowgroup.offsetWidth, 70, "offsetWidth"); + assert_equals(rowgroup.offsetHeight, 564, "offsetHeight"); }, "rowgroup"); test(() => { assert_equals(row.offsetTop, 18, "offsetTop"); assert_equals(row.offsetLeft, 18, "offsetLeft"); - assert_equals(row.offsetWidth, 100, "offsetWidth"); - assert_equals(row.offsetHeight, 164, "offsetHeight"); + assert_equals(row.offsetWidth, 70, "offsetWidth"); + assert_equals(row.offsetHeight, 364, "offsetHeight"); }, "row"); test(() => { assert_equals(cell.offsetTop, 18, "offsetTop"); assert_equals(cell.offsetLeft, 18, "offsetLeft"); - assert_equals(cell.offsetWidth, 100, "offsetWidth"); - assert_equals(cell.offsetHeight, 50, "offsetHeight"); + assert_equals(cell.offsetWidth, 70, "offsetWidth"); + assert_equals(cell.offsetHeight, 250, "offsetHeight"); }, "cell"); test(() => { assert_equals(content.offsetTop, 18, "offsetTop"); assert_equals(content.offsetLeft, 18, "offsetLeft"); - assert_equals(content.offsetWidth, 100, "offsetWidth"); - assert_equals(content.offsetHeight, 50, "offsetHeight"); + assert_equals(content.offsetWidth, 70, "offsetWidth"); + assert_equals(content.offsetHeight, 250, "offsetHeight"); }, "content"); test(() => { assert_equals(cell2.offsetTop, 75, "offsetTop"); assert_equals(cell2.offsetLeft, 18, "offsetLeft"); - assert_equals(cell2.offsetWidth, 100, "offsetWidth"); - assert_equals(cell2.offsetHeight, 50, "offsetHeight"); + assert_equals(cell2.offsetWidth, 70, "offsetWidth"); + assert_equals(cell2.offsetHeight, 250, "offsetHeight"); }, "cell2"); test(() => { assert_equals(content2.offsetTop, 75, "offsetTop"); assert_equals(content2.offsetLeft, 18, "offsetLeft"); - assert_equals(content2.offsetWidth, 100, "offsetWidth"); - assert_equals(content2.offsetHeight, 50, "offsetHeight"); + assert_equals(content2.offsetWidth, 70, "offsetWidth"); + assert_equals(content2.offsetHeight, 250, "offsetHeight"); }, "content2"); test(() => { assert_equals(cell3.offsetTop, 132, "offsetTop"); assert_equals(cell3.offsetLeft, 18, "offsetLeft"); - assert_equals(cell3.offsetWidth, 100, "offsetWidth"); - assert_equals(cell3.offsetHeight, 50, "offsetHeight"); + assert_equals(cell3.offsetWidth, 70, "offsetWidth"); + assert_equals(cell3.offsetHeight, 250, "offsetHeight"); }, "cell3"); test(() => { assert_equals(content3.offsetTop, 132, "offsetTop"); assert_equals(content3.offsetLeft, 18, "offsetLeft"); - assert_equals(content3.offsetWidth, 100, "offsetWidth"); - assert_equals(content3.offsetHeight, 50, "offsetHeight"); + assert_equals(content3.offsetWidth, 70, "offsetWidth"); + assert_equals(content3.offsetHeight, 250, "offsetHeight"); }, "content3"); test(() => { assert_equals(row2.offsetTop, 218, "offsetTop"); assert_equals(row2.offsetLeft, 55, "offsetLeft"); - assert_equals(row2.offsetWidth, 50, "offsetWidth"); - assert_equals(row2.offsetHeight, 164, "offsetHeight"); + assert_equals(row2.offsetWidth, 70, "offsetWidth"); + assert_equals(row2.offsetHeight, 364, "offsetHeight"); }, "row2"); test(() => { assert_equals(cell4.offsetTop, 218, "offsetTop"); assert_equals(cell4.offsetLeft, 55, "offsetLeft"); - assert_equals(cell4.offsetWidth, 50, "offsetWidth"); - assert_equals(cell4.offsetHeight, 50, "offsetHeight"); + assert_equals(cell4.offsetWidth, 70, "offsetWidth"); + assert_equals(cell4.offsetHeight, 250, "offsetHeight"); }, "cell4"); test(() => { assert_equals(content4.offsetTop, 218, "offsetTop"); assert_equals(content4.offsetLeft, 55, "offsetLeft"); - assert_equals(content4.offsetWidth, 50, "offsetWidth"); - assert_equals(content4.offsetHeight, 50, "offsetHeight"); + assert_equals(content4.offsetWidth, 70, "offsetWidth"); + assert_equals(content4.offsetHeight, 250, "offsetHeight"); }, "content4"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html index 1eb751032..ea58b14 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html
@@ -39,103 +39,103 @@ test(() => { assert_equals(table.offsetTop, 8, "offsetTop"); assert_equals(table.offsetLeft, 8, "offsetLeft"); - assert_equals(table.offsetWidth, 177, "offsetWidth"); - assert_equals(table.offsetHeight, 184, "offsetHeight"); + assert_equals(table.offsetWidth, 70, "offsetWidth"); + assert_equals(table.offsetHeight, 584, "offsetHeight"); }, "table"); test(() => { assert_equals(colgroup.offsetTop, 18, "offsetTop"); assert_equals(colgroup.offsetLeft, 8, "offsetLeft"); - assert_equals(colgroup.offsetWidth, 157, "offsetWidth"); - assert_equals(colgroup.offsetHeight, 107, "offsetHeight"); + assert_equals(colgroup.offsetWidth, 70, "offsetWidth"); + assert_equals(colgroup.offsetHeight, 507, "offsetHeight"); }, "colgroup"); test(() => { assert_equals(col.offsetTop, 18, "offsetTop"); assert_equals(col.offsetLeft, 8, "offsetLeft"); - assert_equals(col.offsetWidth, 157, "offsetWidth"); - assert_equals(col.offsetHeight, 50, "offsetHeight"); + assert_equals(col.offsetWidth, 70, "offsetWidth"); + assert_equals(col.offsetHeight, 450, "offsetHeight"); }, "col"); test(() => { assert_equals(col2.offsetTop, 75, "offsetTop"); assert_equals(col2.offsetLeft, 8, "offsetLeft"); - assert_equals(col2.offsetWidth, 157, "offsetWidth"); - assert_equals(col2.offsetHeight, 50, "offsetHeight"); + assert_equals(col2.offsetWidth, 70, "offsetWidth"); + assert_equals(col2.offsetHeight, 450, "offsetHeight"); }, "col2"); test(() => { assert_equals(colgroup2.offsetTop, 132, "offsetTop"); assert_equals(colgroup2.offsetLeft, 8, "offsetLeft"); - assert_equals(colgroup2.offsetWidth, 157, "offsetWidth"); - assert_equals(colgroup2.offsetHeight, 50, "offsetHeight"); + assert_equals(colgroup2.offsetWidth, 70, "offsetWidth"); + assert_equals(colgroup2.offsetHeight, 450, "offsetHeight"); }, "colgroup2"); test(() => { assert_equals(col3.offsetTop, 132, "offsetTop"); assert_equals(col3.offsetLeft, 8, "offsetLeft"); - assert_equals(col3.offsetWidth, 157, "offsetWidth"); - assert_equals(col3.offsetHeight, 50, "offsetHeight"); + assert_equals(col3.offsetWidth, 70, "offsetWidth"); + assert_equals(col3.offsetHeight, 450, "offsetHeight"); }, "col3"); test(() => { assert_equals(rowgroup.offsetTop, 18, "offsetTop"); assert_equals(rowgroup.offsetLeft, 8, "offsetLeft"); - assert_equals(rowgroup.offsetWidth, 157, "offsetWidth"); - assert_equals(rowgroup.offsetHeight, 164, "offsetHeight"); + assert_equals(rowgroup.offsetWidth, 70, "offsetWidth"); + assert_equals(rowgroup.offsetHeight, 564, "offsetHeight"); }, "rowgroup"); test(() => { assert_equals(row.offsetTop, 18, "offsetTop"); assert_equals(row.offsetLeft, 8, "offsetLeft"); - assert_equals(row.offsetWidth, 100, "offsetWidth"); - assert_equals(row.offsetHeight, 164, "offsetHeight"); + assert_equals(row.offsetWidth, 70, "offsetWidth"); + assert_equals(row.offsetHeight, 364, "offsetHeight"); }, "row"); test(() => { assert_equals(cell.offsetTop, 18, "offsetTop"); assert_equals(cell.offsetLeft, 8, "offsetLeft"); - assert_equals(cell.offsetWidth, 100, "offsetWidth"); - assert_equals(cell.offsetHeight, 50, "offsetHeight"); + assert_equals(cell.offsetWidth, 70, "offsetWidth"); + assert_equals(cell.offsetHeight, 250, "offsetHeight"); }, "cell"); test(() => { assert_equals(content.offsetTop, 18, "offsetTop"); assert_equals(content.offsetLeft, 8, "offsetLeft"); - assert_equals(content.offsetWidth, 100, "offsetWidth"); - assert_equals(content.offsetHeight, 50, "offsetHeight"); + assert_equals(content.offsetWidth, 70, "offsetWidth"); + assert_equals(content.offsetHeight, 250, "offsetHeight"); }, "content"); test(() => { assert_equals(cell2.offsetTop, 75, "offsetTop"); assert_equals(cell2.offsetLeft, 8, "offsetLeft"); - assert_equals(cell2.offsetWidth, 100, "offsetWidth"); - assert_equals(cell2.offsetHeight, 50, "offsetHeight"); + assert_equals(cell2.offsetWidth, 70, "offsetWidth"); + assert_equals(cell2.offsetHeight, 250, "offsetHeight"); }, "cell2"); test(() => { assert_equals(content2.offsetTop, 75, "offsetTop"); assert_equals(content2.offsetLeft, 8, "offsetLeft"); - assert_equals(content2.offsetWidth, 100, "offsetWidth"); - assert_equals(content2.offsetHeight, 50, "offsetHeight"); + assert_equals(content2.offsetWidth, 70, "offsetWidth"); + assert_equals(content2.offsetHeight, 250, "offsetHeight"); }, "content2"); test(() => { assert_equals(cell3.offsetTop, 132, "offsetTop"); assert_equals(cell3.offsetLeft, 8, "offsetLeft"); - assert_equals(cell3.offsetWidth, 100, "offsetWidth"); - assert_equals(cell3.offsetHeight, 50, "offsetHeight"); + assert_equals(cell3.offsetWidth, 70, "offsetWidth"); + assert_equals(cell3.offsetHeight, 250, "offsetHeight"); }, "cell3"); test(() => { assert_equals(content3.offsetTop, 132, "offsetTop"); assert_equals(content3.offsetLeft, 8, "offsetLeft"); - assert_equals(content3.offsetWidth, 100, "offsetWidth"); - assert_equals(content3.offsetHeight, 50, "offsetHeight"); + assert_equals(content3.offsetWidth, 70, "offsetWidth"); + assert_equals(content3.offsetHeight, 250, "offsetHeight"); }, "content3"); test(() => { assert_equals(row2.offsetTop, 218, "offsetTop"); assert_equals(row2.offsetLeft, 8, "offsetLeft"); - assert_equals(row2.offsetWidth, 50, "offsetWidth"); - assert_equals(row2.offsetHeight, 164, "offsetHeight"); + assert_equals(row2.offsetWidth, 70, "offsetWidth"); + assert_equals(row2.offsetHeight, 364, "offsetHeight"); }, "row2"); test(() => { assert_equals(cell4.offsetTop, 218, "offsetTop"); assert_equals(cell4.offsetLeft, 8, "offsetLeft"); - assert_equals(cell4.offsetWidth, 50, "offsetWidth"); - assert_equals(cell4.offsetHeight, 50, "offsetHeight"); + assert_equals(cell4.offsetWidth, 70, "offsetWidth"); + assert_equals(cell4.offsetHeight, 250, "offsetHeight"); }, "cell4"); test(() => { assert_equals(content4.offsetTop, 218, "offsetTop"); assert_equals(content4.offsetLeft, 8, "offsetLeft"); - assert_equals(content4.offsetWidth, 50, "offsetWidth"); - assert_equals(content4.offsetHeight, 50, "offsetHeight"); + assert_equals(content4.offsetWidth, 70, "offsetWidth"); + assert_equals(content4.offsetHeight, 250, "offsetHeight"); }, "content4"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets.tentative.html index 265d761..4bed47b6 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-break/table/table-parts-offsets.tentative.html
@@ -38,103 +38,103 @@ test(() => { assert_equals(table.offsetTop, 8, "offsetTop"); assert_equals(table.offsetLeft, 8, "offsetLeft"); - assert_equals(table.offsetWidth, 184, "offsetWidth"); - assert_equals(table.offsetHeight, 177, "offsetHeight"); + assert_equals(table.offsetWidth, 584, "offsetWidth"); + assert_equals(table.offsetHeight, 70, "offsetHeight"); }, "table"); test(() => { assert_equals(colgroup.offsetTop, 18, "offsetTop"); assert_equals(colgroup.offsetLeft, 18, "offsetLeft"); - assert_equals(colgroup.offsetWidth, 107, "offsetWidth"); - assert_equals(colgroup.offsetHeight, 157, "offsetHeight"); + assert_equals(colgroup.offsetWidth, 507, "offsetWidth"); + assert_equals(colgroup.offsetHeight, 70, "offsetHeight"); }, "colgroup"); test(() => { assert_equals(col.offsetTop, 18, "offsetTop"); assert_equals(col.offsetLeft, 18, "offsetLeft"); - assert_equals(col.offsetWidth, 50, "offsetWidth"); - assert_equals(col.offsetHeight, 157, "offsetHeight"); + assert_equals(col.offsetWidth, 450, "offsetWidth"); + assert_equals(col.offsetHeight, 70, "offsetHeight"); }, "col"); test(() => { assert_equals(col2.offsetTop, 18, "offsetTop"); assert_equals(col2.offsetLeft, 75, "offsetLeft"); - assert_equals(col2.offsetWidth, 50, "offsetWidth"); - assert_equals(col2.offsetHeight, 157, "offsetHeight"); + assert_equals(col2.offsetWidth, 450, "offsetWidth"); + assert_equals(col2.offsetHeight, 70, "offsetHeight"); }, "col2"); test(() => { assert_equals(colgroup2.offsetTop, 18, "offsetTop"); assert_equals(colgroup2.offsetLeft, 132, "offsetLeft"); - assert_equals(colgroup2.offsetWidth, 50, "offsetWidth"); - assert_equals(colgroup2.offsetHeight, 157, "offsetHeight"); + assert_equals(colgroup2.offsetWidth, 450, "offsetWidth"); + assert_equals(colgroup2.offsetHeight, 70, "offsetHeight"); }, "colgroup2"); test(() => { assert_equals(col3.offsetTop, 18, "offsetTop"); assert_equals(col3.offsetLeft, 132, "offsetLeft"); - assert_equals(col3.offsetWidth, 50, "offsetWidth"); - assert_equals(col3.offsetHeight, 157, "offsetHeight"); + assert_equals(col3.offsetWidth, 450, "offsetWidth"); + assert_equals(col3.offsetHeight, 70, "offsetHeight"); }, "col3"); test(() => { assert_equals(rowgroup.offsetTop, 18, "offsetTop"); assert_equals(rowgroup.offsetLeft, 18, "offsetLeft"); - assert_equals(rowgroup.offsetWidth, 164, "offsetWidth"); - assert_equals(rowgroup.offsetHeight, 157, "offsetHeight"); + assert_equals(rowgroup.offsetWidth, 564, "offsetWidth"); + assert_equals(rowgroup.offsetHeight, 70, "offsetHeight"); }, "rowgroup"); test(() => { assert_equals(row.offsetTop, 18, "offsetTop"); assert_equals(row.offsetLeft, 18, "offsetLeft"); - assert_equals(row.offsetWidth, 164, "offsetWidth"); - assert_equals(row.offsetHeight, 100, "offsetHeight"); + assert_equals(row.offsetWidth, 364, "offsetWidth"); + assert_equals(row.offsetHeight, 70, "offsetHeight"); }, "row"); test(() => { assert_equals(cell.offsetTop, 18, "offsetTop"); assert_equals(cell.offsetLeft, 18, "offsetLeft"); - assert_equals(cell.offsetWidth, 50, "offsetWidth"); - assert_equals(cell.offsetHeight, 100, "offsetHeight"); + assert_equals(cell.offsetWidth, 250, "offsetWidth"); + assert_equals(cell.offsetHeight, 70, "offsetHeight"); }, "cell"); test(() => { assert_equals(content.offsetTop, 18, "offsetTop"); assert_equals(content.offsetLeft, 18, "offsetLeft"); - assert_equals(content.offsetWidth, 50, "offsetWidth"); - assert_equals(content.offsetHeight, 100, "offsetHeight"); + assert_equals(content.offsetWidth, 250, "offsetWidth"); + assert_equals(content.offsetHeight, 70, "offsetHeight"); }, "content"); test(() => { assert_equals(cell2.offsetTop, 18, "offsetTop"); assert_equals(cell2.offsetLeft, 75, "offsetLeft"); - assert_equals(cell2.offsetWidth, 50, "offsetWidth"); - assert_equals(cell2.offsetHeight, 100, "offsetHeight"); + assert_equals(cell2.offsetWidth, 250, "offsetWidth"); + assert_equals(cell2.offsetHeight, 70, "offsetHeight"); }, "cell2"); test(() => { assert_equals(content2.offsetTop, 18, "offsetTop"); assert_equals(content2.offsetLeft, 75, "offsetLeft"); - assert_equals(content2.offsetWidth, 50, "offsetWidth"); - assert_equals(content2.offsetHeight, 100, "offsetHeight"); + assert_equals(content2.offsetWidth, 250, "offsetWidth"); + assert_equals(content2.offsetHeight, 70, "offsetHeight"); }, "content2"); test(() => { assert_equals(cell3.offsetTop, 18, "offsetTop"); assert_equals(cell3.offsetLeft, 132, "offsetLeft"); - assert_equals(cell3.offsetWidth, 50, "offsetWidth"); - assert_equals(cell3.offsetHeight, 100, "offsetHeight"); + assert_equals(cell3.offsetWidth, 250, "offsetWidth"); + assert_equals(cell3.offsetHeight, 70, "offsetHeight"); }, "cell3"); test(() => { assert_equals(content3.offsetTop, 18, "offsetTop"); assert_equals(content3.offsetLeft, 132, "offsetLeft"); - assert_equals(content3.offsetWidth, 50, "offsetWidth"); - assert_equals(content3.offsetHeight, 100, "offsetHeight"); + assert_equals(content3.offsetWidth, 250, "offsetWidth"); + assert_equals(content3.offsetHeight, 70, "offsetHeight"); }, "content3"); test(() => { assert_equals(row2.offsetTop, 55, "offsetTop"); assert_equals(row2.offsetLeft, 218, "offsetLeft"); - assert_equals(row2.offsetWidth, 164, "offsetWidth"); - assert_equals(row2.offsetHeight, 50, "offsetHeight"); + assert_equals(row2.offsetWidth, 364, "offsetWidth"); + assert_equals(row2.offsetHeight, 70, "offsetHeight"); }, "row2"); test(() => { assert_equals(cell4.offsetTop, 55, "offsetTop"); assert_equals(cell4.offsetLeft, 218, "offsetLeft"); - assert_equals(cell4.offsetWidth, 50, "offsetWidth"); - assert_equals(cell4.offsetHeight, 50, "offsetHeight"); + assert_equals(cell4.offsetWidth, 250, "offsetWidth"); + assert_equals(cell4.offsetHeight, 70, "offsetHeight"); }, "cell4"); test(() => { assert_equals(content4.offsetTop, 55, "offsetTop"); assert_equals(content4.offsetLeft, 218, "offsetLeft"); - assert_equals(content4.offsetWidth, 50, "offsetWidth"); - assert_equals(content4.offsetHeight, 50, "offsetHeight"); + assert_equals(content4.offsetWidth, 250, "offsetWidth"); + assert_equals(content4.offsetHeight, 70, "offsetHeight"); }, "content4"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/offsetProps-001.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/offsetProps-001.html new file mode 100644 index 0000000..a592c5a8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/offsetProps-001.html
@@ -0,0 +1,41 @@ +<!DOCTYPE html> +<title>offsetWidth and offsetHeight of fragmented inline</title> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div style="columns:3; column-fill:auto; column-gap:10px; width:320px; height:50px; font:8px/16px Ahem; orphans:1; widows:1; background:lightgray;"> + p<br> + ppp + <span id="outer" style="background:cyan;"> + <span id="middle" style="background:yellow;"> + <span id="inner1" style="color:blue;"> + pppp pppp + </span> + <span id="inner2" style="color:green;"> + pppp pppp + </span> + </span> + pppp pppp pppp pppp pppp pppp pppp pppp + </span> + </span> +</div> +<script> + test(()=> { + assert_equals(outer.offsetWidth, 292); + assert_equals(outer.offsetHeight, 40); + }, "outer"); + test(()=> { + assert_equals(middle.offsetWidth, 150); + assert_equals(middle.offsetHeight, 40); + }, "middle"); + test(()=> { + assert_equals(inner1.offsetWidth, 64); + assert_equals(inner1.offsetHeight, 24); + }, "inner1"); + test(()=> { + assert_equals(inner2.offsetWidth, 110); + assert_equals(inner2.offsetHeight, 40); + }, "inner2"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/tree-counting/sibling-function-descriptors.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-values/tree-counting/sibling-function-descriptors.tentative.html index 76d2ff8e..8f597aa 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-values/tree-counting/sibling-function-descriptors.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-values/tree-counting/sibling-function-descriptors.tentative.html
@@ -83,6 +83,16 @@ symbols: linear-gradient(red calc(20px * sibling-count()), pink); } </style> +<style id="font_features_sheet"> + @font-feature-values foo { + @swash { pretty: 1; } + @swash { pretty: calc(max(sibling-index(), 2)); } + } + @font-feature-values bar { + @swash { pretty: 1; } + @swash { pretty: calc(max(sibling-count(), 2)); } + } +</style> <script> const page_rules = page_sheet.sheet.cssRules; @@ -140,4 +150,17 @@ assert_equals(counter_style_rules[1].symbols, "--pass"); }, "sibling-count() should not be allowed in @counter-style descriptors"); + + const font_features_rules = font_features_sheet.sheet.cssRules; + + test(() => { + const swash = font_features_rules[0].swash; + assert_equals(swash.get("pretty")[0], 1); + }, "sibling-index() should not be allowed in @font-feature-values descriptors"); + + test(() => { + const swash = font_features_rules[1].swash; + assert_equals(swash.get("pretty")[0], 1); + }, "sibling-count() should not be allowed in @font-feature-values descriptors"); + </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/tree-counting/sibling-index-keyframe-percent-dynamic.html b/third_party/blink/web_tests/external/wpt/css/css-values/tree-counting/sibling-index-keyframe-percent-dynamic.html new file mode 100644 index 0000000..58d1e799 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/tree-counting/sibling-index-keyframe-percent-dynamic.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<title>CSS Values and Units Test: sibling-index() changing percentage during @keyframes animation</title> +<link rel="help" href="https://drafts.csswg.org/css-values-5/#tree-counting"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + @keyframes --anim { + from { + text-size-adjust: calc(50% * sibling-index()); + } + to { + text-size-adjust: 90%; + } + } + #target { + animation: --anim 1000s step-end; + } +</style> +<div> + <div id="rm"></div> + <div></div> + <div id="target"></div> +</div> +<script> + test(() => { + assert_equals(getComputedStyle(target).textSizeAdjust, "150%"); + }, "Initially, the sibling-index() is 3 for #target"); + + test(() => { + rm.remove(); + assert_equals(getComputedStyle(target).textSizeAdjust, "100%"); + }, "Removing a preceding sibling of #target reduces the sibling-index()"); + +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/urls/fragment-only-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-values/urls/fragment-only-expected.txt deleted file mode 100644 index e79da1e..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-values/urls/fragment-only-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This is a testharness.js-based test. -[FAIL] empty URL: inline-unquoted - assert_equals: expected "url(\\"#foo\\")" but got "url(\\"http://web-platform.test:8001/css/css-values/urls/fragment-only.html#foo\\")" -[FAIL] empty URL: inline-quoted - assert_equals: expected "url(\\"#foo\\")" but got "url(\\"http://web-platform.test:8001/css/css-values/urls/fragment-only.html#foo\\")" -[FAIL] empty URL: external-unquoted - assert_equals: expected "url(\\"#foo\\")" but got "url(\\"http://web-platform.test:8001/css/css-values/urls/support/fragment-only-urls.css#foo\\")" -[FAIL] empty URL: external-quoted - assert_equals: expected "url(\\"#foo\\")" but got "url(\\"http://web-platform.test:8001/css/css-values/urls/support/fragment-only-urls.css#foo\\")" -[FAIL] empty URL: external-variable - assert_equals: expected "url(\\"#foo\\")" but got "url(\\"http://web-platform.test:8001/css/css-values/urls/support/fragment-only-urls.css#foo\\")" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/utils.sub.js b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/utils.sub.js index d4efc2dc..adb15d4e 100644 --- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/utils.sub.js +++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/resources/utils.sub.js
@@ -227,6 +227,18 @@ assert_prefetched(interceptedRequest.request.headers, "Prefetch request should be intercepted."); + + if (new URL(location.href).searchParams.has('clientId')) { + // https://github.com/WICG/nav-speculation/issues/346 + // https://crbug.com/404294123 + assert_equals(interceptedRequest.resultingClientId, "", + "resultingClientId shouldn't be exposed."); + + // https://crbug.com/404286918 + // `assert_not_equals()` isn't used for now to create stable failure diffs. + assert_false(interceptedRequest.clientId === "", + "clientId should be initiator."); + } } // The ServiceWorker fetch handler intercepted a non-prefetching request. @@ -236,6 +248,16 @@ assert_not_prefetched(interceptedRequest.request.headers, "Non-prefetch request should be intercepted."); + + if (new URL(location.href).searchParams.has('clientId')) { + // Because this is an ordinal non-prefetch request, `resultingClientId` + // can be set as normal. + assert_not_equals(interceptedRequest.resultingClientId, "", + "resultingClientId can be exposed."); + + assert_not_equals(interceptedRequest.clientId, "", + "clientId should be initiator."); + } } // Use nvs_header query parameter to ask the wpt server
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html index 98e089bc..5b2a4d00 100644 --- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html +++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https.html
@@ -15,11 +15,23 @@ <meta name="variant" content="?origin=same-site&sw=no-fetch-handler"> <meta name="variant" content="?origin=same-site&sw=no-controller"> +<meta name="variant" content="?origin=same-site&sw=fetch-handler&clientId"> +<meta name="variant" content="?origin=same-site&sw=fetch-handler-to-fallback&clientId"> +<meta name="variant" content="?origin=same-site&sw=fetch-handler-modify-url&clientId"> +<meta name="variant" content="?origin=same-site&sw=fetch-handler-modify-referrer&clientId"> +<meta name="variant" content="?origin=same-site&sw=no-fetch-handler&clientId"> +<meta name="variant" content="?origin=same-site&sw=no-controller&clientId"> + <meta name="variant" content="?origin=cross-site&sw=fetch-handler"> <meta name="variant" content="?origin=cross-site&sw=fetch-handler-to-fallback"> <meta name="variant" content="?origin=cross-site&sw=no-fetch-handler"> <meta name="variant" content="?origin=cross-site&sw=no-controller"> +<meta name="variant" content="?origin=cross-site&sw=fetch-handler&clientId"> +<meta name="variant" content="?origin=cross-site&sw=fetch-handler-to-fallback&clientId"> +<meta name="variant" content="?origin=cross-site&sw=no-fetch-handler&clientId"> +<meta name="variant" content="?origin=cross-site&sw=no-controller&clientId"> + <script> setup(() => assertSpeculationRulesIsSupported());
diff --git a/third_party/blink/web_tests/fast/forms/select/select-text-transform-expected.html b/third_party/blink/web_tests/fast/forms/select/select-text-transform-expected.html index 82b2c9b..9441c46 100644 --- a/third_party/blink/web_tests/fast/forms/select/select-text-transform-expected.html +++ b/third_party/blink/web_tests/fast/forms/select/select-text-transform-expected.html
@@ -27,9 +27,9 @@ <span>SS SSSS</span> </div> <div> - <select><option>ß</option><option>ßß</option></select> - <select multiple="true"><option>ß</option><option>ßß</option></select> - <span>ß ßß</span> + <select><option>Ss</option><option>Ssß</option></select> + <select multiple="true"><option>Ss</option><option>Ssß</option></select> + <span>Ss Ssß</span> </div> <div> <select><option>ß</option><option>ßß</option></select>
diff --git a/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space-after-strutless-break.html b/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space-after-strutless-break.html index 0c5d5d5f..8486873e 100644 --- a/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space-after-strutless-break.html +++ b/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space-after-strutless-break.html
@@ -60,10 +60,15 @@ var child2 = document.getElementById("child2"); var child3 = document.getElementById("child3"); var child4 = document.getElementById("child4"); - assert_equals(parent.offsetHeight, 240); - assert_equals(child1.offsetHeight, 140); + assert_equals(parent.offsetWidth, 60); + assert_equals(parent.offsetHeight, 60); + assert_equals(child1.offsetWidth, 45); + assert_equals(child1.offsetHeight, 60); + assert_equals(child2.offsetWidth, 15); assert_equals(child2.offsetHeight, 40); + assert_equals(child3.offsetWidth, 15); assert_equals(child3.offsetHeight, 20); + assert_equals(child4.offsetWidth, 15); assert_equals(child4.offsetHeight, 40); }, "Balance, non-auto height, unused space at break after perfect break with no space loss"); </script>
diff --git a/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space-nested-block.html b/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space-nested-block.html index fa63481..24e4ed5 100644 --- a/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space-nested-block.html +++ b/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space-nested-block.html
@@ -19,8 +19,11 @@ var parent = document.getElementById("parent"); var child1 = document.getElementById("child1"); var child2 = document.getElementById("child2"); - assert_equals(parent.offsetHeight, 400); + assert_equals(parent.offsetWidth, 100); + assert_equals(parent.offsetHeight, 100); + assert_equals(child1.offsetWidth, 25); assert_equals(child1.offsetHeight, 100); - assert_equals(child2.offsetHeight, 300); + assert_equals(child2.offsetWidth, 75); + assert_equals(child2.offsetHeight, 100); }, "Balance, non-auto height, unused space"); </script>
diff --git a/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space.html b/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space.html index 7547fcc..3b7eccc 100644 --- a/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space.html +++ b/third_party/blink/web_tests/fast/multicol/balance-fixed-height-unused-space.html
@@ -17,8 +17,11 @@ var parent = document.getElementById("parent"); var child1 = document.getElementById("child1"); var child2 = document.getElementById("child2"); - assert_equals(parent.offsetHeight, 400); + assert_equals(parent.offsetWidth, 100); + assert_equals(parent.offsetHeight, 100); + assert_equals(child1.offsetWidth, 25); assert_equals(child1.offsetHeight, 100); - assert_equals(child2.offsetHeight, 300); + assert_equals(child2.offsetWidth, 75); + assert_equals(child2.offsetHeight, 100); }, "Balance, non-auto height, unused space"); </script>
diff --git a/third_party/blink/web_tests/fast/multicol/balance-inner-near-outer-boundary.html b/third_party/blink/web_tests/fast/multicol/balance-inner-near-outer-boundary.html index c4855cd..efe156d 100644 --- a/third_party/blink/web_tests/fast/multicol/balance-inner-near-outer-boundary.html +++ b/third_party/blink/web_tests/fast/multicol/balance-inner-near-outer-boundary.html
@@ -1,6 +1,6 @@ <!DOCTYPE html> <p>There should be a green rectangle below, and no red.</p> -<div style="columns:2; column-fill:auto; width:200px; height:55px; line-height:20px; orphans:1; widows:1;"> +<div style="columns:2; column-fill:auto; column-gap:0; width:200px; height:55px; line-height:20px; orphans:1; widows:1;"> <br> <div id="inner" style="columns:4; column-gap:0; background:red;"> <div id="child1" style="background:green;"><br></div> @@ -20,6 +20,7 @@ var child2 = document.getElementById("child2"); assert_equals(inner.offsetHeight, 20); assert_equals(child1.offsetHeight, 20); - assert_equals(child2.offsetHeight, 60); + assert_equals(child2.offsetWidth, 75); + assert_equals(child2.offsetHeight, 20); }, "Lines at outer column boundaries"); </script>
diff --git a/third_party/blink/web_tests/fast/multicol/dynamic/valid-spanner-container-becomes-invalid.html b/third_party/blink/web_tests/fast/multicol/dynamic/valid-spanner-container-becomes-invalid.html index 3d7aa83..a004980 100644 --- a/third_party/blink/web_tests/fast/multicol/dynamic/valid-spanner-container-becomes-invalid.html +++ b/third_party/blink/web_tests/fast/multicol/dynamic/valid-spanner-container-becomes-invalid.html
@@ -16,6 +16,7 @@ changeMe.style.cssFloat = 'left'; assert_equals(multicol.offsetHeight, 50); - assert_equals(spanner.offsetWidth, 50); + assert_equals(spanner.offsetWidth, 150); + assert_equals(spanner.offsetHeight, 50); }, "Turn a spanner's parent from regular block into float"); </script>
diff --git a/third_party/blink/web_tests/fast/multicol/forced-break-before-complex-margin-collapsing.html b/third_party/blink/web_tests/fast/multicol/forced-break-before-complex-margin-collapsing.html index 5c2d761..d8a164e 100644 --- a/third_party/blink/web_tests/fast/multicol/forced-break-before-complex-margin-collapsing.html +++ b/third_party/blink/web_tests/fast/multicol/forced-break-before-complex-margin-collapsing.html
@@ -12,9 +12,9 @@ <br> <br> <div style="margin-bottom:300px;">first</div> - <div style="-webkit-column-break-before:always; background:red;" data-offset-x="210" data-offset-y="45" data-expected-height="85"> + <div style="-webkit-column-break-before:always; background:red;" data-offset-x="210" data-offset-y="45" data-expected-width="410" data-expected-height="90"> <div data-offset-x="210" data-offset-y="45" data-expected-height="0" style="background:red;"></div> - <div style="margin-top:45px; background:yellow;" data-offset-x="210" data-offset-y="45" data-expected-height="85"> + <div style="margin-top:45px; background:yellow;" data-offset-x="210" data-offset-y="45" data-expected-width="410" data-expected-height="90"> second<br>second<br>third<br>third<br> </div> </div>
diff --git a/third_party/blink/web_tests/fast/multicol/nested-balancing-with-line-at-exact-top.html b/third_party/blink/web_tests/fast/multicol/nested-balancing-with-line-at-exact-top.html index 0d6f3ba..2de902e 100644 --- a/third_party/blink/web_tests/fast/multicol/nested-balancing-with-line-at-exact-top.html +++ b/third_party/blink/web_tests/fast/multicol/nested-balancing-with-line-at-exact-top.html
@@ -2,7 +2,7 @@ <script src="../../resources/check-layout.js"></script> <p>The word BOMBINATE should be seen below.</p> <div id="outer" style="position:relative; overflow:hidden; -webkit-column-count:2; -webkit-column-gap:0; column-fill:auto; width:500px; height:70px; line-height:20px; orphans:1; widows:1;"> - <div data-expected-height="110" style="-webkit-column-count:2; -webkit-column-gap:0;"> + <div data-expected-width="500" data-expected-height="70" style="-webkit-column-count:2; -webkit-column-gap:0;"> <div style="height:120px;"></div> <br> <!-- last line in second column in first row. Exactly no space left after this. --> <br> <!-- first line in first column in second row. -->
diff --git a/third_party/blink/web_tests/fast/multicol/nested-balancing-with-lines-and-space-left-in-previous-row.html b/third_party/blink/web_tests/fast/multicol/nested-balancing-with-lines-and-space-left-in-previous-row.html index 76217d7c4..bb6e0108 100644 --- a/third_party/blink/web_tests/fast/multicol/nested-balancing-with-lines-and-space-left-in-previous-row.html +++ b/third_party/blink/web_tests/fast/multicol/nested-balancing-with-lines-and-space-left-in-previous-row.html
@@ -2,7 +2,7 @@ <script src="../../resources/check-layout.js"></script> <p>The word BOMBINATE should be seen below.</p> <div id="outer" style="position:relative; overflow:hidden; -webkit-column-count:2; -webkit-column-gap:0; column-fill:auto; width:500px; height:70px; line-height:20px; orphans:1; widows:1;"> - <div data-expected-height="110" style="-webkit-column-count:2; -webkit-column-gap:0;"> + <div data-expected-width="500" data-expected-height="70" style="-webkit-column-count:2; -webkit-column-gap:0;"> <div style="height:115px;"></div> <br> <!-- last line in second column in first row. 5px of unusable space left after this. --> <br> <!-- first line in first column in second row. -->
diff --git a/third_party/blink/web_tests/fast/multicol/nested-with-forced-breaks-in-eariler-rows.html b/third_party/blink/web_tests/fast/multicol/nested-with-forced-breaks-in-eariler-rows.html index 7558bf7..83e2898b 100644 --- a/third_party/blink/web_tests/fast/multicol/nested-with-forced-breaks-in-eariler-rows.html +++ b/third_party/blink/web_tests/fast/multicol/nested-with-forced-breaks-in-eariler-rows.html
@@ -9,7 +9,7 @@ <br> <div style="-webkit-column-break-before:always;"><br></div> <div style="-webkit-column-break-before:always;"><br></div> - <div style="-webkit-column-break-before:always; background:blue;" data-expected-height="128"> + <div style="-webkit-column-break-before:always; background:blue;" data-expected-width="32" data-expected-height="32"> <div data-offset-y="0" data-expected-width="8" data-expected-height="32"><br></div> <div data-offset-y="0" data-expected-width="8" data-expected-height="32"><br></div> <div data-offset-y="0" data-expected-width="8" data-expected-height="32"><br></div>
diff --git a/third_party/blink/web_tests/fast/multicol/three-inner-rows.html b/third_party/blink/web_tests/fast/multicol/three-inner-rows.html index 076df399..0dcda166 100644 --- a/third_party/blink/web_tests/fast/multicol/three-inner-rows.html +++ b/third_party/blink/web_tests/fast/multicol/three-inner-rows.html
@@ -5,7 +5,7 @@ <p>The first line should read "Roger" and the second one "Wilco".</p> <p>No red should be seen.</p> <div id="outer" style="position:relative; -webkit-columns:3; -webkit-column-gap:0; text-align:center; overflow:hidden; column-fill:auto; line-height:40px; width:180px; height:80px; background:red;"> - <div style="-webkit-columns:2; -webkit-column-gap:0; column-fill:auto; background:papayawhip;" data-expected-height="240"> + <div style="-webkit-columns:2; -webkit-column-gap:0; column-fill:auto; background:papayawhip;" data-expected-width="180" data-expected-height="80"> <div data-offset-x="0" data-offset-y="0">R</div><div data-offset-x="0" data-offset-y="40">W</div> <div data-offset-x="30" data-offset-y="0">o</div><div data-offset-x="30" data-offset-y="40">i</div> <div data-offset-x="60" data-offset-y="0">g</div><div data-offset-x="60" data-offset-y="40">l</div>
diff --git a/third_party/blink/web_tests/fragmentation/break-before-empty-child-block.html b/third_party/blink/web_tests/fragmentation/break-before-empty-child-block.html index 8ea8f63..9e7b835 100644 --- a/third_party/blink/web_tests/fragmentation/break-before-empty-child-block.html +++ b/third_party/blink/web_tests/fragmentation/break-before-empty-child-block.html
@@ -3,7 +3,7 @@ <p>There should be two blue squares below.</p> <div id="multicol" style="columns:3; column-fill:auto; column-gap:0; position:relative; width:120px; height:100px; line-height:20px;"> <div style="height:60px;"></div> - <div data-offset-x="0" data-offset-y="60" data-expected-height="80" style="padding-top:30px; padding-bottom:20px; background:blue;"> + <div data-offset-x="0" data-offset-y="60" data-expected-width="80" data-expected-height="100" style="padding-top:30px; padding-bottom:20px; background:blue;"> <div data-offset-x="0" data-offset-y="90"></div> <!-- This is where the soft break should occur, since it's a valid class A break point. --> <div data-offset-x="40" data-offset-y="0">
diff --git a/third_party/blink/web_tests/fragmentation/break-in-first-table-row-only.html b/third_party/blink/web_tests/fragmentation/break-in-first-table-row-only.html index 72c164f..9333f32 100644 --- a/third_party/blink/web_tests/fragmentation/break-in-first-table-row-only.html +++ b/third_party/blink/web_tests/fragmentation/break-in-first-table-row-only.html
@@ -7,11 +7,11 @@ <br> <br> <br> - <table data-expected-height="110" cellspacing="0" cellpadding="0"> + <table data-expected-width="70" data-expected-height="90" cellspacing="0" cellpadding="0"> <col style="width:10px;"> <col style="width:10px;"> - <tr data-expected-height="50"> - <td data-expected-height="50"> + <tr data-expected-width="70" data-expected-height="90"> + <td data-expected-width="60" data-expected-height="90"> <br><br> </td> </tr>
diff --git a/third_party/blink/web_tests/fragmentation/break-inside-avoid-with-forced-break.html b/third_party/blink/web_tests/fragmentation/break-inside-avoid-with-forced-break.html index 16e02acd..2b29cf2 100644 --- a/third_party/blink/web_tests/fragmentation/break-inside-avoid-with-forced-break.html +++ b/third_party/blink/web_tests/fragmentation/break-inside-avoid-with-forced-break.html
@@ -3,7 +3,7 @@ <p>There should be a blue square below.</p> <div id="multicol" style="position:relative; columns:2; column-fill:auto; column-gap:10px; width:130px; height:120px;"> <div style="height:30px; background:blue;"></div> - <div data-offset-x="0" data-offset-y="30" data-expected-height="290" style="break-inside:avoid;"> + <div data-offset-x="0" data-offset-y="30" data-expected-width="200" data-expected-height="120" style="break-inside:avoid;"> <div data-offset-x="0" data-offset-y="30" style="height:10px; background:blue;"></div> <div> <div data-offset-x="0" data-offset-y="40" style="height:10px; background:blue;"></div>
diff --git a/third_party/blink/web_tests/fragmentation/class-c-break-after-clearance.html b/third_party/blink/web_tests/fragmentation/class-c-break-after-clearance.html index 9b9bfdb..225cd38 100644 --- a/third_party/blink/web_tests/fragmentation/class-c-break-after-clearance.html +++ b/third_party/blink/web_tests/fragmentation/class-c-break-after-clearance.html
@@ -5,7 +5,7 @@ <br> <br> <div style="float:left; width:50px; height:50px;"></div> - <div style="background:blue;" data-offset-x="0" data-offset-y="40" data-expected-height="80"> + <div style="background:blue;" data-offset-x="0" data-offset-y="40" data-expected-width="120" data-expected-height="100"> <div data-offset-x="60" data-offset-y="0" data-expected-height="20" style="clear:both; background:white;"> <br> </div>
diff --git a/third_party/blink/web_tests/platform/linux/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-valid-relative-color-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-valid-relative-color-expected.txt deleted file mode 100644 index 2696651..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-valid-relative-color-expected.txt +++ /dev/null
@@ -1,40 +0,0 @@ -This is a testharness.js-based test. -Found 18 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] e.style['color'] = "rgb(from currentColor r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "rgba(from currentColor r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "hsl(from currentColor h s l)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "hsla(from currentColor h s l)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "hwb(from currentColor h w b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "lab(from currentColor l a b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "oklab(from currentColor l a b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "lch(from currentColor l c h)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "oklch(from currentColor l c h)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor srgb r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor srgb-linear r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor a98-rgb r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor rec2020 r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor prophoto-rgb r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor display-p3 r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor xyz x y z)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor xyz-d50 x y z)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor xyz-d65 x y z)" should set the property value - assert_not_equals: property should be set got disallowed value "" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/README.md b/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/README.md deleted file mode 100644 index ddefc86..0000000 --- a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/README.md +++ /dev/null
@@ -1 +0,0 @@ -# This suite runs tests with --disable-blink-features=CSSRelativeColorSupportsCurrentcolor
diff --git a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-computed-relative-color-expected.txt b/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-computed-relative-color-expected.txt deleted file mode 100644 index 8222f59..0000000 --- a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-computed-relative-color-expected.txt +++ /dev/null
@@ -1,72 +0,0 @@ -This is a testharness.js-based test. -Found 34 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] Property background-color value 'rgb(from currentColor r g b)' - assert_true: 'rgb(from currentColor r g b)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'rgb(from color-mix(in srgb, currentColor, red) r g b / alpha)' - assert_true: 'rgb(from color-mix(in srgb, currentColor, red) r g b / alpha)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'rgb(from rgb(from currentColor r g b) r g b)' - assert_true: 'rgb(from rgb(from currentColor r g b) r g b)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'hsl(from currentColor h s l)' - assert_true: 'hsl(from currentColor h s l)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'hsl(from currentColor calc((h / 360) * 360deg) s l)' - assert_true: 'hsl(from currentColor calc((h / 360) * 360deg) s l)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'hwb(from currentColor h w b)' - assert_true: 'hwb(from currentColor h w b)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'lab(from currentColor l a b)' - assert_true: 'lab(from currentColor l a b)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'oklab(from currentColor l a b)' - assert_true: 'oklab(from currentColor l a b)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'lch(from currentColor l c h)' - assert_true: 'lch(from currentColor l c h)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'oklch(from currentColor l c h)' - assert_true: 'oklch(from currentColor l c h)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'color(from currentColor srgb r g b)' - assert_true: 'color(from currentColor srgb r g b)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'color(from currentColor srgb-linear r g b)' - assert_true: 'color(from currentColor srgb-linear r g b)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'color(from currentColor a98-rgb r g b)' - assert_true: 'color(from currentColor a98-rgb r g b)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'color(from currentColor rec2020 r g b)' - assert_true: 'color(from currentColor rec2020 r g b)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'color(from currentColor prophoto-rgb r g b)' - assert_true: 'color(from currentColor prophoto-rgb r g b)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'color(from currentColor display-p3 r g b)' - assert_true: 'color(from currentColor display-p3 r g b)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'color(from currentColor xyz x y z)' - assert_true: 'color(from currentColor xyz x y z)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'color(from currentColor xyz-d50 x y z)' - assert_true: 'color(from currentColor xyz-d50 x y z)' is a supported value for background-color. expected true got false -[FAIL] Property background-color value 'color(from currentColor xyz-d65 x y z)' - assert_true: 'color(from currentColor xyz-d65 x y z)' is a supported value for background-color. expected true got false -[FAIL] Property color value 'lch(from color(srgb 0.25 0.5 0.75) l c h)' - Colors do not match.\nActual: lch(51.4265 40.4863 262.601)\nExpected: lch(51.4321 40.4828 262.58).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 2, expected 262.58 +/- 0.02, expected 262.58 but got 262.601 -[FAIL] Property color value 'color(from rgb(from color(xyz-d50 0.99 0.88 0.77) r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989872 0.879877 0.769926)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989872 -[FAIL] Property color value 'color(from hsl(from color(xyz-d50 0.99 0.88 0.77) h s l) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989872 0.879877 0.769926)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989872 -[FAIL] Property color value 'color(from color(from color(xyz-d50 0.99 0.88 0.77) srgb r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989872 0.879877 0.769926)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989872 -[FAIL] Property color value 'color(from color(from color(xyz-d50 0.99 0.88 0.77) display-p3 r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989831 0.879845 0.769913)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989831 -[FAIL] Property color value 'color(from color(from color(xyz-d50 0.99 0.88 0.77) a98-rgb r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989614 0.879695 0.769795)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989614 -[FAIL] Property color value 'color(from color(from color(xyz-d50 0.99 0.88 0.77) prophoto-rgb r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989682 0.879725 0.769775)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989682 -[FAIL] Property color value 'color(from color(from color(xyz-d50 0.99 0.88 0.77) rec2020 r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.98984 0.879861 0.769847)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.98984 -[FAIL] Property color value 'color(from rgb(from color(xyz-d65 0.99 0.88 0.77) r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989888 0.879886 0.769923)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989888 -[FAIL] Property color value 'color(from hsl(from color(xyz-d65 0.99 0.88 0.77) h s l) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989888 0.879886 0.769923)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989888 -[FAIL] Property color value 'color(from color(from color(xyz-d65 0.99 0.88 0.77) srgb r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989888 0.879886 0.769923)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989888 -[FAIL] Property color value 'color(from color(from color(xyz-d65 0.99 0.88 0.77) display-p3 r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989874 0.879875 0.76992)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989874 -[FAIL] Property color value 'color(from color(from color(xyz-d65 0.99 0.88 0.77) a98-rgb r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989656 0.879729 0.769826)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989656 -[FAIL] Property color value 'color(from color(from color(xyz-d65 0.99 0.88 0.77) prophoto-rgb r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989647 0.879721 0.769892)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989647 -[FAIL] Property color value 'color(from color(from color(xyz-d65 0.99 0.88 0.77) rec2020 r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989824 0.879848 0.769848)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989824 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-valid-relative-color-expected.txt b/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-valid-relative-color-expected.txt deleted file mode 100644 index 36c65951..0000000 --- a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/parsing/color-valid-relative-color-expected.txt +++ /dev/null
@@ -1,74 +0,0 @@ -This is a testharness.js-based test. -Found 35 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] e.style['color'] = "rgb(from rebeccapurple r calc(g * 2) 10)" should set the property value - Colors do not match.\nActual: rgb(from rebeccapurple r calc(g * 2) 10)\nExpected: rgb(from rebeccapurple r calc(2 * g) 10).\nError: assert_equals: Color format is correct. expected "rgb(from rebeccapurple r calc( * g) )" but got "rgb(from rebeccapurple r calc(g * ) )" -[FAIL] e.style['color'] = "rgb(from rebeccapurple b calc(r * .5) 10)" should set the property value - Colors do not match.\nActual: rgb(from rebeccapurple b calc(r * 0.5) 10)\nExpected: rgb(from rebeccapurple b calc(0.5 * r) 10).\nError: assert_equals: Color format is correct. expected "rgb(from rebeccapurple b calc( * r) )" but got "rgb(from rebeccapurple b calc(r * ) )" -[FAIL] e.style['color'] = "rgb(from rebeccapurple r calc(g * .5 + g * .5) 10)" should set the property value - Colors do not match.\nActual: rgb(from rebeccapurple r calc(g * 0.5 + g * 0.5) 10)\nExpected: rgb(from rebeccapurple r calc((0.5 * g) + (0.5 * g)) 10).\nError: assert_equals: Color format is correct. expected "rgb(from rebeccapurple r calc(( * g) + ( * g)) )" but got "rgb(from rebeccapurple r calc(g * + g * ) )" -[FAIL] e.style['color'] = "rgb(from rebeccapurple r calc(b * .5 - g * .5) 10)" should set the property value - Colors do not match.\nActual: rgb(from rebeccapurple r calc(b * 0.5 - g * 0.5) 10)\nExpected: rgb(from rebeccapurple r calc((0.5 * b) - (0.5 * g)) 10).\nError: assert_equals: Color format is correct. expected "rgb(from rebeccapurple r calc(( * b) - ( * g)) )" but got "rgb(from rebeccapurple r calc(b * - g * ) )" -[FAIL] e.style['color'] = "rgb(from currentColor r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "rgba(from rebeccapurple r calc(g * 2) 10)" should set the property value - Colors do not match.\nActual: rgb(from rebeccapurple r calc(g * 2) 10)\nExpected: rgb(from rebeccapurple r calc(2 * g) 10).\nError: assert_equals: Color format is correct. expected "rgb(from rebeccapurple r calc( * g) )" but got "rgb(from rebeccapurple r calc(g * ) )" -[FAIL] e.style['color'] = "rgba(from rebeccapurple b calc(r * .5) 10)" should set the property value - Colors do not match.\nActual: rgb(from rebeccapurple b calc(r * 0.5) 10)\nExpected: rgb(from rebeccapurple b calc(0.5 * r) 10).\nError: assert_equals: Color format is correct. expected "rgb(from rebeccapurple b calc( * r) )" but got "rgb(from rebeccapurple b calc(r * ) )" -[FAIL] e.style['color'] = "rgba(from rebeccapurple r calc(g * .5 + g * .5) 10)" should set the property value - Colors do not match.\nActual: rgb(from rebeccapurple r calc(g * 0.5 + g * 0.5) 10)\nExpected: rgb(from rebeccapurple r calc((0.5 * g) + (0.5 * g)) 10).\nError: assert_equals: Color format is correct. expected "rgb(from rebeccapurple r calc(( * g) + ( * g)) )" but got "rgb(from rebeccapurple r calc(g * + g * ) )" -[FAIL] e.style['color'] = "rgba(from rebeccapurple r calc(b * .5 - g * .5) 10)" should set the property value - Colors do not match.\nActual: rgb(from rebeccapurple r calc(b * 0.5 - g * 0.5) 10)\nExpected: rgb(from rebeccapurple r calc((0.5 * b) - (0.5 * g)) 10).\nError: assert_equals: Color format is correct. expected "rgb(from rebeccapurple r calc(( * b) - ( * g)) )" but got "rgb(from rebeccapurple r calc(b * - g * ) )" -[FAIL] e.style['color'] = "rgba(from currentColor r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "hsl(from currentColor h s l)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "hsla(from currentColor h s l)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "hwb(from currentColor h w b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "lab(from lab(50 -30 40) l calc(a / 3) calc(b / 2))" should set the property value - Colors do not match.\nActual: lab(from lab(50 -30 40) l calc(a / 3) calc(b / 2))\nExpected: lab(from lab(50 -30 40) l calc(0.333333 * a) calc(0.5 * b)).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 3, expected 0.333333 +/- 0.01, expected 0.333333 but got 3 -[FAIL] e.style['color'] = "lab(from currentColor l a b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "oklab(from oklab(0.7 0.25 -0.15) l calc(a / 2) calc(b / 3))" should set the property value - Colors do not match.\nActual: oklab(from oklab(0.7 0.25 -0.15) l calc(a / 2) calc(b / 3))\nExpected: oklab(from oklab(0.7 0.25 -0.15) l calc(0.5 * a) calc(0.333333 * b)).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 3, expected 0.5 +/- 0.01, expected 0.5 but got 2 -[FAIL] e.style['color'] = "oklab(from currentColor l a b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "lch(from lch(50 100 300) l calc(c / 2) h)" should set the property value - Colors do not match.\nActual: lch(from lch(50 100 300) l calc(c / 2) h)\nExpected: lch(from lch(50 100 300) l calc(0.5 * c) h).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 3, expected 0.5 +/- 0.01, expected 0.5 but got 2 -[FAIL] e.style['color'] = "lch(from lch(50 100 300) l c calc(h * 2.5))" should set the property value - Colors do not match.\nActual: lch(from lch(50 100 300) l c calc(h * 2.5))\nExpected: lch(from lch(50 100 300) l c calc(2.5 * h)).\nError: assert_equals: Color format is correct. expected "lch(from lch( ) l c calc( * h))" but got "lch(from lch( ) l c calc(h * ))" -[FAIL] e.style['color'] = "lch(from currentColor l c h)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "oklch(from oklch(0.7 0.2 300) l calc(c / 2) h)" should set the property value - Colors do not match.\nActual: oklch(from oklch(0.7 0.2 300) l calc(c / 2) h)\nExpected: oklch(from oklch(0.7 0.2 300) l calc(0.5 * c) h).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 3, expected 0.5 +/- 0.01, expected 0.5 but got 2 -[FAIL] e.style['color'] = "oklch(from oklch(0.7 0.2 300) l c calc(h * 2.5))" should set the property value - Colors do not match.\nActual: oklch(from oklch(0.7 0.2 300) l c calc(h * 2.5))\nExpected: oklch(from oklch(0.7 0.2 300) l c calc(2.5 * h)).\nError: assert_equals: Color format is correct. expected "oklch(from oklch( ) l c calc( * h))" but got "oklch(from oklch( ) l c calc(h * ))" -[FAIL] e.style['color'] = "oklch(from currentColor l c h)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor srgb r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor srgb-linear r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor a98-rgb r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor rec2020 r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor prophoto-rgb r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor display-p3 r g b)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor xyz x y z)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor xyz-d50 x y z)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "color(from currentColor xyz-d65 x y z)" should set the property value - assert_not_equals: property should be set got disallowed value "" -[FAIL] e.style['color'] = "lch(from peru calc(l * 0.8) c h)" should set the property value - Colors do not match.\nActual: lch(from peru calc(l * 0.8) c h)\nExpected: lch(from peru calc(0.8 * l) c h).\nError: assert_equals: Color format is correct. expected "lch(from peru calc( * l) c h)" but got "lch(from peru calc(l * ) c h)" -[FAIL] e.style['color'] = "color(from rebeccapurple srgb r g b)" should set the property value - Colors do not match.\nActual: color(from rebeccapurple srgb r g b)\nExpected: color(srgb 0.4 0.2 0.6).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. lengths differ, expected 3 got 0 -[FAIL] e.style['color'] = "rgb(from color(srgb 0.4 0.2 0.6) r g b)" should set the property value - Colors do not match.\nActual: rgb(from color(srgb 0.4 0.2 0.6) r g b)\nExpected: color(srgb 0.4 0.2 0.6).\nError: assert_equals: Color format is correct. expected "color(srgb )" but got "rgb(from color(srgb ) r g b)" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-visited-getcomputedstyle-expected.txt b/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-visited-getcomputedstyle-expected.txt deleted file mode 100644 index 3d6952bb..0000000 --- a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-color/relative-currentcolor-visited-getcomputedstyle-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Property background-color value 'rgb(from currentcolor r g b)' should not leak :visited for computed style - assert_true: 'rgb(from currentcolor r g b)' is a supported value for background-color. expected true got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt b/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt deleted file mode 100644 index 55ebcdd..0000000 --- a/third_party/blink/web_tests/virtual/css-relative-currentcolor-disabled/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt +++ /dev/null
@@ -1,6 +0,0 @@ -This is a testharness.js-based test. -Found 1 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] <color> values are computed correctly [color(from currentcolor srgb b g r)] - assert_equals: expected "color(from currentcolor srgb b g r)" but got "rgb(0, 0, 0)" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/css-relative-preservenone-disabled/README.md b/third_party/blink/web_tests/virtual/css-relative-preservenone-disabled/README.md deleted file mode 100644 index 5be06edd..0000000 --- a/third_party/blink/web_tests/virtual/css-relative-preservenone-disabled/README.md +++ /dev/null
@@ -1 +0,0 @@ -# This suite runs tests with --disable-blink-features=CSSRelativeColorPreserveNone
diff --git a/third_party/blink/web_tests/virtual/css-relative-preservenone-disabled/external/wpt/css/css-color/parsing/color-computed-relative-color-expected.txt b/third_party/blink/web_tests/virtual/css-relative-preservenone-disabled/external/wpt/css/css-color/parsing/color-computed-relative-color-expected.txt deleted file mode 100644 index 1ca6da7..0000000 --- a/third_party/blink/web_tests/virtual/css-relative-preservenone-disabled/external/wpt/css/css-color/parsing/color-computed-relative-color-expected.txt +++ /dev/null
@@ -1,52 +0,0 @@ -This is a testharness.js-based test. -Found 24 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] Property color value 'rgb(from rebeccapurple none none none)' - Colors do not match.\nActual: color(srgb 0 0 0)\nExpected: color(srgb none none none).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. lengths differ, expected 0 got 3 -[FAIL] Property color value 'rgb(from rebeccapurple none none none / none)' - Colors do not match.\nActual: color(srgb 0 0 0 / none)\nExpected: color(srgb none none none / none).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. lengths differ, expected 0 got 3 -[FAIL] Property color value 'rgb(from rebeccapurple r g none)' - Colors do not match.\nActual: color(srgb 0.4 0.2 0)\nExpected: color(srgb 0.4 0.2 none).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. lengths differ, expected 2 got 3 -[FAIL] Property color value 'rgb(from rebeccapurple r g none / alpha)' - Colors do not match.\nActual: color(srgb 0.4 0.2 0)\nExpected: color(srgb 0.4 0.2 none).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. lengths differ, expected 2 got 3 -[FAIL] Property color value 'rgb(from rgb(20% 40% 60% / 80%) r g none / alpha)' - Colors do not match.\nActual: color(srgb 0.2 0.4 0 / 0.8)\nExpected: color(srgb 0.2 0.4 none / 0.8).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. lengths differ, expected 3 got 4 -[FAIL] Property color value 'color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple)' - Colors do not match.\nActual: color(srgb 0.2 0.2 0.6)\nExpected: color(srgb 0.4 0.2 0.6).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.4 +/- 0.01, expected 0.4 but got 0.2 -[FAIL] Property color value 'light-dark(color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple), color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple))' - Colors do not match.\nActual: color(srgb 0.2 0.2 0.6)\nExpected: color(srgb 0.4 0.2 0.6).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.4 +/- 0.01, expected 0.4 but got 0.2 -[FAIL] Property color value 'color-mix(in hsl, hsl(from rebeccapurple none s l), rebeccapurple)' - Colors do not match.\nActual: color(srgb 0.6 0.2 0.5)\nExpected: color(srgb 0.4 0.2 0.6).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.4 +/- 0.01, expected 0.4 but got 0.6 -[FAIL] Property color value 'color-mix(in hwb, hwb(from rebeccapurple none w b), rebeccapurple)' - Colors do not match.\nActual: color(srgb 0.6 0.2 0.5)\nExpected: color(srgb 0.4 0.2 0.6).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.4 +/- 0.01, expected 0.4 but got 0.6 -[FAIL] Property color value 'lch(from color(srgb 0.25 0.5 0.75) l c h)' - Colors do not match.\nActual: lch(51.4265 40.4863 262.601)\nExpected: lch(51.4321 40.4828 262.58).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 2, expected 262.58 +/- 0.02, expected 262.58 but got 262.601 -[FAIL] Property color value 'color(from rgb(from color(xyz-d50 0.99 0.88 0.77) r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989872 0.879877 0.769926)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989872 -[FAIL] Property color value 'color(from hsl(from color(xyz-d50 0.99 0.88 0.77) h s l) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989872 0.879877 0.769926)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989872 -[FAIL] Property color value 'color(from color(from color(xyz-d50 0.99 0.88 0.77) srgb r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989872 0.879877 0.769926)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989872 -[FAIL] Property color value 'color(from color(from color(xyz-d50 0.99 0.88 0.77) display-p3 r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989831 0.879845 0.769913)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989831 -[FAIL] Property color value 'color(from color(from color(xyz-d50 0.99 0.88 0.77) a98-rgb r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989614 0.879695 0.769795)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989614 -[FAIL] Property color value 'color(from color(from color(xyz-d50 0.99 0.88 0.77) prophoto-rgb r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.989682 0.879725 0.769775)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989682 -[FAIL] Property color value 'color(from color(from color(xyz-d50 0.99 0.88 0.77) rec2020 r g b) xyz-d50 x y z)' - Colors do not match.\nActual: color(xyz-d50 0.98984 0.879861 0.769847)\nExpected: color(xyz-d50 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.98984 -[FAIL] Property color value 'color(from rgb(from color(xyz-d65 0.99 0.88 0.77) r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989888 0.879886 0.769923)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989888 -[FAIL] Property color value 'color(from hsl(from color(xyz-d65 0.99 0.88 0.77) h s l) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989888 0.879886 0.769923)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989888 -[FAIL] Property color value 'color(from color(from color(xyz-d65 0.99 0.88 0.77) srgb r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989888 0.879886 0.769923)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989888 -[FAIL] Property color value 'color(from color(from color(xyz-d65 0.99 0.88 0.77) display-p3 r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989874 0.879875 0.76992)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989874 -[FAIL] Property color value 'color(from color(from color(xyz-d65 0.99 0.88 0.77) a98-rgb r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989656 0.879729 0.769826)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989656 -[FAIL] Property color value 'color(from color(from color(xyz-d65 0.99 0.88 0.77) prophoto-rgb r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989647 0.879721 0.769892)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989647 -[FAIL] Property color value 'color(from color(from color(xyz-d65 0.99 0.88 0.77) rec2020 r g b) xyz-d65 x y z)' - Colors do not match.\nActual: color(xyz-d65 0.989824 0.879848 0.769848)\nExpected: color(xyz-d65 0.99 0.88 0.77).\nError: assert_array_approx_equals: Numeric parameters are approximately equal. property 0, expected 0.99 +/- 0.0001, expected 0.99 but got 0.989824 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-referrer_clientId-expected.txt b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-referrer_clientId-expected.txt new file mode 100644 index 0000000..8f586b96 --- /dev/null +++ b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-referrer_clientId-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Prefetch with ServiceWorker (fetch-handler-modify-referrer) + assert_false: clientId should be initiator. expected false got true +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-url_clientId-expected.txt b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-url_clientId-expected.txt new file mode 100644 index 0000000..e5d34539 --- /dev/null +++ b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-url_clientId-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Prefetch with ServiceWorker (fetch-handler-modify-url) + assert_false: clientId should be initiator. expected false got true +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-to-fallback_clientId-expected.txt b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-to-fallback_clientId-expected.txt new file mode 100644 index 0000000..4d01fd9b --- /dev/null +++ b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-to-fallback_clientId-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Prefetch with ServiceWorker (fetch-handler-to-fallback) + assert_false: clientId should be initiator. expected false got true +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler_clientId-expected.txt b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler_clientId-expected.txt new file mode 100644 index 0000000..d164820 --- /dev/null +++ b/third_party/blink/web_tests/virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler_clientId-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Prefetch with ServiceWorker (fetch-handler) + assert_false: clientId should be initiator. expected false got true +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-referrer_clientId-expected.txt b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-referrer_clientId-expected.txt new file mode 100644 index 0000000..ead81c48 --- /dev/null +++ b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-referrer_clientId-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Prefetch with ServiceWorker (fetch-handler-modify-referrer) + assert_in_array: Prefetch request should be intercepted. value undefined not in array ["prefetch", "prefetch;anonymous-client-ip"] +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-url_clientId-expected.txt b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-url_clientId-expected.txt new file mode 100644 index 0000000..1b63268f0 --- /dev/null +++ b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-modify-url_clientId-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Prefetch with ServiceWorker (fetch-handler-modify-url) + assert_in_array: Prefetch request should be intercepted. value undefined not in array ["prefetch", "prefetch;anonymous-client-ip"] +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-to-fallback_clientId-expected.txt b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-to-fallback_clientId-expected.txt new file mode 100644 index 0000000..f67ebb62 --- /dev/null +++ b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler-to-fallback_clientId-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Prefetch with ServiceWorker (fetch-handler-to-fallback) + assert_in_array: Prefetched result should be served. value undefined not in array ["prefetch", "prefetch;anonymous-client-ip"] +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler_clientId-expected.txt b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler_clientId-expected.txt new file mode 100644 index 0000000..33ce740 --- /dev/null +++ b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=fetch-handler_clientId-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Prefetch with ServiceWorker (fetch-handler) + assert_in_array: Prefetched result should be served. value undefined not in array ["prefetch", "prefetch;anonymous-client-ip"] +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=no-fetch-handler_clientId-expected.txt b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=no-fetch-handler_clientId-expected.txt new file mode 100644 index 0000000..600af3c --- /dev/null +++ b/third_party/blink/web_tests/virtual/prefetch/external/wpt/speculation-rules/prefetch/tentative/service-worker/basic.sub.https_origin=same-site_sw=no-fetch-handler_clientId-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Prefetch with ServiceWorker (no-fetch-handler) + assert_in_array: Prefetched result should be served. value undefined not in array ["prefetch", "prefetch;anonymous-client-ip"] +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/wpt_internal/workers/data-url-workers-use-counter.html b/third_party/blink/web_tests/wpt_internal/workers/data-url-workers-use-counter.html new file mode 100644 index 0000000..c3a93296 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/workers/data-url-workers-use-counter.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> + +const kDataUrlDedicatedWorker = 5568; +const kDataUrlSharedWorker = 5569; + +test(() => { + internals.clearUseCounter(document, kDataUrlDedicatedWorker); + new Worker('data:application/javascript,close();'); + assert_true(internals.isUseCounted(document, kDataUrlDedicatedWorker)); +}, "kDataUrlDedicatedWorker UseCounter should be triggered when a classic dedicated worker is created from a data: URL."); + +test(() => { + internals.clearUseCounter(document, kDataUrlDedicatedWorker); + new Worker('data:application/javascript,close();', {type: 'module'}); + assert_true(internals.isUseCounted(document, kDataUrlDedicatedWorker)); +}, "kDataUrlDedicatedWorker UseCounter should be triggered when a module dedicated worker is created from a data: URL."); + +test(() => { + internals.clearUseCounter(document, kDataUrlSharedWorker); + new SharedWorker('data:application/javascript,close();'); + assert_true(internals.isUseCounted(document, kDataUrlSharedWorker)); +}, "kDataUrlSharedWorker UseCounter should be triggered when a classic shared worker is created from a data: URL."); + +test(() => { + internals.clearUseCounter(document, kDataUrlSharedWorker); + new SharedWorker('data:application/javascript,close();', {type: 'module'}); + assert_true(internals.isUseCounted(document, kDataUrlSharedWorker)); +}, "kDataUrlSharedWorker UseCounter should be triggered when a module shared worker is created from a data: URL."); + +</script> +</body> \ No newline at end of file
diff --git a/third_party/dawn b/third_party/dawn index 606e03a..7fda3b6 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit 606e03a22bfe5686be18fcc934555f55f987c1e9 +Subproject commit 7fda3b6896dfd60d7d07f486da449420b01d9e54
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index c049d05..3a15a39 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit c049d058ae5973f47a21fb1e4eb7a224174ef032 +Subproject commit 3a15a39f336401af3597c00cc975b2a323e7e0d2
diff --git a/third_party/libunwind/src b/third_party/libunwind/src index 4acde98..09f6f7b 160000 --- a/third_party/libunwind/src +++ b/third_party/libunwind/src
@@ -1 +1 @@ -Subproject commit 4acde988c52e6a325e3ce2ac761284f295f2ab39 +Subproject commit 09f6f7b1685888b16c0fe52a7a68f9dff8b8d60e
diff --git a/third_party/perfetto b/third_party/perfetto index 6ffe623..11cd406 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit 6ffe623d283575c00047cf9abf90c3659505a592 +Subproject commit 11cd406514a8212d3568448b2207d2925d5ca202
diff --git a/third_party/skia b/third_party/skia index 0feee17..9f9e1f3 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 0feee17aeacab6b88ac8be3d8b35ae4c940eeea4 +Subproject commit 9f9e1f37917e8c2c2a7832325a9caddef8920625
diff --git a/third_party/spirv-tools/src b/third_party/spirv-tools/src index f06e0f3..feba06f 160000 --- a/third_party/spirv-tools/src +++ b/third_party/spirv-tools/src
@@ -1 +1 @@ -Subproject commit f06e0f3d2e5acfe4b14e714e4103dd1ccdb237e5 +Subproject commit feba06f44f682e17e0efcd412dff8de74a23d63a
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps index 72604f0..0f00b76 160000 --- a/third_party/vulkan-deps +++ b/third_party/vulkan-deps
@@ -1 +1 @@ -Subproject commit 72604f04b9576fcda814d388673d7530d95a9a5a +Subproject commit 0f00b76ecd36ec3d2df74e7705ed6efbc1fb89f6
diff --git a/third_party/vulkan-headers/src b/third_party/vulkan-headers/src index 9c77de5c..75ad707 160000 --- a/third_party/vulkan-headers/src +++ b/third_party/vulkan-headers/src
@@ -1 +1 @@ -Subproject commit 9c77de5c3dd216f28e407eec65ed9c0a296c1f74 +Subproject commit 75ad707a587e1469fb53a901b9b68fe9f6fbc11f
diff --git a/third_party/vulkan-loader/src b/third_party/vulkan-loader/src index fefd7ed..a8bec31 160000 --- a/third_party/vulkan-loader/src +++ b/third_party/vulkan-loader/src
@@ -1 +1 @@ -Subproject commit fefd7ed96ef9994f0080dbd078822b07d8637918 +Subproject commit a8bec310845ce80af5c00342243ae972cbe95e3b
diff --git a/third_party/vulkan-tools/src b/third_party/vulkan-tools/src index ba13d38..60b640c 160000 --- a/third_party/vulkan-tools/src +++ b/third_party/vulkan-tools/src
@@ -1 +1 @@ -Subproject commit ba13d38d06830f714a93c5bb159e6e4bacacf0bc +Subproject commit 60b640cb931814fcc6dabe4fc61f4738c56579f6
diff --git a/third_party/vulkan-utility-libraries/src b/third_party/vulkan-utility-libraries/src index be40e67..4f62821 160000 --- a/third_party/vulkan-utility-libraries/src +++ b/third_party/vulkan-utility-libraries/src
@@ -1 +1 @@ -Subproject commit be40e67892c83d4752ccfbee7ce690ea88087d2b +Subproject commit 4f628210460c4df62029959cc7fb237ac75f7189
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src index 6ae58a2..ff0450c 160000 --- a/third_party/vulkan-validation-layers/src +++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@ -Subproject commit 6ae58a2b17b2bcebdc5377995007391b85ffa10f +Subproject commit ff0450c7bccfb78f9c7117f1ecd17f7321535cad
diff --git a/tools/metrics/histograms/metadata/blink/enums.xml b/tools/metrics/histograms/metadata/blink/enums.xml index 82e1e9cc..1a1fd7de 100644 --- a/tools/metrics/histograms/metadata/blink/enums.xml +++ b/tools/metrics/histograms/metadata/blink/enums.xml
@@ -6193,6 +6193,8 @@ <int value="5565" label="Proofreader_Proofread"/> <int value="5566" label="Proofreader_Availability"/> <int value="5567" label="Proofreader_Create"/> + <int value="5568" label="DataUrlDedicatedWorker"/> + <int value="5569" label="DataUrlSharedWorker"/> </enum> <!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom:WebFeature) --> @@ -6715,9 +6717,10 @@ </enum> <enum name="FedCmUserAction"> - <int value="0" label="User signed in"/> + <int value="0" label="Deprecated: User signed in"/> <int value="1" label="User ignored the UI"/> <int value="2" label="User closed the UI"/> + <int value="3" label="User signed in"/> </enum> <enum name="FedCmUserInfoStatus"> @@ -6816,7 +6819,7 @@ </enum> <enum name="ImageHasMultipleGeneratorClientIds"> - <int value="0" label="Image decode is requested bfy at least one client"/> + <int value="0" label="Image decode is requested by at least one client"/> <int value="1" label="Image decode is requested by more than one client"/> </enum>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index a5a1242b..6a50350 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -3223,24 +3223,6 @@ </token> </histogram> -<histogram name="Net.HttpStreamPool.JobCreateToResumeTime2.{Result}" units="ms" - expires_after="2025-09-14"> - <owner>bashi@chromium.org</owner> - <owner>blink-network-stack@google.com</owner> - <summary> - Time from when an HttpStreamPool::Job is created to when the job is resumed. - This is the time the job was paused to wait for a failing AttemptManager. - Recorded for each job that has a result upon destruction of the job. - </summary> - <token key="Result"> - <variant name="Failure" summary="Job failed"/> - <variant name="H1" summary="Job succeeded with HTTP/1.1"/> - <variant name="H2" summary="Job succeeded with HTTP/2"/> - <variant name="H3" summary="Job succeeded with HTTP/3"/> - <variant name="Unknown" summary="Job succeeded with unknown next protocol"/> - </token> -</histogram> - <histogram name="Net.HttpStreamPool.JobErrorCode" enum="NetErrorCodes" expires_after="2025-09-14"> <owner>bashi@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/network/enums.xml b/tools/metrics/histograms/metadata/network/enums.xml index 1209c397..095e1e7 100644 --- a/tools/metrics/histograms/metadata/network/enums.xml +++ b/tools/metrics/histograms/metadata/network/enums.xml
@@ -2304,6 +2304,12 @@ <int value="681" label="97"/> </enum> +<enum name="SharedDictionaryDocumentRequestCacheResult"> + <int value="0" label="Cache Miss"/> + <int value="1" label="Hit from LRU Cache"/> + <int value="2" label="Hit from Active Dictionary List"/> +</enum> + <enum name="SharedDictionaryEncodingType"> <int value="0" label="Not Used"/> <int value="1" label="Shared Brotli"/>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml index a6b1d36..d547d455 100644 --- a/tools/metrics/histograms/metadata/network/histograms.xml +++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -2402,6 +2402,22 @@ </summary> </histogram> +<histogram name="Network.SharedDictionary.DocumentRequestCacheResult" + enum="SharedDictionaryDocumentRequestCacheResult" + expires_after="2025-12-31"> + <owner>pmeenan@chromium.org</owner> + <owner>blink-network-stack@google.com</owner> + <summary> + For each request that is for a document destination that has a shared + compression dictionary available and is using the disk-based dictionary + storage, records if the dictionary was available in one of the memory + caches. + + Logged at the time a request is sent and only for those requests that were + for a document destination and had a compression dictionary available. + </summary> +</histogram> + <histogram name="Network.SharedDictionary.EncodingType" enum="SharedDictionaryEncodingType" expires_after="2025-10-05"> <owner>nidhijaju@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index 55bb0e17..28a4c631 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -5661,13 +5661,13 @@ </token> </histogram> -<histogram name="Hyphenation.Open" units="ms" expires_after="2025-05-11"> +<histogram name="Hyphenation.Open" units="ms" expires_after="2025-11-08"> <owner>kojii@chromium.org</owner> <owner>layout-dev@chromium.org</owner> <summary>The time it takes to open a hyphenation dictionary.</summary> </histogram> -<histogram name="Hyphenation.Open.File" units="ms" expires_after="2025-05-11"> +<histogram name="Hyphenation.Open.File" units="ms" expires_after="2025-11-08"> <owner>kojii@chromium.org</owner> <owner>layout-dev@chromium.org</owner> <summary>The time it takes to open a hyphenation dictionary file.</summary>
diff --git a/tools/metrics/histograms/metadata/renderer/histograms.xml b/tools/metrics/histograms/metadata/renderer/histograms.xml index 81863df..e4f3b74 100644 --- a/tools/metrics/histograms/metadata/renderer/histograms.xml +++ b/tools/metrics/histograms/metadata/renderer/histograms.xml
@@ -289,7 +289,7 @@ </histogram> <histogram name="Renderer.Font.PrimaryFont.DomContentLoaded.Style" units="ms" - expires_after="2025-05-11"> + expires_after="2025-11-08"> <owner>kojii@chromium.org</owner> <owner>tkent@chromium.org</owner> <owner>layout-dev@chromium.org</owner> @@ -313,7 +313,7 @@ </histogram> <histogram name="Renderer.Font.PrimaryFont.FCP.Style" units="ms" - expires_after="2025-05-11"> + expires_after="2025-11-08"> <owner>kojii@chromium.org</owner> <owner>tkent@chromium.org</owner> <owner>layout-dev@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml index 0723f80a..4b3bcf7a6 100644 --- a/tools/metrics/histograms/metadata/sync/histograms.xml +++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -94,6 +94,12 @@ <variant name=".READING_LIST" summary="READING_LIST"/> </variants> +<variants name="SyncErrorInfobarTrigger"> + <variant name="" summary="Any trigger, this is just a total count."/> + <variant name=".NewTab" summary="Opening a new tab."/> + <variant name=".PasswordForm" summary="Loading a page with a password form."/> +</variants> + <variants name="SyncErrorReason"> <variant name=".AuthError" summary="Auth error."/> <variant name=".ClientOutOfDate" summary="Client out of date."/> @@ -2134,13 +2140,17 @@ </summary> </histogram> -<histogram name="Sync.SyncErrorInfobarDisplayed2" enum="SyncErrorInfobarTypes" - expires_after="2025-08-10"> +<histogram name="Sync.SyncErrorInfobarDisplayed2{SyncErrorInfobarTrigger}" + enum="SyncErrorInfobarTypes" expires_after="2025-08-10"> + <owner>rgod@google.com</owner> + <owner>ylahodiuk@google.com</owner> <owner>jlebel@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> <summary> - Enumeration of error conditions that displays an infobar to the user. iOS - only. + Enumeration of error conditions that displays an infobar to the user + triggered by a following event: {SyncErrorInfobarTrigger} + + iOS only. </summary> </histogram>
diff --git a/tools/metrics/histograms/metadata/web_core/histograms.xml b/tools/metrics/histograms/metadata/web_core/histograms.xml index a9af8f2..5576001 100644 --- a/tools/metrics/histograms/metadata/web_core/histograms.xml +++ b/tools/metrics/histograms/metadata/web_core/histograms.xml
@@ -80,7 +80,7 @@ </histogram> <histogram name="WebCore.Document.execCommand" enum="MappedEditingCommands" - expires_after="2025-09-28"> + expires_after="2025-11-08"> <owner>kojii@chromium.org</owner> <owner>tkent@chromium.org</owner> <summary> @@ -90,7 +90,7 @@ </histogram> <histogram name="WebCore.Editing.Commands" enum="MappedEditingCommands" - expires_after="2025-05-11"> + expires_after="2025-11-08"> <owner>kojii@chromium.org</owner> <owner>tkent@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 ee377702..52de2dd 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": "perfetto-luci-artifacts/v50.1/linux-arm64/trace_processor_shell" }, "win": { - "hash": "b85dcca74e1212a0cc61c2b770824bef6a716fef", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/6ffe623d283575c00047cf9abf90c3659505a592/trace_processor_shell.exe" + "hash": "f4034950cbc53ce5c3aa84511b50719ace834891", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/11cd406514a8212d3568448b2207d2925d5ca202/trace_processor_shell.exe" }, "linux_arm": { "hash": "99f971ca131f6d11c73f4b918099d434bdd8093c", @@ -21,8 +21,8 @@ "full_remote_path": "perfetto-luci-artifacts/v50.1/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "6a2c70dd8ecf91307dc9f297bcb297794666935f", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/6ffe623d283575c00047cf9abf90c3659505a592/trace_processor_shell" + "hash": "f770837ce31e9f5b737edf113b10be76d2651dea", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/11cd406514a8212d3568448b2207d2925d5ca202/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn index e5e10c86..d1b0125 100644 --- a/ui/android/BUILD.gn +++ b/ui/android/BUILD.gn
@@ -164,6 +164,7 @@ "java/src/org/chromium/ui/dragdrop/DropDataAndroid.java", "java/src/org/chromium/ui/events/devices/InputDeviceObserver.java", "java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java", + "java/src/org/chromium/ui/listmenu/MenuModelBridge.java", "java/src/org/chromium/ui/modaldialog/ModalDialogManagerBridge.java", "java/src/org/chromium/ui/resources/HandleViewResources.java", "java/src/org/chromium/ui/resources/ResourceFactory.java", @@ -171,6 +172,10 @@ ] } +generate_jni("menu_model_bridge_jni_headers") { + sources = [ "java/src/org/chromium/ui/listmenu/MenuModelBridge.java" ] +} + java_cpp_enum("java_enums_srcjar") { sources = [ "../base/ime/text_input_action.h",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/MenuModelBridge.java b/ui/android/java/src/org/chromium/ui/listmenu/MenuModelBridge.java similarity index 75% rename from chrome/android/java/src/org/chromium/chrome/browser/contextmenu/MenuModelBridge.java rename to ui/android/java/src/org/chromium/ui/listmenu/MenuModelBridge.java index 55f6b23..e03d274 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/MenuModelBridge.java +++ b/ui/android/java/src/org/chromium/ui/listmenu/MenuModelBridge.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chrome.browser.contextmenu; +package org.chromium.ui.listmenu; import static org.chromium.ui.listmenu.BasicListMenu.ListMenuItemType.MENU_ITEM; import static org.chromium.ui.listmenu.BasicListMenu.buildMenuDivider; @@ -14,10 +14,11 @@ import android.graphics.Bitmap; import org.jni_zero.CalledByNative; +import org.jni_zero.JNINamespace; +import org.jni_zero.JniType; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; -import org.chromium.ui.listmenu.ListMenuItemProperties; import org.chromium.ui.modelutil.MVCListAdapter.ListItem; import org.chromium.ui.modelutil.PropertyModel; @@ -30,26 +31,18 @@ * MenuModel</a>) to a Java list of {@link ListItem} to be used in context menus. */ @NullMarked +@JNINamespace("ui") public class MenuModelBridge { - private final long mNativePtr; - private final boolean mIsIncognito; private final List<ListItem> mItems = new ArrayList<>(); @CalledByNative - private static MenuModelBridge create(long nativePtr, boolean isIncognito) { - return new MenuModelBridge(nativePtr, isIncognito); + private static MenuModelBridge create() { + return new MenuModelBridge(); } - /** - * {@return A {@link MenuModelBridge} instance.} - * - * @param nativePtr The {@link Long} address of the MenuModelBridge on the C++ side. - */ - private MenuModelBridge(long nativePtr, boolean isIncognito) { - mNativePtr = nativePtr; - mIsIncognito = isIncognito; - } + /** {@return A {@link MenuModelBridge} instance.} */ + private MenuModelBridge() {} /** {@return The list of {@link ListItem} held by this {@link MenuModelBridge}.} */ public List<ListItem> getListItems() { @@ -66,7 +59,10 @@ */ @CalledByNative private void addCommand( - String label, @Nullable Bitmap bitmap, boolean isEnabled, Runnable callback) { + @JniType("std::u16string") final String label, + @JniType("SkBitmap") final @Nullable Bitmap bitmap, + final boolean isEnabled, + final Runnable callback) { PropertyModel.Builder modelBuilder = new PropertyModel.Builder(ListMenuItemProperties.ALL_KEYS) .with(TITLE, label) @@ -79,6 +75,7 @@ /** Adds a divider to the context menu. */ @CalledByNative private void addDivider() { - mItems.add(buildMenuDivider(mIsIncognito)); + // TODO(crbug.com/416222384): Update context menus to use incognito theming. + mItems.add(buildMenuDivider(/* isIncognito= */ false)); } }
diff --git a/ui/base/data_transfer_policy/data_transfer_endpoint.h b/ui/base/data_transfer_policy/data_transfer_endpoint.h index 234d37f..611c409 100644 --- a/ui/base/data_transfer_policy/data_transfer_endpoint.h +++ b/ui/base/data_transfer_policy/data_transfer_endpoint.h
@@ -65,9 +65,6 @@ DataTransferEndpoint& operator=(DataTransferEndpoint&& other); bool operator==(const DataTransferEndpoint& other) const; - bool operator!=(const DataTransferEndpoint& other) const { - return !(*this == other); - } ~DataTransferEndpoint();
diff --git a/ui/display/display.h b/ui/display/display.h index ab18dc9..4183143 100644 --- a/ui/display/display.h +++ b/ui/display/display.h
@@ -286,7 +286,6 @@ void set_label(const std::string& label) { label_ = label; } bool operator==(const Display& rhs) const; - bool operator!=(const Display& rhs) const { return !(*this == rhs); } static bool EqualExceptForHdrHeadroom(const Display& lhs, const Display& rhs); private:
diff --git a/ui/display/display_layout.cc b/ui/display/display_layout.cc index 85d5c068..85b5833 100644 --- a/ui/display/display_layout.cc +++ b/ui/display/display_layout.cc
@@ -397,18 +397,6 @@ DisplayPlacement& DisplayPlacement::operator=(const DisplayPlacement&) = default; -bool DisplayPlacement::operator==(const DisplayPlacement& other) const { - return display_id == other.display_id && - parent_display_id == other.parent_display_id && - position == other.position && - offset == other.offset && - offset_reference == other.offset_reference; -} - -bool DisplayPlacement::operator!=(const DisplayPlacement& other) const { - return !operator==(other); -} - DisplayPlacement& DisplayPlacement::Swap() { switch (position) { case TOP:
diff --git a/ui/display/display_layout.h b/ui/display/display_layout.h index eb7e152a..3ef174d4 100644 --- a/ui/display/display_layout.h +++ b/ui/display/display_layout.h
@@ -73,8 +73,8 @@ DisplayPlacement(const DisplayPlacement&); DisplayPlacement& operator=(const DisplayPlacement&); - bool operator==(const DisplayPlacement& other) const; - bool operator!=(const DisplayPlacement& other) const; + friend bool operator==(const DisplayPlacement&, + const DisplayPlacement&) = default; DisplayPlacement& Swap();
diff --git a/ui/display/manager/managed_display_info.h b/ui/display/manager/managed_display_info.h index 0f05a42..1097e2d 100644 --- a/ui/display/manager/managed_display_info.h +++ b/ui/display/manager/managed_display_info.h
@@ -73,11 +73,6 @@ float device_scale_factor_ = 1.0f; // The device scale factor of the mode. }; -inline bool operator!=(const ManagedDisplayMode& lhs, - const ManagedDisplayMode& rhs) { - return !(lhs == rhs); -} - // ManagedDisplayInfo contains metadata for each display. This is used to create // |Display| as well as to maintain extra infomation to manage displays in ash // environment. This class is intentionally made copiable.
diff --git a/ui/display/manager/touch_device_manager.cc b/ui/display/manager/touch_device_manager.cc index 757988c..d658771 100644 --- a/ui/display/manager/touch_device_manager.cc +++ b/ui/display/manager/touch_device_manager.cc
@@ -224,18 +224,6 @@ return *this; } -bool TouchDeviceIdentifier::operator<(const TouchDeviceIdentifier& rhs) const { - return std::tie(id_, secondary_id_) < std::tie(rhs.id_, rhs.secondary_id_); -} - -bool TouchDeviceIdentifier::operator==(const TouchDeviceIdentifier& rhs) const { - return id_ == rhs.id_ && secondary_id_ == rhs.secondary_id_; -} - -bool TouchDeviceIdentifier::operator!=(const TouchDeviceIdentifier& rhs) const { - return !(*this == rhs); -} - std::string TouchDeviceIdentifier::ToString() const { return base::NumberToString(id_); }
diff --git a/ui/display/manager/touch_device_manager.h b/ui/display/manager/touch_device_manager.h index e16ec6f..dc720f3 100644 --- a/ui/display/manager/touch_device_manager.h +++ b/ui/display/manager/touch_device_manager.h
@@ -64,9 +64,10 @@ TouchDeviceIdentifier& operator=(TouchDeviceIdentifier other); - bool operator<(const TouchDeviceIdentifier& other) const; - bool operator==(const TouchDeviceIdentifier& other) const; - bool operator!=(const TouchDeviceIdentifier& other) const; + friend bool operator==(const TouchDeviceIdentifier&, + const TouchDeviceIdentifier&) = default; + friend auto operator<=>(const TouchDeviceIdentifier&, + const TouchDeviceIdentifier&) = default; std::string ToString() const; std::string SecondaryIdToString() const;
diff --git a/ui/display/screen_info.cc b/ui/display/screen_info.cc index 4266f45f..a28c68eb 100644 --- a/ui/display/screen_info.cc +++ b/ui/display/screen_info.cc
@@ -35,24 +35,6 @@ ScreenInfo::~ScreenInfo() = default; ScreenInfo& ScreenInfo::operator=(const ScreenInfo& other) = default; -bool ScreenInfo::operator==(const ScreenInfo& other) const { - return device_scale_factor == other.device_scale_factor && - display_color_spaces == other.display_color_spaces && - depth == other.depth && - depth_per_component == other.depth_per_component && - is_monochrome == other.is_monochrome && rect == other.rect && - available_rect == other.available_rect && - orientation_type == other.orientation_type && - orientation_angle == other.orientation_angle && - is_extended == other.is_extended && is_primary == other.is_primary && - is_internal == other.is_internal && label == other.label && - display_id == other.display_id; -} - -bool ScreenInfo::operator!=(const ScreenInfo& other) const { - return !operator==(other); -} - std::string ScreenInfo::ToString() const { return base::StringPrintf( "ScreenInfo[%" PRId64 "] \"%s\" bounds=[%s] avail=[%s] scale=%g %s %s %s",
diff --git a/ui/display/screen_info.h b/ui/display/screen_info.h index 7bd4ec08..9099d2c5 100644 --- a/ui/display/screen_info.h +++ b/ui/display/screen_info.h
@@ -88,8 +88,8 @@ ScreenInfo(const ScreenInfo& other); ~ScreenInfo(); ScreenInfo& operator=(const ScreenInfo& other); - bool operator==(const ScreenInfo& other) const; - bool operator!=(const ScreenInfo& other) const; + + friend bool operator==(const ScreenInfo&, const ScreenInfo&) = default; // Returns a string representation of the screen. std::string ToString() const;
diff --git a/ui/display/screen_infos.cc b/ui/display/screen_infos.cc index bb418bb..8a8b001 100644 --- a/ui/display/screen_infos.cc +++ b/ui/display/screen_infos.cc
@@ -14,15 +14,6 @@ ScreenInfos::ScreenInfos(const ScreenInfos& other) = default; ScreenInfos::~ScreenInfos() = default; ScreenInfos& ScreenInfos::operator=(const ScreenInfos& other) = default; -bool ScreenInfos::operator==(const ScreenInfos& other) const { - return screen_infos == other.screen_infos && - current_display_id == other.current_display_id && - system_cursor_size == other.system_cursor_size; -} - -bool ScreenInfos::operator!=(const ScreenInfos& other) const { - return !operator==(other); -} ScreenInfo& ScreenInfos::mutable_current() { return const_cast<ScreenInfo&>(
diff --git a/ui/display/screen_infos.h b/ui/display/screen_infos.h index 891ae911..bfcefe5 100644 --- a/ui/display/screen_infos.h +++ b/ui/display/screen_infos.h
@@ -21,8 +21,7 @@ ~ScreenInfos(); ScreenInfos& operator=(const ScreenInfos& other); - bool operator==(const ScreenInfos& other) const; - bool operator!=(const ScreenInfos& other) const; + friend bool operator==(const ScreenInfos&, const ScreenInfos&) = default; // Helpers to access the current ScreenInfo element. ScreenInfo& mutable_current();
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn index 6204836..f9bfa14 100644 --- a/ui/events/BUILD.gn +++ b/ui/events/BUILD.gn
@@ -123,13 +123,6 @@ "pointer_details.h", ] - if (is_android) { - sources += [ - "keycodes/keyboard_code_conversion_android.cc", - "keycodes/keyboard_code_conversion_android.h", - ] - } - if (is_win) { sources += [ "keycodes/keyboard_code_conversion_win.cc", @@ -152,6 +145,16 @@ "//ui/gfx/geometry", ] + if (is_android) { + sources += [ + "android/event_flags_android.cc", + "android/event_flags_android.h", + "keycodes/keyboard_code_conversion_android.cc", + "keycodes/keyboard_code_conversion_android.h", + ] + deps += [ ":motionevent_jni_headers" ] + } + if (is_mac) { sources += [ "keycodes/keyboard_code_conversion_mac.h",
diff --git a/ui/events/android/event_flags_android.cc b/ui/events/android/event_flags_android.cc new file mode 100644 index 0000000..0fbc172 --- /dev/null +++ b/ui/events/android/event_flags_android.cc
@@ -0,0 +1,66 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/events/android/event_flags_android.h" + +#include <android/input.h> + +#include "ui/events/event_constants.h" + +// Must come after all headers that specialize FromJniType() / ToJniType(). +#include "ui/events/motionevent_jni_headers/MotionEvent_jni.h" + +namespace ui { + +int EventFlagsFromAndroidMetaState(int meta_state) { + int flags = EF_NONE; + + if ((meta_state & AMETA_SHIFT_ON) != 0) { + flags |= EF_SHIFT_DOWN; + } + if ((meta_state & AMETA_CTRL_ON) != 0) { + flags |= EF_CONTROL_DOWN; + } + if ((meta_state & AMETA_ALT_ON) != 0) { + flags |= EF_ALT_DOWN; + } + if ((meta_state & AMETA_META_ON) != 0) { + flags |= EF_COMMAND_DOWN; + } + if ((meta_state & AMETA_CAPS_LOCK_ON) != 0) { + flags |= EF_CAPS_LOCK_ON; + } + + return flags; +} + +int EventFlagsFromAndroidButtonState(int button_state) { + int flags = EF_NONE; + + if ((button_state & JNI_MotionEvent::BUTTON_BACK) != 0) { + flags |= EF_BACK_MOUSE_BUTTON; + } + if ((button_state & JNI_MotionEvent::BUTTON_FORWARD) != 0) { + flags |= EF_FORWARD_MOUSE_BUTTON; + } + if ((button_state & JNI_MotionEvent::BUTTON_PRIMARY) != 0) { + flags |= EF_LEFT_MOUSE_BUTTON; + } + if ((button_state & JNI_MotionEvent::BUTTON_SECONDARY) != 0) { + flags |= EF_RIGHT_MOUSE_BUTTON; + } + if ((button_state & JNI_MotionEvent::BUTTON_TERTIARY) != 0) { + flags |= EF_MIDDLE_MOUSE_BUTTON; + } + if ((button_state & JNI_MotionEvent::BUTTON_STYLUS_PRIMARY) != 0) { + flags |= EF_LEFT_MOUSE_BUTTON; + } + if ((button_state & JNI_MotionEvent::BUTTON_STYLUS_SECONDARY) != 0) { + flags |= EF_RIGHT_MOUSE_BUTTON; + } + + return flags; +} + +} // namespace ui
diff --git a/ui/events/android/event_flags_android.h b/ui/events/android/event_flags_android.h new file mode 100644 index 0000000..f8c54f6 --- /dev/null +++ b/ui/events/android/event_flags_android.h
@@ -0,0 +1,20 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_EVENTS_ANDROID_EVENT_FLAGS_ANDROID_H_ +#define UI_EVENTS_ANDROID_EVENT_FLAGS_ANDROID_H_ + +#include "ui/events/events_base_export.h" + +namespace ui { + +// Converts android meta state to event flags. +EVENTS_BASE_EXPORT int EventFlagsFromAndroidMetaState(int meta_state); + +// Converts android button state to event flags. +EVENTS_BASE_EXPORT int EventFlagsFromAndroidButtonState(int button_state); + +} // namespace ui + +#endif // UI_EVENTS_ANDROID_EVENT_FLAGS_ANDROID_H_
diff --git a/ui/events/android/key_event_android.cc b/ui/events/android/key_event_android.cc index 1c8a13e..e00505a9 100644 --- a/ui/events/android/key_event_android.cc +++ b/ui/events/android/key_event_android.cc
@@ -3,13 +3,26 @@ // found in the LICENSE file. #include "ui/events/android/key_event_android.h" + #include "base/android/jni_android.h" +#include "ui/events/android/event_flags_android.h" +#include "ui/events/event.h" +#include "ui/events/keycodes/keyboard_code_conversion_android.h" +#include "ui/events/keycodes/keyboard_codes.h" + +// Must come after all headers that specialize FromJniType() / ToJniType(). +#include "ui/events/keyevent_jni_headers/KeyEvent_jni.h" using base::android::ScopedJavaLocalRef; using base::android::AttachCurrentThread; namespace ui { +KeyEventAndroid::KeyEventAndroid(JNIEnv* env, jobject event) { + event_.Reset(env, event); + key_code_ = JNI_KeyEvent::Java_KeyEvent_getKeyCode(env, event_); +} + KeyEventAndroid::KeyEventAndroid(JNIEnv* env, jobject event, int key_code) : key_code_(key_code) { event_.Reset(env, event); @@ -21,4 +34,15 @@ return ScopedJavaLocalRef<jobject>(event_); } +KeyEvent KeyEventAndroid::ToKeyEvent() const { + KeyboardCode key_code = KeyboardCodeFromAndroidKeyCode(key_code_); + + JNIEnv* env = AttachCurrentThread(); + jint android_meta_state = + JNI_KeyEvent::Java_KeyEvent_getMetaState(env, event_); + EventFlags modifiers = EventFlagsFromAndroidMetaState(android_meta_state); + + return KeyEvent(EventType::kKeyPressed, key_code, modifiers); +} + } // namespace ui
diff --git a/ui/events/android/key_event_android.h b/ui/events/android/key_event_android.h index 14bb66f..6bb18dbc 100644 --- a/ui/events/android/key_event_android.h +++ b/ui/events/android/key_event_android.h
@@ -8,6 +8,7 @@ #include <jni.h> #include "base/android/scoped_java_ref.h" +#include "ui/events/event.h" #include "ui/events/events_export.h" namespace ui { @@ -16,6 +17,7 @@ // This is used mainly as a conveyor of Java event object. class EVENTS_EXPORT KeyEventAndroid { public: + KeyEventAndroid(JNIEnv* env, jobject event); KeyEventAndroid(JNIEnv* env, jobject event, int key_code); KeyEventAndroid(const KeyEventAndroid&) = delete; @@ -26,6 +28,11 @@ base::android::ScopedJavaLocalRef<jobject> GetJavaObject() const; int key_code() const { return key_code_; } + // Converts the event to the cross-platform key event. + // TODO(crbug.com/417078839): Update PlatformEvent to be a union-ish type that + // can be a KeyEventAndroid and allow direct conversion of it to the KeyEvent. + KeyEvent ToKeyEvent() const; + private: // The Java reference to the key event. base::android::ScopedJavaGlobalRef<jobject> event_;
diff --git a/ui/events/android/motion_event_android.cc b/ui/events/android/motion_event_android.cc index 5290e93..dda3bc3e 100644 --- a/ui/events/android/motion_event_android.cc +++ b/ui/events/android/motion_event_android.cc
@@ -17,7 +17,9 @@ #include "base/feature_list.h" #include "base/notreached.h" #include "base/numerics/angle_conversions.h" +#include "event_flags_android.h" #include "ui/base/ui_base_features.h" +#include "ui/events/android/event_flags_android.h" #include "ui/events/base_event_utils.h" #include "ui/events/event_constants.h" #include "ui/events/event_utils.h" @@ -115,35 +117,8 @@ } int ToEventFlags(int meta_state, int button_state) { - int flags = ui::EF_NONE; - - if ((meta_state & AMETA_SHIFT_ON) != 0) - flags |= ui::EF_SHIFT_DOWN; - if ((meta_state & AMETA_CTRL_ON) != 0) - flags |= ui::EF_CONTROL_DOWN; - if ((meta_state & AMETA_ALT_ON) != 0) - flags |= ui::EF_ALT_DOWN; - if ((meta_state & AMETA_META_ON) != 0) - flags |= ui::EF_COMMAND_DOWN; - if ((meta_state & AMETA_CAPS_LOCK_ON) != 0) - flags |= ui::EF_CAPS_LOCK_ON; - - if ((button_state & JNI_MotionEvent::BUTTON_BACK) != 0) - flags |= ui::EF_BACK_MOUSE_BUTTON; - if ((button_state & JNI_MotionEvent::BUTTON_FORWARD) != 0) - flags |= ui::EF_FORWARD_MOUSE_BUTTON; - if ((button_state & JNI_MotionEvent::BUTTON_PRIMARY) != 0) - flags |= ui::EF_LEFT_MOUSE_BUTTON; - if ((button_state & JNI_MotionEvent::BUTTON_SECONDARY) != 0) - flags |= ui::EF_RIGHT_MOUSE_BUTTON; - if ((button_state & JNI_MotionEvent::BUTTON_TERTIARY) != 0) - flags |= ui::EF_MIDDLE_MOUSE_BUTTON; - if ((button_state & JNI_MotionEvent::BUTTON_STYLUS_PRIMARY) != 0) - flags |= ui::EF_LEFT_MOUSE_BUTTON; - if ((button_state & JNI_MotionEvent::BUTTON_STYLUS_SECONDARY) != 0) - flags |= ui::EF_RIGHT_MOUSE_BUTTON; - - return flags; + return EventFlagsFromAndroidMetaState(meta_state) | + EventFlagsFromAndroidButtonState(button_state); } size_t ToValidHistorySize(jint history_size, ui::MotionEvent::Action action) {
diff --git a/ui/menus/BUILD.gn b/ui/menus/BUILD.gn index d2d4844..d1aecc7 100644 --- a/ui/menus/BUILD.gn +++ b/ui/menus/BUILD.gn
@@ -21,6 +21,13 @@ ] } + if (is_android) { + sources += [ + "android/menu_model_bridge.cc", + "android/menu_model_bridge.h", + ] + } + defines = [ "IS_UI_MENUS_IMPL" ] public_deps = [ @@ -44,6 +51,10 @@ "QuartzCore.framework", ] } + + if (is_android) { + public_deps += [ "//ui/android:menu_model_bridge_jni_headers" ] + } } source_set("unit_tests") {
diff --git a/ui/menus/android/menu_model_bridge.cc b/ui/menus/android/menu_model_bridge.cc new file mode 100644 index 0000000..07321728 --- /dev/null +++ b/ui/menus/android/menu_model_bridge.cc
@@ -0,0 +1,94 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/menus/android/menu_model_bridge.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_callback.h" +#include "base/android/jni_string.h" +#include "base/android/scoped_java_ref.h" +#include "base/functional/callback.h" +#include "base/memory/weak_ptr.h" +#include "ui/base/models/image_model.h" +#include "ui/base/models/menu_model.h" +#include "ui/gfx/android/java_bitmap.h" + +// Must come after all headers that specialize FromJniType() / ToJniType(). +#include "ui/android/menu_model_bridge_jni_headers/MenuModelBridge_jni.h" + +using base::android::JavaParamRef; +using base::android::ScopedJavaLocalRef; +using base::android::ToJniCallback; + +namespace ui { +MenuModelBridge::MenuModelBridge() { + JNIEnv* env = base::android::AttachCurrentThread(); + java_obj_ = Java_MenuModelBridge_create(env); +} +void MenuModelBridge::AddExtensionItems(ui::MenuModel* menu_model) { + JNIEnv* env = base::android::AttachCurrentThread(); + for (size_t i = 0; i < menu_model->GetItemCount(); ++i) { + if (!menu_model->IsVisibleAt(i)) { + continue; + } + switch (menu_model->GetTypeAt(i)) { + case MenuModel::TYPE_COMMAND: + case MenuModel::TYPE_HIGHLIGHTED: { + /* Translate both of these to basic items for now. */ + Java_MenuModelBridge_addCommand( + env, java_obj_, menu_model->GetLabelAt(i), + menu_model->GetIconAt(i).GetImage().AsBitmap(), + menu_model->IsEnabledAt(i), + ToJniCallback( + env, + base::BindOnce( + &MenuModelBridge::ActivatedAt, + /* If the weak pointer to "this" becomes + invalidated, the method will not be called, see + https://chromium.googlesource.com/chromium/src.git/+/master/docs/callback.md#Binding-A-Class-Method-With-Weak-Pointers + */ + weak_ptr_factory_.GetWeakPtr(), menu_model->AsWeakPtr(), + i))); + break; + } + case MenuModel::TYPE_CHECK: + // TODO(jhimawan): Call Java MenuModelBridge to add check item. + break; + case MenuModel::TYPE_RADIO: + // TODO(jhimawan): Call Java MenuModelBridge to add radio item. + break; + case MenuModel::TYPE_SEPARATOR: { + Java_MenuModelBridge_addDivider(env, java_obj_); + break; + } + /* Don't handle TYPE_BUTTON_ITEM for now; it's not available in the Chrome + * extensions API. */ + case MenuModel::TYPE_SUBMENU: + // TODO(jhimawan): Call Java MenuModelBridge to add submenu item. + break; + /* Don't handle TYPE_ACTIONABLE_SUBMENU for now; it's not available in the + * Chrome extensions API. */ + case MenuModel::TYPE_TITLE: + // TODO(jhimawan): Call Java MenuModelBridge to add title item. + break; + default: + break; + /* Do nothing. */ + } + } +} + +// private +void MenuModelBridge::ActivatedAt(base::WeakPtr<MenuModel> menu_model_weak_ptr, + size_t i) { + /* Should always null-check WeakPtr, see + * https://source.chromium.org/chromium/chromium/src/+/main:base/memory/weak_ptr.h;l=192;drc=192000bedcb9891ac5de22e98115f2578389e1e5 + */ + if (!menu_model_weak_ptr) { + return; + } + menu_model_weak_ptr->ActivatedAt(i); +} + +} // namespace ui
diff --git a/ui/menus/android/menu_model_bridge.h b/ui/menus/android/menu_model_bridge.h new file mode 100644 index 0000000..3675e67b --- /dev/null +++ b/ui/menus/android/menu_model_bridge.h
@@ -0,0 +1,39 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_MENUS_ANDROID_MENU_MODEL_BRIDGE_H_ +#define UI_MENUS_ANDROID_MENU_MODEL_BRIDGE_H_ + +#include <optional> + +#include "base/android/jni_android.h" +#include "base/android/scoped_java_ref.h" +#include "base/memory/weak_ptr.h" +#include "ui/base/models/menu_model.h" + +// Used to translate +// https://source.chromium.org/chromium/chromium/src/+/main:ui/base/models/menu_model.h;l=168 +// to Java List<PropertyModel>. See +// https://source.chromium.org/chromium/chromium/src/+/main:chrome/android/java/src/org/chromium/chrome/browser/contextmenu/MenuModelBridge.java + +namespace ui { +class MenuModelBridge { + public: + MenuModelBridge(); + MenuModelBridge(const MenuModelBridge&) = delete; + MenuModelBridge& operator=(const MenuModelBridge&) = delete; + virtual ~MenuModelBridge(); + + void AddExtensionItems(ui::MenuModel* menu_model); + + private: + base::android::ScopedJavaGlobalRef<jobject> java_obj_; + base::WeakPtrFactory<MenuModelBridge> weak_ptr_factory_{this}; + + void ActivatedAt(base::WeakPtr<ui::MenuModel> menu_model, size_t i); +}; + +} // namespace ui + +#endif // UI_MENUS_ANDROID_MENU_MODEL_BRIDGE_H_
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd index d8286b5..00ab2d2 100644 --- a/ui/strings/ui_strings.grd +++ b/ui/strings/ui_strings.grd
@@ -969,13 +969,13 @@ </message> <!-- Strings describing the touch calibration UX --> - <message name="IDS_DISPLAY_TOUCH_CALIBRATION_EXIT_LABEL" translateable="false" desc="A message to notify the user about using the escape key to exit the calibration mode."> + <message name="IDS_DISPLAY_TOUCH_CALIBRATION_EXIT_LABEL" desc="A message to notify the user about using the escape key to exit the calibration mode."> To exit calibration press Esc. </message> - <message name="IDS_DISPLAY_TOUCH_CALIBRATION_SECONDARY_SKIP_LABEL" translateable="false" desc="A message to notify the user about using the escape key to exit the calibration mode."> + <message name="IDS_DISPLAY_TOUCH_CALIBRATION_SECONDARY_SKIP_LABEL" desc="A message to notify the user about using the escape key to exit the calibration mode."> If the current display is not a touchscreen, press Esc. </message> - <message name="IDS_DISPLAY_TOUCH_CALIBRATION_PRIMARY_SKIP_LABEL" translateable="false" desc="A message to notify the user about using the escape key to exit the calibration mode."> + <message name="IDS_DISPLAY_TOUCH_CALIBRATION_PRIMARY_SKIP_LABEL" desc="A message to notify the user about using the escape key to exit the calibration mode."> If this display is not a touchscreen, press Esc. </message> <message name="IDS_DISPLAY_TOUCH_CALIBRATION_HINT_LABEL_TEXT" desc="Title of the hint message to inform the user what the next step is in touch calibration is">
diff --git a/ui/strings/ui_strings_grd/IDS_DISPLAY_TOUCH_CALIBRATION_EXIT_LABEL.png.sha1 b/ui/strings/ui_strings_grd/IDS_DISPLAY_TOUCH_CALIBRATION_EXIT_LABEL.png.sha1 new file mode 100644 index 0000000..9d0b74d --- /dev/null +++ b/ui/strings/ui_strings_grd/IDS_DISPLAY_TOUCH_CALIBRATION_EXIT_LABEL.png.sha1
@@ -0,0 +1 @@ +ae8672165f411bf106ad0d5026a4bf83a01a3b98 \ No newline at end of file
diff --git a/ui/strings/ui_strings_grd/IDS_DISPLAY_TOUCH_CALIBRATION_PRIMARY_SKIP_LABEL.png.sha1 b/ui/strings/ui_strings_grd/IDS_DISPLAY_TOUCH_CALIBRATION_PRIMARY_SKIP_LABEL.png.sha1 new file mode 100644 index 0000000..bbb67ed9 --- /dev/null +++ b/ui/strings/ui_strings_grd/IDS_DISPLAY_TOUCH_CALIBRATION_PRIMARY_SKIP_LABEL.png.sha1
@@ -0,0 +1 @@ +c40afd1e2c71c20a8343fc338893be1ccc8d0fd0 \ No newline at end of file
diff --git a/ui/strings/ui_strings_grd/IDS_DISPLAY_TOUCH_CALIBRATION_SECONDARY_SKIP_LABEL.png.sha1 b/ui/strings/ui_strings_grd/IDS_DISPLAY_TOUCH_CALIBRATION_SECONDARY_SKIP_LABEL.png.sha1 new file mode 100644 index 0000000..a312be4 --- /dev/null +++ b/ui/strings/ui_strings_grd/IDS_DISPLAY_TOUCH_CALIBRATION_SECONDARY_SKIP_LABEL.png.sha1
@@ -0,0 +1 @@ +415d31ab2a8d16ef462ad3c5604e66b82b66440e \ No newline at end of file
diff --git a/ui/views/examples/README.md b/ui/views/examples/README.md index 899514d..b48730ce 100644 --- a/ui/views/examples/README.md +++ b/ui/views/examples/README.md
@@ -1,7 +1,7 @@ # Overview `views_examples` and `views_examples_with_content` are executable tools to -showcase all the [Views](docs/ui/views/overview.md) components with some varied +showcase all the [Views](../../../docs/ui/views/overview.md) components with some varied styles. The latter has extra support for `web_view` as well. ## How to build and run
diff --git a/ui/views_content_client/views_content_main_delegate.cc b/ui/views_content_client/views_content_main_delegate.cc index a552c7b..77ffabc 100644 --- a/ui/views_content_client/views_content_main_delegate.cc +++ b/ui/views_content_client/views_content_main_delegate.cc
@@ -12,7 +12,7 @@ #include "base/path_service.h" #include "build/build_config.h" #include "content/public/common/content_switches.h" -#include "content/shell/browser/shell_paths.h" +#include "content/shell/common/shell_paths.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_scale_factor.h" #include "ui/base/ui_base_paths.h"
diff --git a/v8 b/v8 index 1beea5f..91514ff 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 1beea5ff6680e267f28e29054239ebcdd4ccb861 +Subproject commit 91514ffc9addb26e0bd78df8e28a668abd045cf1