diff --git a/DEPS b/DEPS index 6852a58..131458fd 100644 --- a/DEPS +++ b/DEPS
@@ -295,7 +295,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'src_internal_revision': '20b9f62811d76f8f5de0eba491b161f8bb948c6e', + 'src_internal_revision': 'ce971f9a7bc61262bdef47fe1bee00420f0bbfc0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. @@ -303,23 +303,23 @@ # 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': '84b3ee97fdd8f2df1e477b0cc79b893707da21b1', + 'v8_revision': '7f56d608e37d27607c638cdb4d9995bd7ad4d68c', # 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': '2d61c576f0dd8a1a5ef5adeefe19101c5ea64eb7', + 'angle_revision': '02bc00c406237810c435277a13f742d14cd16782', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '093b4d82a49affdcc5e6d68cc17aa0c33c82e9a2', + 'swiftshader_revision': '930d46d31b5d637f313fd5ef55da2bbf053c26c1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'e265bde6fee233a96f87ca46464dd662531e0f90', + 'pdfium_revision': 'b8e8a35d09143db3342b94ddef076c03aa46159f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. - 'boringssl_revision': '0f1d0df6183d6ddf0b4d7a10bf80122c7ec260e6', + 'boringssl_revision': '864a235afcf4d2575b1eab8de96fbf0d84f6cda9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Fuchsia sdk # and whatever else without interference from each other. @@ -371,11 +371,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '52ad7cf544050f01f47c070716b9dae8eb9fab2b', + 'catapult_revision': '64c31ffa4d735add4a7e7520a52e0e3160216132', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. - 'crossbench_revision': '35e8177a7d7594203c543fe3875fd587b949fca2', + 'crossbench_revision': '73e0cfe22e2699bf14bedb489c0b39ba1bc03702', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # 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': 'cd650159ff9210d83ed1e1aaf02b1c071d5123b3', + 'devtools_frontend_revision': 'e5e1d2ed56cb0ad0c82a0b36295cae4578d8a226', # 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': '5b595fdbcfc1d0d79354ab74f675c564273874c7', + 'dawn_revision': 'dfe3855e5d0b5367a598e60674766ffa1c894c71', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -519,7 +519,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling llvm-libc # and whatever else without interference from each other. - 'llvm_libc_revision': 'd7bdad4ef86b827a96469b1dfdfcfa1218930e59', + 'llvm_libc_revision': 'e3e030ec6ee1674bf2195d0cfd0a4bf5fee16537', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling llvm-libc # and whatever else without interference from each other. @@ -1486,12 +1486,12 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '4326f348545fb5ef5cbb59389e7e3a903d2320eb', + '72050536a13f233b345a2f22647ff5c1a289b42f', 'condition': 'checkout_android and checkout_src_internal', }, 'src/docs/website': { - 'url': Var('chromium_git') + '/website.git' + '@' + 'b2558d301fc88f8e4671024c47960ff1ee82cf34', + 'url': Var('chromium_git') + '/website.git' + '@' + '406e2b2832f3d734a2ba4f8fa93fb78deecb16d2', }, 'src/ios/third_party/earl_grey2/src': { @@ -1515,7 +1515,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'f25aad87ce54240ed58abe7ae84b9316e80a8492', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'b29adefbd8be6d39542d679b8f9189fc466283b7', 'condition': 'checkout_ios', }, @@ -1645,7 +1645,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'maUv18JmcvP3nwKYXghGhozFkEce3pFDH6JtbSR0SqQC', + 'version': 'a1d-sHWq2y1nFvYwrBfZHKtnwQXeYeyJXaK6H_dKEtQC', }, ], 'condition': 'checkout_android and non_git_source', @@ -1948,7 +1948,7 @@ # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '73e7b77d6878e58c3d26d5fe0d5877cf9ac44597', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '96096c3c83cbe537782e84dfc12981f146723f6a', 'condition': 'checkout_chromeos', }, @@ -1990,7 +1990,7 @@ Var('chromium_git') + '/external/github.com/jk-jeon/dragonbox.git' + '@' + '6c7c925b571d54486b9ffae8d9d18a822801cbda', 'src/third_party/eigen3/src': - Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '464c1d097891a1462ab28bf8bb763c1683883892', + Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '729443409942a1816ddf74b95224003b83f4925c', 'src/third_party/emoji-metadata/src': { 'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '045f146fca682a836e01cd265171312bfb300e06', @@ -2827,7 +2827,7 @@ Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f', 'src/third_party/tflite/src': - Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '829a168408c4422b4290eba063287542a608382e', + Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + 'c4aa8ff91256b43fe0cecc246c77a00e2145b3bd', 'src/third_party/turbine/cipd': { 'packages': [ @@ -2840,16 +2840,16 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@96793fb0ff6fb5d4328cc6f71d84f5cb2d835daf', - 'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@fc9889c889561c5882e83819dcaffef5ed45529b', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@0b7863549d960381696d3cd7485ac6a284122e15', + '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@bab63ff679c41eb75fc67dac76e1dc44426101e1', - 'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@8e9165a3d162967a424dcf2ff645a98b50381cce', - 'src/third_party/vulkan-headers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Headers@e2e53a724677f6eba8ff0ce1ccb64ee321785cbd', - 'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@fb78607414e154c7a5c01b23177ba719c8a44909', - 'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@0b8196724e4ad28cc7459b82a9b75f252c08cb3e', - 'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@4e246c56ec5afb5ad66b9b04374d39ac04675c8e', - 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@cea6ec1cdd37494c1f0fc5619c6c356ac33372fb', + '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@e8864edbebe9fb9872c6c95b2363b490c6105a15', + '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@17cf8188d8b49bafb6c2f8ecede238f8d2dec5bf', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21', @@ -2888,13 +2888,13 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'c01b768bce4a143e152c1870b6ba99ea6267d2b0', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'e5e17d8bb639438e1c99cbf367928a242c3bdef6', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '8b48ab0e88b1c6716598ffa1218783acb0691771', 'src/third_party/webpagereplay': Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'), 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'd69d0808c37b4ea338e59a58837ef180023316a6', + Var('webrtc_git') + '/src.git' + '@' + '8ae8263ecc04b6fd78886e9906194e71a574f88c', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -2918,7 +2918,7 @@ }, 'src/third_party/xnnpack/src': - Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + '05eec89fee573a08d841fbaf11db0357586fc6ae', + Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + '1b2beba83092bed68775b6e2433596627988c74b', 'src/third_party/libei/cipd': { @@ -3016,7 +3016,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/boca_app/app', - 'version': 'vZXDAVTh-nB3mXxHO9THfBFo8DrgCW6mY-5f1Emi_ukC', + 'version': 'N1iPTYt5ijzkWmHZWIguGMVPVXU1jBWJLdMHT6fvAj0C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3038,7 +3038,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'f-zzVreu26KWGyDpux6WAgj31DoLpwAdHVhSl2LBEDQC', + 'version': 'taLuHtO78kWltYP_ZiTnuCBWONLuhnxQmxNbAQWuQEQC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -4591,7 +4591,7 @@ 'src/components/autofill/core/browser/form_parsing/internal_resources': { 'url': Var('chrome_git') + '/chrome/components/autofill_regex_patterns.git' + '@' + - 'ee4b7f29de55d7867a004208580a994e5da35ed0', + '3fb8783d75611c5ada2ee094ad2be8331e9bd233', 'condition': 'checkout_src_internal', }, @@ -4614,7 +4614,7 @@ 'src/components/optimization_guide/internal': { 'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' + - 'd9be8fda5a8b047287677a35f2b3a6111f5883be', + '448e864469af5010a1dbb83b15d0cbfa1dcb5f55', 'condition': 'checkout_src_internal', }, @@ -4680,7 +4680,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - '6753a19d2e211ea27988a2603073395d0469a202', + '8fbb4c8734fa75050d85b613666e0d87d27e061e', 'condition': 'checkout_ios and checkout_src_internal', },
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index cab4c11f..b749005 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -674,8 +674,10 @@ // NavigationThrottles that don't delay or cancel navigations (e.g. // throttles that are only observing callbacks without affecting navigation // behavior) should be added before MetricsNavigationThrottle. - registry.AddThrottle(page_load_metrics::MetricsNavigationThrottle::Create( - &navigation_handle)); + // TODO(https://crbug.com/412524375): This assumption is fragile. This + // should be cared by adding an attribute flag to + // NavigationThrottleRegistry::AddThrottle(). + page_load_metrics::MetricsNavigationThrottle::CreateAndAdd(registry); } // Use Synchronous mode for the navigation interceptor, since this class // doesn't actually call into an arbitrary client, it just posts a task to
diff --git a/android_webview/browser/aw_settings.cc b/android_webview/browser/aw_settings.cc index 94d9a5f..2b68416 100644 --- a/android_webview/browser/aw_settings.cc +++ b/android_webview/browser/aw_settings.cc
@@ -664,9 +664,6 @@ web_prefs->local_storage_enabled = Java_AwSettings_getDomStorageEnabledLocked(env, obj); - web_prefs->databases_enabled = - Java_AwSettings_getDatabaseEnabledLocked(env, obj); - web_prefs->wide_viewport_quirk = true; web_prefs->use_wide_viewport = Java_AwSettings_getUseWideViewportLocked(env, obj);
diff --git a/android_webview/common/aw_switches.cc b/android_webview/common/aw_switches.cc index 8260e5f..9f75931 100644 --- a/android_webview/common/aw_switches.cc +++ b/android_webview/common/aw_switches.cc
@@ -86,6 +86,11 @@ // updater downloading service in nonembedded WebView. const char kWebViewFpsComponent[] = "webview-fps-component"; +// Enables downloading MaskedDomainListComponentInstallerPolicy by the component +// updater downloading service in nonembedded WebView. +const char kWebViewMaskedDomainListComponent[] = + "webview-masked-domain-list-component"; + // Force disables 3rd party cookie for all apps. const char kWebViewForceDisable3pcs[] = "webview-force-disable-3pcs";
diff --git a/android_webview/common/aw_switches.h b/android_webview/common/aw_switches.h index fbab4d82..24539fa 100644 --- a/android_webview/common/aw_switches.h +++ b/android_webview/common/aw_switches.h
@@ -25,6 +25,7 @@ extern const char kWebViewEnableTrustTokensComponent[]; extern const char kWebViewTpcdMetadaComponent[]; extern const char kWebViewFpsComponent[]; +extern const char kWebViewMaskedDomainListComponent[]; extern const char kWebViewForceDisable3pcs[]; extern const char kWebViewForceCrashJava[]; extern const char kWebViewForceCrashNative[];
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java b/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java index 54bf4bf0..724b1a62 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java
@@ -712,11 +712,7 @@ @Override public synchronized void setDatabaseEnabled(boolean flag) { - try (TraceEvent event = - TraceEvent.scoped("WebView.APICall.Framework.WEB_SETTINGS_SET_DATABASE_ENABLED")) { - WebViewChromium.recordWebViewApiCall(ApiCall.WEB_SETTINGS_SET_DATABASE_ENABLED); - mAwSettings.setDatabaseEnabled(flag); - } + // Intentional no-op. } @Override @@ -747,11 +743,8 @@ @Override public synchronized boolean getDatabaseEnabled() { - try (TraceEvent event = - TraceEvent.scoped("WebView.APICall.Framework.WEB_SETTINGS_GET_DATABASE_ENABLED")) { - WebViewChromium.recordWebViewApiCall(ApiCall.WEB_SETTINGS_GET_DATABASE_ENABLED); - return mAwSettings.getDatabaseEnabled(); - } + // Intentional no-op. + return false; } @Override
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java index 06605b7..88de490 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
@@ -426,11 +426,12 @@ () -> { AwBrowserProcess.initializeMetricsLogUploader(); - RecordHistogram.recordSparseHistogram( - "Android.WebView.TargetSdkVersion", + int targetSdkVersion = ContextUtils.getApplicationContext() .getApplicationInfo() - .targetSdkVersion); + .targetSdkVersion; + RecordHistogram.recordSparseHistogram( + "Android.WebView.TargetSdkVersion", targetSdkVersion); try (ScopedSysTraceEvent e = ScopedSysTraceEvent.scoped( @@ -445,7 +446,7 @@ if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) ? CompatChanges.isChangeEnabled(WebSettings.ENABLE_SIMPLIFIED_DARK_MODE) - : BuildInfo.targetsAtLeastT()) { + : targetSdkVersion >= Build.VERSION_CODES.TIRAMISU) { AwDarkMode.enableSimplifiedDarkMode(); }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSettings.java b/android_webview/java/src/org/chromium/android_webview/AwSettings.java index 197004b..3d2ab0f5 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwSettings.java +++ b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
@@ -161,7 +161,6 @@ private boolean mJavaScriptCanOpenWindowsAutomatically; private boolean mSupportMultipleWindows; private boolean mDomStorageEnabled; - private boolean mDatabaseEnabled; private boolean mUseWideViewport; private boolean mZeroLayoutHeightDisablesViewportQuirk; private boolean mForceZeroLayoutHeight; @@ -1591,30 +1590,6 @@ return mDomStorageEnabled; } - /** See {@link android.webkit.WebSettings#setDatabaseEnabled}. */ - public void setDatabaseEnabled(boolean flag) { - if (TRACE) Log.i(TAG, "setDatabaseEnabled=" + flag); - synchronized (mAwSettingsLock) { - if (mDatabaseEnabled != flag) { - mDatabaseEnabled = flag; - mEventHandler.updateWebkitPreferencesLocked(); - } - } - } - - /** See {@link android.webkit.WebSettings#getDatabaseEnabled}. */ - public boolean getDatabaseEnabled() { - synchronized (mAwSettingsLock) { - return mDatabaseEnabled; - } - } - - @CalledByNative - private boolean getDatabaseEnabledLocked() { - assert Thread.holdsLock(mAwSettingsLock); - return mDatabaseEnabled; - } - /** See {@link android.webkit.WebSettings#setDefaultTextEncodingName}. */ public void setDefaultTextEncodingName(String encoding) { if (TRACE) Log.i(TAG, "setDefaultTextEncodingName=" + encoding);
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 a6506ca..81dc59d 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
@@ -942,9 +942,6 @@ Flag.baseFeature( "AllowSensorsToEnterBfcache", "Allow pages with sensors to enter back/forward cache."), - Flag.baseFeature( - BlinkFeatures.FONTATIONS_FONT_BACKEND, - "Enables the Fontations font backend for web fonts."), Flag.baseFeature("OverrideAPIKey"), Flag.baseFeature( "RustyPng", "When enabled, uses Rust `png` crate to decode and encode PNG images."), @@ -1056,6 +1053,7 @@ "Enable the <link blocking=\"full-frame-rate\"/> API to lower the frame rate during" + " loading"), Flag.baseFeature("ProgressiveAccessibility"), + Flag.baseFeature("PreloadingNoSamePageFragmentAnchorTracking"), // Add new commandline switches and features above. The final entry should have a // trailing comma for cleaner diffs. };
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwBackForwardCacheTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwBackForwardCacheTest.java index 2a7e62e..2626f64 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwBackForwardCacheTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwBackForwardCacheTest.java
@@ -516,8 +516,6 @@ () -> settings.setForceZeroLayoutHeight(!settings.getForceZeroLayoutHeight())); verifyPageEvictedWithSettingsChange( () -> settings.setDomStorageEnabled(!settings.getDomStorageEnabled())); - verifyPageEvictedWithSettingsChange( - () -> settings.setDatabaseEnabled(!settings.getDatabaseEnabled())); verifyPageEvictedWithSettingsChange(() -> settings.setDefaultTextEncodingName("Latin-1")); verifyPageEvictedWithSettingsChange( () -> {
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwParameterizedTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwParameterizedTest.java index c786b837..e75b7a9 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwParameterizedTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwParameterizedTest.java
@@ -30,7 +30,6 @@ settings.setAllowFileAccessFromFileUrls(true); settings.setAllowUniversalAccessFromFileUrls(true); settings.setBuiltInZoomControls(true); - settings.setDatabaseEnabled(true); settings.setDisplayZoomControls(false); settings.setDomStorageEnabled(true); settings.setImagesEnabled(false);
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/WebExposedTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/WebExposedTest.java index 36db7e82..01e1f45 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/WebExposedTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/WebExposedTest.java
@@ -141,8 +141,6 @@ settings.setAllowFileAccessFromFileUrls(true); settings.setJavaScriptEnabled(true); - // Exposes window.openDatabase - settings.setDatabaseEnabled(true); // Exposes Payment APIs settings.setPaymentRequestEnabled(true);
diff --git a/android_webview/nonembedded/component_updater/registration.cc b/android_webview/nonembedded/component_updater/registration.cc index 25bd290..0f09d91 100644 --- a/android_webview/nonembedded/component_updater/registration.cc +++ b/android_webview/nonembedded/component_updater/registration.cc
@@ -43,18 +43,27 @@ component_installer_list.push_back( std::make_unique< component_updater::OriginTrialsComponentInstallerPolicy>()); - component_installer_list.push_back( - std::make_unique< - component_updater::MaskedDomainListComponentInstallerPolicy>( - /*on_list_ready=*/base::BindRepeating( - [](base::Version version, - std::optional<mojo_base::ProtoWrapper> masked_domain_list) { - if (masked_domain_list.has_value()) { - VLOG(1) << "Received Masked Domain List version " << version; - } else { - LOG(ERROR) << "Could not read Masked Domain List file"; - } - }))); + + // Note: We're using a command-line switch because finch features + // isn't supported in nonembedded WebView. + // After setting this flag, it may be necessary to force restart the + // non-embedded process. + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kWebViewMaskedDomainListComponent)) { + component_installer_list.push_back( + std::make_unique< + component_updater::MaskedDomainListComponentInstallerPolicy>( + /*on_list_ready=*/base::BindRepeating( + [](base::Version version, + std::optional<mojo_base::ProtoWrapper> masked_domain_list) { + if (masked_domain_list.has_value()) { + VLOG(1) + << "Received Masked Domain List version " << version; + } else { + LOG(ERROR) << "Could not read Masked Domain List file"; + } + }))); + } // Note: We're using a command-line switch because finch features // isn't supported in nonembedded WebView.
diff --git a/android_webview/tools/run_cts.pydeps b/android_webview/tools/run_cts.pydeps index a80607f7..9f26c3bf 100644 --- a/android_webview/tools/run_cts.pydeps +++ b/android_webview/tools/run_cts.pydeps
@@ -74,7 +74,6 @@ //third_party/catapult/devil/devil/devil_env.py //third_party/catapult/devil/devil/utils/__init__.py //third_party/catapult/devil/devil/utils/cmd_helper.py -//third_party/catapult/devil/devil/utils/host_utils.py //third_party/catapult/devil/devil/utils/lazy/__init__.py //third_party/catapult/devil/devil/utils/lazy/weak_constant.py //third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java b/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java index 01fcc52..f0ed2ee 100644 --- a/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java +++ b/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java
@@ -34,7 +34,6 @@ import androidx.webkit.WebViewCompat; import androidx.webkit.WebViewFeature; -import org.chromium.base.BuildInfo; import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.PackageManagerUtils; @@ -114,8 +113,7 @@ if (!WebViewFeature.isFeatureSupported(WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE)) { menu.findItem(R.id.menu_enable_tracing).setEnabled(false); } - if (!WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK) - || BuildInfo.targetsAtLeastT()) { + if (!WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { menu.findItem(R.id.menu_force_dark_off).setEnabled(false); menu.findItem(R.id.menu_force_dark_auto).setEnabled(false); menu.findItem(R.id.menu_force_dark_on).setEnabled(false); @@ -126,8 +124,7 @@ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { menu.findItem(R.id.menu_night_mode_on).setEnabled(false); } - if (!BuildInfo.targetsAtLeastT() - || !WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { + if (!WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { menu.findItem(R.id.menu_algorithmic_darkening_on).setEnabled(false); } return super.onCreateOptionsMenu(menu); @@ -142,8 +139,7 @@ } else { menu.findItem(R.id.menu_enable_tracing).setEnabled(false); } - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK) - && !BuildInfo.targetsAtLeastT()) { + if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { int forceDarkState = WebSettingsCompat.getForceDark(mWebView.getSettings()); switch (forceDarkState) { case WebSettingsCompat.FORCE_DARK_OFF: @@ -171,8 +167,7 @@ } menu.findItem(R.id.menu_night_mode_on).setChecked(checked); } - if (BuildInfo.targetsAtLeastT() - && WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { + if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) { menu.findItem(R.id.menu_algorithmic_darkening_on) .setChecked( WebSettingsCompat.isAlgorithmicDarkeningAllowed( @@ -232,10 +227,10 @@ try (StrictModeContext ignored = StrictModeContext.allowDiskWrites()) { String outFileName = getFilesDir() + "/webview_tracing.json"; try { + mIsStoppingTracing = true; tracingController.stop( new TracingLogger(outFileName, this), Executors.newSingleThreadExecutor()); - mIsStoppingTracing = true; } catch (FileNotFoundException e) { throw new RuntimeException(e); } @@ -422,19 +417,16 @@ @Override public void close() throws IOException { super.close(); - showDialog(mByteCount); - mIsStoppingTracing = false; - } - private void showDialog(long nbBytes) { StringBuilder info = new StringBuilder(); info.append("Tracing data written to file\n"); - info.append("number of bytes: " + nbBytes); + info.append("number of bytes: " + mByteCount); mActivity.runOnUiThread( new Runnable() { @Override public void run() { + mIsStoppingTracing = false; AlertDialog dialog = new AlertDialog.Builder(mActivity) .setTitle("Tracing API")
diff --git a/ash/controls/contextual_nudge.cc b/ash/controls/contextual_nudge.cc index 6e9c08c6..08d072f6f 100644 --- a/ash/controls/contextual_nudge.cc +++ b/ash/controls/contextual_nudge.cc
@@ -50,7 +50,7 @@ // Bubbles that use transparent colors should not paint their ClientViews to a // layer as doing so could result in visual artifacts. SetPaintClientToLayer(false); - set_background_color(SK_ColorTRANSPARENT); + SetBackgroundColor(SK_ColorTRANSPARENT); set_close_on_deactivate(false); set_margins(gfx::Insets()); set_accept_events(!tap_callback.is_null());
diff --git a/ash/game_dashboard/game_dashboard_main_menu_view.cc b/ash/game_dashboard/game_dashboard_main_menu_view.cc index 76252d1b..2fde27e1 100644 --- a/ash/game_dashboard/game_dashboard_main_menu_view.cc +++ b/ash/game_dashboard/game_dashboard_main_menu_view.cc
@@ -814,7 +814,7 @@ : context_(context) { DCHECK(context_); DCHECK(context_->game_dashboard_button_widget()); - set_background_color(cros_tokens::kCrosSysSystemBaseElevatedOpaque); + SetBackgroundColor(cros_tokens::kCrosSysSystemBaseElevatedOpaque); SetBorder(views::CreateRoundedRectBorder( /*thickness=*/1, kBubbleCornerRadius, cros_tokens::kCrosSysSystemHighlight1));
diff --git a/ash/quick_insert/views/quick_insert_preview_bubble.cc b/ash/quick_insert/views/quick_insert_preview_bubble.cc index 1f6a4ac..2ae58bc 100644 --- a/ash/quick_insert/views/quick_insert_preview_bubble.cc +++ b/ash/quick_insert/views/quick_insert_preview_bubble.cc
@@ -32,8 +32,6 @@ namespace ash { namespace { -constexpr ui::ColorId kBackgroundColor = - cros_tokens::kCrosSysSystemBaseElevatedOpaque; constexpr int kBubbleOverlapOverPicker = 4; constexpr int kQuickInsertBubbleCornerRadius = 12; constexpr gfx::Insets kMargins(8); @@ -76,7 +74,7 @@ views::BubbleBorder::LEFT_CENTER, views::BubbleBorder::STANDARD_SHADOW, /*autosize=*/true) { - set_background_color(kBackgroundColor); + SetBackgroundColor(cros_tokens::kCrosSysSystemBaseElevatedOpaque); // Configuration for this view. SetLayoutManager(
diff --git a/ash/shelf/shelf_bubble.cc b/ash/shelf/shelf_bubble.cc index 5ee893a4..021b69f 100644 --- a/ash/shelf/shelf_bubble.cc +++ b/ash/shelf/shelf_bubble.cc
@@ -67,7 +67,7 @@ anchor, arrow_position.value_or(GetArrow(alignment))), for_tooltip_(for_tooltip) { - set_background_color(SK_ColorTRANSPARENT); + SetBackgroundColor(SK_ColorTRANSPARENT); // Bubbles that use transparent colors should not paint their ClientViews to a // layer as doing so could result in visual artifacts.
diff --git a/ash/shelf/shelf_shutdown_confirmation_bubble.cc b/ash/shelf/shelf_shutdown_confirmation_bubble.cc index bea7d87..e39df7e8 100644 --- a/ash/shelf/shelf_shutdown_confirmation_bubble.cc +++ b/ash/shelf/shelf_shutdown_confirmation_bubble.cc
@@ -191,7 +191,7 @@ AshColorProvider::ContentLayerType::kButtonLabelColor); cancel_->SetEnabledTextColors(button_color); confirm_->SetEnabledTextColors(button_color); - set_background_color(ShelfConfig::Get()->GetDefaultShelfColor(GetWidget())); + SetBackgroundColor(ShelfConfig::Get()->GetDefaultShelfColor(GetWidget())); } std::u16string ShelfShutdownConfirmationBubble::GetAccessibleWindowTitle()
diff --git a/ash/system/accessibility/facegaze_bubble_view.cc b/ash/system/accessibility/facegaze_bubble_view.cc index aecc216..1a70348 100644 --- a/ash/system/accessibility/facegaze_bubble_view.cc +++ b/ash/system/accessibility/facegaze_bubble_view.cc
@@ -80,7 +80,7 @@ const base::RepeatingCallback<void()>& on_mouse_entered, const base::RepeatingCallback<void(const ui::Event& event)>& on_close_button_clicked) { - set_background_color(kBackgroundColorId); + SetBackgroundColor(kBackgroundColorId); set_parent_window( Shell::GetContainer(Shell::GetPrimaryRootWindow(), kShellWindowId_AccessibilityBubbleContainer)); @@ -120,19 +120,7 @@ } void FaceGazeBubbleView::UpdateColor(bool is_warning) { - ui::ColorId background_color_id = - is_warning ? kWarningBackgroundColor : kBackgroundColorId; - SkColor background_color = GetColorProvider()->GetColor(background_color_id); - - set_background_color(background_color_id); - View* const contents_view = GetContentsView(); - DCHECK(contents_view); - contents_view->SetBackground( - (views::CreateSolidBackground(background_color))); - views::BubbleFrameView* frame_view = GetBubbleFrameView(); - if (frame_view) { - frame_view->SetBackgroundColor(background_color); - } + SetBackgroundColor(is_warning ? kWarningBackgroundColor : kBackgroundColorId); } std::u16string_view FaceGazeBubbleView::GetTextForTesting() const { @@ -178,7 +166,7 @@ is_warning ? kWarningForegroundColor : kColorAshTextColorPrimary; image_->SetImage(ui::ImageModel::FromVectorIcon( kFacegazeIcon, foreground_color, kIconSizeDip)); - label_->SetEnabledColor(GetColorProvider()->GetColor(foreground_color)); + label_->SetEnabledColor(foreground_color); } BEGIN_METADATA(FaceGazeBubbleMainContentView)
diff --git a/ash/system/toast/anchored_nudge.cc b/ash/system/toast/anchored_nudge.cc index a958d8db..9e35355 100644 --- a/ash/system/toast/anchored_nudge.cc +++ b/ash/system/toast/anchored_nudge.cc
@@ -119,7 +119,7 @@ click_callback_(std::move(nudge_data.click_callback)), dismiss_callback_(std::move(nudge_data.dismiss_callback)) { SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone)); - set_background_color(SK_ColorTRANSPARENT); + SetBackgroundColor(SK_ColorTRANSPARENT); set_margins(gfx::Insets()); set_close_on_deactivate(false); set_highlight_button_when_shown(nudge_data.highlight_anchor_button);
diff --git a/ash/system/tray/tray_bubble_view.cc b/ash/system/tray/tray_bubble_view.cc index 94dc07a..3802dd6 100644 --- a/ash/system/tray/tray_bubble_view.cc +++ b/ash/system/tray/tray_bubble_view.cc
@@ -356,7 +356,7 @@ gfx::RoundedCornersF{static_cast<float>(params_.corner_radius)}); layer()->SetIsFastRoundedCorner(true); - set_background_color(cros_tokens::kCrosSysSystemBaseElevatedOpaque); + SetBackgroundColor(cros_tokens::kCrosSysSystemBaseElevatedOpaque); SetBorder(std::make_unique<views::HighlightBorder>( params_.corner_radius, views::HighlightBorder::Type::kHighlightBorderOnShadow)); @@ -364,7 +364,7 @@ if (init_params.translucent && chromeos::features::IsSystemBlurEnabled()) { CHECK(!init_params.transparent); - set_background_color(cros_tokens::kCrosSysSystemBaseElevated); + SetBackgroundColor(cros_tokens::kCrosSysSystemBaseElevated); layer()->SetFillsBoundsOpaquely(false); layer()->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma); layer()->SetBackdropFilterQuality(ColorProvider::kBackgroundBlurQuality);
diff --git a/ash/user_education/views/help_bubble_view_ash.cc b/ash/user_education/views/help_bubble_view_ash.cc index d2b29c96..9d1d280 100644 --- a/ash/user_education/views/help_bubble_view_ash.cc +++ b/ash/user_education/views/help_bubble_view_ash.cc
@@ -282,7 +282,7 @@ TranslateArrow(params.arrow), views::BubbleBorder::STANDARD_SHADOW), id_(id) { - set_background_color(cros_tokens::kCrosSysDialogContainer); + SetBackgroundColor(cros_tokens::kCrosSysDialogContainer); SetCanActivate(true); // When hosted within a `views::ScrollView`, the anchor view may be
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service.cc b/ash/webui/shimless_rma/backend/shimless_rma_service.cc index fa100a7..baf806f 100644 --- a/ash/webui/shimless_rma/backend/shimless_rma_service.cc +++ b/ash/webui/shimless_rma/backend/shimless_rma_service.cc
@@ -1609,7 +1609,7 @@ void ShimlessRmaService::InstallLastFound3pDiagnosticsApp( InstallLastFound3pDiagnosticsAppCallback callback) { if (extracted_3p_diag_swbn_path_.empty() || - extracted_3p_diag_swbn_path_.empty()) { + extracted_3p_diag_crx_path_.empty()) { LOG(ERROR) << "Should call GetInstallable3pDiagnosticsAppPath first"; std::move(callback).Run(nullptr); return;
diff --git a/base/BUILD.gn b/base/BUILD.gn index 3b5e3da6..34f4bc9a 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -5555,7 +5555,6 @@ "test/android/junit/src/org/chromium/base/test/BaseRobolectricTestListener.java", "test/android/junit/src/org/chromium/base/test/BaseRobolectricTestRule.java", "test/android/junit/src/org/chromium/base/test/BaseRobolectricTestRunner.java", - "test/android/junit/src/org/chromium/base/test/ShadowBuildInfo.java", "test/android/junit/src/org/chromium/base/test/util/BaseFlagTestRule.java", "test/android/junit/src/org/chromium/base/test/util/TestRunnerTestRule.java", ]
diff --git a/base/android/android_info.cc b/base/android/android_info.cc index 99d736d..2b745c7f 100644 --- a/base/android/android_info.cc +++ b/base/android/android_info.cc
@@ -53,15 +53,11 @@ const char* hardware; - bool is_at_least_u; - const char* codename; // Available only on android S+. For S-, this method returns empty string. const char* soc_manufacturer; - bool is_at_least_t; - const char* abi_name; }; @@ -96,9 +92,7 @@ const jni_zero::JavaParamRef<jstring>& socManufacturer, const jni_zero::JavaParamRef<jstring>& supportedAbis, jint sdkInt, - jboolean isDebugAndroid, - jboolean isAtleastU, - jboolean isAtleastT) { + jboolean isDebugAndroid) { DCHECK(!holder.has_value()); auto java_string_to_const_char = [](const jni_zero::JavaParamRef<jstring>& str) { @@ -117,12 +111,9 @@ .is_debug_android = static_cast<bool>(isDebugAndroid), .version_incremental = java_string_to_const_char(versionIncremental), .hardware = java_string_to_const_char(hardware), - .is_at_least_u = static_cast<bool>(isAtleastU), .codename = java_string_to_const_char(codeName), .soc_manufacturer = java_string_to_const_char(socManufacturer), - .is_at_least_t = static_cast<bool>(isAtleastT), - .abi_name = java_string_to_const_char(supportedAbis), - }; + .abi_name = java_string_to_const_char(supportedAbis)}; } const char* device() { @@ -173,10 +164,6 @@ return get_android_info().hardware; } -bool is_at_least_u() { - return get_android_info().is_at_least_u; -} - const char* codename() { return get_android_info().codename; } @@ -186,10 +173,6 @@ return get_android_info().soc_manufacturer; } -bool is_at_least_t() { - return get_android_info().is_at_least_t; -} - const char* abi_name() { return get_android_info().abi_name; }
diff --git a/base/android/android_info.h b/base/android/android_info.h index fc5da27..556b13e 100644 --- a/base/android/android_info.h +++ b/base/android/android_info.h
@@ -59,15 +59,11 @@ BASE_EXPORT const char* hardware(); -bool is_at_least_u(); - const char* codename(); // Available only on android S+. For S-, this method returns empty string. const char* soc_manufacturer(); -bool is_at_least_t(); - const char* abi_name(); } // namespace base::android::android_info
diff --git a/base/android/apk_info.cc b/base/android/apk_info.cc index f9e629e8..84527af9 100644 --- a/base/android/apk_info.cc +++ b/base/android/apk_info.cc
@@ -35,7 +35,6 @@ const char* resources_version; const char* installer_package_name; bool is_debug_app; - bool targets_at_least_u; int target_sdk_version; }; @@ -65,7 +64,6 @@ const jni_zero::JavaParamRef<jstring>& resourcesVersion, const jni_zero::JavaParamRef<jstring>& installerPackageName, jboolean isDebugApp, - jboolean targetsAtleastU, jint targetSdkVersion) { DCHECK(!holder.has_value()); auto java_string_to_const_char = @@ -82,7 +80,6 @@ .resources_version = java_string_to_const_char(resourcesVersion), .installer_package_name = java_string_to_const_char(installerPackageName), .is_debug_app = static_cast<bool>(isDebugApp), - .targets_at_least_u = static_cast<bool>(targetsAtleastU), .target_sdk_version = targetSdkVersion}; } @@ -126,7 +123,4 @@ return get_apk_info().target_sdk_version; } -bool targets_at_least_u() { - return get_apk_info().targets_at_least_u; -} } // namespace base::android::apk_info
diff --git a/base/android/build_info.cc b/base/android/build_info.cc index 6d6ba20..8acac8d 100644 --- a/base/android/build_info.cc +++ b/base/android/build_info.cc
@@ -62,10 +62,7 @@ is_tv_(device_info::is_tv()), version_incremental_(android_info::version_incremental()), hardware_(android_info::hardware()), - is_at_least_t_(android_info::is_at_least_t()), is_automotive_(device_info::is_automotive()), - is_at_least_u_(android_info::is_at_least_u()), - targets_at_least_u_(apk_info::targets_at_least_u()), codename_(android_info::codename()), vulkan_deqp_level_(device_info::vulkan_deqp_level()), is_foldable_(device_info::is_foldable()),
diff --git a/base/android/build_info.h b/base/android/build_info.h index 93ab2104..b58b2bd6 100644 --- a/base/android/build_info.h +++ b/base/android/build_info.h
@@ -137,14 +137,8 @@ const char* hardware() const { return hardware_; } - bool is_at_least_t() const { return is_at_least_t_; } - bool is_automotive() const { return is_automotive_; } - bool is_at_least_u() const { return is_at_least_u_; } - - bool targets_at_least_u() const { return targets_at_least_u_; } - const char* codename() const { return codename_; } bool is_foldable() const { return is_foldable_; } @@ -192,10 +186,7 @@ const bool is_tv_; const char* const version_incremental_; const char* const hardware_; - const bool is_at_least_t_; const bool is_automotive_; - const bool is_at_least_u_; - const bool targets_at_least_u_; const char* const codename_; const int32_t vulkan_deqp_level_; const bool is_foldable_;
diff --git a/base/android/bundle_utils.cc b/base/android/bundle_utils.cc index c0f024cd..c4b070a 100644 --- a/base/android/bundle_utils.cc +++ b/base/android/bundle_utils.cc
@@ -41,9 +41,8 @@ // contains the offset to add to the pointer, in order to find the actual // desired pointer address. // -// # Safety -// If the value in the pointer does not provide an offset from the pointer that -// stays inside the same allocation, Undefined Behaviour can result. +// PRECONDITIONS: The value in the pointer must provide an offset from the +// pointer that stays inside the same allocation. UNSAFE_BUFFER_USAGE void* ReadRelPtr(int32_t* relptr) { // SAFETY: This relies on the caller to provide a valid pointer + value. return UNSAFE_BUFFERS(reinterpret_cast<char*>(relptr) + *relptr);
diff --git a/base/android/java/src/org/chromium/base/AndroidInfo.java b/base/android/java/src/org/chromium/base/AndroidInfo.java index a9cd969..485dcf293 100644 --- a/base/android/java/src/org/chromium/base/AndroidInfo.java +++ b/base/android/java/src/org/chromium/base/AndroidInfo.java
@@ -5,7 +5,6 @@ package org.chromium.base; import android.os.Build; -import android.os.Build.VERSION_CODES; import android.text.TextUtils; import org.jni_zero.CalledByNative; @@ -45,9 +44,7 @@ : "", /* supportedAbis= */ TextUtils.join(", ", Build.SUPPORTED_ABIS), /* sdkInt= */ Build.VERSION.SDK_INT, - /* isDebugAndroid= */ isDebugAndroid(), - /* isAtleastU= */ Build.VERSION.SDK_INT >= VERSION_CODES.UPSIDE_DOWN_CAKE, - /* isAtleastT= */ Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU); + /* isDebugAndroid= */ isDebugAndroid()); } /* Truncated version of Build.FINGERPRINT (for crash reporting). */ @@ -86,8 +83,6 @@ String socManufacturer, String supportedAbis, int sdkInt, - boolean isDebugAndroid, - boolean isAtleastU, - boolean isAtleastT); + boolean isDebugAndroid); } }
diff --git a/base/android/java/src/org/chromium/base/ApkInfo.java b/base/android/java/src/org/chromium/base/ApkInfo.java index cb020ced8..bb5ba01 100644 --- a/base/android/java/src/org/chromium/base/ApkInfo.java +++ b/base/android/java/src/org/chromium/base/ApkInfo.java
@@ -10,7 +10,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.os.Build; import android.os.Process; import org.jni_zero.CalledByNative; @@ -100,7 +99,6 @@ /* resourcesVersion= */ instance.mResourcesVersion, /* installerPackageName= */ instance.mInstallerPackageName, /* isDebugApp= */ isDebugApp(), - /* targetsAtleastU= */ targetsAtLeastU(), /* targetSdkVersion= */ ContextUtils.getApplicationContext() .getApplicationInfo() .targetSdkVersion); @@ -139,17 +137,6 @@ } /** - * Checks if the application targets pre-release SDK U. This must be manually maintained as the - * SDK goes through finalization! Avoid depending on this if possible; this is only intended for - * WebView. - */ - public static boolean targetsAtLeastU() { - int target = ContextUtils.getApplicationContext().getApplicationInfo().targetSdkVersion; - - return target >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE; - } - - /** * Checks if the application targets pre-release SDK B. This must be manually maintained as the * SDK goes through finalization. */ @@ -344,7 +331,6 @@ String resourcesVersion, String installerPackageName, boolean isDebugApp, - boolean targetsAtleastU, int targetSdkVersion); } }
diff --git a/base/android/java/src/org/chromium/base/BinderCallsListener.java b/base/android/java/src/org/chromium/base/BinderCallsListener.java index 8349b17..55e6f881 100644 --- a/base/android/java/src/org/chromium/base/BinderCallsListener.java +++ b/base/android/java/src/org/chromium/base/BinderCallsListener.java
@@ -36,6 +36,10 @@ private static final String TAG = "BinderCallsListener"; private static final String PROXY_TRANSACT_LISTENER_CLASS_NAME = "android.os.Binder$ProxyTransactListener"; + private static final String NON_ANDROID_INTERFACE = "NON_ANDROID_INTERFACE"; + private static final String EMPTY_INTERFACE = "EMPTY_INTERFACE"; + private static final String NULL_INTERFACE = "NULL_INTERFACE"; + private static final String UNKNOWN_INTERFACE = "UNKNOWN_INTERFACE"; private static @Nullable BinderCallsListener sInstance; @@ -277,13 +281,31 @@ } private static class InterfaceInvocationHandler implements InvocationHandler { - private @Nullable String mCurrentInterfaceDescriptor; + private String mCurrentInterfaceDescriptor = EMPTY_INTERFACE; private @Nullable BiConsumer<String, String> mObserver; private int mCurrentTransactionId; private int mNumUploads; private long mTotalTimeSpentInBinderCallsMillis; private long mCurrentTransactionStartTimeMillis; + private static boolean isAndroidBinderInterface(String interfaceDescriptor) { + return (interfaceDescriptor.startsWith("com.android.") + && !interfaceDescriptor.startsWith("com.android.vending")) + || interfaceDescriptor.startsWith("android."); + } + + private String getInterfaceDescriptor(IBinder binder) { + try { + String interfaceDescriptor = binder.getInterfaceDescriptor(); + return interfaceDescriptor == null + ? NULL_INTERFACE + : (interfaceDescriptor.isEmpty() ? EMPTY_INTERFACE : interfaceDescriptor); + } catch (RemoteException e) { + Log.w(TAG, "Unable to read interface descriptor."); + } + return UNKNOWN_INTERFACE; + } + public long getTimeSpentInBinderCalls() { return mTotalTimeSpentInBinderCallsMillis; } @@ -296,28 +318,25 @@ IBinder binder = (IBinder) args[0]; mCurrentTransactionId++; mCurrentTransactionStartTimeMillis = SystemClock.uptimeMillis(); - try { - mCurrentInterfaceDescriptor = binder.getInterfaceDescriptor(); - } catch (RemoteException e) { + + mCurrentInterfaceDescriptor = getInterfaceDescriptor(binder); + // If we failed to read the interface descriptor, ignore it. + if (mCurrentInterfaceDescriptor.equals(UNKNOWN_INTERFACE)) { return null; } - if (mCurrentInterfaceDescriptor == null) return null; + boolean shouldTrackBinderIpc = + !sSlowBinderCallAllowList.contains(mCurrentInterfaceDescriptor); + if (!isAndroidBinderInterface(mCurrentInterfaceDescriptor)) { + mCurrentInterfaceDescriptor = NON_ANDROID_INTERFACE; + shouldTrackBinderIpc = false; + } TraceEvent.begin("BinderCallsListener.invoke", mCurrentInterfaceDescriptor); if (mObserver != null) { mObserver.accept("onTransactStarted", mCurrentInterfaceDescriptor); } - // There are some Binder calls that don't have an interface descriptor (e.g. - // https://crbug.com/407792383). Ignore these for now, but the empty string - // check here could be the source of discrepancies in the future. - boolean shouldTrackBinderIpc = - !(mCurrentInterfaceDescriptor.equals("") - || sSlowBinderCallAllowList.contains( - mCurrentInterfaceDescriptor)); - if (shouldTrackBinderIpc) { - return mCurrentTransactionId; - } - return null; + + return shouldTrackBinderIpc ? mCurrentTransactionId : null; case "onTransactEnded": TraceEvent.end("BinderCallsListener.invoke", mCurrentInterfaceDescriptor);
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java index c45bcdeb..4b0686db 100644 --- a/base/android/java/src/org/chromium/base/BuildInfo.java +++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -9,7 +9,6 @@ import android.content.pm.PackageManager; import android.content.pm.Signature; import android.os.Build; -import android.os.Build.VERSION_CODES; import android.os.Process; import org.jni_zero.CalledByNative; @@ -219,29 +218,6 @@ return isDebugAndroid() || isDebugApp(); } - /** - * Checks if the application targets the T SDK or later. - * @deprecated Chrome callers should just remove this test - Chrome targets T or later now. - * WebView callers should just inline the logic below to check the target level of the embedding - * App when necessary. - */ - @Deprecated - public static boolean targetsAtLeastT() { - int target = ContextUtils.getApplicationContext().getApplicationInfo().targetSdkVersion; - - // Now that the public SDK is upstreamed we can use the defined constant. - return target >= VERSION_CODES.TIRAMISU; - } - - /** - * Checks if the application targets pre-release SDK U. This must be manually maintained as the - * SDK goes through finalization! Avoid depending on this if possible; this is only intended for - * WebView. - */ - public static boolean targetsAtLeastU() { - return ApkInfo.targetsAtLeastU(); - } - @NullUnmarked public String getHostSigningCertSha256() { // We currently only make use of this certificate for calls from the storage access API
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc index a53ad8b..69ae041 100644 --- a/base/android/jni_array.cc +++ b/base/android/jni_array.cc
@@ -13,11 +13,12 @@ namespace base::android { -UNSAFE_BUFFER_USAGE ScopedJavaLocalRef<jbyteArray> -ToJavaByteArray(JNIEnv* env, const uint8_t* bytes, size_t len) { +ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(JNIEnv* env, + const uint8_t* bytes, + size_t len) { return ToJavaByteArray( env, - // SAFETY: The caller must provide a valid pointer and length. + // SAFETY: required from caller, see UNSAFE_BUFFER_USAGE in header. UNSAFE_BUFFERS(base::span(bytes, len))); }
diff --git a/base/android/jni_array.h b/base/android/jni_array.h index 64776a7..6c4f2b3 100644 --- a/base/android/jni_array.h +++ b/base/android/jni_array.h
@@ -34,6 +34,7 @@ } // Returns a new Java byte array converted from the given bytes array. +// PRECONDITIONS: `bytes` must point to `len` valid bytes. UNSAFE_BUFFER_USAGE BASE_EXPORT ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(JNIEnv* env, const uint8_t* bytes, size_t len);
diff --git a/base/containers/buffer_iterator.h b/base/containers/buffer_iterator.h index 61abd79..e8e27c0 100644 --- a/base/containers/buffer_iterator.h +++ b/base/containers/buffer_iterator.h
@@ -71,6 +71,7 @@ : buffer_(buffer), remaining_(buffer) {} // TODO(crbug.com/40284755): Move all callers to use spans and remove this. + // PRECONDITIONS: `data` must point to `size` contiguous B elements. UNSAFE_BUFFER_USAGE BufferIterator(B* data, size_t size) : BufferIterator( // TODO(crbug.com/40284755): Remove this constructor entirely,
diff --git a/base/containers/flat_tree.h b/base/containers/flat_tree.h index 937ed6b..9a98af6d 100644 --- a/base/containers/flat_tree.h +++ b/base/containers/flat_tree.h
@@ -249,6 +249,9 @@ template <class InputIterator> requires(std::input_iterator<InputIterator>) void insert(InputIterator first, InputIterator last); + + // PRECONDITIONS: `first` and `last` must be iterators into the + // same object, with `first` less than or equal to `last`. template <class InputIteratorPtr> UNSAFE_BUFFER_USAGE void insert(InputIteratorPtr* first, InputIteratorPtr* last); @@ -755,6 +758,8 @@ .first; } +// PRECONDITIONS: `first` and `last` must be iterators into the +// same object, with `first` less than or equal to `last`. template <class Key, class GetKeyFromValue, class KeyCompare, class Container> template <class InputIteratorPtr> UNSAFE_BUFFER_USAGE void
diff --git a/base/containers/span.h b/base/containers/span.h index 1dd00d71..1320eb00 100644 --- a/base/containers/span.h +++ b/base/containers/span.h
@@ -462,9 +462,8 @@ // Iterator + count. template <typename It> requires(internal::CompatibleIter<element_type, It>) - // SAFETY: `first` must point to the first of at least `count` contiguous - // valid elements, or the span will allow access to invalid elements, - // resulting in UB. + // PRECONDITIONS: `first` must point to the first of at least `count` + // contiguous valid elements. UNSAFE_BUFFER_USAGE constexpr explicit span(It first, StrictNumeric<size_type> count) : data_(to_address(first)) { @@ -480,9 +479,8 @@ requires(internal::CompatibleIter<element_type, It> && std::sized_sentinel_for<End, It> && !std::is_convertible_v<End, size_t>) - // SAFETY: `first` and `last` must be for the same allocation and all elements - // in the range [first, last) must be valid, or the span will allow access to - // invalid elements, resulting in UB. + // PRECONDITIONS: `first` and `last` must be for the same allocation and all + // elements in the range [first, last) must be valid. UNSAFE_BUFFER_USAGE constexpr explicit span(It first, End last) // SAFETY: The caller must guarantee that `first` and `last` point into // the same allocation. In this case, the extent will be the number of @@ -959,9 +957,8 @@ // Iterator + count. template <typename It> requires(internal::CompatibleIter<element_type, It>) - // SAFETY: `first` must point to the first of at least `count` contiguous - // valid elements, or the span will allow access to invalid elements, - // resulting in UB. + // PRECONDITIONS: `first` must point to the first of at least `count` + // contiguous valid elements. UNSAFE_BUFFER_USAGE constexpr span(It first, StrictNumeric<size_type> count) : data_(to_address(first)), size_(count) { // Non-zero `count` implies non-null `data_`. Use `SpanOrSize<T>` to @@ -974,9 +971,8 @@ requires(internal::CompatibleIter<element_type, It> && std::sized_sentinel_for<End, It> && !std::is_convertible_v<End, size_t>) - // SAFETY: `first` and `last` must be for the same allocation and all elements - // in the range [first, last) must be valid, or the span will allow access to - // invalid elements, resulting in UB. + // PRECONDITIONS: `first` and `last` must be for the same allocation and all + // elements in the range [first, last) must be valid. UNSAFE_BUFFER_USAGE constexpr span(It first, End last) // SAFETY: The caller must guarantee that `first` and `last` point into // the same allocation. In this case, `size_` will be the number of
diff --git a/base/files/file.h b/base/files/file.h index 9ca6817..020a33a4 100644 --- a/base/files/file.h +++ b/base/files/file.h
@@ -219,16 +219,22 @@ // is not intended for stream oriented files but instead for cases when the // normal expectation is that actually |size| bytes are read unless there is // an error. + // PRECONDITIONS: `size` must be non-negative and `data` must point to at + // least `size` valid bytes. UNSAFE_BUFFER_USAGE int Read(int64_t offset, char* data, int size); std::optional<size_t> Read(int64_t offset, base::span<uint8_t> data); // Same as above but without seek. + // PRECONDITIONS: `size` must be non-negative and `data` must point to at + // least `size` valid bytes. UNSAFE_BUFFER_USAGE int ReadAtCurrentPos(char* data, int size); std::optional<size_t> ReadAtCurrentPos(base::span<uint8_t> data); // Reads the given number of bytes (or until EOF is reached) starting with the // given offset, but does not make any effort to read all data on all // platforms. Returns the number of bytes read, or -1/std::nullopt on error. + // PRECONDITIONS: `size` must be non-negative and `data` must point to at + // least `size` valid bytes. UNSAFE_BUFFER_USAGE int ReadNoBestEffort(int64_t offset, char* data, int size); @@ -236,6 +242,8 @@ base::span<uint8_t> data); // Same as above but without seek. + // PRECONDITIONS: `size` must be non-negative and `data` must point to at + // least `size` valid bytes. UNSAFE_BUFFER_USAGE int ReadAtCurrentPosNoBestEffort(char* data, int size); std::optional<size_t> ReadAtCurrentPosNoBestEffort(base::span<uint8_t> data); @@ -251,16 +259,22 @@ // all platforms. |data| can be nullptr when |size| is 0. // Ignores the offset and writes to the end of the file if the file was opened // with FLAG_APPEND. + // PRECONDITIONS: `size` must be non-negative and `data` must point to at + // least `size` valid bytes. UNSAFE_BUFFER_USAGE int Write(int64_t offset, const char* data, int size); std::optional<size_t> Write(int64_t offset, base::span<const uint8_t> data); - // Save as above but without seek. + // Same as above but without seek. + // PRECONDITIONS: `size` must be non-negative and `data` must point to at + // least `size` valid bytes. UNSAFE_BUFFER_USAGE int WriteAtCurrentPos(const char* data, int size); std::optional<size_t> WriteAtCurrentPos(base::span<const uint8_t> data); - // Save as above but does not make any effort to write all data on all + // Same as above but does not make any effort to write all data on all // platforms. Returns the number of bytes written, or -1/std::nullopt // on error. + // PRECONDITIONS: `size` must be non-negative and `data` must point to at + // least `size` valid bytes. UNSAFE_BUFFER_USAGE int WriteAtCurrentPosNoBestEffort(const char* data, int size); std::optional<size_t> WriteAtCurrentPosNoBestEffort(
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java index 548a15a..4517e8f 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java
@@ -109,6 +109,19 @@ return mViewSpec; } + /** Returns a {@link ViewSpec} to declare a descandant of this ViewElement. */ + @SafeVarargs + public final ViewSpec<View> descendant(Matcher<View>... viewMatcher) { + return mViewSpec.descendant(viewMatcher); + } + + /** Returns a {@link ViewSpec} to declare a descandant of this ViewElement. */ + @SafeVarargs + public final <DescendantViewT extends View> ViewSpec<DescendantViewT> descendant( + Class<DescendantViewT> viewClass, Matcher<View>... viewMatcher) { + return mViewSpec.descendant(viewClass, viewMatcher); + } + /** Trigger an Espresso action on this View. */ public Transition.Trigger getPerformTrigger(ViewAction action) { return () -> {
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewSpec.java b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewSpec.java index ceedc38..0714fee 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewSpec.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewSpec.java
@@ -72,6 +72,15 @@ return viewSpec(allViewMatchers); } + /** Create a ViewSpec for a descendant of this ViewSpec that matches multiple Matchers<View>. */ + @SafeVarargs + public final <ChildViewT extends View> ViewSpec<ChildViewT> descendant( + Class<ChildViewT> viewClass, Matcher<View>... viewMatchers) { + Matcher<View>[] allViewMatchers = Arrays.copyOf(viewMatchers, viewMatchers.length + 1); + allViewMatchers[viewMatchers.length] = isDescendantOfA(mViewMatcher); + return viewSpec(viewClass, allViewMatchers); + } + /** Creates a ViewSpec that matches this ViewSpec _and_ another Matcher<View>. */ public final ViewSpec<View> and(Matcher<View> viewMatcher) { return viewSpec(viewMatcher, mViewMatcher); @@ -93,7 +102,17 @@ // states by their description. Espresso Matcher descriptions are not stable: the integer // resource ids are translated when a View is provided. See examples in // https://crbug.com/41494895#comment7. - mMatcherDescription = StringDescription.toString(mViewMatcher); + mMatcherDescription = removeResolvedIds(StringDescription.toString(mViewMatcher)); + } + + private static String removeResolvedIds(String matcherDescription) { + // Replace: + // "VE/view.getId() is <2130773232/org.chromium.chrome.tests:id/hub_toolbar>" + // with: + // "VE/view.getId() is <2130773232>" + + // Generated ids have at least 8 digits, since they are >= 0xffffff (16777215) + return matcherDescription.replaceAll("<([0-9]{8,})/.*>", "<$1>"); } /**
diff --git a/base/test/android/junit/src/org/chromium/base/test/ShadowBuildInfo.java b/base/test/android/junit/src/org/chromium/base/test/ShadowBuildInfo.java deleted file mode 100644 index 93848c3..0000000 --- a/base/test/android/junit/src/org/chromium/base/test/ShadowBuildInfo.java +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.annotation.Resetter; - -import org.chromium.base.BuildInfo; - -/** Shadow class of {@link BuildInfo} */ -@Implements(BuildInfo.class) -public class ShadowBuildInfo { - private static boolean sTargetsAtLeastT; - - /** Rests the changes made to static state. */ - @Resetter - public static void reset() { - sTargetsAtLeastT = false; - } - - /** Whether the current build is targeting at least T. */ - @Implementation - public static boolean targetsAtLeastT() { - return sTargetsAtLeastT; - } - - /** Sets whether the current build is targeting at least T. */ - public static void setTargetsAtLeastT(boolean targetsAtLeastT) { - sTargetsAtLeastT = targetsAtLeastT; - } -}
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc index 871e8ff3..06571421 100644 --- a/base/test/launcher/unit_test_launcher.cc +++ b/base/test/launcher/unit_test_launcher.cc
@@ -282,7 +282,7 @@ #if BUILDFLAG(IS_WIN) -// Safety: as is normal in command lines, argc and argv must correspond +// PRECONDITIONS: As is normal in command lines, argc and argv must correspond // to one another. Otherwise there will be out-of-bounds accesses. UNSAFE_BUFFER_USAGE void InitGoogleTestWChar(int* argc, wchar_t** argv) { testing::InitGoogleTest(argc, argv);
diff --git a/base/time/time.h b/base/time/time.h index 40a5589..e301dc8 100644 --- a/base/time/time.h +++ b/base/time/time.h
@@ -69,7 +69,6 @@ #include <concepts> #include <iosfwd> #include <limits> -#include <ostream> #include <type_traits> #include "base/base_export.h" @@ -103,6 +102,8 @@ #endif #if BUILDFLAG(IS_WIN) +#include <string> + #include "base/gtest_prod_util.h" #include "base/win/windows_types.h"
diff --git a/base/tools_sanity_unittest.cc b/base/tools_sanity_unittest.cc index 1500a6f..2b3649a 100644 --- a/base/tools_sanity_unittest.cc +++ b/base/tools_sanity_unittest.cc
@@ -360,7 +360,9 @@ #if defined(THREAD_SANITIZER) // A data race detector should report an error in this test. -TEST(ToolsSanityTest, DataRace) { +// TODO(crbug.com/416191043): Re-enable when symbol_level on sanitizer bots +// can safely be raised again. +TEST(ToolsSanityTest, DISABLED_DataRace) { // The suppression regexp must match that in base/debug/tsan_suppressions.cc. EXPECT_DEATH(DataRace(), "1 race:base/tools_sanity_unittest.cc"); }
diff --git a/build/android/apk_operations.pydeps b/build/android/apk_operations.pydeps index cde63ff..5455106a 100644 --- a/build/android/apk_operations.pydeps +++ b/build/android/apk_operations.pydeps
@@ -48,7 +48,6 @@ ../../third_party/catapult/devil/devil/devil_env.py ../../third_party/catapult/devil/devil/utils/__init__.py ../../third_party/catapult/devil/devil/utils/cmd_helper.py -../../third_party/catapult/devil/devil/utils/host_utils.py ../../third_party/catapult/devil/devil/utils/lazy/__init__.py ../../third_party/catapult/devil/devil/utils/lazy/weak_constant.py ../../third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/build/android/test_runner.pydeps b/build/android/test_runner.pydeps index 523ae642..f87ec1b 100644 --- a/build/android/test_runner.pydeps +++ b/build/android/test_runner.pydeps
@@ -78,7 +78,6 @@ ../../third_party/catapult/devil/devil/utils/__init__.py ../../third_party/catapult/devil/devil/utils/cmd_helper.py ../../third_party/catapult/devil/devil/utils/file_utils.py -../../third_party/catapult/devil/devil/utils/host_utils.py ../../third_party/catapult/devil/devil/utils/lazy/__init__.py ../../third_party/catapult/devil/devil/utils/lazy/weak_constant.py ../../third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 2fc8d823..708c204 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -512,7 +512,13 @@ # Linux-specific compiler flags setup. # ------------------------------------ if (use_icf && (!is_apple || use_lld)) { - ldflags += [ "-Wl,--icf=all" ] + if (is_fuchsia) { + # TODO(crbug.com/415810137): A temporary workaround to avoid crashing + # blink on fuchsia. + ldflags += [ "-Wl,--icf=safe" ] + } else { + ldflags += [ "-Wl,--icf=all" ] + } } if (is_linux || is_chromeos) { @@ -1727,7 +1733,6 @@ rebase_path(clang_warning_suppression_file, root_build_dir) inputs = [ clang_warning_suppression_file ] cflags = [ - "-Xclang", "--warning-suppression-mappings=" + from_build_root, ] }
diff --git a/build/config/warning_suppression.txt b/build/config/warning_suppression.txt index 4f78ea8..1a1b2cdf 100644 --- a/build/config/warning_suppression.txt +++ b/build/config/warning_suppression.txt
@@ -2,8 +2,36 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# Warning suppression mappings are listed here on a per-warning basis. -# Upstream docs: https://clang.llvm.org/docs/WarningSuppressionMappings.html -# We'll put the policy here too when it's written. -# Don't use this file until the policy is written. -# See crbug.com/404297941 for more information. +# This file is used to suppress warnings based on the file they originate from, +# as opposed to disabling warnings via -Wno flags which apply to all the files +# involved in each compilation. For more information, see +# https://clang.llvm.org/docs/WarningSuppressionMappings.html +# For background information on their use in chromium, see crbug.com/404297941 + +# Warning Suppression Policy: updates to this file should be tightly controlled, +# for reasons discussed in crbug.com/404297941. In particular: +# +# 1. This file should never grow (as measured by the number of files suppressed) +# except when a new warning is enabled. +# 2. This file should only be used to opt out whole directories, never +# individual files. +# 3. This file should be used as a last resort; if it's possible to fix the warning or suppress +# it without using the file, do so. +# 1. For first-party code, just fix it directly, or use `#pragma GCC diagnostic ignored`. +# 2. For third-party code, first attempt to fix it upstream. +# 3. If that's not possible, attempt to suppress the warning using `-Wno` flags in a gn file. +# 4. All entries should have a path to eventually be removed. +# +# In practice, rules (3) and (4) mean that the only accepted use case for this file is to +# speed up rolls or enable a warning slightly sooner, for cases where an upstream fix has been +# proposed but is likely to take a long time to get merged and rolled into chromium. +# +# We may make an exception to the policy for extremely high-value warnings that backslide a lot +# (such as unsafe buffers), but this is expected to be rare. + +# Formatting note: Don't put comments on the same line as a glob pattern! Clang +# will get confused and the warning won't be suppressed. + +[unnecessary-virtual-specifier] +# Can be removed when https://github.com/google/nearby/pull/3392 is merged and rolled +src:*/third_party/nearby/* \ No newline at end of file
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index 5445093..5e67c8d 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -27.20250501.100.1 +28.20250508.101.1
diff --git a/cc/base/features.cc b/cc/base/features.cc index 11157a84..fb35620 100644 --- a/cc/base/features.cc +++ b/cc/base/features.cc
@@ -106,10 +106,6 @@ "EvictionThrottlesDraw", base::FEATURE_ENABLED_BY_DEFAULT); -BASE_FEATURE(kAdjustFastMainThreadThreshold, - "AdjustFastMainThreadThreshold", - base::FEATURE_DISABLED_BY_DEFAULT); - BASE_FEATURE(kClearCanvasResourcesInBackground, "ClearCanvasResourcesInBackground", base::FEATURE_DISABLED_BY_DEFAULT); @@ -137,10 +133,6 @@ "PreserveDiscardableImageMapQuality", base::FEATURE_ENABLED_BY_DEFAULT); -BASE_FEATURE(kWarmUpCompositor, - "WarmUpCompositor", - base::FEATURE_ENABLED_BY_DEFAULT); - BASE_FEATURE(kCCSlimming, "CCSlimming", base::FEATURE_ENABLED_BY_DEFAULT); bool IsCCSlimmingEnabled() {
diff --git a/cc/base/features.h b/cc/base/features.h index 31520bd..4e96f70 100644 --- a/cc/base/features.h +++ b/cc/base/features.h
@@ -73,11 +73,6 @@ // viz::Surface. CC_BASE_EXPORT BASE_DECLARE_FEATURE(kEvictionThrottlesDraw); -// Permits adjusting the threshold we use for determining if main thread updates -// are fast. Specifically, via a scalar on the range [0,1] that we multiply with -// the existing threshold. I.e., |new_threshold| = |scalar| * |old_threshold|. -CC_BASE_EXPORT BASE_DECLARE_FEATURE(kAdjustFastMainThreadThreshold); - // When a LayerTreeHostImpl is not visible, clear its transferable resources // that haven't been imported into viz. CC_BASE_EXPORT BASE_DECLARE_FEATURE(kClearCanvasResourcesInBackground); @@ -111,12 +106,6 @@ // image map. CC_BASE_EXPORT BASE_DECLARE_FEATURE(kPreserveDiscardableImageMapQuality); -// When enabled, the renderer asks the compositor to request warming up and -// create FrameSink speculatively even if invisible. Currently, this is intended -// to be used when prerender initial navigation is happening in background. -// Please see crbug.com/41496019 for more details. -CC_BASE_EXPORT BASE_DECLARE_FEATURE(kWarmUpCompositor); - // Kill switch for a bunch of optimizations for cc-slimming project. // Please see crbug.com/335450599 for more details. CC_BASE_EXPORT BASE_DECLARE_FEATURE(kCCSlimming);
diff --git a/cc/mojo_embedder/async_layer_tree_frame_sink.cc b/cc/mojo_embedder/async_layer_tree_frame_sink.cc index 2703317..c3b6661 100644 --- a/cc/mojo_embedder/async_layer_tree_frame_sink.cc +++ b/cc/mojo_embedder/async_layer_tree_frame_sink.cc
@@ -285,13 +285,7 @@ compositor_frame_sink_ptr_->SubmitCompositorFrame( local_surface_id_, std::move(frame), std::move(hit_test_region_list), 0); - if (base::FeatureList::IsEnabled( - features::kExportFrameTimingAfterFrameDone)) { - for (const auto& pair : timing_details_) { - client_->DidPresentCompositorFrame(pair.first, pair.second); - } - timing_details_.clear(); - } + ExportFrameTiming(); num_did_not_produce_frame_since_last_submit_ = 0; if (use_internal_begin_frame_source_) { @@ -320,13 +314,8 @@ data->set_surface_frame_trace_id(ack.trace_id); }); - if (base::FeatureList::IsEnabled( - features::kExportFrameTimingAfterFrameDone)) { - for (const auto& pair : timing_details_) { - client_->DidPresentCompositorFrame(pair.first, pair.second); - } - timing_details_.clear(); - } + ExportFrameTiming(); + if (use_internal_begin_frame_source_) { if (ack.preferred_frame_interval) { const viz::BeginFrameArgs last_args = @@ -352,6 +341,16 @@ } } +void AsyncLayerTreeFrameSink::ExportFrameTiming() { + if (base::FeatureList::IsEnabled( + features::kExportFrameTimingAfterFrameDone)) { + for (const auto& pair : timing_details_) { + client_->DidPresentCompositorFrame(pair.first, pair.second); + } + timing_details_.clear(); + } +} + std::unique_ptr<LayerContext> AsyncLayerTreeFrameSink::CreateLayerContext( LayerTreeHostImpl& host_impl) { CHECK(compositor_frame_sink_ptr_);
diff --git a/cc/mojo_embedder/async_layer_tree_frame_sink.h b/cc/mojo_embedder/async_layer_tree_frame_sink.h index a7541f6f..73fc705 100644 --- a/cc/mojo_embedder/async_layer_tree_frame_sink.h +++ b/cc/mojo_embedder/async_layer_tree_frame_sink.h
@@ -139,6 +139,7 @@ bool hit_test_data_changed) override; void DidNotProduceFrame(const viz::BeginFrameAck& ack, FrameSkippedReason reason) override; + void ExportFrameTiming() override; std::unique_ptr<LayerContext> CreateLayerContext( LayerTreeHostImpl& host_impl) override;
diff --git a/cc/mojo_embedder/viz_layer_context.cc b/cc/mojo_embedder/viz_layer_context.cc index 7fad3bc..a4bfc34 100644 --- a/cc/mojo_embedder/viz_layer_context.cc +++ b/cc/mojo_embedder/viz_layer_context.cc
@@ -913,6 +913,8 @@ update->begin_frame_args = tree.CurrentBeginFrameArgs(); update->source_frame_number = tree.source_frame_number(); update->trace_id = tree.trace_id().value(); + update->primary_main_frame_item_sequence_number = + tree.primary_main_frame_item_sequence_number(); update->page_scale_factor = tree.page_scale_factor()->Current(true); update->min_page_scale_factor = tree.min_page_scale_factor(); update->max_page_scale_factor = tree.max_page_scale_factor();
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index 860e1cf..b03e0d3 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc
@@ -35,21 +35,6 @@ // for message latency and kernel scheduling variability. const base::TimeDelta kDeadlineFudgeFactor = base::Microseconds(1000); -// This adjustment is applied by multiplying with the previous, begin-main-frame -// to activate threshold. For example, if we want to consider a page fast if it -// it takes half the threshold, we would return 0.5. Naturally, this function -// will return values in the range [0, 1]. -double FastMainThreadThresholdAdjustment() { - if (base::FeatureList::IsEnabled(features::kAdjustFastMainThreadThreshold)) { - double result = base::GetFieldTrialParamByFeatureAsDouble( - features::kAdjustFastMainThreadThreshold, "Scalar", -1.0); - if (result >= 0.0 && result <= 1.0) { - return result; - } - } - return 1.0; -} - } // namespace Scheduler::Scheduler( @@ -114,7 +99,6 @@ } void Scheduler::SetShouldWarmUp() { - CHECK(base::FeatureList::IsEnabled(features::kWarmUpCompositor)); state_machine_.SetShouldWarmUp(); ProcessScheduledActions(); } @@ -547,10 +531,8 @@ base::TimeDelta bmf_to_activate_estimate_critical = compositor_timing_history_ ->BeginMainFrameQueueToActivateCriticalEstimate(); - base::TimeDelta fast_main_thread_threshold = - bmf_to_activate_threshold * FastMainThreadThresholdAdjustment(); state_machine_.SetCriticalBeginMainFrameToActivateIsFast( - bmf_to_activate_estimate_critical < fast_main_thread_threshold); + bmf_to_activate_estimate_critical < bmf_to_activate_threshold); // Update the BeginMainFrame args now that we know whether the main // thread will be on the critical path or not.
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc index 9c31e8e..ccb5f6f 100644 --- a/cc/scheduler/scheduler_state_machine.cc +++ b/cc/scheduler/scheduler_state_machine.cc
@@ -1579,7 +1579,6 @@ } void SchedulerStateMachine::SetShouldWarmUp() { - CHECK(base::FeatureList::IsEnabled(features::kWarmUpCompositor)); should_warm_up_ = true; }
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h index 40ef1b6..d7780929 100644 --- a/cc/scheduler/scheduler_state_machine.h +++ b/cc/scheduler/scheduler_state_machine.h
@@ -219,10 +219,7 @@ bool visible() const { return visible_; } // Indicates that warming up is requested to create a new LayerTreeFrameSink - // even if the LayerTreeHost is invisible. This is an experimental function - // and only used if `kWarmUpCompositor` is enabled. Currently, this will be - // requested only from prerendered pages. Please see crbug.com/40240492 for - // more details. + // even if the LayerTreeHost is invisible. void SetShouldWarmUp(); void SetBeginFrameSourcePaused(bool paused);
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc index 2cf449d7..da91b81 100644 --- a/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -3632,20 +3632,10 @@ ScrollingSchedulerStateMachineTest, testing::Bool()); -class WarmUpCompositorSchedulerStateMachineTest : public testing::Test { - public: - WarmUpCompositorSchedulerStateMachineTest() { - scoped_feature_list_.InitAndEnableFeature(features::kWarmUpCompositor); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - // Tests that `SetShouldWarmUp()` will start initial `LayerTreeFrameSink` // creation even if invisible. -TEST_F(WarmUpCompositorSchedulerStateMachineTest, - SetShouldWarmUpWillStartLayerTreeFrameSinkCreation) { +TEST(SchedulerStateMachineTest, + SetShouldWarmUpWillStartLayerTreeFrameSinkCreation) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetVisible(false);
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 8b5cb9a..54e64b9b 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc
@@ -4178,20 +4178,9 @@ scheduler_->state_machine().MainFrameThrottledInterval().is_zero()); } -class WarmUpCompositorSchedulerTest : public SchedulerTest { - public: - WarmUpCompositorSchedulerTest() { - scoped_feature_list_.InitAndEnableFeature(features::kWarmUpCompositor); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - // Tests that `SetShouldWarmUp()` will start initial `LayerTreeFrameSink` // creation even if invisible. -TEST_F(WarmUpCompositorSchedulerTest, - SetShouldWarmUpWillStartLayerTreeFrameSinkCreation) { +TEST_F(SchedulerTest, SetShouldWarmUpWillStartLayerTreeFrameSinkCreation) { SetUpSchedulerWithNoLayerTreeFrameSink(EXTERNAL_BFS); scheduler_->SetVisible(false);
diff --git a/cc/trees/layer_tree_frame_sink.h b/cc/trees/layer_tree_frame_sink.h index 722be481..27f255d 100644 --- a/cc/trees/layer_tree_frame_sink.h +++ b/cc/trees/layer_tree_frame_sink.h
@@ -138,6 +138,8 @@ virtual void DidNotProduceFrame(const viz::BeginFrameAck& ack, FrameSkippedReason reason) = 0; + virtual void ExportFrameTiming() {} + // Creates a new LayerContext through which the client can control layers in // a GPU-side display tree. virtual std::unique_ptr<LayerContext> CreateLayerContext(
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index 9e597544..8487d71b 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -852,16 +852,12 @@ void LayerTreeHost::SetShouldWarmUp() { DCHECK(IsMainThread()); - CHECK(base::FeatureList::IsEnabled(features::kWarmUpCompositor)); should_warm_up_ = true; proxy_->SetShouldWarmUp(); } bool LayerTreeHost::ShouldWarmUp() const { DCHECK(IsMainThread()); - if (!base::FeatureList::IsEnabled(features::kWarmUpCompositor)) { - return false; - } return should_warm_up_; }
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h index a10f549..600add9 100644 --- a/cc/trees/layer_tree_host.h +++ b/cc/trees/layer_tree_host.h
@@ -258,8 +258,8 @@ // Visibility and LayerTreeFrameSink ------------------------------- // Sets or gets if the LayerTreeHost is visible. When not visible it will: - // - Not request a new LayerTreeFrameSink from the client (except - // `kWarmUpCompositor` is enabled and warm-up is explicitly requested). + // - Not request a new LayerTreeFrameSink from the client (except the warm-up + // is explicitly requested by `SetShouldWarmUp`). // - Stop submitting frames to the display compositor. // - Stop producing main frames and committing them. // The LayerTreeHost is not visible when first created, so this must be called @@ -268,10 +268,7 @@ bool IsVisible() const; // Indicates that warm-up is requested to create a new LayerTreeFrameSink - // even if the LayerTreeHost is invisible. This is an experimental function - // and only used if `kWarmUpCompositor` is enabled. Currently, this will be - // requested only from prerendered pages. Please see crbug.com/41496019 for - // more details. + // even if the LayerTreeHost is invisible. void SetShouldWarmUp(); bool ShouldWarmUp() const;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 435c8b1..31da38d 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -2907,6 +2907,8 @@ if (settings_.TreesInVizInClientProcess()) { UpdateDisplayTree(*frame); + layer_tree_frame_sink_->ExportFrameTiming(); + // For the display compositor we should have already submitted at display // Immediately queue a DidReceiveCompositorFrameAck. GetTaskRunner()->PostTask( @@ -3239,7 +3241,11 @@ // The swap-promises should not change the frame-token. DCHECK_EQ(metadata.frame_token, *next_frame_token_); - if (render_frame_metadata_observer_) { + // In TreesInViz mode in viz, we need to compute + // |last_draw_render_frame_metadata_| because it impacts HasDamage() + // computation. + if (render_frame_metadata_observer_ || + settings_.trees_in_viz_in_viz_process) { last_draw_render_frame_metadata_ = MakeRenderFrameMetadata(frame); if (gfx::DelegatedInkMetadata* ink_metadata = metadata.delegated_ink_metadata.get()) { @@ -3257,9 +3263,12 @@ last_draw_render_frame_metadata_->new_vertical_scroll_direction; } - render_frame_metadata_observer_->OnRenderFrameSubmission( - *last_draw_render_frame_metadata_, &metadata, - active_tree()->TakeForceSendMetadataRequest()); + // TODO(zmo): Consider plumbing the observer to viz as well. + if (render_frame_metadata_observer_) { + render_frame_metadata_observer_->OnRenderFrameSubmission( + *last_draw_render_frame_metadata_, &metadata, + active_tree()->TakeForceSendMetadataRequest()); + } } if (!CommitsToActiveTree() && !metadata.latency_info.empty()) {
diff --git a/chrome/VERSION b/chrome/VERSION index a063e48..f80e5b3 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=138 MINOR=0 -BUILD=7168 +BUILD=7169 PATCH=0
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 5536e34..739d6306 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -480,6 +480,7 @@ "java/src/org/chromium/chrome/browser/customtabs/content/TabCreationMode.java", "java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java", "java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandler.java", + "java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandlerHistogram.java", "java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchParams.java", "java/src/org/chromium/chrome/browser/customtabs/features/CustomTabDimensionUtils.java", "java/src/org/chromium/chrome/browser/customtabs/features/CustomTabNavigationBarController.java",
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn index f83a008..9ed9df2 100644 --- a/chrome/android/features/tab_ui/BUILD.gn +++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -73,6 +73,7 @@ "java/res/layout/archived_tabs_dialog.xml", "java/res/layout/archived_tabs_message_card_view.xml", "java/res/layout/bottom_tab_strip_toolbar.xml", + "java/res/layout/color_picker_icon_button_layout.xml", "java/res/layout/color_picker_item.xml", "java/res/layout/custom_message_card_item.xml", "java/res/layout/dynamic_bottom_tab_strip_toolbar.xml",
diff --git a/chrome/android/features/tab_ui/java/res/layout/color_picker_icon_button_layout.xml b/chrome/android/features/tab_ui/java/res/layout/color_picker_icon_button_layout.xml new file mode 100644 index 0000000..77bff508 --- /dev/null +++ b/chrome/android/features/tab_ui/java/res/layout/color_picker_icon_button_layout.xml
@@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +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. +--> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + <com.google.android.material.button.MaterialButton + android:id="@+id/color_picker_icon" + style="?attr/colorPickerButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:checkable="true" /> +</FrameLayout> \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/values/dimens.xml b/chrome/android/features/tab_ui/java/res/values/dimens.xml index a33e5bf8..862ef07 100644 --- a/chrome/android/features/tab_ui/java/res/values/dimens.xml +++ b/chrome/android/features/tab_ui/java/res/values/dimens.xml
@@ -95,6 +95,9 @@ <dimen name="tab_group_color_icon_item_radius">9dp</dimen> <dimen name="tab_group_color_picker_popup_padding">10dp</dimen> <dimen name="tab_group_visual_data_dialog_margin_padding">3dp</dimen> + <dimen name="color_picker_button_stroke_inset">11dp</dimen> + <dimen name="color_picker_button_stroke_width">2dp</dimen> + <dimen name="color_picker_button_stroke_radius">9dp</dimen> <!-- Dimens for tab card label --> <dimen name="tab_card_label_icon_size">16dp</dimen>
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java index a828c32..f0b5f3b 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java
@@ -63,6 +63,7 @@ import org.chromium.chrome.browser.tasks.tab_management.TabListMediator.TabActionListener; import org.chromium.chrome.browser.tasks.tab_management.TabProperties.TabActionState; import org.chromium.chrome.browser.tasks.tab_management.TabProperties.UiType; +import org.chromium.chrome.browser.theme.SurfaceColorUpdateUtils; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeControllerFactory; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeUtils; @@ -431,6 +432,12 @@ mShadowView.init( mActivity.getColor(R.color.toolbar_shadow_color), FadingShadow.POSITION_BOTTOM); + // TODO(crbug.com/410040707): Set the color in the layout file. + getCloseAllTabsButtonContainer() + .setBackgroundColor( + SurfaceColorUpdateUtils.getGridTabSwitcherBackgroundColor( + mActivity, /* isIncognito= */ false)); + // Initialize the confirmation dialog for when the last archived tab is removed. mActionConfirmationDialog = new ActionConfirmationDialog(mActivity, mModalDialogManager);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ColorPickerItemViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ColorPickerItemViewBinder.java index 7ef8e551..ad6184f 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ColorPickerItemViewBinder.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ColorPickerItemViewBinder.java
@@ -9,23 +9,29 @@ import static org.chromium.chrome.browser.tasks.tab_management.ColorPickerItemProperties.IS_INCOGNITO; import static org.chromium.chrome.browser.tasks.tab_management.ColorPickerItemProperties.IS_SELECTED; import static org.chromium.chrome.browser.tasks.tab_management.ColorPickerItemProperties.ON_CLICK_LISTENER; +import static org.chromium.chrome.browser.tasks.tab_management.TabUiThemeProvider.getColorPickerDialogBackgroundColor; import android.content.Context; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.LayerDrawable; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewOverlay; +import android.widget.Button; import android.widget.ImageView; import androidx.annotation.ColorInt; import androidx.annotation.StringRes; -import androidx.core.content.ContextCompat; +import com.google.android.material.button.MaterialButton; + +import org.chromium.chrome.browser.theme.ThemeModuleUtils; import org.chromium.chrome.tab_ui.R; -import org.chromium.components.browser_ui.styles.SemanticColorUtils; import org.chromium.components.tab_groups.TabGroupColorPickerUtils; +import org.chromium.ui.drawable.BorderDrawable; import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; @@ -44,15 +50,20 @@ public static final int INNER_LAYER = 2; static View createItemView(Context context) { - return LayoutInflater.from(context) - .inflate(R.layout.color_picker_item, /* root= */ null, false); + int layoutToInflate = + isAndroidThemeModuleEnabled() + ? R.layout.color_picker_icon_button_layout + : R.layout.color_picker_item; + + return LayoutInflater.from(context).inflate(layoutToInflate, /* root= */ null, false); } static void bind(PropertyModel model, View view, PropertyKey propertyKey) { if (propertyKey == COLOR_ID) { setColorOnColorIcon(model, view); } else if (propertyKey == ON_CLICK_LISTENER) { - view.setOnClickListener((v) -> model.get(ON_CLICK_LISTENER).run()); + view.findViewById(R.id.color_picker_icon) + .setOnClickListener((v) -> model.get(ON_CLICK_LISTENER).run()); } else if (propertyKey == IS_SELECTED) { refreshColorIconOnSelection(model, view); setAccessibilityContent(view, model.get(IS_SELECTED), model.get(COLOR_ID)); @@ -66,33 +77,72 @@ int colorId = model.get(COLOR_ID); final @ColorInt int color = getColor(context, colorPickerType, colorId, isIncognito); - final @ColorInt int selectionBackgroundColor = - isIncognito - ? ContextCompat.getColor( - context, R.color.tab_group_color_picker_selection_bg_incognito) - : SemanticColorUtils.getDialogBgColor(context); // Update the color icon with the indicated color id. - ImageView colorIcon = view.findViewById(R.id.color_picker_icon); - LayerDrawable layerDrawable = (LayerDrawable) colorIcon.getBackground(); - ((GradientDrawable) layerDrawable.getDrawable(OUTER_LAYER)).setColor(color); - ((GradientDrawable) layerDrawable.getDrawable(SELECTION_LAYER)) - .setColor(selectionBackgroundColor); - ((GradientDrawable) layerDrawable.getDrawable(INNER_LAYER)).setColor(color); + if (isAndroidThemeModuleEnabled()) { + Button colorIcon = view.findViewById(R.id.color_picker_icon); + colorIcon.setBackgroundTintList(ColorStateList.valueOf(color)); + } else { + final @ColorInt int selectionBackgroundColor = + getColorPickerDialogBackgroundColor(context, isIncognito); + + ImageView colorIcon = view.findViewById(R.id.color_picker_icon); + LayerDrawable layerDrawable = (LayerDrawable) colorIcon.getBackground(); + ((GradientDrawable) layerDrawable.getDrawable(OUTER_LAYER)).setColor(color); + ((GradientDrawable) layerDrawable.getDrawable(SELECTION_LAYER)) + .setColor(selectionBackgroundColor); + ((GradientDrawable) layerDrawable.getDrawable(INNER_LAYER)).setColor(color); + } } private static void refreshColorIconOnSelection(PropertyModel model, View view) { - ImageView colorIcon = view.findViewById(R.id.color_picker_icon); - LayerDrawable layerDrawable = (LayerDrawable) colorIcon.getBackground(); + final View colorIcon = view.findViewById(R.id.color_picker_icon); - // Toggle the selected layer opaqueness based on the user click action. - int alpha = model.get(IS_SELECTED) ? 0xFF : 0; - layerDrawable.getDrawable(SELECTION_LAYER).setAlpha(alpha); + if (isAndroidThemeModuleEnabled()) { + ((MaterialButton) colorIcon).setChecked(model.get(IS_SELECTED)); + colorIcon.setEnabled(!model.get(IS_SELECTED)); + + ViewOverlay overlay = colorIcon.getOverlay(); + + if (model.get(IS_SELECTED)) { + BorderDrawable borderDrawable = getBorderDrawable(model, view); + overlay.add(borderDrawable); + } else { + overlay.clear(); + } + } else { + LayerDrawable layerDrawable = (LayerDrawable) colorIcon.getBackground(); + + // Toggle the selected layer opaqueness based on the user click action. + int alpha = model.get(IS_SELECTED) ? 0xFF : 0; + layerDrawable.getDrawable(SELECTION_LAYER).setAlpha(alpha); + } // Refresh the color item view. colorIcon.invalidate(); } + private static BorderDrawable getBorderDrawable(PropertyModel model, View view) { + Resources res = view.getResources(); + + int borderWidthPx = res.getDimensionPixelSize(R.dimen.color_picker_button_stroke_width); + int insetPx = res.getDimensionPixelSize(R.dimen.color_picker_button_stroke_inset); + int borderRadiusPx = res.getDimensionPixelSize(R.dimen.color_picker_button_stroke_radius); + int touchTargetSize = res.getDimensionPixelSize(R.dimen.min_touch_target_size); + + BorderDrawable borderDrawable = + new BorderDrawable( + borderWidthPx, + insetPx, + getColorPickerDialogBackgroundColor( + view.getContext(), model.get(IS_INCOGNITO)), + borderRadiusPx); + + // Set the bounds of the drawable to match the color button view. + borderDrawable.setBounds(0, 0, touchTargetSize, touchTargetSize); + return borderDrawable; + } + private static @ColorInt int getColor( Context context, @ColorPickerType int colorPickerType, @@ -107,7 +157,7 @@ } private static void setAccessibilityContent(View view, boolean isSelected, int colorId) { - ImageView colorIcon = view.findViewById(R.id.color_picker_icon); + View colorIcon = view.findViewById(R.id.color_picker_icon); Resources res = view.getContext().getResources(); final @StringRes int colorDescRes = @@ -122,4 +172,8 @@ String contentDescription = res.getString(selectedFormatDescRes, colorDesc); colorIcon.setContentDescription(contentDescription); } + + private static boolean isAndroidThemeModuleEnabled() { + return ThemeModuleUtils.isEnabled(); + } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java index 1153127d..c85db0f 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
@@ -1071,8 +1071,7 @@ RecordUserAction.record("TabGridDialogMenu.ManageSharing"); mDataSharingTabManager.createOrManageFlow( mActivity, - /* syncId= */ null, - new LocalTabGroupId(tabGroupId), + EitherGroupId.createLocalId(new LocalTabGroupId(tabGroupId)), CollaborationServiceShareOrManageEntryPoint.ANDROID_TAB_GRID_DIALOG_MANAGE, /* createGroupFinishedCallback= */ null); } else if (menuId == R.id.recent_activity) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java index fb099d5..27a8227 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
@@ -565,4 +565,19 @@ ? SemanticColorUtils.getColorSurfaceBright(context) : SemanticColorUtils.getColorSurfaceContainerLow(context); } + + /** + * Returns the color used by dialogs as background. + * + * @param context {@link Context} used to retrieve color. + * @param isIncognito Whether the color is used for incognito mode. + * @return The color for the dialog background. + */ + public static @ColorInt int getColorPickerDialogBackgroundColor( + Context context, boolean isIncognito) { + return isIncognito + ? ContextCompat.getColor( + context, R.color.tab_group_color_picker_selection_bg_incognito) + : SemanticColorUtils.getDialogBgColor(context); + } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiUtils.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiUtils.java index 7bd5868..c5a5ee16 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiUtils.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiUtils.java
@@ -44,6 +44,7 @@ import org.chromium.components.signin.base.CoreAccountInfo; import org.chromium.components.signin.identitymanager.ConsentLevel; import org.chromium.components.signin.identitymanager.IdentityManager; +import org.chromium.components.tab_group_sync.EitherId.EitherGroupId; import org.chromium.components.tab_group_sync.LocalTabGroupId; import org.chromium.components.tab_group_sync.SavedTabGroup; import org.chromium.components.tab_group_sync.TabGroupSyncService; @@ -322,7 +323,7 @@ LocalTabGroupId localTabGroupId = TabGroupSyncUtils.getLocalTabGroupId(tab); dataSharingTabManager.createOrManageFlow( - activity, /* syncId= */ null, localTabGroupId, entry, (ignored) -> {}); + activity, EitherGroupId.createLocalId(localTabGroupId), entry, (ignored) -> {}); } /**
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java index a5ed56a3..88878606 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java
@@ -209,7 +209,6 @@ @Test @MediumTest @Feature({"RenderTest"}) - @DisabledTest(message = "Flaky due to NTP thumbnails not being consistently loaded") public void testRenderGrid_3NativeTabs() throws IOException { ChromeTabbedActivity cta = mCtaTestRule.getActivity(); RegularNewTabPageStation pageStation =
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorUnitTest.java index d16a8bdc..c61dd6f3 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorUnitTest.java
@@ -19,6 +19,7 @@ import static org.mockito.Mockito.when; import android.app.Activity; +import android.graphics.drawable.ColorDrawable; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -72,6 +73,7 @@ import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.components.browser_ui.edge_to_edge.EdgeToEdgePadAdjuster; +import org.chromium.components.browser_ui.styles.SemanticColorUtils; import org.chromium.components.browser_ui.widget.gesture.BackPressHandler; import org.chromium.components.tab_group_sync.LocalTabGroupId; import org.chromium.components.tab_group_sync.SavedTabGroup; @@ -376,4 +378,24 @@ // Assert that the tab group has a request to open from GTS. verify(mTabSwitcherPaneBase).requestOpenTabGroupDialog(TAB1_ID); } + + @Test + @DisableFeatures(ChromeFeatureList.GRID_TAB_SWITCHER_SURFACE_COLOR_UPDATE) + public void testCloseAllTabsButtonBackgroundColor() { + mCoordinator.show(mOnTabSelectingListener); + FrameLayout buttonContainer = mCoordinator.getCloseAllTabsButtonContainer(); + assertEquals( + SemanticColorUtils.getColorSurface(mActivity), + ((ColorDrawable) buttonContainer.getBackground()).getColor()); + } + + @Test + @EnableFeatures(ChromeFeatureList.GRID_TAB_SWITCHER_SURFACE_COLOR_UPDATE) + public void testCloseAllTabsButtonBackgroundColorUpdate() { + mCoordinator.show(mOnTabSelectingListener); + FrameLayout buttonContainer = mCoordinator.getCloseAllTabsButtonContainer(); + assertEquals( + SemanticColorUtils.getColorSurfaceContainerHigh(mActivity), + ((ColorDrawable) buttonContainer.getBackground()).getColor()); + } }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ColorPickerItemViewBinderUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ColorPickerItemViewBinderUnitTest.java index 4e1017a..3f57b04 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ColorPickerItemViewBinderUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ColorPickerItemViewBinderUnitTest.java
@@ -7,6 +7,7 @@ import static androidx.test.espresso.matcher.ViewMatchers.assertThat; import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertEquals; import static org.chromium.chrome.browser.tasks.tab_management.ColorPickerItemProperties.COLOR_ID; import static org.chromium.chrome.browser.tasks.tab_management.ColorPickerItemProperties.IS_SELECTED; @@ -16,10 +17,11 @@ import android.content.res.ColorStateList; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.LayerDrawable; -import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; +import com.google.android.material.button.MaterialButton; + import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -28,6 +30,8 @@ import org.robolectric.annotation.Config; import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.Features.EnableFeatures; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.components.browser_ui.styles.SemanticColorUtils; import org.chromium.components.tab_groups.TabGroupColorId; import org.chromium.components.tab_groups.TabGroupColorPickerUtils; @@ -47,9 +51,8 @@ @Before public void setUp() throws Exception { mActivity = Robolectric.buildActivity(Activity.class).setup().get(); - mColorPickerItemView = - LayoutInflater.from(mActivity) - .inflate(R.layout.color_picker_item, /* root= */ null); + mActivity.setTheme(R.style.Theme_BrowserUI_DayNight); + mColorPickerItemView = ColorPickerItemViewBinder.createItemView(mActivity); mModel = ColorPickerItemProperties.create( @@ -88,13 +91,13 @@ LayerDrawable layerDrawable = (LayerDrawable) mColorPickerItemView.findViewById(R.id.color_picker_icon).getBackground(); - Assert.assertEquals(3, layerDrawable.getNumberOfLayers()); + assertEquals(3, layerDrawable.getNumberOfLayers()); // Check outer drawable assertThat(layerDrawable.getDrawable(0), instanceOf(GradientDrawable.class)); GradientDrawable drawable0 = (GradientDrawable) layerDrawable.getDrawable(0); - Assert.assertEquals(GradientDrawable.OVAL, drawable0.getShape()); - Assert.assertEquals( + assertEquals(GradientDrawable.OVAL, drawable0.getShape()); + assertEquals( ColorStateList.valueOf( TabGroupColorPickerUtils.getTabGroupColorPickerItemColor( mActivity, TabGroupColorId.BLUE, false)), @@ -103,30 +106,45 @@ // Check selection drawable assertThat(layerDrawable.getDrawable(1), instanceOf(GradientDrawable.class)); GradientDrawable drawable1 = (GradientDrawable) layerDrawable.getDrawable(1); - Assert.assertEquals(GradientDrawable.OVAL, drawable1.getShape()); - Assert.assertEquals( + assertEquals(GradientDrawable.OVAL, drawable1.getShape()); + assertEquals( ColorStateList.valueOf(SemanticColorUtils.getDialogBgColor(mActivity)), drawable1.getColor()); // Check inner drawable assertThat(layerDrawable.getDrawable(2), instanceOf(GradientDrawable.class)); GradientDrawable drawable2 = (GradientDrawable) layerDrawable.getDrawable(2); - Assert.assertEquals(GradientDrawable.OVAL, drawable2.getShape()); - Assert.assertEquals( + assertEquals(GradientDrawable.OVAL, drawable2.getShape()); + assertEquals( ColorStateList.valueOf( TabGroupColorPickerUtils.getTabGroupColorPickerItemColor( mActivity, TabGroupColorId.BLUE, false)), drawable2.getColor()); // Check layer insets - Assert.assertEquals(faviconOuterInset, layerDrawable.getLayerInsetLeft(1)); - Assert.assertEquals(faviconOuterInset, layerDrawable.getLayerInsetTop(1)); - Assert.assertEquals(faviconOuterInset, layerDrawable.getLayerInsetRight(1)); - Assert.assertEquals(faviconOuterInset, layerDrawable.getLayerInsetBottom(1)); - Assert.assertEquals(faviconInnerInset, layerDrawable.getLayerInsetLeft(2)); - Assert.assertEquals(faviconInnerInset, layerDrawable.getLayerInsetTop(2)); - Assert.assertEquals(faviconInnerInset, layerDrawable.getLayerInsetRight(2)); - Assert.assertEquals(faviconInnerInset, layerDrawable.getLayerInsetBottom(2)); + assertEquals(faviconOuterInset, layerDrawable.getLayerInsetLeft(1)); + assertEquals(faviconOuterInset, layerDrawable.getLayerInsetTop(1)); + assertEquals(faviconOuterInset, layerDrawable.getLayerInsetRight(1)); + assertEquals(faviconOuterInset, layerDrawable.getLayerInsetBottom(1)); + assertEquals(faviconInnerInset, layerDrawable.getLayerInsetLeft(2)); + assertEquals(faviconInnerInset, layerDrawable.getLayerInsetTop(2)); + assertEquals(faviconInnerInset, layerDrawable.getLayerInsetRight(2)); + assertEquals(faviconInnerInset, layerDrawable.getLayerInsetBottom(2)); + } + + @Test + @EnableFeatures({ChromeFeatureList.ANDROID_THEME_MODULE}) + public void testColorPickerItem_color_withThemeModuleEnabled() { + mModel.get(COLOR_ID); + + View colorButton = mColorPickerItemView.findViewById(R.id.color_picker_icon); + assertThat(colorButton, instanceOf(MaterialButton.class)); + + assertEquals( + ColorStateList.valueOf( + TabGroupColorPickerUtils.getTabGroupColorPickerItemColor( + mActivity, TabGroupColorId.BLUE, false)), + colorButton.getBackgroundTintList()); } @Test @@ -139,6 +157,16 @@ } @Test + @EnableFeatures({ChromeFeatureList.ANDROID_THEME_MODULE}) + public void testColorPickerItem_onClickListener_withThemeModuleEnabled() { + mModel.get(ON_CLICK_LISTENER); + + View onClickListener = mColorPickerItemView.findViewById(R.id.color_picker_icon); + Assert.assertNotNull(onClickListener); + onClickListener.performClick(); + } + + @Test public void testColorPickerItem_isSelected() { ImageView imageView = mColorPickerItemView.findViewById(R.id.color_picker_icon); LayerDrawable layerDrawable1 = (LayerDrawable) imageView.getBackground(); @@ -155,13 +183,33 @@ .accessibility_tab_group_color_picker_color_item_selected_description, color); - Assert.assertEquals(0, layerDrawable1.getDrawable(1).getAlpha()); - Assert.assertEquals(notSelectedString, imageView.getContentDescription()); + assertEquals(0, layerDrawable1.getDrawable(1).getAlpha()); + assertEquals(notSelectedString, imageView.getContentDescription()); mModel.set(IS_SELECTED, true); LayerDrawable layerDrawable2 = (LayerDrawable) imageView.getBackground(); - Assert.assertEquals(0xFF, layerDrawable2.getDrawable(1).getAlpha()); - Assert.assertEquals(selectedString, imageView.getContentDescription()); + assertEquals(0xFF, layerDrawable2.getDrawable(1).getAlpha()); + assertEquals(selectedString, imageView.getContentDescription()); + } + + @Test + @EnableFeatures({ChromeFeatureList.ANDROID_THEME_MODULE}) + public void testColorPickerItem_isSelected_withThemeModuleEnabled() { + MaterialButton view = mColorPickerItemView.findViewById(R.id.color_picker_icon); + String color = + mActivity.getString(R.string.accessibility_tab_group_color_picker_color_item_blue); + int notSelectedStringId = + R.string.accessibility_tab_group_color_picker_color_item_not_selected_description; + String notSelectedString = mActivity.getString(notSelectedStringId, color); + int selectedStringId = + R.string.accessibility_tab_group_color_picker_color_item_selected_description; + String selectedString = mActivity.getString(selectedStringId, color); + + assertEquals(notSelectedString, view.getContentDescription()); + + mModel.set(IS_SELECTED, true); + + assertEquals(selectedString, view.getContentDescription()); } }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java index b45dd20..6388bbb 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
@@ -134,6 +134,7 @@ import org.chromium.components.feature_engagement.Tracker; import org.chromium.components.signin.base.CoreAccountInfo; import org.chromium.components.signin.identitymanager.IdentityManager; +import org.chromium.components.tab_group_sync.EitherId.EitherGroupId; import org.chromium.components.tab_group_sync.LocalTabGroupId; import org.chromium.components.tab_group_sync.SavedTabGroup; import org.chromium.components.tab_group_sync.TabGroupSyncService; @@ -171,6 +172,8 @@ private static final int POSITION2 = 1; private static final Token TAB_GROUP_ID = new Token(1L, 2L); private static final LocalTabGroupId LOCAL_TAB_GROUP_ID = new LocalTabGroupId(TAB_GROUP_ID); + private static final EitherGroupId EITHER_LOCAL_TAB_GROUP_ID = + EitherGroupId.createLocalId(LOCAL_TAB_GROUP_ID); @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); @@ -323,13 +326,11 @@ mModel.get(TabGridDialogProperties.SHARE_BUTTON_CLICK_LISTENER).onClick(null); verify(mDataSharingTabManager) - .createOrManageFlow( - eq(mActivity), eq(null), eq(LOCAL_TAB_GROUP_ID), anyInt(), any()); + .createOrManageFlow(eq(mActivity), eq(EITHER_LOCAL_TAB_GROUP_ID), anyInt(), any()); mModel.get(TabGridDialogProperties.SHARE_IMAGE_TILES_CLICK_LISTENER).onClick(null); verify(mDataSharingTabManager, times(2)) - .createOrManageFlow( - eq(mActivity), eq(null), eq(LOCAL_TAB_GROUP_ID), anyInt(), any()); + .createOrManageFlow(eq(mActivity), eq(EITHER_LOCAL_TAB_GROUP_ID), anyInt(), any()); mModel.get(TabGridDialogProperties.SEND_FEEDBACK_RUNNABLE).run(); ArgumentCaptor<String> categoryCaptor = ArgumentCaptor.forClass(String.class); @@ -1525,7 +1526,7 @@ mMediator.onToolbarMenuItemClick(R.id.manage_sharing, TAB_GROUP_ID, COLLABORATION_ID1); assertEquals(1, mActionTester.getActionCount("TabGridDialogMenu.ManageSharing")); verify(mDataSharingTabManager) - .createOrManageFlow(any(), eq(null), eq(LOCAL_TAB_GROUP_ID), anyInt(), eq(null)); + .createOrManageFlow(any(), eq(EITHER_LOCAL_TAB_GROUP_ID), anyInt(), eq(null)); } @Test
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java index 254d03d..f087f5f 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -4363,8 +4363,7 @@ assertNotNull(mModelList.get(POSITION1).model.get(TabProperties.TAB_ACTION_BUTTON_DATA)); when(mTabGroupModelFilter.getGroupLastShownTabId(TAB_GROUP_ID)).thenReturn(TAB1_ID); mMediator.onMenuItemClicked(R.id.share_group, TAB_GROUP_ID, /* collaborationId= */ null); - verify(mDataSharingTabManager) - .createOrManageFlow(eq(mActivity), eq(null), any(), anyInt(), any()); + verify(mDataSharingTabManager).createOrManageFlow(eq(mActivity), any(), anyInt(), any()); } @Test
diff --git a/chrome/android/java/res/menu/custom_tabs_menu.xml b/chrome/android/java/res/menu/custom_tabs_menu.xml index 31416ff..8cd8621f 100644 --- a/chrome/android/java/res/menu/custom_tabs_menu.xml +++ b/chrome/android/java/res/menu/custom_tabs_menu.xml
@@ -66,6 +66,10 @@ <item android:id="@+id/disable_price_tracking_menu_id" android:title="@string/disable_price_tracking_menu_item" android:icon="@drawable/price_tracking_enabled_filled" /> + <item android:id="@+id/price_insights_menu_id" + android:title="@string/price_insights_title" + android:icon="@drawable/ic_trending_down_24dp" + android:visible="false" /> <item android:id="@+id/universal_install" android:title="@string/menu_add_to_homescreen" android:orderInCategory="2" />
diff --git a/chrome/android/java/res/values/attrs.xml b/chrome/android/java/res/values/attrs.xml index 86aff98..d4b0d48 100644 --- a/chrome/android/java/res/values/attrs.xml +++ b/chrome/android/java/res/values/attrs.xml
@@ -26,4 +26,8 @@ <declare-styleable name="HubToolbarView"> <attr name="newTabButtonStyle" format="reference" /> </declare-styleable> + + <declare-styleable name="TabGroupColorPickerContainer"> + <attr name="colorPickerButtonStyle" format="reference" /> + </declare-styleable> </resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java index e1cb8522..4ed3d42f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java
@@ -19,7 +19,6 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.lifetime.Destroyable; import org.chromium.base.supplier.ObservableSupplier; -import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.Supplier; import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; @@ -35,6 +34,7 @@ import org.chromium.chrome.browser.tab.tab_restore.HistoricalTabModelObserver; import org.chromium.chrome.browser.tab_group_sync.TabGroupSyncServiceFactory; import org.chromium.chrome.browser.tab_ui.TabContentManager; +import org.chromium.chrome.browser.tabmodel.ArchivedTabCountSupplier; import org.chromium.chrome.browser.tabmodel.ArchivedTabCreator; import org.chromium.chrome.browser.tabmodel.ArchivedTabModelSelectorHolder; import org.chromium.chrome.browser.tabmodel.ArchivedTabModelSelectorImpl; @@ -132,9 +132,6 @@ private final AsyncTabParamsManager mAsyncTabParamsManager; private final ObserverList<Observer> mObservers = new ObserverList<>(); private final TabWindowManager mTabWindowManager; - private final ObservableSupplierImpl<Integer> mTabCountSupplier = - new ObservableSupplierImpl<>(); - private final Callback<Integer> mTabCountSupplierObserver = mTabCountSupplier::set; // The set of {@link TabModelOrchestrators} which have registered themselves as active for // declutter. private final List<TabbedModeTabModelOrchestrator> mActivityTabModelOrchestrators = @@ -150,9 +147,10 @@ private boolean mRestoreTabsCalled; private boolean mRescueTabsCalled; private CallbackController mCallbackController = new CallbackController(); - private ObservableSupplier<Integer> mUnderlyingTabCountSupplier; private @Nullable HistoricalTabModelObserver mHistoricalTabModelObserver; private boolean mTriggerAutodeleteAfterDataCreated; + private @Nullable TabGroupSyncService mTabGroupSyncService; + private ArchivedTabCountSupplier mArchivedTabCountSupplier; /** * Returns the ArchivedTabModelOrchestrator that corresponds to the given profile. Must be @@ -240,10 +238,6 @@ mTabWindowManager.setArchivedTabModelSelector(null); } - if (mUnderlyingTabCountSupplier != null) { - mUnderlyingTabCountSupplier.removeObserver(mTabCountSupplierObserver); - } - if (mHistoricalTabModelObserver != null) { mHistoricalTabModelObserver.destroy(); mHistoricalTabModelObserver = null; @@ -254,6 +248,11 @@ mTabArchiver = null; } + if (mArchivedTabCountSupplier != null) { + mArchivedTabCountSupplier.destroy(); + mArchivedTabCountSupplier = null; + } + super.destroy(); } @@ -300,7 +299,7 @@ /** Returns a supplier for the archive tab count. */ public ObservableSupplier<Integer> getTabCountSupplier() { - return mTabCountSupplier; + return mArchivedTabCountSupplier; } public TabModel getTabModel() { @@ -388,9 +387,7 @@ observer.onTabModelCreated(model); } - mUnderlyingTabCountSupplier = model.getTabCountSupplier(); - mTabCountSupplier.set(mUnderlyingTabCountSupplier.get()); - mUnderlyingTabCountSupplier.addObserver(mTabCountSupplierObserver); + mArchivedTabCountSupplier = new ArchivedTabCountSupplier(model, mTabGroupSyncService); mHistoricalTabModelObserver = new HistoricalTabModelObserver( @@ -505,8 +502,7 @@ mTabArchiveSettings = new TabArchiveSettings(ChromeSharedPreferences.getInstance()); mTabArchiveSettings.addObserver(mTabArchiveSettingsObserver); - TabGroupSyncService tabGroupSyncService = - TabGroupSyncServiceFactory.getForProfile(mProfile); + mTabGroupSyncService = TabGroupSyncServiceFactory.getForProfile(mProfile); mTabArchiver = new TabArchiverImpl( mTabModelSelector @@ -515,7 +511,7 @@ mArchivedTabCreator, mTabArchiveSettings, System::currentTimeMillis, - tabGroupSyncService); + mTabGroupSyncService); mTabArchiver.addObserver(mTabArchiverObserver); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewTabAnimationLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewTabAnimationLayout.java index 72911306..18495935 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewTabAnimationLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewTabAnimationLayout.java
@@ -21,7 +21,6 @@ import android.view.ViewGroup; import androidx.annotation.ColorInt; -import androidx.annotation.IntDef; import androidx.annotation.Nullable; import androidx.annotation.Px; import androidx.annotation.VisibleForTesting; @@ -42,6 +41,7 @@ import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.fullscreen.BrowserControlsManager; import org.chromium.chrome.browser.hub.NewTabAnimationUtils; +import org.chromium.chrome.browser.hub.NewTabAnimationUtils.RectStart; import org.chromium.chrome.browser.hub.RoundedCornerAnimatorUtil; import org.chromium.chrome.browser.hub.ShrinkExpandAnimator; import org.chromium.chrome.browser.hub.ShrinkExpandImageView; @@ -70,10 +70,6 @@ import org.chromium.ui.interpolators.Interpolators; import org.chromium.ui.resources.ResourceManager; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -84,21 +80,6 @@ * uses modern UX designs. */ public class NewTabAnimationLayout extends Layout { - @IntDef({ - RectStart.TOP, - RectStart.TOP_TOOLBAR, - RectStart.BOTTOM, - RectStart.BOTTOM_TOOLBAR, - }) - @Target(ElementType.TYPE_USE) - @Retention(RetentionPolicy.SOURCE) - /*package*/ @interface RectStart { - int TOP = 0; - int TOP_TOOLBAR = 1; - int BOTTOM = 2; - int BOTTOM_TOOLBAR = 3; - } - private static final long FOREGROUND_ANIMATION_DURATION_MS = 300L; private static final long FOREGROUND_FADE_DURATION_MS = 150L; private static final long ANIMATION_TIMEOUT_MS = 800L; @@ -111,6 +92,7 @@ private final ToolbarManager mToolbarManager; private final BrowserControlsManager mBrowserControlsManager; private final ObservableSupplier<Boolean> mScrimVisibilitySupplier; + private final CustomTabCount mCustomTabCount; private @Nullable StaticTabSceneLayer mSceneLayer; private AnimatorSet mTabCreatedForegroundAnimation; @@ -121,7 +103,6 @@ private Runnable mAnimationRunnable; private Runnable mTimeoutRunnable; private Callback<Boolean> mVisibilityObserver; - private CustomTabCount mCustomTabCount; private @TabId int mNextTabId = Tab.INVALID_TAB_ID; private boolean mSkipForceAnimationToFinish; @@ -430,7 +411,13 @@ * @param newTab The new {@link Tab} to animate. */ private @RectStart int getForegroundRectStart(Tab oldTab, Tab newTab) { - // TODO(crbug.com/40933120): Account for {@code oldTab} being null. + @TabLaunchType int tabLaunchType = newTab.getLaunchType(); + if (oldTab == null + || tabLaunchType == TabLaunchType.FROM_LONGPRESS_FOREGROUND + || tabLaunchType == TabLaunchType.FROM_LONGPRESS_FOREGROUND_IN_GROUP) { + return RectStart.CENTER; + } + boolean oldTabHasTopToolbar = ToolbarPositionController.shouldShowToolbarOnTop(oldTab); boolean newTabHasTopToolbar = ToolbarPositionController.shouldShowToolbarOnTop(newTab); @@ -495,6 +482,7 @@ * @param id The id of the new tab to animate. * @param sourceId The id of the tab that spawned this new tab. * @param newIsIncognito True if the new tab is an incognito tab. + * @param rectStart Origin point where the animation starts. */ private void tabCreatedInForeground( @TabId int id, @TabId int sourceId, boolean newIsIncognito, @RectStart int rectStart) { @@ -526,40 +514,50 @@ Rect initialRect = new Rect(); Rect finalRect = new Rect(); - RectF compositorViewportRectf = new RectF(); Rect hostViewRect = new Rect(); - mCompositorViewHolder.getVisibleViewport(compositorViewportRectf); - compositorViewportRectf.round(finalRect); mAnimationHostView.getGlobalVisibleRect(hostViewRect); - boolean isTopAligned = rectStart == RectStart.TOP || rectStart == RectStart.TOP_TOOLBAR; int radius = context.getResources() .getDimensionPixelSize(R.dimen.new_tab_animation_rect_corner_radius); - int[] startRadii; + int[] startRadii = new int[4]; + Arrays.fill(startRadii, radius); - // Without adding/subtracting 1px, the origin corner shows a bit of blinking when running - // the animation. Doing so ensures the {@link ShrinkExpandImageView} fully covers the origin - // corner. - if (isTopAligned) { - startRadii = new int[] {0, radius, radius, radius}; - mCompositorViewHolder.getWindowViewport(compositorViewportRectf); - finalRect.bottom = Math.round(compositorViewportRectf.bottom); - finalRect.top = rectStart == RectStart.TOP ? hostViewRect.top : finalRect.top - 1; + if (rectStart != RectStart.CENTER) { + RectF compositorViewportRectf = new RectF(); + mCompositorViewHolder.getVisibleViewport(compositorViewportRectf); + compositorViewportRectf.round(finalRect); + + // Without adding/subtracting 1px, the origin corner shows a bit of blinking when + // running the animation. Doing so ensures the {@link ShrinkExpandImageView} fully + // covers the origin corner. + if (rectStart == RectStart.TOP || rectStart == RectStart.TOP_TOOLBAR) { + startRadii[0] = 0; + mCompositorViewHolder.getWindowViewport(compositorViewportRectf); + finalRect.bottom = Math.round(compositorViewportRectf.bottom); + finalRect.top = + rectStart == RectStart.TOP ? hostViewRect.top - 1 : finalRect.top - 1; + } else { + startRadii[2] = 0; + finalRect.top = hostViewRect.top; + finalRect.bottom = + rectStart == RectStart.BOTTOM + ? hostViewRect.bottom + 1 + : finalRect.bottom + 1; + } + if (isRtl) { + finalRect.right += 1; + } else { + finalRect.left -= 1; + } } else { - startRadii = new int[] {radius, radius, 0, radius}; - finalRect.top = hostViewRect.top; - finalRect.bottom = - rectStart == RectStart.BOTTOM ? hostViewRect.bottom : finalRect.bottom + 1; + finalRect = hostViewRect; + Rect compositorViewRect = new Rect(); + mCompositorViewHolder.getGlobalVisibleRect(compositorViewRect); + finalRect.bottom -= compositorViewRect.top; } - if (isRtl) { - finalRect.right += 1; - } else { - finalRect.left -= 1; - } - // TODO(crbug.com/40933120): Make the initial rect start from the center when opening a tab - // from the context menu. - NewTabAnimationUtils.updateRects(initialRect, finalRect, isRtl, isTopAligned); + + NewTabAnimationUtils.updateRects(rectStart, isRtl, initialRect, finalRect); ShrinkExpandAnimator shrinkExpandAnimator = new ShrinkExpandAnimator( @@ -612,9 +610,13 @@ mAnimationRunnable = () -> { mAnimationRunnable = null; + // Make View visible once the animation is ready to start. + mRectView.setVisibility(View.VISIBLE); mTabCreatedForegroundAnimation.start(); }; + // {@link View#INVISIBLE} is needed to generate the geometry information. + mRectView.setVisibility(View.INVISIBLE); mAnimationHostView.addView(mRectView); mRectView.reset(initialRect); mHandler.post(mAnimationRunnable);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinator.java index e7c6d1e..8aaabb1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinator.java
@@ -52,6 +52,7 @@ import org.chromium.components.collaboration.CollaborationServiceShareOrManageEntryPoint; import org.chromium.components.data_sharing.member_role.MemberRole; import org.chromium.components.embedder_support.util.UrlConstants; +import org.chromium.components.tab_group_sync.EitherId.EitherGroupId; import org.chromium.components.tab_group_sync.LocalTabGroupId; import org.chromium.components.tab_group_sync.TabGroupSyncService; import org.chromium.components.tab_groups.TabGroupColorId; @@ -225,8 +226,7 @@ } else if (menuId == R.id.manage_sharing) { dataSharingTabManager.createOrManageFlow( activity, - /* syncId= */ null, - new LocalTabGroupId(tabGroupId), + EitherGroupId.createLocalId(new LocalTabGroupId(tabGroupId)), CollaborationServiceShareOrManageEntryPoint .ANDROID_TAB_GROUP_CONTEXT_MENU_MANAGE, /* createGroupFinishedCallback= */ null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java index 203c36d..b0c8cf3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -948,6 +948,7 @@ mIntentDataProvider.isOffTheRecord(), isMenuIconAtStart, mBaseCustomTabRootUiCoordinator.getReadAloudControllerSupplier(), + mBaseCustomTabRootUiCoordinator::getContextualPageActionController, mIntentDataProvider.getClientPackageNameIdentitySharing() != null); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java index 0778a81..43cef22 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
@@ -81,6 +81,7 @@ import org.chromium.chrome.browser.readaloud.ReadAloudIphController; import org.chromium.chrome.browser.reengagement.ReengagementNotificationController; import org.chromium.chrome.browser.searchwidget.SearchActivityClientImpl; +import org.chromium.chrome.browser.segmentation_platform.ContextualPageActionController; import org.chromium.chrome.browser.share.ShareDelegate; import org.chromium.chrome.browser.signin.services.IdentityServicesProvider; import org.chromium.chrome.browser.signin.services.SigninPreferencesManager; @@ -413,7 +414,9 @@ new CustomTabToolbarButtonsCoordinator( toolbar, mIntentDataProvider.get(), - params -> mToolbarCoordinator.get().onCustomButtonClick(params)); + params -> mToolbarCoordinator.get().onCustomButtonClick(params), + mMinimizeDelegateSupplier.get(), + mFeatureOverridesManagerSupplier.get()); super.initializeToolbar(); @@ -567,6 +570,14 @@ return mCustomTabHistoryIphController; } + public ContextualPageActionController getContextualPageActionController() { + return mAdaptiveToolbarUiCoordinator.getContextualPageActionController(); + } + + public void runPriceInsightsAction() { + mAdaptiveToolbarUiCoordinator.runPriceInsightsAction(); + } + @Override public int getControlContainerHeightResource() { return R.dimen.custom_tabs_control_container_height;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java index 460fe5dc..5d01dfb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -308,6 +308,8 @@ getTabCreator(getCurrentTabModel().isIncognito())) .show(tab, ChromePageInfoHighlight.noHighlight()); return true; + } else if (id == R.id.price_insights_menu_id) { + getBaseCustomTabRootUiCoordinator().runPriceInsightsAction(); } else if (id == R.id.open_history_menu_id) { // The menu is visible only when the app-specific history is enabled. Assert that. assert HistoryManager.isAppSpecificHistoryEnabled();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java index 503abc7..2c592f94 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
@@ -34,6 +34,7 @@ import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher; import org.chromium.chrome.browser.readaloud.ReadAloudController; import org.chromium.chrome.browser.readaloud.ReadAloudFeatures; +import org.chromium.chrome.browser.segmentation_platform.ContextualPageActionController; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.toolbar.ToolbarManager; @@ -68,6 +69,7 @@ private final List<String> mMenuEntries; private final Map<String, Integer> mTitleToItemIdMap = new HashMap<String, Integer>(); private final Map<Integer, Integer> mItemIdToIndexMap = new HashMap<Integer, Integer>(); + private final Supplier<ContextualPageActionController> mContextualPageActionControllerSupplier; private boolean mHasClientPackage; @@ -91,6 +93,7 @@ boolean isOffTheRecord, boolean isStartIconMenu, Supplier<ReadAloudController> readAloudControllerSupplier, + Supplier<ContextualPageActionController> contextualPageActionControllerSupplier, boolean hasClientPackage) { super( context, @@ -112,6 +115,7 @@ mIsIncognitoBranded = isIncognitoBranded; mIsOffTheRecord = isOffTheRecord; mIsStartIconMenu = isStartIconMenu; + mContextualPageActionControllerSupplier = contextualPageActionControllerSupplier; mHasClientPackage = hasClientPackage; } @@ -284,6 +288,11 @@ // TODO(crbug.com/391931899): Also check the dev-controlled flag updatePriceTrackingMenuItemRow( startPriceTrackingMenuItem, stopPriceTrackingMenuItem, currentTab); + var cpaController = mContextualPageActionControllerSupplier.get(); + if (cpaController != null) { + menu.findItem(R.id.price_insights_menu_id) + .setVisible(cpaController.hasPriceInsights()); + } } boolean showOpenWith = currentTab.isNativePage() && currentTab.getNativePage().isPdf();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java index b61ae2e..93e7687 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
@@ -475,11 +475,6 @@ assert false : assertMsg; } - static void enablePredictiveBackGestureForTesting() { - sVersionForTesting = Build.VERSION_CODES.BAKLAVA; - ResettersForTesting.register(() -> sVersionForTesting = null); - } - public BrowserServicesIntentDataProvider getIntentDataProviderForTesting() { return mIntentDataProvider; } @@ -491,4 +486,9 @@ public Integer getVersionForTesting() { return sVersionForTesting; } + + public static void enablePredictiveBackGestureForTesting() { + sVersionForTesting = Build.VERSION_CODES.BAKLAVA; + ResettersForTesting.register(() -> sVersionForTesting = null); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandler.java index d6199f9..ef73417 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandler.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.customtabs.content; +import static androidx.browser.trusted.LaunchHandlerClientMode.AUTO; import static androidx.browser.trusted.LaunchHandlerClientMode.FOCUS_EXISTING; import static androidx.browser.trusted.LaunchHandlerClientMode.NAVIGATE_EXISTING; import static androidx.browser.trusted.LaunchHandlerClientMode.NAVIGATE_NEW; @@ -26,6 +27,9 @@ import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.ui.controller.CurrentPageVerifier; import org.chromium.chrome.browser.browserservices.ui.controller.Verifier; +import org.chromium.chrome.browser.customtabs.content.WebAppLaunchHandlerHistogram.ClientModeAction; +import org.chromium.chrome.browser.customtabs.content.WebAppLaunchHandlerHistogram.FailureReasonAction; +import org.chromium.chrome.browser.customtabs.content.WebAppLaunchHandlerHistogram.FileHandlingAction; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.WebContents; @@ -110,8 +114,15 @@ String packageName, @Nullable FileHandlingData fileHandlingData) { List<Uri> fileUris = null; - if (fileHandlingData != null) { + if (fileHandlingData != null && !fileHandlingData.uris.isEmpty()) { + if (fileHandlingData.uris.size() == 1) { + WebAppLaunchHandlerHistogram.logFileHandling(FileHandlingAction.SINGLE_FILE); + } else { + WebAppLaunchHandlerHistogram.logFileHandling(FileHandlingAction.MULTIPLE_FILES); + } fileUris = fileHandlingData.uris; + } else { + WebAppLaunchHandlerHistogram.logFileHandling(FileHandlingAction.NO_FILES); } return new WebAppLaunchParams(newNavigationStarted, targetUrl, packageName, fileUris); @@ -128,6 +139,8 @@ * data. */ public void handleInitialIntent(BrowserServicesIntentDataProvider intentDataProvider) { + WebAppLaunchHandlerHistogram.logClientMode(ClientModeAction.INITIAL_INTENT); + WebAppLaunchParams launchParams = getLaunchParams( /* newNavigationStarted= */ true, @@ -150,7 +163,9 @@ * data. */ public void handleNewIntent(BrowserServicesIntentDataProvider intentDataProvider) { - @ClientMode int clientMode = getClientMode(intentDataProvider.getLaunchHandlerClientMode()); + @ClientMode int clientModeFromIntent = intentDataProvider.getLaunchHandlerClientMode(); + recordClientMode(clientModeFromIntent); + @ClientMode int clientMode = getClientMode(clientModeFromIntent); if (clientMode == NAVIGATE_NEW) { launchNewIntent( @@ -176,6 +191,23 @@ } } + private void recordClientMode(@ClientMode int clientMode) { + switch (clientMode) { + case NAVIGATE_EXISTING: + WebAppLaunchHandlerHistogram.logClientMode(ClientModeAction.MODE_NAVIGATE_EXISTING); + break; + case FOCUS_EXISTING: + WebAppLaunchHandlerHistogram.logClientMode(ClientModeAction.MODE_FOCUS_EXISTING); + break; + case NAVIGATE_NEW: + WebAppLaunchHandlerHistogram.logClientMode(ClientModeAction.MODE_NAVIGATE_NEW); + break; + case AUTO: + WebAppLaunchHandlerHistogram.logClientMode(ClientModeAction.MODE_AUTO); + break; + } + } + /** * Launches a new instance of TWA in a separate task. In order to support navigate-new client * mode we need to support several running instances of the same TWA app simultaneously in @@ -212,6 +244,8 @@ // Launch params should not be sent to a not verified origin. CurrentPageVerifier.VerificationState state = mCurrentPageVerifier.getState(); if (state == null || state.status != CurrentPageVerifier.VerificationStatus.SUCCESS) { + WebAppLaunchHandlerHistogram.logFailureReason( + FailureReasonAction.CURRENT_PAGE_VERIFICATION_FAILED); return; } } @@ -220,7 +254,11 @@ .verify(launchParams.targetUrl) .then( (verified) -> { - if (!verified) return; + if (!verified) { + WebAppLaunchHandlerHistogram.logFailureReason( + FailureReasonAction.TARGET_URL_VERIFICATION_FAILED); + return; + } WebAppLaunchHandlerJni.get() .notifyLaunchQueue( mWebContents,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandlerHistogram.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandlerHistogram.java new file mode 100644 index 0000000..f9256ba9 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/WebAppLaunchHandlerHistogram.java
@@ -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. + +package org.chromium.chrome.browser.customtabs.content; + +import androidx.annotation.IntDef; + +import org.chromium.base.metrics.RecordHistogram; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Records a histogram that tracks usage of Launch Handler API. All actions must be kept in sync + * with the definition in tools/metrics/histograms/metadata/custom_tabs/enums.xml. + */ +public class WebAppLaunchHandlerHistogram { + private WebAppLaunchHandlerHistogram() {} + + private static final String CLIENT_MODE_HISTOGRAM = + "TrustedWebActivity.LaunchHandler.ClientMode"; + + @IntDef({ + ClientModeAction.INITIAL_INTENT, + ClientModeAction.MODE_NAVIGATE_EXISTING, + ClientModeAction.MODE_NAVIGATE_NEW, + ClientModeAction.MODE_FOCUS_EXISTING, + ClientModeAction.MODE_AUTO, + ClientModeAction.COUNT, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ClientModeAction { + int INITIAL_INTENT = 0; + int MODE_NAVIGATE_EXISTING = 1; + int MODE_NAVIGATE_NEW = 2; + int MODE_FOCUS_EXISTING = 3; + int MODE_AUTO = 4; + + /** Total count of entries. */ + int COUNT = 5; + } + + public static void logClientMode(@ClientModeAction int action) { + RecordHistogram.recordEnumeratedHistogram( + CLIENT_MODE_HISTOGRAM, action, ClientModeAction.COUNT); + } + + private static final String FILE_HANDLING_HISTOGRAM = + "TrustedWebActivity.LaunchHandler.FileHandling"; + + @IntDef({ + FileHandlingAction.NO_FILES, + FileHandlingAction.SINGLE_FILE, + FileHandlingAction.MULTIPLE_FILES, + FileHandlingAction.COUNT, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FileHandlingAction { + int NO_FILES = 0; + int SINGLE_FILE = 1; + int MULTIPLE_FILES = 2; + + /** Total count of entries. */ + int COUNT = 3; + } + + public static void logFileHandling(@FileHandlingAction int action) { + RecordHistogram.recordEnumeratedHistogram( + FILE_HANDLING_HISTOGRAM, action, FileHandlingAction.COUNT); + } + + private static final String FAILURE_REASON_HISTOGRAM = + "TrustedWebActivity.LaunchHandler.FailureReason"; + + @IntDef({ + FailureReasonAction.TARGET_URL_VERIFICATION_FAILED, + FailureReasonAction.CURRENT_PAGE_VERIFICATION_FAILED, + FailureReasonAction.COUNT, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FailureReasonAction { + int TARGET_URL_VERIFICATION_FAILED = 0; + int CURRENT_PAGE_VERIFICATION_FAILED = 1; + + /** Total count of entries. */ + int COUNT = 2; + } + + public static void logFailureReason(@FailureReasonAction int action) { + RecordHistogram.recordEnumeratedHistogram( + FAILURE_REASON_HISTOGRAM, action, FailureReasonAction.COUNT); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBottomSheetStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBottomSheetStrategy.java index 73c7a51..ddbb5fc8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBottomSheetStrategy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBottomSheetStrategy.java
@@ -50,6 +50,7 @@ import org.chromium.chrome.browser.customtabs.features.partialcustomtab.ContentGestureListener.GestureState; import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar; import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsCoordinator; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.fullscreen.FullscreenManager; import org.chromium.chrome.browser.fullscreen.FullscreenOptions; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; @@ -346,7 +347,11 @@ new PartialCustomTabHandleStrategy( mActivity, this::isFullHeight, () -> mStatus, this); toolbar.setHandleStrategy(mHandleStrategy); - toolbar.setMinimizeButtonEnabled(false); + if (ChromeFeatureList.sCctToolbarRefactor.isEnabled()) { + toolbarButtonsCoordinator.setMinimizeButtonVisible(false); + } else { + toolbar.setMinimizeButtonEnabled(false); + } CustomTabDragBar dragBar = mActivity.findViewById(R.id.drag_bar); dragBar.setHandleStrategy(mHandleStrategy); View dragHandle = mActivity.findViewById(R.id.drag_handle);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabFullSizeStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabFullSizeStrategy.java index d1a4c15..ded6995 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabFullSizeStrategy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabFullSizeStrategy.java
@@ -24,6 +24,7 @@ import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar; import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsCoordinator; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.fullscreen.FullscreenManager; /** @@ -71,7 +72,11 @@ CustomTabToolbarButtonsCoordinator toolbarButtonsCoordinator) { super.onToolbarInitialized( coordinatorView, toolbar, toolbarCornerRadius, toolbarButtonsCoordinator); - toolbar.setMinimizeButtonEnabled(true); + if (ChromeFeatureList.sCctToolbarRefactor.isEnabled()) { + toolbarButtonsCoordinator.setMinimizeButtonVisible(true); + } else { + toolbar.setMinimizeButtonEnabled(true); + } updateDragBarVisibility(/* dragHandlebarVisibility= */ View.GONE); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategy.java index 9aff197..fb3a958e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategy.java
@@ -173,7 +173,11 @@ toolbar.initSideSheetMaximizeButton(mIsMaximized, () -> toggleMaximize(true)); } } - toolbar.setMinimizeButtonEnabled(false); + if (ChromeFeatureList.sCctToolbarRefactor.isEnabled()) { + mToolbarButtonsCoordinator.setMinimizeButtonVisible(false); + } else { + toolbar.setMinimizeButtonEnabled(false); + } updateDragBarVisibility(/* dragHandlebarVisibility= */ View.GONE); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java index 057eb41..231ca84 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -197,7 +197,6 @@ private int mToolbarWidth; private BrowserServicesIntentDataProvider mIntentDataProvider; private CustomTabMinimizeDelegate mMinimizeDelegate; - private Boolean mEnableMinimizeButton; private FrameLayout mCustomButtonsParent; private PropertyListModel<PropertyModel, PropertyKey> mCustomActionButtonsListModel; private boolean mIsInMultiWindowMode; @@ -405,8 +404,8 @@ prepareMinimizeButton(); if (mMinimizeButton != null && mMinimizeButton.getVisibility() == VISIBLE) { - boolean isEndPosition = mCloseButtonPosition == CLOSE_BUTTON_POSITION_END; - positionButton(mMinimizeButton, posParams, mDefaultIconWidth, isEndPosition); + // The minimize button is always start aligned. + positionButton(mMinimizeButton, posParams, mDefaultIconWidth, false); } } @@ -791,10 +790,10 @@ /** * Inflates and prepares the minimize button if it should be enabled. * - * This is only used when CCTToolbarRefactor is enabled. + * <p>This is only used when CCTToolbarRefactor is enabled. */ private void prepareMinimizeButton() { - if (!isMinimizeButtonEnabled()) return; + if (!mMinimizeButtonEnabled) return; if (isInMultiWindowMode()) { if (mMinimizeButton != null) { @@ -821,24 +820,6 @@ } /** - * Whether the minimize button should be enabled. A true return value doesn't mean the minimize - * button will be visible on the toolbar. The minimize button will be hidden if there isn't - * enough space on the toolbar or if the CCT is in multi-window mode. - * - * This is only used when CCTToolbarRefactor is enabled. - */ - private boolean isMinimizeButtonEnabled() { - if (mEnableMinimizeButton != null) return mEnableMinimizeButton; - - mEnableMinimizeButton = - MinimizedFeatureUtils.isMinimizedCustomTabAvailable( - getContext(), mFeatureOverridesManager) - && MinimizedFeatureUtils.shouldEnableMinimizedCustomTabs( - mIntentDataProvider); - return mEnableMinimizeButton; - } - - /** * Inflates and prepares the minimize button if it should be enabled, when CCTToolbarRefactor is * disabled. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java index 2e1130ae..06df415a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java
@@ -8,15 +8,21 @@ import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.DESCRIPTION; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.ICON; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.INDIVIDUAL_BUTTON_KEYS; +import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.MINIMIZE_BUTTON; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.SIDE_SHEET_MAXIMIZE_BUTTON; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.VISIBLE; import android.content.Context; import org.chromium.base.Callback; +import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.intents.CustomButtonParams; +import org.chromium.chrome.browser.customtabs.CustomTabFeatureOverridesManager; +import org.chromium.chrome.browser.customtabs.features.minimizedcustomtab.CustomTabMinimizeDelegate; +import org.chromium.chrome.browser.customtabs.features.minimizedcustomtab.MinimizedFeatureUtils; import org.chromium.chrome.browser.customtabs.features.partialcustomtab.PartialCustomTabSideSheetStrategy.MaximizeButtonCallback; +import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.MinimizeButtonData; import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.SideSheetMaximizeButtonData; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.ui.modelutil.ListModelChangeProcessor; @@ -32,16 +38,31 @@ PropertyListModel<PropertyModel, PropertyKey>, CustomTabToolbar, PropertyKey> mCustomActionButtonsMcp; private final PropertyModel mModel; + private final CustomTabMinimizeDelegate mMinimizeDelegate; + + /** Whether the minimize button is available for the device and the current configuration. */ + private final boolean mMinimizeButtonAvailable; public CustomTabToolbarButtonsCoordinator( CustomTabToolbar view, BrowserServicesIntentDataProvider intentDataProvider, - Callback<CustomButtonParams> customButtonClickCallback) { + Callback<CustomButtonParams> customButtonClickCallback, + CustomTabMinimizeDelegate minimizeDelegate, + @Nullable CustomTabFeatureOverridesManager featureOverridesManager) { CustomTabToolbarButtonsViewBinder viewBinder = new CustomTabToolbarButtonsViewBinder(); var customActionButtons = getCustomActionButtonsModel( view.getContext(), intentDataProvider, customButtonClickCallback); - mModel = CustomTabToolbarButtonsProperties.create(customActionButtons); + mMinimizeButtonAvailable = + MinimizedFeatureUtils.isMinimizedCustomTabAvailable( + view.getContext(), featureOverridesManager) + && MinimizedFeatureUtils.shouldEnableMinimizedCustomTabs( + intentDataProvider); + mMinimizeDelegate = minimizeDelegate; + var minimizeButton = + getMinimizeButtonData( + mMinimizeButtonAvailable && minimizeDelegate != null, minimizeDelegate); + mModel = CustomTabToolbarButtonsProperties.create(customActionButtons, minimizeButton); PropertyModelChangeProcessor.create(mModel, view, viewBinder); mCustomActionButtonsMcp = new ListModelChangeProcessor<>( @@ -72,6 +93,13 @@ mModel.set(SIDE_SHEET_MAXIMIZE_BUTTON, buttonData); } + public void setMinimizeButtonVisible(boolean visible) { + assert ChromeFeatureList.sCctToolbarRefactor.isEnabled(); + mModel.set( + MINIMIZE_BUTTON, + getMinimizeButtonData(mMinimizeButtonAvailable && visible, mMinimizeDelegate)); + } + static PropertyListModel<PropertyModel, PropertyKey> getCustomActionButtonsModel( Context context, BrowserServicesIntentDataProvider intentDataProvider, @@ -92,4 +120,13 @@ } return listModel; } + + private static MinimizeButtonData getMinimizeButtonData( + boolean visible, CustomTabMinimizeDelegate minimizeDelegate) { + return new MinimizeButtonData( + visible, + v -> { + if (minimizeDelegate != null) minimizeDelegate.minimize(); + }); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsProperties.java index 6ef6615..9e0d9c0b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsProperties.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsProperties.java
@@ -65,11 +65,31 @@ public static final WritableObjectPropertyKey<SideSheetMaximizeButtonData> SIDE_SHEET_MAXIMIZE_BUTTON = new WritableObjectPropertyKey<>(); + public static class MinimizeButtonData { + /** Whether the minimize button is visible. */ + public final boolean visible; + + /** The {@link OnClickListener} to notify of the click events. */ + public final OnClickListener clickListener; + + MinimizeButtonData(boolean visible, OnClickListener clickListener) { + this.visible = visible; + this.clickListener = clickListener; + } + } + + /** Property key for the minimize button. */ + public static final WritableObjectPropertyKey<MinimizeButtonData> MINIMIZE_BUTTON = + new WritableObjectPropertyKey<>(); + public static PropertyModel create( - PropertyListModel<PropertyModel, PropertyKey> customActionButtons) { - return new PropertyModel.Builder(CUSTOM_ACTION_BUTTONS, SIDE_SHEET_MAXIMIZE_BUTTON) + PropertyListModel<PropertyModel, PropertyKey> customActionButtons, + MinimizeButtonData minimizeButtonData) { + return new PropertyModel.Builder( + CUSTOM_ACTION_BUTTONS, SIDE_SHEET_MAXIMIZE_BUTTON, MINIMIZE_BUTTON) .with(CUSTOM_ACTION_BUTTONS, customActionButtons) .with(SIDE_SHEET_MAXIMIZE_BUTTON, new SideSheetMaximizeButtonData()) + .with(MINIMIZE_BUTTON, minimizeButtonData) .build(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java index 875c568..5043128 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java
@@ -7,6 +7,7 @@ import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.CUSTOM_ACTION_BUTTONS; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.DESCRIPTION; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.ICON; +import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.MINIMIZE_BUTTON; import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.SIDE_SHEET_MAXIMIZE_BUTTON; import android.support.annotation.DrawableRes; @@ -39,6 +40,13 @@ } else if (propertyKey == SIDE_SHEET_MAXIMIZE_BUTTON) { prepareSideSheetMaximizeButton(view, model.get(SIDE_SHEET_MAXIMIZE_BUTTON)); view.reinflateAndRepositionToolbarElements(); + } else if (propertyKey == MINIMIZE_BUTTON) { + view.setMinimizeButtonEnabled(model.get(MINIMIZE_BUTTON).visible); + view.reinflateAndRepositionToolbarElements(); + View minimizeButton = view.findViewById(R.id.custom_tabs_minimize_button); + if (minimizeButton != null) { + minimizeButton.setOnClickListener(model.get(MINIMIZE_BUTTON).clickListener); + } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayout.java index 3bffbae2..371c11af 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayout.java
@@ -578,7 +578,7 @@ initialRect = new Rect(); NewTabAnimationUtils.updateRects( - initialRect, finalRect, isRtl, /* isTopAligned= */ true); + NewTabAnimationUtils.RectStart.TOP, isRtl, initialRect, finalRect); cornerRadius = getContext() .getResources()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtils.java index 6e744eb..6965e4c9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtils.java
@@ -4,9 +4,11 @@ package org.chromium.chrome.browser.hub; import android.content.Context; +import android.graphics.Point; import android.graphics.Rect; import androidx.annotation.ColorInt; +import androidx.annotation.IntDef; import androidx.core.content.ContextCompat; import org.chromium.build.annotations.NullMarked; @@ -15,9 +17,31 @@ import org.chromium.chrome.browser.theme.ThemeModuleUtils; import org.chromium.components.browser_ui.styles.ChromeColors; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + /** Utilities related to new tab animations. */ @NullMarked public class NewTabAnimationUtils { + @IntDef({ + RectStart.TOP, + RectStart.TOP_TOOLBAR, + RectStart.BOTTOM, + RectStart.BOTTOM_TOOLBAR, + RectStart.CENTER + }) + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.SOURCE) + public @interface RectStart { + int TOP = 0; + int TOP_TOOLBAR = 1; + int BOTTOM = 2; + int BOTTOM_TOOLBAR = 3; + int CENTER = 4; + } + private static final float INITIAL_SCALE = 0.2f; private static final float FINAL_SCALE = 1.1f; @@ -47,45 +71,57 @@ * final {@link Rect} will be scaled by {@link #FINAL_SCALE}. This method takes into account RTL * and LTR layout directions. * + * @param rectStart Origin point where the animation starts. + * @param isRtl Whether the Layout direction is RTL or LTR. * @param initialRect The initial {@link Rect}. Its values will be overwritten by {@code * finalRect} * {@link #INITIAL_SCALE}. * @param finalRect The final {@link Rect} in which the {@code initialRect} will be based on. * Its values will be multiplied by {@link #FINAL_SCALE}. - * @param isRtl Whether the Layout direction is RTL or LTR. - * @param isTopAligned Whether the {@code initialRect} starts from the top or from the bottom of - * {@code finalRect}. */ public static void updateRects( - Rect initialRect, Rect finalRect, boolean isRtl, boolean isTopAligned) { + @RectStart int rectStart, boolean isRtl, Rect initialRect, Rect finalRect) { int initialWidth = Math.round(finalRect.width() * INITIAL_SCALE); int initialHeight = Math.round(finalRect.height() * INITIAL_SCALE); int finalWidth = Math.round(finalRect.width() * FINAL_SCALE); int finalHeight = Math.round(finalRect.height() * FINAL_SCALE); - int x; - if (isRtl) { - x = finalRect.right; - initialRect.left = x - initialWidth; - initialRect.right = x; - finalRect.left = x - finalWidth; + if (rectStart == RectStart.CENTER) { + Point center = new Point(finalRect.centerX(), finalRect.centerY()); + updateCenterRect(center, initialWidth, initialHeight, initialRect); + updateCenterRect(center, finalWidth, finalHeight, finalRect); } else { - x = finalRect.left; - initialRect.left = x; - initialRect.right = x + initialWidth; - finalRect.right = x + finalWidth; - } + int x; + if (isRtl) { + x = finalRect.right; + initialRect.left = x - initialWidth; + initialRect.right = x; + finalRect.left = x - finalWidth; + } else { + x = finalRect.left; + initialRect.left = x; + initialRect.right = x + initialWidth; + finalRect.right = x + finalWidth; + } - int y; - if (isTopAligned) { - y = finalRect.top; - initialRect.top = y; - initialRect.bottom = y + initialHeight; - finalRect.bottom = y + finalHeight; - } else { - y = finalRect.bottom; - initialRect.top = y - initialHeight; - initialRect.bottom = y; - finalRect.top = y - finalHeight; + int y; + if (rectStart == RectStart.TOP || rectStart == RectStart.TOP_TOOLBAR) { + y = finalRect.top; + initialRect.top = y; + initialRect.bottom = y + initialHeight; + finalRect.bottom = y + finalHeight; + } else { + y = finalRect.bottom; + initialRect.top = y - initialHeight; + initialRect.bottom = y; + finalRect.top = y - finalHeight; + } } } + + private static void updateCenterRect(Point center, int width, int height, Rect rect) { + rect.left = center.x - width / 2; + rect.right = rect.left + width; + rect.top = center.y - height / 2; + rect.bottom = rect.top + height; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtilsUnitTest.java b/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtilsUnitTest.java index 61df4d5..341710c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtilsUnitTest.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtilsUnitTest.java
@@ -21,7 +21,7 @@ Rect finalRect = new Rect(-200, -100, 150, 200); NewTabAnimationUtils.updateRects( - initialRect, finalRect, /* isRtl= */ true, /* isTopAligned= */ true); + NewTabAnimationUtils.RectStart.TOP, /* isRtl= */ true, initialRect, finalRect); Rect expectedInitialRect = new Rect(80, -100, 150, -40); Rect expectedFinalRect = new Rect(-235, -100, 150, 230); @@ -36,7 +36,7 @@ Rect finalRect = new Rect(-200, -100, 150, 200); NewTabAnimationUtils.updateRects( - initialRect, finalRect, /* isRtl= */ true, /* isTopAligned= */ false); + NewTabAnimationUtils.RectStart.BOTTOM, /* isRtl= */ true, initialRect, finalRect); Rect expectedInitialRect = new Rect(80, 140, 150, 200); Rect expectedFinalRect = new Rect(-235, -130, 150, 200); @@ -51,7 +51,7 @@ Rect finalRect = new Rect(-200, -100, 150, 200); NewTabAnimationUtils.updateRects( - initialRect, finalRect, /* isRtl= */ false, /* isTopAligned= */ true); + NewTabAnimationUtils.RectStart.TOP, /* isRtl= */ false, initialRect, finalRect); Rect expectedInitialRect = new Rect(-200, -100, -130, -40); Rect expectedFinalRect = new Rect(-200, -100, 185, 230); @@ -66,7 +66,7 @@ Rect finalRect = new Rect(-200, -100, 150, 200); NewTabAnimationUtils.updateRects( - initialRect, finalRect, /* isRtl= */ false, /* isTopAligned= */ false); + NewTabAnimationUtils.RectStart.BOTTOM, /* isRtl= */ false, initialRect, finalRect); Rect expectedInitialRect = new Rect(-200, 140, -130, 200); Rect expectedFinalRect = new Rect(-200, -130, 185, 200); @@ -74,4 +74,19 @@ assertEquals(expectedInitialRect, initialRect); assertEquals(expectedFinalRect, finalRect); } + + @Test + public void testUpdateRects_centerAligned() { + Rect initialRect = new Rect(); + Rect finalRect = new Rect(-30, -10, 40, 30); + + NewTabAnimationUtils.updateRects( + NewTabAnimationUtils.RectStart.CENTER, /* isRtl= */ false, initialRect, finalRect); + + Rect expectedInitialRect = new Rect(-2, 6, 12, 14); + Rect expectedFinalRect = new Rect(-33, -12, 44, 32); + + assertEquals(expectedInitialRect, initialRect); + assertEquals(expectedFinalRect, finalRect); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncher.java index 7212765..bd25a837 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncher.java
@@ -25,7 +25,6 @@ import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.browserservices.intents.SessionHolder; import org.chromium.chrome.browser.customtabs.CustomTabsConnection; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.components.externalauth.ExternalAuthUtils; @@ -126,9 +125,7 @@ */ public static void updateComponentEnabledState(Profile profile) { // TODO(peconn): Update state in a few more places (eg CustomTabsConnection#warmup). - boolean enable = - ChromeFeatureList.isEnabled(ChromeFeatureList.ALLOW_NEW_INCOGNITO_TAB_INTENTS) - && IncognitoUtils.isIncognitoModeEnabled(profile); + boolean enable = IncognitoUtils.isIncognitoModeEnabled(profile); PostTask.postTask(TaskTraits.USER_VISIBLE, () -> setComponentEnabled(enable)); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionController.java b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionController.java index 0f9ce4e..b1132b1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionController.java
@@ -68,6 +68,7 @@ private ObservableSupplier<Tab> mTabSupplier; private final AdaptiveToolbarButtonController mAdaptiveToolbarButtonController; private CurrentTabObserver mCurrentTabObserver; + private SignalAccumulator mSignalAccumulator; // The action provider backends. protected final List<ActionProvider> mActionProviders = new ArrayList<>(); @@ -140,6 +141,15 @@ removeProviders(); } + /** + * @return Whether the page is price insights eligible. The eligibility represents the most + * recent price insights state, which could be from a previous page load or tab. Default is + * false. + */ + public boolean hasPriceInsights() { + return mSignalAccumulator == null ? false : mSignalAccumulator.hasPriceInsights(); + } + private void removeProviders() { for (ActionProvider provider : mActionProviders) { provider.destroy(); @@ -167,27 +177,27 @@ private void collectSignals(Tab tab) { if (mActionProviders.isEmpty()) return; - final SignalAccumulator signalAccumulator = + mSignalAccumulator = new SignalAccumulator(new Handler(Looper.getMainLooper()), tab, mActionProviders); - signalAccumulator.getSignals(() -> findBestAction(signalAccumulator)); + mSignalAccumulator.getSignals(this::findBestAction); } - private void findBestAction(SignalAccumulator signalAccumulator) { + private void findBestAction() { Tab tab = getValidActiveTab(); if (tab == null) return; InputContext inputContext = new InputContext(); inputContext.addEntry( Constants.CONTEXTUAL_PAGE_ACTIONS_PRICE_TRACKING_INPUT, - ProcessedValue.fromFloat(signalAccumulator.hasPriceTracking() ? 1.0f : 0.0f)); + ProcessedValue.fromFloat(mSignalAccumulator.hasPriceTracking() ? 1.0f : 0.0f)); inputContext.addEntry( Constants.CONTEXTUAL_PAGE_ACTIONS_READER_MODE_INPUT, - ProcessedValue.fromFloat(signalAccumulator.hasReaderMode() ? 1.0f : 0.0f)); + ProcessedValue.fromFloat(mSignalAccumulator.hasReaderMode() ? 1.0f : 0.0f)); inputContext.addEntry( Constants.CONTEXTUAL_PAGE_ACTIONS_PRICE_INSIGHTS_INPUT, - ProcessedValue.fromFloat(signalAccumulator.hasPriceInsights() ? 1.0f : 0.0f)); + ProcessedValue.fromFloat(mSignalAccumulator.hasPriceInsights() ? 1.0f : 0.0f)); inputContext.addEntry( Constants.CONTEXTUAL_PAGE_ACTIONS_DISCOUNTS_INPUT, - ProcessedValue.fromFloat(signalAccumulator.hasDiscounts() ? 1.0f : 0.0f)); + ProcessedValue.fromFloat(mSignalAccumulator.hasDiscounts() ? 1.0f : 0.0f)); inputContext.addEntry("url", ProcessedValue.fromGURL(tab.getUrl())); ContextualPageActionControllerJni.get()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index a532550..ebd0cc3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -450,6 +450,14 @@ private final CallbackController mCallbackController = new CallbackController(); @Override + public boolean invokeBackActionOnEscape() { + // Escape key presses should not navigate back in tab history. We do not also implement + // a custom {@link BackPressHandler#handleEscPress()} since we don't want anything to + // happen and for the manager to move to the next priority handler. + return false; + } + + @Override public int handleBackPress() { mIsInProgress = false; if (mIsGestureMode && mBackGestureInProgress) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/AdaptiveToolbarUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/AdaptiveToolbarUiCoordinator.java index bdae239..f337a598 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/AdaptiveToolbarUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/AdaptiveToolbarUiCoordinator.java
@@ -287,11 +287,21 @@ return mButtonDataProviders; } + /** Returns {@link ContextualPageActionController} used for adaptive toolbar button. */ + public ContextualPageActionController getContextualPageActionController() { + return mContextualPageActionController; + } + /** Returns {@link VoiceToolbarButtonController} used for voice search button. */ public VoiceToolbarButtonController getVoiceToolbarButtonController() { return mVoiceToolbarButtonController; } + /** Invokes Price Insights UI. */ + public void runPriceInsightsAction() { + mAdaptiveToolbarButtonController.runPriceInsightsAction(); + } + /** Destroy internally used objects. */ public void destroy() { if (mCurrentTabPriceTrackingStateSupplier != null) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index 836685ab..c2981a9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -99,6 +99,7 @@ import org.chromium.base.BuildInfo; import org.chromium.base.ContextUtils; import org.chromium.base.IntentUtils; +import org.chromium.base.ObserverList; import org.chromium.base.ServiceLoaderUtil; import org.chromium.base.ThreadUtils; import org.chromium.base.library_loader.LibraryLoader; @@ -136,6 +137,7 @@ import org.chromium.chrome.browser.contextmenu.ContextMenuCoordinator; import org.chromium.chrome.browser.customtabs.CustomTabActivityLifecycleUmaTracker.ClientIdentifierType; import org.chromium.chrome.browser.customtabs.CustomTabsIntentTestUtils.OnFinishedForTest; +import org.chromium.chrome.browser.customtabs.content.CustomTabActivityNavigationController; import org.chromium.chrome.browser.customtabs.content.CustomTabActivityNavigationController.FinishReason; import org.chromium.chrome.browser.customtabs.features.partialcustomtab.PartialCustomTabBaseStrategy; import org.chromium.chrome.browser.customtabs.features.partialcustomtab.PartialCustomTabDisplayManager; @@ -179,6 +181,7 @@ import org.chromium.components.browser_ui.widget.CoordinatorLayoutForPointer; import org.chromium.components.browser_ui.widget.TintedDrawable; import org.chromium.components.browser_ui.widget.gesture.BackPressHandler; +import org.chromium.components.browser_ui.widget.gesture.OnSystemNavigationObserver; import org.chromium.components.content_settings.CookieControlsMode; import org.chromium.components.embedder_support.util.Origin; import org.chromium.components.page_info.PageInfoController; @@ -2872,6 +2875,27 @@ @Test @SmallTest + @Features.EnableFeatures({ChromeFeatureList.CCT_PREDICTIVE_BACK_GESTURE}) + public void + testBackPressManagerAddsSystemNavigationObserver_WhenPredictiveBackGestureIsSupported() { + CustomTabActivityNavigationController.enablePredictiveBackGestureForTesting(); + Context context = getInstrumentation().getTargetContext().getApplicationContext(); + Intent intent = CustomTabsIntentTestUtils.createMinimalCustomTabIntent(context, mTestPage); + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + + ObserverList<OnSystemNavigationObserver> onSystemNavigationObservers = + getActivity().getBackPressManagerForTesting().getObserverListForTesting(); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertTrue( + onSystemNavigationObservers.hasObserver( + getActivity().getCustomTabActivityNavigationController())); + }); + } + + @Test + @SmallTest public void disableShareEntriesForAutomotive() { mAutomotiveRule.setIsAutomotive(true); Intent intent = createMinimalCustomTabIntent();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncherTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncherTest.java index ae28864..a59f831e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncherTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncherTest.java
@@ -28,12 +28,10 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; -import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.customtabs.CustomTabsConnection; import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; @@ -47,7 +45,6 @@ /** Tests for {@link IncognitoTabLauncher}. */ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -@EnableFeatures({ChromeFeatureList.ALLOW_NEW_INCOGNITO_TAB_INTENTS}) public class IncognitoTabLauncherTest { @Rule public final FreshCtaTransitTestRule mActivityRule =
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegateUnitTest.java index d94a6d7..bcf75498 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegateUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegateUnitTest.java
@@ -46,6 +46,7 @@ import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.readaloud.ReadAloudController; +import org.chromium.chrome.browser.segmentation_platform.ContextualPageActionController; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; @@ -165,6 +166,7 @@ /* isOffTheRecord= */ false, /* isStartIconMenu= */ true, mReadAloudControllerSupplier, + /* contextualPageActionControllerSupplier */ () -> null, /* hasClientPackage= */ false); Menu menu = createMenu(context, delegate.getAppMenuLayoutId()); delegate.prepareMenu(menu, null); @@ -173,6 +175,42 @@ } @Test + @EnableFeatures({ChromeFeatureList.CCT_ADAPTIVE_BUTTON}) + public void enablePriceInsightsMenu() { + ContextualPageActionController cpac = mock(ContextualPageActionController.class); + doReturn(true).when(cpac).hasPriceInsights(); + + Context context = + new ContextThemeWrapper( + ContextUtils.getApplicationContext(), R.style.Theme_BrowserUI_DayNight); + var delegate = + new CustomTabAppMenuPropertiesDelegate( + context, + mActivityTabProvider, + mMultiWindowModeStateDispatcher, + mTabModelSelector, + mToolbarManager, + mDecorView, + mBookmarkModelSupplier, + mVerifier, + CustomTabsUiType.AUTH_TAB, + /* menuEntries= */ new ArrayList<String>(), + /* isOpenedByChrome= */ true, + /* showShare= */ true, + /* showStar= */ true, + /* showDownload= */ true, + /* isIncognitoBranded= */ false, + /* isOffTheRecord= */ false, + /* isStartIconMenu= */ true, + mReadAloudControllerSupplier, + () -> cpac, + /* hasClientPackage= */ false); + Menu menu = createMenu(context, delegate.getAppMenuLayoutId()); + delegate.prepareMenu(menu, null); + assertTrue(isMenuVisible(menu, R.id.price_insights_menu_id)); + } + + @Test public void authTabMenuItemVisibility() { Context context = new ContextThemeWrapper( @@ -197,6 +235,7 @@ /* isOffTheRecord= */ false, /* isStartIconMenu= */ true, mReadAloudControllerSupplier, + /* contextualPageActionControllerSupplier */ () -> null, /* hasClientPackage= */ false); Menu menu = createMenu(context, delegate.getAppMenuLayoutId()); delegate.prepareMenu(menu, null); @@ -236,6 +275,7 @@ /* isOffTheRecord= */ false, /* isStartIconMenu= */ true, mReadAloudControllerSupplier, + /* contextualPageActionControllerSupplier */ () -> null, /* hasClientPackage= */ false); Menu menu = createMenu(context, delegate.getAppMenuLayoutId()); delegate.prepareMenu(menu, null);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarUnitTest.java index 7eea09c..8ef712b 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarUnitTest.java
@@ -211,8 +211,12 @@ CustomTabToolbarButtonsCoordinator.getCustomActionButtonsModel( mActivity, mIntentDataProvider, params -> {}); mToolbar.setCustomActionButtonsListModel(model); + // Minimize button is enabled by default. + mToolbar.setMinimizeButtonEnabled(true); + mToolbar.reinflateAndRepositionToolbarElements(); + } else { + mToolbar.setFeatureOverridesManager(mFeatureOverridesManager); } - mToolbar.setFeatureOverridesManager(mFeatureOverridesManager); mLocationBar = (CustomTabLocationBar)
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt index 5b74f799..9795381 100644 --- a/chrome/android/profiles/arm.newest.txt +++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-138.0.7161.0_rc-r1-merged.afdo.bz2 +chromeos-chrome-arm-138.0.7166.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 5734eb32..b3e118f7 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-138.0.7164.0_rc-r1-merged.afdo.bz2 +chromeos-chrome-amd64-138.0.7166.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 3f1e31a1..0176f00 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -18593,6 +18593,9 @@ <message name="IDS_READING_LIST_TOAST_BUTTON" desc="Button on a toast notification that allows a user to open a reading list entry."> Open </message> + <message name="IDS_CLOSE_PINNED_TAB_TOAST_BODY" desc="Text on a toast notification that is shown when a pinned tab is being closed."> + Press <ph name="SHORTCUT_TEXT">$1<ex>⌘ + W</ex></ph> again to close the pinned tab + </message> <message name="IDS_TOAST_CLOSE_TOOLTIP" desc="Tooltip for the X button on a toast notification that closes the toast."> Close </message>
diff --git a/chrome/app/generated_resources_grd/IDS_CLOSE_PINNED_TAB_TOAST_BODY.png.sha1 b/chrome/app/generated_resources_grd/IDS_CLOSE_PINNED_TAB_TOAST_BODY.png.sha1 new file mode 100644 index 0000000..445a1220 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_CLOSE_PINNED_TAB_TOAST_BODY.png.sha1
@@ -0,0 +1 @@ +c4c4f529a56f15b99f0c6cc47437b9c66d4b840a \ No newline at end of file
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp index 5b930bf..ac6616bb 100644 --- a/chrome/app/os_settings_strings.grdp +++ b/chrome/app/os_settings_strings.grdp
@@ -271,6 +271,9 @@ <message name="IDS_OS_SETTINGS_FIRMWARE_UP_TO_DATE_DESCRIPTION" desc="Sublabel shown when no firmware updates are available."> Firmware is up to date </message> + <message name="IDS_OS_SETTINGS_FIRMWARE_DISABLED_DESCRIPTION" desc="Sublabel shown when firmware updates are disabled."> + Firmware updates are disabled by your administrator. + </message> <message name="IDS_OS_SETTINGS_FIRMWARE_UPDATE_AVAILABLE_DESCRIPTION" desc="Sublabel shown when firmware updates are available."> Update available </message> @@ -779,6 +782,18 @@ <message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_KOREAN_SYLLABLE_INPUT"> Input a syllable at a time </message> + <message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_CLEAR_PERSONALIZATION_DATA" desc="Label for a heading/button to clear persionalized data from the Japanese IME"> + Clear personalization data + </message> + <message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_DELETE_ITEMS" desc="Label for a form for users to select the type of personalized data they wany to Delete"> + Delete the following items: + </message> + <message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_CONVERSATION_HISTORY" desc="One of the types of personalization data that can be cleared from the Japanese IME"> + Conversation history + </message> + <message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_SUGGESTION_HISTORY" desc="One of the types of personalization data that can be cleared from the Japanese IME"> + Suggestion history + </message> <message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_INPUT_MODE" desc="The label for the Input Mode section of the Japanese keyboad settings. As an example, it could be set to have a value of Romaji or Kana. In Japanese, this string should be 'ローマ字入力・かな入力'."> Input mode </message>
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_FIRMWARE_DISABLED_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_FIRMWARE_DISABLED_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..5381230 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_FIRMWARE_DISABLED_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +a0a3c173a22b590dd7bae9abfd6eea915212552a \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_CLEAR_PERSONALIZATION_DATA.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_CLEAR_PERSONALIZATION_DATA.png.sha1 new file mode 100644 index 0000000..ccfe6b7 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_CLEAR_PERSONALIZATION_DATA.png.sha1
@@ -0,0 +1 @@ +27f24cce4d51d472931bb2c29107edb8931439ba \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_CONVERSATION_HISTORY.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_CONVERSATION_HISTORY.png.sha1 new file mode 100644 index 0000000..ccfe6b7 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_CONVERSATION_HISTORY.png.sha1
@@ -0,0 +1 @@ +27f24cce4d51d472931bb2c29107edb8931439ba \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_DELETE_ITEMS.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_DELETE_ITEMS.png.sha1 new file mode 100644 index 0000000..ccfe6b7 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_DELETE_ITEMS.png.sha1
@@ -0,0 +1 @@ +27f24cce4d51d472931bb2c29107edb8931439ba \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_SUGGESTION_HISTORY.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_SUGGESTION_HISTORY.png.sha1 new file mode 100644 index 0000000..ccfe6b7 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_SUGGESTION_HISTORY.png.sha1
@@ -0,0 +1 @@ +27f24cce4d51d472931bb2c29107edb8931439ba \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 68adbda6..5af9213 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1019,6 +1019,8 @@ "password_manager/password_change/change_password_form_finder.h", "password_manager/password_change/change_password_form_waiter.cc", "password_manager/password_change/change_password_form_waiter.h", + "password_manager/password_change/model_quality_logs_uploader.cc", + "password_manager/password_change/model_quality_logs_uploader.h", "password_manager/password_change_delegate.h", "password_manager/password_change_delegate_impl.cc", "password_manager/password_change_delegate_impl.h", @@ -4539,6 +4541,7 @@ "//chrome/browser/importer:impl", "//chrome/browser/ui/webui/commerce:impl", "//chrome/browser/ui/webui/settings:impl", + "//chrome/browser/ui/webui/new_tab_footer:impl", "//chrome/browser/ui/webui/signin:signin_impl", "//chrome/browser/ui/webui/signin:signin_utils_impl", "//chrome/browser/ui/webui/signin:login_impl",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 119e0f4e..77a4ff9c 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -3827,32 +3827,6 @@ #endif // BUILDFLAG(IS_ANDROID) -const FeatureEntry::FeatureParam - kPrerender2WarmUpCompositorTriggerPointDidCommitLoad[] = { - {"trigger_point", "did_commit_load"}}; -const FeatureEntry::FeatureParam - kPrerender2WarmUpCompositorTriggerPointDidDispatchDOMContentLoadedEvent[] = - {{"trigger_point", "did_dispatch_dom_content_loaded_event"}}; -const FeatureEntry::FeatureParam - kPrerender2WarmUpCompositorTriggerPointDidFinishLoad[] = { - {"trigger_point", "did_finish_load"}}; -const FeatureEntry::FeatureVariation - kPrerender2WarmUpCompositorTriggerPointVariations[] = { - {"(on DidCommitLoad)", - kPrerender2WarmUpCompositorTriggerPointDidCommitLoad, - std::size(kPrerender2WarmUpCompositorTriggerPointDidCommitLoad), - nullptr}, - {"(on DOMContentLoaded)", - kPrerender2WarmUpCompositorTriggerPointDidDispatchDOMContentLoadedEvent, - std::size( - kPrerender2WarmUpCompositorTriggerPointDidDispatchDOMContentLoadedEvent), - nullptr}, - {"(on DidFinishLoad)", - kPrerender2WarmUpCompositorTriggerPointDidFinishLoad, - std::size(kPrerender2WarmUpCompositorTriggerPointDidFinishLoad), - nullptr}, -}; - const FeatureEntry::FeatureParam kGroupSuggestionEnableRecentlyOpenedOnly[] = { {"group_suggestion_enable_recently_opened", "true"}, {"group_suggestion_enable_switch_between", "false"}, @@ -4864,9 +4838,6 @@ {"enable-gpu-rasterization", flag_descriptions::kGpuRasterizationName, flag_descriptions::kGpuRasterizationDescription, kOsAll, MULTI_VALUE_TYPE(kEnableGpuRasterizationChoices)}, - {"enable-fontations-backend", flag_descriptions::kFontationsFontBackendName, - flag_descriptions::kFontationsFontBackendDescription, kOsAll, - FEATURE_VALUE_TYPE(blink::features::kFontationsFontBackend)}, {"enable-experimental-web-platform-features", flag_descriptions::kExperimentalWebPlatformFeaturesName, flag_descriptions::kExperimentalWebPlatformFeaturesDescription, kOsAll, @@ -8990,18 +8961,6 @@ FEATURE_VALUE_TYPE( blink::features::kPrerender2EarlyDocumentLifecycleUpdate)}, - {"warm-up-compositor", flag_descriptions::kWarmUpCompositorName, - flag_descriptions::kWarmUpCompositorDescription, kOsAll, - FEATURE_VALUE_TYPE(features::kWarmUpCompositor)}, - - {"prerender2-warm-up-compositor", - flag_descriptions::kPrerender2WarmUpCompositorName, - flag_descriptions::kPrerender2WarmUpCompositorDescription, kOsAll, - FEATURE_WITH_PARAMS_VALUE_TYPE( - blink::features::kPrerender2WarmUpCompositor, - kPrerender2WarmUpCompositorTriggerPointVariations, - "Prerender2WarmUpCompositor")}, - #if BUILDFLAG(IS_ANDROID) {"prerender2-new-tab-page-android", flag_descriptions::kPrerender2ForNewTabPageAndroidName, @@ -10867,6 +10826,11 @@ FEATURE_VALUE_TYPE( autofill::features::kAutofillEnableSyncingOfPixBankAccounts)}, + {"enable-pix-account-linking", + flag_descriptions::kEnablePixAccountLinkingName, + flag_descriptions::kEnablePixAccountLinkingDescription, kOsAndroid, + FEATURE_VALUE_TYPE(payments::facilitated::kEnablePixAccountLinking)}, + {"enable-pix-payments", flag_descriptions::kEnablePixPaymentsName, flag_descriptions::kEnablePixPaymentsDescription, kOsAndroid, FEATURE_VALUE_TYPE(payments::facilitated::kEnablePixPayments)}, @@ -12427,6 +12391,12 @@ #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || // BUILDFLAG(IS_CHROME_OS) +#if !BUILDFLAG(IS_ANDROID) + {"pinned-tab-toast-on-close", flag_descriptions::kPinnedTabToastOnCloseName, + flag_descriptions::kPinnedTabToastOnCloseDescription, kOsDesktop, + FEATURE_VALUE_TYPE(toast_features::kPinnedTabToastOnClose)}, +#endif // !BUILDFLAG(IS_ANDROID) + // Add new entries above this line. // NOTE: Adding a new flag requires adding a corresponding entry to enum
diff --git a/chrome/browser/accessibility/accessibility_labels_service.cc b/chrome/browser/accessibility/accessibility_labels_service.cc index d2b2ae2..9a6b3a383 100644 --- a/chrome/browser/accessibility/accessibility_labels_service.cc +++ b/chrome/browser/accessibility/accessibility_labels_service.cc
@@ -26,7 +26,6 @@ #include "content/public/browser/scoped_accessibility_mode.h" #include "content/public/browser/web_contents.h" #include "google_apis/google_api_keys.h" -#include "services/data_decoder/public/cpp/data_decoder.h" #include "services/image_annotation/image_annotation_service.h" #include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_enums.mojom.h" @@ -59,12 +58,6 @@ ~ImageAnnotatorClient() override = default; - // image_annotation::Annotator::Client implementation: - void BindJsonParser(mojo::PendingReceiver<data_decoder::mojom::JsonParser> - receiver) override { - data_decoder_.GetService()->BindJsonParser(std::move(receiver)); - } - std::vector<std::string> GetAcceptLanguages() override { std::vector<std::string> accept_languages; const PrefService* pref_service = profile_->GetPrefs(); @@ -113,7 +106,6 @@ private: const raw_ptr<Profile> profile_; - data_decoder::DataDecoder data_decoder_; }; } // namespace
diff --git a/chrome/browser/actor/actor_test_util.cc b/chrome/browser/actor/actor_test_util.cc index 17ed264e..6c78fe9 100644 --- a/chrome/browser/actor/actor_test_util.cc +++ b/chrome/browser/actor/actor_test_util.cc
@@ -65,7 +65,9 @@ TypeAction* type_action = action.add_action_information()->mutable_type(); type_action->mutable_target()->set_content_node_id(content_node_id); type_action->set_text(text); - type_action->set_mode(TypeAction_TypeMode::TypeAction_TypeMode_APPEND); + // TODO(crbug.com/409570203): Tests should set a mode. + type_action->set_mode( + TypeAction_TypeMode::TypeAction_TypeMode_UNKNOWN_TYPE_MODE); type_action->set_follow_by_enter(follow_by_enter); return action; }
diff --git a/chrome/browser/actor/tools/tools_browsertest.cc b/chrome/browser/actor/tools/tools_browsertest.cc index d1604c9..987fa80 100644 --- a/chrome/browser/actor/tools/tools_browsertest.cc +++ b/chrome/browser/actor/tools/tools_browsertest.cc
@@ -433,6 +433,64 @@ EXPECT_TRUE(result.Get()); } +// Ensure that the default mode is for the type tool to replace any existing +// text in the targeted element. +IN_PROC_BROWSER_TEST_F(ActorToolsTest, TypeTool_ReplacesText) { + const GURL url = embedded_test_server()->GetURL("/actor/input.html"); + ASSERT_TRUE(content::NavigateToURL(web_contents(), url)); + + ASSERT_TRUE(ExecJs(web_contents(), + "document.getElementById('input').value = 'foo bar'")); + std::optional<int> input_id = GetDOMNodeId(*main_frame(), "#input"); + ASSERT_TRUE(input_id); + + std::string typed_string = "abc"; + BrowserAction action = + MakeType(input_id.value(), typed_string, /*follow_by_enter=*/false); + + TestFuture<bool> result; + actor_coordinator().Act(action, result.GetCallback()); + EXPECT_TRUE(result.Get()); + EXPECT_EQ(typed_string, + EvalJs(web_contents(), "document.getElementById('input').value")); +} + +// Ensure that if the page moves focus immediately to a different input box, the +// type tool correctly operates on the new input box. +IN_PROC_BROWSER_TEST_F(ActorToolsTest, TypeTool_FocusMovesFocus) { + const GURL url = embedded_test_server()->GetURL("/actor/input.html"); + ASSERT_TRUE(content::NavigateToURL(web_contents(), url)); + + // Setup the first input box to immediately move focus to the second input + // box. Ensure the existing text in the second box is replaced. + ASSERT_TRUE(ExecJs(web_contents(), + R"JS( + let input = document.getElementById('input'); + let input2 = document.getElementById('input2'); + input2.value = 'foo bar'; + input.addEventListener('focus', () => { + input2.focus(); + }); + )JS")); + std::optional<int> input_id = GetDOMNodeId(*main_frame(), "#input"); + ASSERT_TRUE(input_id); + + std::string typed_string = "abc"; + BrowserAction action = + MakeType(input_id.value(), typed_string, /*follow_by_enter=*/false); + + TestFuture<bool> result; + actor_coordinator().Act(action, result.GetCallback()); + EXPECT_TRUE(result.Get()); + + // Since focusing the first input causes the second input to become focused, + // the tool should operate on the second input. + EXPECT_EQ("", + EvalJs(web_contents(), "document.getElementById('input').value")); + EXPECT_EQ(typed_string, + EvalJs(web_contents(), "document.getElementById('input2').value")); +} + // =============================================== // Mouse Move Tool // ===============================================
diff --git a/chrome/browser/apps/app_service/BUILD.gn b/chrome/browser/apps/app_service/BUILD.gn index 22021d7b..b7335ae 100644 --- a/chrome/browser/apps/app_service/BUILD.gn +++ b/chrome/browser/apps/app_service/BUILD.gn
@@ -69,6 +69,7 @@ "//chrome/browser/resources:app_icon_resources", "//chrome/browser/sync", "//chrome/browser/ui:browser_navigator_params_headers", + "//chrome/browser/ui/browser_window", "//chrome/browser/ui/tabs:tab_enums", "//chrome/browser/web_applications", "//chrome/browser/web_applications:features",
diff --git a/chrome/browser/apps/app_service/launch_utils.cc b/chrome/browser/apps/app_service/launch_utils.cc index 9c2dc8e..e3768dd 100644 --- a/chrome/browser/apps/app_service/launch_utils.cc +++ b/chrome/browser/apps/app_service/launch_utils.cc
@@ -19,10 +19,10 @@ #include "chrome/browser/apps/app_service/intent_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/web_applications/link_capturing_features.h" #include "chrome/common/chrome_switches.h" @@ -33,6 +33,8 @@ #include "components/services/app_service/public/cpp/app_update.h" #include "components/services/app_service/public/cpp/intent_util.h" #include "components/sessions/core/session_id.h" +#include "components/tabs/public/tab_interface.h" +#include "content/public/browser/web_contents.h" #include "extensions/common/constants.h" #include "mojo/public/cpp/bindings/struct_ptr.h" #include "storage/browser/file_system/file_system_url.h" @@ -267,12 +269,14 @@ return SessionID::InvalidValue().id(); } - Browser* browser = chrome::FindBrowserWithTab(web_contents); + const tabs::TabInterface* tab = + tabs::TabInterface::GetFromContents(web_contents); + const BrowserWindowInterface* browser = tab->GetBrowserWindowInterface(); if (!browser) { return SessionID::InvalidValue().id(); } - return browser->session_id().id(); + return browser->GetSessionID().id(); } #if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.h b/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.h index fee3712..95dd498 100644 --- a/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.h +++ b/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.h
@@ -88,17 +88,17 @@ extern const int kDurationBuckets; extern const int kUsageTimeBuckets; -constexpr char kArcHistogramName[] = "Arc"; -constexpr char kCrostiniHistogramName[] = "Crostini"; -constexpr char kChromeAppHistogramName[] = "ChromeApp"; -constexpr char kWebAppHistogramName[] = "WebApp"; -constexpr char kPluginVmHistogramName[] = "PluginVm"; -constexpr char kRemoteHistogramName[] = "RemoteApp"; -constexpr char kBorealisHistogramName[] = "Borealis"; -constexpr char kSystemWebAppHistogramName[] = "SystemWebApp"; -constexpr char kChromeBrowserHistogramName[] = "ChromeBrowser"; -constexpr char kExtensionHistogramName[] = "Extension"; -constexpr char kBruschettaHistogramName[] = "Bruschetta"; +inline constexpr char kArcHistogramName[] = "Arc"; +inline constexpr char kCrostiniHistogramName[] = "Crostini"; +inline constexpr char kChromeAppHistogramName[] = "ChromeApp"; +inline constexpr char kWebAppHistogramName[] = "WebApp"; +inline constexpr char kPluginVmHistogramName[] = "PluginVm"; +inline constexpr char kRemoteHistogramName[] = "RemoteApp"; +inline constexpr char kBorealisHistogramName[] = "Borealis"; +inline constexpr char kSystemWebAppHistogramName[] = "SystemWebApp"; +inline constexpr char kChromeBrowserHistogramName[] = "ChromeBrowser"; +inline constexpr char kExtensionHistogramName[] = "Extension"; +inline constexpr char kBruschettaHistogramName[] = "Bruschetta"; // Determines what app type a web app should be logged as based on its launch // container and app id. In particular, web apps in tabs are logged as part of
diff --git a/chrome/browser/apps/app_service/policy_util.h b/chrome/browser/apps/app_service/policy_util.h index 186fae33..f1bbedd8 100644 --- a/chrome/browser/apps/app_service/policy_util.h +++ b/chrome/browser/apps/app_service/policy_util.h
@@ -35,7 +35,7 @@ namespace apps_util { #if BUILDFLAG(IS_CHROMEOS) -constexpr char kVirtualTaskPrefix[] = "VirtualTask/"; +inline constexpr char kVirtualTaskPrefix[] = "VirtualTask/"; #endif // BUILDFLAG(IS_CHROMEOS) // Checks whether |policy_id| specifies a Chrome App.
diff --git a/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.h b/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.h index 774c78b..42a89ffa 100644 --- a/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.h +++ b/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.h
@@ -11,7 +11,7 @@ // The removable media path in ChromeOS. This is the actual directory to be // watched. -constexpr base::FilePath::CharType kCrosRemovableMediaDir[] = +inline constexpr base::FilePath::CharType kCrosRemovableMediaDir[] = FILE_PATH_LITERAL("/media/removable"); // The prefix for device label used in Android paths for removable media.
diff --git a/chrome/browser/ash/arc/input_overlay/constants.h b/chrome/browser/ash/arc/input_overlay/constants.h index 0f28439..c1b867a6 100644 --- a/chrome/browser/ash/arc/input_overlay/constants.h +++ b/chrome/browser/ash/arc/input_overlay/constants.h
@@ -29,7 +29,7 @@ // Maximum of actions size. inline constexpr size_t kMaxActionCount = 50; -constexpr char16_t kUnknownBind[] = u"?"; +inline constexpr char16_t kUnknownBind[] = u"?"; // Directions from up, left, down, right. constexpr int kDirection[kActionMoveKeysSize][kAxisSize] = {{0, -1},
diff --git a/chrome/browser/ash/arc/input_overlay/ui/delete_edit_shortcut.cc b/chrome/browser/ash/arc/input_overlay/ui/delete_edit_shortcut.cc index 1da39182..761f420 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/delete_edit_shortcut.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/delete_edit_shortcut.cc
@@ -47,7 +47,7 @@ // TODO(b/329895423): Add shadow. views::BubbleBorder::NO_SHADOW), controller_(controller) { - set_background_color(cros_tokens::kCrosSysSystemBaseElevatedOpaque); + SetBackgroundColor(cros_tokens::kCrosSysSystemBaseElevatedOpaque); set_margins(gfx::Insets(12)); set_corner_radius(20); set_close_on_deactivate(false);
diff --git a/chrome/browser/ash/arc/input_overlay/ui/rich_nudge.cc b/chrome/browser/ash/arc/input_overlay/ui/rich_nudge.cc index 27633e8..e2ac218 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/rich_nudge.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/rich_nudge.cc
@@ -35,7 +35,7 @@ views::BubbleBorder::FLOAT, views::BubbleBorder::NO_SHADOW) { set_parent_window(parent_window); - set_background_color(SK_ColorTRANSPARENT); + SetBackgroundColor(SK_ColorTRANSPARENT); set_margins(gfx::Insets()); set_close_on_deactivate(false); set_accept_events(false);
diff --git a/chrome/browser/ash/auth/BUILD.gn b/chrome/browser/ash/auth/BUILD.gn index 697db1ef..1ffce35 100644 --- a/chrome/browser/ash/auth/BUILD.gn +++ b/chrome/browser/ash/auth/BUILD.gn
@@ -22,7 +22,6 @@ deps = [ "//ash/constants", "//base", - "//chrome/browser:browser_process", "//chrome/browser/ash/login/quick_unlock", "//chrome/browser/ash/login/users", "//chrome/browser/ash/profiles",
diff --git a/chrome/browser/ash/auth/DEPS b/chrome/browser/ash/auth/DEPS index 0804487..36f5e29 100644 --- a/chrome/browser/ash/auth/DEPS +++ b/chrome/browser/ash/auth/DEPS
@@ -13,6 +13,5 @@ "+chrome/browser/ash/login/quick_unlock", "+chrome/browser/ash/login/users", "+chrome/browser/ash/profiles", - "+chrome/browser/browser_process.h", "+chrome/browser/profiles", ]
diff --git a/chrome/browser/ash/auth/cryptohome_pin_engine.cc b/chrome/browser/ash/auth/cryptohome_pin_engine.cc index 704995b..912854a 100644 --- a/chrome/browser/ash/auth/cryptohome_pin_engine.cc +++ b/chrome/browser/ash/auth/cryptohome_pin_engine.cc
@@ -5,11 +5,12 @@ #include "chrome/browser/ash/auth/cryptohome_pin_engine.h" #include "ash/constants/ash_pref_names.h" +#include "base/check_deref.h" #include "base/check_op.h" #include "base/containers/contains.h" +#include "base/memory/raw_ref.h" #include "chrome/browser/ash/login/users/chrome_user_manager_util.h" #include "chrome/browser/ash/profiles/profile_helper.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chromeos/ash/components/login/auth/auth_performer.h" #include "components/account_id/account_id.h" @@ -52,8 +53,8 @@ } // Read the salt from local state. -std::string GetUserSalt(const AccountId& account_id) { - user_manager::KnownUser known_user(g_browser_process->local_state()); +std::string GetUserSalt(PrefService& local_state, const AccountId& account_id) { + user_manager::KnownUser known_user(&local_state); if (const std::string* salt = known_user.FindStringPath(account_id, prefs::kQuickUnlockPinSalt)) { return *salt; @@ -63,8 +64,10 @@ } // namespace -CryptohomePinEngine::CryptohomePinEngine(ash::AuthPerformer* auth_performer) - : auth_performer_(auth_performer), +CryptohomePinEngine::CryptohomePinEngine(PrefService* local_state, + ash::AuthPerformer* auth_performer) + : local_state_(CHECK_DEREF(local_state)), + auth_performer_(auth_performer), auth_factor_editor_(ash::UserDataAuthClient::Get()) {} CryptohomePinEngine::~CryptohomePinEngine() = default; @@ -121,7 +124,7 @@ const cryptohome::RawPin& pin, std::unique_ptr<UserContext> user_context, AuthOperationCallback callback) { - auto salt = GetUserSalt(user_context->GetAccountId()); + auto salt = GetUserSalt(local_state_.get(), user_context->GetAccountId()); auth_performer_->AuthenticateWithPin(*pin, salt, std::move(user_context), std::move(callback)); }
diff --git a/chrome/browser/ash/auth/cryptohome_pin_engine.h b/chrome/browser/ash/auth/cryptohome_pin_engine.h index e597c7e..4a37999 100644 --- a/chrome/browser/ash/auth/cryptohome_pin_engine.h +++ b/chrome/browser/ash/auth/cryptohome_pin_engine.h
@@ -10,11 +10,14 @@ #include <string> #include "base/functional/callback_forward.h" +#include "base/memory/raw_ref.h" #include "base/memory/weak_ptr.h" #include "chromeos/ash/components/cryptohome/common_types.h" #include "chromeos/ash/components/login/auth/auth_factor_editor.h" #include "chromeos/ash/components/login/auth/auth_performer.h" +class PrefService; + namespace ash { class UserContext; @@ -26,7 +29,9 @@ public: enum class Purpose { kAny, kUnlock, kWebAuthn }; - explicit CryptohomePinEngine(ash::AuthPerformer* auth_performer); + // `local_state` must be non-null and must outlive `this`. + CryptohomePinEngine(PrefService* local_state, + ash::AuthPerformer* auth_performer); CryptohomePinEngine(const CryptohomePinEngine&) = delete; CryptohomePinEngine& operator=(const CryptohomePinEngine&) = delete; virtual ~CryptohomePinEngine(); @@ -64,6 +69,8 @@ std::unique_ptr<UserContext> user_context, std::optional<AuthenticationError> error); + const raw_ref<PrefService> local_state_; + // Non owning pointer const raw_ptr<ash::AuthPerformer> auth_performer_;
diff --git a/chrome/browser/ash/cert_provisioning/BUILD.gn b/chrome/browser/ash/cert_provisioning/BUILD.gn index dc4b4c4..6d341d3 100644 --- a/chrome/browser/ash/cert_provisioning/BUILD.gn +++ b/chrome/browser/ash/cert_provisioning/BUILD.gn
@@ -55,6 +55,7 @@ "//chromeos/ash/components/cryptohome", "//chromeos/ash/components/dbus/attestation", "//chromeos/ash/components/dbus/attestation:attestation_proto", + "//chromeos/ash/components/kcer", "//chromeos/dbus/common", "//chromeos/dbus/tpm_manager", "//chromeos/dbus/tpm_manager:tpm_manager_proto",
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_dynamic.cc b/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_dynamic.cc index 0aff375..0cd67919 100644 --- a/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_dynamic.cc +++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_dynamic.cc
@@ -34,6 +34,7 @@ #include "chrome/browser/ash/platform_keys/platform_keys_service_factory.h" #include "chrome/browser/chromeos/platform_keys/platform_keys.h" #include "chrome/browser/profiles/profile.h" +#include "chromeos/ash/components/kcer/kcer_utils.h" #include "components/policy/core/common/cloud/device_management_service.h" #include "components/policy/proto/device_management_backend.pb.h" #include "content/public/browser/browser_context.h" @@ -835,7 +836,23 @@ return; } - signature_ = std::move(signature); + if (signature_algorithm_ == + em::CertProvSignatureAlgorithm::SIGNATURE_ALGORITHM_ECDSA_SHA256) { + base::expected<std::vector<uint8_t>, kcer::Error> asn1_ec_signature = + kcer::ReencodeEcSignatureAsAsn1(signature); + if (!asn1_ec_signature.has_value()) { + failure_message_no_pii_ = + base::StringPrintf("Failed to re-encode ECC signature, error: %d", + static_cast<int>(asn1_ec_signature.error())); + FINAL_STATE_EXPECTED( + UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed)); + return; + } + signature_ = std::move(asn1_ec_signature).value(); + } else { + signature_ = std::move(signature); + } + RETURN_ON_FINAL_STATE( UpdateState(FROM_HERE, CertProvisioningWorkerState::kSignCsrFinished)); DoStep();
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_dynamic_unittest.cc b/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_dynamic_unittest.cc index 887a4a0..e4d5fda 100644 --- a/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_dynamic_unittest.cc +++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_dynamic_unittest.cc
@@ -171,6 +171,12 @@ constexpr char kChallenge[] = "fake_va_challenge_1"; constexpr char kChallengeResponse[] = "fake_va_challenge_response_1"; constexpr char kSignatureBase64[] = "AQIDBAU="; +// The signature was recorded from the code under test. A real CA successfully +// issued a cert for it, so it should be correct. It is not related to the +// kPublicKeyEcBase64 key, but it shouldn't matter for these unit tests. +constexpr char kEccSignatureAsn1Base64[] = + "MEQCIHRmp42nHk9m/rx4cITQE7lkYG9NVFXQQgQHHOzmbMZhAiB/c/" + "D3K3fFFeprb+IKs4cYLzX5d3JsGDXAca/eCzyaTg=="; constexpr unsigned int kNonVaKeyModulusLengthBits = 2048; constexpr char kEcNamedCurve[] = "P-256"; @@ -228,6 +234,22 @@ return std::vector<uint8_t>({1, 2, 3, 4, 5}); } +std::vector<uint8_t> GetEccSignatureRawBin() { + // The raw values from the kEccSignatureAsn1Base64 signature (concatenated to + // each other) without the ASN.1 structure. This should be a realistic example + // of what is returned from the SIgnEcdsa method. + return base::Base64Decode( + "dGanjaceT2b+vHhwhNATuWRgb01UVdBCBAcc7OZsxmF/c/" + "D3K3fFFeprb+IKs4cYLzX5d3JsGDXAca/eCzyaTg==") + .value(); +} + +std::string GetEccSignatureAsn1Str() { + std::vector<uint8_t> asn1_signature = + base::Base64Decode(kEccSignatureAsn1Base64).value(); + return std::string(asn1_signature.begin(), asn1_signature.end()); +} + std::vector<uint8_t> GetCertProfileIdBin() { // -1 because of '\0'. return std::vector<uint8_t>(kCertProfileId, @@ -418,7 +440,8 @@ { \ EXPECT_CALL(*platform_keys_service_, SIGN_FUNC) \ .Times(1) \ - .WillOnce(RunOnceCallback<4>(GetSignatureBin(), Status::kSuccess)); \ + .WillOnce( \ + RunOnceCallback<4>(GetEccSignatureRawBin(), Status::kSuccess)); \ } #define EXPECT_IMPORT_CERTIFICATE_OK(IMPORT_FUNC) \ @@ -1006,7 +1029,7 @@ EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), NoDataResultOk()); @@ -1343,7 +1366,7 @@ EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), NoDataResultOk()); @@ -1779,7 +1802,7 @@ chromeos::platform_keys::HASH_ALGORITHM_SHA256, /*callback=*/_)); EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), NoDataResultOk()); EXPECT_GET_NEXT_INSTRUCTION( @@ -1957,7 +1980,7 @@ EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), NoDataResultOk()); @@ -2260,7 +2283,7 @@ EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), NoDataResultOk()); @@ -2415,7 +2438,7 @@ EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), NoDataResultOk()); @@ -2659,7 +2682,7 @@ EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), NoDataResultOk()); @@ -3047,7 +3070,7 @@ EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), NoDataResultOk()); @@ -3346,7 +3369,7 @@ EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), NoDataResultOk()); @@ -4306,7 +4329,7 @@ EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), base::unexpected( DmStatusError(policy::DM_STATUS_TEMPORARY_UNAVAILABLE))); @@ -4317,7 +4340,7 @@ { EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), NoDataResultOk()); FastForwardBy(kRequestRetryInitialDelay + kSmallDelay); @@ -5334,12 +5357,12 @@ "state": 6 } })", - process_id.c_str(), kSignatureBase64, kPublicKeyEcBase64)); + process_id.c_str(), kEccSignatureAsn1Base64, kPublicKeyEcBase64)); EXPECT_CALL(pref_observer, OnPrefValueUpdated(IsJson(pref_val))).Times(1); EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), base::unexpected( DmStatusError(policy::DM_STATUS_TEMPORARY_UNAVAILABLE))); @@ -5367,7 +5390,7 @@ testing::InSequence seq; EXPECT_UPLOAD_PROOF_OF_POSSESSION( UploadProofOfPossession(Eq(std::ref(provisioning_process)), - GetSignatureStr(), + GetEccSignatureAsn1Str(), /*callback=*/_), NoDataResultOk());
diff --git a/chrome/browser/ash/crosapi/structured_metrics_service_ash.h b/chrome/browser/ash/crosapi/structured_metrics_service_ash.h index 32a4ba8b..552a0c35 100644 --- a/chrome/browser/ash/crosapi/structured_metrics_service_ash.h +++ b/chrome/browser/ash/crosapi/structured_metrics_service_ash.h
@@ -12,9 +12,12 @@ namespace crosapi { -// Implements the StructuredMetricsService mojo interface to record events. -// Wrapper to validate and record structured metrics received from lacros. Lives -// on the UI thread. +// Implements the StructuredMetricsService mojo interface to record events from +// AshStructuredMetricsDelegate. Wrapper to validate and record structured +// metrics. Lives on the UI thread. Although both AshStructuredMetricsDelegate +// and StructuredMetricsServiceAsh live in the same Ash process, instantiating a +// mojo pipe adds little overhead and provides lots of benefits out of the box +// (ie message buffer). class StructuredMetricsServiceAsh final : public mojom::StructuredMetricsService { public:
diff --git a/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc index 37c807d..d99113c 100644 --- a/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc +++ b/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc
@@ -4820,7 +4820,9 @@ }; AutotestPrivateInstallPWAForCurrentURLFunction:: - AutotestPrivateInstallPWAForCurrentURLFunction() = default; + AutotestPrivateInstallPWAForCurrentURLFunction() + : auto_accept_pwa_install_confirmation_( + web_app::SetAutoAcceptPWAInstallConfirmationForTesting()) {} AutotestPrivateInstallPWAForCurrentURLFunction:: ~AutotestPrivateInstallPWAForCurrentURLFunction() = default; @@ -4869,7 +4871,6 @@ base::BindOnce( &AutotestPrivateInstallPWAForCurrentURLFunction::PWAInstalled, this)); - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(true); if (!chrome::ExecuteCommand(browser, IDC_INSTALL_PWA)) { return Respond(Error("Failed to execute INSTALL_PWA command")); } @@ -4877,13 +4878,11 @@ void AutotestPrivateInstallPWAForCurrentURLFunction::PWAInstalled( const webapps::AppId& app_id) { - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(false); Respond(WithArguments(app_id)); timeout_timer_.Stop(); } void AutotestPrivateInstallPWAForCurrentURLFunction::PWATimeout() { - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(false); Respond(Error("Install PWA timed out")); }
diff --git a/chrome/browser/ash/extensions/autotest_private/autotest_private_api.h b/chrome/browser/ash/extensions/autotest_private/autotest_private_api.h index 4ea5b95..5bb0d21 100644 --- a/chrome/browser/ash/extensions/autotest_private/autotest_private_api.h +++ b/chrome/browser/ash/extensions/autotest_private/autotest_private_api.h
@@ -1222,6 +1222,7 @@ std::unique_ptr<PWABannerObserver> banner_observer_; std::unique_ptr<PWAInstallManagerObserver> install_mananger_observer_; base::OneShotTimer timeout_timer_; + base::AutoReset<bool> auto_accept_pwa_install_confirmation_; }; class AutotestPrivateActivateAcceleratorFunction : public ExtensionFunction {
diff --git a/chrome/browser/ash/login/screens/osauth/cryptohome_recovery_setup_screen.cc b/chrome/browser/ash/login/screens/osauth/cryptohome_recovery_setup_screen.cc index 825c82c..95b2551 100644 --- a/chrome/browser/ash/login/screens/osauth/cryptohome_recovery_setup_screen.cc +++ b/chrome/browser/ash/login/screens/osauth/cryptohome_recovery_setup_screen.cc
@@ -57,7 +57,9 @@ view_(std::move(view)), exit_callback_(std::move(exit_callback)), auth_performer_(UserDataAuthClient::Get()), - cryptohome_pin_engine_(&auth_performer_) {} + // TODO(crbug.com/404133029): Remove g_browser_process usage. + cryptohome_pin_engine_(g_browser_process->local_state(), + &auth_performer_) {} CryptohomeRecoverySetupScreen::~CryptohomeRecoverySetupScreen() = default;
diff --git a/chrome/browser/ash/login/screens/pin_setup_screen.cc b/chrome/browser/ash/login/screens/pin_setup_screen.cc index dd2485b..a241263 100644 --- a/chrome/browser/ash/login/screens/pin_setup_screen.cc +++ b/chrome/browser/ash/login/screens/pin_setup_screen.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h" #include "chrome/browser/ash/login/users/chrome_user_manager_util.h" #include "chrome/browser/ash/login/wizard_context.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/policy/profile_policy_connector.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/ash/login/pin_setup_screen_handler.h" @@ -127,7 +128,9 @@ view_(std::move(view)), exit_callback_(exit_callback), auth_performer_(UserDataAuthClient::Get()), - cryptohome_pin_engine_(&auth_performer_) { + // TODO(crbug.com/404133029): Remove g_browser_process usage. + cryptohome_pin_engine_(g_browser_process->local_state(), + &auth_performer_) { DCHECK(view_); quick_unlock::PinBackend::GetInstance()->HasLoginSupport(base::BindOnce(
diff --git a/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.cc b/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.cc index 372ad570..26cc0a47 100644 --- a/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.cc +++ b/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.cc
@@ -22,6 +22,7 @@ #include "components/omnibox/browser/actions/omnibox_extension_action.h" #include "components/omnibox/browser/autocomplete_input.h" #include "components/omnibox/browser/autocomplete_match_classification.h" +#include "components/omnibox/browser/suggestion_group_util.h" #include "components/omnibox/browser/unscoped_extension_provider.h" #include "components/omnibox/browser/vector_icons.h" // nogncheck #include "extensions/browser/extension_util.h" @@ -32,6 +33,10 @@ constexpr size_t kMaxSuggestionsPerExtension = 4; // LINT.ThenChange(//components/omnibox/browser/autocomplete_grouper_sections.cc) +// Unscoped Extension suggestions are grouped after all other suggestions. But +// they still need to score within top N suggestions to be shown. +constexpr int kUnscopedExtensionRelevance = 2000; + constexpr auto kReservedGroupIdMap = base::MakeFixedFlatMap<size_t, omnibox::GroupId>( {{0, omnibox::GROUP_UNSCOPED_EXTENSION_1}, @@ -65,6 +70,9 @@ std::set<std::string> unscoped_mode_extension_ids) { CHECK(extension_suggest_matches_.empty()); CHECK(extension_id_to_group_id_map_.empty()); + first_suggestion_relevance_ = + input.IsZeroSuggest() ? omnibox::kUnscopedExtensionZeroSuggestRelevance + : kUnscopedExtensionRelevance; for (const std::string& extension_id : unscoped_mode_extension_ids) { if (!IsEnabledExtension(extension_id)) { @@ -136,10 +144,10 @@ group.set_header_text(base::UTF16ToUTF8(template_url->keyword())); provider_->AddToSuggestionGroupsMap(current_group_id, std::move(group)); - int first_relevance = 10000000; for (const auto& suggestion : suggestions) { - extension_suggest_matches_.push_back( - CreateAutocompleteMatch(suggestion, --first_relevance, extension_id)); + CHECK_GE(first_suggestion_relevance_, 0); + extension_suggest_matches_.push_back(CreateAutocompleteMatch( + suggestion, first_suggestion_relevance_--, extension_id)); } ACMatches* matches = provider_->matches();
diff --git a/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.h b/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.h index 5572b6fe..c16461ca 100644 --- a/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.h +++ b/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.h
@@ -82,6 +82,10 @@ // incoming later with a stale request ID. int current_request_id_ = 0; + // The first relevance score to assign to the suggestions for the current + // request for suggestions. + int first_suggestion_relevance_ = 0; + // Current list of matches received from the extensions. Used to update the // list of matches in the provider. std::vector<AutocompleteMatch> extension_suggest_matches_;
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java index df81a7a..1ad31d6a 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/editors/AddressEditorMediator.java
@@ -205,7 +205,7 @@ .with(FOOTER_MESSAGE, getRecordTypeNoticeText()) .with(DELETE_CONFIRMATION_TITLE, getDeleteConfirmationTitle()) .with(DELETE_CONFIRMATION_TEXT, getDeleteConfirmationText()) - .with(SHOW_REQUIRED_INDICATOR, false) + .with(SHOW_REQUIRED_INDICATOR, true) .with( EDITOR_FIELDS, buildEditorFieldList(
diff --git a/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/editors/AddressEditorTest.java b/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/editors/AddressEditorTest.java index 09c91c9..37d18c01 100644 --- a/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/editors/AddressEditorTest.java +++ b/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/editors/AddressEditorTest.java
@@ -11,8 +11,8 @@ import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; @@ -271,7 +271,7 @@ @Nullable String expectedRecordTypeNotice) { assertNotNull(editorModel); - assertFalse(editorModel.get(SHOW_REQUIRED_INDICATOR)); + assertTrue(editorModel.get(SHOW_REQUIRED_INDICATOR)); assertEquals(expectedDeleteTitle, editorModel.get(DELETE_CONFIRMATION_TITLE)); assertEquals(expectedDeleteText, editorModel.get(DELETE_CONFIRMATION_TEXT)); assertEquals(expectedRecordTypeNotice, editorModel.get(FOOTER_MESSAGE));
diff --git a/chrome/browser/autofill/automated_tests/cache_replayer.h b/chrome/browser/autofill/automated_tests/cache_replayer.h index 8b9610cc..4492ae5 100644 --- a/chrome/browser/autofill/automated_tests/cache_replayer.h +++ b/chrome/browser/autofill/automated_tests/cache_replayer.h
@@ -49,7 +49,7 @@ // using the cached responses from the wpr archive. The valid values match the // enum AutofillServerBehaviorType below. Options are: // SavedCache, ProductionServer, or OnlyLocalHeuristics. -constexpr char kAutofillServerBehaviorParam[] = "autofill-server-type"; +inline constexpr char kAutofillServerBehaviorParam[] = "autofill-server-type"; enum class AutofillServerBehaviorType { kSavedCache, // Uses cached responses. This is the Default. kProductionServer, // Connects to live Autofill Server for recommendations.
diff --git a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java index ae24396..1137b53 100644 --- a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java +++ b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java
@@ -105,7 +105,6 @@ } } - if (mFallbackOnBackPressed != null) mFallbackOnBackPressed.run(); assert !failed : "Callback is enabled but didn't consume the esc."; return null; } @@ -490,6 +489,10 @@ mLastCalledHandlerType = -1; } + public ObserverList<OnSystemNavigationObserver> getObserverListForTesting() { + return mOnSystemNavigationObservers; + } + public static String getHistogramForTesting() { return HISTOGRAM; }
diff --git a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerTest.java b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerTest.java index d7057e6..399828b3 100644 --- a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerTest.java +++ b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerTest.java
@@ -464,6 +464,48 @@ }); } + @Test + @SmallTest + public void testEscapePressesDoNotUseFallback() { + BackPressManager manager = new BackPressManager(); + + EscModifyingBackPressHandler h1 = + ThreadUtils.runOnUiThreadBlocking( + () -> new EscModifyingBackPressHandler(Boolean.FALSE)); + EscModifyingBackPressHandler h2 = + ThreadUtils.runOnUiThreadBlocking(() -> new EscModifyingBackPressHandler(null)); + + // Fail if the BackPressManager calls the fallback method, which it shouldn't. + manager.setFallbackOnBackPressed( + () -> { + assert false + : "BackPressManager should not call fallback on escape key presses."; + }); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + manager.addHandler(h1, 2); + manager.addHandler(h2, 4); + h1.getHandleBackPressChangedSupplier().set(true); + h2.getHandleBackPressChangedSupplier().set(true); + }); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertNull( + "Manager should not have found any handlers to consume Esc.", + manager.processEscapeKeyEvent()); + Assert.assertEquals( + "Handler did not execute custom esc key code even though it will fail.", + 1, + h1.getCallbackHelper().getCallCount()); + Assert.assertEquals( + "Handler did not execute custom esc key code even though it will fail.", + 1, + h2.getCallbackHelper().getCallCount()); + }); + } + // Trigger back press ignoring built-in assertion errors. private void triggerBackPressWithoutAssertionError(BackPressManager manager) { ThreadUtils.runOnUiThreadBlocking(
diff --git a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java index d73d482e..916f34e 100644 --- a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java +++ b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java
@@ -595,6 +595,37 @@ h4.getCallbackHelper().getCallCount()); } + @Test + public void testEscapePressesDoNotUseFallback() { + BackPressManager manager = new BackPressManager(); + EscapeBackPressHandlerFailure h1 = new EscapeBackPressHandlerFailure(); + EscapeBackPressHandlerFailure h2 = new EscapeBackPressHandlerFailure(); + + // Fail if the BackPressManager calls the fallback method, which it shouldn't. + manager.setFallbackOnBackPressed( + () -> { + assert false + : "BackPressManager should not call fallback on escape key presses."; + }); + + manager.addHandler(h1, 3); + manager.addHandler(h2, 6); + h1.getHandleBackPressChangedSupplier().set(true); + h2.getHandleBackPressChangedSupplier().set(true); + + Assert.assertNull( + "Manager should not have found any handlers to consume Esc.", + manager.processEscapeKeyEvent()); + Assert.assertEquals( + "Handler did not execute custom esc key code even though it will fail.", + 1, + h1.getCallbackHelper().getCallCount()); + Assert.assertEquals( + "Handler did not execute back press code even though it will fall through.", + 1, + h2.getCallbackHelper().getCallCount()); + } + private int getHandlerCount(BackPressManager manager) { int count = 0; for (BackPressHandler handler : manager.getHandlersForTesting()) {
diff --git a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc index 03e7dbd..3a03b68 100644 --- a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc +++ b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
@@ -53,7 +53,9 @@ class AppBannerManagerDesktopBrowserTest : public AppBannerManagerBrowserTestBase { public: - AppBannerManagerDesktopBrowserTest() = default; + AppBannerManagerDesktopBrowserTest() + : auto_accept_pwa_install_confirmation_( + web_app::SetAutoAcceptPWAInstallConfirmationForTesting()) {} void SetUp() override { TestAppBannerManagerDesktop::SetUp(); @@ -61,19 +63,16 @@ } void SetUpOnMainThread() override { - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(true); - AppBannerManagerBrowserTestBase::SetUpOnMainThread(); } - void TearDown() override { - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(false); - } - AppBannerManagerDesktopBrowserTest( const AppBannerManagerDesktopBrowserTest&) = delete; AppBannerManagerDesktopBrowserTest& operator=( const AppBannerManagerDesktopBrowserTest&) = delete; + + private: + base::AutoReset<bool> auto_accept_pwa_install_confirmation_; }; IN_PROC_BROWSER_TEST_F(AppBannerManagerDesktopBrowserTest, @@ -230,10 +229,8 @@ } // Install the app via the menu instead of the banner. - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(true); browser()->command_controller()->ExecuteCommand(IDC_INSTALL_PWA); manager->AwaitAppInstall(); - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(false); EXPECT_FALSE(manager->IsPromptAvailableForTesting()); @@ -261,11 +258,9 @@ } // Install the app via the menu instead of the banner. - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(true); browser()->window()->ExecutePageActionIconForTesting( PageActionIconType::kPwaInstall); manager->AwaitAppInstall(); - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(false); EXPECT_FALSE(manager->IsPromptAvailableForTesting()); @@ -375,10 +370,8 @@ } // Install the app via the menu instead of the banner. - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(true); browser()->command_controller()->ExecuteCommand(IDC_INSTALL_PWA); manager->AwaitAppInstall(); - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(false); EXPECT_FALSE(manager->IsPromptAvailableForTesting());
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index e360fc26..0b3e177 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -4779,9 +4779,6 @@ parts->OverrideWebPreferences(web_contents, main_frame_site, web_prefs); } - // TODO(crbug.com/395838064): Cleanup WebSQL WebPreference. - web_prefs->databases_enabled = false; - web_prefs->prefers_default_scrollbar_styles = prefs->GetBoolean(prefs::kPrefersDefaultScrollbarStyles); #if BUILDFLAG(IS_ANDROID) @@ -5399,15 +5396,17 @@ void ChromeContentBrowserClient::CreateThrottlesForNavigation( content::NavigationThrottleRegistry& registry) { - // MetricsNavigationThrottle requires that it runs before NavigationThrottles - // that may delay or cancel navigations, so only NavigationThrottles that - // don't delay or cancel navigations (e.g. throttles that are only observing - // callbacks without affecting navigation behavior) should be added before - // MetricsNavigationThrottle. content::NavigationHandle& handle = registry.GetNavigationHandle(); if (handle.IsInMainFrame()) { - registry.AddThrottle( - page_load_metrics::MetricsNavigationThrottle::Create(&handle)); + // MetricsNavigationThrottle requires that it runs before + // NavigationThrottles that may delay or cancel navigations, so only + // NavigationThrottles that don't delay or cancel navigations (e.g. + // throttles that are only observing callbacks without affecting navigation + // behavior) should be added before MetricsNavigationThrottle. + // TODO(https://crbug.com/412524375): This assumption is fragile. This + // should be cared by adding an attribute flag to + // NavigationThrottleRegistry::AddThrottle(). + page_load_metrics::MetricsNavigationThrottle::CreateAndAdd(registry); } #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/chromeos/platform_keys/extension_key_permissions_service.h b/chrome/browser/chromeos/platform_keys/extension_key_permissions_service.h index bb3a071..5b31d032 100644 --- a/chrome/browser/chromeos/platform_keys/extension_key_permissions_service.h +++ b/chrome/browser/chromeos/platform_keys/extension_key_permissions_service.h
@@ -47,7 +47,7 @@ // } // // Do not change this constant as clients will lose their existing state. -const char kStateStorePlatformKeys[] = "PlatformKeys"; +inline constexpr char kStateStorePlatformKeys[] = "PlatformKeys"; using ExtensionKeyPermissionQueryCallback = base::OnceCallback<void(bool allowed)>;
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_clipboard_bubble_constants.h b/chrome/browser/chromeos/policy/dlp/dlp_clipboard_bubble_constants.h index f790351..6a36c52 100644 --- a/chrome/browser/chromeos/policy/dlp/dlp_clipboard_bubble_constants.h +++ b/chrome/browser/chromeos/policy/dlp/dlp_clipboard_bubble_constants.h
@@ -8,24 +8,26 @@ namespace policy { // Clipboard ARC toast ID in block mode. -constexpr char kClipboardBlockArcToastId[] = "clipboard_dlp_block_arc"; +inline constexpr char kClipboardBlockArcToastId[] = "clipboard_dlp_block_arc"; // Clipboard ARC toast ID in warning mode. -constexpr char kClipboardWarnArcToastId[] = "clipboard_dlp_warn_arc"; +inline constexpr char kClipboardWarnArcToastId[] = "clipboard_dlp_warn_arc"; // Clipboard Crostini toast ID in block mode. -constexpr char kClipboardBlockCrostiniToastId[] = +inline constexpr char kClipboardBlockCrostiniToastId[] = "clipboard_dlp_block_crostini"; // Clipboard Crostini toast ID in warning mode. -constexpr char kClipboardWarnCrostiniToastId[] = "clipboard_dlp_warn_crostini"; +inline constexpr char kClipboardWarnCrostiniToastId[] = + "clipboard_dlp_warn_crostini"; // Clipboard Plugin VM toast ID in block mode. -constexpr char kClipboardBlockPluginVmToastId[] = +inline constexpr char kClipboardBlockPluginVmToastId[] = "clipboard_dlp_block_plugin_vm"; // Clipboard Plugin VM toast ID in warning mode. -constexpr char kClipboardWarnPluginVmToastId[] = "clipboard_dlp_warn_plugin_vm"; +inline constexpr char kClipboardWarnPluginVmToastId[] = + "clipboard_dlp_warn_plugin_vm"; // The duration of the clipboard bubble shown on blocked paste. constexpr int kClipboardDlpBlockDurationMs = 6000;
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_policy_constants.h b/chrome/browser/chromeos/policy/dlp/dlp_policy_constants.h index 4b8e7cb..ea79d20 100644 --- a/chrome/browser/chromeos/policy/dlp/dlp_policy_constants.h +++ b/chrome/browser/chromeos/policy/dlp/dlp_policy_constants.h
@@ -12,7 +12,7 @@ namespace dlp { // Link to the Help Center article about Data Leak Prevention. -constexpr char kDlpLearnMoreUrl[] = +inline constexpr char kDlpLearnMoreUrl[] = "https://support.google.com/chrome/a/?p=chromeos_datacontrols"; } // namespace dlp
diff --git a/chrome/browser/chromeos/reporting/metric_reporting_prefs.h b/chrome/browser/chromeos/reporting/metric_reporting_prefs.h index 715ab58..defe870b 100644 --- a/chrome/browser/chromeos/reporting/metric_reporting_prefs.h +++ b/chrome/browser/chromeos/reporting/metric_reporting_prefs.h
@@ -18,27 +18,28 @@ // A list pref that specifies allowlisted URLs for website activity event // reporting. -constexpr char kReportWebsiteActivityAllowlist[] = +inline constexpr char kReportWebsiteActivityAllowlist[] = "reporting.report_website_activity_allowlist"; // A list pref that specifies allowlisted URLs for website telemetry reporting. -constexpr char kReportWebsiteTelemetryAllowlist[] = +inline constexpr char kReportWebsiteTelemetryAllowlist[] = "reporting.report_website_telemetry_allowlist"; // A list pref that controls website telemetry data types being reported. -constexpr char kReportWebsiteTelemetry[] = "reporting.report_website_telemetry"; +inline constexpr char kReportWebsiteTelemetry[] = + "reporting.report_website_telemetry"; // An integer pref that controls the collection frequency of website telemetry // data. -constexpr char kReportWebsiteTelemetryCollectionRateMs[] = +inline constexpr char kReportWebsiteTelemetryCollectionRateMs[] = "reporting.report_website_telemetry_collection_rate_ms"; // A dictionary pref that tracks foreground website usage for URLs with the // current user profile. -constexpr char kWebsiteUsage[] = "reporting.website_usage"; +inline constexpr char kWebsiteUsage[] = "reporting.website_usage"; // Website telemetry types tracked by the `ReportWebsiteTelemetry` policy. -constexpr char kWebsiteTelemetryUsageType[] = "usage"; +inline constexpr char kWebsiteTelemetryUsageType[] = "usage"; void RegisterProfilePrefs(::user_prefs::PrefRegistrySyncable* registry);
diff --git a/chrome/browser/chromeos/upload_office_to_cloud/upload_office_to_cloud.h b/chrome/browser/chromeos/upload_office_to_cloud/upload_office_to_cloud.h index 7df03ca8..5aca318e 100644 --- a/chrome/browser/chromeos/upload_office_to_cloud/upload_office_to_cloud.h +++ b/chrome/browser/chromeos/upload_office_to_cloud/upload_office_to_cloud.h
@@ -20,9 +20,9 @@ namespace cloud_upload { -constexpr char kCloudUploadPolicyAllowed[] = "allowed"; -constexpr char kCloudUploadPolicyDisallowed[] = "disallowed"; -constexpr char kCloudUploadPolicyAutomated[] = "automated"; +inline constexpr char kCloudUploadPolicyAllowed[] = "allowed"; +inline constexpr char kCloudUploadPolicyDisallowed[] = "disallowed"; +inline constexpr char kCloudUploadPolicyAutomated[] = "automated"; void RegisterProfilePrefs(PrefRegistrySimple* registry);
diff --git a/chrome/browser/collaboration/BUILD.gn b/chrome/browser/collaboration/BUILD.gn index c9e3511..991b0f7 100644 --- a/chrome/browser/collaboration/BUILD.gn +++ b/chrome/browser/collaboration/BUILD.gn
@@ -97,6 +97,7 @@ "//chrome/test/android:chrome_java_integration_test_support", "//components/collaboration/public:java", "//components/data_sharing/public:public_java", + "//components/saved_tab_groups/public:java", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/androidx:androidx_test_runner_java", "//third_party/hamcrest:hamcrest_core_java",
diff --git a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationServiceFactoryTest.java b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationServiceFactoryTest.java index 135789b..d2bf1cc 100644 --- a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationServiceFactoryTest.java +++ b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationServiceFactoryTest.java
@@ -36,6 +36,7 @@ import org.chromium.components.collaboration.SyncStatus; import org.chromium.components.data_sharing.GroupData; import org.chromium.components.data_sharing.member_role.MemberRole; +import org.chromium.components.tab_group_sync.EitherId.EitherGroupId; import org.chromium.url.GURL; import java.util.concurrent.CountDownLatch; @@ -64,13 +65,13 @@ @Override public void startShareOrManageFlow( CollaborationControllerDelegate delegate, - String syncId, + EitherGroupId eitherId, @CollaborationServiceShareOrManageEntryPoint int entry) {} @Override public void startLeaveOrDeleteFlow( CollaborationControllerDelegate delegate, - String syncId, + EitherGroupId eitherId, @CollaborationServiceLeaveOrDeleteEntryPoint int entry) {} @Override
diff --git a/chrome/browser/contextual_cueing/zero_state_suggestions_page_data.cc b/chrome/browser/contextual_cueing/zero_state_suggestions_page_data.cc index c0cf375..c749f51 100644 --- a/chrome/browser/contextual_cueing/zero_state_suggestions_page_data.cc +++ b/chrome/browser/contextual_cueing/zero_state_suggestions_page_data.cc
@@ -6,6 +6,7 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros_local.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" #include "chrome/browser/content_extraction/inner_text.h"
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java index 9bab51f..1c6375c 100644 --- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java +++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java
@@ -64,6 +64,7 @@ import org.chromium.components.data_sharing.configs.DataSharingStringConfig; import org.chromium.components.data_sharing.configs.DataSharingUiConfig; import org.chromium.components.data_sharing.configs.DataSharingUiConfig.DataSharingUserAction; +import org.chromium.components.tab_group_sync.EitherId.EitherGroupId; import org.chromium.components.tab_group_sync.LocalTabGroupId; import org.chromium.components.tab_group_sync.SavedTabGroup; import org.chromium.components.tab_group_sync.SavedTabGroupTab; @@ -537,40 +538,35 @@ } createOrManageFlow( activity, - /* syncId= */ null, - new LocalTabGroupId(assumeNonNull(tab.getTabGroupId())), + EitherGroupId.createLocalId( + new LocalTabGroupId(assumeNonNull(tab.getTabGroupId()))), entryPoint, createGroupFinishedCallback); } /** - * Creates a collaboration group. + * Creates or manage a collaboration group. * * @param activity The activity in which the group is to be created. - * @param syncId The sync ID of the tab group. - * @param localTabGroupId The tab group ID of the tab in the local tab group model. + * @param eitherId The sync ID or local tab group ID of the tab group. + * @param entry The entry point of the flow. * @param createGroupFinishedCallback Callback invoked when the creation flow is finished. */ public void createOrManageFlow( Activity activity, - @Nullable String syncId, - @Nullable LocalTabGroupId localTabGroupId, + EitherGroupId eitherId, @CollaborationServiceShareOrManageEntryPoint int entry, @Nullable Callback<Boolean> createGroupFinishedCallback) { DataSharingMetrics.recordShareActionFlowState( DataSharingMetrics.ShareActionStateAndroid.SHARE_TRIGGERED); - SavedTabGroup existingGroup = getSavedTabGroupForEitherId(syncId, localTabGroupId); - assert existingGroup != null : "Group not found in TabGroupSyncService."; - // TODO(haileywang): Ensure createGroupFinishedCallback is called when the creation is // finished. mCurrentDelegate = mCollaborationControllerDelegateFactory.create( FlowType.SHARE_OR_MANAGE, /* switchToTabSwitcherCallback= */ null); assumeNonNull(mCollaborationService); - mCollaborationService.startShareOrManageFlow( - mCurrentDelegate, assumeNonNull(existingGroup.syncId), entry); + mCollaborationService.startShareOrManageFlow(mCurrentDelegate, eitherId, entry); } /** @@ -901,17 +897,17 @@ () -> createOrManageFlow( activity, - existingGroup.syncId, - /* localTabGroupId= */ null, + EitherGroupId.createSyncId(assumeNonNull(existingGroup.syncId)), CollaborationServiceShareOrManageEntryPoint.RECENT_ACTIVITY, /* createGroupFinishedCallback= */ null); + assumeNonNull(existingGroup.syncId); RecentActivityActionHandler recentActivityActionHandler = new RecentActivityActionHandlerImpl( tabGroupSyncService, mTabModelSelectorSupplier.get(), mDataSharingTabGroupsDelegate, collaborationId, - assumeNonNull(existingGroup.syncId), + existingGroup.syncId, manageSharingCallback); Runnable showFullActivityRunnable =
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManagerUnitTest.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManagerUnitTest.java index 74016d16..98bfcc0 100644 --- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManagerUnitTest.java +++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManagerUnitTest.java
@@ -69,6 +69,7 @@ import org.chromium.components.data_sharing.ParseUrlStatus; import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils; import org.chromium.components.dom_distiller.core.DomDistillerUrlUtilsJni; +import org.chromium.components.tab_group_sync.EitherId.EitherGroupId; import org.chromium.components.tab_group_sync.LocalTabGroupId; import org.chromium.components.tab_group_sync.SavedTabGroup; import org.chromium.components.tab_group_sync.SyncedGroupTestHelper; @@ -238,14 +239,11 @@ public void testShareOrManageFlowWithCollaborationService() { doReturn(mProfile).when(mProfile).getOriginalProfile(); doReturn(mSavedTabGroup).when(mTabGroupSyncService).getGroup(LOCAL_ID); + EitherGroupId either_id = EitherGroupId.createLocalId(LOCAL_ID); mDataSharingTabManager.createOrManageFlow( - mActivity, - /* syncId= */ null, - LOCAL_ID, - CollaborationServiceShareOrManageEntryPoint.UNKNOWN, - null); + mActivity, either_id, CollaborationServiceShareOrManageEntryPoint.UNKNOWN, null); - verify(mCollaborationService).startShareOrManageFlow(any(), eq(SYNC_GROUP_ID1), anyInt()); + verify(mCollaborationService).startShareOrManageFlow(any(), eq(either_id), anyInt()); } @Test @@ -274,7 +272,8 @@ mCreateGroupFinishedCallback); verify(mTabGroupModelFilter).createSingleTabGroup(eq(mTab)); - verify(mCollaborationService).startShareOrManageFlow(any(), eq(SYNC_GROUP_ID1), anyInt()); + verify(mCollaborationService) + .startShareOrManageFlow(any(), eq(EitherGroupId.createLocalId(LOCAL_ID)), anyInt()); } @Test @@ -302,7 +301,8 @@ CollaborationServiceShareOrManageEntryPoint.UNKNOWN, mCreateGroupFinishedCallback); - verify(mCollaborationService).startShareOrManageFlow(any(), eq(SYNC_GROUP_ID1), anyInt()); + verify(mCollaborationService) + .startShareOrManageFlow(any(), eq(EitherGroupId.createLocalId(LOCAL_ID)), anyInt()); } @Test
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/InstantMessageDelegateImpl.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/InstantMessageDelegateImpl.java index 9d6a4c5..baf58a47 100644 --- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/InstantMessageDelegateImpl.java +++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/InstantMessageDelegateImpl.java
@@ -46,7 +46,7 @@ import org.chromium.components.messages.MessageDispatcherProvider; import org.chromium.components.messages.MessageIdentifier; import org.chromium.components.messages.PrimaryActionClickBehavior; -import org.chromium.components.tab_group_sync.LocalTabGroupId; +import org.chromium.components.tab_group_sync.EitherId.EitherGroupId; import org.chromium.components.tab_group_sync.SavedTabGroup; import org.chromium.components.tab_group_sync.TabGroupSyncService; import org.chromium.ui.base.WindowAndroid; @@ -359,7 +359,6 @@ Runnable onSuccess) { @Nullable String collaborationId = MessageUtils.extractCollaborationId(message); @Nullable String syncId = MessageUtils.extractSyncTabGroupId(message); - @Nullable Token localId = MessageUtils.extractTabGroupId(message); String buttonText = activity.getString(R.string.data_sharing_browser_message_manage); GroupMember groupMember = MessageUtils.extractMember(message); Runnable openManageSharingRunnable = @@ -367,13 +366,11 @@ // TODO(crbug.com/379148260): Use shared #isCollaborationIdValid. if (TextUtils.isEmpty(collaborationId)) return; if (TextUtils.isEmpty(syncId)) return; - if (localId == null) return; if (mTabGroupSyncService.getGroup(syncId) == null) return; dataSharingTabManager.createOrManageFlow( activity, - syncId, - new LocalTabGroupId(localId), + EitherGroupId.createSyncId(syncId), CollaborationServiceShareOrManageEntryPoint.ANDROID_MESSAGE, /* createGroupFinishedCallback= */ null); };
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/InstantMessageDelegateImplUnitTest.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/InstantMessageDelegateImplUnitTest.java index 310ab704..2f8d23ad 100644 --- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/InstantMessageDelegateImplUnitTest.java +++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/InstantMessageDelegateImplUnitTest.java
@@ -314,7 +314,7 @@ Supplier<Integer> action = propertyModel.get(ON_PRIMARY_ACTION); assertNotNull(action); assertEquals(DISMISS_IMMEDIATELY, action.get().intValue()); - verify(mDataSharingTabManager).createOrManageFlow(any(), any(), any(), anyInt(), any()); + verify(mDataSharingTabManager).createOrManageFlow(any(), any(), anyInt(), any()); } @Test @@ -329,8 +329,7 @@ Supplier<Integer> action = propertyModel.get(ON_PRIMARY_ACTION); assertNotNull(action); assertEquals(DISMISS_IMMEDIATELY, action.get().intValue()); - verify(mDataSharingTabManager, never()) - .createOrManageFlow(any(), any(), any(), anyInt(), any()); + verify(mDataSharingTabManager, never()).createOrManageFlow(any(), any(), anyInt(), any()); } @Test
diff --git a/chrome/browser/download/insecure_download_blocking.cc b/chrome/browser/download/insecure_download_blocking.cc index 6d8b743..fadce51 100644 --- a/chrome/browser/download/insecure_download_blocking.cc +++ b/chrome/browser/download/insecure_download_blocking.cc
@@ -24,6 +24,7 @@ #include "components/prefs/pref_service.h" #include "content/public/browser/download_item_utils.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/url_constants.h" #include "net/base/url_util.h" #include "services/network/public/cpp/is_potentially_trustworthy.h" #include "third_party/blink/public/mojom/devtools/console_message.mojom.h" @@ -352,6 +353,10 @@ !download_delivered_securely) && !net::IsLocalhost(dl_url); } + + is_user_initiated_on_webui_ = + item->GetTabUrl().SchemeIs(content::kChromeUIScheme) && + download_source == DownloadSource::CONTEXT_MENU; } std::optional<url::Origin> initiator_; @@ -364,6 +369,8 @@ bool is_mixed_content_; // Was the download initiated by an insecure origin or delivered insecurely? bool is_insecure_download_; + // Was the download initiated by a user on a chrome:// WebUI? + bool is_user_initiated_on_webui_; }; // Check if |extension| is contained in the comma separated |extension_list|. @@ -405,6 +412,10 @@ return; } + if (data.is_user_initiated_on_webui_) { + return; + } + rfh->AddMessageToConsole( blink::mojom::ConsoleMessageLevel::kError, base::StringPrintf(
diff --git a/chrome/browser/enterprise/client_certificates/certificate_store_factory.cc b/chrome/browser/enterprise/client_certificates/certificate_store_factory.cc index 5f0a131..9f227f91 100644 --- a/chrome/browser/enterprise/client_certificates/certificate_store_factory.cc +++ b/chrome/browser/enterprise/client_certificates/certificate_store_factory.cc
@@ -9,7 +9,9 @@ #include "base/no_destructor.h" #include "chrome/browser/enterprise/client_certificates/cert_utils.h" #include "chrome/browser/profiles/profile.h" +#include "components/enterprise/client_certificates/core/features.h" #include "components/enterprise/client_certificates/core/leveldb_certificate_store.h" +#include "components/enterprise/client_certificates/core/prefs_certificate_store.h" #include "components/keyed_service/core/keyed_service.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/storage_partition.h" @@ -38,8 +40,16 @@ CertificateStoreFactory::BuildServiceInstanceForBrowserContext( content::BrowserContext* context) const { auto* profile = Profile::FromBrowserContext(context); + if (!profile) { + return nullptr; + } - if (!profile || !profile->GetDefaultStoragePartition() || + if (features::IsManagedUserClientCertificateInPrefsEnabled()) { + return std::make_unique<PrefsCertificateStore>(profile->GetPrefs(), + CreatePrivateKeyFactory()); + } + + if (!profile->GetDefaultStoragePartition() || !profile->GetDefaultStoragePartition()->GetProtoDatabaseProvider()) { return nullptr; }
diff --git a/chrome/browser/enterprise/reporting/cloud_profile_reporting_browsertest.cc b/chrome/browser/enterprise/reporting/cloud_profile_reporting_browsertest.cc index 63e6f54..538cab1 100644 --- a/chrome/browser/enterprise/reporting/cloud_profile_reporting_browsertest.cc +++ b/chrome/browser/enterprise/reporting/cloud_profile_reporting_browsertest.cc
@@ -36,7 +36,8 @@ void SetUpOnMainThread() override { Profile* profile = chrome_test_utils::GetProfile(this); EnableProfileManagement(profile); - EnableReportingPolicy(profile); + profile->GetPrefs()->SetBoolean(kCloudProfileReportingEnabled, true); + SetReportingPolicy(profile, /*enabled=*/true); } void EnableProfileManagement(Profile* profile) { @@ -54,8 +55,8 @@ /*service=*/nullptr, std::move(client)); } - void EnableReportingPolicy(Profile* profile) { - profile->GetPrefs()->SetBoolean(kCloudProfileReportingEnabled, true); + void SetReportingPolicy(Profile* profile, bool enabled) { + profile->GetPrefs()->SetBoolean(kCloudProfileReportingEnabled, enabled); } }; @@ -71,4 +72,64 @@ ReportScheduler::kTriggerTimer); } +#if !BUILDFLAG(IS_ANDROID) +class CloudProfileReportingServiceTestDesktop + : public CloudProfileReportingServiceTest, + public testing::WithParamInterface< + // Two boolean variables represents whether profile reporting and + // signals reporting is enabled + testing::tuple<bool, bool>> { + public: + CloudProfileReportingServiceTestDesktop() = default; + ~CloudProfileReportingServiceTestDesktop() override = default; + + void SetUpOnMainThread() override { + Profile* profile = chrome_test_utils::GetProfile(this); + EnableProfileManagement(profile); + SetReportingPolicy(profile, profile_reporting_enabled()); + profile->GetPrefs()->SetBoolean(kUserSecuritySignalsReporting, + signals_reporting_enabled()); + } + + bool profile_reporting_enabled() { return testing::get<0>(GetParam()); } + bool signals_reporting_enabled() { return testing::get<1>(GetParam()); } +}; + +IN_PROC_BROWSER_TEST_P(CloudProfileReportingServiceTestDesktop, + VerifyReportingConfig) { + base::RunLoop().RunUntilIdle(); + ReportScheduler* report_scheduler = + CloudProfileReportingServiceFactory::GetForProfile( + chrome_test_utils::GetProfile(this)) + ->report_scheduler(); + ASSERT_TRUE(report_scheduler); + + auto active_trigger = report_scheduler->GetActiveTriggerForTesting(); + auto active_config = report_scheduler->GetActiveGenerationConfigForTesting(); + + if (signals_reporting_enabled() && profile_reporting_enabled()) { + EXPECT_EQ(active_trigger, ReportScheduler::kTriggerTimer); + EXPECT_EQ(active_config.security_signals_mode, + SecuritySignalsMode::kSignalsAttached); + } else if (profile_reporting_enabled()) { + EXPECT_EQ(active_trigger, ReportScheduler::kTriggerTimer); + EXPECT_EQ(active_config.security_signals_mode, + SecuritySignalsMode::kNoSignals); + } else if (signals_reporting_enabled()) { + EXPECT_EQ(active_trigger, ReportScheduler::kTriggerSecurity); + EXPECT_EQ(active_config.security_signals_mode, + SecuritySignalsMode::kSignalsOnly); + } else { + EXPECT_EQ(active_trigger, ReportScheduler::kTriggerNone); + } +} + +INSTANTIATE_TEST_SUITE_P(All, + CloudProfileReportingServiceTestDesktop, + testing::Combine( + /*profile_reporting_enabled=*/testing::Bool(), + /*signals_reporting_enabled=*/testing::Bool())); + +#endif // !BUILDFLAG(IS_ANDROID) + } // namespace enterprise_reporting
diff --git a/chrome/browser/enterprise/reporting/cloud_profile_reporting_service_factory.cc b/chrome/browser/enterprise/reporting/cloud_profile_reporting_service_factory.cc index 0ddc529..b36c4f9 100644 --- a/chrome/browser/enterprise/reporting/cloud_profile_reporting_service_factory.cc +++ b/chrome/browser/enterprise/reporting/cloud_profile_reporting_service_factory.cc
@@ -37,6 +37,7 @@ return std::make_unique<CloudProfileReportingService>(profile); } + bool CloudProfileReportingServiceFactory::ServiceIsCreatedWithBrowserContext() const { return true;
diff --git a/chrome/browser/enterprise/signals/profile_signals_collector.cc b/chrome/browser/enterprise/signals/profile_signals_collector.cc index 4bfd36a..3fe59ff2 100644 --- a/chrome/browser/enterprise/signals/profile_signals_collector.cc +++ b/chrome/browser/enterprise/signals/profile_signals_collector.cc
@@ -79,6 +79,20 @@ #if BUILDFLAG(ENTERPRISE_CLOUD_CONTENT_ANALYSIS) signal_response.realtime_url_check_mode = connectors_service_->GetAppliedRealTimeUrlCheck(); + signal_response.file_downloaded_providers = + connectors_service_->GetAnalysisServiceProviderNames( + enterprise_connectors::FILE_DOWNLOADED); + signal_response.file_attached_providers = + connectors_service_->GetAnalysisServiceProviderNames( + enterprise_connectors::FILE_ATTACHED); + signal_response.bulk_data_entry_providers = + connectors_service_->GetAnalysisServiceProviderNames( + enterprise_connectors::BULK_DATA_ENTRY); + signal_response.print_providers = + connectors_service_->GetAnalysisServiceProviderNames( + enterprise_connectors::PRINT); + signal_response.security_event_providers = + connectors_service_->GetReportingServiceProviderNames(); #endif // BUILDFLAG(ENTERPRISE_CLOUD_CONTENT_ANALYSIS) response.profile_signals_response = std::move(signal_response);
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index 667a623f..825cc89 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -47,6 +47,8 @@ "activity_log/database_string_table.h", "activity_log/fullstream_ui_policy.cc", "activity_log/fullstream_ui_policy.h", + "api/bookmarks/bookmarks_api.cc", + "api/bookmarks/bookmarks_api.h", "api/bookmarks/bookmarks_api_watcher.cc", "api/bookmarks/bookmarks_api_watcher.h", "api/bookmarks_core/bookmarks_function.cc", @@ -163,6 +165,8 @@ "bookmarks/bookmarks_error_constants.h", "bookmarks/bookmarks_features.cc", "bookmarks/bookmarks_features.h", + "bookmarks/bookmarks_helpers.cc", + "bookmarks/bookmarks_helpers.h", "chrome_app_icon.cc", "chrome_app_icon.h", "chrome_app_icon_delegate.h", @@ -464,6 +468,7 @@ "//components/services/unzip/content", "//components/spellcheck/browser", "//components/supervised_user/core/browser", + "//components/tabs:public", "//components/update_client", "//components/update_client:common_impl", "//components/user_prefs", @@ -517,8 +522,6 @@ "api/automation_internal/chrome_automation_internal_api_delegate.h", "api/bookmark_manager_private/bookmark_manager_private_api.cc", "api/bookmark_manager_private/bookmark_manager_private_api.h", - "api/bookmarks/bookmarks_api.cc", - "api/bookmarks/bookmarks_api.h", "api/chrome_device_permissions_prompt.h", "api/chrome_extensions_api_client.cc", "api/chrome_extensions_api_client.h", @@ -658,8 +661,6 @@ "api/tabs/tabs_windows_api.h", "api/tabs/windows_event_router.cc", "api/tabs/windows_event_router.h", - "bookmarks/bookmarks_helpers.cc", - "bookmarks/bookmarks_helpers.h", "browser_extension_window_controller.cc", "browser_extension_window_controller.h", "chrome_app_icon_loader.cc",
diff --git a/chrome/browser/extensions/DEPS b/chrome/browser/extensions/DEPS index 96aec20..e23247e 100644 --- a/chrome/browser/extensions/DEPS +++ b/chrome/browser/extensions/DEPS
@@ -4,6 +4,7 @@ "+components/guest_view/common", "+components/security_state/content", "+components/live_caption", + "+components/tabs/public", "+dbus", "+extensions/strings/grit/extensions_strings.h", "+services/network/public",
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc index 0106c95..3bef5db 100644 --- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc +++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
@@ -657,10 +657,7 @@ ExtensionTabUtil::OpenTabParams options; options.url = node->url().spec(); - if (params->params.has_value()) { - options.active = params->params.value().active; - options.split = params->params.value().split; - } + options.active = params->active; options.bookmark_id = node->id(); auto result =
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc index 7332397..cbceebd 100644 --- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc +++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc
@@ -109,7 +109,7 @@ TEST_F(BookmarkManagerPrivateApiUnitTest, RunOpenInNewTabFunction) { auto new_tab_function = base::MakeRefCounted<BookmarkManagerPrivateOpenInNewTabFunction>(); - std::string args = base::StringPrintf(R"(["%s"])", node_id().c_str()); + std::string args = base::StringPrintf(R"(["%s", false])", node_id().c_str()); ASSERT_TRUE( api_test_utils::RunFunction(new_tab_function.get(), args, profile())); @@ -122,7 +122,7 @@ base::MakeRefCounted<BookmarkManagerPrivateOpenInNewTabFunction>(); std::string node_id = base::NumberToString(model()->bookmark_bar_node()->id()); - std::string args = base::StringPrintf(R"(["%s"])", node_id.c_str()); + std::string args = base::StringPrintf(R"(["%s", false])", node_id.c_str()); EXPECT_EQ("Cannot open a folder in a new tab.", api_test_utils::RunFunctionAndReturnError(new_tab_function.get(), args, profile()));
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api_unittest.cc b/chrome/browser/extensions/api/bookmarks/bookmarks_api_unittest.cc index ca7caa2..cf723ebb 100644 --- a/chrome/browser/extensions/api/bookmarks/bookmarks_api_unittest.cc +++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api_unittest.cc
@@ -133,6 +133,10 @@ EXPECT_EQ(result_node.index, model()->other_node()->children().size() - 1); } +#if !BUILDFLAG(IS_ANDROID) +// TODO(crbug.com/414844449): Port to desktop Android once default visible +// bookmarks behavior is clarified. + // Tests that attempting to create a bookmark with no parent folder specified // succeeds and uses the account bookmarks folder when the user is signed in // with bookmarks in transport mode. @@ -155,6 +159,7 @@ EXPECT_EQ(result_node.index, model()->account_other_node()->children().size() - 1); } +#endif // !BUILDFLAG(IS_ANDROID) // Tests creating a bookmark with a valid parent specified. TEST_F(BookmarksApiUnittest, Create_ValidParent) { @@ -249,6 +254,9 @@ ASSERT_TRUE(model()->mobile_node()->IsVisible()); } +#if !BUILDFLAG(IS_ANDROID) +// TODO(crbug.com/414844449): Port to desktop Android once default visible +// bookmarks behavior is clarified. TEST_F(BookmarksApiUnittest, Create_NonVisibleParent) { // The mobile node is not visible, because it is empty. ASSERT_FALSE(model()->mobile_node()->IsVisible()); @@ -262,6 +270,7 @@ EXPECT_EQ(error, bookmarks_errors::kNoParentError); } +#endif // !BUILDFLAG(IS_ANDROID) TEST_F(BookmarksApiUnittest, Get_SucceedsForLocalPermanentFolderWhenNoAccountFolders) { @@ -295,6 +304,9 @@ EXPECT_THAT(result, ResultMatchesNodes(expected_nodes)); } +#if !BUILDFLAG(IS_ANDROID) +// TODO(crbug.com/414844449): Port to desktop Android once default visible +// bookmarks behavior is clarified. TEST_F(BookmarksApiUnittest, Get_ReturnsEmptyForNonVisibleFolderNoVisibilityEnforcement) { base::test::ScopedFeatureList scoped_feature_list; @@ -326,6 +338,7 @@ EXPECT_EQ(error, extensions::bookmarks_errors::kNoNodeError); } +#endif // !BUILDFLAG(IS_ANDROID) TEST_F(BookmarksApiUnittest, Get_FailsForNonExistentId) { auto get_function = base::MakeRefCounted<BookmarksGetFunction>(); @@ -335,6 +348,9 @@ EXPECT_EQ(error, extensions::bookmarks_errors::kNoNodeError); } +#if !BUILDFLAG(IS_ANDROID) +// TODO(crbug.com/414844449): Port to desktop Android once default visible +// bookmarks behavior is clarified. TEST_F(BookmarksApiUnittest, GetChildren_ReturnsEmptyForNonVisibleFolderNoVisibilityEnforcement) { base::test::ScopedFeatureList scoped_feature_list; @@ -366,6 +382,7 @@ EXPECT_EQ(error, extensions::bookmarks_errors::kNoNodeError); } +#endif // !BUILDFLAG(IS_ANDROID) TEST_F(BookmarksApiUnittest, GetChildren_FailsForNonExistentId) { auto get_function = base::MakeRefCounted<BookmarksGetChildrenFunction>(); @@ -375,6 +392,9 @@ EXPECT_EQ(error, extensions::bookmarks_errors::kNoNodeError); } +#if !BUILDFLAG(IS_ANDROID) +// TODO(crbug.com/414844449): Port to desktop Android once default visible +// bookmarks behavior is clarified. TEST_F(BookmarksApiUnittest, GetSubTree_ReturnsEmptyForNonVisibleFolderNoVisibilityEnforcement) { base::test::ScopedFeatureList scoped_feature_list; @@ -406,6 +426,7 @@ EXPECT_EQ(error, extensions::bookmarks_errors::kNoNodeError); } +#endif // !BUILDFLAG(IS_ANDROID) TEST_F(BookmarksApiUnittest, GetSubTree_FailsForNonExistentId) { auto get_function = base::MakeRefCounted<BookmarksGetSubTreeFunction>(); @@ -426,6 +447,9 @@ EXPECT_THAT(result, ResultMatchesNodes(expected_nodes)); } +#if !BUILDFLAG(IS_ANDROID) +// TODO(crbug.com/414844449): Port to desktop Android once default visible +// bookmarks behavior is clarified. TEST_F(BookmarksApiUnittest, Search_NonVisibleFolderNotReturned) { // Set the title of the folder node to a fixed value. model()->SetTitle(model()->mobile_node(), u"Mobile Bookmarks", @@ -540,6 +564,7 @@ EXPECT_EQ(result_node.index, 0); EXPECT_EQ(model()->account_other_node()->children()[0].get(), folder_node()); } +#endif // !BUILDFLAG(IS_ANDROID) // Tests that attempting to move a bookmark to a non-folder parent does // not add the bookmark to that parent. @@ -574,6 +599,9 @@ ASSERT_TRUE(url_node->children().empty()); } +#if !BUILDFLAG(IS_ANDROID) +// TODO(crbug.com/414844449): Port to desktop Android once default visible +// bookmarks behavior is clarified. TEST_F(BookmarksApiUnittest, Move_NonVisibleParentNoVisibilityEnforcement) { base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitAndDisableFeature( @@ -614,6 +642,7 @@ EXPECT_EQ(error, bookmarks_errors::kNoParentError); } +#endif // !BUILDFLAG(IS_ANDROID) // Tests that attempting to move a folder to itself returns an error. TEST_F(BookmarksApiUnittest, Move_FolderToItself) {
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.cc b/chrome/browser/extensions/api/cookies/cookies_api.cc index 4c77b172..e284ce2 100644 --- a/chrome/browser/extensions/api/cookies/cookies_api.cc +++ b/chrome/browser/extensions/api/cookies/cookies_api.cc
@@ -217,11 +217,13 @@ // When an off-the-record spinoff of |profile_| is created, start listening // for cookie changes there. The OTR receiver should never be bound, since // there wasn't previously an OTR profile. - CHECK(!otr_receiver_.is_bound()); + if (off_the_record->IsPrimaryOTRProfile()) { + DCHECK(!otr_receiver_.is_bound()); #if !BUILDFLAG(IS_ANDROID) - otr_profile_observation_.Observe(off_the_record); + otr_profile_observation_.Observe(off_the_record); #endif - BindToCookieManager(&otr_receiver_, off_the_record); + BindToCookieManager(&otr_receiver_, off_the_record); + } } void CookiesEventRouter::OnProfileWillBeDestroyed(Profile* profile) {
diff --git a/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc b/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc index b6164b2..e50a02d 100644 --- a/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc +++ b/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
@@ -93,6 +93,7 @@ const std::optional<MockCrashEndpoint::Report>& last_report() { return crash_endpoint_->last_report(); } + void clear_last_report() { crash_endpoint_->clear_last_report(); } raw_ptr<const Extension, DanglingUntriaged> extension_; std::unique_ptr<MockCrashEndpoint> crash_endpoint_; std::unique_ptr<ScopedMockChromeJsErrorReportProcessor> processor_; @@ -259,12 +260,14 @@ const std::optional<MockCrashEndpoint::Report>& report = last_report(); // Ensure error is not reported since devtools is open. + clear_last_report(); EXPECT_EQ("", ExecuteScriptInBackgroundPage(extension_->id(), kTestScript)); ASSERT_FALSE(report); DevToolsWindowTesting::CloseDevToolsWindow(devtools_window); // Ensure error is not reported after devtools has been closed. + clear_last_report(); EXPECT_EQ("", ExecuteScriptInBackgroundPage(extension_->id(), kTestScript)); ASSERT_FALSE(report); }
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc index fa1ff0c..83b5afa 100644 --- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc +++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -7165,19 +7165,9 @@ } // Tests that Protected Audience requests can be blocked by the -// declarativeNetRequest API, and that if they try to redirect requests, the -// request is blocked by the Protected Audience logic, which doesn't allow -// redirects, instead of being redirected. -// Flaky on Mac and Win bots, see also crbug.com/414462480 -#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) -#define MAYBE_ProtectedAudienceNetworkRequestsBlockRequests \ - DISABLED_ProtectedAudienceNetworkRequestsBlockRequests -#else -#define MAYBE_ProtectedAudienceNetworkRequestsBlockRequests \ - ProtectedAudienceNetworkRequestsBlockRequests -#endif +// declarativeNetRequest API. IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, - MAYBE_ProtectedAudienceNetworkRequestsBlockRequests) { + ProtectedAudienceNetworkRequestsBlockRequests) { privacy_sandbox::ScopedPrivacySandboxAttestations scoped_attestations( privacy_sandbox::PrivacySandboxAttestations::CreateForTesting()); // Mark all Privacy Sandbox APIs as attested since the test case is testing @@ -7265,10 +7255,74 @@ FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); run_loop.Run(); EXPECT_EQ(0u, GetAndResetRequestsToServer().count(bidder_report_url)); +} - // Load a second extension which redirects requests for the bidding script - // (not the report URL, which the first extension blocks) to a URL that serves - // an identical bidding script. +// Tests that if the declarativeNetRequest API tries to redirect Protected +// Audience requests, the request is blocked by the Protected Audience logic, +// which doesn't allow redirects, instead of being redirected. +IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, + ProtectedAudienceNetworkRequestsBlockRedirect) { + privacy_sandbox::ScopedPrivacySandboxAttestations scoped_attestations( + privacy_sandbox::PrivacySandboxAttestations::CreateForTesting()); + // Mark all Privacy Sandbox APIs as attested since the test case is testing + // behaviors not related to attestations. + privacy_sandbox::PrivacySandboxAttestations::GetInstance() + ->SetAllPrivacySandboxAttestedForTesting(true); + + ASSERT_TRUE(https_server()->Start()); + + PrivacySandboxSettingsFactory::GetForProfile(profile()) + ->SetAllPrivacySandboxAllowedForTesting(); + + NavigateToURL(https_server()->GetURL("/interest_group/fenced_frame.html")); + + GURL bidding_logic_url = + https_server()->GetURL("/interest_group/bidding_logic.js"); + GURL decision_logic_url = + https_server()->GetURL("/interest_group/decision_logic.js"); + GURL bidder_report_url = https_server()->GetURL("/echo?bidder_report"); + GURL decision_report_url = https_server()->GetURL("/echo?decision_report"); + + // Add an interest group. + EXPECT_EQ("done", content::EvalJs( + web_contents(), + content::JsReplace( + R"( + (function() { + navigator.joinAdInterestGroup({ + name: 'cars', + owner: $1, + biddingLogicURL: $2, + userBiddingSignals: [], + ads: [{ + renderURL: 'https://example.com/render', + metadata: {ad: 'metadata', here: [1, 2, 3]} + }] + }, /*joinDurationSec=*/ 300); + return 'done'; + })(); + )", + url::Origin::Create(bidding_logic_url).Serialize(), + bidding_logic_url))); + + std::string run_auction_command = content::JsReplace( + R"( + (async function() { + let config = await navigator.runAdAuction({ + seller: $1, + decisionLogicURL: $2, + interestGroupBuyers: [$1], + }); + document.querySelector('fencedframe').config = + new FencedFrameConfig(config); + return config; + })() + )", + url::Origin::Create(decision_logic_url).Serialize(), + decision_logic_url.spec()); + + // Add an extension which redirects requests for the bidding script to a URL + // that serves an identical bidding script. TestRule redirect_bidding_logic_rule = CreateGenericRule(); redirect_bidding_logic_rule.condition->url_filter = bidding_logic_url.spec() + "^";
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_functions_shared.cc b/chrome/browser/extensions/api/developer_private/developer_private_functions_shared.cc index fd28858e..bcfd7ae 100644 --- a/chrome/browser/extensions/api/developer_private/developer_private_functions_shared.cc +++ b/chrome/browser/extensions/api/developer_private/developer_private_functions_shared.cc
@@ -7,6 +7,7 @@ #include "base/barrier_closure.h" #include "base/files/file_util.h" #include "base/memory/ref_counted.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/task/thread_pool.h" #include "chrome/browser/devtools/devtools_window.h"
diff --git a/chrome/browser/extensions/api/image_writer_private/operation.cc b/chrome/browser/extensions/api/image_writer_private/operation.cc index 9e0be495..2dc7ca87 100644 --- a/chrome/browser/extensions/api/image_writer_private/operation.cc +++ b/chrome/browser/extensions/api/image_writer_private/operation.cc
@@ -29,8 +29,6 @@ namespace { -const int kMD5BufferSize = 1024; - // Returns true if the file at |image_path| is an archived image. bool IsArchive(const base::FilePath& image_path) { return ZipExtractor::IsZipFile(image_path) || @@ -256,9 +254,6 @@ void Operation::GetMD5SumOfFile( const base::FilePath& file_path, - int64_t file_size, - int progress_offset, - int progress_scale, base::OnceCallback<void(const std::string&)> callback) { DCHECK(IsRunningInCorrectSequence()); if (IsCancelled()) { @@ -273,16 +268,14 @@ return; } - if (file_size <= 0) { - file_size = file.GetLength(); - if (file_size < 0) { - Error(error::kImageOpenError); - return; - } + int64_t file_size = file.GetLength(); + if (file_size < 0) { + Error(error::kImageOpenError); + return; } PostTask(base::BindOnce(&Operation::MD5Chunk, this, std::move(file), 0, - file_size, progress_offset, progress_scale, + base::checked_cast<size_t>(file_size), std::move(callback))); } @@ -292,10 +285,8 @@ void Operation::MD5Chunk( base::File file, - int64_t bytes_processed, - int64_t bytes_total, - int progress_offset, - int progress_scale, + size_t bytes_processed, + size_t bytes_total, base::OnceCallback<void(const std::string&)> callback) { DCHECK(IsRunningInCorrectSequence()); if (IsCancelled()) @@ -303,8 +294,8 @@ CHECK_LE(bytes_processed, bytes_total); - int read_size = std::min(bytes_total - bytes_processed, - static_cast<int64_t>(kMD5BufferSize)); + std::array<uint8_t, 1024> buffer; + size_t read_size = std::min(bytes_total - bytes_processed, buffer.size()); if (read_size == 0) { // Nothing to read, we are done. @@ -312,22 +303,19 @@ base::MD5Final(&digest, &md5_context_); std::move(callback).Run(base::MD5DigestToBase16(digest)); } else { - auto buffer = base::HeapArray<char>::Uninit(kMD5BufferSize); - int len = - file.Read(bytes_processed, base::as_writable_bytes(buffer.as_span())) - .value_or(0); + int64_t offset = base::checked_cast<int64_t>(bytes_processed); + auto target = base::span(buffer).first(read_size); - if (len == read_size) { + if (file.ReadAndCheck(offset, target)) { // Process data. - base::MD5Update(&md5_context_, std::string_view(buffer.data(), len)); - int percent_curr = - ((bytes_processed + len) * progress_scale) / bytes_total + - progress_offset; + base::MD5Update(&md5_context_, target); + bytes_processed += read_size; + int percent_curr = (bytes_processed * kProgressComplete) / bytes_total; SetProgress(percent_curr); - PostTask(base::BindOnce( - &Operation::MD5Chunk, this, std::move(file), bytes_processed + len, - bytes_total, progress_offset, progress_scale, std::move(callback))); + PostTask(base::BindOnce(&Operation::MD5Chunk, this, std::move(file), + bytes_processed, bytes_total, + std::move(callback))); // Skip closing the file. return; } else {
diff --git a/chrome/browser/extensions/api/image_writer_private/operation.h b/chrome/browser/extensions/api/image_writer_private/operation.h index d62800a..37103c1c 100644 --- a/chrome/browser/extensions/api/image_writer_private/operation.h +++ b/chrome/browser/extensions/api/image_writer_private/operation.h
@@ -147,9 +147,6 @@ // sum. `progress_offset` is an percentage that will be added to the progress // of the MD5 sum before updating `progress_` but after scaling. void GetMD5SumOfFile(const base::FilePath& file, - int64_t file_size, - int progress_offset, - int progress_scale, base::OnceCallback<void(const std::string&)> callback); bool IsRunningInCorrectSequence() const; @@ -207,10 +204,8 @@ // Incrementally calculates the MD5 sum of a file. void MD5Chunk(base::File file, - int64_t bytes_processed, - int64_t bytes_total, - int progress_offset, - int progress_scale, + size_t bytes_processed, + size_t bytes_total, const base::OnceCallback<void(const std::string&)> callback); // Callbacks for Extractor.
diff --git a/chrome/browser/extensions/api/image_writer_private/test_utils.h b/chrome/browser/extensions/api/image_writer_private/test_utils.h index a0733d5..87a753da 100644 --- a/chrome/browser/extensions/api/image_writer_private/test_utils.h +++ b/chrome/browser/extensions/api/image_writer_private/test_utils.h
@@ -35,7 +35,7 @@ class ImageWriterFakeImageBurnerClient; #endif -const char kDummyExtensionId[] = "DummyExtension"; +inline constexpr char kDummyExtensionId[] = "DummyExtension"; // Default file size to use in tests. Currently 32kB. const size_t kTestFileSize = 32 * 1024; @@ -44,7 +44,7 @@ // Pattern to use in the device file. const uint8_t kDevicePattern = 0xAA; // 10101010 // Disk file system type -const char kTestFileSystemType[] = "vfat"; +inline constexpr char kTestFileSystemType[] = "vfat"; // A mock around the operation manager for tracking callbacks. Note that there // are non-virtual methods on this class that should not be called in tests.
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc index 1d55f1b..a7b8434 100644 --- a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc +++ b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc
@@ -181,7 +181,7 @@ SetStage(image_writer_api::Stage::kVerifyDownload); - GetMD5SumOfFile(image_path_, 0, 0, kProgressComplete, + GetMD5SumOfFile(image_path_, base::BindOnce(&WriteFromUrlOperation::VerifyDownloadCompare, this, std::move(continuation))); }
diff --git a/chrome/browser/extensions/api/management/management_apitest.cc b/chrome/browser/extensions/api/management/management_apitest.cc index 5e7ea951..120cb69 100644 --- a/chrome/browser/extensions/api/management/management_apitest.cc +++ b/chrome/browser/extensions/api/management/management_apitest.cc
@@ -261,7 +261,8 @@ }); });)"; - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(true); + auto auto_accept_pwa_install_confirmation = + web_app::SetAutoAcceptPWAInstallConfirmationForTesting(); const GURL start_url = https_test_server_.GetURL(web_app_start_url); webapps::AppId web_app_id = web_app::GenerateAppId(/*manifest_id_path=*/std::nullopt, start_url); @@ -284,8 +285,6 @@ web_app::proto::INSTALLED_WITH_OS_INTEGRATION); EXPECT_EQ(2, static_cast<int>( provider->ui_manager().GetNumWindowsForApp(web_app_id))); - - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(false); } net::EmbeddedTestServer https_test_server_;
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc b/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc index 0d04d61..dadd99f5 100644 --- a/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc +++ b/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc
@@ -1775,36 +1775,49 @@ // Check if the suggestion is received (+1 for the IPH). ASSERT_EQ(5U, result.size()) << AutocompleteResultAsString(result); - // Each extension suggestion header should match the extension name that - // it came from. Extension suggestions should also be grouped together. + // Suggestions from the same extension should be grouped together and their + // group id header should match the extension name. std::set<std::u16string> extension_names = {u"alpha", u"dog"}; + std::set<omnibox::GroupId> extension_group_ids = { + omnibox::GROUP_UNSCOPED_EXTENSION_1, omnibox::GROUP_UNSCOPED_EXTENSION_2}; { - EXPECT_EQ(AutocompleteProvider::TYPE_UNSCOPED_EXTENSION, - result.match_at(0).provider->type()); - EXPECT_EQ(omnibox::GROUP_UNSCOPED_EXTENSION_1, - result.match_at(0).suggestion_group_id); + EXPECT_THAT(AutocompleteProvider::TYPE_UNSCOPED_EXTENSION, + testing::Eq(result.match_at(0).provider->type())); + EXPECT_THAT(extension_group_ids, + testing::Contains(result.match_at(0).suggestion_group_id)); EXPECT_THAT(extension_names, testing::Contains(result.GetHeaderForSuggestionGroup( - *result.match_at(1).suggestion_group_id))); - extension_names.erase(result.GetHeaderForSuggestionGroup( - *result.match_at(1).suggestion_group_id)); + result.match_at(0).suggestion_group_id.value()))); + + EXPECT_THAT(AutocompleteProvider::TYPE_UNSCOPED_EXTENSION, + testing::Eq(result.match_at(1).provider->type())); + EXPECT_THAT(extension_group_ids, + testing::Contains(result.match_at(1).suggestion_group_id)); + EXPECT_THAT(extension_names, + testing::Contains(result.GetHeaderForSuggestionGroup( + result.match_at(1).suggestion_group_id.value()))); } - // The third and fourth match should be from the other extension. + + extension_group_ids.erase(result.match_at(1).suggestion_group_id.value()); + extension_names.erase(result.GetHeaderForSuggestionGroup( + result.match_at(1).suggestion_group_id.value())); + { - EXPECT_EQ(AutocompleteProvider::TYPE_UNSCOPED_EXTENSION, - result.match_at(2).provider->type()); - EXPECT_EQ(omnibox::GROUP_UNSCOPED_EXTENSION_2, - result.match_at(2).suggestion_group_id); + EXPECT_THAT(AutocompleteProvider::TYPE_UNSCOPED_EXTENSION, + testing::Eq(result.match_at(2).provider->type())); + EXPECT_THAT(extension_group_ids, + testing::Contains(result.match_at(2).suggestion_group_id)); EXPECT_THAT(extension_names, testing::Contains(result.GetHeaderForSuggestionGroup( - *result.match_at(2).suggestion_group_id))); - EXPECT_EQ(AutocompleteProvider::TYPE_UNSCOPED_EXTENSION, - result.match_at(3).provider->type()); - EXPECT_EQ(omnibox::GROUP_UNSCOPED_EXTENSION_2, - result.match_at(3).suggestion_group_id); + result.match_at(2).suggestion_group_id.value()))); + + EXPECT_THAT(AutocompleteProvider::TYPE_UNSCOPED_EXTENSION, + testing::Eq(result.match_at(3).provider->type())); + EXPECT_THAT(extension_group_ids, + testing::Contains(result.match_at(3).suggestion_group_id)); EXPECT_THAT(extension_names, testing::Contains(result.GetHeaderForSuggestionGroup( - *result.match_at(3).suggestion_group_id))); + result.match_at(3).suggestion_group_id.value()))); } } } // namespace extensions
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc index 4ac2686..10af690fd 100644 --- a/chrome/browser/extensions/api/tabs/tabs_api.cc +++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -64,7 +64,6 @@ #include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/recently_audible_helper.h" -#include "chrome/browser/ui/tabs/split_tab_data.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_model.h" @@ -88,6 +87,7 @@ #include "components/tab_groups/tab_group_color.h" #include "components/tab_groups/tab_group_id.h" #include "components/tab_groups/tab_group_visual_data.h" +#include "components/tabs/public/split_tab_data.h" #include "components/tabs/public/split_tab_id.h" #include "components/translate/core/browser/language_state.h" #include "components/translate/core/common/language_detection_details.h"
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc index aa4c5914..4fc79ca 100644 --- a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc +++ b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
@@ -25,8 +25,6 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h" -#include "chrome/browser/ui/tabs/split_tab_collection.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -39,6 +37,8 @@ #include "components/saved_tab_groups/public/types.h" #include "components/sessions/content/session_tab_helper.h" #include "components/tab_groups/tab_group_id.h" +#include "components/tabs/public/split_tab_collection.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "content/public/browser/navigation_entry.h" #include "content/public/test/navigation_simulator.h" #include "content/public/test/web_contents_tester.h"
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc index 8bab3abf..198e134 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "extensions/browser/api/web_request/web_request_api.h" + #include <stddef.h> #include <stdint.h> @@ -41,10 +43,10 @@ #include "extensions/browser/api/declarative_net_request/test_utils.h" #include "extensions/browser/api/web_request/extension_web_request_event_router.h" #include "extensions/browser/api/web_request/upload_data_presenter.h" -#include "extensions/browser/api/web_request/web_request_api.h" #include "extensions/browser/api/web_request/web_request_api_constants.h" #include "extensions/browser/api/web_request/web_request_api_helpers.h" #include "extensions/browser/api/web_request/web_request_info.h" +#include "extensions/buildflags/buildflags.h" #include "extensions/common/api/declarative_net_request.h" #include "extensions/common/api/web_request.h" #include "extensions/common/constants.h" @@ -57,6 +59,8 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-forward.h" +static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE)); + namespace helpers = extension_web_request_api_helpers; namespace keys = extension_web_request_api_constants; namespace web_request = extensions::api::web_request;
diff --git a/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc index 88bac723..fafae55 100644 --- a/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc
@@ -2,20 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "extensions/browser/api/web_request/web_request_event_details.h" + #include <memory> #include "base/check_deref.h" #include "base/values.h" #include "extensions/browser/api/web_request/web_request_api_constants.h" #include "extensions/browser/api/web_request/web_request_api_helpers.h" -#include "extensions/browser/api/web_request/web_request_event_details.h" #include "extensions/browser/api/web_request/web_request_info.h" +#include "extensions/buildflags/buildflags.h" #include "google_apis/gaia/gaia_urls.h" #include "net/http/http_response_headers.h" #include "net/http/http_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" +static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE)); + namespace extensions { TEST(WebRequestEventDetailsTest, SetResponseHeaders) {
diff --git a/chrome/browser/extensions/desktop_android/desktop_android_extensions_browser_client.cc b/chrome/browser/extensions/desktop_android/desktop_android_extensions_browser_client.cc index 83a0936a..28127d7 100644 --- a/chrome/browser/extensions/desktop_android/desktop_android_extensions_browser_client.cc +++ b/chrome/browser/extensions/desktop_android/desktop_android_extensions_browser_client.cc
@@ -21,6 +21,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_selections.h" +#include "components/signin/core/browser/signin_header_helper.h" #include "components/update_client/update_client.h" #include "components/value_store/value_store_factory.h" #include "components/version_info/version_info.h" @@ -42,6 +43,7 @@ #include "extensions/browser/updater/scoped_extension_updater_keep_alive.h" #include "extensions/browser/url_request_util.h" #include "extensions/common/features/feature_channel.h" +#include "google_apis/gaia/gaia_urls.h" #include "services/network/public/mojom/url_loader.mojom.h" using content::BrowserContext; @@ -103,6 +105,20 @@ *Profile::FromBrowserContext(context), factory, observer); } + // The following code is used to support chrome.webRequest api for + // CalculateOnHeadersReceivedDelta(), until ChromeExtensionAPIClient is ported + // for desktop android. + bool ShouldHideResponseHeader(const GURL& url, + const std::string& header_name) const override { + // Gaia may send a OAUth2 authorization code in the Dice response header, + // which could allow an extension to generate a refresh token for the + // account. + return url.host_piece() == + GaiaUrls::GetInstance()->gaia_url().host_piece() && + base::CompareCaseInsensitiveASCII(header_name, + signin::kDiceResponseHeader) == 0; + } + private: std::unique_ptr<MessagingDelegate> messaging_delegate_; };
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc index 0e1e7f7..8ec335e9 100644 --- a/chrome/browser/extensions/extension_tab_util.cc +++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -14,8 +14,8 @@ #include "chrome/browser/extensions/window_controller_list.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "components/sessions/content/session_tab_helper.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_handle.h" @@ -297,10 +297,6 @@ // will override this default. bool active = params.active.value_or(true); - // Default to unsplit for the new tab. The presence of the 'split' property - // will override this default. - bool split = params.split.value_or(false); - // Default to not pinning the tab. Setting the 'pinned' property to true // will override this default. bool pinned = params.pinned.value_or(false); @@ -379,11 +375,6 @@ if (active) navigate_params.navigated_or_inserted_contents->SetInitialFocus(); - if (split) { - tab_strip->AddToNewSplit({new_index}, - split_tabs::SplitTabLayout::kVertical); - } - ExtensionTabUtil::ScrubTabBehavior scrub_tab_behavior = ExtensionTabUtil::GetScrubTabBehavior( function->extension(), function->source_context_type(),
diff --git a/chrome/browser/extensions/extension_tab_util.h b/chrome/browser/extensions/extension_tab_util.h index c79667d..8785b77 100644 --- a/chrome/browser/extensions/extension_tab_util.h +++ b/chrome/browser/extensions/extension_tab_util.h
@@ -106,7 +106,6 @@ std::optional<int> opener_tab_id; std::optional<std::string> url; std::optional<bool> active; - std::optional<bool> split; std::optional<bool> pinned; std::optional<int> index; std::optional<int> bookmark_id;
diff --git a/chrome/browser/extensions/extension_webkit_preferences.cc b/chrome/browser/extensions/extension_webkit_preferences.cc index dff7cd5..9615662 100644 --- a/chrome/browser/extensions/extension_webkit_preferences.cc +++ b/chrome/browser/extensions/extension_webkit_preferences.cc
@@ -33,7 +33,6 @@ } if (extension->is_platform_app()) { - webkit_prefs->databases_enabled = false; webkit_prefs->local_storage_enabled = false; webkit_prefs->sync_xhr_in_documents_enabled = false; webkit_prefs->cookie_enabled = false;
diff --git a/chrome/browser/extensions/service_worker_tracking_browsertest.cc b/chrome/browser/extensions/service_worker_tracking_browsertest.cc index d05f14d8..76aec9e9 100644 --- a/chrome/browser/extensions/service_worker_tracking_browsertest.cc +++ b/chrome/browser/extensions/service_worker_tracking_browsertest.cc
@@ -114,7 +114,9 @@ extension_ = nullptr; } - void LoadServiceWorkerExtension() { + virtual std::string GetExtensionPageContent() const { return "<p>page</p>"; } + + virtual void LoadServiceWorkerExtension() { // Load a basic extension with a service worker and wait for the worker to // start running. static constexpr char kManifest[] = @@ -143,7 +145,7 @@ test_dir->WriteManifest(kManifest); test_dir->WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundScript); test_dir->WriteFile(FILE_PATH_LITERAL("extension_page_tab.html"), - "<p>page</p>"); + GetExtensionPageContent()); ExtensionTestMessageListener extension_oninstall_listener_fired( "installed listener fired"); const Extension* extension = LoadExtension( @@ -176,6 +178,14 @@ const Extension* extension() { return extension_; } + TestExtensionDir* test_extension_dir() { + if (test_extension_dirs_.size() != 1) { + ADD_FAILURE() << "Expected exactly one test extension directory"; + return nullptr; + } + return test_extension_dirs_.front().get(); + } + raw_ptr<const Extension> extension_; // Ensure `TestExtensionDir`s live past the test helper methods finishing. std::vector<std::unique_ptr<TestExtensionDir>> test_extension_dirs_; @@ -783,6 +793,96 @@ EXPECT_FALSE(web_contents->IsCrashed()); } +// Tests tracking behavior of the main extension service worker when an +// additional service worker is registered by the extension for a sub-scope +// via `navigator.serviceWorker.register()` from an extension page. +class ServiceWorkerSubScopeWorkerTrackingBrowserTest + : public ServiceWorkerIdTrackingBrowserTest { + protected: + std::string GetExtensionPageContent() const override { + return R"(<script src="/page.js"></script>)"; + } + + void LoadServiceWorkerExtension() override { + ServiceWorkerIdTrackingBrowserTest::LoadServiceWorkerExtension(); + + // Code for a service worker that will be registered for a sub-scope + // of the extension root scope. This service worker is not allowed + // access to extension APIs, as it's not listed in the manifest. + { + base::ScopedAllowBlockingForTesting allow_blocking; + base::CreateDirectory(test_extension_dir()->UnpackedPath().Append( + FILE_PATH_LITERAL("subscope"))); + test_extension_dir()->WriteFile(FILE_PATH_LITERAL("subscope/sw.js"), R"( + console.log("subscope service worker"); + )"); + } + + // Code for the script that will be executed as part of the extension page. + // This registers the previously defined service worker. + test_extension_dir()->WriteFile(FILE_PATH_LITERAL("page.js"), R"( + navigator.serviceWorker.register("subscope/sw.js").then(function() { + // Wait until the service worker is active. + return navigator.serviceWorker.ready; + }).then(function(r) { + console.log("registration successful"); + }).catch(function(err) { + console.log("registration error: " + err.message); + }); + )"); + } +}; + +// Tests that stopping a service worker that was registered for +// a sub-scope via `navigation.serviceWorker.register()`, rather +// than being declared in the extension's manifest does not influence the +// tracking of the main extension service worker. Regression test for +// crbug.com/395536907. +IN_PROC_BROWSER_TEST_F(ServiceWorkerSubScopeWorkerTrackingBrowserTest, + StoppingSubScopeWorkerDoesNotAffectExtensionWorker) { + ASSERT_NO_FATAL_FAILURE(LoadServiceWorkerExtensionAndOpenExtensionTab()); + + // Wait for a console message that confirms the service worker for + // the sub-scope has been registered. Note that we can't use + // ExtensionTestMessageListener here since extension APIs are not + // available. + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + content::WebContentsConsoleObserver console_observer(web_contents); + console_observer.SetPattern("registration successful"); + ASSERT_TRUE(console_observer.Wait()); + + // Confirm that we are tracking the main extension service worker. + std::optional<WorkerId> extension_service_worker_id = + GetWorkerIdForExtension(); + ASSERT_TRUE(extension_service_worker_id); + + // Check that there's 2 service workers running in total. + content::ServiceWorkerContext* sw_context = + GetServiceWorkerContext(profile()); + ASSERT_TRUE(sw_context); + EXPECT_EQ(sw_context->GetRunningServiceWorkerInfos().size(), 2ul); + // One of them should be the main extension service worker. + EXPECT_TRUE(sw_context->GetRunningServiceWorkerInfos().contains( + extension_service_worker_id->version_id)); + + // Stop the sub-scope service worker. + TestServiceWorkerTaskQueueObserver untracked_observer; + GURL sub_scope(extension()->url().spec() + "subscope/"); + content::StopServiceWorkerForScope(sw_context, sub_scope, base::DoNothing()); + // Wait until the code responsible for untracking workers is called. + untracked_observer.WaitForUntrackServiceWorkerState(sub_scope); + + // Verify that the main extension service worker is still tracked as running + // by the task queue. + ServiceWorkerTaskQueue::WorkerState* worker_state = GetWorkerState(); + EXPECT_EQ(worker_state->browser_state(), + ServiceWorkerTaskQueue::BrowserState::kReady); + EXPECT_EQ(worker_state->renderer_state(), + ServiceWorkerTaskQueue::RendererState::kActive); + EXPECT_TRUE(worker_state->worker_id()); +} + } // namespace } // namespace extensions
diff --git a/chrome/browser/fast_checkout/fast_checkout_trigger_validator.h b/chrome/browser/fast_checkout/fast_checkout_trigger_validator.h index 72e5a1c..d16a275 100644 --- a/chrome/browser/fast_checkout/fast_checkout_trigger_validator.h +++ b/chrome/browser/fast_checkout/fast_checkout_trigger_validator.h
@@ -8,7 +8,7 @@ #include "components/autofill/core/browser/foundations/browser_autofill_manager.h" #include "components/autofill/core/browser/integrators/fast_checkout/fast_checkout_enums.h" -constexpr char kUmaKeyFastCheckoutTriggerOutcome[] = +inline constexpr char kUmaKeyFastCheckoutTriggerOutcome[] = "Autofill.FastCheckout.TriggerOutcome"; // Checks whether a Fast Checkout run should be permitted or not.
diff --git a/chrome/browser/feedback/system_logs/log_sources/related_website_sets_source_unittest.cc b/chrome/browser/feedback/system_logs/log_sources/related_website_sets_source_unittest.cc index e899857..2a4c43c3 100644 --- a/chrome/browser/feedback/system_logs/log_sources/related_website_sets_source_unittest.cc +++ b/chrome/browser/feedback/system_logs/log_sources/related_website_sets_source_unittest.cc
@@ -145,11 +145,9 @@ SetGlobalSets(net::GlobalFirstPartySets( base::Version("0.0"), {{primary1_site, - {net::FirstPartySetEntry(primary1_site, net::SiteType::kPrimary, - std::nullopt)}}, + {net::FirstPartySetEntry(primary1_site, net::SiteType::kPrimary)}}, {associate_site, - {net::FirstPartySetEntry(primary1_site, net::SiteType::kAssociated, - 0)}}}, + {net::FirstPartySetEntry(primary1_site, net::SiteType::kAssociated)}}}, {{primary1_cctld, primary1_site}})); // The context config of the profile adds a new set: @@ -159,10 +157,10 @@ net::FirstPartySetsContextConfig::Create( {{primary2_site, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - primary2_site, net::SiteType::kPrimary, std::nullopt))}, + primary2_site, net::SiteType::kPrimary))}, {service_site, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - primary2_site, net::SiteType::kService, std::nullopt))}}) + primary2_site, net::SiteType::kService))}}) .value()); service()->InitForTesting(); @@ -200,23 +198,19 @@ base::Version("0.0"), { {primary, - {net::FirstPartySetEntry(primary, net::SiteType::kPrimary, - std::nullopt)}}, + {net::FirstPartySetEntry(primary, net::SiteType::kPrimary)}}, {associated3, - {net::FirstPartySetEntry(primary, net::SiteType::kAssociated, 2)}}, + {net::FirstPartySetEntry(primary, net::SiteType::kAssociated)}}, {associated1, - {net::FirstPartySetEntry(primary, net::SiteType::kAssociated, 0)}}, + {net::FirstPartySetEntry(primary, net::SiteType::kAssociated)}}, {associated2, - {net::FirstPartySetEntry(primary, net::SiteType::kAssociated, 1)}}, + {net::FirstPartySetEntry(primary, net::SiteType::kAssociated)}}, {service2, - {net::FirstPartySetEntry(primary, net::SiteType::kService, - std::nullopt)}}, + {net::FirstPartySetEntry(primary, net::SiteType::kService)}}, {service1, - {net::FirstPartySetEntry(primary, net::SiteType::kService, - std::nullopt)}}, + {net::FirstPartySetEntry(primary, net::SiteType::kService)}}, {service3, - {net::FirstPartySetEntry(primary, net::SiteType::kService, - std::nullopt)}}, + {net::FirstPartySetEntry(primary, net::SiteType::kService)}}, }, {}));
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc b/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc index 9a31807..f467cee 100644 --- a/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc +++ b/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc
@@ -230,7 +230,7 @@ {{net::SchemefulSite(GURL("https://example.test")), net::FirstPartySetEntryOverride(net::FirstPartySetEntry( net::SchemefulSite(GURL("https://primary.test")), - net::SiteType::kAssociated, std::nullopt))}}) + net::SiteType::kAssociated))}}) .value()); service()->InitForTesting(); @@ -258,7 +258,7 @@ {{example_site, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( net::SchemefulSite(GURL("https://primary.test")), - net::SiteType::kAssociated, std::nullopt))}}) + net::SiteType::kAssociated))}}) .value()); service()->InitForTesting(); EXPECT_TRUE(service()->IsSiteInManagedSet(example_site)); @@ -323,7 +323,7 @@ {{example_site, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( net::SchemefulSite(GURL("https://primary.test")), - net::SiteType::kAssociated, std::nullopt))}}) + net::SiteType::kAssociated))}}) .value()); SetRwsEnabledViaPref(false); service()->InitForTesting(); @@ -343,11 +343,9 @@ kVersion, { {associate1_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, - 0)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}}, {primary_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary, - std::nullopt)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)}}, }, {})); @@ -364,10 +362,10 @@ FindEntry_FpsEnabled_ReturnsEmptyUntilAllSetsReady) { net::SchemefulSite primary_site(GURL("https://primary.test")); net::SchemefulSite associate1_site(GURL("https://associate1.test")); - net::FirstPartySetEntry primary_entry(net::FirstPartySetEntry( - primary_site, net::SiteType::kPrimary, std::nullopt)); + net::FirstPartySetEntry primary_entry( + net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)); net::FirstPartySetEntry associate1_entry( - net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, 0)); + net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)); SetRwsEnabledViaPref(true); // Verify that FindEntry returns empty if the global sets and profile sets @@ -403,10 +401,10 @@ net::SchemefulSite primary_site(GURL("https://primary.test")); net::SchemefulSite associate_site(GURL("https://associate.test")); - net::FirstPartySetEntry primary_entry(net::FirstPartySetEntry( - primary_site, net::SiteType::kPrimary, std::nullopt)); + net::FirstPartySetEntry primary_entry( + net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)); net::FirstPartySetEntry associate_entry( - net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, 0)); + net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)); SetRwsEnabledViaPref(true); @@ -441,10 +439,10 @@ net::SchemefulSite primary_site(GURL("https://primary.test")); net::SchemefulSite associate_site(GURL("https://associate.test")); - net::FirstPartySetEntry primary_entry(net::FirstPartySetEntry( - primary_site, net::SiteType::kPrimary, std::nullopt)); + net::FirstPartySetEntry primary_entry( + net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)); net::FirstPartySetEntry associate_entry( - net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, 0)); + net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)); SetRwsEnabledViaPref(true); @@ -480,11 +478,9 @@ kVersion, { {primary_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary, - std::nullopt)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)}}, {associate_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, - 0)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}}, }, {})); @@ -506,10 +502,10 @@ ForEachEffectiveSetEntry_ReturnsEmptyUntilAllSetsReady) { net::SchemefulSite primary_site(GURL("https://primary.test")); net::SchemefulSite associate_site(GURL("https://associate.test")); - net::FirstPartySetEntry primary_entry(net::FirstPartySetEntry( - primary_site, net::SiteType::kPrimary, std::nullopt)); + net::FirstPartySetEntry primary_entry( + net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)); net::FirstPartySetEntry associate_entry( - net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, 0)); + net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)); SetRwsEnabledViaPref(true); // Verify that ForEachEffectiveSetEntry returns false if FPS is not @@ -558,12 +554,12 @@ net::SchemefulSite primary_site(GURL("https://primary.test")); net::SchemefulSite associate_site(GURL("https://associate.test")); net::SchemefulSite service_site(GURL("https://service.test")); - net::FirstPartySetEntry primary_entry(net::FirstPartySetEntry( - primary_site, net::SiteType::kPrimary, std::nullopt)); + net::FirstPartySetEntry primary_entry( + net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)); net::FirstPartySetEntry associate_entry( - net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, 0)); - net::FirstPartySetEntry override_entry(net::FirstPartySetEntry( - primary_site, net::SiteType::kService, std::nullopt)); + net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)); + net::FirstPartySetEntry override_entry( + net::FirstPartySetEntry(primary_site, net::SiteType::kService)); // Create the global First-Party Sets with the following set: // { primary: "https://primary.test", @@ -597,8 +593,7 @@ TEST_F(FirstPartySetsPolicyServicePrefTest, OnProfileConfigReady_InitDisabled_NotifiesReadyWithConfig) { net::SchemefulSite test_primary(GURL("https://a.test")); - net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary, - std::nullopt); + net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary); net::FirstPartySetsContextConfig test_config = net::FirstPartySetsContextConfig::Create( {{test_primary, net::FirstPartySetEntryOverride(test_entry)}}) @@ -659,8 +654,7 @@ TEST_F(FirstPartySetsPolicyServicePrefTest, OnRelatedWebsiteSetsEnabledChanged_Enables_WithConfig) { net::SchemefulSite test_primary(GURL("https://a.test")); - net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary, - std::nullopt); + net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary); net::FirstPartySetsContextConfig test_config = net::FirstPartySetsContextConfig::Create( {{test_primary, net::FirstPartySetEntryOverride(test_entry)}}) @@ -726,8 +720,7 @@ TEST_F(FirstPartySetsPolicyServiceTest, NotifiesReadyWithConfigAndCacheFilter) { net::SchemefulSite test_primary(GURL("https://a.test")); - net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary, - std::nullopt); + net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary); net::FirstPartySetsContextConfig test_config = net::FirstPartySetsContextConfig::Create( {{test_primary, net::FirstPartySetEntryOverride(test_entry)}}) @@ -749,8 +742,7 @@ TEST_F(FirstPartySetsPolicyServiceTest, ComputeFirstPartySetMetadata_BeforeInitialization) { net::SchemefulSite test_primary(GURL("https://a.test")); - net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary, - std::nullopt); + net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary); net::FirstPartySetsContextConfig test_config = net::FirstPartySetsContextConfig::Create( {{test_primary, net::FirstPartySetEntryOverride(test_entry)}}) @@ -771,8 +763,7 @@ TEST_F(FirstPartySetsPolicyServiceTest, ComputeFirstPartySetMetadata_AfterInitialization_StillAsync) { net::SchemefulSite test_primary(GURL("https://a.test")); - net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary, - std::nullopt); + net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary); net::FirstPartySetsContextConfig test_config = net::FirstPartySetsContextConfig::Create( {{test_primary, net::FirstPartySetEntryOverride(test_entry)}}) @@ -791,8 +782,7 @@ TEST_F(FirstPartySetsPolicyServiceTest, ComputeFirstPartySetMetadata_AfterInitialization_Sync) { net::SchemefulSite test_primary(GURL("https://a.test")); - net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary, - std::nullopt); + net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary); net::FirstPartySetsContextConfig test_config = net::FirstPartySetsContextConfig::Create( {{test_primary, net::FirstPartySetEntryOverride(test_entry)}}) @@ -812,8 +802,7 @@ TEST_P(FirstPartySetsPolicyServicePrefTest, ComputeFirstPartySetMetadata_PrefDisabled) { net::SchemefulSite test_primary(GURL("https://a.test")); - net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary, - std::nullopt); + net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary); net::FirstPartySetsContextConfig test_config = net::FirstPartySetsContextConfig::Create( {{test_primary, net::FirstPartySetEntryOverride(test_entry)}})
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 775db982..cf221ff7 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -3088,17 +3088,17 @@ { "name": "enable-desktop-pwas-tab-strip", "owners": [ "pwa-team@google.com" ], - "expiry_milestone": 140 + "expiry_milestone": 150 }, { "name": "enable-desktop-pwas-tab-strip-customizations", "owners": [ "cros-web-apps-core@google.com", "pwa-team@google.com" ], - "expiry_milestone": 140 + "expiry_milestone": 150 }, { "name": "enable-desktop-pwas-tab-strip-settings", "owners": [ "pwa-team@google.com" ], - "expiry_milestone": 132 + "expiry_milestone": 150 }, { "name": "enable-disco-feed-endpoint", @@ -3953,6 +3953,11 @@ "expiry_milestone": 125 }, { + "name": "enable-pix-account-linking", + "owners": [ "vishwasuppoor@google.com", "chrome-payments-team@google.com", "payments-autofill-team@google.com" ], + "expiry_milestone": 143 + }, + { "name": "enable-pix-payments", "owners": [ "siashah@google.com", "chrome-payments-team@google.com", "payments-autofill-team@google.com" ], "expiry_milestone": 140 @@ -7456,7 +7461,7 @@ { "name": "pdf-xfa-forms", "owners": [ "thestig@chromium.org", "//pdf/OWNERS" ], - "expiry_milestone": 135 + "expiry_milestone": 140 }, { "name": "permission-element", @@ -7501,6 +7506,14 @@ "expiry_milestone": 130 }, { + "name": "pinned-tab-toast-on-close", + "owners": [ + "dljames@chromium.org", + "top-chrome-desktop-ui@google.com" + ], + "expiry_milestone": 150 + }, + { "name": "platform-keys-changes-wave-1", "owners": [ "fsandrade@chromium.org",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 191efbe8..3dde30f 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -480,11 +480,6 @@ "If enabled, the full screen signin promo will be forced to show up at " "Chrome start-up."; -const char kFontationsFontBackendName[] = "Enable Fontations font backend"; -const char kFontationsFontBackendDescription[] = - "If enabled, the Fontations font backend will be used for web fonts where " - "otherwise FreeType would have been used."; - const char kFwupdDeveloperModeName[] = "Enable fwupd developer mode"; const char kFwupdDeveloperModeDescription[] = "Allows display and installation in UI of unauthenticated firmware by " @@ -1373,6 +1368,11 @@ "system compositor."; #if BUILDFLAG(IS_ANDROID) +const char kEnablePixAccountLinkingName[] = "Enable Pix account linking"; +const char kEnablePixAccountLinkingDescription[] = + "When enabled, users without linked Pix accounts will be prompted to link " + "their Pix accounts to Google Wallet."; + const char kEnablePixPaymentsName[] = "Enable Pix payments"; const char kEnablePixPaymentsDescription[] = "When enabled, users will be offered to pay for Pix transactions using " @@ -3306,17 +3306,6 @@ "Allows prerendering pages to execute more lifecycle updates, such as " "prepaint, before activation"; -const char kWarmUpCompositorName[] = "Warm up compositor"; -const char kWarmUpCompositorDescription[] = - "Allows compositor to start warming up on certain signals"; - -const char kPrerender2WarmUpCompositorName[] = - "Warm up compositor on prerendering"; -const char kPrerender2WarmUpCompositorDescription[] = - "Enables compositor warming up on particular loading events of prerender " - "initial navigation. Requires chrome://flags/#compositor-warm-up to be " - "enabled"; - const char kPrerender2ForNewTabPageAndroidName[] = "Enable prerendering on New Tab Page Android"; const char kPrerender2ForNewTabPageAndroidDescription[] = @@ -3985,6 +3974,11 @@ const char kTopChromeToastRefinementsName[] = "Top Chrome Toast Refinements"; const char kTopChromeToastRefinementsDescription[] = "Enables the use of options to control which toasts appear."; + +const char kPinnedTabToastOnCloseName[] = "Pinned Tab Toast On Close"; +const char kPinnedTabToastOnCloseDescription[] = + "Enable to show a confirmation toast that displays when a pinned tab is " + "closed via the keyboard shortcut."; #endif const char kTopChromeTouchUiName[] = "Touch UI Layout";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index b63113f..1aff2eb8 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -785,6 +785,9 @@ extern const char kEnableDelegatedCompositingDescription[]; #if BUILDFLAG(IS_ANDROID) +extern const char kEnablePixAccountLinkingName[]; +extern const char kEnablePixAccountLinkingDescription[]; + extern const char kEnablePixPaymentsName[]; extern const char kEnablePixPaymentsDescription[]; @@ -1907,12 +1910,6 @@ extern const char kPrerender2EarlyDocumentLifecycleUpdateName[]; extern const char kPrerender2EarlyDocumentLifecycleUpdateDescription[]; -extern const char kWarmUpCompositorName[]; -extern const char kWarmUpCompositorDescription[]; - -extern const char kPrerender2WarmUpCompositorName[]; -extern const char kPrerender2WarmUpCompositorDescription[]; - extern const char kPrerender2ForNewTabPageAndroidName[]; extern const char kPrerender2ForNewTabPageAndroidDescription[]; @@ -2301,6 +2298,9 @@ extern const char kTopChromeToastRefinementsName[]; extern const char kTopChromeToastRefinementsDescription[]; + +extern const char kPinnedTabToastOnCloseName[]; +extern const char kPinnedTabToastOnCloseDescription[]; #endif extern const char kTopChromeTouchUiName[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index cbbb38f..c418a0ed 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -179,7 +179,6 @@ &history_clusters::internal::kOmniboxAction, &kAdaptiveButtonInTopToolbarCustomizationV2, &kAdaptiveButtonInTopToolbarPageSummary, - &kAllowNewIncognitoTabIntents, &kAllowTabClosingUponMinimization, &kAndroidAppIntegration, &kAndroidAppIntegrationV2, @@ -465,10 +464,6 @@ "AdaptiveButtonInTopToolbarPageSummary", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kAllowNewIncognitoTabIntents, - "AllowNewIncognitoTabIntents", - base::FEATURE_ENABLED_BY_DEFAULT); - BASE_FEATURE(kAllowTabClosingUponMinimization, "AllowTabClosingUponMinimization", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index a76bb28..c56769af 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -16,7 +16,6 @@ // Alphabetical: BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarCustomizationV2); BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarPageSummary); -BASE_DECLARE_FEATURE(kAllowNewIncognitoTabIntents); BASE_DECLARE_FEATURE(kAllowTabClosingUponMinimization); BASE_DECLARE_FEATURE(kAndroidAppIntegration); BASE_DECLARE_FEATURE(kAndroidAppIntegrationV2);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 0ee2fc3..ac06dde 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -158,7 +158,6 @@ "AdaptiveButtonInTopToolbarCustomizationV2"; public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_PAGE_SUMMARY = "AdaptiveButtonInTopToolbarPageSummary"; - public static final String ALLOW_NEW_INCOGNITO_TAB_INTENTS = "AllowNewIncognitoTabIntents"; public static final String ALLOW_TAB_CLOSING_UPON_MINIMIZATION = "AllowTabClosingUponMinimization"; public static final String ALWAYS_BLOCK_3PCS_INCOGNITO = "AlwaysBlock3pcsIncognito";
diff --git a/chrome/browser/glic/e2e_test/internal_test_placeholder_constants.h b/chrome/browser/glic/e2e_test/internal_test_placeholder_constants.h index 506e66485..9eee867 100644 --- a/chrome/browser/glic/e2e_test/internal_test_placeholder_constants.h +++ b/chrome/browser/glic/e2e_test/internal_test_placeholder_constants.h
@@ -13,8 +13,8 @@ namespace glic::test { -const char kAllowedHostAndPathForWpr[] = ""; -const char kTestAccountLabel[] = ""; +inline constexpr char kAllowedHostAndPathForWpr[] = ""; +inline constexpr char kTestAccountLabel[] = ""; auto kWprArguments = std::vector<std::string>{}; } // namespace glic::test
diff --git a/chrome/browser/glic/fre/glic_fre_controller.cc b/chrome/browser/glic/fre/glic_fre_controller.cc index 19a6213..74a8600 100644 --- a/chrome/browser/glic/fre/glic_fre_controller.cc +++ b/chrome/browser/glic/fre/glic_fre_controller.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/glic/fre/fre_util.h" #include "chrome/browser/glic/fre/glic_fre_dialog_view.h" +#include "chrome/browser/glic/glic_enabling.h" #include "chrome/browser/glic/glic_keyed_service.h" #include "chrome/browser/glic/glic_keyed_service_factory.h" #include "chrome/browser/glic/glic_pref_names.h" @@ -30,6 +31,7 @@ #include "chrome/browser/shell_integration.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/tabs/public/tab_dialog_manager.h" #include "chrome/browser/ui/tabs/public/tab_features.h" #include "chrome/common/channel_info.h" @@ -79,8 +81,7 @@ bool GlicFreController::ShouldShowFreDialog() { // If the given profile has not previously completed the FRE, then it should // be shown. - return profile_->GetPrefs()->GetInteger(prefs::kGlicCompletedFre) != - static_cast<int>(prefs::FreStatus::kCompleted); + return !GlicEnabling::HasConsentedForProfile(profile_); } bool GlicFreController::CanShowFreDialog(Browser* browser) { @@ -96,6 +97,17 @@ return tab && tab->CanShowModalUI(); } +void GlicFreController::OpenFreDialogInNewTab(BrowserWindowInterface* bwi) { + Browser* browser = bwi->GetBrowserForMigrationOnly(); + if (!ShouldShowFreDialog()) { + return; + } + chrome::AddAndReturnTabAt(browser, GURL(), /*index=*/-1, /*foreground=*/true); + if (CanShowFreDialog(browser)) { + ShowFreDialog(browser); + } +} + void GlicFreController::ShowFreDialog(Browser* browser) { CHECK(CanShowFreDialog(browser)); @@ -112,7 +124,6 @@ // Sign-in required and handled by AuthController. In this case, do not // record the FRE load time metric. show_start_time_ = base::TimeTicks(); - return; } } @@ -133,18 +144,17 @@ CreateView(); - tabs::TabInterface* tab_interface = browser->GetActiveTabInterface(); + tab_showing_modal_ = browser->GetActiveTabInterface(); // Note that this call to `CreateShowDialogAndBlockTabInteraction` is // necessarily preceded by a call to `CanShowModalUI`. See // `GlicFreController::CanShowFreDialog`. // TODO(crbug.com/393400004): This returned widget should be configured to // use a synchronous close. - fre_widget_ = - tab_interface->GetTabFeatures() - ->tab_dialog_manager() - ->CreateShowDialogAndBlockTabInteraction(fre_view_.release()); + fre_widget_ = tab_showing_modal_->GetTabFeatures() + ->tab_dialog_manager() + ->CreateShowDialogAndBlockTabInteraction( + fre_view_.release(), /*close_on_navigation=*/false); GetWebContents()->Focus(); - tab_showing_modal_ = tab_interface; will_detach_subscription_ = tab_showing_modal_->RegisterWillDetach( base::BindRepeating(&GlicFreController::OnTabShowingModalWillDetach, base::Unretained(this)));
diff --git a/chrome/browser/glic/fre/glic_fre_controller.h b/chrome/browser/glic/fre/glic_fre_controller.h index 7b53161..8299613 100644 --- a/chrome/browser/glic/fre/glic_fre_controller.h +++ b/chrome/browser/glic/fre/glic_fre_controller.h
@@ -66,6 +66,10 @@ // showing the dialog. bool CanShowFreDialog(Browser* browser); + // Open the new tab page in the browser and show the FRE in that tab if + // possible. + void OpenFreDialogInNewTab(BrowserWindowInterface* bwi); + // Shows the FRE dialog. This should only be called if `ShouldShowFreDialog` // and `CanShowFreDialog` are both satisfied. void ShowFreDialog(Browser* browser);
diff --git a/chrome/browser/glic/glic_enabling.cc b/chrome/browser/glic/glic_enabling.cc index 89db3f6..7805564 100644 --- a/chrome/browser/glic/glic_enabling.cc +++ b/chrome/browser/glic/glic_enabling.cc
@@ -23,15 +23,6 @@ namespace glic { -namespace { - -bool HasConsentedForProfile(Profile* profile) { - return profile->GetPrefs()->GetInteger(prefs::kGlicCompletedFre) == - static_cast<int>(prefs::FreStatus::kCompleted); -} - -} // namespace - GlicEnabling::ProfileEnablement GlicEnabling::EnablementForProfile( Profile* profile) { ProfileEnablement result; @@ -119,6 +110,11 @@ return EnablementForProfile(profile).IsEnabled(); } +bool GlicEnabling::HasConsentedForProfile(Profile* profile) { + return profile->GetPrefs()->GetInteger(prefs::kGlicCompletedFre) == + static_cast<int>(prefs::FreStatus::kCompleted); +} + bool GlicEnabling::IsEnabledAndConsentForProfile(Profile* profile) { return EnablementForProfile(profile).IsEnabledAndConsented(); }
diff --git a/chrome/browser/glic/glic_enabling.h b/chrome/browser/glic/glic_enabling.h index 0cfbf05..7c6482bfa 100644 --- a/chrome/browser/glic/glic_enabling.h +++ b/chrome/browser/glic/glic_enabling.h
@@ -61,6 +61,9 @@ // Code inside should use instance method IsAllowed() instead. static bool IsEnabledForProfile(Profile* profile); + // Returns true if the profile has completed the FRE. + static bool HasConsentedForProfile(Profile* profile); + // Returns true if the given profile has Glic enabled and has completed the // FRE. True implies that IsEnabledByFlags(), IsProfileEligible(profile), and // IsEnabledForProfile(profile) are also true. This value can change at
diff --git a/chrome/browser/glic/glic_keyed_service.cc b/chrome/browser/glic/glic_keyed_service.cc index 7f3f6b60..34afb46 100644 --- a/chrome/browser/glic/glic_keyed_service.cc +++ b/chrome/browser/glic/glic_keyed_service.cc
@@ -154,6 +154,16 @@ window_controller_->Toggle(bwi, prevent_close, source); } +void GlicKeyedService::OpenFreDialogInNewTab(BrowserWindowInterface* bwi) { + // Glic may be disabled for certain user profiles (the user is browsing in + // incognito or guest mode, policy, etc). In those cases, the entry points to + // this method should already have been removed. + CHECK(GlicEnabling::IsEnabledForProfile(profile_)); + + glic_profile_manager_->SetActiveGlic(this); + window_controller_->fre_controller()->OpenFreDialogInNewTab(bwi); +} + void GlicKeyedService::CloseUI() { window_controller_->Shutdown(); host().Shutdown();
diff --git a/chrome/browser/glic/glic_keyed_service.h b/chrome/browser/glic/glic_keyed_service.h index 3431c01..7b5125d 100644 --- a/chrome/browser/glic/glic_keyed_service.h +++ b/chrome/browser/glic/glic_keyed_service.h
@@ -74,6 +74,8 @@ bool prevent_close, mojom::InvocationSource source); + void OpenFreDialogInNewTab(BrowserWindowInterface* bwi); + // Forcibly close the UI. This is similar to Shutdown in that it causes the // window controller to shutdown (and clear cached state), but unlike // Shutdown, it doesn't unregister as the "active glic" with the profile
diff --git a/chrome/browser/glic/glic_profile_manager.cc b/chrome/browser/glic/glic_profile_manager.cc index 0eb12b1..bdddeb8 100644 --- a/chrome/browser/glic/glic_profile_manager.cc +++ b/chrome/browser/glic/glic_profile_manager.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/profiles/profile_picker.h" +#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" #include "content/public/browser/network_service_instance.h" @@ -203,17 +204,23 @@ } void GlicProfileManager::DidSelectProfile(Profile* profile) { - // TODO(crbug.com/399727295) Remove once the profile picker calls this with - // fully initialized profiles. if (!GlicEnabling::IsEnabledForProfile(profile)) { return; } - // Toggle glic but prevent close if it is already open for the selected - // profile. + GlicKeyedService* service = GlicKeyedServiceFactory::GetGlicKeyedService(profile); - service->ToggleUI(nullptr, /*prevent_close=*/true, - mojom::InvocationSource::kProfilePicker); + + if (!GlicEnabling::HasConsentedForProfile(profile)) { + // Open a browser and show the FRE in a new tab. + chrome::ScopedTabbedBrowserDisplayer displayer(profile); + service->OpenFreDialogInNewTab(displayer.browser()); + } else { + // Toggle glic but prevent close if it is already open for the selected + // profile. + service->ToggleUI(nullptr, /*prevent_close=*/true, + mojom::InvocationSource::kProfilePicker); + } } void GlicProfileManager::AddObserver(Observer* observer) {
diff --git a/chrome/browser/glic/widget/glic_window_controller.h b/chrome/browser/glic/widget/glic_window_controller.h index ad9d3a2d..acc5306 100644 --- a/chrome/browser/glic/widget/glic_window_controller.h +++ b/chrome/browser/glic/widget/glic_window_controller.h
@@ -74,7 +74,7 @@ // Show, summon, or activate the panel if needed, or close it if it's already // active and prevent_close is false. - virtual void Toggle(BrowserWindowInterface* browser, + virtual void Toggle(BrowserWindowInterface* bwi, bool prevent_close, mojom::InvocationSource source) = 0;
diff --git a/chrome/browser/google/google_brand_code_map_chromeos.cc b/chrome/browser/google/google_brand_code_map_chromeos.cc index 7259d9b..de6ff148 100644 --- a/chrome/browser/google/google_brand_code_map_chromeos.cc +++ b/chrome/browser/google/google_brand_code_map_chromeos.cc
@@ -185,6 +185,7 @@ {"FCPG", {"WITB", "FOXJ", "YJQZ"}}, {"FCVS", {"HOBX", "YMDN", "GKTP"}}, {"FENM", {"NTNB", "RIJA", "WEHG"}}, + {"FHOM", {"RFZM", "TFXJ", "ENQL"}}, {"FHYR", {"YKUD", "XTKX", "QFMD"}}, {"FIGU", {"VMWP", "SBFY", "IYUS"}}, {"FNVY", {"DLEJ", "DCNV", "XALG"}}, @@ -463,6 +464,7 @@ {"MZVS", {"VUZM", "RIDT", "URTS"}}, {"NAMM", {"BFSS", "BKVK", "EBDV"}}, {"NBQS", {"KMJF", "MFWA", "UWRX"}}, + {"NDQE", {"XNUV", "DTTJ", "RAYN"}}, {"NFCO", {"VBYL", "IUIS", "KMVC"}}, {"NGVJ", {"GVZG", "GJWP", "CFNU"}}, {"NHYA", {"JUYB", "XYFL", "XRQH"}}, @@ -536,7 +538,9 @@ {"QLWW", {"LNZB", "JTVW", "XVCX"}}, {"QNDA", {"VFMY", "KTBL", "UOJY"}}, {"QOAX", {"ITAT", "RSMG", "IFBZ"}}, + {"QPEQ", {"EHWX", "ROSZ", "MPXK"}}, {"QQFU", {"ZUKV", "QBAU", "SIID"}}, + {"QQKF", {"PRKZ", "BFPF", "WSQL"}}, {"QRII", {"NHZV", "AUJW", "NSZF"}}, {"QRQB", {"IXPL", "NBMV", "KVTR"}}, {"QSAX", {"IGTA", "AMBN", "ASDW"}}, @@ -639,6 +643,8 @@ {"TZNR", {"MHIP", "YJBK", "VDZV"}}, {"TZXN", {"VQDQ", "NKBA", "NNUN"}}, {"UBKE", {"CPTX", "EGAC", "MRXT"}}, + {"UBRR", {"UBYQ", "SDFZ", "DPKG"}}, + {"UCAB", {"LLAZ", "RLYU", "CADQ"}}, {"UCLD", {"XHWD", "CBQT", "UUFI"}}, {"UDAJ", {"XNWC", "GPQO", "JTJZ"}}, {"UERT", {"XSDZ", "GOMR", "THXS"}}, @@ -707,6 +713,7 @@ {"WPFB", {"JOSR", "MHKH", "OHJH"}}, {"WPKT", {"NAPI", "TQRX", "DBBS"}}, {"WTXQ", {"NPCP", "DIOS", "DSTX"}}, + {"WUSA", {"BWCF", "RWUY", "BFXG"}}, {"WVRW", {"GJGN", "QQFA", "AGVP"}}, {"WWTI", {"GZHX", "JHGD", "ZDGL"}}, {"WXZG", {"IUGR", "JOEE", "PTHY"}},
diff --git a/chrome/browser/headless/headless_mode_protocol_browsertest.cc b/chrome/browser/headless/headless_mode_protocol_browsertest.cc index 2ccaec9..65fed52 100644 --- a/chrome/browser/headless/headless_mode_protocol_browsertest.cc +++ b/chrome/browser/headless/headless_mode_protocol_browsertest.cc
@@ -316,10 +316,13 @@ "sanity/fullscreen-restore-window.js") #endif // !BUILDFLAG(IS_MAC) +// This currently fails on Mac, see https://crbug.com/416088625 +#if !BUILDFLAG(IS_MAC) HEADLESS_MODE_PROTOCOL_TEST_WITH_COMMAND_LINE_EXTRAS( MaximizedWindowSize, "sanity/maximized-window-size.js", "--screen-info={1600x1200}") +#endif // !BUILDFLAG(IS_MAC) // This currently fails on Mac, see https://crbug.com/1500046 #if !BUILDFLAG(IS_MAC) @@ -348,8 +351,6 @@ "--ozone-override-screen-size=1234,5678") #endif -// --screen-info switch is only supported on Linux and Windows at this time. -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) // This currently results in an unexpected screen orientation type, // see http://crbug.com/398150465. HEADLESS_MODE_PROTOCOL_TEST_WITH_COMMAND_LINE_EXTRAS( @@ -357,8 +358,15 @@ "sanity/multiple-screen-details.js", "--screen-info={label=#1}{600x800 label='#2'}") +// TODO(crbug.com/40283476): MoveWindowBetweenScreens is failing on Mac +#if !BUILDFLAG(IS_MAC) +#define MAYBE_MoveWindowBetweenScreens MoveWindowBetweenScreens +#else +#define MAYBE_MoveWindowBetweenScreens DISABLED_MoveWindowBetweenScreens +#endif + HEADLESS_MODE_PROTOCOL_TEST_WITH_COMMAND_LINE_EXTRAS( - MoveWindowBetweenScreens, + MAYBE_MoveWindowBetweenScreens, "sanity/move-window-between-screens.js", "--screen-info={label='#1'}{label='#2'}{0,600 label='#3'}{label='#4'}") @@ -367,11 +375,16 @@ "sanity/window-open-on-secondary-screen.js", "--screen-info={label='#1'}{label='#2'} --disable-popup-blocking") +// TODO(crbug.com/40283476): CreateTargetSecondaryScreen is failing on Mac +#if !BUILDFLAG(IS_MAC) +#define MAYBE_CreateTargetSecondaryScreen CreateTargetSecondaryScreen +#else +#define MAYBE_CreateTargetSecondaryScreen DISABLED_CreateTargetSecondaryScreen +#endif + HEADLESS_MODE_PROTOCOL_TEST_WITH_COMMAND_LINE_EXTRAS( - CreateTargetSecondaryScreen, + MAYBE_CreateTargetSecondaryScreen, "sanity/create-target-secondary-screen.js", "--screen-info={label='#1'}{label='#2'}") -#endif - } // namespace headless
diff --git a/chrome/browser/k_anonymity_service/k_anonymity_service_urls.h b/chrome/browser/k_anonymity_service/k_anonymity_service_urls.h index 87f9062..8f254ca 100644 --- a/chrome/browser/k_anonymity_service/k_anonymity_service_urls.h +++ b/chrome/browser/k_anonymity_service/k_anonymity_service_urls.h
@@ -5,16 +5,16 @@ #ifndef CHROME_BROWSER_K_ANONYMITY_SERVICE_K_ANONYMITY_SERVICE_URLS_H_ #define CHROME_BROWSER_K_ANONYMITY_SERVICE_K_ANONYMITY_SERVICE_URLS_H_ -constexpr char kGenNonUniqueUserIdPath[] = "/v1/generateShortIdentifier"; -constexpr char kFetchKeysPathFmt[] = +inline constexpr char kGenNonUniqueUserIdPath[] = "/v1/generateShortIdentifier"; +inline constexpr char kFetchKeysPathFmt[] = "/v1/%d/fetchKeys?key=%s"; // Put the short ID in the path. -constexpr char kIssueTrustTokenPathFmt[] = +inline constexpr char kIssueTrustTokenPathFmt[] = "/v1/%d/issueTrustToken"; // Put the short ID in the path. -constexpr char kJoinSetPathFmt[] = "/v1/types/%s/sets/%s:join?key=%s"; -constexpr char kJoinSetOhttpPath[] = "/v1/proxy/keys?key="; +inline constexpr char kJoinSetPathFmt[] = "/v1/types/%s/sets/%s:join?key=%s"; +inline constexpr char kJoinSetOhttpPath[] = "/v1/proxy/keys?key="; -constexpr char kQuerySetsPath[] = "/v1:query?key="; -constexpr char kQuerySetOhttpPath[] = "/v1/proxy/keys?key="; +inline constexpr char kQuerySetsPath[] = "/v1:query?key="; +inline constexpr char kQuerySetOhttpPath[] = "/v1/proxy/keys?key="; #endif // CHROME_BROWSER_K_ANONYMITY_SERVICE_K_ANONYMITY_SERVICE_URLS_H_
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_feature.h b/chrome/browser/media/router/discovery/access_code/access_code_cast_feature.h index bd0de5d..c1311d3 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_feature.h +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_feature.h
@@ -21,12 +21,12 @@ namespace prefs { // Pref name that allows the AccessCode/QR code scanning dialog button to be // shown. -constexpr char kAccessCodeCastEnabled[] = +inline constexpr char kAccessCodeCastEnabled[] = "media_router.access_code_cast.enabled"; // Pref name for the pref that determines how long a scanned receiver remains in // the receiver list. Duration is measured in seconds. -constexpr char kAccessCodeCastDeviceDuration[] = +inline constexpr char kAccessCodeCastDeviceDuration[] = "media_router.access_code_cast.device_duration"; // Pref that keeps track of cast devices added on a user's profile. It is @@ -35,13 +35,13 @@ // as a base::Value::Dict. // Whenever a cast device is discovered via access code, a new entry will be // added to this dictionary (or updated if the MediaSink::Id already exists). -constexpr char kAccessCodeCastDevices[] = +inline constexpr char kAccessCodeCastDevices[] = "media_router.access_code_cast.devices"; // Pref that keeps track of when a cast device is added. It is be registered // as a dictionary pref with each key being a MediaSink::Id and value being a // base::Time. -constexpr char kAccessCodeCastDeviceAdditionTime[] = +inline constexpr char kAccessCodeCastDeviceAdditionTime[] = "media_router.access_code_cast.addition_time"; } // namespace prefs
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_test_util.h b/chrome/browser/media/router/discovery/access_code/access_code_test_util.h index c2eb2f71..43aca48 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_test_util.h +++ b/chrome/browser/media/router/discovery/access_code/access_code_test_util.h
@@ -14,11 +14,12 @@ namespace media_router { -const char kExpectedDisplayName[] = "test_device"; -const char kExpectedSinkId[] = "1234"; -const char kExpectedPort[] = "666"; -const char kExpectedIpV4[] = "192.0.2.146"; -const char kExpectedIpV6[] = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; +inline constexpr char kExpectedDisplayName[] = "test_device"; +inline constexpr char kExpectedSinkId[] = "1234"; +inline constexpr char kExpectedPort[] = "666"; +inline constexpr char kExpectedIpV4[] = "192.0.2.146"; +inline constexpr char kExpectedIpV6[] = + "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; using DiscoveryDevice = chrome_browser_media::proto::DiscoveryDevice; using NetworkInfo = chrome_browser_media::proto::NetworkInfo;
diff --git a/chrome/browser/media/router/providers/cast/cast_internal_message_util.h b/chrome/browser/media/router/providers/cast/cast_internal_message_util.h index 38020c8f..beeb27a 100644 --- a/chrome/browser/media/router/providers/cast/cast_internal_message_util.h +++ b/chrome/browser/media/router/providers/cast/cast_internal_message_util.h
@@ -20,12 +20,12 @@ // Values in the "supportedMediaCommands" list in media status messages // sent to the Cast sender SDK. -constexpr char kMediaCommandPause[] = "pause"; -constexpr char kMediaCommandSeek[] = "seek"; -constexpr char kMediaCommandStreamVolume[] = "stream_volume"; -constexpr char kMediaCommandStreamMute[] = "stream_mute"; -constexpr char kMediaCommandQueueNext[] = "queue_next"; -constexpr char kMediaCommandQueuePrev[] = "queue_prev"; +inline constexpr char kMediaCommandPause[] = "pause"; +inline constexpr char kMediaCommandSeek[] = "seek"; +inline constexpr char kMediaCommandStreamVolume[] = "stream_volume"; +inline constexpr char kMediaCommandStreamMute[] = "stream_mute"; +inline constexpr char kMediaCommandQueueNext[] = "queue_next"; +inline constexpr char kMediaCommandQueuePrev[] = "queue_prev"; // Values in the "supportedMediaCommands" bit array in media status messages // received from Cast receivers. They are converted to string values by
diff --git a/chrome/browser/media_galleries/media_galleries_preferences.h b/chrome/browser/media_galleries/media_galleries_preferences.h index 6c5bc5a..e517ca5 100644 --- a/chrome/browser/media_galleries/media_galleries_preferences.h +++ b/chrome/browser/media_galleries/media_galleries_preferences.h
@@ -35,8 +35,9 @@ typedef uint64_t MediaGalleryPrefId; const MediaGalleryPrefId kInvalidMediaGalleryPrefId = 0; -const char kMediaGalleriesPrefsVersionKey[] = "preferencesVersion"; -const char kMediaGalleriesDefaultGalleryTypeKey[] = "defaultGalleryType"; +inline constexpr char kMediaGalleriesPrefsVersionKey[] = "preferencesVersion"; +inline constexpr char kMediaGalleriesDefaultGalleryTypeKey[] = + "defaultGalleryType"; struct MediaGalleryPermission { MediaGalleryPrefId pref_id;
diff --git a/chrome/browser/metrics/chrome_metrics_service_accessor.h b/chrome/browser/metrics/chrome_metrics_service_accessor.h index 3827c4d4..8dc956a2 100644 --- a/chrome/browser/metrics/chrome_metrics_service_accessor.h +++ b/chrome/browser/metrics/chrome_metrics_service_accessor.h
@@ -78,6 +78,10 @@ class CrOSPreConsentMetricsManagerTest; } // namespace metrics +namespace optimization_guide { +class ChromeOnDeviceModelServiceController; +} // namespace optimization_guide + namespace safe_browsing { class ChromeSafeBrowsingUIManagerDelegate; class DownloadUrlSBClient; @@ -192,6 +196,7 @@ friend class glic::GlicSyntheticTrialManager; #endif friend class OptimizationGuideKeyedService; + friend class optimization_guide::ChromeOnDeviceModelServiceController; friend class WebUITabStripFieldTrial; friend class feed::FeedServiceDelegateImpl; friend class FirstRunService;
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc index 1cfb5f7..c38b64d3 100644 --- a/chrome/browser/metrics/process_memory_metrics_emitter.cc +++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -1740,6 +1740,7 @@ base::flat_set<const performance_manager::PageNode*> page_nodes = performance_manager::GraphOperations::GetAssociatedPageNodes( process_node); + const base::TimeTicks now = base::TimeTicks::Now(); for (const performance_manager::PageNode* page_node : page_nodes) { if (page_node->GetUkmSourceID() == ukm::kInvalidSourceId) continue; @@ -1759,7 +1760,7 @@ page_info.hosts_main_frame = HostsMainFrame(process_node, page_node); page_info.is_visible = page_node->IsVisible(); page_info.time_since_last_visibility_change = - page_node->GetTimeSinceLastVisibilityChange(); + now - page_node->GetLastVisibilityChangeTime(); page_info.time_since_last_navigation = page_node->GetTimeSinceLastNavigation(); }
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc b/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc index 0bcac26..f84c791d 100644 --- a/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc +++ b/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc
@@ -112,6 +112,9 @@ url::Origin::Create(https_server_->base_url())) { return; } + if (observer.is_valid()) { + observer_.Bind(std::move(observer)); + } EXPECT_TRUE(success); preresolve_done_count_++; if (run_loop_) @@ -129,6 +132,7 @@ protected: int preresolve_done_count_ = 0; std::unique_ptr<net::EmbeddedTestServer> https_server_; + mojo::Remote<network::mojom::ReconnectEventObserver> observer_; private: base::test::ScopedFeatureList feature_list_; @@ -336,9 +340,14 @@ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); // Now there should be an onload preconnect as well as a navigation - // preconnect. - WaitForPreresolveCount(3); - EXPECT_EQ(3, preresolve_done_count_); + // preconnect. If `SearchEnginePreconnect2` is enabled, we will have one + // additional preresolve count because navigating to a URL will start a + // preconnect due to a change in web visibility (i.e. the app is foregrounded) + // for the first navigation. + int preresolve_count = + SearchEnginePreconnector::SearchEnginePreconnect2Enabled() ? 4 : 3; + WaitForPreresolveCount(preresolve_count); + EXPECT_EQ(preresolve_count, preresolve_done_count_); } class NavigationPredictorPreconnectClientLocalURLBrowserTest
diff --git a/chrome/browser/navigation_predictor/search_engine_preconnector_browsertest.cc b/chrome/browser/navigation_predictor/search_engine_preconnector_browsertest.cc index 30f9345..abee4af 100644 --- a/chrome/browser/navigation_predictor/search_engine_preconnector_browsertest.cc +++ b/chrome/browser/navigation_predictor/search_engine_preconnector_browsertest.cc
@@ -524,8 +524,10 @@ IN_PROC_BROWSER_TEST_F(SearchEnginePreconnectorDesktopAutoStartBrowserTest, AutoStartDesktop) { + int preresolve_count = + SearchEnginePreconnector::SearchEnginePreconnect2Enabled() ? 1 : 2; // Verifies that the default search is preconnected. - WaitForPreresolveCountForURL(GURL(kGoogleSearch), 2); + WaitForPreresolveCountForURL(GURL(kGoogleSearch), preresolve_count); } class SearchEnginePreconnectorEnabledOnlyBrowserTest
diff --git a/chrome/browser/nearby_sharing/instantmessaging/constants.h b/chrome/browser/nearby_sharing/instantmessaging/constants.h index 1261e414..38a4fe1 100644 --- a/chrome/browser/nearby_sharing/instantmessaging/constants.h +++ b/chrome/browser/nearby_sharing/instantmessaging/constants.h
@@ -5,13 +5,13 @@ #ifndef CHROME_BROWSER_NEARBY_SHARING_INSTANTMESSAGING_CONSTANTS_H_ #define CHROME_BROWSER_NEARBY_SHARING_INSTANTMESSAGING_CONSTANTS_H_ -const char kInstantMessagingReceiveMessageAPI[] = +inline constexpr char kInstantMessagingReceiveMessageAPI[] = "https://instantmessaging-pa.googleapis.com/v1/messages:receiveExpress"; -const char kInstantMessagingSendMessageAPI[] = +inline constexpr char kInstantMessagingSendMessageAPI[] = "https://instantmessaging-pa.googleapis.com/v1/message:sendExpress"; // Template for optional OAuth2 authorization HTTP header. -const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s"; +inline constexpr char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s"; #endif // CHROME_BROWSER_NEARBY_SHARING_INSTANTMESSAGING_CONSTANTS_H_
diff --git a/chrome/browser/nearby_sharing/wifi_network_configuration/fake_wifi_network_configuration_handler.h b/chrome/browser/nearby_sharing/wifi_network_configuration/fake_wifi_network_configuration_handler.h index 13a2d9a6..8f83f56 100644 --- a/chrome/browser/nearby_sharing/wifi_network_configuration/fake_wifi_network_configuration_handler.h +++ b/chrome/browser/nearby_sharing/wifi_network_configuration/fake_wifi_network_configuration_handler.h
@@ -11,7 +11,7 @@ namespace { const uint64_t kDefaultId = 0; -const char kDefaultSsid[] = "not_set"; +inline constexpr char kDefaultSsid[] = "not_set"; const WifiCredentialsAttachment::SecurityType kDefaultSecurityType = sharing::mojom::WifiCredentialsMetadata::SecurityType::kWpaPsk; @@ -51,4 +51,4 @@ std::string error_message_ = "not set"; }; -#endif // CHROME_BROWSER_NEARBY_SHARING_WIFI_NETWORK_CONFIGURATION_FAKE_WIFI_NETWORK_CONFIGURATION_HANDLER_H_ +#endif // CHROME_BROWSER_NEARBY_SHARING_WIFI_NETWORK_CONFIGURATION_FAKE_WIFI_NETWORK_CONFIGURATION_HANDLER_H_
diff --git a/chrome/browser/new_tab_page/modules/new_tab_page_modules_interactive_uitest.cc b/chrome/browser/new_tab_page/modules/new_tab_page_modules_interactive_uitest.cc index bd2d936..625f4a0 100644 --- a/chrome/browser/new_tab_page/modules/new_tab_page_modules_interactive_uitest.cc +++ b/chrome/browser/new_tab_page/modules/new_tab_page_modules_interactive_uitest.cc
@@ -26,9 +26,8 @@ DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kNewTabPageElementId); using DeepQuery = WebContentsInteractionTestUtil::DeepQuery; -const DeepQuery kModulesV2Container = {"ntp-app", "ntp-modules-v2", - "#container"}; -const DeepQuery kModulesV2Wrapper = {"ntp-app", "ntp-modules-v2", "#container", +const DeepQuery kModulesV2Container = {"ntp-app", "ntp-modules", "#container"}; +const DeepQuery kModulesV2Wrapper = {"ntp-app", "ntp-modules", "#container", "ntp-module-wrapper"}; const DeepQuery kMicrosoftAuthIframe = {"ntp-app", "#microsoftAuth"}; @@ -53,18 +52,18 @@ {{ntp_features::kNtpMostRelevantTabResumptionModule, {{ntp_features::kNtpMostRelevantTabResumptionModuleDataParam, "Fake Data"}}}}, - {"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-most-relevant-tab-resumption"}, - {"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-most-relevant-tab-resumption", "ntp-module-header-v2", "#menuButton"}, - {"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-most-relevant-tab-resumption", "ntp-module-header-v2", "cr-action-menu", "dialog"}, - {"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-most-relevant-tab-resumption", "ntp-module-header-v2", "#dismiss"}, - {"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-most-relevant-tab-resumption", "ntp-module-header-v2", "#disable"}, - {{{"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {{{"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-most-relevant-tab-resumption", "#urlVisits", "a"}, "https://www.google.com"}}, }; @@ -73,29 +72,29 @@ ntp_features::kNtpCalendarModule, {{ntp_features::kNtpCalendarModule, {{ntp_features::kNtpCalendarModuleDataParam, "fake"}}}}, - {"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-google-calendar-module"}, - {"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-google-calendar-module", "ntp-module-header-v2", "#menuButton"}, - {"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-google-calendar-module", "ntp-module-header-v2", "cr-action-menu", "dialog"}, - {"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-google-calendar-module", "ntp-module-header-v2", "#dismiss"}, - {"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-google-calendar-module", "ntp-module-header-v2", "#disable"}, - {{{"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {{{"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-google-calendar-module", "ntp-calendar", "ntp-calendar-event", "#header"}, "https://foo.com/0"}, - {{"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {{"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-google-calendar-module", "ntp-calendar", "#seeMore", "a"}, "https://calendar.google.com"}, - {{"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {{"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-google-calendar-module", "ntp-calendar", "ntp-calendar-event", "cr-chip"}, "https://foo.com/attachment0"}, - {{"ntp-app", "ntp-modules-v2", "ntp-module-wrapper", + {{"ntp-app", "ntp-modules", "ntp-module-wrapper", "ntp-google-calendar-module", "ntp-calendar", "ntp-calendar-event", "cr-button"}, "https://foo.com/conference0"}}, @@ -237,8 +236,11 @@ NewTabPageModulesInteractiveUiTest, ::testing::ValuesIn(kAllModules)); +// TODO(crbug.com/416206296): Re-enable once we have a workaround for querying +// the `module_wrapper.html` slotted element. +// @see chrome/browser/resources/new_tab_page/modules/module_wrapper.html IN_PROC_BROWSER_TEST_P(NewTabPageModulesInteractiveUiTest, - ClickingHideButtonDismissesModule) { + DISABLED_ClickingHideButtonDismissesModule) { RunTestSequence( // 1. Wait for new tab page to load. LoadNewTabPage(), @@ -269,8 +271,11 @@ WaitForElementChildElementCount(kModulesV2Container, 0)); } +// TODO(crbug.com/416206296): Re-enable once we have a workaround for querying +// the `module_wrapper.html` slotted element. +// @see chrome/browser/resources/new_tab_page/modules/module_wrapper.html IN_PROC_BROWSER_TEST_P(NewTabPageModulesInteractiveUiTest, - ClickingDisableButtonDisablesModule) { + DISABLED_ClickingDisableButtonDisablesModule) { const auto& module_details = ModuleDetails(); RunTestSequence( // 1. Wait for new tab page to load. @@ -334,8 +339,11 @@ ::testing::ValuesIn(GetAllModuleLinks(kAllModules))); #endif +// TODO(crbug.com/416206296): Re-enable once we have a workaround for querying +// the `module_wrapper.html` slotted element. +// @see chrome/browser/resources/new_tab_page/modules/module_wrapper.html IN_PROC_BROWSER_TEST_P(NewTabPageModulesInteractiveLinkUiTest, - ClickingEntryNavigatesToCorrectPage) { + DISABLED_ClickingEntryNavigatesToCorrectPage) { RunTestSequence( // 1. Wait for new tab page to load. LoadNewTabPage(),
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java index 71fe3d8..a40802b 100644 --- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChannelsInitializerTest.java
@@ -321,21 +321,6 @@ @Test @Feature({"Browser", "Notifications"}) - public void testEnsureInitialized_priceDropChannel() { - mChannelsInitializer.ensureInitialized(ChromeChannelDefinitions.ChannelId.PRICE_DROP); - - assertThat(getChannelsIgnoringDefault(), hasSize(1)); - NotificationChannel channel = getChannelsIgnoringDefault().get(0); - assertThat(channel.getId(), is(ChromeChannelDefinitions.ChannelId.PRICE_DROP)); - assertThat( - channel.getName().toString(), - is(mContext.getString(R.string.notification_category_price_drop))); - assertThat(channel.getImportance(), is(NotificationManager.IMPORTANCE_DEFAULT)); - assertThat(channel.getGroup(), is(ChromeChannelDefinitions.ChannelGroupId.GENERAL)); - } - - @Test - @Feature({"Browser", "Notifications"}) public void testEnsureInitialized_priceDropDefaultChannel() { mChannelsInitializer.ensureInitialized( ChromeChannelDefinitions.ChannelId.PRICE_DROP_DEFAULT);
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChromeChannelDefinitions.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChromeChannelDefinitions.java index 20a3ffe..e4fa4608 100644 --- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChromeChannelDefinitions.java +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChromeChannelDefinitions.java
@@ -4,10 +4,7 @@ package org.chromium.chrome.browser.notifications.channels; -import android.app.NotificationChannel; import android.app.NotificationManager; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; import android.text.TextUtils; import androidx.annotation.StringDef; @@ -15,8 +12,6 @@ import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.notifications.R; -import org.chromium.components.browser_ui.notifications.NotificationManagerProxy; -import org.chromium.components.browser_ui.notifications.NotificationManagerProxyImpl; import org.chromium.components.browser_ui.notifications.channels.ChannelDefinitions; import java.lang.annotation.Retention; @@ -93,7 +88,7 @@ ChannelId.WEBAPPS, ChannelId.WEBAPPS_QUIET, ChannelId.WEBRTC_CAM_AND_MIC, - ChannelId.PRICE_DROP, + ChannelId.PRICE_DROP, // Deprecated, use PRICE_DROP_DEFAULT. ChannelId.PRICE_DROP_DEFAULT, ChannelId.SECURITY_KEY, ChannelId.BLUETOOTH, @@ -319,35 +314,11 @@ // Not added to startup channels because we want this channel to be created on the first // use. map.put( - ChannelId.PRICE_DROP, - PredefinedChannel.create( - ChannelId.PRICE_DROP, - R.string.notification_category_price_drop, - NotificationManager.IMPORTANCE_DEFAULT, - ChannelGroupId.GENERAL)); - // TODO(crbug.com/40244973): Make the new channel's behavior consistent with the old - // channel's if it's created and modified by the user. Clean this up after one or two - // milestones. - int priceDropDefaultChannelImportance = NotificationManager.IMPORTANCE_DEFAULT; - if (VERSION.SDK_INT >= VERSION_CODES.O) { - NotificationManagerProxy notificationManager = - NotificationManagerProxyImpl.getInstance(); - NotificationChannel priceDropChannel = - notificationManager.getNotificationChannel(ChannelId.PRICE_DROP); - if (priceDropChannel != null) { - startup.add(ChannelId.PRICE_DROP_DEFAULT); - if (priceDropChannel.getImportance() != NotificationManager.IMPORTANCE_LOW) { - priceDropDefaultChannelImportance = priceDropChannel.getImportance(); - } - notificationManager.deleteNotificationChannel(ChannelId.PRICE_DROP); - } - } - map.put( ChannelId.PRICE_DROP_DEFAULT, PredefinedChannel.create( ChannelId.PRICE_DROP_DEFAULT, R.string.notification_category_price_drop, - priceDropDefaultChannelImportance, + NotificationManager.IMPORTANCE_DEFAULT, ChannelGroupId.GENERAL)); // The security key notification channel will only appear for users
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java index 76d425f9..4e5d8926 100644 --- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java
@@ -11,7 +11,6 @@ import androidx.annotation.IntDef; import org.chromium.base.ApiCompatibilityUtils; -import org.chromium.base.BuildInfo; import org.chromium.base.Callback; import org.chromium.base.TimeUtils; import org.chromium.base.UnownedUserData; @@ -184,7 +183,6 @@ */ public boolean requestPermissionIfNeeded(boolean contextual) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU - || !BuildInfo.targetsAtLeastT() || ApiCompatibilityUtils.isDemoUser()) { return false; } @@ -235,7 +233,7 @@ int shouldRequestPermission() { // Notifications only require permission starting at Android T. And apps targeting < T can't // request permission as the OS prompts the user automatically. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || !BuildInfo.targetsAtLeastT()) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { return PermissionRequestMode.DO_NOT_REQUEST; }
diff --git a/chrome/browser/notifications/notification_permission_context.cc b/chrome/browser/notifications/notification_permission_context.cc index ee6fbf5..216a00e 100644 --- a/chrome/browser/notifications/notification_permission_context.cc +++ b/chrome/browser/notifications/notification_permission_context.cc
@@ -184,7 +184,8 @@ ShortcutHelper::DoesOriginContainAnyInstalledTrustedWebActivity( request_data->requesting_origin); bool contains_installed_webapp = contains_twa || contains_webapk; - if (base::android::BuildInfo::GetInstance()->is_at_least_t() && + if (base::android::BuildInfo::GetInstance()->sdk_int() >= + base::android::SDK_VERSION_T && contains_installed_webapp) { // WebAPKs match URLs using a scope URL which may contain a path. An origin // has no path and would not fall within such a scope. So to find a matching
diff --git a/chrome/browser/notifications/scheduler/internal/scheduler_config.h b/chrome/browser/notifications/scheduler/internal/scheduler_config.h index 4dc38a6..f7b9cb3 100644 --- a/chrome/browser/notifications/scheduler/internal/scheduler_config.h +++ b/chrome/browser/notifications/scheduler/internal/scheduler_config.h
@@ -12,33 +12,37 @@ namespace notifications { // Configure the maxmium number of notifications daily shown for all types. -constexpr char kMaxDailyShownAllTypeConfig[] = "max_daily_shown_all_type"; +inline constexpr char kMaxDailyShownAllTypeConfig[] = + "max_daily_shown_all_type"; // Configure the maxmium number of notifications daily shown per type. -constexpr char kMaxDailyShownPerTypeConfig[] = "max_daily_shown_per_type"; +inline constexpr char kMaxDailyShownPerTypeConfig[] = + "max_daily_shown_per_type"; // Configure the initial number of notifications daily shown per type. -constexpr char kInitialDailyShownPerTypeConfig[] = +inline constexpr char kInitialDailyShownPerTypeConfig[] = "initial_daily_shown_per_type"; // Configure the expiration duration for notifications. -constexpr char kNotificationExpirationConfig[] = +inline constexpr char kNotificationExpirationConfig[] = "notification_expiration_in_days"; // Configure the expiration duration for impressions. -constexpr char kImpressionExpirationConfig[] = "impression_expiration_in_days"; +inline constexpr char kImpressionExpirationConfig[] = + "impression_expiration_in_days"; // Configure the expiration duration for suppression. -constexpr char kSuppressionDurationConfig[] = "suppression_duration_in_days"; +inline constexpr char kSuppressionDurationConfig[] = + "suppression_duration_in_days"; // Configure the number of dismiss count. -constexpr char kDismissCountConfig[] = "dismiss_count"; +inline constexpr char kDismissCountConfig[] = "dismiss_count"; // Configure the duration of a dismiss. -constexpr char kDismissDurationConfig[] = "dismiss_duration_in_days"; +inline constexpr char kDismissDurationConfig[] = "dismiss_duration_in_days"; // Configure the duration of background task window. -constexpr char kBackgroundTaskWindowDurationConfig[] = +inline constexpr char kBackgroundTaskWindowDurationConfig[] = "background_task_window_duration_in_hours"; // Configuration of notification scheduler system.
diff --git a/chrome/browser/notifications/scheduler/public/notification_scheduler_constant.h b/chrome/browser/notifications/scheduler/public/notification_scheduler_constant.h index 7a4f97b..74984ba 100644 --- a/chrome/browser/notifications/scheduler/public/notification_scheduler_constant.h +++ b/chrome/browser/notifications/scheduler/public/notification_scheduler_constant.h
@@ -7,9 +7,9 @@ namespace notifications { -constexpr char kDefaultHelpfulButtonId[] = +inline constexpr char kDefaultHelpfulButtonId[] = "NOTIFICATION_SCHEDULER_DEFAULT_HELPFUL_BUTTON_ID"; -constexpr char kDefaultUnhelpfulButtonId[] = +inline constexpr char kDefaultUnhelpfulButtonId[] = "NOTIFICATION_SCHEDULER_DEFAULT_UNHELPFUL_BUTTON_ID"; } // namespace notifications
diff --git a/chrome/browser/on_device_translation/component_manager.cc b/chrome/browser/on_device_translation/component_manager.cc index 908ef53..83ab626 100644 --- a/chrome/browser/on_device_translation/component_manager.cc +++ b/chrome/browser/on_device_translation/component_manager.cc
@@ -147,14 +147,14 @@ // static std::set<LanguagePackKey> ComponentManager::GetInstalledLanguagePacks() { - std::set<LanguagePackKey> insalled_pack_keys; + std::set<LanguagePackKey> installed_pack_keys; for (const auto& it : kLanguagePackComponentConfigMap) { if (!GetFilePathFromGlobalPrefs(GetComponentPathPrefName(*it.second)) .empty()) { - insalled_pack_keys.insert(it.first); + installed_pack_keys.insert(it.first); } } - return insalled_pack_keys; + return installed_pack_keys; } // static
diff --git a/chrome/browser/optimization_guide/model_execution/chrome_on_device_model_service_controller.cc b/chrome/browser/optimization_guide/model_execution/chrome_on_device_model_service_controller.cc index d509291..898ee0b 100644 --- a/chrome/browser/optimization_guide/model_execution/chrome_on_device_model_service_controller.cc +++ b/chrome/browser/optimization_guide/model_execution/chrome_on_device_model_service_controller.cc
@@ -5,7 +5,9 @@ #include "chrome/browser/optimization_guide/model_execution/chrome_on_device_model_service_controller.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/metrics/chrome_metrics_service_accessor.h" #include "components/optimization_guide/core/model_execution/on_device_model_access_controller.h" +#include "components/optimization_guide/core/model_execution/performance_class.h" #include "components/optimization_guide/core/optimization_guide_features.h" #include "content/public/browser/service_process_host.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -53,4 +55,15 @@ g_instance = nullptr; } +void ChromeOnDeviceModelServiceController:: + RegisterPerformanceClassSyntheticTrial( + OnDeviceModelPerformanceClass perf_class) { + if (perf_class != OnDeviceModelPerformanceClass::kUnknown) { + ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial( + "SyntheticOnDeviceModelPerformanceClass", + SyntheticTrialGroupForPerformanceClass(perf_class), + variations::SyntheticTrialAnnotationMode::kCurrentLog); + } +} + } // namespace optimization_guide
diff --git a/chrome/browser/optimization_guide/model_execution/chrome_on_device_model_service_controller.h b/chrome/browser/optimization_guide/model_execution/chrome_on_device_model_service_controller.h index 211a97b..88969f8 100644 --- a/chrome/browser/optimization_guide/model_execution/chrome_on_device_model_service_controller.h +++ b/chrome/browser/optimization_guide/model_execution/chrome_on_device_model_service_controller.h
@@ -5,9 +5,9 @@ #ifndef CHROME_BROWSER_OPTIMIZATION_GUIDE_MODEL_EXECUTION_CHROME_ON_DEVICE_MODEL_SERVICE_CONTROLLER_H_ #define CHROME_BROWSER_OPTIMIZATION_GUIDE_MODEL_EXECUTION_CHROME_ON_DEVICE_MODEL_SERVICE_CONTROLLER_H_ -#include "components/optimization_guide/core/model_execution/on_device_model_service_controller.h" - #include "base/memory/scoped_refptr.h" +#include "components/optimization_guide/core/model_execution/on_device_model_service_controller.h" +#include "components/optimization_guide/core/optimization_guide_enums.h" namespace optimization_guide { class OnDeviceModelComponentStateManager; @@ -30,6 +30,10 @@ // created yet. static ChromeOnDeviceModelServiceController* GetSingleInstanceMayBeNull(); + void RegisterPerformanceClassSyntheticTrial( + OnDeviceModelPerformanceClass perf_class) override; + + protected: private: ~ChromeOnDeviceModelServiceController() override; };
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc index 59b73806..12487b2 100644 --- a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc +++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
@@ -202,17 +202,6 @@ } // static -void OptimizationGuideKeyedService::RegisterPerformanceClassSyntheticTrial( - OnDeviceModelPerformanceClass perf_class) { - if (perf_class != OnDeviceModelPerformanceClass::kUnknown) { - ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial( - "SyntheticOnDeviceModelPerformanceClass", - SyntheticTrialGroupForPerformanceClass(perf_class), - variations::SyntheticTrialAnnotationMode::kCurrentLog); - } -} - -// static void OptimizationGuideKeyedService::SetIsOfficialBuildForTesting( bool is_official_build) { g_is_official_build_for_testing = is_official_build; @@ -409,9 +398,11 @@ optimization_guide::features::GetOnDeviceStartupMetricDelay()); } // If the perf class was previously determined, register that. - RegisterPerformanceClassSyntheticTrial( - optimization_guide::PerformanceClassFromPref( - *g_browser_process->local_state())); + GetOnDeviceModelServiceController( + on_device_component_manager_->GetWeakPtr()) + ->RegisterPerformanceClassSyntheticTrial( + optimization_guide::PerformanceClassFromPref( + *g_browser_process->local_state())); auto* variations_service = g_browser_process->variations_service(); auto dogfood_status = @@ -853,47 +844,8 @@ void OptimizationGuideKeyedService::EnsurePerformanceClassAvailable( base::OnceClosure complete) { - if (!on_device_component_manager_ || - !on_device_component_manager_->NeedsPerformanceClassUpdate()) { - std::move(complete).Run(); - return; - } - - if (performance_class_state_ == PerformanceClassState::kComplete) { - std::move(complete).Run(); - return; - } - - // Use unsafe because cancellation isn't needed. - performance_class_callbacks_.AddUnsafe(std::move(complete)); - - if (performance_class_state_ == PerformanceClassState::kComputing) { - return; - } - - performance_class_state_ = PerformanceClassState::kComputing; - OnDeviceModelServiceController::GetEstimatedPerformanceClass( - GetOnDeviceModelServiceController( - on_device_component_manager_->GetWeakPtr()), - base::BindOnce([](OnDeviceModelPerformanceClass perf_class) { - base::UmaHistogramEnumeration( - "OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", - perf_class); - RegisterPerformanceClassSyntheticTrial(perf_class); - return perf_class; - }) - .Then(base::BindOnce( - &OnDeviceModelComponentStateManager:: - DevicePerformanceClassChanged, - on_device_component_manager_->GetWeakPtr(), - base::BindOnce( - &OptimizationGuideKeyedService::PerformanceClassUpdated, - weak_factory_.GetWeakPtr())))); -} - -void OptimizationGuideKeyedService::PerformanceClassUpdated() { - performance_class_state_ = PerformanceClassState::kComplete; - performance_class_callbacks_.Notify(); + GetOnDeviceModelServiceController(on_device_component_manager_->GetWeakPtr()) + ->EnsurePerformanceClassAvailable(std::move(complete)); } void OptimizationGuideKeyedService::FinishGetOnDeviceModelEligibility(
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service.h b/chrome/browser/optimization_guide/optimization_guide_keyed_service.h index ed50b03..24d09d85 100644 --- a/chrome/browser/optimization_guide/optimization_guide_keyed_service.h +++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service.h
@@ -9,8 +9,6 @@ #include <optional> #include <vector> -#include "base/callback_list.h" -#include "base/cancelable_callback.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/scoped_observation.h" @@ -282,9 +280,6 @@ friend class optimization_guide::android::OptimizationGuideBridge; #endif // BUILDFLAG(IS_ANDROID) - static void RegisterPerformanceClassSyntheticTrial( - optimization_guide::OnDeviceModelPerformanceClass perf_class); - // Allows tests to override the value of `version_info::IsOfficialBuild()`. static void SetIsOfficialBuildForTesting(bool is_official_build); @@ -361,9 +356,6 @@ // `complete` runs. void EnsurePerformanceClassAvailable(base::OnceClosure complete); - // Called when performance class has finished updating. - void PerformanceClassUpdated(); - void FinishGetOnDeviceModelEligibility( optimization_guide::ModelBasedCapabilityKey feature, base::OnceCallback< @@ -423,17 +415,6 @@ // Used to observe profile initialization event. base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this}; - enum class PerformanceClassState { - kNotSet, - kComputing, - kComplete, - }; - PerformanceClassState performance_class_state_ = - PerformanceClassState::kNotSet; - - // Callbacks waiting for performance class to finish computing. - base::OnceClosureList performance_class_callbacks_; - base::WeakPtrFactory<OptimizationGuideKeyedService> weak_factory_{this}; };
diff --git a/chrome/browser/os_crypt/app_bound_encryption_provider_win.cc b/chrome/browser/os_crypt/app_bound_encryption_provider_win.cc index 1e4a805..8ebeebb 100644 --- a/chrome/browser/os_crypt/app_bound_encryption_provider_win.cc +++ b/chrome/browser/os_crypt/app_bound_encryption_provider_win.cc
@@ -83,7 +83,7 @@ BASE_FEATURE(kRegenerateKeyForCatastrophicFailures, "RegenerateKeyForCatastrophicFailures", - base::FEATURE_ENABLED_BY_DEFAULT); + base::FEATURE_DISABLED_BY_DEFAULT); } // namespace features AppBoundEncryptionProviderWin::AppBoundEncryptionProviderWin(
diff --git a/chrome/browser/os_crypt/app_bound_encryption_provider_win.h b/chrome/browser/os_crypt/app_bound_encryption_provider_win.h index 52c8b1d..548d22a1 100644 --- a/chrome/browser/os_crypt/app_bound_encryption_provider_win.h +++ b/chrome/browser/os_crypt/app_bound_encryption_provider_win.h
@@ -42,9 +42,8 @@ // for data encryption by the elevated service. BASE_DECLARE_FEATURE(kAppBoundEncryptionKeyV3); -// An emergency kill switch feature to prevent key regeneration for catastrophic -// failures, in case the numbers in https://crbug.com/382059244#comment2 prove -// incorrect for some reason. +// If enabled, will re-generate a new key for catastrophic failures. See +// `DetermineErrorType` in the cc file for the two current cases. BASE_DECLARE_FEATURE(kRegenerateKeyForCatastrophicFailures); } // namespace features
diff --git a/chrome/browser/os_crypt/app_bound_encryption_provider_win_unittest.cc b/chrome/browser/os_crypt/app_bound_encryption_provider_win_unittest.cc index 92dd750..1b62b10 100644 --- a/chrome/browser/os_crypt/app_bound_encryption_provider_win_unittest.cc +++ b/chrome/browser/os_crypt/app_bound_encryption_provider_win_unittest.cc
@@ -113,6 +113,9 @@ } TEST(AppBoundEncryptionProvider, Basic) { + base::test::ScopedFeatureList feature( + os_crypt_async::features::kRegenerateKeyForCatastrophicFailures); + base::test::TaskEnvironment env; ::testing::StrictMock<MockAppBoundEncryptionOverrides> mock_app_bound;
diff --git a/chrome/browser/password_manager/password_change/change_form_submission_verifier.cc b/chrome/browser/password_manager/password_change/change_form_submission_verifier.cc index 31efaafe..b5995527 100644 --- a/chrome/browser/password_manager/password_change/change_form_submission_verifier.cc +++ b/chrome/browser/password_manager/password_change/change_form_submission_verifier.cc
@@ -11,10 +11,10 @@ #include "chrome/browser/page_content_annotations/page_content_extraction_service.h" #include "chrome/browser/page_content_annotations/page_content_extraction_service_factory.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" +#include "chrome/browser/password_manager/password_change/model_quality_logs_uploader.h" #include "chrome/browser/profiles/profile.h" #include "components/optimization_guide/content/browser/page_content_proto_provider.h" #include "components/optimization_guide/core/model_quality/model_execution_logging_wrappers.h" -#include "components/optimization_guide/core/model_quality/model_quality_log_entry.h" #include "components/optimization_guide/core/optimization_guide_features.h" #include "components/optimization_guide/core/optimization_guide_model_executor.h" #include "components/optimization_guide/core/optimization_guide_proto_util.h" @@ -53,28 +53,6 @@ .Record(ukm::UkmRecorder::Get()); } -void AddFinalModelStatusLog( - OptimizationGuideKeyedService* optimization_executor, - FinalModelStatus final_status) { - base::WeakPtr<optimization_guide::ModelQualityLogsUploaderService> - logs_uploader_ptr; - - auto* logs_uploader = - optimization_executor->GetModelQualityLogsUploaderService(); - if (logs_uploader) { - logs_uploader_ptr = logs_uploader->GetWeakPtr(); - } - - QualityLogEntry log_entry = - std::make_unique<optimization_guide::ModelQualityLogEntry>( - logs_uploader_ptr); - log_entry->log_ai_data_request() - ->mutable_password_change_submission() - ->mutable_quality() - ->set_final_model_status(final_status); - optimization_guide::ModelQualityLogEntry::Upload(std::move(log_entry)); -} - void RecordOutcomeMetrics( optimization_guide::proto ::PasswordChangeSubmissionData submission_data, ukm::SourceId ukm_id) { @@ -131,21 +109,26 @@ ChangeFormSubmissionVerifier::ChangeFormSubmissionVerifier( content::WebContents* web_contents, - FormSubmissionResultCallback callback) + FormSubmissionResultCallback callback, + ModelQualityLogsUploader* logs_uploader) : web_contents_(web_contents->GetWeakPtr()), capture_annotated_page_content_( base::BindOnce(&optimization_guide::GetAIPageContent, web_contents, optimization_guide::DefaultAIPageContentOptions())), - callback_(std::move(callback)) {} + callback_(std::move(callback)), + logs_uploader_(logs_uploader) {} ChangeFormSubmissionVerifier::ChangeFormSubmissionVerifier( base::PassKey<class ChangeFormSubmissionVerifierTest>, content::WebContents* web_contents, base::OnceCallback<void(optimization_guide::OnAIPageContentDone)> capture_annotated_page_content, - FormSubmissionResultCallback callback) - : ChangeFormSubmissionVerifier(web_contents, std::move(callback)) { + FormSubmissionResultCallback callback, + ModelQualityLogsUploader* logs_uploader) + : ChangeFormSubmissionVerifier(web_contents, + std::move(callback), + std::move(logs_uploader)) { capture_annotated_page_content_ = std::move(capture_annotated_page_content); } @@ -352,13 +335,9 @@ ChromePasswordManagerClient* client = ChromePasswordManagerClient::FromWebContents(web_contents_.get()); - OptimizationGuideKeyedService* optimization_executor = - GetOptimizationService(); if (!execution_result.response.has_value()) { LogSubmissionOutcome(SubmissionOutcome::kNoResponse, client->GetUkmSourceId()); - AddFinalModelStatusLog(optimization_executor, - FinalModelStatus::FINAL_MODEL_STATUS_UNSPECIFIED); std::move(callback_).Run(false); return; } @@ -369,12 +348,15 @@ if (!response) { LogSubmissionOutcome(SubmissionOutcome::kCouldNotParse, client->GetUkmSourceId()); - AddFinalModelStatusLog(optimization_executor, - FinalModelStatus::FINAL_MODEL_STATUS_UNSPECIFIED); std::move(callback_).Run(false); return; } + if (logging_data) { + // There is data to log, meaning this is a complete response. + logs_uploader_->MergeData(response.value(), std::move(logging_data)); + } + RecordOutcomeMetrics(response.value().outcome_data(), client->GetUkmSourceId()); PasswordChangeOutcome outcome = @@ -385,12 +367,8 @@ outcome != PasswordChangeOutcome:: PasswordChangeSubmissionData_PasswordChangeOutcome_UNKNOWN_OUTCOME) { - AddFinalModelStatusLog(optimization_executor, - FinalModelStatus::FINAL_MODEL_STATUS_FAILURE); std::move(callback_).Run(false); return; } - AddFinalModelStatusLog(optimization_executor, - FinalModelStatus::FINAL_MODEL_STATUS_SUCCESS); std::move(callback_).Run(true); }
diff --git a/chrome/browser/password_manager/password_change/change_form_submission_verifier.h b/chrome/browser/password_manager/password_change/change_form_submission_verifier.h index dfeee84f..c0951c2 100644 --- a/chrome/browser/password_manager/password_change/change_form_submission_verifier.h +++ b/chrome/browser/password_manager/password_change/change_form_submission_verifier.h
@@ -8,6 +8,7 @@ #include <string> #include "base/functional/callback_forward.h" +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/timer/timer.h" #include "components/autofill/core/common/form_data.h" @@ -19,6 +20,7 @@ namespace content { class WebContents; } +class ModelQualityLogsUploader; class OptimizationGuideKeyedService; namespace password_manager { class PasswordFormManager; @@ -63,13 +65,15 @@ "PasswordManager.PasswordChangeVerificationTriggeredAutomatically"; ChangeFormSubmissionVerifier(content::WebContents* web_contents, - FormSubmissionResultCallback callback); + FormSubmissionResultCallback callback, + ModelQualityLogsUploader* logs_uploader); ChangeFormSubmissionVerifier( base::PassKey<class ChangeFormSubmissionVerifierTest>, content::WebContents* web_contents, base::OnceCallback<void(optimization_guide::OnAIPageContentDone)> capture_annotated_page_content, - FormSubmissionResultCallback callback); + FormSubmissionResultCallback callback, + ModelQualityLogsUploader* logs_uploader); ~ChangeFormSubmissionVerifier(); // Starts chain of actions: @@ -127,6 +131,7 @@ base::OnceCallback<void(optimization_guide::OnAIPageContentDone)> capture_annotated_page_content_; FormSubmissionResultCallback callback_; + raw_ptr<ModelQualityLogsUploader> logs_uploader_; std::unique_ptr<password_manager::PasswordFormManager> form_manager_; // TODO(crbug.com/409946698): Delete this when removing support for AX tree // prompts.
diff --git a/chrome/browser/password_manager/password_change/change_form_submission_verifier_unittest.cc b/chrome/browser/password_manager/password_change/change_form_submission_verifier_unittest.cc index e8f4d5c..a7751fb9 100644 --- a/chrome/browser/password_manager/password_change/change_form_submission_verifier_unittest.cc +++ b/chrome/browser/password_manager/password_change/change_form_submission_verifier_unittest.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/password_manager/chrome_webauthn_credentials_delegate_factory.h" +#include "chrome/browser/password_manager/password_change/model_quality_logs_uploader.h" #include "chrome/browser/password_manager/password_manager_settings_service_factory.h" #include "chrome/browser/password_manager/profile_password_store_factory.h" #include "chrome/browser/sync/sync_service_factory.h" @@ -141,7 +142,8 @@ public: ChangeFormSubmissionVerifierTest() : ChromeRenderViewHostTestHarness( - base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} + base::test::TaskEnvironment::TimeSource::MOCK_TIME), + logs_uploader_(profile()) {} ~ChangeFormSubmissionVerifierTest() override = default; void SetUp() override { @@ -157,7 +159,6 @@ base::BindRepeating(&password_manager::BuildPasswordStoreInterface< content::BrowserContext, password_manager::MockPasswordStoreInterface>)); - // `ChromePasswordManagerClient` observes `AutofillManager`s, so // `ChromeAutofillClient` needs to be set up, too. autofill::ChromeAutofillClient::CreateForWebContents(web_contents()); @@ -190,7 +191,8 @@ base::OnceCallback<void(bool)> result_callback) { auto verifier = std::make_unique<ChangeFormSubmissionVerifier>( base::PassKey<class ChangeFormSubmissionVerifierTest>(), web_contents(), - std::move(capture_annotated_page_content), std::move(result_callback)); + std::move(capture_annotated_page_content), std::move(result_callback), + &logs_uploader_); verifier->FillChangePasswordForm(manager, kOldPassword, kNewPassword); return verifier; } @@ -211,6 +213,7 @@ autofill::test::AutofillUnitTestEnvironment autofill_environment_{ {.disable_server_communication = true}}; password_manager::FakeFormFetcher form_fetcher_; + ModelQualityLogsUploader logs_uploader_; MockStubPasswordManagerDriver driver_; };
diff --git a/chrome/browser/password_manager/password_change/model_quality_logs_uploader.cc b/chrome/browser/password_manager/password_change/model_quality_logs_uploader.cc new file mode 100644 index 0000000..f04f61316 --- /dev/null +++ b/chrome/browser/password_manager/password_change/model_quality_logs_uploader.cc
@@ -0,0 +1,72 @@ +// 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/password_manager/password_change/model_quality_logs_uploader.h" + +#include "base/logging.h" +#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h" +#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "components/optimization_guide/core/model_quality/model_quality_log_entry.h" +#include "content/public/browser/web_contents.h" + +using FinalModelStatus = optimization_guide::proto::FinalModelStatus; +using PasswordChangeOutcome = optimization_guide::proto :: + PasswordChangeSubmissionData_PasswordChangeOutcome; + +ModelQualityLogsUploader::ModelQualityLogsUploader(Profile* profile) + : profile_(profile) {} +ModelQualityLogsUploader::~ModelQualityLogsUploader() = default; + +void ModelQualityLogsUploader::AddFinalModelStatusLog( + FinalModelStatus final_model_status, + std::unique_ptr< + optimization_guide::proto::PasswordChangeSubmissionLoggingData> + logging_data) { + optimization_guide::proto::LogAiDataRequest request; + request.mutable_password_change_submission()->MergeFrom(*logging_data); + // Set final model status + request.mutable_password_change_submission() + ->mutable_quality() + ->set_final_model_status(final_model_status); + // Store the new log request + log_entries_requests_.push_back(std::move(request)); +} + +void ModelQualityLogsUploader::UploadFinalLog() { + auto* logs_uploader = + OptimizationGuideKeyedServiceFactory::GetForProfile(profile_) + ->GetModelQualityLogsUploaderService(); + if (!logs_uploader) { + return; + } + auto new_log_entry = + std::make_unique<optimization_guide::ModelQualityLogEntry>( + logs_uploader->GetWeakPtr()); + for (const auto& entry : log_entries_requests_) { + new_log_entry->log_ai_data_request()->MergeFrom(entry); + } + optimization_guide::ModelQualityLogEntry::Upload(std::move(new_log_entry)); +} + +void ModelQualityLogsUploader::MergeData( + const optimization_guide::proto::PasswordChangeResponse& response, + std::unique_ptr< + optimization_guide::proto::PasswordChangeSubmissionLoggingData> + logging_data) { + // TODO(407503334): Split this per step, now assuming it is just verify + // submission. + PasswordChangeOutcome outcome = response.outcome_data().submission_outcome(); + if (outcome != + PasswordChangeOutcome:: + PasswordChangeSubmissionData_PasswordChangeOutcome_SUCCESSFUL_OUTCOME && + outcome != + PasswordChangeOutcome:: + PasswordChangeSubmissionData_PasswordChangeOutcome_UNKNOWN_OUTCOME) { + AddFinalModelStatusLog(FinalModelStatus::FINAL_MODEL_STATUS_FAILURE, + std::move(logging_data)); + } else { + AddFinalModelStatusLog(FinalModelStatus::FINAL_MODEL_STATUS_SUCCESS, + std::move(logging_data)); + } +}
diff --git a/chrome/browser/password_manager/password_change/model_quality_logs_uploader.h b/chrome/browser/password_manager/password_change/model_quality_logs_uploader.h new file mode 100644 index 0000000..4f1f4a4e --- /dev/null +++ b/chrome/browser/password_manager/password_change/model_quality_logs_uploader.h
@@ -0,0 +1,56 @@ +// 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_PASSWORD_MANAGER_PASSWORD_CHANGE_MODEL_QUALITY_LOGS_UPLOADER_H_ +#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_CHANGE_MODEL_QUALITY_LOGS_UPLOADER_H_ + +#include "components/optimization_guide/core/model_quality/model_quality_log_entry.h" +#include "components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.h" + +class Profile; + +// Helper class which handles Model Logging Quality logic and uploads the +// logs to the Server. +class ModelQualityLogsUploader { + public: + explicit ModelQualityLogsUploader(Profile* profile); + ~ModelQualityLogsUploader(); + ModelQualityLogsUploader(const ModelQualityLogsUploader&) = delete; + ModelQualityLogsUploader& operator=(const ModelQualityLogsUploader&) = delete; + // As we only want to record one log per flow, this is to be called just + // once. It will merge all existing LogAiDataRequest and upload a single + // log entry to the model quality logging service. + void UploadFinalLog(); + // Merges the logging data with the response given by + // optimization service call. + void MergeData( + const optimization_guide::proto::PasswordChangeResponse& response, + std::unique_ptr< + optimization_guide::proto::PasswordChangeSubmissionLoggingData> + logging_data); +#if defined(UNIT_TEST) + // Used for testing only. + const std::vector<optimization_guide::proto::LogAiDataRequest>& + GetLogEntryRequestsForTesting() const { + return log_entries_requests_; + } +#endif + + private: + std::unique_ptr<optimization_guide::ModelQualityLogEntry> CreateNewLogEntry(); + void AddFinalModelStatusLog( + optimization_guide::proto::FinalModelStatus final_model_status, + std::unique_ptr< + optimization_guide::proto::PasswordChangeSubmissionLoggingData> + logging_data); + + // Holds all feature's logging data request to at the end of the + // flow merge them in a single log entry. + std::vector<optimization_guide::proto::LogAiDataRequest> + log_entries_requests_; + const raw_ptr<Profile> profile_; + base::WeakPtrFactory<ModelQualityLogsUploader> weak_ptr_factory_{this}; +}; + +#endif // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_CHANGE_MODEL_QUALITY_LOGS_UPLOADER_H_
diff --git a/chrome/browser/password_manager/password_change/model_quality_logs_uploader_unittest.cc b/chrome/browser/password_manager/password_change/model_quality_logs_uploader_unittest.cc new file mode 100644 index 0000000..1bbd3d3 --- /dev/null +++ b/chrome/browser/password_manager/password_change/model_quality_logs_uploader_unittest.cc
@@ -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. + +#include "chrome/browser/password_manager/password_change/model_quality_logs_uploader.h" + +#include <memory> +#include <vector> + +#include "base/test/test_future.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/base/testing_profile.h" +#include "components/optimization_guide/core/model_quality/model_quality_log_entry.h" +#include "components/prefs/testing_pref_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +using FinalModelStatus = optimization_guide::proto::FinalModelStatus; +using PasswordChangeSubmissionLoggingData = + optimization_guide::proto::PasswordChangeSubmissionLoggingData; +using PasswordChangeOutcome = ::optimization_guide::proto:: + PasswordChangeSubmissionData_PasswordChangeOutcome; + +class ModelQualityLogsUploaderTest : public ChromeRenderViewHostTestHarness { + public: + ModelQualityLogsUploaderTest() = default; + ~ModelQualityLogsUploaderTest() override = default; +}; + +TEST_F(ModelQualityLogsUploaderTest, AddFinalModelStatusLog) { + ModelQualityLogsUploader logs_uploader(profile()); + auto logging_data = std::make_unique<PasswordChangeSubmissionLoggingData>(); + optimization_guide::proto::PasswordChangeResponse response; + response.mutable_outcome_data()->set_submission_outcome( + PasswordChangeOutcome:: + PasswordChangeSubmissionData_PasswordChangeOutcome_SUCCESSFUL_OUTCOME); + logs_uploader.MergeData(response, std::move(logging_data)); + auto logs = logs_uploader.GetLogEntryRequestsForTesting(); + ASSERT_EQ(logs.size(), 1u); + ASSERT_EQ(logs[0] + .mutable_password_change_submission() + ->mutable_quality() + ->final_model_status(), + FinalModelStatus::FINAL_MODEL_STATUS_SUCCESS); +}
diff --git a/chrome/browser/password_manager/password_change_delegate_impl.cc b/chrome/browser/password_manager/password_change_delegate_impl.cc index 161fb39..30ff47a 100644 --- a/chrome/browser/password_manager/password_change_delegate_impl.cc +++ b/chrome/browser/password_manager/password_change_delegate_impl.cc
@@ -12,6 +12,8 @@ #include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/password_manager/password_change/change_form_submission_verifier.h" #include "chrome/browser/password_manager/password_change/change_password_form_finder.h" +#include "chrome/browser/password_manager/password_change/change_password_form_waiter.h" +#include "chrome/browser/password_manager/password_change/model_quality_logs_uploader.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h" #include "components/autofill/core/browser/logging/log_manager.h" @@ -154,7 +156,9 @@ : change_password_url_(std::move(change_password_url)), username_(std::move(username)), original_password_(std::move(password)), - originator_(originator->GetWeakPtr()) { + originator_(originator->GetWeakPtr()), + logs_uploader_(std::make_unique<ModelQualityLogsUploader>( + Profile::FromBrowserContext(originator->GetBrowserContext()))) { if (auto logger = GetLoggerIfAvailable(originator_)) { logger->LogMessage( BrowserSavePasswordProgressLogger::STRING_PASSWORD_CHANGE_STARTED); @@ -227,7 +231,8 @@ executor_.get(), base::BindOnce( &PasswordChangeDelegateImpl::OnChangeFormSubmissionVerified, - weak_ptr_factory_.GetWeakPtr())); + weak_ptr_factory_.GetWeakPtr()), + logs_uploader_.get()); submission_verifier_->FillChangePasswordForm(form_manager, original_password_, generated_password_); UpdateState(PasswordChangeDelegate::State::kChangingPassword); @@ -393,7 +398,7 @@ submission_verifier_->SavePassword(username_); UpdateState(State::kPasswordSuccessfullyChanged); } - + logs_uploader_->UploadFinalLog(); submission_verifier_.reset(); } bool PasswordChangeDelegateImpl::IsPrivacyNoticeAcknowledged() const {
diff --git a/chrome/browser/password_manager/password_change_delegate_impl.h b/chrome/browser/password_manager/password_change_delegate_impl.h index 87c22ea..6a8f195 100644 --- a/chrome/browser/password_manager/password_change_delegate_impl.h +++ b/chrome/browser/password_manager/password_change_delegate_impl.h
@@ -28,6 +28,8 @@ class ChangeFormSubmissionVerifier; class ChangePasswordFormFinder; +class ChangePasswordFormWaiter; +class ModelQualityLogsUploader; // This class controls password change process including acceptance of privacy // notice, opening of a new tab, navigation to the change password url, password @@ -115,6 +117,11 @@ // Helper class which looks for a change password form. std::unique_ptr<ChangePasswordFormFinder> form_finder_; + // Helper class which uploads model quality logs. + std::unique_ptr<ModelQualityLogsUploader> logs_uploader_; + + // Class which awaits for change password form to appear. + std::unique_ptr<ChangePasswordFormWaiter> form_waiter_; // Helper class which submits a form and verifies submission. std::unique_ptr<ChangeFormSubmissionVerifier> submission_verifier_;
diff --git a/chrome/browser/pdf/pdf_extension_js_test.cc b/chrome/browser/pdf/pdf_extension_js_test.cc index b17e27cc..1c168c0 100644 --- a/chrome/browser/pdf/pdf_extension_js_test.cc +++ b/chrome/browser/pdf/pdf_extension_js_test.cc
@@ -624,7 +624,14 @@ RunTestsInJsModule("ink2_size_selector_test.js", "test.pdf"); } -IN_PROC_BROWSER_TEST_P(PDFExtensionJSInk2Test, Ink2ViewerToolbar) { +// TODO(crbug.com/416359681): Ink2ViewerToolbar is flaky on Mac12 and Mac13 +// tests. +#if !BUILDFLAG(IS_MAC) +#define MAYBE_Ink2ViewerToolbar Ink2ViewerToolbar +#else +#define MAYBE_Ink2ViewerToolbar DISABLED_Ink2ViewerToolbar +#endif +IN_PROC_BROWSER_TEST_P(PDFExtensionJSInk2Test, MAYBE_Ink2ViewerToolbar) { RunTestsInJsModule("ink2_viewer_toolbar_test.js", "test.pdf"); }
diff --git a/chrome/browser/performance_manager/policies/background_tab_loading_policy.cc b/chrome/browser/performance_manager/policies/background_tab_loading_policy.cc index 8780830..4a93348 100644 --- a/chrome/browser/performance_manager/policies/background_tab_loading_policy.cc +++ b/chrome/browser/performance_manager/policies/background_tab_loading_policy.cc
@@ -387,8 +387,10 @@ return false; // Enforce a max time since last use. - if (page_node_data.page_node->GetTimeSinceLastVisibilityChange() > - kMaxTimeSinceLastUseToLoad) { + const base::TimeDelta time_since_last_visibility_change = + base::TimeTicks::Now() - + page_node_data.page_node->GetLastVisibilityChangeTime(); + if (time_since_last_visibility_change > kMaxTimeSinceLastUseToLoad) { return false; } @@ -492,9 +494,10 @@ // Refine the score using the age of the tab. More recently used tabs have // higher scores. - score += CalculateAgeScore( - page_node_to_load_data->page_node->GetTimeSinceLastVisibilityChange() - .InSecondsF()); + const base::TimeDelta time_since_last_visibility_change = + base::TimeTicks::Now() - + page_node_to_load_data->page_node->GetLastVisibilityChangeTime(); + score += CalculateAgeScore(time_since_last_visibility_change.InSecondsF()); ++tabs_scored_; page_node_to_load_data->score = score;
diff --git a/chrome/browser/performance_manager/policies/discard_eligibility_policy.cc b/chrome/browser/performance_manager/policies/discard_eligibility_policy.cc index dc0490b..8ddcc06 100644 --- a/chrome/browser/performance_manager/policies/discard_eligibility_policy.cc +++ b/chrome/browser/performance_manager/policies/discard_eligibility_policy.cc
@@ -36,16 +36,17 @@ } // namespace -PageNodeSortProxy::PageNodeSortProxy(base::WeakPtr<const PageNode> page_node, - CanDiscardResult can_discard_result, - bool is_visible, - bool is_focused, - base::TimeDelta last_visible) +PageNodeSortProxy::PageNodeSortProxy( + base::WeakPtr<const PageNode> page_node, + CanDiscardResult can_discard_result, + bool is_visible, + bool is_focused, + base::TimeTicks last_visibility_change_time) : page_node_(std::move(page_node)), can_discard_result_(can_discard_result), is_visible_(is_visible), is_focused_(is_focused), - last_visible_(last_visible) {} + last_visibility_change_time_(last_visibility_change_time) {} PageNodeSortProxy::PageNodeSortProxy(PageNodeSortProxy&&) = default; PageNodeSortProxy& PageNodeSortProxy::operator=(PageNodeSortProxy&&) = default; @@ -179,7 +180,8 @@ if (page_node->IsVisible()) { add_reason_and_update_result(CannotDiscardReason::kVisible, CanDiscardResult::kProtected); - } else if (page_node->GetTimeSinceLastVisibilityChange() < + } else if ((base::TimeTicks::Now() - + page_node->GetLastVisibilityChangeTime()) < minimum_time_in_background) { add_reason_and_update_result(CannotDiscardReason::kRecentlyVisible, CanDiscardResult::kProtected);
diff --git a/chrome/browser/performance_manager/policies/discard_eligibility_policy.h b/chrome/browser/performance_manager/policies/discard_eligibility_policy.h index 6488603..dbdcf4b 100644 --- a/chrome/browser/performance_manager/policies/discard_eligibility_policy.h +++ b/chrome/browser/performance_manager/policies/discard_eligibility_policy.h
@@ -58,7 +58,7 @@ CanDiscardResult can_discard_result, bool is_visible, bool is_focused, - base::TimeDelta last_visible); + base::TimeTicks last_visibility_change_time); PageNodeSortProxy(PageNodeSortProxy&&); PageNodeSortProxy& operator=(PageNodeSortProxy&&); ~PageNodeSortProxy(); @@ -72,7 +72,9 @@ } bool is_visible() const { return is_visible_; } bool is_focused() const { return is_focused_; } - base::TimeDelta last_visible() const { return last_visible_; } + base::TimeTicks last_visibility_change_time() const { + return last_visibility_change_time_; + } // Returns true if the rhs is more important. bool operator<(const PageNodeSortProxy& rhs) const { @@ -88,7 +90,7 @@ if (is_protected() != rhs.is_protected()) { return rhs.is_protected(); } - return last_visible_ > rhs.last_visible_; + return last_visibility_change_time_ < rhs.last_visibility_change_time_; } private: @@ -96,8 +98,7 @@ CanDiscardResult can_discard_result_; bool is_visible_; bool is_focused_; - // Delta between current time and last visibility change time. - base::TimeDelta last_visible_; + base::TimeTicks last_visibility_change_time_; }; // DiscardEligibilityPolicy decides which PageNode is eligigle for tab
diff --git a/chrome/browser/performance_manager/policies/discard_eligibility_policy_unittest.cc b/chrome/browser/performance_manager/policies/discard_eligibility_policy_unittest.cc index 2f84370..cd13c64d 100644 --- a/chrome/browser/performance_manager/policies/discard_eligibility_policy_unittest.cc +++ b/chrome/browser/performance_manager/policies/discard_eligibility_policy_unittest.cc
@@ -30,41 +30,45 @@ using ::testing::Return; TEST(PageNodeSortProxyTest, Order) { + auto absolute_time = [](int seconds) { + return base::TimeTicks() + base::Seconds(seconds); + }; + // Disabled tab is never discarded over focused tabs. EXPECT_TRUE( - PageNodeSortProxy(nullptr, kProtected, true, true, base::Seconds(1)) < - PageNodeSortProxy(nullptr, kDisallowed, false, false, base::Seconds(10))); + PageNodeSortProxy(nullptr, kProtected, true, true, absolute_time(10)) < + PageNodeSortProxy(nullptr, kDisallowed, false, false, absolute_time(1))); // Focused tab is more important than visible & non-focused tab. EXPECT_TRUE( - PageNodeSortProxy(nullptr, kProtected, true, false, base::Seconds(1)) < - PageNodeSortProxy(nullptr, kProtected, true, true, base::Seconds(10))); + PageNodeSortProxy(nullptr, kProtected, true, false, absolute_time(10)) < + PageNodeSortProxy(nullptr, kProtected, true, true, absolute_time(1))); // Visible tab is more important than protected & non-visible tab. EXPECT_TRUE( - PageNodeSortProxy(nullptr, kProtected, false, false, base::Seconds(1)) < - PageNodeSortProxy(nullptr, kProtected, true, false, base::Seconds(10))); + PageNodeSortProxy(nullptr, kProtected, false, false, absolute_time(10)) < + PageNodeSortProxy(nullptr, kProtected, true, false, absolute_time(1))); // Protected tab is more important than non-protected tab. EXPECT_TRUE( - PageNodeSortProxy(nullptr, kEligible, false, false, base::Seconds(1)) < - PageNodeSortProxy(nullptr, kProtected, false, false, base::Seconds(10))); + PageNodeSortProxy(nullptr, kEligible, false, false, absolute_time(10)) < + PageNodeSortProxy(nullptr, kProtected, false, false, absolute_time(1))); // Compare disabled tabs. EXPECT_TRUE( - PageNodeSortProxy(nullptr, kDisallowed, false, false, base::Seconds(10)) < - PageNodeSortProxy(nullptr, kDisallowed, false, false, base::Seconds(1))); - // Sort visible tabs based on last_visible_. + PageNodeSortProxy(nullptr, kDisallowed, false, false, absolute_time(1)) < + PageNodeSortProxy(nullptr, kDisallowed, false, false, absolute_time(10))); + // Sort visible tabs based on `last_visibility_change_time_`. // TODO(crbug.com/391243672): use focus status change instead of // last_visible_. EXPECT_TRUE( - PageNodeSortProxy(nullptr, kProtected, true, false, base::Seconds(10)) < - PageNodeSortProxy(nullptr, kProtected, true, false, base::Seconds(1))); - // Sort protected tabs based on last_visible_. + PageNodeSortProxy(nullptr, kProtected, true, false, absolute_time(1)) < + PageNodeSortProxy(nullptr, kProtected, true, false, absolute_time(10))); + // Sort protected tabs based on `last_visibility_change_time_`. EXPECT_TRUE( - PageNodeSortProxy(nullptr, kProtected, false, false, base::Seconds(10)) < - PageNodeSortProxy(nullptr, kProtected, false, false, base::Seconds(1))); - // Sort non-protected tabs based on last_visible_. + PageNodeSortProxy(nullptr, kProtected, false, false, absolute_time(1)) < + PageNodeSortProxy(nullptr, kProtected, false, false, absolute_time(10))); + // Sort non-protected tabs based on `last_visibility_change_time_`. EXPECT_TRUE( - PageNodeSortProxy(nullptr, kEligible, false, false, base::Seconds(10)) < - PageNodeSortProxy(nullptr, kEligible, false, false, base::Seconds(1))); + PageNodeSortProxy(nullptr, kEligible, false, false, absolute_time(1)) < + PageNodeSortProxy(nullptr, kEligible, false, false, absolute_time(10))); } class DiscardEligibilityPolicyTest
diff --git a/chrome/browser/performance_manager/policies/oom_score_policy_chromeos.cc b/chrome/browser/performance_manager/policies/oom_score_policy_chromeos.cc index e40fd03..a502f89 100644 --- a/chrome/browser/performance_manager/policies/oom_score_policy_chromeos.cc +++ b/chrome/browser/performance_manager/policies/oom_score_policy_chromeos.cc
@@ -83,7 +83,7 @@ bool is_focused = page_node->IsFocused(); candidates.emplace_back(page_node->GetWeakPtr(), can_discard_result, is_visible, is_focused, - page_node->GetTimeSinceLastVisibilityChange()); + page_node->GetLastVisibilityChangeTime()); } // Sorts with descending importance.
diff --git a/chrome/browser/performance_manager/policies/page_discarding_helper.cc b/chrome/browser/performance_manager/policies/page_discarding_helper.cc index b5912c9..dafe483 100644 --- a/chrome/browser/performance_manager/policies/page_discarding_helper.cc +++ b/chrome/browser/performance_manager/policies/page_discarding_helper.cc
@@ -155,7 +155,7 @@ } candidates.emplace_back(page_node->GetWeakPtr(), can_discard_result, page_node->IsVisible(), page_node->IsFocused(), - page_node->GetTimeSinceLastVisibilityChange()); + page_node->GetLastVisibilityChangeTime()); } // Sorts with descending importance.
diff --git a/chrome/browser/performance_manager/policies/page_discarding_helper_unittest.cc b/chrome/browser/performance_manager/policies/page_discarding_helper_unittest.cc index a988a7b..7bd87807 100644 --- a/chrome/browser/performance_manager/policies/page_discarding_helper_unittest.cc +++ b/chrome/browser/performance_manager/policies/page_discarding_helper_unittest.cc
@@ -313,8 +313,8 @@ page_node2->SetIsVisible(false); AdvanceClock(base::Minutes(30)); EXPECT_EQ(kEligible, CanDiscard(page_node2.get(), DiscardReason::URGENT)); - EXPECT_GT(page_node()->GetTimeSinceLastVisibilityChange(), - page_node2->GetTimeSinceLastVisibilityChange()); + EXPECT_LT(page_node()->GetLastVisibilityChangeTime(), + page_node2->GetLastVisibilityChangeTime()); process_node()->set_resident_set_kb(1024); process_node2->set_resident_set_kb(2048); @@ -394,8 +394,8 @@ page_node()->SetIsVisible(false); AdvanceClock(base::Minutes(30)); EXPECT_EQ(kEligible, CanDiscard(page_node(), DiscardReason::URGENT)); - EXPECT_GT(page_node2->GetTimeSinceLastVisibilityChange(), - page_node()->GetTimeSinceLastVisibilityChange()); + EXPECT_LT(page_node2->GetLastVisibilityChangeTime(), + page_node()->GetLastVisibilityChangeTime()); // |page_node2| should be discarded as there's no RSS data for any of the // pages and it's the least recently visible page. @@ -423,8 +423,8 @@ page_node()->SetIsVisible(false); AdvanceClock(base::Minutes(30)); EXPECT_EQ(kEligible, CanDiscard(page_node(), DiscardReason::URGENT)); - EXPECT_GT(page_node2->GetTimeSinceLastVisibilityChange(), - page_node()->GetTimeSinceLastVisibilityChange()); + EXPECT_LT(page_node2->GetLastVisibilityChangeTime(), + page_node()->GetLastVisibilityChangeTime()); // |page_node2| should be discarded as there's no RSS data for any of the // pages and it's the least recently visible page.
diff --git a/chrome/browser/performance_manager/policies/policy_features.cc b/chrome/browser/performance_manager/policies/policy_features.cc index 7b3478b..b3b7339 100644 --- a/chrome/browser/performance_manager/policies/policy_features.cc +++ b/chrome/browser/performance_manager/policies/policy_features.cc
@@ -98,7 +98,7 @@ // // * To mitigate load pressure on system because the system is busy just after // resuming for a while. -// * GetTimeSinceLastVisibilityChange() of each node become meaningless because +// * GetLastVisibilityChangeTime() of each node become meaningless because // the monotonic clock keeps proceeding during dark resume. Waiting for // kNodeInvisibleTimeSec after resuming ensures that enough time has elapsed // so that inappropriately added time from dark resume can no longer affect
diff --git a/chrome/browser/performance_manager/policies/report_page_processes_policy.cc b/chrome/browser/performance_manager/policies/report_page_processes_policy.cc index d0c49b6..3b87519 100644 --- a/chrome/browser/performance_manager/policies/report_page_processes_policy.cc +++ b/chrome/browser/performance_manager/policies/report_page_processes_policy.cc
@@ -143,7 +143,7 @@ bool is_focused = page_node->IsFocused(); candidates.emplace_back(page_node->GetWeakPtr(), can_discard_result, is_visible, is_focused, - page_node->GetTimeSinceLastVisibilityChange()); + page_node->GetLastVisibilityChangeTime()); } // Sorts with descending importance. @@ -159,8 +159,6 @@ const std::vector<PageNodeSortProxy>& candidates) { base::flat_map<base::ProcessId, PageState> current_pages; - base::TimeTicks report_time = base::TimeTicks::Now(); - for (auto& candidate : candidates) { // Only list candidates that could be discarded. if (candidate.is_disallowed()) { @@ -182,7 +180,7 @@ std::piecewise_construct, std::forward_as_tuple(pid), std::forward_as_tuple(candidate.is_protected(), candidate.is_visible(), candidate.is_focused(), - report_time - candidate.last_visible())); + candidate.last_visibility_change_time())); } }
diff --git a/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos.cc b/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos.cc index a5eb2b2..27f4a89 100644 --- a/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos.cc +++ b/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos.cc
@@ -190,7 +190,7 @@ if (process_node && process_node->GetProcess().IsValid()) { bool is_visible = page_node->IsVisible(); auto last_visibility_change = - page_node->GetTimeSinceLastVisibilityChange(); + now_ticks - page_node->GetLastVisibilityChangeTime(); auto url = main_frame_node->GetURL(); uint64_t memory_reclaimed = GetProcessNodeReclaimedBytes(process_node); @@ -254,9 +254,9 @@ return page_node->IsVisible(); } -base::TimeDelta UserspaceSwapPolicy::GetTimeSinceLastVisibilityChange( +base::TimeTicks UserspaceSwapPolicy::GetLastVisibilityChangeTime( const PageNode* page_node) { - return page_node->GetTimeSinceLastVisibilityChange(); + return page_node->GetLastVisibilityChangeTime(); } bool UserspaceSwapPolicy::IsEligibleToSwap(const ProcessNode* process_node, @@ -296,7 +296,7 @@ // Next the page node must have been invisible for longer than the // configured time. - if (GetTimeSinceLastVisibilityChange(page_node) < + if ((now_ticks - GetLastVisibilityChangeTime(page_node)) < config_->invisible_time_before_swap) { return false; }
diff --git a/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos.h b/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos.h index cbb02a6b..0f00794 100644 --- a/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos.h +++ b/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos.h
@@ -73,7 +73,7 @@ virtual bool IsPageNodeVisible(const PageNode* page_node); virtual bool IsPageNodeAudible(const PageNode* page_node); virtual bool IsPageNodeLoadingOrBusy(const PageNode* page_node); - virtual base::TimeDelta GetTimeSinceLastVisibilityChange( + virtual base::TimeTicks GetLastVisibilityChangeTime( const PageNode* page_node); // IsEligibleToSwap will return true if the |page_node| belonging to the
diff --git a/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos_unittest.cc b/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos_unittest.cc index b28d7ede..db695d56 100644 --- a/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos_unittest.cc +++ b/chrome/browser/performance_manager/policies/userspace_swap_policy_chromeos_unittest.cc
@@ -8,6 +8,7 @@ #include "base/compiler_specific.h" #include "base/memory/raw_ptr.h" #include "base/system/sys_info.h" +#include "base/time/time.h" #include "chrome/browser/performance_manager/policies/policy_features.h" #include "chromeos/ash/components/memory/userspace_swap/userspace_swap.h" #include "components/performance_manager/graph/graph_impl.h" @@ -53,8 +54,7 @@ MOCK_METHOD1(IsPageNodeAudible, bool(const PageNode*)); MOCK_METHOD1(IsPageNodeVisible, bool(const PageNode*)); MOCK_METHOD1(IsPageNodeLoading, bool(const PageNode*)); - MOCK_METHOD1(GetTimeSinceLastVisibilityChange, - base::TimeDelta(const PageNode*)); + MOCK_METHOD1(GetLastVisibilityChangeTime, base::TimeTicks(const PageNode*)); // Allow our mock to dispatch to default implementations. bool DefaultIsEligibleToSwap(const ProcessNode* process_node, @@ -378,8 +378,8 @@ .WillRepeatedly(Return(false)); EXPECT_CALL(*policy(), IsPageNodeVisible(page_node().get())) .WillRepeatedly(Return(false)); - EXPECT_CALL(*policy(), GetTimeSinceLastVisibilityChange(page_node().get())) - .WillRepeatedly(Return(base::TimeDelta::Max())); + EXPECT_CALL(*policy(), GetLastVisibilityChangeTime(page_node().get())) + .WillRepeatedly(Return(base::TimeTicks::Max())); EXPECT_CALL(*policy(), SwapNodesOnGraph()) .WillRepeatedly(
diff --git a/chrome/browser/performance_manager/policies/working_set_trimmer_policy_chromeos.cc b/chrome/browser/performance_manager/policies/working_set_trimmer_policy_chromeos.cc index 1f26047..6ed5029 100644 --- a/chrome/browser/performance_manager/policies/working_set_trimmer_policy_chromeos.cc +++ b/chrome/browser/performance_manager/policies/working_set_trimmer_policy_chromeos.cc
@@ -164,7 +164,7 @@ const base::TimeTicks now_ticks = base::TimeTicks::Now(); for (const PageNode* page_node : GetOwningGraph()->GetAllPageNodes()) { if (!page_node->IsVisible() && - page_node->GetTimeSinceLastVisibilityChange() > + (now_ticks - page_node->GetLastVisibilityChangeTime()) > params_.node_invisible_time) { // Get the process node and if it has not been // trimmed within the backoff period, we will do that
diff --git a/chrome/browser/persisted_state_db/session_proto_db_factory.h b/chrome/browser/persisted_state_db/session_proto_db_factory.h index e97bc3a..138e163 100644 --- a/chrome/browser/persisted_state_db/session_proto_db_factory.h +++ b/chrome/browser/persisted_state_db/session_proto_db_factory.h
@@ -25,13 +25,14 @@ #endif namespace { -const char kPersistedStateDBFolder[] = "persisted_state_db"; -const char kChromeCartDBFolder[] = "chrome_cart_db"; -const char kMerchantTrustSignalDBFolder[] = "merchant_signal_db"; -const char kCommerceSubscriptionDBFolder[] = "commerce_subscription_db"; -const char kCouponDBFolder[] = "coupon_db"; -const char kDiscountsDBFolder[] = "discounts_db"; -const char kParcelTrackingDBFolder[] = "parcel_tracking_db"; +inline constexpr char kPersistedStateDBFolder[] = "persisted_state_db"; +inline constexpr char kChromeCartDBFolder[] = "chrome_cart_db"; +inline constexpr char kMerchantTrustSignalDBFolder[] = "merchant_signal_db"; +inline constexpr char kCommerceSubscriptionDBFolder[] = + "commerce_subscription_db"; +inline constexpr char kCouponDBFolder[] = "coupon_db"; +inline constexpr char kDiscountsDBFolder[] = "discounts_db"; +inline constexpr char kParcelTrackingDBFolder[] = "parcel_tracking_db"; } // namespace SessionProtoDBFactory<persisted_state_db::PersistedStateContentProto>*
diff --git a/chrome/browser/policy/messaging_layer/util/reporting_server_connector_test_util.h b/chrome/browser/policy/messaging_layer/util/reporting_server_connector_test_util.h index 14deda7..1b26eca 100644 --- a/chrome/browser/policy/messaging_layer/util/reporting_server_connector_test_util.h +++ b/chrome/browser/policy/messaging_layer/util/reporting_server_connector_test_util.h
@@ -27,7 +27,7 @@ namespace reporting { -constexpr char kFakeDmToken[] = "FAKE_DM_TOKEN"; +inline constexpr char kFakeDmToken[] = "FAKE_DM_TOKEN"; class EncryptedReportingClient;
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc index 1bd7e64..de3d81a 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc
@@ -780,6 +780,8 @@ } CHECK(!search_terms.empty()); + RecordPotentialDuplicateSearchTermsAheadOfNavigationalPrefetch(search_terms); + // Search history suggestions (those that are not also server suggestions) // don't have search term args. If search history suggestions are enabled, // generate search term args to get a prefetch URL. @@ -1292,3 +1294,19 @@ } search_terms_cache_.Put(search_terms, base::Time::Now()); } + +void SearchPrefetchService:: + RecordPotentialDuplicateSearchTermsAheadOfNavigationalPrefetch( + const std::u16string& search_terms) { + // Do not affect the order. + const auto& iter = search_terms_cache_.Peek(search_terms); + if (iter != search_terms_cache_.end()) { + // For now we just want to track the very recent duplicate terms which might + // be a bug. + base::UmaHistogramCustomTimes( + "Omnibox.SearchPrefetch." + "DuplicateSearchTermsAgeAheadOfNavigationalPrefetch", + base::Time::Now() - iter->second, base::Milliseconds(1), + base::Minutes(2), 50); + } +}
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h index 6f2ca1aa..9d4d7dd 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h
@@ -274,6 +274,8 @@ void RecordInterceptionMetrics(const std::u16string& search_terms, SearchPrefetchServingReason serving_status); + void RecordPotentialDuplicateSearchTermsAheadOfNavigationalPrefetch( + const std::u16string& search_terms); // Prefetches that are started are stored using search terms as a key. Only // one prefetch should be started for a given search term until the old
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc index 23cef01..ff58cd7 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
@@ -3477,6 +3477,54 @@ std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_; }; +// Tests DuplicateSearchTermsAgeAheadOfNavigationalPrefetch is recorded as +// expected. +IN_PROC_BROWSER_TEST_F( + SearchPrefetchServiceNavigationPrefetchBrowserTest, + RecordDuplicateSearchTermsAgeAheadOfNavigationalPrefetch) { + SetDSEWithURL( + GetSearchServerQueryURL( + "{searchTerms}&{google:assistedQueryStats}{google:prefetchSource}"), + true); + base::HistogramTester histogram_tester; + + auto* search_prefetch_service = + SearchPrefetchServiceFactory::GetForProfile(browser()->profile()); + std::string search_terms = "terms of service"; + std::string user_input = "terms"; + + auto [prefetch_url, search_url] = + GetSearchPrefetchAndNonPrefetch(search_terms); + ASSERT_TRUE(content::NavigateToURL(GetWebContents(), search_url)); + + AutocompleteMatch autocomplete_match = + CreateSearchSuggestionMatch(search_terms, search_terms, false); + SearchPrefetchServiceFactory::GetForProfile(browser()->profile()) + ->OnNavigationLikely(1, autocomplete_match, + NavigationPredictor::kMouseDown, GetWebContents()); + + WaitUntilStatusChangesTo( + GetCanonicalSearchURL(autocomplete_match.destination_url), + SearchPrefetchStatus::kComplete); + auto prefetch_status = + search_prefetch_service->GetSearchPrefetchStatusForTesting( + GetCanonicalSearchURL(autocomplete_match.destination_url)); + ASSERT_TRUE(prefetch_status.has_value()); + EXPECT_EQ(SearchPrefetchStatus::kComplete, prefetch_status.value()); + + GURL canonical_search_url = GetCanonicalSearchURL(prefetch_url); + // Navigate. + ASSERT_TRUE(content::NavigateToURL(GetWebContents(), search_url)); + + auto inner_html = GetDocumentInnerHTML(); + EXPECT_FALSE(base::Contains(inner_html, "regular")); + EXPECT_TRUE(base::Contains(inner_html, "prefetch")); + histogram_tester.ExpectTotalCount( + "Omnibox.SearchPrefetch." + "DuplicateSearchTermsAgeAheadOfNavigationalPrefetch", + 1); +} + IN_PROC_BROWSER_TEST_F(SearchPrefetchServiceNavigationPrefetchBrowserTest, NavigationPrefetchIsServedMouseDown) { SetDSEWithURL(
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc b/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc index a582336f..79f7b74 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
@@ -18,6 +18,7 @@ #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" +#include "base/trace_event/named_trigger.h" #include "base/trace_event/trace_event.h" #include "chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.h" #include "chrome/browser/preloading/prerender/prerender_utils.h" @@ -351,6 +352,7 @@ scoped_refptr<StreamingSearchPrefetchURLLoader> loader) { DCHECK(!loader->streaming_prefetch_request_); DCHECK(!loader->forwarding_client_); + loader->should_be_serving_to_activation_navigation_ = true; loader->RecordInterceptionTime(); return base::BindOnce( &StreamingSearchPrefetchURLLoader::SetUpForwardingClient, @@ -371,6 +373,7 @@ mojo::PendingReceiver<network::mojom::URLLoader> receiver, mojo::PendingRemote<network::mojom::URLLoaderClient> forwarding_client) { CHECK(!streaming_prefetch_request_); + CHECK(should_be_serving_to_activation_navigation_); // Bind to the content/ navigation code. CHECK(!receiver_.is_bound()); @@ -837,6 +840,11 @@ : "Omnibox.SearchPreload.ForwardingResult.NotServedToPrerender", forwarding_result_); } + if (should_be_serving_to_activation_navigation_ && + forwarding_result_ == ForwardingResult::kNotServed) { + base::trace_event::EmitNamedTrigger( + "search-prefetch-destroyed-unexpectedly"); + } // To avoid UAF bugs, post a separate task to delete this object. base::SequencedTaskRunner::GetCurrentDefault()->ReleaseSoon(
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h b/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h index ee59e30..0e352c6 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h +++ b/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
@@ -437,7 +437,12 @@ // Whether this loader is created specifically for a navigation prefetch. bool navigation_prefetch_; - // Whether this url loader was activated via the navigation stack. + // Whether the SearchPrefetchService selected to use this loader to serve a + // real navigation. + bool should_be_serving_to_activation_navigation_ = false; + + // Whether this url loader was activated via the navigation stack. Set after + // the call to `SetUpForwardingClient`. bool is_activated_ = false; base::OnceClosure on_destruction_callback_for_testing_;
diff --git a/chrome/browser/printing/web_api/web_printing_browsertest.cc b/chrome/browser/printing/web_api/web_printing_browsertest.cc index 358e2d0..56df0a4 100644 --- a/chrome/browser/printing/web_api/web_printing_browsertest.cc +++ b/chrome/browser/printing/web_api/web_printing_browsertest.cc
@@ -140,6 +140,8 @@ Pointee(Eq("tray-1")))))), // printColorMode: Property(&PrintSettings::color, Eq(mojom::ColorModel::kColorModeColor)), + // printQuality: + Property(&PrintSettings::quality, Eq(mojom::Quality::kUnknownQuality)), Property(&PrintSettings::title, Eq(u"Title")), // multipleDocumentHandling: Property(&PrintSettings::collate, Eq(true)), @@ -335,6 +337,8 @@ }], "printColorModeDefault": "monochrome", "printColorModeSupported": [ "monochrome", "color" ], + "printQualityDefault": "normal", + "printQualitySupported": [ "draft", "normal", "high" ], "printerName": "name", "printerState": "idle", "printerStateMessage": "Ready to Print!",
diff --git a/chrome/browser/printing/web_api/web_printing_mojom_traits.cc b/chrome/browser/printing/web_api/web_printing_mojom_traits.cc index 9f9d4449..ae0f01c 100644 --- a/chrome/browser/printing/web_api/web_printing_mojom_traits.cc +++ b/chrome/browser/printing/web_api/web_printing_mojom_traits.cc
@@ -28,6 +28,10 @@ // orientation-requested: using OrientationRequested = blink::mojom::WebPrintingOrientationRequested; +// print-quality: +using WebPrintQuality = blink::mojom::WebPrintQuality; +using printing::mojom::Quality; + // print-color-mode: using PrintColorMode = blink::mojom::WebPrintColorMode; using printing::mojom::ColorModel; @@ -118,6 +122,39 @@ } // static +blink::mojom::WebPrintQuality EnumTraits<WebPrintQuality, Quality>::ToMojom( + Quality input) { + switch (input) { + case Quality::kDraft: + return WebPrintQuality::kDraft; + case Quality::kNormal: + return WebPrintQuality::kNormal; + case Quality::kHigh: + return WebPrintQuality::kHigh; + case Quality::kUnknownQuality: + return WebPrintQuality::kNormal; + } + NOTREACHED(); +} + +// static +bool EnumTraits<WebPrintQuality, Quality>::FromMojom(WebPrintQuality input, + Quality* output) { + switch (input) { + case WebPrintQuality::kDraft: + *output = Quality::kDraft; + return true; + case WebPrintQuality::kNormal: + *output = Quality::kNormal; + return true; + case WebPrintQuality::kHigh: + *output = Quality::kHigh; + return true; + } + NOTREACHED(); +} + +// static blink::mojom::WebPrinterState EnumTraits<blink::mojom::WebPrinterState, ipp_pstate_t>::ToMojom( ipp_pstate_t printer_state) { @@ -271,6 +308,15 @@ if (auto print_color_mode = data.print_color_mode()) { settings->set_color(PrintColorModeToColorModel(*print_color_mode)); } + { + std::optional<Quality> quality; + if (!data.ReadPrintQuality(&quality)) { + return false; + } + if (quality) { + settings->set_quality(*quality); + } + } *out = std::move(settings); return true;
diff --git a/chrome/browser/printing/web_api/web_printing_mojom_traits.h b/chrome/browser/printing/web_api/web_printing_mojom_traits.h index edac760f..a5affce6 100644 --- a/chrome/browser/printing/web_api/web_printing_mojom_traits.h +++ b/chrome/browser/printing/web_api/web_printing_mojom_traits.h
@@ -29,6 +29,13 @@ }; template <> +struct EnumTraits<blink::mojom::WebPrintQuality, printing::mojom::Quality> { + static blink::mojom::WebPrintQuality ToMojom(printing::mojom::Quality input); + static bool FromMojom(blink::mojom::WebPrintQuality input, + printing::mojom::Quality* output); +}; + +template <> struct EnumTraits<blink::mojom::WebPrinterState, ipp_pstate_t> { static blink::mojom::WebPrinterState ToMojom(ipp_pstate_t input); static bool FromMojom(blink::mojom::WebPrinterState input, @@ -93,6 +100,10 @@ const std::unique_ptr<printing::PrintSettings>& ptr) { NOTREACHED(); } + static const std::optional<blink::mojom::WebPrintQuality>& print_quality( + const std::unique_ptr<printing::PrintSettings>& ptr) { + NOTREACHED(); + } static const std::optional<blink::mojom::WebPrintingSides>& sides( const std::unique_ptr<printing::PrintSettings>& ptr) { NOTREACHED();
diff --git a/chrome/browser/printing/web_api/web_printing_type_converters.cc b/chrome/browser/printing/web_api/web_printing_type_converters.cc index 6842a74..20be313 100644 --- a/chrome/browser/printing/web_api/web_printing_type_converters.cc +++ b/chrome/browser/printing/web_api/web_printing_type_converters.cc
@@ -163,6 +163,14 @@ } } +void ProcessPrintQuality(const PrinterSemanticCapsAndDefaults& caps, + blink::mojom::WebPrinterAttributes* attributes) { + attributes->print_quality_default = blink::mojom::WebPrintQuality::kNormal; + attributes->print_quality_supported = {blink::mojom::WebPrintQuality::kDraft, + blink::mojom::WebPrintQuality::kNormal, + blink::mojom::WebPrintQuality::kHigh}; +} + void ProcessSides(const PrinterSemanticCapsAndDefaults& caps, blink::mojom::WebPrinterAttributes* attributes) { if (caps.duplex_default != mojom::DuplexMode::kUnknownDuplexMode) { @@ -201,6 +209,7 @@ printing::ProcessOrientationRequested(capabilities, attributes.get()); printing::ProcessPrinterResolution(capabilities, attributes.get()); printing::ProcessPrintColorMode(capabilities, attributes.get()); + printing::ProcessPrintQuality(capabilities, attributes.get()); printing::ProcessSides(capabilities, attributes.get()); return attributes;
diff --git a/chrome/browser/privacy_sandbox/BUILD.gn b/chrome/browser/privacy_sandbox/BUILD.gn index 21ddfda5f..fe578739 100644 --- a/chrome/browser/privacy_sandbox/BUILD.gn +++ b/chrome/browser/privacy_sandbox/BUILD.gn
@@ -153,6 +153,26 @@ "//net:test_support", ] } +} else { + source_set("attestations_component_installer_android_browsertest") { + testonly = true + defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + sources = [ "privacy_sandbox_attestations/privacy_sandbox_attestations_component_installer_android_browsertest.cc" ] + deps = [ + "//base/test:test_support", + "//chrome/browser:browser_process", + "//chrome/test:test_support", + "//chrome/test:test_support_ui_android", + "//components/component_updater:component_updater_paths", + "//components/privacy_sandbox:features", + "//components/privacy_sandbox:test_support", + "//components/privacy_sandbox/privacy_sandbox_attestations", + "//components/privacy_sandbox/privacy_sandbox_attestations:metrics", + "//components/privacy_sandbox/privacy_sandbox_attestations/preload", + "//components/privacy_sandbox/privacy_sandbox_attestations/proto", + "//content/test:test_support", + ] + } } group("browser_tests") { @@ -169,6 +189,8 @@ ":settings_browser_test", ":survey_desktop_controller_browser_test", ] + } else { + deps += [ ":attestations_component_installer_android_browsertest" ] } }
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl_unittest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl_unittest.cc index f2ee1381..8072afbe 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl_unittest.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl_unittest.cc
@@ -1791,11 +1791,9 @@ kRelatedWebsiteSetsVersion, { {primary_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary, - std::nullopt)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)}}, {associate1_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, - 0)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}}, }, {}); @@ -1831,11 +1829,9 @@ kRelatedWebsiteSetsVersion, { {primary_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary, - std::nullopt)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)}}, {associate1_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, - 0)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}}, }, {}); @@ -1872,11 +1868,9 @@ kRelatedWebsiteSetsVersion, { {primary_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary, - std::nullopt)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)}}, {associate1_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, - 0)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}}, }, {}); @@ -1955,14 +1949,11 @@ kRelatedWebsiteSetsVersion, { {primary_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary, - std::nullopt)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kPrimary)}}, {associate1_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, - 0)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}}, {associate2_site, - {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, - 1)}}, + {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated)}}, }, {})); @@ -2069,10 +2060,10 @@ { {youtube_primary_site, {net::FirstPartySetEntry(youtube_primary_site, - net::SiteType::kPrimary, std::nullopt)}}, + net::SiteType::kPrimary)}}, {youtube_site, {net::FirstPartySetEntry(youtube_primary_site, - net::SiteType::kAssociated, 0)}}, + net::SiteType::kAssociated)}}, }, {})); @@ -2082,7 +2073,7 @@ {{net::SchemefulSite(GURL("https://google.de")), net::FirstPartySetEntryOverride(net::FirstPartySetEntry( net::SchemefulSite(GURL("https://new-primary.test")), - net::SiteType::kAssociated, 0))}}) + net::SiteType::kAssociated))}}) .value()); first_party_sets_policy_service()->InitForTesting();
diff --git a/chrome/browser/private_network_access/private_network_device_permission_context.h b/chrome/browser/private_network_access/private_network_device_permission_context.h index f64dc8f..1dd88d879 100644 --- a/chrome/browser/private_network_access/private_network_device_permission_context.h +++ b/chrome/browser/private_network_access/private_network_device_permission_context.h
@@ -17,9 +17,9 @@ class Profile; -const char kPrivateNetworkDeviceValidityHistogramName[] = +inline constexpr char kPrivateNetworkDeviceValidityHistogramName[] = "Security.PrivateNetworkAccess.PermissionDeviceValidity"; -const char kUserAcceptedPrivateNetworkDeviceHistogramName[] = +inline constexpr char kUserAcceptedPrivateNetworkDeviceHistogramName[] = "Security.PrivateNetworkAccess.PermissionNewAcceptedDeviceType"; // These values are logged to UMA. Entries should not be renumbered and numeric
diff --git a/chrome/browser/resources/ash/settings/os_about_page/about_page_browser_proxy.ts b/chrome/browser/resources/ash/settings/os_about_page/about_page_browser_proxy.ts index dc5b6832..715c9f7 100644 --- a/chrome/browser/resources/ash/settings/os_about_page/about_page_browser_proxy.ts +++ b/chrome/browser/resources/ash/settings/os_about_page/about_page_browser_proxy.ts
@@ -200,6 +200,8 @@ */ getChannelInfo(): Promise<ChannelInfo>; + canChangeFirmware(): Promise<boolean>; + canChangeChannel(): Promise<boolean>; getVersionInfo(): Promise<VersionInfo>; @@ -324,6 +326,10 @@ return sendWithPromise('getChannelInfo'); } + canChangeFirmware(): Promise<boolean> { + return sendWithPromise('canChangeFirmware'); + } + canChangeChannel(): Promise<boolean> { return sendWithPromise('canChangeChannel'); }
diff --git a/chrome/browser/resources/ash/settings/os_about_page/os_about_page.html b/chrome/browser/resources/ash/settings/os_about_page/os_about_page.html index fae2123..165e992 100644 --- a/chrome/browser/resources/ash/settings/os_about_page/os_about_page.html +++ b/chrome/browser/resources/ash/settings/os_about_page/os_about_page.html
@@ -253,6 +253,7 @@ external deep-link-focus-id$="[[Setting.kDiagnostics]]"> </cr-link-row> + <template is="dom-if" if="[[canChangeFirmware_]]"> <cr-link-row class="hr" id="firmwareUpdates" start-icon="os-settings:about-firmware-updates" on-click="onFirmwareUpdatesClick_" @@ -272,6 +273,32 @@ firmwareUpdateCount_)]]"> </div> </cr-link-row> + </template> + <template is="dom-if" if="[[!canChangeFirmware_]]"> + <cr-link-row class="hr" id="firmwareUpdates" + start-icon="os-settings:about-firmware-updates" + label="$i18n{aboutFirmwareUpdates}" + sub-label="[[getFirmwareSublabel_(firmwareUpdateCount_)]]" + external + using-slotted-label + disabled=true + deep-link-focus-id$="[[Setting.kFirmwareUpdates]]"> + <iron-icon id="firmwareUpdateBadge" + icon$="[[getFirmwareUpdatesIcon_(firmwareUpdateCount_)]]" + hidden$="[[!shouldShowFirmwareUpdatesBadge_( + firmwareUpdateCount_)]]"> + </iron-icon> + <div id="firmwareUpdateBadgeSeparator" + class="separator separator-firmware-updates-badge" + hidden$="[[!shouldShowFirmwareUpdatesBadge_( + firmwareUpdateCount_)]]"> + </div> + <cr-policy-indicator + id="changeChannelPolicyIndicator" + indicator-type="[[getFirmwareDisabledIndicatorType_()]]"> + </cr-policy-indicator> + </cr-link-row> + </template> <cr-link-row class="hr" id="detailedBuildInfoTrigger" start-icon="os-settings:about-additional-details" on-click="onDetailedBuildInfoClick_"
diff --git a/chrome/browser/resources/ash/settings/os_about_page/os_about_page.ts b/chrome/browser/resources/ash/settings/os_about_page/os_about_page.ts index 9aefa3583..23dcea3 100644 --- a/chrome/browser/resources/ash/settings/os_about_page/os_about_page.ts +++ b/chrome/browser/resources/ash/settings/os_about_page/os_about_page.ts
@@ -23,10 +23,12 @@ import './eol_offer_section.js'; import './update_warning_dialog.js'; import '../crostini_page/crostini_settings_card.js'; +import 'chrome://resources/ash/common/cr_elements/policy/cr_policy_indicator.js'; import {LifetimeBrowserProxyImpl} from '/shared/settings/lifetime_browser_proxy.js'; import type {CrButtonElement} from 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js'; import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; +import {CrPolicyIndicatorType} from 'chrome://resources/ash/common/cr_elements/policy/cr_policy_indicator_mixin.js'; import {WebUiListenerMixin} from 'chrome://resources/ash/common/cr_elements/web_ui_listener_mixin.js'; import {assert} from 'chrome://resources/js/assert.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; @@ -92,6 +94,11 @@ value: false, }, + /** + * Whether users may initiate firmware updates + */ + canChangeFirmware_: Boolean, + currentUpdateStatusEvent_: { type: Object, value: { @@ -288,6 +295,7 @@ ]); private isDarkModeActive_: boolean; + private canChangeFirmware_: boolean; private currentUpdateStatusEvent_: UpdateStatusChangedEvent; private isManaged_: boolean; private deviceManager_: string; @@ -415,6 +423,12 @@ this.onExtendedUpdatesSettingChanged_.bind(this)); } + private updateFirmwareInfo_(): void { + this.aboutBrowserProxy_.canChangeFirmware().then(canChangeFirmware => { + this.canChangeFirmware_ = canChangeFirmware; + }); + } + private onUpdateStatusChanged_(event: UpdateStatusChangedEvent): void { if (event.status === UpdateStatus.CHECKING) { this.hasCheckedForUpdates_ = true; @@ -489,6 +503,10 @@ this.currentUpdateStatusEvent_.status !== UpdateStatus.DISABLED; } + private getFirmwareDisabledIndicatorType_(): string { + return CrPolicyIndicatorType.DEVICE_POLICY; + } + /** * Hide the button container if all buttons are hidden, otherwise the * container displays an unwanted border (see separator class). @@ -755,6 +773,7 @@ private onTpmFirmwareUpdateStatusChanged_( event: TpmFirmwareUpdateStatusChangedEvent): void { this.showTPMFirmwareUpdateLineItem_ = event.updateAvailable; + this.updateFirmwareInfo_(); } private onTpmFirmwareUpdateClick_(): void { @@ -787,9 +806,13 @@ // </if> private getFirmwareSublabel_(): string|null { - return this.firmwareUpdateCount_ > 0 ? - this.i18n('aboutFirmwareUpdateAvailableDescription') : - this.i18n('aboutFirmwareUpToDateDescription'); + if (!this.canChangeFirmware_) { + return this.i18n('aboutFirmwareUpdatesDisabledDescription'); + } + if (this.firmwareUpdateCount_ > 0) { + return this.i18n('aboutFirmwareUpdateAvailableDescription'); + } + return this.i18n('aboutFirmwareUpToDateDescription'); } private computeShowExtendedUpdatesOption_(): boolean {
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/os_japanese_clear_ime_data_dialog.html b/chrome/browser/resources/ash/settings/os_languages_page/os_japanese_clear_ime_data_dialog.html index ea267ae..cc18f46 100644 --- a/chrome/browser/resources/ash/settings/os_languages_page/os_japanese_clear_ime_data_dialog.html +++ b/chrome/browser/resources/ash/settings/os_languages_page/os_japanese_clear_ime_data_dialog.html
@@ -25,23 +25,23 @@ } </style> <cr-dialog id="dialog" close-text="$i18n{close}" show-on-attach> - <div slot="title">Clear personalization data</div> + <div slot="title">$i18n{japaneseClearPersonalizationData}</div> <div id="dialogBody" slot="body"> - <div class="subheading">Delete the following items:</div> + <div class="subheading">$i18n{japaneseDeleteItems}</div> <div> <cr-checkbox class="list-item no-outline is-width-of-dialog" checked="{{clearConversionHistory_}}"> - Conversion History + $i18n{japaneseConversationHistory} </cr-checkbox> <cr-checkbox class="list-item no-outline is-width-of-dialog" checked="{{clearSuggestionHistory_}}"> - Suggestion History + $i18n{japaneseSuggestionHistory} </cr-checkbox> </div> </div> <div slot="button-container"> <cr-button class="action-button" on-click="onClearButtonClick_"> - Clear Personalized data + $i18n{japaneseClearPersonalizationData} </cr-button> <cr-button class="cancel-button" on-click="onCancelButtonClick_"> $i18n{cancel}
diff --git a/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts b/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts index 9ed38991..8b61f59 100644 --- a/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts +++ b/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts
@@ -3,11 +3,6 @@ // found in the LICENSE file. import type {ChromeEvent} from '/tools/typescript/definitions/chrome_event.js'; -export interface OpenInNewTabParams { - active?: boolean; - split?: boolean; -} - export interface BookmarkManagerApiProxy { onDragEnter: ChromeEvent<(p1: chrome.bookmarkManagerPrivate.DragData) => void>; @@ -19,7 +14,7 @@ removeTrees(idList: string[]): Promise<void>; canPaste(parentId: string): Promise<boolean>; openInNewWindow(idList: string[], incognito: boolean): void; - openInNewTab(id: string, params?: OpenInNewTabParams): void; + openInNewTab(id: string, active: boolean): void; openInNewTabGroup(idList: string[]): void; cut(idList: string[]): Promise<void>; paste(parentId: string, selectedIdList?: string[]): Promise<void>; @@ -49,12 +44,11 @@ } openInNewWindow(idList: string[], incognito: boolean) { - chrome.bookmarkManagerPrivate.openInNewWindow(idList, incognito); + return chrome.bookmarkManagerPrivate.openInNewWindow(idList, incognito); } - openInNewTab(id: string, params: OpenInNewTabParams) { - chrome.bookmarkManagerPrivate.openInNewTab( - id, {active: params.active, split: params.split}); + openInNewTab(id: string, active: boolean) { + return chrome.bookmarkManagerPrivate.openInNewTab(id, active); } openInNewTabGroup(idList: string[]) {
diff --git a/chrome/browser/resources/bookmarks/bookmarks.ts b/chrome/browser/resources/bookmarks/bookmarks.ts index 0f98b33..87e30696 100644 --- a/chrome/browser/resources/bookmarks/bookmarks.ts +++ b/chrome/browser/resources/bookmarks/bookmarks.ts
@@ -8,7 +8,7 @@ export {changeFolderOpen, clearSearch, createBookmark, deselectItems, editBookmark, moveBookmark, removeBookmark, reorderChildren, selectFolder, SelectFolderAction, selectItem, SelectItemsAction, setSearchResults, setSearchTerm, StartSearchAction, updateAnchor} from './actions.js'; export {setDebouncerForTesting} from './api_listener.js'; export {BookmarksAppElement, HIDE_FOCUS_RING_ATTRIBUTE} from './app.js'; -export {BookmarkManagerApiProxy, BookmarkManagerApiProxyImpl, OpenInNewTabParams} from './bookmark_manager_api_proxy.js'; +export {BookmarkManagerApiProxy, BookmarkManagerApiProxyImpl} from './bookmark_manager_api_proxy.js'; export {BookmarksApiProxy, BookmarksApiProxyImpl, Query} from './bookmarks_api_proxy.js'; export {BrowserProxy, BrowserProxyImpl} from './browser_proxy.js'; export {BookmarksCommandManagerElement} from './command_manager.js';
diff --git a/chrome/browser/resources/bookmarks/command_manager.ts b/chrome/browser/resources/bookmarks/command_manager.ts index 70bf956..7f5e9b3 100644 --- a/chrome/browser/resources/bookmarks/command_manager.ts +++ b/chrome/browser/resources/bookmarks/command_manager.ts
@@ -257,7 +257,6 @@ case Command.OPEN_NEW_GROUP: case Command.OPEN_NEW_TAB: case Command.OPEN_NEW_WINDOW: - case Command.OPEN_SPLIT_VIEW: return itemIds.size > 0; case Command.ADD_BOOKMARK: case Command.ADD_FOLDER: @@ -287,8 +286,6 @@ return this.expandIds_(itemIds).length > 0 && state.prefs.incognitoAvailability !== IncognitoAvailability.DISABLED; - case Command.OPEN_SPLIT_VIEW: - return this.expandIds_(itemIds).length === 1; case Command.SORT: return this.canChangeList_() && state.nodes[state.selectedFolder]!.children!.length > 1; @@ -403,7 +400,6 @@ case Command.OPEN_NEW_GROUP: case Command.OPEN_NEW_TAB: case Command.OPEN_NEW_WINDOW: - case Command.OPEN_SPLIT_VIEW: this.openBookmarkIds_(this.expandIds_(itemIds), command); break; case Command.OPEN: @@ -524,34 +520,27 @@ command === Command.OPEN || command === Command.OPEN_NEW_TAB || command === Command.OPEN_NEW_WINDOW || command === Command.OPEN_INCOGNITO || - command === Command.OPEN_SPLIT_VIEW || command === Command.OPEN_NEW_GROUP); if (ids.length === 0) { return; } - if (command === Command.OPEN_SPLIT_VIEW) { - assert(ids.length === 1); - } - const openBookmarkIdsCallback = function() { const incognito = command === Command.OPEN_INCOGNITO; if (command === Command.OPEN_NEW_WINDOW || incognito) { BookmarkManagerApiProxyImpl.getInstance().openInNewWindow( ids, incognito); - } else if (command === Command.OPEN_SPLIT_VIEW) { - BookmarkManagerApiProxyImpl.getInstance().openInNewTab( - ids.shift()!, {active: false, split: true}); } else if (command === Command.OPEN_NEW_GROUP) { BookmarkManagerApiProxyImpl.getInstance().openInNewTabGroup(ids); } else { if (command === Command.OPEN) { - BookmarkManagerApiProxyImpl.getInstance().openInNewTab(ids.shift()!); + BookmarkManagerApiProxyImpl.getInstance().openInNewTab( + ids.shift()!, /*active=*/ true); } ids.forEach(function(id) { BookmarkManagerApiProxyImpl.getInstance().openInNewTab( - id, {active: false}); + id, /*active=*/ false); }); } }; @@ -663,9 +652,6 @@ case Command.HELP_CENTER: label = 'menuHelpCenter'; break; - case Command.OPEN_SPLIT_VIEW: - label = 'menuOpenSplitView'; - break; } if (label !== null) { return loadTimeData.getString(label); @@ -715,7 +701,7 @@ switch (this.menuSource_) { case MenuSource.ITEM: case MenuSource.TREE: - const commands = [ + return [ Command.EDIT, Command.SHOW_IN_FOLDER, Command.DELETE, @@ -729,10 +715,6 @@ Command.OPEN_NEW_TAB, Command.OPEN_NEW_WINDOW, ]; - if (loadTimeData.getBoolean('splitViewEnabled')) { - commands.push(Command.OPEN_SPLIT_VIEW); - } - return commands; case MenuSource.TOOLBAR: return [ Command.SORT,
diff --git a/chrome/browser/resources/bookmarks/constants.ts b/chrome/browser/resources/bookmarks/constants.ts index 7eaef0c..b38e604 100644 --- a/chrome/browser/resources/bookmarks/constants.ts +++ b/chrome/browser/resources/bookmarks/constants.ts
@@ -46,12 +46,10 @@ OPEN_BOOKMARK = 21, OPEN_FOLDER = 22, - OPEN_SPLIT_VIEW = 23, - - OPEN_NEW_GROUP = 24, + OPEN_NEW_GROUP = 23, // Append new values to the end of the enum. - MAX_VALUE = 25, + MAX_VALUE = 24, } /**
diff --git a/chrome/browser/resources/new_tab_footer/app.css b/chrome/browser/resources/new_tab_footer/app.css index 7b2b17a..279ea37 100644 --- a/chrome/browser/resources/new_tab_footer/app.css +++ b/chrome/browser/resources/new_tab_footer/app.css
@@ -19,7 +19,8 @@ } #centerContainer > div > p, -#centerContainer > div > a { +#centerContainer > div > a, +#managementNoticeText > p { color: var(--color-new-tab-footer-text); display: inline-block; font-size: 13px;
diff --git a/chrome/browser/resources/new_tab_footer/app.html.ts b/chrome/browser/resources/new_tab_footer/app.html.ts index 1c81add..f1810a6 100644 --- a/chrome/browser/resources/new_tab_footer/app.html.ts +++ b/chrome/browser/resources/new_tab_footer/app.html.ts
@@ -14,10 +14,8 @@ separated from each other by a divider. --> <div id="centerContainer"> - ${!this.extensionAttribution_ ? - html`<!-- TODO(crbug.com/409056431): Remove #example-div once actual - elements added. This is used as a placeholder. --> - <div id="example-div"><p>${this.message_}</p></div>` : ''} + ${this.managementNotice_ ? + html`<div id="managementNoticeText"><p>${this.managementNotice_.text}</p></div>` : ''} ${this.extensionAttribution_ ? html`<div id="extensionAttribution"> <a href="${this.extensionAttribution_.url}">
diff --git a/chrome/browser/resources/new_tab_footer/app.ts b/chrome/browser/resources/new_tab_footer/app.ts index b2a0ea47..cc87468 100644 --- a/chrome/browser/resources/new_tab_footer/app.ts +++ b/chrome/browser/resources/new_tab_footer/app.ts
@@ -4,14 +4,14 @@ import '/strings.m.js'; +import {assert} from '//resources/js/assert.js'; import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js'; -import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {getCss} from './app.css.js'; import {getHtml} from './app.html.js'; import {NewTabFooterDocumentProxy} from './browser_proxy.js'; -import type {ExtensionAttribution} from './new_tab_footer.mojom-webui.js'; +import type {ExtensionAttribution, ManagementNotice, NewTabFooterDocumentCallbackRouter} from './new_tab_footer.mojom-webui.js'; export class NewTabFooterAppElement extends CrLitElement { static get is() { @@ -29,17 +29,20 @@ static override get properties() { return { extensionAttribution_: {type: Object}, - message_: {type: String}, + managementNotice_: {type: Object}, }; } + protected accessor extensionAttribution_: ExtensionAttribution|null = null; - // TODO(crbug.com/409056431): Remove `message_` once relevant - // variables/properties are added. This is used as a placeholder. - protected accessor message_: string = loadTimeData.getString('message'); + protected accessor managementNotice_: ManagementNotice|null = null; + private callbackRouter_: NewTabFooterDocumentCallbackRouter; + private setManagementNoticeListener_: number|null = null; constructor() { super(); + this.callbackRouter_ = + NewTabFooterDocumentProxy.getInstance().callbackRouter; this.getNtpExtensionAttribution_(); } @@ -47,6 +50,24 @@ ColorChangeUpdater.forDocument().start(); } + override connectedCallback() { + super.connectedCallback(); + this.setManagementNoticeListener_ = + this.callbackRouter_.setManagementNotice.addListener( + (notice: ManagementNotice) => { + if (notice) { + this.managementNotice_ = notice; + } + }); + NewTabFooterDocumentProxy.getInstance().handler.updateManagementNotice(); + } + + override disconnectedCallback() { + super.disconnectedCallback(); + assert(this.setManagementNoticeListener_); + this.callbackRouter_.removeListener(this.setManagementNoticeListener_); + } + private async getNtpExtensionAttribution_() { this.extensionAttribution_ = (await NewTabFooterDocumentProxy.getInstance() .handler.getNtpExtensionAttribution())
diff --git a/chrome/browser/resources/new_tab_page/app.css b/chrome/browser/resources/new_tab_page/app.css index 39980d7..2b3c866 100644 --- a/chrome/browser/resources/new_tab_page/app.css +++ b/chrome/browser/resources/new_tab_page/app.css
@@ -120,11 +120,6 @@ position: relative; } -ntp-modules { - flex-shrink: 0; - width: var(--ntp-module-layout-width); -} - #modules:not([hidden]) { /* We use animation instead of transition to allow a fade-in out of display: none. */
diff --git a/chrome/browser/resources/new_tab_page/app.html b/chrome/browser/resources/new_tab_page/app.html index f7b589a..1218fff 100644 --- a/chrome/browser/resources/new_tab_page/app.html +++ b/chrome/browser/resources/new_tab_page/app.html
@@ -55,13 +55,13 @@ ` : ''} ${this.modulesEnabled_ ? html` ${html` - <ntp-modules-v2 id="modules" + <ntp-modules id="modules" ?modules-shown-to-user="${this.modulesShownToUser}" @modules-shown-to-user-changed="${this.onModulesShownToUserChanged_}" @customize-module="${this.onCustomizeModule_}" @modules-loaded="${this.onModulesLoaded_}" ?hidden="${!this.promoAndModulesLoaded_}"> - </ntp-modules-v2> + </ntp-modules> `} ` : ''} <a id="backgroundImageAttribution"
diff --git a/chrome/browser/resources/new_tab_page/lazy_load.ts b/chrome/browser/resources/new_tab_page/lazy_load.ts index a4baca4..fb9470a 100644 --- a/chrome/browser/resources/new_tab_page/lazy_load.ts +++ b/chrome/browser/resources/new_tab_page/lazy_load.ts
@@ -25,7 +25,7 @@ export {InitializeModuleCallback, Module, ModuleDescriptor} from './modules/module_descriptor.js'; export {counterfactualLoad} from './modules/module_descriptors.js'; export {ModuleRegistry} from './modules/module_registry.js'; -export {ModuleWrapperElement} from './modules/module_wrapper.js'; +export {ModuleInstance, ModuleWrapperElement} from './modules/module_wrapper.js'; export {microsoftAuthModuleDescriptor, MicrosoftAuthModuleElement} from './modules/v2/authentication/microsoft_auth_module.js'; export {MicrosoftAuthProxyImpl} from './modules/v2/authentication/microsoft_auth_module_proxy.js'; export {CalendarElement} from './modules/v2/calendar/calendar.js'; @@ -45,7 +45,7 @@ export {microsoftFilesModuleDescriptor, MicrosoftFilesModuleElement} from './modules/v2/file_suggestion/microsoft_files_module.js'; export {MicrosoftFilesProxyImpl} from './modules/v2/file_suggestion/microsoft_files_proxy.js'; export {ModuleHeaderElement as ModuleHeaderElementV2} from './modules/v2/module_header.js'; -export {DisableModuleEvent, DismissModuleElementEvent, DismissModuleInstanceEvent, ModulesV2Element, NamedWidth, SUPPORTED_MODULE_WIDTHS} from './modules/v2/modules.js'; +export {DisableModuleEvent, DismissModuleElementEvent, DismissModuleInstanceEvent, ModulesElement, NamedWidth, SUPPORTED_MODULE_WIDTHS} from './modules/v2/modules.js'; export {ModuleElement as MostRelevantTabResumptionModuleElement, mostRelevantTabResumptionDescriptor} from './modules/v2/most_relevant_tab_resumption/module.js'; export {MostRelevantTabResumptionProxyImpl} from './modules/v2/most_relevant_tab_resumption/most_relevant_tab_resumption_proxy.js'; export {VoiceSearchOverlayElement} from './voice_search_overlay.js';
diff --git a/chrome/browser/resources/new_tab_page/modules/module_wrapper.css b/chrome/browser/resources/new_tab_page/modules/module_wrapper.css new file mode 100644 index 0000000..bf81088 --- /dev/null +++ b/chrome/browser/resources/new_tab_page/modules/module_wrapper.css
@@ -0,0 +1,35 @@ +/* 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. */ + +/* #css_wrapper_metadata_start + * #type=style-lit + * #scheme=relative + * #css_wrapper_metadata_end */ + +:host { + background-color: var(--color-new-tab-page-module-background); + border: none; + border-radius: var(--ntp-module-border-radius); + box-sizing: border-box; + display: block; + height: fit-content; + overflow: visible; + position: relative; +} + +#impressionProbe { + height: 27px; + pointer-events: none; + position: absolute; + width: 100%; +} + +#moduleElement { + align-items: center; + background: var(--color-new-tab-page-module-background); + border-radius: var(--ntp-module-border-radius); + display: flex; + height: 100%; + justify-content: center; +}
diff --git a/chrome/browser/resources/new_tab_page/modules/module_wrapper.html b/chrome/browser/resources/new_tab_page/modules/module_wrapper.html index 284624fc..9392dd5 100644 --- a/chrome/browser/resources/new_tab_page/modules/module_wrapper.html +++ b/chrome/browser/resources/new_tab_page/modules/module_wrapper.html
@@ -1,30 +1,4 @@ -<style> - :host { - background-color: var(--color-new-tab-page-module-background); - border: none; - border-radius: var(--ntp-module-border-radius); - box-sizing: border-box; - display: block; - height: fit-content; - overflow: visible; - position: relative; - } - - #impressionProbe { - height: 27px; - pointer-events: none; - position: absolute; - width: 100%; - } - - #moduleElement { - align-items: center; - background: var(--color-new-tab-page-module-background); - border-radius: var(--ntp-module-border-radius); - display: flex; - height: 100%; - justify-content: center; - } -</style> <div id="impressionProbe"></div> -<div id="moduleElement"></div> +<div id="moduleElement"> + <slot id="slot"></slot> +</div>
diff --git a/chrome/browser/resources/new_tab_page/modules/module_wrapper.ts b/chrome/browser/resources/new_tab_page/modules/module_wrapper.ts index 0499a85..af31ccc 100644 --- a/chrome/browser/resources/new_tab_page/modules/module_wrapper.ts +++ b/chrome/browser/resources/new_tab_page/modules/module_wrapper.ts
@@ -2,21 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {assert} from 'chrome://resources/js/assert.js'; -import {microTask, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrLitElement, render} from 'chrome://resources/lit/v3_0/lit.rollup.js'; import {recordLoadDuration, recordOccurence, recordPerdecage} from '../metrics_utils.js'; import {NewTabPageProxy} from '../new_tab_page_proxy.js'; import {WindowProxy} from '../window_proxy.js'; import type {ModuleDescriptor} from './module_descriptor.js'; -import {getTemplate} from './module_wrapper.html.js'; +import {getCss} from './module_wrapper.css.js'; +import {getHtml} from './module_wrapper.html.js'; /** @fileoverview Element that implements the common module UI. */ export interface ModuleInstance { element: HTMLElement; descriptor: ModuleDescriptor; + initialized: boolean; + impressed: boolean; } export interface ModuleWrapperElement { @@ -26,34 +28,65 @@ }; } -export class ModuleWrapperElement extends PolymerElement { +export class ModuleWrapperElement extends CrLitElement { static get is() { return 'ntp-module-wrapper'; } - static get template() { - return getTemplate(); + static override get styles() { + return getCss(); } - static get properties() { + static override get properties() { return { module: { - observer: 'onModuleChange_', type: Object, }, }; } - declare module: ModuleInstance; + accessor module: ModuleInstance; - private onModuleChange_( - _newValue: ModuleInstance, oldValue?: ModuleInstance) { - assert(!oldValue); - this.$.moduleElement.appendChild(this.module.element); + override render() { + // Update the light DOM element(s) and allow Lit to handle the shadow DOM + // with a slotted module's UI element. + if (this.module) { + render(this.module.element, this, {host: this}); + } + return getHtml.bind(this)(); + } + override firstUpdated() { + if (!this.module.initialized) { + this.module.initialized = true; + this.initModuleInstance_(); + } + + if (!this.module.impressed) { + // Install observer to log module header impression. + const headerObserver = + new IntersectionObserver(([{intersectionRatio}]) => { + if (intersectionRatio >= 1.0) { + headerObserver.disconnect(); + + const time = WindowProxy.getInstance().now(); + recordLoadDuration('NewTabPage.Modules.Impression', time); + recordLoadDuration( + `NewTabPage.Modules.Impression.${this.module.descriptor.id}`, + time); + this.module.impressed = true; + this.dispatchEvent(new Event('detect-impression')); + this.module.element.dispatchEvent(new Event('detect-impression')); + } + }, {threshold: 1.0}); + headerObserver.observe(this.$.impressionProbe); + } + } + + private initModuleInstance_() { // Log at most one usage per module per NTP page load. This is possible, // if a user opens a link in a new tab. - this.$.moduleElement.addEventListener('usage', (e: Event) => { + this.module.element.addEventListener('usage', (e: Event) => { e.stopPropagation(); NewTabPageProxy.getInstance().handler.onModuleUsed( this.module.descriptor.id); @@ -64,7 +97,7 @@ // Dispatch at most one interaction event for a module's `More Actions` menu // button clicks. - this.$.moduleElement.addEventListener('menu-button-click', (e: Event) => { + this.module.element.addEventListener('menu-button-click', (e: Event) => { e.stopPropagation(); NewTabPageProxy.getInstance().handler.onModuleUsed( this.module.descriptor.id); @@ -76,21 +109,17 @@ 'NewTabPage.Modules.InfoButtonClicked', this.module.descriptor.id); }, {once: true}); - // Install observer to log module header impression. - const headerObserver = new IntersectionObserver(([{intersectionRatio}]) => { - if (intersectionRatio >= 1.0) { - headerObserver.disconnect(); - const time = WindowProxy.getInstance().now(); - recordLoadDuration('NewTabPage.Modules.Impression', time); - recordLoadDuration( - `NewTabPage.Modules.Impression.${this.module.descriptor.id}`, time); - this.dispatchEvent(new Event('detect-impression')); - this.module.element.dispatchEvent(new Event('detect-impression')); - } - }, {threshold: 1.0}); + // Track whether the user hovered on the module. + this.module.element.addEventListener('mouseover', () => { + chrome.metricsPrivate.recordSparseValueWithPersistentHash( + 'NewTabPage.Modules.Hover', this.module.descriptor.id); + }, { + capture: true, // So that modules cannot swallow event. + once: true, // Only one log per NTP load. + }); - // Install observer to track max perdecage (x/10th) of the module visible on - // the page. + // Install observer to track max perdecage (x/10th) of the module visible + // on the page. let intersectionPerdecage = 0; const moduleObserver = new IntersectionObserver(([{intersectionRatio}]) => { intersectionPerdecage = @@ -106,24 +135,7 @@ `NewTabPage.Modules.ImpressionRatio.${this.module.descriptor.id}`, intersectionPerdecage); }); - - // Calling observe will immediately invoke the callback. If the module is - // fully shown when the page loads, the first callback invocation will - // happen before the elements have dimensions. For this reason, we start - // observing after the elements have had a chance to be rendered. - microTask.run(() => { - headerObserver.observe(this.$.impressionProbe); - moduleObserver.observe(this); - }); - - // Track whether the user hovered on the module. - this.addEventListener('mouseover', () => { - chrome.metricsPrivate.recordSparseValueWithPersistentHash( - 'NewTabPage.Modules.Hover', this.module.descriptor.id); - }, { - capture: true, // So that modules cannot swallow event. - once: true, // Only one log per NTP load. - }); + moduleObserver.observe(this); } }
diff --git a/chrome/browser/resources/new_tab_page/modules/modules.gni b/chrome/browser/resources/new_tab_page/modules/modules.gni index db176477..31a14ac 100644 --- a/chrome/browser/resources/new_tab_page/modules/modules.gni +++ b/chrome/browser/resources/new_tab_page/modules/modules.gni
@@ -39,7 +39,9 @@ modules_css_files = [ "modules/info_dialog.css", + "modules/module_wrapper.css", "modules/v2/module_header.css", + "modules/v2/modules.css", ] + authentication_css_files + calendar_css_files + file_suggestion_v2_css_files + most_relevant_tab_resumption_v2_css_files
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/authentication/microsoft_auth_module.ts b/chrome/browser/resources/new_tab_page/modules/v2/authentication/microsoft_auth_module.ts index 3fc06ea..795e35011 100644 --- a/chrome/browser/resources/new_tab_page/modules/v2/authentication/microsoft_auth_module.ts +++ b/chrome/browser/resources/new_tab_page/modules/v2/authentication/microsoft_auth_module.ts
@@ -78,6 +78,7 @@ protected onDisableButtonClick_() { const disableEvent = new CustomEvent('disable-module', { + bubbles: true, composed: true, detail: { message: loadTimeData.getStringF(
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/calendar/outlook_calendar_module.ts b/chrome/browser/resources/new_tab_page/modules/v2/calendar/outlook_calendar_module.ts index d047ea54..be4b0e61 100644 --- a/chrome/browser/resources/new_tab_page/modules/v2/calendar/outlook_calendar_module.ts +++ b/chrome/browser/resources/new_tab_page/modules/v2/calendar/outlook_calendar_module.ts
@@ -96,6 +96,7 @@ protected onDisableButtonClick_() { const disableEvent = new CustomEvent('disable-module', { + bubbles: true, composed: true, detail: { message: loadTimeData.getStringF(
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/file_suggestion/drive_module.ts b/chrome/browser/resources/new_tab_page/modules/v2/file_suggestion/drive_module.ts index 649ddf0..d91d572 100644 --- a/chrome/browser/resources/new_tab_page/modules/v2/file_suggestion/drive_module.ts +++ b/chrome/browser/resources/new_tab_page/modules/v2/file_suggestion/drive_module.ts
@@ -82,6 +82,7 @@ protected onDisableButtonClick_() { const disableEvent = new CustomEvent('disable-module', { + bubbles: true, composed: true, detail: { message: loadTimeData.getStringF(
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/file_suggestion/microsoft_files_module.ts b/chrome/browser/resources/new_tab_page/modules/v2/file_suggestion/microsoft_files_module.ts index 104e436..3f0fb0d 100644 --- a/chrome/browser/resources/new_tab_page/modules/v2/file_suggestion/microsoft_files_module.ts +++ b/chrome/browser/resources/new_tab_page/modules/v2/file_suggestion/microsoft_files_module.ts
@@ -100,6 +100,7 @@ protected onDisableButtonClick_() { const disableEvent = new CustomEvent('disable-module', { + bubbles: true, composed: true, detail: { message: loadTimeData.getStringF(
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/modules.css b/chrome/browser/resources/new_tab_page/modules/v2/modules.css new file mode 100644 index 0000000..283f425 --- /dev/null +++ b/chrome/browser/resources/new_tab_page/modules/v2/modules.css
@@ -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. */ + +/* #css_wrapper_metadata_start + * #type=style-lit + * #import=//resources/cr_elements/cr_hidden_style_lit.css.js + * #scheme=relative + * #include=cr-hidden-style-lit + * #css_wrapper_metadata_end */ + +#container { + display: flex; + flex-flow: row wrap; + gap: var(--container-gap); + justify-content: center; + margin-top: 8px; + max-width: var(--container-max-width, inherit); +} + +#undoToastMessage { + flex-grow: 1; +}
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/modules.html b/chrome/browser/resources/new_tab_page/modules/v2/modules.html index 59856469..08d0489 100644 --- a/chrome/browser/resources/new_tab_page/modules/v2/modules.html +++ b/chrome/browser/resources/new_tab_page/modules/v2/modules.html
@@ -1,34 +1,20 @@ -<style include="cr-hidden-style"> - #container { - display: flex; - flex-flow: row wrap; - gap: var(--container-gap); - justify-content: center; - margin-top: 8px; - max-width: var(--container-max-width, inherit); - } - - #undoToastMessage { - flex-grow: 1; - } -</style> <div id="container"> + ${this.moduleInstances_.map(item => html` + <ntp-module-wrapper .module="${item}" + ?hidden="${this.moduleDisabled_(item)}" + @disable-module="${this.onDisableModule_}" + @dismiss-module-element="${this.onDismissModuleElement_}" + @dismiss-module-instance="${this.onDismissModuleInstance_}"> + </ntp-module-wrapper> + `)} </div> -<template> - <ntp-module-wrapper module="[[item]]" - hidden="[[moduleDisabled_(disabledModules_, item)]]" - on-disable-module="onDisableModule_" - on-dismiss-module-element="onDismissModuleElement_" - on-dismiss-module-instance="onDismissModuleInstance_"> - </ntp-module-wrapper> -</template> <cr-toast id="undoToast" duration="10000"> - <div id="undoToastMessage">[[undoData_.message]]</div> - <template is="dom-if" if="[[undoData_.undo]]"> + <div id="undoToastMessage">${this.undoData_?.message || ''}</div> + ${this.undoData_?.undo ? html ` <cr-button id="undoButton" aria-label="$i18n{undoDescription}" - on-click="onUndoButtonClick_"> + @click="${this.onUndoButtonClick_}"> $i18n{undo} </cr-button> - </template> + ` : ''} </cr-toast>
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/modules.ts b/chrome/browser/resources/new_tab_page/modules/v2/modules.ts index 1987678..63f693c 100644 --- a/chrome/browser/resources/new_tab_page/modules/v2/modules.ts +++ b/chrome/browser/resources/new_tab_page/modules/v2/modules.ts
@@ -2,27 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'chrome://resources/cr_elements/cr_hidden_style.css.js'; import 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.js'; import type {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; import {assert} from 'chrome://resources/js/assert.js'; import {EventTracker} from 'chrome://resources/js/event_tracker.js'; -import type {TemplateInstanceBase} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {PolymerElement, templatize} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import type {PropertyValues} from 'chrome://resources/lit/v3_0/lit.rollup.js'; +import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js'; import {loadTimeData} from '../../i18n_setup.js'; import {recordOccurence as recordOccurrence} from '../../metrics_utils.js'; -import type {PageCallbackRouter, PageHandlerRemote} from '../../new_tab_page.mojom-webui.js'; -import type {ModuleIdName} from '../../new_tab_page.mojom-webui.js'; +import type {ModuleIdName, PageCallbackRouter, PageHandlerRemote} from '../../new_tab_page.mojom-webui.js'; import {NewTabPageProxy} from '../../new_tab_page_proxy.js'; import {WindowProxy} from '../../window_proxy.js'; -import type {Module, ModuleDescriptor} from '../module_descriptor.js'; +import type {Module} from '../module_descriptor.js'; import {ModuleRegistry} from '../module_registry.js'; import type {ModuleInstance, ModuleWrapperElement} from '../module_wrapper.js'; -import {getTemplate} from './modules.html.js'; +import {getCss} from './modules.css.js'; +import {getHtml} from './modules.html.js'; export interface NamedWidth { name: string; @@ -52,13 +51,6 @@ export type DismissModuleInstanceEvent = UndoActionEvent; export type DisableModuleEvent = UndoActionEvent; -type ModuleWrapperConstructor = new (_: Object) => - TemplateInstanceBase&HTMLElement; - -interface ItemTemplateInstance extends TemplateInstanceBase { - item: {descriptor: ModuleDescriptor}; -} - declare global { interface HTMLElementEventMap { 'disable-module': DisableModuleEvent; @@ -67,7 +59,7 @@ } } -export interface ModulesV2Element { +export interface ModulesElement { $: { container: HTMLElement, undoToast: CrToastElement, @@ -75,115 +67,74 @@ }; } -/** - * Creates template instances for a list of modules. - * - * @param modules The modules for which to create template instances. - * @param moduleWrapperConstructor The constructor used to create the template - * instances. - * @returns An array of `TemplateInstanceBase` objects. - */ -function createTemplateInstances( - modules: Module[], moduleWrapperConstructor: ModuleWrapperConstructor): - TemplateInstanceBase[] { - return modules.flatMap(module => module.elements.map(element => { - const instanceData = { +function createModuleInstances(module: Module): ModuleInstance[] { + return module.elements.map(element => { + return { element, descriptor: module.descriptor, + initialized: false, + impressed: false, }; - return new moduleWrapperConstructor({item: instanceData}); - })); + }); } /** Container for the NTP modules. */ -export class ModulesV2Element extends PolymerElement { +export class ModulesElement extends CrLitElement { static get is() { - return 'ntp-modules-v2'; + return 'ntp-modules'; } - static get template() { - return getTemplate(); + static override get styles() { + return getCss(); } - static get properties() { + static override get properties() { return { - disabledModules_: { - type: Object, - observer: 'onDisabledModulesChange_', - value: () => ({all: true, ids: []}), - }, - modulesShownToUser: { type: Boolean, notify: true, }, - + moduleInstances_: {type: Array}, + disabledModules_: {type: Object}, /** Data about the most recent un-doable action. */ - undoData_: { - type: Object, - value: null, - }, + undoData_: {type: Object}, }; } - declare modulesShownToUser: boolean; + accessor modulesShownToUser: boolean = false; private waitToLoadModules_: boolean = loadTimeData.getBoolean('waitToLoadModules'); - private maxColumnCount_: number; + accessor moduleInstances_: ModuleInstance[] = []; + accessor disabledModules_: + {all: boolean, ids: string[]} = {all: true, ids: []}; + protected accessor undoData_: {message: string, undo?: () => void}|null = + null; + + private maxColumnCount_: number = + loadTimeData.getInteger('modulesMaxColumnCount'); + private availableWidth_: number = 0; private containerMaxWidth_: number; - declare private disabledModules_: {all: boolean, ids: string[]}; private eventTracker_: EventTracker = new EventTracker(); - declare private undoData_: {message: string, undo?: () => void}|null; private setDisabledModulesListenerId_: number|null = null; private setModulesLoadableListenerId_: number|null = null; - private containerObserver_: MutationObserver|null = null; - private templateInstances_: TemplateInstanceBase[] = []; - private availableModulesIds_: string[]|null = null; - private modulesLoadInitiated_: boolean = false; + + private availableModulesIds_: Set<string>|null = null; private moduleLoadPromise_: Promise<void>|null = null; // TODO(crbug.com/385174675): Remove |modulesReloadable_| flag when safe. - // Otherwise, when Microsoft modules are enabled ToT, the current behavior - // gated by |modulesReloadable_| should become the default module loading - // behavior. + // Otherwise, when Microsoft modules are enabled ToT, the current + // behavior gated by |modulesReloadable_| should become the default module + // loading behavior. private modulesReloadable_: boolean = loadTimeData.getBoolean('modulesReloadable'); - private moduleWrapperConstructor_: ModuleWrapperConstructor|null = null; - private needsReload_: boolean = false; - private newlyEnabledModuleIds_: string[] = []; + private modulesLoadInitiated_: boolean = false; - private callbackRouter_: PageCallbackRouter; - private handler_: PageHandlerRemote; - private moduleRegistry_: ModuleRegistry; - - constructor() { - super(); - this.callbackRouter_ = NewTabPageProxy.getInstance().callbackRouter; - this.handler_ = NewTabPageProxy.getInstance().handler; - this.moduleRegistry_ = ModuleRegistry.getInstance(); + override render() { + return getHtml.bind(this)(); } override connectedCallback() { super.connectedCallback(); - this.setDisabledModulesListenerId_ = - this.callbackRouter_.setDisabledModules.addListener( - (all: boolean, ids: string[]) => { - if (this.modulesReloadable_ && this.modulesLoadInitiated_) { - this.handleModuleEnablement_(this.disabledModules_.ids, ids); - } - - this.disabledModules_ = {all, ids}; - }); - this.handler_.updateDisabledModules(); - - this.setModulesLoadableListenerId_ = - this.callbackRouter_.setModulesLoadable.addListener(() => { - if (this.waitToLoadModules_) { - this.waitToLoadModules_ = false; - this.moduleLoadPromise_ = this.loadModules_(); - } - }); - const widths: Set<number> = new Set(); for (let i = 0; i < SUPPORTED_MODULE_WIDTHS.length; i++) { const namedWidth = SUPPORTED_MODULE_WIDTHS[i]; @@ -231,10 +182,27 @@ this.eventTracker_.add(window, 'keydown', this.onWindowKeydown_.bind(this)); - this.containerObserver_ = new MutationObserver(() => { - this.updateContainerAndChildrenStyles_(); - }); - this.containerObserver_.observe(this.$.container, {childList: true}); + this.setDisabledModulesListenerId_ = + this.callbackRouter_.setDisabledModules.addListener( + (all: boolean, ids: string[]) => { + this.disabledModules_ = {all, ids}; + }); + this.pageHandler_.updateDisabledModules(); + + this.setModulesLoadableListenerId_ = + this.callbackRouter_.setModulesLoadable.addListener(() => { + if (this.waitToLoadModules_) { + this.waitToLoadModules_ = false; + this.moduleLoadPromise_ = this.loadModules_(); + } else if (this.modulesReloadable_) { + this.handleModuleEnablement_(this.disabledModules_); + } + }); + if (this.waitToLoadModules_) { + this.pageHandler_.updateModulesLoadable(); + } else { + this.moduleLoadPromise_ = this.loadModules_(); + } } override disconnectedCallback() { @@ -247,158 +215,68 @@ this.eventTracker_.removeAll(); - this.containerObserver_!.disconnect(); } - override ready() { - super.ready(); + override firstUpdated() { + this.style.setProperty('--container-gap', `${CONTAINER_GAP_WIDTH}px`); - this.updateStyles({ - '--container-gap': `${CONTAINER_GAP_WIDTH}px`, - }); - - this.maxColumnCount_ = loadTimeData.getInteger('modulesMaxColumnCount'); this.containerMaxWidth_ = this.maxColumnCount_ * SUPPORTED_MODULE_WIDTHS[0].value + (this.maxColumnCount_ - 1) * CONTAINER_GAP_WIDTH; + } - if (this.waitToLoadModules_) { - this.handler_.updateModulesLoadable(); - } else { - this.moduleLoadPromise_ = this.loadModules_(); + override updated(changedProperties: PropertyValues<this>) { + super.updated(changedProperties); + this.availableWidth_ = Math.min( + document.body.clientWidth - 2 * MARGIN_WIDTH, this.containerMaxWidth_); + } + + override willUpdate(changedProperties: PropertyValues<this>) { + super.willUpdate(changedProperties); + if (changedProperties.has('moduleInstances_') || + changedProperties.has('disabledModules_')) { + this.updateContainerAndChildrenStyles_(this.availableWidth_); } } - private moduleDisabled_( - disabledModules: {all: true, ids: string[]}, - instance: ModuleInstance): boolean { - return disabledModules.all || - disabledModules.ids.includes(instance.descriptor.id); + get pageHandler_(): PageHandlerRemote { + return NewTabPageProxy.getInstance().handler; } - /** - * Manages the reloading of modules within the container based on - * updates to the disabled modules list. - * - * Subsequent calls handle potential reloads. Newly enabled modules are - * queued and loaded individually. The user does not see these modules until - * the entire container is reloaded via |reloadModules_()| after all - * queued modules have been loaded. Loading continues as long as - * |this.newlyEnabledModuleIds_| is not empty, even across multiple calls to - * |maybeLoadModules_()|. - * - * @param prevDisabledIds - Previous list of disabled module IDs. - * @param newDisabledIds - Latest list of disabled module IDs. - */ - private async handleModuleEnablement_( - prevDisabledIds: string[], newDisabledIds: string[]): Promise<void> { - if (this.moduleLoadPromise_) { - await this.moduleLoadPromise_; - } + get callbackRouter_(): PageCallbackRouter { + return NewTabPageProxy.getInstance().callbackRouter; + } - if (!this.availableModulesIds_) { - const modulesIdNames = (await this.handler_.getModulesIdNames()).data; - // TODO(crbug.com/385174675): Set |this.availableModulesIds_| in - // |this.loadModules_()| when Microsoft modules are enabled ToT, as this - // experimental behavior is currently gated to the Microsoft modules. - this.availableModulesIds_ = modulesIdNames.map((m: ModuleIdName) => m.id); - } - - const filteredNewlyEnabledModuleIds = - prevDisabledIds.filter(id => !newDisabledIds.includes(id)) - .filter(id => this.availableModulesIds_!.includes(id)); - this.newlyEnabledModuleIds_ = - this.newlyEnabledModuleIds_.concat(filteredNewlyEnabledModuleIds); - - if (filteredNewlyEnabledModuleIds.length === 0) { - return; - } - - // Load modules one by one until the queue is empty. - while (this.newlyEnabledModuleIds_.length > 0) { - const id = this.newlyEnabledModuleIds_.shift() as string; - const hasExistingInstance = this.templateInstances_.some( - (templateInstance) => - (templateInstance as unknown as ItemTemplateInstance) - .item.descriptor.id === id); - if (!hasExistingInstance) { - await this.addTemplateInstance_(id); - this.needsReload_ = true; - } - if (this.newlyEnabledModuleIds_.length === 0 && this.needsReload_) { - await this.reloadModules_(); - this.needsReload_ = false; - } else { - // More modules to load; the next call to this function will continue - // the process. - return; - } - } + protected moduleDisabled_(instance: ModuleInstance): boolean { + return this.disabledModules_.all || + this.disabledModules_.ids.includes(instance.descriptor.id); } /** * Initializes the module container by loading all currently enabled modules. - * This method uses |this.moduleRegistry_| to determine which modules to load + * This method uses the `ModuleRegistry` to determine which modules to load * and is called only when the container is empty. - * */ private async loadModules_(): Promise<void> { - if (this.waitToLoadModules_) { - return; - } - this.modulesLoadInitiated_ = true; - const modulesIdNames = (await this.handler_.getModulesIdNames()).data; - const modules = await this.moduleRegistry_.initializeModulesHavingIds( - modulesIdNames.map((m: ModuleIdName) => m.id), - loadTimeData.getInteger('modulesLoadTimeout')); + const modulesIdNames = (await this.pageHandler_.getModulesIdNames()).data; + const modules = + await ModuleRegistry.getInstance().initializeModulesHavingIds( + modulesIdNames.map((m: ModuleIdName) => m.id), + loadTimeData.getInteger('modulesLoadTimeout')); if (modules) { - this.handler_.onModulesLoadedWithData( + this.pageHandler_.onModulesLoadedWithData( modules.map(module => module.descriptor.id)); - // TODO(crbug.com/392889804): Remove this logic, since no modules populate - // more than once anymore. - if (modules.length > 1) { - const maxModuleInstanceCount = - (modules.length >= this.maxColumnCount_) ? - 1 : - loadTimeData.getInteger( - 'multipleLoadedModulesMaxModuleInstanceCount'); - if (maxModuleInstanceCount > 0) { - modules.forEach(module => { - module.elements.splice( - maxModuleInstanceCount, - module.elements.length - maxModuleInstanceCount); - }); - } - } - - if (modules.length > 0) { - if (!this.moduleWrapperConstructor_) { - this.initModuleWrapperConstructor_(); - } - - this.templateInstances_ = - createTemplateInstances(modules, this.moduleWrapperConstructor_!); - this.$.container.replaceChildren( - ...this.templateInstances_.map(t => t.children[0] as HTMLElement)); - } + this.moduleInstances_ = modules + .map(module => { + return createModuleInstances(module); + }) + .flat(); this.recordInitialLoadMetrics_(modules, modulesIdNames); this.dispatchEvent(new Event('modules-loaded')); } - - this.moduleLoadPromise_ = null; - } - - private initModuleWrapperConstructor_() { - const template = this.shadowRoot!.querySelector('template')!; - this.moduleWrapperConstructor_ = templatize(template, this, { - parentModel: true, - forwardHostProp: this.forwardHostProp_, - instanceProps: {item: true}, - }) as new (item: Object) => - TemplateInstanceBase & HTMLElement; } private recordInitialLoadMetrics_( @@ -412,18 +290,15 @@ !this.disabledModules_.ids.includes(id)); }); chrome.metricsPrivate.recordSmallCount( - 'NewTabPage.Modules.InstanceCount', this.templateInstances_.length); + 'NewTabPage.Modules.InstanceCount', this.moduleInstances_.length); chrome.metricsPrivate.recordBoolean( 'NewTabPage.Modules.VisibleOnNTPLoad', !this.disabledModules_.all); this.recordModuleLoadedWithModules_(/*onNtpLoad=*/ true); - - this.dispatchEvent(new Event('modules-loaded')); } private recordModuleLoadedWithModules_(onNtpLoad: boolean) { - const moduleDescriptorIds = [...new Set(this.templateInstances_.map( - instance => - (instance as unknown as ItemTemplateInstance).item.descriptor.id))]; + const moduleDescriptorIds = [...new Set( + this.moduleInstances_.map(instance => instance.descriptor.id))]; const histogramBase = onNtpLoad ? 'NewTabPage.Modules.LoadedWith' : 'NewTabPage.Modules.ReloadedWith'; @@ -439,79 +314,85 @@ } /** - * Creates a template instance for a module then appends it to - * |this.templateInstances_| based on the provided module id. + * Manages the reloading of modules within the container based on + * updates to the disabled modules list. * - * @param moduleId A module id to be leveraged when determining the - * module to be initialized. + * Subsequent calls handle potential reloads. Newly enabled modules are + * queued and loaded individually. The user does not see these modules until + * the entire container is reloaded after all queued modules have been loaded. + * + * @param disabledModules - An object containing the current list of disabled + * module ids. */ - private async addTemplateInstance_(moduleId: string): Promise<void> { - const module = await this.moduleRegistry_.initializeModuleById( - moduleId, loadTimeData.getInteger('modulesLoadTimeout')); + private async handleModuleEnablement_( + disabledModules: {all: boolean, ids: string[]}): Promise<void> { + if (this.moduleLoadPromise_) { + await this.moduleLoadPromise_; + } - if (!module) { + if (!this.availableModulesIds_) { + const modulesIdNames = (await this.pageHandler_.getModulesIdNames()).data; + // TODO(crbug.com/385174675): Set |this.availableModulesIds_| in + // |this.loadModules_()| when Microsoft modules are enabled ToT, as this + // experimental behavior is currently gated to the Microsoft modules. + this.availableModulesIds_ = new Set(modulesIdNames.map((m) => m.id)); + } + + const disabledModuleIds = disabledModules.ids; + const newlyEnabledModuleIds = [...this.availableModulesIds_.difference( + new Set(disabledModuleIds.concat( + this.moduleInstances_.map((m) => m.descriptor.id))))]; + if (newlyEnabledModuleIds.length === 0) { + return; + } + // Load modules one by one until the queue is empty. + const newModuleInstances: ModuleInstance[] = []; + while (newlyEnabledModuleIds.length > 0) { + const moduleId = newlyEnabledModuleIds.shift()!; + const module = await ModuleRegistry.getInstance().initializeModuleById( + moduleId, loadTimeData.getInteger('modulesLoadTimeout')); + if (module) { + newModuleInstances.push(...createModuleInstances(module)); + } + } + + if (newModuleInstances.length > 0) { + newModuleInstances.push(...this.moduleInstances_); + const orderedIds = (await this.pageHandler_.getModulesOrder()).moduleIds; + if (orderedIds && orderedIds.length > 0) { + newModuleInstances.sort((a, b) => { + const aId = a.descriptor.id; + const bId = b.descriptor.id; + const aHasOrder = orderedIds.includes(aId); + const bHasOrder = orderedIds.includes(bId); + if (aHasOrder && bHasOrder) { + return orderedIds.indexOf(aId) - orderedIds.indexOf(bId); + } + return +bHasOrder - +aHasOrder; + }); + } + + this.moduleInstances_ = newModuleInstances; + chrome.metricsPrivate.recordSmallCount( + 'NewTabPage.Modules.ReloadedModulesCount', + this.moduleInstances_.length); + this.recordModuleLoadedWithModules_(/*onNtpLoad=*/ false); + } + } + + private updateContainerAndChildrenStyles_(availableWidth: number) { + const visibleModuleInstances = this.disabledModules_.all ? + [] : + this.moduleInstances_.filter( + instance => + !this.disabledModules_.ids.includes(instance.descriptor.id)); + + this.modulesShownToUser = visibleModuleInstances.length !== 0; + if (visibleModuleInstances.length === 0) { return; } - if (!this.moduleWrapperConstructor_) { - this.initModuleWrapperConstructor_(); - } - - this.templateInstances_ = this.templateInstances_.concat( - ...createTemplateInstances([module], this.moduleWrapperConstructor_!)); - } - - /** - * Reloads the modules container by sorting template instances based on the - * order provided by |this.handler_| and then updating the container's DOM. - */ - private async reloadModules_(): Promise<void> { - const orderedIds = (await this.handler_.getModulesOrder()).moduleIds; - if (orderedIds && orderedIds.length > 0) { - this.templateInstances_ = this.templateInstances_.sort((a, b) => { - const aId = (a as unknown as ItemTemplateInstance).item.descriptor.id; - const bId = (b as unknown as ItemTemplateInstance).item.descriptor.id; - const aHasOrder = orderedIds.includes(aId); - const bHasOrder = orderedIds.includes(bId); - if (aHasOrder && bHasOrder) { - // Apply order. - return orderedIds.indexOf(aId) - orderedIds.indexOf(bId); - } - return +bHasOrder - +aHasOrder; - }); - } - - this.$.container.replaceChildren( - ...this.templateInstances_.map(t => t.children[0] as HTMLElement)); - - chrome.metricsPrivate.recordSmallCount( - 'NewTabPage.Modules.ReloadedModulesCount', - this.templateInstances_.length); - this.recordModuleLoadedWithModules_(/*onNtpLoad=*/ false); - } - - private forwardHostProp_(property: string, value: any) { - this.templateInstances_.forEach(instance => { - instance.forwardHostProp(property, value); - }); - } - - private updateContainerAndChildrenStyles_(availableWidth?: number) { - if (typeof availableWidth === 'undefined') { - availableWidth = Math.min( - document.body.clientWidth - 2 * MARGIN_WIDTH, - this.containerMaxWidth_); - } - - const moduleWrappers = - Array.from(this.shadowRoot!.querySelectorAll<ModuleWrapperElement>( - 'ntp-module-wrapper:not([hidden])')); - this.modulesShownToUser = moduleWrappers.length !== 0; - if (moduleWrappers.length === 0) { - return; - } - - this.updateStyles({'--container-max-width': `${availableWidth}px`}); + this.style.setProperty('--container-max-width', `${availableWidth}px`); const clamp = (min: number, val: number, max: number) => Math.max(min, Math.min(val, max)); @@ -523,9 +404,9 @@ this.maxColumnCount_); let index = 0; - while (index < moduleWrappers.length) { - const instances = moduleWrappers.slice(index, index + rowMaxInstanceCount) - .map(w => w.module); + while (index < visibleModuleInstances.length) { + const instances = + visibleModuleInstances.slice(index, index + rowMaxInstanceCount); let namedWidth = SUPPORTED_MODULE_WIDTHS[0]; for (let i = 1; i < SUPPORTED_MODULE_WIDTHS.length; i++) { if (Math.floor( @@ -548,8 +429,9 @@ } } - private onDisableModule_(e: DisableModuleEvent) { - const id = (e.target! as ModuleWrapperElement).module.descriptor.id; + protected onDisableModule_(e: DisableModuleEvent) { + const id = ((e.target! as HTMLElement).parentNode as ModuleWrapperElement) + .module.descriptor.id; const restoreCallback = e.detail.restoreCallback; this.undoData_ = { message: e.detail.message, @@ -557,7 +439,7 @@ if (restoreCallback) { restoreCallback(); } - this.handler_.setModuleDisabled(id, false); + this.pageHandler_.setModuleDisabled(id, false); chrome.metricsPrivate.recordSparseValueWithPersistentHash( 'NewTabPage.Modules.Enabled', id); chrome.metricsPrivate.recordSparseValueWithPersistentHash( @@ -565,7 +447,7 @@ }, }; - this.handler_.setModuleDisabled(id, true); + this.pageHandler_.setModuleDisabled(id, true); this.$.undoToast.show(); chrome.metricsPrivate.recordSparseValueWithPersistentHash( METRIC_NAME_MODULE_DISABLED, id); @@ -573,31 +455,29 @@ `${METRIC_NAME_MODULE_DISABLED}.ModuleRequest`, id); } - private onDisabledModulesChange_() { - this.updateContainerAndChildrenStyles_(); - } - /** * @param e Event notifying a module instance was dismissed. Contains the * message to show in the toast. */ - private onDismissModuleInstance_(e: DismissModuleInstanceEvent) { - const wrapper = (e.target! as ModuleWrapperElement); + protected onDismissModuleInstance_(e: DismissModuleInstanceEvent) { + const wrapper = + ((e.target! as HTMLElement).parentNode as ModuleWrapperElement); const index = Array.from(wrapper.parentNode!.children).indexOf(wrapper); - wrapper.remove(); + const module = this.moduleInstances_[index]; + this.moduleInstances_ = this.moduleInstances_.toSpliced(index, 1); const restoreCallback = e.detail.restoreCallback; this.undoData_ = { message: e.detail.message, undo: restoreCallback ? () => { - this.$.container.insertBefore( - wrapper, this.$.container.childNodes[index]); + this.moduleInstances_ = + this.moduleInstances_.toSpliced(index, 0, module); restoreCallback(); recordOccurrence('NewTabPage.Modules.Restored'); recordOccurrence( - `NewTabPage.Modules.Restored.${wrapper.module.descriptor.id}`); + `NewTabPage.Modules.Restored.${module.descriptor.id}`); } : undefined, }; @@ -605,10 +485,10 @@ // Notify the user. this.$.undoToast.show(); - this.handler_.onDismissModule(wrapper.module.descriptor.id); + this.pageHandler_.onDismissModule(module.descriptor.id); } - private onDismissModuleElement_(e: DismissModuleElementEvent) { + protected onDismissModuleElement_(e: DismissModuleElementEvent) { const restoreCallback = e.detail.restoreCallback; this.undoData_ = { message: e.detail.message, @@ -623,7 +503,7 @@ this.$.undoToast.show(); } - private onUndoButtonClick_() { + protected onUndoButtonClick_() { if (!this.undoData_) { return; } @@ -646,4 +526,4 @@ } } -customElements.define(ModulesV2Element.is, ModulesV2Element); +customElements.define(ModulesElement.is, ModulesElement);
diff --git a/chrome/browser/resources/pdf/constants.ts b/chrome/browser/resources/pdf/constants.ts index 7e9556c..d50ea68 100644 --- a/chrome/browser/resources/pdf/constants.ts +++ b/chrome/browser/resources/pdf/constants.ts
@@ -58,12 +58,18 @@ ITALIC = 'italic', } +export enum TextTypeface { + SANS_SERIF = 'sans-serif', + SERIF = 'serif', + MONOSPACE = 'monospace', +} + export type TextStyles = { [key in TextStyle]: boolean }; export interface TextAttributes { - typeface: string; + typeface: TextTypeface; size: number; color: Color; alignment: TextAlignment;
diff --git a/chrome/browser/resources/pdf/controller.ts b/chrome/browser/resources/pdf/controller.ts index c9be83854..70dfb5e 100644 --- a/chrome/browser/resources/pdf/controller.ts +++ b/chrome/browser/resources/pdf/controller.ts
@@ -64,11 +64,6 @@ type: 'finishTextAnnotation'; data: TextAnnotation; } - -interface AnnotationFontsMessage { - type: 'getTextAnnotFontNames'; - data: string[]; -} // </if> /** @@ -231,23 +226,6 @@ }); } - getTextAnnotFontNames(): Promise<AnnotationFontsMessage> { - // TODO(crbug.com/402546154): Use backend reply instead of dropping it - // on the ground and returning dummy data once the backend is in place. - this.postMessageWithReply_({ - type: 'getTextAnnotFontNames', - }); - return Promise.resolve({ - type: 'getTextAnnotFontNames', - data: [ - 'Roboto', - 'Serif', - 'Sans', - 'Monospace', - ], - }); - } - setAnnotationBrush(brush: AnnotationBrush) { const message: AnnotationBrushMessage = { type: 'setAnnotationBrush',
diff --git a/chrome/browser/resources/pdf/elements/ink_annotation_text_mixin.ts b/chrome/browser/resources/pdf/elements/ink_annotation_text_mixin.ts index 4c02afc..3ed649c 100644 --- a/chrome/browser/resources/pdf/elements/ink_annotation_text_mixin.ts +++ b/chrome/browser/resources/pdf/elements/ink_annotation_text_mixin.ts
@@ -5,6 +5,7 @@ import type {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js'; import type {Color, TextAttributes} from '../constants.js'; +import {TextTypeface} from '../constants.js'; import {Ink2Manager} from '../ink2_manager.js'; import {hexToColor} from '../pdf_viewer_utils.js'; @@ -63,23 +64,30 @@ } accessor currentColor: Color = hexToColor(TEXT_COLORS[0]!.color); - accessor currentSize: number = TEXT_SIZES[0]!; - accessor currentTypeface: string = ''; + accessor currentSize: number = TEXT_SIZES[3]!; + accessor currentTypeface: TextTypeface = TextTypeface.SANS_SERIF; accessor colors: ColorOption[] = TEXT_COLORS; - accessor fontNames: string[] = []; + accessor fontNames: TextTypeface[] = [ + TextTypeface.SANS_SERIF, + TextTypeface.SERIF, + TextTypeface.MONOSPACE, + ]; accessor sizes: number[] = TEXT_SIZES; - override firstUpdated() { - Ink2Manager.getInstance().getTextAnnotationFontNames().then( - fontNames => { - // Set the fontNames and then update the text. - this.fontNames = fontNames; - this.onTextAttributesChanged( - Ink2Manager.getInstance().getCurrentTextAttributes()); - }); + getLabelForTypeface(typeface: TextTypeface): string { + // TODO(crbug.com/402547554): These strings should be retrieved from + // loadTimeData so they are internationalized once they are final. + switch (typeface) { + case TextTypeface.SANS_SERIF: + return 'Sans-serif'; + case TextTypeface.SERIF: + return 'Serif'; + case TextTypeface.MONOSPACE: + return 'Fixed-width'; + } } - isSelectedTypeface(typeface: string): boolean { + isSelectedTypeface(typeface: TextTypeface): boolean { return typeface === this.currentTypeface; } @@ -89,7 +97,7 @@ onTypefaceSelected(e: Event) { const newValue = (e.target as HTMLSelectElement).value; - Ink2Manager.getInstance().setTextTypeface(newValue); + Ink2Manager.getInstance().setTextTypeface(newValue as TextTypeface); } onSizeSelected(e: Event) { @@ -121,8 +129,9 @@ currentColor: Color; currentSize: number; currentTypeface: string; - fontNames: string[]; + fontNames: TextTypeface[]; sizes: number[]; + getLabelForTypeface(typeface: TextTypeface): string; isSelectedTypeface(typeface: string): boolean; isSelectedSize(size: number): boolean; onTypefaceSelected(e: Event): void;
diff --git a/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.html.ts b/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.html.ts index 93a4464..bc8f8d26 100644 --- a/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.html.ts +++ b/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.html.ts
@@ -20,7 +20,7 @@ ${this.fontNames.map(typeface => html` <option value="${typeface}" ?selected="${this.isSelectedTypeface(typeface)}"> - ${typeface} + ${this.getLabelForTypeface(typeface)} </option>`)} </select> <select class="md-select size-select" @change="${this.onSizeSelected}">
diff --git a/chrome/browser/resources/pdf/elements/viewer_text_side_panel.html.ts b/chrome/browser/resources/pdf/elements/viewer_text_side_panel.html.ts index 0abe923..53194f3a 100644 --- a/chrome/browser/resources/pdf/elements/viewer_text_side_panel.html.ts +++ b/chrome/browser/resources/pdf/elements/viewer_text_side_panel.html.ts
@@ -19,7 +19,7 @@ ${this.fontNames.map(typeface => html` <option value="${typeface}" ?selected="${this.isSelectedTypeface(typeface)}"> - ${typeface} + ${this.getLabelForTypeface(typeface)} </option>`)} </select> <select class="md-select" @change="${this.onSizeSelected}">
diff --git a/chrome/browser/resources/pdf/ink2_manager.ts b/chrome/browser/resources/pdf/ink2_manager.ts index 62c0ba8..4fcf73b 100644 --- a/chrome/browser/resources/pdf/ink2_manager.ts +++ b/chrome/browser/resources/pdf/ink2_manager.ts
@@ -6,7 +6,7 @@ import {PromiseResolver} from 'chrome://resources/js/promise_resolver.js'; import type {AnnotationBrush, Color, Point, TextAnnotation, TextAttributes, TextBoxRect, TextStyles} from './constants.js'; -import {AnnotationBrushType, TextAlignment, TextStyle} from './constants.js'; +import {AnnotationBrushType, TextAlignment, TextStyle, TextTypeface} from './constants.js'; import {PluginController, PluginControllerEventType} from './controller.js'; import type {Viewport} from './viewport.js'; @@ -40,7 +40,7 @@ private annotations_: Map<number, Map<number, TextAnnotation>> = new Map(); // The attributes selected by the user for new annotations. private attributes_: TextAttributes = { - typeface: '', + typeface: TextTypeface.SANS_SERIF, size: 12, color: {r: 0, g: 0, b: 0}, alignment: TextAlignment.LEFT, @@ -54,7 +54,6 @@ // user is editing. Null if the user is not editing an annotation or is // creating a new annotation using |attributes_|. private existingAnnotationAttributes_: TextAttributes|null = null; - private fontNamesResolver_: PromiseResolver<string[]>|null = null; private pageNumber_: number = -1; private pluginController_: PluginController = PluginController.getInstance(); private viewport_: Viewport|null = null; @@ -220,20 +219,7 @@ this.setAnnotationBrushInPlugin_(); } - getTextAnnotationFontNames(): Promise<string[]> { - if (this.fontNamesResolver_ === null) { - this.fontNamesResolver_ = new PromiseResolver(); - this.pluginController_.getTextAnnotFontNames().then(fontsMessage => { - assert(this.fontNamesResolver_); - this.fontNamesResolver_.resolve(fontsMessage.data); - assert(fontsMessage.data.length > 0); - this.setTextTypeface(fontsMessage.data[0]!); - }); - } - return this.fontNamesResolver_.promise; - } - - setTextTypeface(typeface: string) { + setTextTypeface(typeface: TextTypeface) { const current = this.getCurrentTextAttributes(); if (current.typeface === typeface) { return;
diff --git a/chrome/browser/resources/pdf/pdf_viewer_wrapper.ts b/chrome/browser/resources/pdf/pdf_viewer_wrapper.ts index 2bb0178..ef975d9 100644 --- a/chrome/browser/resources/pdf/pdf_viewer_wrapper.ts +++ b/chrome/browser/resources/pdf/pdf_viewer_wrapper.ts
@@ -14,7 +14,7 @@ export {Bookmark} from './bookmark_type.js'; export {BrowserApi, ZoomBehavior} from './browser_api.js'; // <if expr="enable_pdf_ink2"> -export {AnnotationBrush, AnnotationBrushType, Color, TextAlignment, TextAnnotation, TextAttributes, TextStyle} from './constants.js'; +export {AnnotationBrush, AnnotationBrushType, Color, TextAlignment, TextAnnotation, TextAttributes, TextStyle, TextTypeface} from './constants.js'; // </if> // <if expr="enable_pdf_ink2 or enable_ink"> export {AnnotationMode} from './constants.js';
diff --git a/chrome/browser/resources/print_preview/BUILD.gn b/chrome/browser/resources/print_preview/BUILD.gn index 9bbb0e1..3f5fca2d 100644 --- a/chrome/browser/resources/print_preview/BUILD.gn +++ b/chrome/browser/resources/print_preview/BUILD.gn
@@ -29,7 +29,6 @@ "ui/destination_list.ts", "ui/destination_list_item.ts", "ui/destination_select.ts", - "ui/destination_settings.ts", "ui/dpi_settings.ts", "ui/duplex_settings.ts", "ui/header.ts", @@ -75,6 +74,8 @@ "print_preview.ts", "print_preview_utils.ts", "ui/debouncer.ts", + "ui/destination_settings.html.ts", + "ui/destination_settings.ts", "ui/highlight_utils.ts", "ui/input_mixin.ts", "ui/input_mixin_lit.ts",
diff --git a/chrome/browser/resources/print_preview/ui/app.html b/chrome/browser/resources/print_preview/ui/app.html index 4ec27454..d2c513c9 100644 --- a/chrome/browser/resources/print_preview/ui/app.html +++ b/chrome/browser/resources/print_preview/ui/app.html
@@ -47,11 +47,12 @@ </div> <print-preview-sidebar id="sidebar" destination-state="{{destinationState_}}" - controls-managed="[[controlsManaged_]]" destination="{{destination_}}" + controls-managed="[[controlsManaged_]]" destination="[[destination_]]" error="{{error_}}" is-pdf="[[!documentSettings_.isModifiable]]" page-count="[[documentSettings_.pageCount]]" settings="[[settings]]" state="[[state]]" on-focus="onSidebarFocus_" + on-destination-changed="onDestinationChanged_" on-destination-capabilities-changed="onDestinationCapabilitiesChanged_" <if expr="is_macosx"> on-open-pdf-in-preview="onOpenPdfInPreview_"
diff --git a/chrome/browser/resources/print_preview/ui/app.ts b/chrome/browser/resources/print_preview/ui/app.ts index 34fcdbd74..fa1b0ad 100644 --- a/chrome/browser/resources/print_preview/ui/app.ts +++ b/chrome/browser/resources/print_preview/ui/app.ts
@@ -537,6 +537,10 @@ this.$.state.transitTo(State.CLOSING); } + private onDestinationChanged_(e: CustomEvent<{value: Destination}>) { + this.destination_ = e.detail.value; + } + private onDestinationCapabilitiesChanged_() { this.$.model.updateSettingsFromDestination(); }
diff --git a/chrome/browser/resources/print_preview/ui/destination_select.html b/chrome/browser/resources/print_preview/ui/destination_select.html index ca70525..aa5a352e 100644 --- a/chrome/browser/resources/print_preview/ui/destination_select.html +++ b/chrome/browser/resources/print_preview/ui/destination_select.html
@@ -12,16 +12,19 @@ style="background-image: [[getBackgroundImages_(selectedValue, destination, noDestinations, dark)]];" - disabled$="[[disabled]]" - value="[[selectedValue]]" on-change="onSelectChange"> + disabled$="[[disabled]]" on-change="onSelectChange"> <template is="dom-repeat" items="[[recentDestinationList]]"> - <option value="[[item.key]]">[[item.displayName]]</option> + <option value="[[item.key]]" + selected$="[[isSelected_(item.key, selectedValue)]]"> + [[item.displayName]] + </option> </template> - <option value="[[pdfDestinationKey_]]" hidden$="[[pdfPrinterDisabled]]"> + <option value="[[pdfDestinationKey_]]" hidden$="[[pdfPrinterDisabled]]" + selected$="[[isSelected_(pdfDestinationKey_, selectedValue)]]"> $i18n{printToPDF} </option> - <option value="noDestinations" - hidden$="[[!noDestinations]]" selected$="[[noDestinations]]"> + <option value="noDestinations" hidden$="[[!noDestinations]]" + selected$="[[noDestinations]]"> $i18n{noDestinationsMessage} </option> <option value="seeMore" aria-label$="[[i18n(seeMoreDestinationsLabel)]]">
diff --git a/chrome/browser/resources/print_preview/ui/destination_select.ts b/chrome/browser/resources/print_preview/ui/destination_select.ts index 930b822..a58570ad 100644 --- a/chrome/browser/resources/print_preview/ui/destination_select.ts +++ b/chrome/browser/resources/print_preview/ui/destination_select.ts
@@ -45,19 +45,32 @@ static get properties() { return { - activeUser: String, - - dark: Boolean, + dark: { + type: Boolean, + value: false, + }, destination: Object, - disabled: Boolean, + disabled: { + type: Boolean, + value: false, + }, - loaded: Boolean, + loaded: { + type: Boolean, + value: false, + }, - noDestinations: Boolean, + noDestinations: { + type: Boolean, + value: false, + }, - pdfPrinterDisabled: Boolean, + pdfPrinterDisabled: { + type: Boolean, + value: false, + }, recentDestinationList: Array, @@ -68,7 +81,6 @@ }; } - declare activeUser: string; declare dark: boolean; declare destination: Destination; declare disabled: boolean; @@ -157,6 +169,10 @@ return this.shadowRoot!.querySelectorAll<HTMLOptionElement>( 'option:not([hidden])'); } + + private isSelected_(destinationKey: string): boolean { + return this.selectedValue === destinationKey; + } } declare global {
diff --git a/chrome/browser/resources/print_preview/ui/destination_settings.html b/chrome/browser/resources/print_preview/ui/destination_settings.html deleted file mode 100644 index a03936a..0000000 --- a/chrome/browser/resources/print_preview/ui/destination_settings.html +++ /dev/null
@@ -1,22 +0,0 @@ -<style include="print-preview-shared"> -</style> -<print-preview-destination-select id="destinationSelect" - active-user="[[activeUser_]]" dark="[[dark]]" - destination="[[destination]]" - disabled="[[shouldDisableDropdown_( - destinationState, state, disabled)]]" - loaded="[[loaded_]]" - no-destinations="[[noDestinations_]]" - pdf-printer-disabled="[[pdfPrinterDisabled_]]" - recent-destination-list="[[displayedDestinations_]]" - on-selected-option-change="onSelectedDestinationOptionChange_"> -</print-preview-destination-select> -<cr-lazy-render id="destinationDialog"> - <template> - <print-preview-destination-dialog - destination-store="[[destinationStore_]]" - recent-destination-list="[[recentDestinationList_]]" - on-close="onDialogClose_"> - </print-preview-destination-dialog> - </template> -</cr-lazy-render>
diff --git a/chrome/browser/resources/print_preview/ui/destination_settings.html.ts b/chrome/browser/resources/print_preview/ui/destination_settings.html.ts new file mode 100644 index 0000000..e0e2c305 --- /dev/null +++ b/chrome/browser/resources/print_preview/ui/destination_settings.html.ts
@@ -0,0 +1,31 @@ +// 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. + +import {html} from 'chrome://resources/lit/v3_0/lit.rollup.js'; + +import type {DestinationSettingsElement} from './destination_settings.js'; + +export function getHtml(this: DestinationSettingsElement) { + // clang-format off + return html`<!--_html_template_start_--> +<print-preview-destination-select id="destinationSelect" + ?dark="${this.dark}" + .destination="${this.destination}" + ?disabled="${this.shouldDisableDropdown_()}" + ?loaded="${this.loaded_}" + ?no-destinations="${this.noDestinations_}" + ?pdf-printer-disabled="${this.pdfPrinterDisabled_}" + .recentDestinationList="${this.displayedDestinations_}" + @selected-option-change="${this.onSelectedDestinationOptionChange_}"> +</print-preview-destination-select> +<cr-lazy-render-lit id="destinationDialog" .template="${() => html` + <print-preview-destination-dialog + .destinationStore="${this.destinationStore_}" + @close="${this.onDialogClose_}"> + </print-preview-destination-dialog> +`}"> +</cr-lazy-render-lit> +<!--_html_template_end_-->`; + // clang-format on +}
diff --git a/chrome/browser/resources/print_preview/ui/destination_settings.ts b/chrome/browser/resources/print_preview/ui/destination_settings.ts index b70cb91..18c175ab8 100644 --- a/chrome/browser/resources/print_preview/ui/destination_settings.ts +++ b/chrome/browser/resources/print_preview/ui/destination_settings.ts
@@ -2,34 +2,29 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; -import 'chrome://resources/cr_elements/cr_hidden_style.css.js'; -import 'chrome://resources/cr_elements/cr_shared_vars.css.js'; +import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render_lit.js'; import './destination_dialog.js'; import './destination_select.js'; -import './print_preview_shared.css.js'; -import './print_preview_vars.css.js'; -import './throbber.css.js'; -import './settings_section.js'; import '/strings.m.js'; -import type {CrLazyRenderElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; -import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; -import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js'; +import type {CrLazyRenderLitElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render_lit.js'; +import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js'; +import {WebUiListenerMixinLit} from 'chrome://resources/cr_elements/web_ui_listener_mixin_lit.js'; import {assert} from 'chrome://resources/js/assert.js'; import {EventTracker} from 'chrome://resources/js/event_tracker.js'; -import {beforeNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js'; +import type {PropertyValues} from 'chrome://resources/lit/v3_0/lit.rollup.js'; import type {Destination, RecentDestination} from '../data/destination.js'; import {createRecentDestinationKey, isPdfPrinter, makeRecentDestination, PrinterType} from '../data/destination.js'; - import {DestinationErrorType, DestinationStore, DestinationStoreEventType} from '../data/destination_store.js'; import {Error, State} from '../data/state.js'; import type {PrintPreviewDestinationDialogElement} from './destination_dialog.js'; import type {PrintPreviewDestinationSelectElement} from './destination_select.js'; -import {getTemplate} from './destination_settings.html.js'; -import {SettingsMixin} from './settings_mixin.js'; +import {getHtml} from './destination_settings.html.js'; +import {getCss as getPrintPreviewSharedLitCss} from './print_preview_shared_lit.css.js'; +import {SettingsMixinLit} from './settings_mixin_lit.js'; export enum DestinationState { INIT = 0, @@ -50,13 +45,13 @@ export interface PrintPreviewDestinationSettingsElement { $: { destinationDialog: - CrLazyRenderElement<PrintPreviewDestinationDialogElement>, + CrLazyRenderLitElement<PrintPreviewDestinationDialogElement>, destinationSelect: PrintPreviewDestinationSelectElement, }; } const PrintPreviewDestinationSettingsElementBase = - I18nMixin(WebUiListenerMixin(SettingsMixin(PolymerElement))); + I18nMixinLit(WebUiListenerMixinLit(SettingsMixinLit(CrLitElement))); export class PrintPreviewDestinationSettingsElement extends PrintPreviewDestinationSettingsElementBase { @@ -64,78 +59,61 @@ return 'print-preview-destination-settings'; } - static get template() { - return getTemplate(); + static override get styles() { + return [ + getPrintPreviewSharedLitCss(), + ]; } - static get properties() { + override render() { + return getHtml.bind(this)(); + } + + static override get properties() { return { - dark: Boolean, + dark: {type: Boolean}, destination: { type: Object, notify: true, - value: null, }, destinationState: { type: Number, notify: true, - value: DestinationState.INIT, - observer: 'updateDestinationSelect_', }, - disabled: Boolean, + disabled: {type: Boolean}, error: { type: Number, notify: true, - observer: 'onErrorChanged_', }, - firstLoad: Boolean, - - state: Number, - - destinationStore_: { - type: Object, - value: null, - }, - - displayedDestinations_: Array, - - isDialogOpen_: { - type: Boolean, - value: false, - }, - - noDestinations_: { - type: Boolean, - value: false, - }, - - pdfPrinterDisabled_: Boolean, - - loaded_: { - type: Boolean, - computed: 'computeLoaded_(destinationState, destination)', - }, + firstLoad: {type: Boolean}, + state: {type: Number}, + destinationStore_: {type: Object}, + displayedDestinations_: {type: Array}, + isDialogOpen_: {type: Boolean}, + noDestinations_: {type: Boolean}, + pdfPrinterDisabled_: {type: Boolean}, + loaded_: {type: Boolean}, }; } - declare dark: boolean; - declare destination: Destination; - declare destinationState: DestinationState; - declare disabled: boolean; - declare error: Error; - declare firstLoad: boolean; - declare state: State; - declare private destinationStore_: DestinationStore|null; - declare private displayedDestinations_: Destination[]; - declare private isDialogOpen_: boolean; - declare private noDestinations_: boolean; - declare private pdfPrinterDisabled_: boolean; - declare private loaded_: boolean; + accessor dark: boolean; + accessor destination: Destination|null = null; + accessor destinationState: DestinationState = DestinationState.INIT; + accessor disabled: boolean; + accessor error: Error; + accessor firstLoad: boolean; + accessor state: State; + protected accessor destinationStore_: DestinationStore|null = null; + protected accessor displayedDestinations_: Destination[]; + private accessor isDialogOpen_: boolean = false; + protected accessor noDestinations_: boolean = false; + protected accessor pdfPrinterDisabled_: boolean; + protected accessor loaded_: boolean; private lastUser_: string = ''; private tracker_: EventTracker = new EventTracker(); @@ -172,6 +150,27 @@ this.tracker_.removeAll(); } + override willUpdate(changedProperties: PropertyValues<this>) { + super.willUpdate(changedProperties); + + if (changedProperties.has('error')) { + this.onErrorChanged_(); + } + + if (changedProperties.has('destinationState') || + changedProperties.has('destination')) { + this.loaded_ = this.computeLoaded_(); + } + } + + override updated(changedProperties: PropertyValues<this>) { + super.updated(changedProperties); + + if (changedProperties.has('destinationState')) { + this.updateDestinationSelect_(); + } + } + /** * @param defaultPrinter The system default printer ID. * @param pdfPrinterDisabled Whether the PDF printer is disabled. @@ -233,11 +232,13 @@ this.updateRecentDestinations_(); } - private onDestinationCapabilitiesReady_() { - this.dispatchEvent(new CustomEvent('destination-capabilities-changed', { - bubbles: true, - composed: true, - })); + private async onDestinationCapabilitiesReady_() { + // Wait for any 'destination-changed' events to be fired first. + await this.updateComplete; + + this.fire( + 'destination-capabilities-changed', + this.destinationStore_!.selectedDestination); this.updateRecentDestinations_(); if (this.destinationState === DestinationState.SET) { this.destinationState = DestinationState.UPDATED; @@ -311,12 +312,19 @@ indexFound = NUM_PERSISTED_DESTINATIONS - 1; } + // Create a clone first, otherwise array modifications will not be detected + // by the underlying Observable instance. + const recentDestinationsClone = recentDestinations.slice(); + if (indexFound !== -1) { - this.setSettingSplice('recentDestinations', indexFound, 1, null); + // Remove from the list if it already exists, it will be re-added to the + // front below. + recentDestinationsClone.splice(indexFound, 1); } // Add the most recent destination - this.setSettingSplice('recentDestinations', 0, 0, newDestination); + recentDestinationsClone.splice(0, 0, newDestination); + this.setSetting('recentDestinations', recentDestinationsClone); // The dropdown needs to be updated if a new printer or one not currently // visible in the dropdown has been added. @@ -351,7 +359,7 @@ /** * @return Whether the destinations dropdown should be disabled. */ - private shouldDisableDropdown_(): boolean { + protected shouldDisableDropdown_(): boolean { return this.state === State.FATAL_ERROR || (this.destinationState === DestinationState.UPDATED && this.disabled && this.state !== State.NOT_READY); @@ -369,7 +377,7 @@ * @param e Event containing the key of the recent destination that was * selected, or "seeMore". */ - private onSelectedDestinationOptionChange_(e: CustomEvent<string>) { + protected onSelectedDestinationOptionChange_(e: CustomEvent<string>) { const value = e.detail; if (value === 'seeMore') { this.destinationStore_!.startLoadAllDestinations(); @@ -380,7 +388,7 @@ } } - private onDialogClose_() { + protected onDialogClose_() { // Reset the select value if the user dismissed the dialog without // selecting a new destination. this.updateDestinationSelect_(); @@ -398,12 +406,11 @@ const shouldFocus = this.destinationState !== DestinationState.SET && !this.firstLoad; - beforeNextRender(this.$.destinationSelect, () => { - this.$.destinationSelect.updateDestination(); - if (shouldFocus) { - this.$.destinationSelect.focus(); - } - }); + + this.$.destinationSelect.updateDestination(); + if (shouldFocus) { + this.$.destinationSelect.focus(); + } } getDestinationStoreForTest(): DestinationStore { @@ -412,6 +419,8 @@ } } +export type DestinationSettingsElement = PrintPreviewDestinationSettingsElement; + declare global { interface HTMLElementTagNameMap { 'print-preview-destination-settings':
diff --git a/chrome/browser/resources/print_preview/ui/sidebar.html b/chrome/browser/resources/print_preview/ui/sidebar.html index 3c5bbdf..d9a588f 100644 --- a/chrome/browser/resources/print_preview/ui/sidebar.html +++ b/chrome/browser/resources/print_preview/ui/sidebar.html
@@ -9,7 +9,7 @@ destination-state="${this.destinationState}" @destination-state-changed="${this.onDestinationStateChanged_}" error="${this.error}" @error-changed="${this.onErrorChanged_}" - ?first-load="${this.firstLoad_}" .settings="${this.settings}" + ?first-load="${this.firstLoad_}" .state="${this.state}" ?app-kiosk-mode="${this.isInAppKioskMode_}" ?disabled="${this.controlsDisabled_}" available class="settings-section"
diff --git a/chrome/browser/resources/print_preview/ui/sidebar.ts b/chrome/browser/resources/print_preview/ui/sidebar.ts index 8aa39f1..e5e71e1 100644 --- a/chrome/browser/resources/print_preview/ui/sidebar.ts +++ b/chrome/browser/resources/print_preview/ui/sidebar.ts
@@ -229,10 +229,12 @@ protected onDestinationChanged_(e: CustomEvent<{value: Destination}>) { this.destination = e.detail.value; + this.destinationCapabilities_ = null; } - protected onDestinationCapabilitiesChanged_() { + protected onDestinationCapabilitiesChanged_(e: CustomEvent<Destination>) { assert(this.destination); + assert(e.detail.id === this.destination.id); // When `this.destination.capabilities` changes it is always a new object. this.destinationCapabilities_ = this.destination.capabilities; }
diff --git a/chrome/browser/resources/print_preview/ui/throbber_lit.css b/chrome/browser/resources/print_preview/ui/throbber_lit.css index 14bd379..c05b602c 100644 --- a/chrome/browser/resources/print_preview/ui/throbber_lit.css +++ b/chrome/browser/resources/print_preview/ui/throbber_lit.css
@@ -13,4 +13,3 @@ height: var(--throbber-size); width: var(--throbber-size); } -
diff --git a/chrome/browser/resources/side_panel/customize_chrome/app.html.ts b/chrome/browser/resources/side_panel/customize_chrome/app.html.ts index b3019bb..6504139 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/app.html.ts +++ b/chrome/browser/resources/side_panel/customize_chrome/app.html.ts
@@ -33,14 +33,14 @@ </sp-heading> <cr-icon icon="cr:chevron-right" slot="suffix-icon"></cr-icon> </cr-button> - ${this.isSourceTabFirstPartyNtp_ ? html`<hr class="sp-cards-separator"> + ${this.isSourceTabFirstPartyNtp_() ? html`<hr class="sp-cards-separator"> <div id="shortcuts" class="section sp-card"> <sp-heading hide-back-button> <h2 slot="heading">$i18n{shortcutsHeader}</h2> </sp-heading> <customize-chrome-shortcuts></customize-chrome-shortcuts> </div>`: ''} - ${(this.modulesEnabled_ && this.isSourceTabFirstPartyNtp_) ? html` + ${(this.modulesEnabled_ && this.isSourceTabFirstPartyNtp_()) ? html` <hr class="sp-cards-separator"> <div id="modules" class="section sp-card"> <sp-heading hide-back-button> @@ -77,7 +77,7 @@ </div> </div> ` : ''} - ${this.footerEnabled_ ? html` + ${(this.footerEnabled_ && this.isSourceTabExtension_()) ? html` <hr class="sp-cards-separator"> <div id="footer" class="section sp-card"> <sp-heading hide-back-button>
diff --git a/chrome/browser/resources/side_panel/customize_chrome/app.ts b/chrome/browser/resources/side_panel/customize_chrome/app.ts index ea99b2d..4fbb739a 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/app.ts +++ b/chrome/browser/resources/side_panel/customize_chrome/app.ts
@@ -29,7 +29,7 @@ import type {CategoriesElement} from './categories.js'; import {CustomizeChromeImpression, recordCustomizeChromeImpression} from './common.js'; import type {BackgroundCollection, CustomizeChromePageHandlerInterface} from './customize_chrome.mojom-webui.js'; -import {ChromeWebStoreCategory, ChromeWebStoreCollection, CustomizeChromeSection} from './customize_chrome.mojom-webui.js'; +import {ChromeWebStoreCategory, ChromeWebStoreCollection, CustomizeChromeSection, NewTabPageType} from './customize_chrome.mojom-webui.js'; import {CustomizeChromeApiProxy} from './customize_chrome_api_proxy.js'; import type {ThemesElement} from './themes.js'; @@ -82,7 +82,7 @@ extensionsCardEnabled_: {type: Boolean}, footerEnabled_: {type: Boolean}, wallpaperSearchEnabled_: {type: Boolean}, - isSourceTabFirstPartyNtp_: {type: Boolean}, + newTabPageType_: {type: NewTabPageType}, showEditTheme_: {type: Boolean}, }; } @@ -106,7 +106,8 @@ loadTimeData.getBoolean('footerEnabled'); protected accessor wallpaperSearchEnabled_: boolean = loadTimeData.getBoolean('wallpaperSearchEnabled'); - protected accessor isSourceTabFirstPartyNtp_: boolean = true; + protected accessor newTabPageType_: NewTabPageType = + NewTabPageType.kFirstPartyWebUI; protected accessor showEditTheme_: boolean = true; private scrollToSectionListenerId_: number|null = null; private attachedTabStateUpdatedId_: number|null = null; @@ -142,17 +143,16 @@ this.attachedTabStateUpdatedId_ = CustomizeChromeApiProxy.getInstance() .callbackRouter.attachedTabStateUpdated.addListener( - (isSourceTabFirstPartyNtp: boolean) => { - if (this.isSourceTabFirstPartyNtp_ === - isSourceTabFirstPartyNtp) { + (newTabPageType: NewTabPageType) => { + if (this.newTabPageType_ === newTabPageType) { return; } - this.isSourceTabFirstPartyNtp_ = isSourceTabFirstPartyNtp; + this.newTabPageType_ = newTabPageType; // Since some pages aren't supported in non first party mode, // change the section back to the overview. - if (!this.isSourceTabFirstPartyNtp_ && + if (!this.isSourceTabFirstPartyNtp_() && !this.pageSupportedOnNonFirstPartyNtps()) { this.page_ = CustomizeChromePage.OVERVIEW; } @@ -207,6 +207,14 @@ this.setThemeEditableId_); } + protected isSourceTabFirstPartyNtp_(): boolean { + return this.newTabPageType_ === NewTabPageType.kFirstPartyWebUI; + } + + protected isSourceTabExtension_(): boolean { + return this.newTabPageType_ === NewTabPageType.kExtension; + } + protected async onBackClick_() { switch (this.page_) { case CustomizeChromePage.CATEGORIES:
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts index d2f4dd3..8e91616 100644 --- a/chrome/browser/resources/side_panel/read_anything/app.ts +++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -35,7 +35,7 @@ import type {ReadAnythingToolbarElement} from './read_anything_toolbar.js'; import type {SpeechBrowserProxy} from './speech_browser_proxy.js'; import {SpeechBrowserProxyImpl} from './speech_browser_proxy.js'; -import {areVoicesEqual, AVAILABLE_GOOGLE_TTS_LOCALES, convertLangOrLocaleForVoicePackManager, convertLangOrLocaleToExactVoicePackLocale, convertLangToAnAvailableLangIfPresent, doesLanguageHaveNaturalVoices, getNaturalVoiceOrDefault, getVoicePackConvertedLangIfExists, isNatural, isVoicePackStatusError, isVoicePackStatusSuccess, mojoVoicePackStatusToVoicePackStatusEnum, VoiceClientSideStatusCode, VoicePackServerStatusErrorCode, VoicePackServerStatusSuccessCode} from './voice_language_util.js'; +import {AVAILABLE_GOOGLE_TTS_LOCALES, convertLangOrLocaleForVoicePackManager, convertLangOrLocaleToExactVoicePackLocale, convertLangToAnAvailableLangIfPresent, doesLanguageHaveNaturalVoices, getVoicePackConvertedLangIfExists, isNatural, isVoicePackStatusError, isVoicePackStatusSuccess, mojoVoicePackStatusToVoicePackStatusEnum, VoiceClientSideStatusCode, VoicePackServerStatusErrorCode, VoicePackServerStatusSuccessCode} from './voice_language_util.js'; import type {VoicePackStatus} from './voice_language_util.js'; import {VoiceNotificationManager} from './voice_notification_manager.js'; @@ -125,7 +125,7 @@ // request the install. private waitingForNewEngine_ = false; - protected accessor selectedVoice_: SpeechSynthesisVoice|undefined; + protected accessor selectedVoice_: SpeechSynthesisVoice|null = null; // The set of languages currently enabled for use by Read Aloud. This // includes user-enabled languages and auto-downloaded languages. The former // are stored in preferences. The latter are not. @@ -935,129 +935,16 @@ // If we go from having no available voices to having voices available, // restore voice settings from preferences. this.restoreEnabledLanguagesFromPref(); - this.selectPreferredVoice(); + this.selectUserPreferredVoice(); } // If voice was selected automatically and not by the user, check if // there's a higher quality voice available now. - if (!this.currentVoiceIsUserChosen_()) { - const naturalVoicesForLang = - this.voicePackController_.getAvailableVoices().filter( - voice => isNatural(voice) && - voice.lang.startsWith( - chrome.readingMode.baseLanguageForSpeech)); - - if (naturalVoicesForLang) { - this.selectedVoice_ = naturalVoicesForLang[0]; - this.resetSpeechPostSettingChange_(); - } - } - - // Now that the voice list has changed, refresh the VoicePackStatuses in - // case a language has been uninstalled. - this.voicePackController_.refreshVoicePackStatuses(); + this.voicePackController_.updateAutoSelectedVoiceToNaturalVoice(); // If the selected voice is now unavailable, such as after an uninstall, // reselect a new voice. - if (this.selectedVoice_ && - !this.voicePackController_.isVoiceAvailable(this.selectedVoice_)) { - this.selectedVoice_ = undefined; - } - - if (!this.selectedVoice_) { - this.getSpeechSynthesisVoice(); - } - } - - getSpeechSynthesisVoice(): SpeechSynthesisVoice|undefined { - if (!this.selectedVoice_) { - this.selectedVoice_ = this.defaultVoice(); - } - return this.selectedVoice_; - } - - defaultVoice(): SpeechSynthesisVoice|undefined { - const baseLang = this.voicePackController_.getCurrentLanguage(); - const allPossibleVoices = this.getVoices_(); - const voicesForLanguage = - allPossibleVoices.filter(voice => voice.lang.startsWith(baseLang)); - - if (!voicesForLanguage || (voicesForLanguage.length === 0)) { - // Stay with the current voice if no voices are available for this - // language. - return this.selectedVoice_ ? this.selectedVoice_ : - getNaturalVoiceOrDefault(allPossibleVoices); - } - - // First try to choose a voice only from currently enabled locales for this - // language. - const voicesForCurrentEnabledLocale = voicesForLanguage.filter( - v => this.voicePackController_.isLangEnabled(v.lang)); - if (!voicesForCurrentEnabledLocale || - !voicesForCurrentEnabledLocale.length) { - // If there's no enabled locales for this language, check for any other - // voices for enabled locales. - const allVoicesForEnabledLocales = allPossibleVoices.filter( - v => this.voicePackController_.isLangEnabled(v.lang)); - if (!allVoicesForEnabledLocales.length) { - // If there are no voices for the enabled locales, or no enabled - // locales at all, we can't select a voice. So return undefined so we - // can disable the play button. - return undefined; - } else { - return getNaturalVoiceOrDefault(allVoicesForEnabledLocales); - } - } - - return getNaturalVoiceOrDefault(voicesForCurrentEnabledLocale); - } - - // Attempt to get a new voice using the current language. In theory, the - // previously unavailable voice should no longer be showing up in - // getVoices, but we ensure that the alternative voice does not match - // the previously unavailable voice as an extra measure. This method should - // only be called when speech synthesis returns an error. - getAlternativeVoice(unavailableVoice: SpeechSynthesisVoice|undefined): - SpeechSynthesisVoice|undefined { - const newVoice = this.defaultVoice(); - - // If the default voice is not the same as the original, unavailable voice, - // use that, only if the new voice is also defined. - if (newVoice !== undefined && !areVoicesEqual(newVoice, unavailableVoice)) { - return newVoice; - } - - // If the default voice won't work, try another voice in that language. - const baseLang = this.voicePackController_.getCurrentLanguage(); - const voicesForLanguage = - this.getVoices_().filter(voice => voice.lang.startsWith(baseLang)); - - // TODO: crbug.com/40927698 - It's possible we can get stuck in an infinite - // loop of jumping back and forth between two or more invalid voices, if - // multiple voices are invalid. Investigate if we need to do more to handle - // this case. - - // TODO: crbug.com/336596926 - If there still aren't voices for the - // language, attempt to fallback to the browser language, if we're using - // the page language. - if (!voicesForLanguage || (voicesForLanguage.length === 0)) { - return undefined; - } - - let voiceIndex = 0; - while (voiceIndex < voicesForLanguage.length) { - if (!areVoicesEqual(voicesForLanguage[voiceIndex], unavailableVoice)) { - // Return another voice in the same language, ensuring we're not - // returning the previously unavailable voice for extra safety. - return voicesForLanguage[voiceIndex]; - } - voiceIndex++; - } - - // TODO: crbug.com/336596926 - Handle language updates if there aren't any - // available voices in the current language other than the unavailable - // voice. - return undefined; + this.voicePackController_.updateUnavailableVoiceToDefaultVoice(); } private getVoices_(forceRefresh: boolean = false): SpeechSynthesisVoice[] { @@ -1133,6 +1020,11 @@ this.voicePackController_.getDisplayNamesForLocaleCodes(); } + onCurrentVoiceChange(): void { + this.selectedVoice_ = this.voicePackController_.getCurrentVoice(); + this.resetSpeechPostSettingChange_(); + } + private logSpeechPlaySession_() { // Don't log a playback session just in case something has gotten out of // sync and we call stopSpeech before playSpeech. @@ -1440,8 +1332,7 @@ chrome.readingMode.getCurrentTextStartIndex(this.lastReadingId_); } this.highlighter_.highlightCurrentGranularity( - axNodeIds, scrollIntoView, shouldUpdateSentenceHighlight, - this.selectedVoice_); + axNodeIds, scrollIntoView, shouldUpdateSentenceHighlight); } // Gets the accessible text boundary for the given string. @@ -1535,7 +1426,7 @@ } }; - const voice = this.getSpeechSynthesisVoice(); + const voice = this.voicePackController_.getCurrentVoiceOrDefault(); if (!voice) { // TODO: crbug.com/40927698 - Handle when no voices are available. return; @@ -1589,6 +1480,13 @@ return; } + // When we hit an error, stop speech to clear all utterances, update the + // button state, and highlighting in order to give visual feedback that + // something went wrong. + // TODO: crbug.com/40927698 - Consider showing an error message. + this.logger_.logSpeechStopSource(chrome.readingMode.engineErrorStopSource); + this.speechController_.stopSpeech(PauseActionSource.DEFAULT); + // No appropriate voice is available for the language designated in // SpeechSynthesisUtterance lang. if (error.error === 'language-unavailable') { @@ -1598,21 +1496,8 @@ // The voice designated in SpeechSynthesisUtterance voice attribute // is not available. if (error.error === 'voice-unavailable') { - let newVoice = this.selectedVoice_ ? this.selectedVoice_ : undefined; - this.selectedVoice_ = undefined; - newVoice = this.getAlternativeVoice(newVoice); - - if (newVoice) { - this.selectedVoice_ = newVoice; - } + this.voicePackController_.onVoiceUnavailableError(); } - - // When we hit an error, stop speech to clear all utterances, update the - // button state, and highlighting in order to give visual feedback that - // something went wrong. - // TODO: crbug.com/40927698 - Consider showing an error message. - this.logger_.logSpeechStopSource(chrome.readingMode.engineErrorStopSource); - this.speechController_.stopSpeech(PauseActionSource.DEFAULT); } private extractTextOf(axNodeIds: number[]): string { @@ -1657,25 +1542,17 @@ event.preventDefault(); event.stopPropagation(); - let localesAreIdentical = false; - if (this.selectedVoice_) { - localesAreIdentical = this.selectedVoice_.lang.toLowerCase() === - event.detail.selectedVoice.lang.toLowerCase(); - } - - this.selectedVoice_ = event.detail.selectedVoice; - chrome.readingMode.onVoiceChange( - this.selectedVoice_.name, this.selectedVoice_.lang); + const currentVoice = this.voicePackController_.getCurrentVoice(); + this.voicePackController_.setUserPreferredVoice(event.detail.selectedVoice); // If the locales are identical, the voices are likely from the same // voice pack and use the same TTS engine, therefore, we don't need // to reset the word boundary state. - if (!localesAreIdentical) { + if (currentVoice?.lang.toLowerCase() !== + event.detail.selectedVoice.lang.toLowerCase()) { this.wordBoundaries_.resetToDefaultState( /*possibleWordBoundarySupportChange=*/ true); } - - this.resetSpeechPostSettingChange_(); } protected onVoiceLanguageToggle_(event: CustomEvent<{language: string}>) { @@ -1701,7 +1578,7 @@ if (!currentlyEnabled && !this.selectedVoice_) { // If there were no enabled languages (and thus no selected voice), // select a voice. - this.getSpeechSynthesisVoice(); + this.voicePackController_.getCurrentVoiceOrDefault(); } } @@ -1730,7 +1607,7 @@ // We need to restore enabled languages prior to selecting the preferred // voice to ensure we have the right voices available. this.restoreEnabledLanguagesFromPref(); - this.selectPreferredVoice(); + this.selectUserPreferredVoice(); } this.settingsPrefs_ = { ...this.settingsPrefs_, @@ -1748,8 +1625,7 @@ } restoreEnabledLanguagesFromPref() { - this.voicePackController_.restoreEnabledLanguagesFromPref( - this.defaultVoice()?.lang); + this.voicePackController_.restoreEnabledLanguagesFromPref(); for (const lang of this.voicePackController_.getEnabledLangs()) { this.installVoicePackIfPossible( @@ -1758,20 +1634,7 @@ } } - private currentVoiceIsUserChosen_(): boolean { - const storedVoiceName = chrome.readingMode.getStoredVoice(); - - // `this.selectedVoice` is not necessarily chosen by the user, it is just - // the voice that read aloud is using. It may be a default voice chosen by - // read aloud, so we check it against user preferences to see if it was - // user-chosen. - if (storedVoiceName) { - return this.selectedVoice_?.name === storedVoiceName; - } - return false; - } - - selectPreferredVoice() { + selectUserPreferredVoice() { // TODO: crbug.com/40275871 - decide whether this is the behavior we want. // This shouldn't happen often, so just skip selecting a new voice for now. // Another option would be to update the voice and the call @@ -1780,20 +1643,7 @@ return; } - const storedVoiceName = chrome.readingMode.getStoredVoice(); - if (!storedVoiceName) { - this.selectedVoice_ = this.defaultVoice(); - return; - } - - const selectedVoice = - this.getVoices_().filter(voice => voice.name === storedVoiceName); - this.selectedVoice_ = selectedVoice && (selectedVoice.length > 0) ? - selectedVoice[0] : - this.defaultVoice(); - - // Enable the locale for the preferred voice for this language. - this.voicePackController_.enableLang(this.selectedVoice_?.lang); + this.voicePackController_.setUserPreferredVoiceFromPrefs(); } protected onLineSpacingChange_() { @@ -1893,7 +1743,7 @@ if (!availableLang || (speechSynthesisBaseLang && !availableLang.startsWith(speechSynthesisBaseLang))) { - this.selectPreferredVoice(); + this.selectUserPreferredVoice(); return; } @@ -1916,7 +1766,7 @@ // Enable the locales so we can select a voice for the given language and // show it in the voice menu. this.voicePackController_.enableLang(localeToEnable); - this.selectPreferredVoice(); + this.selectUserPreferredVoice(); } // Kicks off a workflow to install a voice pack. @@ -1966,10 +1816,6 @@ this.onPlayPauseClick_(); } } - - resetVoiceForTesting() { - this.selectedVoice_ = undefined; - } } declare global {
diff --git a/chrome/browser/resources/side_panel/read_anything/read_aloud/highlighter.ts b/chrome/browser/resources/side_panel/read_anything/read_aloud/highlighter.ts index 3514ed8..d69ed38 100644 --- a/chrome/browser/resources/side_panel/read_anything/read_aloud/highlighter.ts +++ b/chrome/browser/resources/side_panel/read_anything/read_aloud/highlighter.ts
@@ -8,6 +8,7 @@ import {NodeStore} from '../node_store.js'; import {isEspeak} from '../voice_language_util.js'; +import {VoicePackController} from './voice_pack_controller.js'; import {WordBoundaries} from './word_boundaries.js'; // Characters that should be ignored for word highlighting when not accompanied @@ -30,6 +31,7 @@ private wordBoundaries_: WordBoundaries; private nodeStore_: NodeStore; private allowAutoScroll_ = true; + private voicePackController_ = VoicePackController.getInstance(); constructor() { this.wordBoundaries_ = WordBoundaries.getInstance(); @@ -65,10 +67,8 @@ highlightCurrentGranularity( axNodeIds: number[], scrollIntoView: boolean, - shouldUpdateSentenceHighlight: boolean, - selectedVoice?: SpeechSynthesisVoice): void { - const highlightGranularity = - this.getEffectiveHighlightingGranularity_(selectedVoice); + shouldUpdateSentenceHighlight: boolean): void { + const highlightGranularity = this.getEffectiveHighlightingGranularity_(); switch (highlightGranularity) { case chrome.readingMode.noHighlighting: // Even without highlighting, we may still need to calculate the sentence @@ -135,8 +135,9 @@ isInvalidHighlightForWordHighlighting(textToHighlight?: string): boolean { // If a highlight is just white space or punctuation, we can skip // highlighting. - return !textToHighlight || textToHighlight === '' || - IGNORED_HIGHLIGHT_CHARACTERS_REGEX.test(textToHighlight); + const text = textToHighlight?.trim(); + return !text || text === '' || + IGNORED_HIGHLIGHT_CHARACTERS_REGEX.test(text); } private getCurrentHighlightBounds_(): DOMRect { @@ -177,8 +178,7 @@ return ancestor; } - private getEffectiveHighlightingGranularity_( - selectedVoice?: SpeechSynthesisVoice): number { + private getEffectiveHighlightingGranularity_(): number { // Parse all of the conditions that control highlighting and return the // effective highlighting granularity. const highlight = chrome.readingMode.highlightGranularity; @@ -188,7 +188,8 @@ return highlight; } - if (this.wordBoundaries_.notSupported() || isEspeak(selectedVoice)) { + if (this.wordBoundaries_.notSupported() || + isEspeak(this.voicePackController_.getCurrentVoice())) { // Fall back where word highlighting is not possible. Since espeak // boundaries are different than Google TTS word boundaries, fall back // to sentence boundaries in that case too. @@ -231,7 +232,8 @@ const wordBoundaryState = this.wordBoundaries_.state; const index = wordBoundaryState.speechUtteranceStartIndex + wordBoundaryState.previouslySpokenIndex; - const length = wordBoundaryState.speechUtteranceLength; + const speechUtteranceLength = wordBoundaryState.speechUtteranceLength; + let alreadyHighlightedSpeechUtteranceLength = 0; const highlightNodes = chrome.readingMode.getHighlightForCurrentSegmentIndex( @@ -239,7 +241,11 @@ let hasHighlights = false; for (const highlightNode of highlightNodes) { const nodeId = highlightNode.nodeId; - const highlightLength: number = length ? length : highlightNode.length; + const remainingSpeechUtteranceLength = Math.max( + speechUtteranceLength - alreadyHighlightedSpeechUtteranceLength, 0); + const highlightLength: number = speechUtteranceLength ? + (remainingSpeechUtteranceLength) : + highlightNode.length; const highlightStartIndex = highlightNode.start; const endIndex = highlightStartIndex + highlightLength; const node = this.nodeStore_.getDomNode(nodeId); @@ -253,6 +259,10 @@ continue; } + // Keep track of the highlight length that's been spoken so that + // speechUtteranceLength can be used across multiple nodes. + alreadyHighlightedSpeechUtteranceLength += highlightLength; + hasHighlights = true; const element = node as HTMLElement; const highlighted =
diff --git a/chrome/browser/resources/side_panel/read_anything/read_aloud/voice_pack_controller.ts b/chrome/browser/resources/side_panel/read_anything/read_aloud/voice_pack_controller.ts index a16a2e7..f84351b 100644 --- a/chrome/browser/resources/side_panel/read_anything/read_aloud/voice_pack_controller.ts +++ b/chrome/browser/resources/side_panel/read_anything/read_aloud/voice_pack_controller.ts
@@ -11,7 +11,7 @@ import type {SpeechBrowserProxy} from '../speech_browser_proxy.js'; import {SpeechBrowserProxyImpl} from '../speech_browser_proxy.js'; import type {VoicePackStatus} from '../voice_language_util.js'; -import {areVoicesEqual, AVAILABLE_GOOGLE_TTS_LOCALES, convertLangOrLocaleForVoicePackManager, convertLangToAnAvailableLangIfPresent, createInitialListOfEnabledLanguages, EXTENSION_RESPONSE_TIMEOUT_MS, getFilteredVoiceList, getVoicePackConvertedLangIfExists, isVoicePackStatusError, isVoicePackStatusSuccess, VoiceClientSideStatusCode, VoicePackServerStatusSuccessCode} from '../voice_language_util.js'; +import {areVoicesEqual, AVAILABLE_GOOGLE_TTS_LOCALES, convertLangOrLocaleForVoicePackManager, convertLangToAnAvailableLangIfPresent, createInitialListOfEnabledLanguages, EXTENSION_RESPONSE_TIMEOUT_MS, getFilteredVoiceList, getNaturalVoiceOrDefault, getVoicePackConvertedLangIfExists, isNatural, isVoicePackStatusError, isVoicePackStatusSuccess, VoiceClientSideStatusCode, VoicePackServerStatusSuccessCode} from '../voice_language_util.js'; import {VoiceNotificationManager} from '../voice_notification_manager.js'; import {VoicePackModel} from './voice_pack_model.js'; @@ -19,6 +19,7 @@ export interface VoiceLanguageListener { onEnabledLangsChange(): void; onAvailableVoicesChange(): void; + onCurrentVoiceChange(): void; } export class VoicePackController { @@ -46,6 +47,17 @@ this.model_.setCurrentLanguage(language); } + getCurrentVoice(): SpeechSynthesisVoice|null { + return this.model_.getCurrentVoice(); + } + + setCurrentVoice(voice: SpeechSynthesisVoice|null): void { + if (!areVoicesEqual(voice, this.getCurrentVoice())) { + this.model_.setCurrentVoice(voice); + this.listeners_.forEach(l => l.onCurrentVoiceChange()); + } + } + getEnabledLangs(): string[] { return [...this.model_.getEnabledLangs()]; } @@ -72,6 +84,66 @@ availableVoice => areVoicesEqual(availableVoice, voice)); } + setUserPreferredVoice(selectedVoice: SpeechSynthesisVoice): void { + this.setCurrentVoice(selectedVoice); + chrome.readingMode.onVoiceChange(selectedVoice.name, selectedVoice.lang); + } + + setUserPreferredVoiceFromPrefs(): void { + const storedVoiceName = chrome.readingMode.getStoredVoice(); + if (!storedVoiceName) { + this.setCurrentVoice(this.getDefaultVoice_()); + return; + } + + this.refreshAvailableVoices(); + const selectedVoice = this.getAvailableVoices().filter( + voice => voice.name === storedVoiceName); + const newVoice = (selectedVoice.length && selectedVoice[0]) ? + selectedVoice[0] : + this.getDefaultVoice_(); + this.setCurrentVoice(newVoice); + + // Enable the locale for the preferred voice for this language. + this.enableLang(this.getCurrentVoice()?.lang); + } + + updateAutoSelectedVoiceToNaturalVoice(): void { + if (this.currentVoiceIsUserChosen_()) { + return; + } + + const naturalVoicesForLang = this.getAvailableVoices().filter( + voice => isNatural(voice) && + voice.lang.startsWith(this.getCurrentLanguage())); + if (!naturalVoicesForLang.length || !naturalVoicesForLang[0]) { + return; + } + + this.setCurrentVoice(naturalVoicesForLang[0]); + } + + // Checks the voice pack status of the current voice and updates to the + // default voice if it's no longer available. + updateUnavailableVoiceToDefaultVoice(): void { + for (const lang of this.model_.getServerLanguages()) { + this.requestInfo_(lang); + } + const currentVoice = this.getCurrentVoice(); + if (currentVoice && !this.isVoiceAvailable(currentVoice)) { + this.setCurrentVoice(this.getDefaultVoice_()); + } + } + + getCurrentVoiceOrDefault(): SpeechSynthesisVoice|null { + const currentVoice = this.getCurrentVoice(); + if (!currentVoice) { + this.setCurrentVoice(this.getDefaultVoice_()); + } + + return this.getCurrentVoice(); + } + onLanguageUnavailableError(): void { const possibleNewLanguage = convertLangToAnAvailableLangIfPresent( this.getCurrentLanguage(), this.getAvailableLangs(), @@ -81,6 +153,53 @@ } } + // Attempt to get a new voice using the current language. In theory, the + // previously unavailable voice should no longer be showing up in + // availableVoices, but we ensure that the alternative voice does not match + // the previously unavailable voice as an extra measure. This method should + // only be called when speech synthesis returns an error. + onVoiceUnavailableError(): void { + const currentVoice = this.getCurrentVoice(); + const newVoice = this.getDefaultVoice_(); + + // If the default voice is not the same as the original, unavailable voice, + // use that, only if the new voice is also defined. + if (newVoice && !areVoicesEqual(newVoice, currentVoice)) { + this.setCurrentVoice(newVoice); + return; + } + + // If the default voice won't work, try another voice in that language. + const baseLang = this.getCurrentLanguage(); + this.refreshAvailableVoices(); + const voicesForLanguage = this.getAvailableVoices().filter( + voice => voice.lang.startsWith(baseLang)); + + // TODO: crbug.com/40927698 - It's possible we can get stuck in an infinite + // loop of jumping back and forth between two or more invalid voices, if + // multiple voices are invalid. Investigate if we need to do more to handle + // this case. + + // TODO: crbug.com/336596926 - If there still aren't voices for the + // language, attempt to fallback to the browser language, if we're using + // the page language. + let voiceIndex = 0; + while (voiceIndex < voicesForLanguage.length) { + if (!areVoicesEqual(voicesForLanguage[voiceIndex], currentVoice)) { + // Return another voice in the same language, ensuring we're not + // returning the previously unavailable voice for extra safety. + this.setCurrentVoice(voicesForLanguage[voiceIndex] || null); + return; + } + voiceIndex++; + } + + // TODO: crbug.com/336596926 - Handle language updates if there aren't any + // available voices in the current language other than the unavailable + // voice. + this.setCurrentVoice(null); + } + disableLangIfNoVoices(lang: string): void { const lowerLang = lang.toLowerCase(); this.refreshAvailableVoices(); @@ -151,12 +270,13 @@ } // </if> - restoreEnabledLanguagesFromPref(langOfDefaultVoice?: string): void { + restoreEnabledLanguagesFromPref(): void { // We need to make sure the languages we choose correspond to voices, so // refresh the list of voices and available langs this.refreshAvailableVoices(); this.setCurrentLanguage(chrome.readingMode.baseLanguageForSpeech); const storedLanguagesPref = chrome.readingMode.getLanguagesEnabledInPref(); + const langOfDefaultVoice = this.getDefaultVoice_()?.lang; const langs = createInitialListOfEnabledLanguages( chrome.readingMode.baseLanguageForSpeech, storedLanguagesPref, this.getAvailableLangs(), langOfDefaultVoice); @@ -220,12 +340,6 @@ } } - refreshVoicePackStatuses() { - for (const lang of this.model_.getServerLanguages()) { - this.requestInfo_(lang); - } - } - triggerInstall(voicePackLanguage: string) { // Install the voice if it's not currently installed and it's marked // as a language that should be installed @@ -365,6 +479,55 @@ v => getVoicePackConvertedLangIfExists(v.lang) === lang); } + private currentVoiceIsUserChosen_(): boolean { + const storedVoiceName = chrome.readingMode.getStoredVoice(); + + // getCurrentVoice() is not necessarily chosen by the user, it is just + // the voice that read aloud is using. It may be a default voice chosen by + // read aloud, so we check it against user preferences to see if it was + // user-chosen. + if (storedVoiceName) { + return this.getCurrentVoice()?.name === storedVoiceName; + } + return false; + } + + private getDefaultVoice_(): SpeechSynthesisVoice|null { + this.refreshAvailableVoices(); + const allPossibleVoices = this.getAvailableVoices(); + const voicesForLanguage = allPossibleVoices.filter( + voice => voice.lang.startsWith(this.getCurrentLanguage())); + + if (!voicesForLanguage.length) { + // Stay with the current voice if no voices are available for this + // language. + return this.getCurrentVoice() ? + this.getCurrentVoice() : + getNaturalVoiceOrDefault(allPossibleVoices); + } + + // First try to choose a voice only from currently enabled locales for this + // language. + const voicesForCurrentEnabledLocale = + voicesForLanguage.filter(v => this.isLangEnabled(v.lang)); + if (!voicesForCurrentEnabledLocale.length) { + // If there's no enabled locales for this language, check for any other + // voices for enabled locales. + const allVoicesForEnabledLocales = + allPossibleVoices.filter(v => this.isLangEnabled(v.lang)); + if (!allVoicesForEnabledLocales.length) { + // If there are no voices for the enabled locales, or no enabled + // locales at all, we can't select a voice. So return null so we + // can disable the play button. + return null; + } else { + return getNaturalVoiceOrDefault(allVoicesForEnabledLocales); + } + } + + return getNaturalVoiceOrDefault(voicesForCurrentEnabledLocale); + } + static getInstance(): VoicePackController { return instance || (instance = new VoicePackController()); }
diff --git a/chrome/browser/resources/side_panel/read_anything/read_aloud/voice_pack_model.ts b/chrome/browser/resources/side_panel/read_anything/read_aloud/voice_pack_model.ts index c2f6656..6dca8c69 100644 --- a/chrome/browser/resources/side_panel/read_anything/read_aloud/voice_pack_model.ts +++ b/chrome/browser/resources/side_panel/read_anything/read_aloud/voice_pack_model.ts
@@ -41,6 +41,7 @@ // need to download Natural voices for automatically private languagesForVoiceDownloads_: Set<string> = new Set(); + private currentVoice_: SpeechSynthesisVoice|null = null; private currentLanguage_: string = ''; addLanguageForDownload(lang: string): void { @@ -119,6 +120,14 @@ return Array.from(this.voicePackInstallStatusServerResponses_.keys()); } + getCurrentVoice(): SpeechSynthesisVoice|null { + return this.currentVoice_ || null; + } + + setCurrentVoice(voice: SpeechSynthesisVoice|null): void { + this.currentVoice_ = voice; + } + getCurrentLanguage(): string { return this.currentLanguage_; }
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything_logger.ts b/chrome/browser/resources/side_panel/read_anything/read_anything_logger.ts index ea433357..9b13e16 100644 --- a/chrome/browser/resources/side_panel/read_anything/read_anything_logger.ts +++ b/chrome/browser/resources/side_panel/read_anything/read_anything_logger.ts
@@ -85,7 +85,7 @@ this.metrics.recordHighlightGranularity(highlight); } - private logVoiceTypeUsedForReading_(voice: SpeechSynthesisVoice|undefined) { + private logVoiceTypeUsedForReading_(voice: SpeechSynthesisVoice|null) { if (!voice) { return; } @@ -136,8 +136,7 @@ this.metrics.recordVoiceSpeed(index); } - logSpeechPlaySession( - startTime: number, voice: SpeechSynthesisVoice|undefined) { + logSpeechPlaySession(startTime: number, voice: SpeechSynthesisVoice|null) { this.logVoiceTypeUsedForReading_(voice); this.logLanguageUsedForReading_(voice?.lang); this.metrics.recordSpeechPlaybackLength(Date.now() - startTime);
diff --git a/chrome/browser/resources/side_panel/read_anything/voice_language_util.ts b/chrome/browser/resources/side_panel/read_anything/voice_language_util.ts index c5cc22d..216f55e 100644 --- a/chrome/browser/resources/side_panel/read_anything/voice_language_util.ts +++ b/chrome/browser/resources/side_panel/read_anything/voice_language_util.ts
@@ -156,7 +156,7 @@ return voice.name.includes(NATURAL_STRING_IDENTIFIER); } -export function isEspeak(voice: SpeechSynthesisVoice|undefined) { +export function isEspeak(voice?: SpeechSynthesisVoice|null) { return voice && voice.name.includes(ESPEAK_STRING_IDENTIFIER); } @@ -165,9 +165,9 @@ } export function getNaturalVoiceOrDefault(voices: SpeechSynthesisVoice[]): - SpeechSynthesisVoice|undefined { + SpeechSynthesisVoice|null { if (voices.length === 0) { - return undefined; + return null; } const naturalVoice = voices.find(v => isNatural(v)); @@ -177,7 +177,7 @@ const defaultVoice = voices.find(({default: isDefaultVoice}) => isDefaultVoice); - return defaultVoice ? defaultVoice : voices[0]; + return defaultVoice ? defaultVoice : (voices[0] || null); } export function getNotification(
diff --git a/chrome/browser/selection/android/java/src/org/chromium/chrome/browser/selection/SelectionPopupBackPressHandler.java b/chrome/browser/selection/android/java/src/org/chromium/chrome/browser/selection/SelectionPopupBackPressHandler.java index 8ba1e12..a0cc0868 100644 --- a/chrome/browser/selection/android/java/src/org/chromium/chrome/browser/selection/SelectionPopupBackPressHandler.java +++ b/chrome/browser/selection/android/java/src/org/chromium/chrome/browser/selection/SelectionPopupBackPressHandler.java
@@ -52,6 +52,14 @@ } @Override + public boolean invokeBackActionOnEscape() { + // For Escape key presses, we do not want to clear selection, which matches with Desktop. We + // do not also implement a custom {@link BackPressHandler#handleEscPress()} since we don't + // want anything to happen and for the manager to move to the next priority handler. + return false; + } + + @Override public ObservableSupplier<Boolean> getHandleBackPressChangedSupplier() { return mBackPressChangedSupplier; }
diff --git a/chrome/browser/sharesheet/sharesheet_test_util.h b/chrome/browser/sharesheet/sharesheet_test_util.h index aa6c8468..62d018c80a 100644 --- a/chrome/browser/sharesheet/sharesheet_test_util.h +++ b/chrome/browser/sharesheet/sharesheet_test_util.h
@@ -13,13 +13,13 @@ namespace sharesheet { -const char kTestText[] = "text"; -const char kTestTitle[] = "title"; -const char kTestUrl[] = "https://fake-url.com/fake"; -const char kTestTextFile[] = "path/to/text.txt"; -const char kTestPdfFile[] = "path/to/file.pdf"; -const char kMimeTypeText[] = "text/plain"; -const char kMimeTypePdf[] = "application/pdf"; +inline constexpr char kTestText[] = "text"; +inline constexpr char kTestTitle[] = "title"; +inline constexpr char kTestUrl[] = "https://fake-url.com/fake"; +inline constexpr char kTestTextFile[] = "path/to/text.txt"; +inline constexpr char kTestPdfFile[] = "path/to/file.pdf"; +inline constexpr char kMimeTypeText[] = "text/plain"; +inline constexpr char kMimeTypePdf[] = "application/pdf"; apps::IntentPtr CreateValidTextIntent();
diff --git a/chrome/browser/signin/e2e_tests/signin_util.h b/chrome/browser/signin/e2e_tests/signin_util.h index dae19ae3..49013e7a 100644 --- a/chrome/browser/signin/e2e_tests/signin_util.h +++ b/chrome/browser/signin/e2e_tests/signin_util.h
@@ -23,7 +23,7 @@ // A wrapper importing the settings module when the chrome://settings serve the // Polymer 3 version. -const char kSettingsScriptWrapperFormat[] = +inline constexpr char kSettingsScriptWrapperFormat[] = "import('./settings.js').then(settings => {%s});"; signin::IdentityManager* identity_manager(Browser* browser);
diff --git a/chrome/browser/site_isolation/about_flags.h b/chrome/browser/site_isolation/about_flags.h index 862fc54..6c0b8bd 100644 --- a/chrome/browser/site_isolation/about_flags.h +++ b/chrome/browser/site_isolation/about_flags.h
@@ -11,7 +11,7 @@ namespace about_flags { -constexpr char kSiteIsolationTrialOptOutInternalName[] = +inline constexpr char kSiteIsolationTrialOptOutInternalName[] = "site-isolation-trial-opt-out"; inline std::string SiteIsolationTrialOptOutChoiceEnabled() {
diff --git a/chrome/browser/speech/on_device_speech_recognition_impl.cc b/chrome/browser/speech/on_device_speech_recognition_impl.cc index 8096216b..e7a6511 100644 --- a/chrome/browser/speech/on_device_speech_recognition_impl.cc +++ b/chrome/browser/speech/on_device_speech_recognition_impl.cc
@@ -4,7 +4,10 @@ #include "chrome/browser/speech/on_device_speech_recognition_impl.h" +#include "base/rand_util.h" #include "base/strings/string_util.h" +#include "base/task/task_runner.h" +#include "base/time/time.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/profiles/profile.h" @@ -42,6 +45,17 @@ language_code); } +bool IsLanguageInstalled(const std::string& language_code) { + for (const auto& language : g_browser_process->local_state()->GetList( + prefs::kSodaRegisteredLanguagePacks)) { + if (language.GetString() == language_code) { + return true; + } + } + + return false; +} + } // namespace #endif // !BUILDFLAG(IS_ANDROID) @@ -76,15 +90,7 @@ return; } - media::mojom::AvailabilityStatus availability_status = - IsOnDeviceSpeechRecognitionAvailable(language); - if (availability_status == media::mojom::AvailabilityStatus::kAvailable && - !HasOnDeviceLanguageDownloaded(language)) { - std::move(callback).Run(media::mojom::AvailabilityStatus::kDownloadable); - return; - } - - std::move(callback).Run(availability_status); + std::move(callback).Run(GetMaskedAvailabilityStatus(language)); #endif // BUILDFLAG(IS_ANDROID) } @@ -120,18 +126,13 @@ return; } - language_installation_callbacks_[language].push_back(std::move(callback)); - // `InstallSoda` will only install the SODA binary if it is not already - // installed. - speech::SodaInstaller::GetInstance()->InstallSoda( - g_browser_process->local_state()); - - // `InstallLanguage` will only install languages that are not already - // installed. - speech::SodaInstaller::GetInstance()->InstallLanguage( - language_config.value().language_name, g_browser_process->local_state()); - - SetOnDeviceLanguageDownloaded(language); + base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&OnDeviceSpeechRecognitionImpl::InstallLanguageInternal, + weak_ptr_factory_.GetWeakPtr(), + language_config.value().language_name, + std::move(callback)), + GetDownloadDelay(language_config.value().language_name)); } void OnDeviceSpeechRecognitionImpl::OnSodaInstalled( @@ -196,6 +197,25 @@ } #if !BUILDFLAG(IS_ANDROID) +void OnDeviceSpeechRecognitionImpl::InstallLanguageInternal( + const std::string& language, + OnDeviceSpeechRecognitionImpl::InstallOnDeviceSpeechRecognitionCallback + callback) { + language_installation_callbacks_[language].push_back(std::move(callback)); + + // `InstallSoda` will only install the SODA binary if it is not already + // installed. + speech::SodaInstaller::GetInstance()->InstallSoda( + g_browser_process->local_state()); + + // `InstallLanguage` will only install languages that are not already + // installed. + speech::SodaInstaller::GetInstance()->InstallLanguage( + language, g_browser_process->local_state()); + + SetOnDeviceLanguageDownloaded(language); +} + void OnDeviceSpeechRecognitionImpl::RunAndRemoveInstallationCallbacks( const std::string& language, bool installation_success) { @@ -235,6 +255,19 @@ std::move(on_device_languages_downloaded)); } +media::mojom::AvailabilityStatus +OnDeviceSpeechRecognitionImpl::GetMaskedAvailabilityStatus( + const std::string& language) { + media::mojom::AvailabilityStatus availability_status = + IsOnDeviceSpeechRecognitionAvailable(language); + if (availability_status == media::mojom::AvailabilityStatus::kAvailable && + !HasOnDeviceLanguageDownloaded(language)) { + return media::mojom::AvailabilityStatus::kDownloadable; + } + + return availability_status; +} + bool OnDeviceSpeechRecognitionImpl::HasOnDeviceLanguageDownloaded( const std::string& language) { base::Value on_device_languages_downloaded_value = @@ -269,6 +302,20 @@ SetOnDeviceLanguagesDownloadedContentSetting( std::move(on_device_languages_downloaded_value)); } + +base::TimeDelta OnDeviceSpeechRecognitionImpl::GetDownloadDelay( + const std::string& language) { + // Check if SODA is already installed for the given language. If it is and the + // origin isn't supposed to know that, then add a delay to simulate a real + // download before proceeding. + if (GetMaskedAvailabilityStatus(language) == + media::mojom::AvailabilityStatus::kDownloadable && + IsLanguageInstalled(language)) { + return base::RandTimeDelta(base::Seconds(2), base::Seconds(3)); + } + + return base::TimeDelta(); +} #endif // !BUILDFLAG(IS_ANDROID) DOCUMENT_USER_DATA_KEY_IMPL(OnDeviceSpeechRecognitionImpl);
diff --git a/chrome/browser/speech/on_device_speech_recognition_impl.h b/chrome/browser/speech/on_device_speech_recognition_impl.h index 6ae5255c..1873067 100644 --- a/chrome/browser/speech/on_device_speech_recognition_impl.h +++ b/chrome/browser/speech/on_device_speech_recognition_impl.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/memory/weak_ptr.h" #include "content/public/browser/document_user_data.h" #include "media/mojo/mojom/speech_recognizer.mojom.h" #include "mojo/public/cpp/bindings/receiver_set.h" @@ -79,6 +80,10 @@ bool CanRenderFrameHostUseOnDeviceSpeechRecognition(); #if !BUILDFLAG(IS_ANDROID) + void InstallLanguageInternal( + const std::string& language, + OnDeviceSpeechRecognitionImpl::InstallOnDeviceSpeechRecognitionCallback + callback); void RunAndRemoveInstallationCallbacks(const std::string& language, bool installation_success); base::Value GetOnDeviceLanguagesDownloadedValue(); @@ -87,6 +92,16 @@ bool HasOnDeviceLanguageDownloaded(const std::string& language); void SetOnDeviceLanguageDownloaded(const std::string&); + // Mask on-device speech recognition availability by requiring a call to + // installOnDevice() for a language before the language is available to the + // origin. + media::mojom::AvailabilityStatus GetMaskedAvailabilityStatus( + const std::string& language); + + // Returns a delay when installing on-device speech recognition language packs + // to safeguard against fingerprinting resulting from timing the installation. + base::TimeDelta GetDownloadDelay(const std::string& language); + base::flat_map<std::string, std::list<InstallOnDeviceSpeechRecognitionCallback>> language_installation_callbacks_; @@ -97,6 +112,7 @@ mojo::Receiver<media::mojom::OnDeviceSpeechRecognition> receiver_{this}; + base::WeakPtrFactory<OnDeviceSpeechRecognitionImpl> weak_ptr_factory_{this}; DOCUMENT_USER_DATA_KEY_DECL(); };
diff --git a/chrome/browser/speech/on_device_speech_recognition_impl_browsertest.cc b/chrome/browser/speech/on_device_speech_recognition_impl_browsertest.cc index 3999fe9..68f7810 100644 --- a/chrome/browser/speech/on_device_speech_recognition_impl_browsertest.cc +++ b/chrome/browser/speech/on_device_speech_recognition_impl_browsertest.cc
@@ -8,6 +8,7 @@ #include "base/functional/bind.h" #include "base/run_loop.h" +#include "base/test/run_until.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h" #include "chrome/browser/profiles/profile.h" @@ -30,6 +31,7 @@ namespace { constexpr char kValidLanguageCode[] = "en-US"; constexpr char kInvalidLanguageCode[] = "xx-XX"; + } // namespace namespace speech { @@ -49,26 +51,24 @@ void SetUpOnMainThread() override; void OnDeviceWebSpeechAvailableCallback( + media::mojom::AvailabilityStatus actual_status); + void OnDeviceWebSpeechAvailableCallbackAndAssertStatus( media::mojom::AvailabilityStatus expected_status, media::mojom::AvailabilityStatus actual_status); + void InstallOnDeviceSpeechRecognition(); void InstallOnDeviceSpeechRecognitionCallback(bool expected_success, bool actual_success); - void WaitForCallback(); + void WaitUntilAvailable(); void NavigateToUrl(const std::string& url_string); void ClearSiteContentSettings(); + OnDeviceSpeechRecognitionImpl* on_device_speech_recognition(); protected: - std::unique_ptr<base::RunLoop> run_loop_; - mojo::Remote<media::mojom::OnDeviceSpeechRecognition> - on_device_speech_recognition_; base::test::ScopedFeatureList scoped_feature_list_; + media::mojom::AvailabilityStatus availability_status_; }; void OnDeviceSpeechRecognitionImplBrowserTest::SetUpOnMainThread() { - OnDeviceSpeechRecognitionImpl::GetOrCreateForCurrentDocument( - chrome_test_utils::GetActiveWebContents(this)->GetPrimaryMainFrame()) - ->Bind(on_device_speech_recognition_.BindNewPipeAndPassReceiver()); - host_resolver()->AddRule("*", "127.0.0.1"); embedded_https_test_server().ServeFilesFromSourceDirectory( GetChromeTestDataDir()); @@ -79,25 +79,49 @@ void OnDeviceSpeechRecognitionImplBrowserTest:: OnDeviceWebSpeechAvailableCallback( + media::mojom::AvailabilityStatus actual_status) { + OnDeviceWebSpeechAvailableCallbackAndAssertStatus(actual_status, + actual_status); +} + +void OnDeviceSpeechRecognitionImplBrowserTest:: + OnDeviceWebSpeechAvailableCallbackAndAssertStatus( media::mojom::AvailabilityStatus expected_status, media::mojom::AvailabilityStatus actual_status) { ASSERT_EQ(expected_status, actual_status); - run_loop_->Quit(); + availability_status_ = actual_status; +} + +void OnDeviceSpeechRecognitionImplBrowserTest:: + InstallOnDeviceSpeechRecognition() { + // Install on-device speech recognition and simulate the installation of the + // SODA library and language pack. + on_device_speech_recognition()->InstallOnDeviceSpeechRecognition( + kValidLanguageCode, + base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: + InstallOnDeviceSpeechRecognitionCallback, + base::Unretained(this), true)); + + speech::SodaInstaller::GetInstance()->NotifySodaInstalledForTesting(); + speech::SodaInstaller::GetInstance()->NotifySodaInstalledForTesting( + speech::LanguageCode::kEnUs); } void OnDeviceSpeechRecognitionImplBrowserTest:: InstallOnDeviceSpeechRecognitionCallback(bool expected_success, bool actual_success) { ASSERT_EQ(expected_success, actual_success); - run_loop_->Quit(); } -void OnDeviceSpeechRecognitionImplBrowserTest::WaitForCallback() { - ASSERT_FALSE(run_loop_); - run_loop_ = std::make_unique<base::RunLoop>( - base::RunLoop::Type::kNestableTasksAllowed); - run_loop_->Run(); - run_loop_ = nullptr; +void OnDeviceSpeechRecognitionImplBrowserTest::WaitUntilAvailable() { + ASSERT_TRUE(base::test::RunUntil([&]() { + on_device_speech_recognition()->OnDeviceWebSpeechAvailable( + kValidLanguageCode, + base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: + OnDeviceWebSpeechAvailableCallback, + base::Unretained(this))); + return availability_status_ == media::mojom::AvailabilityStatus::kAvailable; + })); } void OnDeviceSpeechRecognitionImplBrowserTest::NavigateToUrl( @@ -105,10 +129,6 @@ const GURL kUrl( embedded_https_test_server().GetURL(url_string, "/empty.html")); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kUrl)); - on_device_speech_recognition_.reset(); - OnDeviceSpeechRecognitionImpl::GetOrCreateForCurrentDocument( - chrome_test_utils::GetActiveWebContents(this)->GetPrimaryMainFrame()) - ->Bind(on_device_speech_recognition_.BindNewPipeAndPassReceiver()); } void OnDeviceSpeechRecognitionImplBrowserTest::ClearSiteContentSettings() { @@ -122,23 +142,26 @@ observer.BlockUntilCompletion(); } +OnDeviceSpeechRecognitionImpl* +OnDeviceSpeechRecognitionImplBrowserTest::on_device_speech_recognition() { + return OnDeviceSpeechRecognitionImpl::GetOrCreateForCurrentDocument( + chrome_test_utils::GetActiveWebContents(this)->GetPrimaryMainFrame()); +} + IN_PROC_BROWSER_TEST_F(OnDeviceSpeechRecognitionImplBrowserTest, OnDeviceWebSpeechAvailable) { - on_device_speech_recognition_->OnDeviceWebSpeechAvailable( + on_device_speech_recognition()->OnDeviceWebSpeechAvailable( kInvalidLanguageCode, base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: - OnDeviceWebSpeechAvailableCallback, + OnDeviceWebSpeechAvailableCallbackAndAssertStatus, base::Unretained(this), media::mojom::AvailabilityStatus::kUnavailable)); - WaitForCallback(); - - on_device_speech_recognition_->OnDeviceWebSpeechAvailable( + on_device_speech_recognition()->OnDeviceWebSpeechAvailable( kValidLanguageCode, base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: - OnDeviceWebSpeechAvailableCallback, + OnDeviceWebSpeechAvailableCallbackAndAssertStatus, base::Unretained(this), media::mojom::AvailabilityStatus::kDownloadable)); - WaitForCallback(); } IN_PROC_BROWSER_TEST_F(OnDeviceSpeechRecognitionImplBrowserTest, @@ -147,93 +170,51 @@ // Verify that on-device speech recognition is downloadable before it is // installed. - on_device_speech_recognition_->OnDeviceWebSpeechAvailable( + on_device_speech_recognition()->OnDeviceWebSpeechAvailable( kValidLanguageCode, base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: - OnDeviceWebSpeechAvailableCallback, + OnDeviceWebSpeechAvailableCallbackAndAssertStatus, base::Unretained(this), media::mojom::AvailabilityStatus::kDownloadable)); - WaitForCallback(); - - // Install on-device speech recognition and simulate the installation of the - // SODA library and language pack. - on_device_speech_recognition_->InstallOnDeviceSpeechRecognition( - kValidLanguageCode, - base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: - InstallOnDeviceSpeechRecognitionCallback, - base::Unretained(this), true)); - - // Run the loop until idle, otherwise SODA might get install before the - // `InstallOnDeviceSpeechRecognition` message is flushed through the pipe. - // This won't happen outside of tests because - // `InstallOnDeviceSpeechRecognition` triggers the installation of SODA. - base::RunLoop().RunUntilIdle(); - - speech::SodaInstaller::GetInstance()->NotifySodaInstalledForTesting(); - speech::SodaInstaller::GetInstance()->NotifySodaInstalledForTesting( - speech::LanguageCode::kEnUs); - WaitForCallback(); + InstallOnDeviceSpeechRecognition(); // Verify that on-device speech recognition is available after it is // installed. - on_device_speech_recognition_->OnDeviceWebSpeechAvailable( - kValidLanguageCode, - base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: - OnDeviceWebSpeechAvailableCallback, - base::Unretained(this), - media::mojom::AvailabilityStatus::kAvailable)); - WaitForCallback(); + WaitUntilAvailable(); // On-device speech recognition availability is masked by origin, so the // previously installed language pack should not be available to a different // origin even if it's already installed. NavigateToUrl("bar.com"); - on_device_speech_recognition_->OnDeviceWebSpeechAvailable( + on_device_speech_recognition()->OnDeviceWebSpeechAvailable( kValidLanguageCode, base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: - OnDeviceWebSpeechAvailableCallback, + OnDeviceWebSpeechAvailableCallbackAndAssertStatus, base::Unretained(this), media::mojom::AvailabilityStatus::kDownloadable)); - WaitForCallback(); // Verify that on-device speech recognition can be installed on the second // origin. - on_device_speech_recognition_->InstallOnDeviceSpeechRecognition( - kValidLanguageCode, - base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: - InstallOnDeviceSpeechRecognitionCallback, - base::Unretained(this), true)); - base::RunLoop().RunUntilIdle(); - speech::SodaInstaller::GetInstance()->NotifySodaInstalledForTesting(); - speech::SodaInstaller::GetInstance()->NotifySodaInstalledForTesting( - speech::LanguageCode::kEnUs); - WaitForCallback(); - on_device_speech_recognition_->OnDeviceWebSpeechAvailable( - kValidLanguageCode, - base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: - OnDeviceWebSpeechAvailableCallback, - base::Unretained(this), - media::mojom::AvailabilityStatus::kAvailable)); - WaitForCallback(); + InstallOnDeviceSpeechRecognition(); + + WaitUntilAvailable(); // Verify that clearing site content settings resets the on-device speech // recognition mask for both origins. ClearSiteContentSettings(); - on_device_speech_recognition_->OnDeviceWebSpeechAvailable( + on_device_speech_recognition()->OnDeviceWebSpeechAvailable( kValidLanguageCode, base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: - OnDeviceWebSpeechAvailableCallback, + OnDeviceWebSpeechAvailableCallbackAndAssertStatus, base::Unretained(this), media::mojom::AvailabilityStatus::kDownloadable)); - WaitForCallback(); NavigateToUrl("foo.com"); - on_device_speech_recognition_->OnDeviceWebSpeechAvailable( + on_device_speech_recognition()->OnDeviceWebSpeechAvailable( kValidLanguageCode, base::BindOnce(&OnDeviceSpeechRecognitionImplBrowserTest:: - OnDeviceWebSpeechAvailableCallback, + OnDeviceWebSpeechAvailableCallbackAndAssertStatus, base::Unretained(this), media::mojom::AvailabilityStatus::kDownloadable)); - WaitForCallback(); } } // namespace speech
diff --git a/chrome/browser/storage_access_api/storage_access_grant_permission_context_unittest.cc b/chrome/browser/storage_access_api/storage_access_grant_permission_context_unittest.cc index 156a6953..a6563ff2 100644 --- a/chrome/browser/storage_access_api/storage_access_grant_permission_context_unittest.cc +++ b/chrome/browser/storage_access_api/storage_access_grant_permission_context_unittest.cc
@@ -797,10 +797,10 @@ /*entries=*/ {{net::SchemefulSite(GetTopLevelURL()), {net::FirstPartySetEntry(net::SchemefulSite(GetTopLevelURL()), - net::SiteType::kPrimary, std::nullopt)}}, + net::SiteType::kPrimary)}}, {net::SchemefulSite(GetRequesterURL()), {net::FirstPartySetEntry(net::SchemefulSite(GetTopLevelURL()), - net::SiteType::kAssociated, 0)}}}, + net::SiteType::kAssociated)}}}, /*aliases=*/{})); }
diff --git a/chrome/browser/supervised_user/supervised_user_extensions_manager.h b/chrome/browser/supervised_user/supervised_user_extensions_manager.h index 8a2e49f..fd872c2 100644 --- a/chrome/browser/supervised_user/supervised_user_extensions_manager.h +++ b/chrome/browser/supervised_user/supervised_user_extensions_manager.h
@@ -25,9 +25,10 @@ class ExtensionRegistry; // UMA metrics for auto-approved extensions. -constexpr char kInitialLocallyApprovedExtensionCountWinLinuxMacHistogramName[] = - "SupervisedUsers.InitialLocallyApprovedExtensionsCountOnWinLinuxMac"; -constexpr char kExtensionApprovalsCountOnExtensionToggleHistogramName[] = +inline constexpr char + kInitialLocallyApprovedExtensionCountWinLinuxMacHistogramName[] = + "SupervisedUsers.InitialLocallyApprovedExtensionsCountOnWinLinuxMac"; +inline constexpr char kExtensionApprovalsCountOnExtensionToggleHistogramName[] = "SupervisedUsers.ExtensionApprovalsCountOnExtensionToggle"; // This class groups all the functionality to handle extensions
diff --git a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc index ff5e7c9..f993662 100644 --- a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
@@ -60,6 +60,7 @@ #include "components/trusted_vault/command_line_switches.h" #include "components/trusted_vault/securebox.h" #include "components/trusted_vault/standalone_trusted_vault_client.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/test/fake_security_domains_server.h" #include "components/trusted_vault/trusted_vault_client.h" #include "components/trusted_vault/trusted_vault_connection.h"
diff --git a/chrome/browser/tabmodel/BUILD.gn b/chrome/browser/tabmodel/BUILD.gn index f5f68129..8ea7f34 100644 --- a/chrome/browser/tabmodel/BUILD.gn +++ b/chrome/browser/tabmodel/BUILD.gn
@@ -9,6 +9,7 @@ resources_package = "org.chromium.chrome.browser.tabmodel" sources = [ + "android/java/src/org/chromium/chrome/browser/tabmodel/ArchivedTabCountSupplier.java", "android/java/src/org/chromium/chrome/browser/tabmodel/ArchivedTabModelSelectorHolder.java", "android/java/src/org/chromium/chrome/browser/tabmodel/AsyncTabCreationParams.java", "android/java/src/org/chromium/chrome/browser/tabmodel/AsyncTabLauncher.java", @@ -103,6 +104,7 @@ robolectric_library("junit") { sources = [ + "android/java/src/org/chromium/chrome/browser/tabmodel/ArchivedTabCountSupplierUnitTest.java", "android/java/src/org/chromium/chrome/browser/tabmodel/TabClosureParamsUnitTest.java", "android/java/src/org/chromium/chrome/browser/tabmodel/TabGroupCollapsedUtilsUnitTest.java", "android/java/src/org/chromium/chrome/browser/tabmodel/TabGroupColorUtilsUnitTest.java",
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/ArchivedTabCountSupplier.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/ArchivedTabCountSupplier.java new file mode 100644 index 0000000..177d968 --- /dev/null +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/ArchivedTabCountSupplier.java
@@ -0,0 +1,121 @@ +// 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. + +package org.chromium.chrome.browser.tabmodel; + +import org.chromium.base.Callback; +import org.chromium.base.lifetime.Destroyable; +import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.supplier.ObservableSupplierImpl; +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; +import org.chromium.components.tab_group_sync.LocalTabGroupId; +import org.chromium.components.tab_group_sync.SavedTabGroup; +import org.chromium.components.tab_group_sync.TabGroupSyncService; +import org.chromium.components.tab_group_sync.TabGroupSyncService.Observer; +import org.chromium.components.tab_group_sync.TriggerSource; + +/** + * An {@link ObservableSupplier} which manages the total tab count in the archived surface, which + * includes tab counts in the archived {@link TabModel} and any tab groups from the {@link + * TabGroupSyncService}. + */ +@NullMarked +public class ArchivedTabCountSupplier extends ObservableSupplierImpl<Integer> + implements Destroyable { + private final TabModel mArchivedTabModel; + private final ObservableSupplier<Integer> mArchivedTabModelTabCountSupplier; + private final Callback<Integer> mArchivedTabModelTabCountObserver = + (tabModelTabCount) -> { + updateArchivedTabCount(); + }; + private final @Nullable TabGroupSyncService mTabGroupSyncService; + + private final Observer mTabGroupSyncObserver = + new Observer() { + @Override + public void onInitialized() { + updateArchivedTabCount(); + } + + @Override + public void onTabGroupAdded(SavedTabGroup group, @TriggerSource int source) { + updateArchivedTabCount(); + } + + @Override + public void onTabGroupUpdated(SavedTabGroup group, @TriggerSource int source) { + updateArchivedTabCount(); + } + + @Override + public void onTabGroupRemoved(LocalTabGroupId localId, @TriggerSource int source) { + updateArchivedTabCount(); + } + + @Override + public void onTabGroupRemoved(String syncId, @TriggerSource int source) { + updateArchivedTabCount(); + } + }; + + /** + * Creates an instance of {@link ArchivedTabCountSupplier}. + * + * @param archivedTabModel The {@link TabModel} representing archived tabs. + * @param tabGroupSyncService The {@link TabGroupSyncService} governing synced tab groups. + * @return The supplier that manages tab count updates from both the tab model and sync service. + */ + public ArchivedTabCountSupplier( + TabModel archivedTabModel, @Nullable TabGroupSyncService tabGroupSyncService) { + mArchivedTabModel = archivedTabModel; + mArchivedTabModelTabCountSupplier = mArchivedTabModel.getTabCountSupplier(); + mArchivedTabModelTabCountSupplier.addObserver(mArchivedTabModelTabCountObserver); + mTabGroupSyncService = tabGroupSyncService; + + if (mTabGroupSyncService != null) { + mTabGroupSyncService.addObserver(mTabGroupSyncObserver); + } + + // Set this supplier once so there is a base value at minimum. + super.set(mArchivedTabModelTabCountSupplier.get()); + } + + private void updateArchivedTabCount() { + int totalTabCount = getArchivedTabGroupTabCount(); + totalTabCount += mArchivedTabModel.getCount(); + super.set(totalTabCount); + } + + private int getArchivedTabGroupTabCount() { + int archivedTabGroupTabCount = 0; + if (mTabGroupSyncService != null) { + for (String syncId : mTabGroupSyncService.getAllGroupIds()) { + SavedTabGroup savedTabGroup = mTabGroupSyncService.getGroup(syncId); + + if (savedTabGroup != null && savedTabGroup.archivalTimeMs != null) { + archivedTabGroupTabCount += savedTabGroup.savedTabs.size(); + } + } + } + + return archivedTabGroupTabCount; + } + + @Override + public void set(Integer tabCount) { + assert false : "ArchivedTabCountSupplier should only be set through its observers."; + } + + @Override + public void destroy() { + if (mArchivedTabModelTabCountSupplier != null) { + mArchivedTabModelTabCountSupplier.removeObserver(mArchivedTabModelTabCountObserver); + } + + if (mTabGroupSyncService != null) { + mTabGroupSyncService.removeObserver(mTabGroupSyncObserver); + } + } +}
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/ArchivedTabCountSupplierUnitTest.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/ArchivedTabCountSupplierUnitTest.java new file mode 100644 index 0000000..0f65a3d9 --- /dev/null +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/ArchivedTabCountSupplierUnitTest.java
@@ -0,0 +1,124 @@ +// 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. + +package org.chromium.chrome.browser.tabmodel; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import org.chromium.base.Callback; +import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.components.tab_group_sync.SavedTabGroup; +import org.chromium.components.tab_group_sync.SavedTabGroupTab; +import org.chromium.components.tab_group_sync.TabGroupSyncService; +import org.chromium.components.tab_group_sync.TabGroupSyncService.Observer; + +import java.util.List; + +/** Unit tests for {@link ArchivedTabCountSupplier}. */ +@RunWith(BaseRobolectricTestRunner.class) +public class ArchivedTabCountSupplierUnitTest { + private static final int BASE_TAB_COUNT = 1; + private static final int TAB_MODEL_TAB_COUNT = 2; + private static final String SYNC_GROUP_ID = "test_sync_group_id1"; + + @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Mock private ObservableSupplier<Integer> mArchivedTabModelTabCountSupplier; + @Mock private TabModel mTabModel; + @Mock private TabGroupSyncService mTabGroupSyncService; + + @Captor ArgumentCaptor<Callback<Integer>> mArchivedTabModelTabCountObserverCaptor; + @Captor ArgumentCaptor<Observer> mTabGroupSyncServiceObserverCaptor; + + private ArchivedTabCountSupplier mArchivedTabCountSupplier; + + @Before + public void setUp() { + when(mTabModel.getTabCountSupplier()).thenReturn(mArchivedTabModelTabCountSupplier); + when(mArchivedTabModelTabCountSupplier.get()).thenReturn(BASE_TAB_COUNT); + doReturn(null) + .when(mArchivedTabModelTabCountSupplier) + .addObserver(mArchivedTabModelTabCountObserverCaptor.capture()); + doNothing() + .when(mTabGroupSyncService) + .addObserver(mTabGroupSyncServiceObserverCaptor.capture()); + + mArchivedTabCountSupplier = new ArchivedTabCountSupplier(mTabModel, mTabGroupSyncService); + } + + @Test + public void testTabModelUpdate() { + SavedTabGroupTab savedTab = new SavedTabGroupTab(); + SavedTabGroup savedTabGroup = new SavedTabGroup(); + savedTabGroup.syncId = SYNC_GROUP_ID; + savedTabGroup.savedTabs = List.of(savedTab); + savedTabGroup.archivalTimeMs = System.currentTimeMillis(); + + when(mTabGroupSyncService.getGroup(SYNC_GROUP_ID)).thenReturn(savedTabGroup); + when(mTabGroupSyncService.getAllGroupIds()).thenReturn(new String[] {SYNC_GROUP_ID}); + when(mTabModel.getCount()).thenReturn(TAB_MODEL_TAB_COUNT); + + mArchivedTabModelTabCountObserverCaptor.getValue().onResult(TAB_MODEL_TAB_COUNT); + assertEquals( + TAB_MODEL_TAB_COUNT + savedTabGroup.savedTabs.size(), + mArchivedTabCountSupplier.get().intValue()); + } + + @Test + public void testTabGroupSyncUpdate() { + SavedTabGroupTab savedTab = new SavedTabGroupTab(); + SavedTabGroup savedTabGroup = new SavedTabGroup(); + savedTabGroup.syncId = SYNC_GROUP_ID; + savedTabGroup.savedTabs = List.of(savedTab); + savedTabGroup.archivalTimeMs = System.currentTimeMillis(); + + when(mTabGroupSyncService.getGroup(SYNC_GROUP_ID)).thenReturn(savedTabGroup); + when(mTabGroupSyncService.getAllGroupIds()).thenReturn(new String[] {SYNC_GROUP_ID}); + when(mTabModel.getCount()).thenReturn(TAB_MODEL_TAB_COUNT); + + mTabGroupSyncServiceObserverCaptor.getValue().onInitialized(); + assertEquals( + TAB_MODEL_TAB_COUNT + savedTabGroup.savedTabs.size(), + mArchivedTabCountSupplier.get().intValue()); + } + + @Test + public void testAllObserversUpdate() { + SavedTabGroupTab savedTab = new SavedTabGroupTab(); + SavedTabGroup savedTabGroup = new SavedTabGroup(); + savedTabGroup.syncId = SYNC_GROUP_ID; + savedTabGroup.savedTabs = List.of(savedTab); + savedTabGroup.archivalTimeMs = System.currentTimeMillis(); + + when(mTabGroupSyncService.getGroup(SYNC_GROUP_ID)).thenReturn(savedTabGroup); + when(mTabGroupSyncService.getAllGroupIds()).thenReturn(new String[] {SYNC_GROUP_ID}); + when(mTabModel.getCount()).thenReturn(BASE_TAB_COUNT); + + mTabGroupSyncServiceObserverCaptor.getValue().onInitialized(); + assertEquals( + BASE_TAB_COUNT + savedTabGroup.savedTabs.size(), + mArchivedTabCountSupplier.get().intValue()); + + when(mTabModel.getCount()).thenReturn(TAB_MODEL_TAB_COUNT); + + mArchivedTabModelTabCountObserverCaptor.getValue().onResult(TAB_MODEL_TAB_COUNT); + assertEquals( + TAB_MODEL_TAB_COUNT + savedTabGroup.savedTabs.size(), + mArchivedTabCountSupplier.get().intValue()); + } +}
diff --git a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc index 51cab4bd..be4d2b72 100644 --- a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc +++ b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context_unittest.cc
@@ -216,9 +216,9 @@ /*entries=*/ { {net::SchemefulSite(GetRequesterURL()), - net::FirstPartySetEntry(top_level, net::SiteType::kAssociated, 0)}, - {top_level, net::FirstPartySetEntry( - top_level, net::SiteType::kPrimary, std::nullopt)}, + net::FirstPartySetEntry(top_level, net::SiteType::kAssociated)}, + {top_level, + net::FirstPartySetEntry(top_level, net::SiteType::kPrimary)}, }, /*aliases=*/{})); }
diff --git a/chrome/browser/tpcd/support/trial_test_utils.h b/chrome/browser/tpcd/support/trial_test_utils.h index f98a236..50a72ac 100644 --- a/chrome/browser/tpcd/support/trial_test_utils.h +++ b/chrome/browser/tpcd/support/trial_test_utils.h
@@ -66,7 +66,7 @@ // Origin Trials token for `kTrialEnabledDomain` generated with: // tools/origin_trials/generate_token.py https://example.test TopLevelTpcd // --expire-days 5000 -const char k1pDeprecationTrialToken[] = +inline constexpr char k1pDeprecationTrialToken[] = "A5sGfiy3qkhJES3yFHkBd7i0jX8rC+" "pCA2M0tAhfmetOLkvOVTAR2589eHxZHbdv3QgX7BtANaw3A+" "A3NvgAtwIAAABXeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLnRlc3Q6NDQzIiwgImZlYXR1" @@ -76,7 +76,7 @@ // generated with: // tools/origin_trials/generate_token.py https://example.test TopLevelTpcd // --is-subdomain --expire-days 5000 -const char k1pDeprecationTrialSubdomainMatchingToken[] = +inline constexpr char k1pDeprecationTrialSubdomainMatchingToken[] = "A5+BZIDRMyQWn2lWBHXWd3egEk2WqNdtEuzEbDZV0qXwYM8nKiqlHNYjGrfXuFgmUQ+" "j0wpk0EBVJC51I3K0gQkAAABseyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLnRlc3Q6NDQzI" "iwgImZlYXR1cmUiOiAiVG9wTGV2ZWxUcGNkIiwgImV4cGlyeSI6IDIxMzkzMzg0NjcsICJpc1N" @@ -85,7 +85,7 @@ // Origin Trials token for `kTrialEnabledSiteSubdomain` generated with: // tools/origin_trials/generate_token.py https://sub.example.test TopLevelTpcd // --expire-days 5000 -const char kSubdomain1pDeprecationTrialToken[] = +inline constexpr char kSubdomain1pDeprecationTrialToken[] = "A7CJlPHXa8yQc2lJRvM/" "mq4Oi5+" "SJHbT4nnUmWiYKeuguuMkTd6y8DHBRAdEgvLXPajr9Qm2cMe4f5qzovm07QwAAABbeyJvcmlna" @@ -96,7 +96,7 @@ // generated with: // tools/origin_trials/generate_token.py https://sub.example.test TopLevelTpcd // --is-subdomain --expire-days 5000 -const char kSubdomain1pDeprecationTrialSubdomainMatchingToken[] = +inline constexpr char kSubdomain1pDeprecationTrialSubdomainMatchingToken[] = "Ayuwtl4l9AC0MUBPlPDMZ3on5Db2hTQtFJdRM4fC1Bj03JLXWKNoe9bg4m5CslS5wFG9WQQsKu" "q/" "IbnFBxzGXwMAAABweyJvcmlnaW4iOiAiaHR0cHM6Ly9zdWIuZXhhbXBsZS50ZXN0OjQ0MyIsIC" @@ -106,7 +106,7 @@ // Origin Trials token for `kOtherTrialEnabledDomain` generated with: // tools/origin_trials/generate_token.py https://example.test TopLevelTpcd // --expire-days 5000 -const char kOtherDomain1pDeprecationTrialToken[] = +inline constexpr char kOtherDomain1pDeprecationTrialToken[] = "A7Dsv5nB89HuyiPl64hqJ0V0FporBq7g33dvjUABxJ3K4z3QdjCuurIGcF9wJJE0s1piYA2y4T" "0B+" "oO2n6sbIQwAAABVeyJvcmlnaW4iOiAiaHR0cHM6Ly9vdGhlci50ZXN0OjQ0MyIsICJmZWF0dXJ"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index e1f99b8b4..0647eac 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -81,8 +81,6 @@ "passwords/ui_utils.h", "passwords/well_known_change_password_navigation_throttle.cc", "passwords/well_known_change_password_navigation_throttle.h", - "plus_addresses/plus_address_creation_controller.h", - "plus_addresses/plus_address_creation_view.h", "profiles/profile_error_dialog.cc", "profiles/profile_error_dialog.h", "recently_audible_helper.cc", @@ -421,6 +419,8 @@ "//chrome/browser/ui/page_action:icon_type", "//chrome/browser/ui/page_info", "//chrome/browser/ui/page_info:impl", + "//chrome/browser/ui/plus_addresses", + "//chrome/browser/ui/plus_addresses:impl", "//chrome/browser/ui/prefs", "//chrome/browser/ui/prefs:impl", "//chrome/browser/ui/safety_hub", @@ -1941,6 +1941,7 @@ # TODO(crbug.com/382237520): Remove this once NTP code is modularized. "//chrome/browser/ui/lens:impl", + "//chrome/browser/ui/webui/new_tab_footer:impl", "//chrome/browser/ui/signin:impl", "//chrome/browser/ui/webui/commerce:impl", "//chrome/browser/ui/webui/signin:signin_impl", @@ -3677,11 +3678,6 @@ if (toolkit_views) { sources += [ "bubble_anchor_util.h", - "plus_addresses/plus_address_creation_controller_desktop.h", - "plus_addresses/plus_address_error_dialog.cc", - "plus_addresses/plus_address_error_dialog.h", - "plus_addresses/plus_address_menu_model.cc", - "plus_addresses/plus_address_menu_model.h", "plus_addresses/views/plus_address_creation_controller_desktop.cc", "plus_addresses/views/plus_address_creation_dialog_delegate.cc", "plus_addresses/views/plus_address_creation_dialog_delegate.h",
diff --git a/chrome/browser/ui/android/android_about_app_info.cc b/chrome/browser/ui/android/android_about_app_info.cc index aa6b83a1..7864759c 100644 --- a/chrome/browser/ui/android/android_about_app_info.cc +++ b/chrome/browser/ui/android/android_about_app_info.cc
@@ -26,14 +26,3 @@ embedder_support::IncludeAndroidBuildNumber::Include, embedder_support::IncludeAndroidModel::Include); } - -std::string AndroidAboutAppInfo::GetTargetsUInfo() { - std::string targets_u_info = - base::android::BuildInfo::GetInstance()->is_at_least_u() ? "true" - : "false"; - targets_u_info += "/"; - targets_u_info += - base::android::BuildInfo::GetInstance()->targets_at_least_u() ? "true" - : "false"; - return targets_u_info; -}
diff --git a/chrome/browser/ui/android/android_about_app_info.h b/chrome/browser/ui/android/android_about_app_info.h index 06bea07..eef9d2b 100644 --- a/chrome/browser/ui/android/android_about_app_info.h +++ b/chrome/browser/ui/android/android_about_app_info.h
@@ -15,10 +15,6 @@ // Returns a string containing detailed info about the os environment. static std::string GetOsInfo(); - - // Returns a string containing info about whether the device is at least - // Android U and whether Chrome targets at least U. - static std::string GetTargetsUInfo(); }; #endif // CHROME_BROWSER_UI_ANDROID_ANDROID_ABOUT_APP_INFO_H_
diff --git a/chrome/browser/ui/android/omnibox/BUILD.gn b/chrome/browser/ui/android/omnibox/BUILD.gn index 8b8171d..2ab5ece3 100644 --- a/chrome/browser/ui/android/omnibox/BUILD.gn +++ b/chrome/browser/ui/android/omnibox/BUILD.gn
@@ -81,6 +81,7 @@ "java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsVisualState.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/PreWarmingRecycledViewPool.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/RecyclerViewSelectionController.java", + "java/src/org/chromium/chrome/browser/omnibox/suggestions/SelectionController.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionCommonProperties.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionHorizontalDivider.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionHost.java", @@ -305,6 +306,7 @@ "java/res/drawable-xxxhdpi/btn_suggestion_refine.png", "java/res/drawable-xxxhdpi/ic_history_googblue_24dp.png", "java/res/drawable-xxxhdpi/ic_suggestion_magnifier.png", + "java/res/drawable/hairline_circle.xml", "java/res/drawable/ic_book_round.xml", "java/res/drawable/ic_content_copy_black.xml", "java/res/drawable/ic_equals_sign_round.xml", @@ -424,6 +426,7 @@ "java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownUnitTest.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/PreWarmingRecycledViewPoolTest.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/RecyclerViewSelectionControllerUnitTest.java", + "java/src/org/chromium/chrome/browser/omnibox/suggestions/SelectionControllerUnitTest.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionHorizontalDividerTest.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionListViewBinderUnitTest.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/UnsyncedSuggestionsListAnimationDriverTest.java",
diff --git a/chrome/browser/ui/android/omnibox/java/res/drawable/hairline_circle.xml b/chrome/browser/ui/android/omnibox/java/res/drawable/hairline_circle.xml new file mode 100644 index 0000000..b214e195 --- /dev/null +++ b/chrome/browser/ui/android/omnibox/java/res/drawable/hairline_circle.xml
@@ -0,0 +1,14 @@ +<!-- +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. +--> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:gravity="center"> + <shape android:shape="oval"> + <solid android:color="@android:color/transparent"/> + <stroke android:width="2dp" android:color="@android:color/black"/> + <size android:width="32dp" android:height="32dp" /> + </shape> + </item> +</layer-list>
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SelectionController.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SelectionController.java new file mode 100644 index 0000000..e0f2af9 --- /dev/null +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SelectionController.java
@@ -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. + +package org.chromium.chrome.browser.omnibox.suggestions; + +import androidx.annotation.IntDef; +import androidx.annotation.VisibleForTesting; + +import org.chromium.base.MathUtils; +import org.chromium.build.annotations.NullMarked; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.OptionalInt; + +/** + * Helper class allowing advancing forward/backward while saturating outside the valid range. + * + * <p>TODO(344930378): Explore possibility to reconcile this with RecyclerViewSelectionController. + * The two classes serve similar purpose, but the complexity of view recycling may make the merge + * difficult. This controller expands RVSC capabilities, however the following aspects make + * immediate merge difficult: - volume of items changing at runtime, - exposure triggering (to + * ensure we can locate views for items not currently bound), - reused views propagate the selected + * state when rebound to a different item, + * + * <p>Consider adding WRAPPING and WRAPPING_WITH_SENTINEL variants to allow cycling through. + */ +@NullMarked +public class SelectionController { + /** + * Operational modes of the SelectionController + * + * <ul> + * <li>SATURATING: + * <ul> + * <li>forward: A -> B -> C -> C -> C + * <li>backward: C -> B -> A -> A -> A + * </ul> + * <li>SATURATING_WITH_SENTINEL: + * <ul> + * <li>forward: ∅- -> A -> B -> C -> ∅+ -> ∅+ + * <li>backward: ∅+ -> C -> B -> A -> ∅- -> ∅- + * </ul> + * </ul> + */ + @IntDef({Mode.SATURATING, Mode.SATURATING_WITH_SENTINEL}) + @Retention(RetentionPolicy.SOURCE) + @Target(ElementType.TYPE_USE) + public @interface Mode { + int SATURATING = 0; + int SATURATING_WITH_SENTINEL = 1; + } + + private final OnSelectionChangedListener mListener; + private final @Mode int mMode; + private final int mDefaultPosition; + private int mMaxPosition; + private int mPosition; + + @FunctionalInterface + public interface OnSelectionChangedListener { + /** + * Invoked whenever selected state at specific position changed. + * + * @param position the position to apply selection change to + * @param isSelected whether that position should be selected + * @return whether selection was applied at requested position + */ + boolean onSelectionChanged(int position, boolean isSelected); + } + + /** + * SelectionController constructor. + * + * @param listener the listener receiving notifications about selection changes + */ + public SelectionController(OnSelectionChangedListener listener, @Mode int mode) { + this(listener, 0, mode); + } + + /** + * SelectionController constructor. + * + * @param listener the listener receiving notifications about selection changes + * @param maxPosition the maximum valid position that can be reported to the listener + * @param mode Selection mode that defines how the controller will behave + */ + public SelectionController( + OnSelectionChangedListener listener, int maxPosition, @Mode int mode) { + assert maxPosition < Integer.MAX_VALUE; + assert maxPosition >= 0; + + switch (mode) { + case Mode.SATURATING: + mDefaultPosition = 0; + break; + + case Mode.SATURATING_WITH_SENTINEL: + default: + mDefaultPosition = -1; // Just before the first entry. + break; + } + + // Initialization step only, to ensure we do not emit bogus selection change event. + mPosition = Integer.MIN_VALUE; + mListener = listener; + mMode = mode; + updateMaxPosition(maxPosition); + } + + /** + * Update range of valid positions. + * + * @param maxPosition the upper value in the selection range (inclusive) + */ + public void updateMaxPosition(int maxPosition) { + if (!isParkedAtSentinel()) { + mListener.onSelectionChanged(mPosition, false); + } + + mMaxPosition = maxPosition; + mPosition = mDefaultPosition; + + if (!isParkedAtSentinel()) { + mListener.onSelectionChanged(mPosition, true); + } + } + + /** Resets the controller, making the current position point to default item. */ + public void reset() { + setPosition(mDefaultPosition); + } + + /** + * Advances the counter towards the maxPosition, returning false if the held value has + * saturated. + * + * @return whether selection was applied to the new element. + */ + public boolean advanceForward() { + return setPosition(mPosition + 1); + } + + /** + * Advances the counter towards the minPosition, returning false if the held value has + * saturated. + * + * @return whether selection was applied to the new element. + */ + public boolean advanceBack() { + return setPosition(mPosition - 1); + } + + /** Returns true if selection controller is currently parked outside the valid range. */ + public boolean isParkedAtSentinel() { + return mPosition < 0 || mPosition > mMaxPosition; + } + + /** Returns current counter value (unless saturated). */ + public OptionalInt getPosition() { + if (isParkedAtSentinel()) return OptionalInt.empty(); + return OptionalInt.of(mPosition); + } + + /** + * Set the new counter value, saturating it according to @Mode. + * + * @param newPosition - new value to apply to the mPosition + * @return whether selection was applied to the new element. + */ + @VisibleForTesting + boolean setPosition(int newPosition) { + if (!isParkedAtSentinel()) { + mListener.onSelectionChanged(mPosition, false); + } + + int oldPosition = mPosition; + mPosition = newPosition; + switch (mMode) { + case Mode.SATURATING: + mPosition = MathUtils.clamp(mPosition, 0, mMaxPosition); + break; + + case Mode.SATURATING_WITH_SENTINEL: + // Park outside the valid range, keeping the information which edge we hit. + mPosition = MathUtils.clamp(mPosition, -1, mMaxPosition + 1); + break; + } + + if (isParkedAtSentinel()) return false; + + // Select new item, fall back to old position if not possible. + if (!mListener.onSelectionChanged(mPosition, true)) { + mPosition = oldPosition; + mListener.onSelectionChanged(mPosition, true); + // We failed to select the requested entry. + return false; + } + + return true; + } +}
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SelectionControllerUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SelectionControllerUnitTest.java new file mode 100644 index 0000000..bc0d767 --- /dev/null +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/SelectionControllerUnitTest.java
@@ -0,0 +1,190 @@ +// 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. + +package org.chromium.chrome.browser.omnibox.suggestions; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.omnibox.suggestions.SelectionController.Mode; + +import java.util.OptionalInt; + +/** Robolectric unit tests for {@link SelectionController}. */ +@RunWith(BaseRobolectricTestRunner.class) +public class SelectionControllerUnitTest { + private static final int MAX_POSITION = 2; // Items 0‒2 inclusive. + + public @Rule MockitoRule mMockitoRule = MockitoJUnit.rule(); + private @Mock SelectionController.OnSelectionChangedListener mListener; + + @Before + public void setUp() { + // Allow selection changes to succeed unless explicitly overridden. + when(mListener.onSelectionChanged(anyInt(), eq(true))).thenReturn(true); + when(mListener.onSelectionChanged(anyInt(), eq(false))).thenReturn(true); + } + + private void verifyPositionReset(SelectionController c, int position) { + verify(mListener).onSelectionChanged(position, false); + assertEquals(OptionalInt.empty(), c.getPosition()); + assertTrue(c.isParkedAtSentinel()); + clearInvocations(mListener); + } + + private void verifyPositionSet(SelectionController c, int position) { + verify(mListener).onSelectionChanged(position, true); + assertEquals(OptionalInt.of(position), c.getPosition()); + assertFalse(c.isParkedAtSentinel()); + clearInvocations(mListener); + } + + private void verifyPositionChanged(SelectionController c, int from, int to) { + verify(mListener).onSelectionChanged(from, false); + verifyPositionSet(c, to); + } + + @Test + public void advanceForward_saturating() { + SelectionController c = new SelectionController(mListener, MAX_POSITION, Mode.SATURATING); + verifyPositionSet(c, 0); + + assertTrue(c.advanceForward()); + verifyPositionChanged(c, 0, 1); + + assertTrue(c.advanceForward()); + verifyPositionChanged(c, 1, 2); + + assertTrue(c.advanceForward()); + verifyPositionChanged(c, 2, 2); + + assertTrue(c.advanceForward()); + verifyPositionChanged(c, 2, 2); + } + + @Test + public void advanceForward_saturatingWithSentinel() { + SelectionController c = + new SelectionController(mListener, MAX_POSITION, Mode.SATURATING_WITH_SENTINEL); + assertTrue(c.isParkedAtSentinel()); + + assertTrue(c.advanceForward()); + verifyPositionSet(c, 0); + + assertTrue(c.advanceForward()); + verifyPositionChanged(c, 0, 1); + + assertTrue(c.advanceForward()); + verifyPositionChanged(c, 1, 2); + + assertFalse(c.advanceForward()); + verifyPositionReset(c, 2); + + assertFalse(c.advanceForward()); + verifyNoMoreInteractions(mListener); + } + + @Test + public void advanceBack_saturating() { + SelectionController c = new SelectionController(mListener, MAX_POSITION, Mode.SATURATING); + c.setPosition(MAX_POSITION); + verifyPositionChanged(c, 0, 2); + + assertTrue(c.advanceBack()); + verifyPositionChanged(c, 2, 1); + + assertTrue(c.advanceBack()); + verifyPositionChanged(c, 1, 0); + + assertTrue(c.advanceBack()); + verifyPositionChanged(c, 0, 0); + + assertTrue(c.advanceBack()); + verifyPositionChanged(c, 0, 0); + } + + @Test + public void advanceBack_saturatingWithSentinel() { + SelectionController c = + new SelectionController(mListener, MAX_POSITION, Mode.SATURATING_WITH_SENTINEL); + c.setPosition(MAX_POSITION); + verifyPositionSet(c, 2); + + assertTrue(c.advanceBack()); + verifyPositionChanged(c, 2, 1); + + assertTrue(c.advanceBack()); + verifyPositionChanged(c, 1, 0); + + assertFalse(c.advanceBack()); + verifyPositionReset(c, 0); + + assertFalse(c.advanceBack()); + verifyNoMoreInteractions(mListener); + } + + @Test + public void advanceForward_saturating_listenerReturnsFalse() { + when(mListener.onSelectionChanged(1, true)).thenReturn(false); + + SelectionController c = + new SelectionController( + mListener, MAX_POSITION, SelectionController.Mode.SATURATING); + verifyPositionSet(c, 0); + assertFalse(c.advanceForward()); + verifyPositionChanged(c, 0, 0); + } + + @Test + public void updateMaxPosition() { + SelectionController c = new SelectionController(mListener, MAX_POSITION, Mode.SATURATING); + verifyPositionSet(c, 0); + + // Grow list of items + c.updateMaxPosition(4); + verifyPositionSet(c, 0); + + assertTrue(c.advanceForward()); // Should now reach index 4 without saturating + verifyPositionChanged(c, 0, 1); + assertTrue(c.advanceForward()); // 2 + verifyPositionChanged(c, 1, 2); + assertTrue(c.advanceForward()); // 3 + verifyPositionChanged(c, 2, 3); + assertTrue(c.advanceForward()); // 4 + verifyPositionChanged(c, 3, 4); + + // Shrink list of items + c.updateMaxPosition(2); + verifyPositionSet(c, 0); + } + + @Test + public void reset_saturating() { + SelectionController c = new SelectionController(mListener, MAX_POSITION, Mode.SATURATING); + verifyPositionSet(c, 0); + + c.advanceForward(); // 1 + verifyPositionChanged(c, 0, 1); + c.advanceForward(); // 2 + verifyPositionChanged(c, 1, 2); + c.reset(); // back to default (0) + verifyPositionChanged(c, 2, 0); + } +}
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionView.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionView.java index 8449f13..848b140 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionView.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionView.java
@@ -13,17 +13,21 @@ import androidx.annotation.LayoutRes; import androidx.annotation.VisibleForTesting; +import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.widget.AppCompatImageView; import org.chromium.build.annotations.CheckDiscard; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; +import org.chromium.chrome.browser.omnibox.R; +import org.chromium.chrome.browser.omnibox.suggestions.SelectionController; import org.chromium.chrome.browser.util.KeyNavigationUtil; import org.chromium.components.browser_ui.widget.RoundedCornerOutlineProvider; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.OptionalInt; /** * Base layout for common suggestion types. Includes support for a configurable suggestion content @@ -39,6 +43,7 @@ public final RoundedCornerOutlineProvider decorationIconOutline; private final List<ImageView> mActionButtons; private Optional<Runnable> mOnFocusViaSelectionListener = Optional.empty(); + private @Nullable SelectionController mActionButtonsHighlighter; /** * Constructs a new suggestion view and inflates supplied layout as the contents view. @@ -95,6 +100,15 @@ } else if (currentViewCount > desiredViewCount) { decreaseActionButtonsCount(desiredViewCount); } + + mActionButtonsHighlighter = null; + if (desiredViewCount > 0) { + mActionButtonsHighlighter = + new SelectionController( + this::highlightActionButton, + desiredViewCount - 1, + SelectionController.Mode.SATURATING_WITH_SENTINEL); + } } /** @@ -105,6 +119,24 @@ } /** + * Applies / removes selection hairline from action button. + * + * @param buttonIndex the index of an action button + * @param isSelected whether to apply hairline + * @return the highlight state of the specified action button. + */ + private boolean highlightActionButton(int buttonIndex, boolean isHighlighted) { + mActionButtons + .get(buttonIndex) + .setForeground( + isHighlighted + ? AppCompatResources.getDrawable( + getContext(), R.drawable.hairline_circle) + : null); + return isHighlighted; + } + + /** * Create additional action buttons for the suggestion view. * * @param desiredViewCount Desired number of action buttons. @@ -141,8 +173,31 @@ // navigation. if (actionChipsView.onKeyDown(keyCode, event)) return true; if (KeyNavigationUtil.isEnter(event)) { + if (mActionButtonsHighlighter != null + && !mActionButtonsHighlighter.isParkedAtSentinel()) { + OptionalInt selection = mActionButtonsHighlighter.getPosition(); + return mActionButtons.get(selection.getAsInt()).performClick(); + } return performClick(); } + + // Allow browsing through right hand side buttons. + if (keyCode == KeyEvent.KEYCODE_TAB) { + if (!event.isShiftPressed()) { + // Pass the TAB key to Action Buttons, then to Action Chips. + if (mActionButtonsHighlighter != null + && mActionButtonsHighlighter.advanceForward()) { + return true; + } + return super_onKeyDown(keyCode, event); + } else { + // Pass the TAB key to Action Chips, then to Action Buttons. + if (super_onKeyDown(keyCode, event)) return true; + return (mActionButtonsHighlighter != null + && mActionButtonsHighlighter.advanceBack()); + } + } + return super_onKeyDown(keyCode, event); } @@ -155,6 +210,7 @@ @Override public void setSelected(boolean selected) { super.setSelected(selected); + if (mActionButtonsHighlighter != null) mActionButtonsHighlighter.reset(); if (selected) mOnFocusViaSelectionListener.ifPresent(Runnable::run); }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinder.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinder.java index e3db3989..3902f73 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinder.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinder.java
@@ -215,6 +215,7 @@ final List<ImageView> actionViews = view.getActionButtons(); for (int index = 0; index < actionViews.size(); index++) { ImageView actionView = actionViews.get(index); + applySelectableBackground(model, actionView); updateIcon( actionView, @@ -348,6 +349,7 @@ } view.setImageDrawable(sds.drawable); + view.setForegroundTintList(tint); ImageViewCompat.setImageTintList(view, tint); }
diff --git a/chrome/browser/ui/android/toolbar/BUILD.gn b/chrome/browser/ui/android/toolbar/BUILD.gn index a4c053f..8de9b93 100644 --- a/chrome/browser/ui/android/toolbar/BUILD.gn +++ b/chrome/browser/ui/android/toolbar/BUILD.gn
@@ -64,6 +64,8 @@ "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManager.java", "java/src/org/chromium/chrome/browser/toolbar/home_button/HomeButton.java", "java/src/org/chromium/chrome/browser/toolbar/home_button/HomeButtonCoordinator.java", + "java/src/org/chromium/chrome/browser/toolbar/home_page_button/HomePageButtonView.java", + "java/src/org/chromium/chrome/browser/toolbar/home_page_button/HomePageButtonsContainerView.java", "java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressCoordinator.java", "java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediator.java", "java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressProperties.java", @@ -320,6 +322,7 @@ "java/res/layout/bottom_control_container.xml", "java/res/layout/control_container.xml", "java/res/layout/extension_toolbar_container.xml", + "java/res/layout/home_page_buttons_layout.xml", "java/res/layout/menu_button.xml", "java/res/layout/navigation_popup_item.xml", "java/res/layout/optional_button_layout.xml",
diff --git a/chrome/browser/ui/android/toolbar/java/res/layout/home_page_buttons_layout.xml b/chrome/browser/ui/android/toolbar/java/res/layout/home_page_buttons_layout.xml new file mode 100644 index 0000000..cce9f33 --- /dev/null +++ b/chrome/browser/ui/android/toolbar/java/res/layout/home_page_buttons_layout.xml
@@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +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. +--> + +<org.chromium.chrome.browser.toolbar.home_page_button.HomePageButtonsContainerView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/home_page_buttons_layout" + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:orientation="horizontal"> + + <org.chromium.chrome.browser.toolbar.home_page_button.HomePageButtonView + android:id="@+id/home_button" + android:src="@drawable/btn_toolbar_home" + android:contentDescription="@string/accessibility_toolbar_btn_home" + android:tooltipText="@string/accessibility_toolbar_btn_home" + style="@style/ToolbarHoverableButton" + android:visibility="gone" + app:menuVerticalOverlapAnchor="false" + app:menuMaxWidth="@dimen/home_button_list_menu_width" + app:menuPositionedAtStart="true" + app:tint="@color/default_icon_color_tint_list" /> + + <org.chromium.chrome.browser.toolbar.home_page_button.HomePageButtonView + android:id="@+id/ntp_customization_button" + android:src="@drawable/edit_icon" + android:contentDescription="@string/ntp_customization_title" + style="@style/ToolbarHoverableButton" + android:visibility="gone" + app:tint="@color/default_icon_color_tint_list" /> + +</org.chromium.chrome.browser.toolbar.home_page_button.HomePageButtonsContainerView> \ No newline at end of file
diff --git a/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_phone.xml b/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_phone.xml index 7987b2df..592005f 100644 --- a/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_phone.xml +++ b/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_phone.xml
@@ -27,6 +27,13 @@ app:menuPositionedAtStart="true" app:tint="@color/default_icon_color_tint_list" /> + <ViewStub + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:id="@+id/home_page_buttons_stub" + android:layout="@layout/home_page_buttons_layout" + android:visibility="gone" /> + <org.chromium.chrome.browser.omnibox.LocationBarPhone android:id="@+id/location_bar" android:layout_width="match_parent"
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarButtonController.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarButtonController.java index 7d0890f..a00f865 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarButtonController.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarButtonController.java
@@ -41,6 +41,7 @@ import org.chromium.chrome.browser.toolbar.R; import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarStatePredictor.UiState; import org.chromium.chrome.browser.toolbar.adaptive.settings.AdaptiveToolbarSettingsFragment; +import org.chromium.chrome.browser.toolbar.optional_button.BaseButtonDataProvider; import org.chromium.chrome.browser.toolbar.optional_button.ButtonData; import org.chromium.chrome.browser.toolbar.optional_button.ButtonData.ButtonSpec; import org.chromium.chrome.browser.toolbar.optional_button.ButtonDataImpl; @@ -178,6 +179,20 @@ mButtonDataProviderMap.put(variant, buttonProvider); } + /** + * Invoke Price Insights UI. TODO(crbug.com/391931899): Consider making this method generic to + * support other button variants. + */ + public void runPriceInsightsAction() { + var buttonDataProvider = + mButtonDataProviderMap.get(AdaptiveToolbarButtonVariant.PRICE_INSIGHTS); + if (buttonDataProvider instanceof BaseButtonDataProvider toolbarButtonProvider) { + toolbarButtonProvider.onClick(new View(mContext)); // Param is not used. + } else { + assert false : "PriceInsightButtonController must inherit BaseButtonDataProvider!"; + } + } + @Override // Suppress to observe SharedPreferences, which is discouraged; use another messaging channel // instead.
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/home_page_button/HomePageButtonView.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/home_page_button/HomePageButtonView.java new file mode 100644 index 0000000..ba3d365 --- /dev/null +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/home_page_button/HomePageButtonView.java
@@ -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. + +package org.chromium.chrome.browser.toolbar.home_page_button; + +import android.content.Context; +import android.util.AttributeSet; + +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; +import org.chromium.ui.listmenu.ListMenuButton; + +/** The home page button. */ +@NullMarked +public class HomePageButtonView extends ListMenuButton { + public HomePageButtonView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } +}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/home_page_button/HomePageButtonsContainerView.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/home_page_button/HomePageButtonsContainerView.java new file mode 100644 index 0000000..4dda09c --- /dev/null +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/home_page_button/HomePageButtonsContainerView.java
@@ -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. + +package org.chromium.chrome.browser.toolbar.home_page_button; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.LinearLayout; + +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; + +/** The container of the two home page buttons. */ +@NullMarked +public class HomePageButtonsContainerView extends LinearLayout { + public HomePageButtonsContainerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } +}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/home_page_button/OWNERS b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/home_page_button/OWNERS new file mode 100644 index 0000000..e153613 --- /dev/null +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/home_page_button/OWNERS
@@ -0,0 +1,2 @@ +hanxi@chromium.org +xinyiji@chromium.org \ No newline at end of file
diff --git a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediator.java b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediator.java index 6870815..52772d7 100644 --- a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediator.java +++ b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediator.java
@@ -44,7 +44,6 @@ private final ScrimManager mScrimManager; private final Supplier<List<Rect>> mNonDraggableAreasSupplier; private final ObservableSupplierImpl<Integer> mWidthSupplier; - private final Callback<Integer> mOnWidthChangedCallback; private final ThemeColorProvider mThemeColorProvider; private final int mWebAppMinHeaderHeight; private @Nullable AppHeaderState mCurrentHeaderState; @@ -96,12 +95,10 @@ mWidthSupplier = new ObservableSupplierImpl<>(); mAppHeaderUnoccludedWidthSupplier = new ObservableSupplierImpl<>(); - mOnWidthChangedCallback = (width) -> updateNonDraggableAreas(); - mWidthSupplier.addObserver(mOnWidthChangedCallback); mModel = model; // View should notify us about initial width. - mModel.set(WebAppHeaderLayoutProperties.WIDTH_CHANGED_CALLBACK, mWidthSupplier::set); + mModel.set(WebAppHeaderLayoutProperties.WIDTH_CHANGED_CALLBACK, this::onLayoutWidthUpdated); final var appHeaderState = desktopWindowStateManager.getAppHeaderState(); if (appHeaderState != null) { @@ -113,6 +110,13 @@ mThemeColorProvider.addThemeColorObserver(this); } + private void onLayoutWidthUpdated(int width) { + mWidthSupplier.set(width); + + // Update draggable area even if width hasn't changed, because children might've changed. + updateNonDraggableAreas(); + } + @Override public void onThemeColorChanged(int color, boolean shouldAnimate) { mDesktopWindowStateManager.updateForegroundColor(color); @@ -166,7 +170,9 @@ } final var areas = mNonDraggableAreasSupplier.get(); - mModel.set(WebAppHeaderLayoutProperties.NON_DRAGGABLE_AREAS, areas); + mModel.set( + WebAppHeaderLayoutProperties.NON_DRAGGABLE_AREAS, + areas == null || areas.isEmpty() ? List.of(EMPTY_NON_DRAGGABLE_AREA) : areas); } /** Navigates back in the navigation history of the current {@link Tab}. */ @@ -190,7 +196,6 @@ /** Destroys the mediator, existing instance is not usable after this method is called */ public void destroy() { mDesktopWindowStateManager.removeObserver(this); - mWidthSupplier.removeObserver(mOnWidthChangedCallback); mThemeColorProvider.removeThemeColorObserver(this); mScrimManager.getScrimVisibilitySupplier().removeObserver(mScrimVisibilityObserver); }
diff --git a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediatorTest.java b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediatorTest.java index 343a25e..88f14f61 100644 --- a/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediatorTest.java +++ b/chrome/browser/ui/android/web_app_header/java/src/org/chromium/chrome/browser/ui/web_app_header/WebAppHeaderLayoutMediatorTest.java
@@ -282,7 +282,10 @@ public void testInDWButNotInWindow_AllAreaIsDraggable() { setupDesktopWindowing(/* isInDesktopWindow= */ false, WIDEST_UNOCCLUDED_RECT); + final var nonDraggableAreas = List.of(new Rect(0, 0, 10, 10), new Rect(10, 0, 10, 10)); + mNonDraggableAreasSupplier.set(nonDraggableAreas); mMediator.onAppHeaderStateChanged(mAppHeaderState); + mModel.get(WebAppHeaderLayoutProperties.WIDTH_CHANGED_CALLBACK).onResult(SCREEN_WIDTH); final var areas = mModel.get(WebAppHeaderLayoutProperties.NON_DRAGGABLE_AREAS); @@ -313,6 +316,38 @@ } @Test + public void testInDwLayoutStructureChanges_SetNonDraggableAreaOnEachUpdate() { + setupDesktopWindowing(/* isInDesktopWindow= */ true, WIDEST_UNOCCLUDED_RECT); + + // Setup layout without children. + final List<Rect> initialNonDraggableArea = List.of(); + mNonDraggableAreasSupplier.set(initialNonDraggableArea); + mMediator.onAppHeaderStateChanged(mAppHeaderState); + mModel.get(WebAppHeaderLayoutProperties.WIDTH_CHANGED_CALLBACK).onResult(SCREEN_WIDTH); + + // Verify area is empty. + var areas = mModel.get(WebAppHeaderLayoutProperties.NON_DRAGGABLE_AREAS); + assertEquals("There should be only one area in the list", 1, areas.size()); + assertEquals( + "The area should be an empty area that allows to drag everywhere", + new Rect(0, 0, 0, 0), + areas.get(0)); + + // Children has laid out and layout update is sent with the same width. + final var nonDraggableAreas = List.of(new Rect(0, 0, 10, 10), new Rect(10, 0, 10, 10)); + mNonDraggableAreasSupplier.set(nonDraggableAreas); + mModel.get(WebAppHeaderLayoutProperties.WIDTH_CHANGED_CALLBACK).onResult(SCREEN_WIDTH); + + // Verify non-draggable area is updated. + areas = mModel.get(WebAppHeaderLayoutProperties.NON_DRAGGABLE_AREAS); + assertEquals("There should be only 2 non draggable areas", 2, areas.size()); + assertArrayEquals( + "Non draggable areas from supplier should match model areas", + areas.toArray(), + mModel.get(WebAppHeaderLayoutProperties.NON_DRAGGABLE_AREAS).toArray()); + } + + @Test public void testSetInitialTheme() { setupDesktopWindowing(/* isInDesktopWindow= */ true, WIDEST_UNOCCLUDED_RECT); assertEquals(
diff --git a/chrome/browser/ui/ash/in_session_auth/BUILD.gn b/chrome/browser/ui/ash/in_session_auth/BUILD.gn index 4ab90452..7d27315ae 100644 --- a/chrome/browser/ui/ash/in_session_auth/BUILD.gn +++ b/chrome/browser/ui/ash/in_session_auth/BUILD.gn
@@ -49,6 +49,7 @@ "//base/test:test_support", "//chrome/browser/ash/login/users:test_support", "//chrome/browser/ash/profiles", + "//chrome/test:test_support", "//chromeos/ash/components/cryptohome", "//chromeos/ash/components/dbus/userdataauth", "//chromeos/ash/components/install_attributes:test_support",
diff --git a/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client.cc b/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client.cc index 3bcb2c3..c810ecff 100644 --- a/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client.cc +++ b/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client.cc
@@ -8,9 +8,11 @@ #include "ash/constants/ash_features.h" #include "ash/public/cpp/webauthn_dialog_controller.h" +#include "base/check_deref.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/logging.h" +#include "base/memory/raw_ref.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ash/auth/cryptohome_pin_engine.h" #include "chrome/browser/ash/auth/legacy_fingerprint_engine.h" @@ -38,6 +40,8 @@ using ::ash::Key; using ::ash::UserContext; +class PrefService; + namespace { const char kInSessionAuthHelpPageUrl[] = @@ -47,8 +51,9 @@ } // namespace -InSessionAuthDialogClient::InSessionAuthDialogClient() - : auth_performer_(ash::UserDataAuthClient::Get()) { +InSessionAuthDialogClient::InSessionAuthDialogClient(PrefService* local_state) + : local_state_(CHECK_DEREF(local_state)), + auth_performer_(ash::UserDataAuthClient::Get()) { ash::WebAuthNDialogController::Get()->SetClient(this); DCHECK(!g_auth_dialog_client_instance); @@ -274,7 +279,7 @@ // Take temporary ownership of user_context to pass on later. user_context_ = std::move(user_context); - pin_engine_.emplace(&auth_performer_); + pin_engine_.emplace(&local_state_.get(), &auth_performer_); legacy_fingerprint_engine_.emplace(&auth_performer_); std::move(callback).Run(true); }
diff --git a/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client.h b/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client.h index 85322b4..a70f374e 100644 --- a/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client.h +++ b/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client.h
@@ -12,6 +12,7 @@ #include "ash/public/cpp/in_session_auth_dialog_client.h" #include "base/functional/callback.h" #include "base/functional/callback_forward.h" +#include "base/memory/raw_ref.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" @@ -32,6 +33,7 @@ } class AccountId; +class PrefService; // Handles method calls sent from Ash to ChromeOS. class InSessionAuthDialogClient @@ -43,7 +45,7 @@ using FingerprintScanDoneCallback = base::OnceCallback<void(bool, ash::FingerprintState)>; - InSessionAuthDialogClient(); + explicit InSessionAuthDialogClient(PrefService* local_state); InSessionAuthDialogClient(const InSessionAuthDialogClient&) = delete; InSessionAuthDialogClient& operator=(const InSessionAuthDialogClient&) = delete; @@ -139,6 +141,8 @@ bool is_pin_auth_available, std::unique_ptr<ash::UserContext> user_context); + const raw_ref<PrefService> local_state_; + // State associated with a pending authentication attempt. std::optional<AuthState> pending_auth_state_;
diff --git a/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client_unittest.cc b/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client_unittest.cc index ad24c20c..7d3a38b 100644 --- a/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client_unittest.cc +++ b/chrome/browser/ui/ash/in_session_auth/in_session_auth_dialog_client_unittest.cc
@@ -13,6 +13,8 @@ #include "base/test/bind.h" #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" #include "chrome/browser/ash/profiles/profile_helper.h" +#include "chrome/test/base/scoped_testing_local_state.h" +#include "chrome/test/base/testing_browser_process.h" #include "chromeos/ash/components/cryptohome/system_salt_getter.h" #include "chromeos/ash/components/dbus/userdataauth/fake_cryptohome_misc_client.h" #include "chromeos/ash/components/dbus/userdataauth/fake_userdataauth_client.h" @@ -68,7 +70,8 @@ ash::CryptohomeMiscClient::InitializeFake(); ash::SystemSaltGetter::Initialize(); - client_ = std::make_unique<InSessionAuthDialogClient>(); + client_ = std::make_unique<InSessionAuthDialogClient>( + TestingBrowserProcess::GetGlobal()->local_state()); } ~InSessionAuthDialogClientTest() override { @@ -129,6 +132,9 @@ protected: const content::BrowserTaskEnvironment task_environment_; + ScopedTestingLocalState scoped_testing_local_state_{ + TestingBrowserProcess::GetGlobal()}; + ash::ScopedStubInstallAttributes install_attributes{ ash::StubInstallAttributes::CreateConsumerOwned()}; user_manager::TypedScopedUserManager<ash::FakeChromeUserManager>
diff --git a/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc index 84a6c8ff..76d2c03 100644 --- a/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc +++ b/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc
@@ -262,8 +262,8 @@ ash::input_method::InputMethodManager::Get()); ime_controller_client_->Init(); - in_session_auth_dialog_client_ = - std::make_unique<InSessionAuthDialogClient>(); + in_session_auth_dialog_client_ = std::make_unique<InSessionAuthDialogClient>( + g_browser_process->local_state()); in_session_auth_token_provider_ = std::make_unique<ash::InSessionAuthTokenProviderImpl>();
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc index cba18b8..a8c2c69 100644 --- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc +++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc
@@ -1248,12 +1248,12 @@ registration_waiter.AwaitRegistration(); // Install PWA. - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(true); + auto auto_accept_pwa_install_confirmation = + web_app::SetAutoAcceptPWAInstallConfirmationForTesting(); web_app::WebAppTestInstallWithOsHooksObserver install_observer(profile()); install_observer.BeginListening(); chrome::ExecuteCommand(browser(), IDC_INSTALL_PWA); const webapps::AppId app_id = install_observer.Wait(); - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(false); // Find the native window for the app. gfx::NativeWindow native_window = gfx::NativeWindow(); @@ -2445,12 +2445,12 @@ ASSERT_TRUE(AddTabAtIndex(1, url, ui::PAGE_TRANSITION_LINK)); registration_waiter.AwaitRegistration(); // Install PWA. - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(true); + auto auto_accept_pwa_install_confirmation = + web_app::SetAutoAcceptPWAInstallConfirmationForTesting(); web_app::WebAppTestInstallWithOsHooksObserver install_observer(profile()); install_observer.BeginListening(); chrome::ExecuteCommand(browser(), IDC_INSTALL_PWA); const webapps::AppId app_id = install_observer.Wait(); - web_app::SetAutoAcceptPWAInstallConfirmationForTesting(false); ash::ShelfID shelf_id(app_id); EXPECT_FALSE(ChromeShelfController::instance()->IsPinned(shelf_id));
diff --git a/chrome/browser/ui/autofill/BUILD.gn b/chrome/browser/ui/autofill/BUILD.gn index 2d8dedc..0b6dfb7d 100644 --- a/chrome/browser/ui/autofill/BUILD.gn +++ b/chrome/browser/ui/autofill/BUILD.gn
@@ -135,6 +135,7 @@ "//chrome/browser/ui/autofill/payments", "//chrome/browser/ui/hats", "//chrome/browser/ui/page_info", + "//chrome/browser/ui/plus_addresses", "//components/autofill/content/browser", "//components/autofill/content/browser:risk_proto", "//components/compose/core/browser",
diff --git a/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc b/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc index 8eb7a34a0..bde58b88 100644 --- a/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc +++ b/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc
@@ -27,7 +27,6 @@ #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/simple_message_box.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_model.h" #include "chrome/grit/branded_strings.h" @@ -36,6 +35,7 @@ #include "components/bookmarks/browser/bookmark_node.h" #include "components/bookmarks/browser/bookmark_utils.h" #include "components/tab_groups/tab_group_id.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/page_navigator.h" #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 30f168f3..2f0de74 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -1229,7 +1229,7 @@ /*navigation_handle_callback=*/{}); } -const SessionID& Browser::GetSessionID() { +const SessionID& Browser::GetSessionID() const { return session_id_; }
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index 9841afe..c28ef87 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -868,7 +868,7 @@ const content::OpenURLParams& params, base::OnceCallback<void(content::NavigationHandle&)> navigation_handle_callback) override; - const SessionID& GetSessionID() override; + const SessionID& GetSessionID() const override; TabStripModel* GetTabStripModel() override; bool IsTabStripVisible() override; bool ShouldHideUIForFullscreen() const override;
diff --git a/chrome/browser/ui/browser_actions.cc b/chrome/browser/ui/browser_actions.cc index 38faf66..98fe0ca 100644 --- a/chrome/browser/ui/browser_actions.cc +++ b/chrome/browser/ui/browser_actions.cc
@@ -669,9 +669,12 @@ actions::ActionInvocationContext context) { // TODO(crbug.com/356468503): Figure out how to capture // action invocation location. - browser->browser_window_features() - ->cast_browser_controller() - ->ToggleDialog(); + auto* cast_browser_controller = + browser->browser_window_features() + ->cast_browser_controller(); + if (cast_browser_controller) { + cast_browser_controller->ToggleDialog(); + } }, base::Unretained(browser)), kActionRouteMedia, IDS_MEDIA_ROUTER_MENU_ITEM_TITLE,
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc index 3987c0ee..488381a2 100644 --- a/chrome/browser/ui/browser_commands.cc +++ b/chrome/browser/ui/browser_commands.cc
@@ -96,7 +96,6 @@ #include "chrome/browser/ui/tabs/organization/tab_organization_service_factory.h" #include "chrome/browser/ui/tabs/organization/tab_organization_session.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_model.h" @@ -157,6 +156,8 @@ #include "components/sessions/core/tab_restore_service.h" #include "components/tab_groups/tab_group_id.h" #include "components/tab_groups/tab_group_visual_data.h" +#include "components/tabs/public/split_tab_visual_data.h" +#include "components/tabs/public/tab_interface.h" #include "components/translate/core/browser/language_state.h" #include "components/translate/core/browser/translate_manager.h" #include "components/user_education/common/feature_promo/feature_promo_controller.h" @@ -980,6 +981,30 @@ void CloseTab(Browser* browser) { base::RecordAction(UserMetricsAction("CloseTab_Accelerator")); + + if (!toast_features::IsEnabled(toast_features::kPinnedTabToastOnClose)) { + browser->tab_strip_model()->CloseSelectedTabs(); + return; + } + + ToastController* toast_controller = browser->GetFeatures().toast_controller(); + if (!toast_controller) { + browser->tab_strip_model()->CloseSelectedTabs(); + return; + } + + tabs::TabInterface* tab = browser->tab_strip_model()->GetActiveTab(); + bool single_tab_selected = + browser->tab_strip_model()->selection_model().size() == 1; + if (tab->IsPinned() && single_tab_selected) { + // Pinned tabs should show a toast asking the user to continue holding the + // command for some time before a pinned tab is closed. The toast will + // handle the call to TabStripModel::CloseSelectedTabs so we don't need to + // handle it here. + toast_controller->MaybeShowToast(ToastParams(ToastId::kClosePinnedTab)); + return; + } + browser->tab_strip_model()->CloseSelectedTabs(); }
diff --git a/chrome/browser/ui/browser_tab_strip_model_delegate.cc b/chrome/browser/ui/browser_tab_strip_model_delegate.cc index 63e325c..a19d5014 100644 --- a/chrome/browser/ui/browser_tab_strip_model_delegate.cc +++ b/chrome/browser/ui/browser_tab_strip_model_delegate.cc
@@ -27,7 +27,6 @@ #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.h" #include "chrome/browser/ui/tabs/tab_group_model.h" @@ -46,6 +45,7 @@ #include "components/sessions/core/session_id.h" #include "components/sessions/core/tab_restore_service.h" #include "components/tab_groups/tab_group_id.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h"
diff --git a/chrome/browser/ui/browser_window/public/browser_window_interface.h b/chrome/browser/ui/browser_window/public/browser_window_interface.h index 457cde1..8fda121 100644 --- a/chrome/browser/ui/browser_window/public/browser_window_interface.h +++ b/chrome/browser/ui/browser_window/public/browser_window_interface.h
@@ -78,7 +78,7 @@ WindowOpenDisposition disposition) = 0; // Returns a session-unique ID. - virtual const SessionID& GetSessionID() = 0; + virtual const SessionID& GetSessionID() const = 0; virtual TabStripModel* GetTabStripModel() = 0;
diff --git a/chrome/browser/ui/browser_window/test/mock_browser_window_interface.h b/chrome/browser/ui/browser_window/test/mock_browser_window_interface.h index ddb2088..1b52a92 100644 --- a/chrome/browser/ui/browser_window/test/mock_browser_window_interface.h +++ b/chrome/browser/ui/browser_window/test/mock_browser_window_interface.h
@@ -19,7 +19,7 @@ OpenGURL, (const GURL& gurl, WindowOpenDisposition disposition), (override)); - MOCK_METHOD(const SessionID&, GetSessionID, (), (override)); + MOCK_METHOD(const SessionID&, GetSessionID, (), (const override)); MOCK_METHOD(TabStripModel*, GetTabStripModel, (), (override)); MOCK_METHOD(bool, IsTabStripVisible, (), (override)); MOCK_METHOD(bool, ShouldHideUIForFullscreen, (), (const, override));
diff --git a/chrome/browser/ui/lens/lens_preselection_bubble.cc b/chrome/browser/ui/lens/lens_preselection_bubble.cc index d0c99135..e13ffcf 100644 --- a/chrome/browser/ui/lens/lens_preselection_bubble.cc +++ b/chrome/browser/ui/lens/lens_preselection_bubble.cc
@@ -65,7 +65,7 @@ set_close_on_deactivate(false); DialogDelegate::SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone)); set_corner_radius(48); - set_background_color(kColorLensOverlayToastBackground); + SetBackgroundColor(kColorLensOverlayToastBackground); SetProperty(views::kElementIdentifierKey, kLensPreselectionBubbleElementId); SetAccessibleWindowRole(ax::mojom::Role::kAlertDialog); SetCancelCallback(std::move(on_cancel_callback));
diff --git a/chrome/browser/ui/plus_addresses/BUILD.gn b/chrome/browser/ui/plus_addresses/BUILD.gn new file mode 100644 index 0000000..174e46a4 --- /dev/null +++ b/chrome/browser/ui/plus_addresses/BUILD.gn
@@ -0,0 +1,143 @@ +# 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. + +import("//build/config/ui.gni") + +assert(toolkit_views || is_android) + +# TODO(crbug.com/413572035): Pull in android and views impl and test code. + +source_set("plus_addresses") { + sources = [ + "plus_address_creation_controller.h", + "plus_address_creation_view.h", + ] + + public_deps = [ + "//components/plus_addresses:types", + "//content/public/browser", + "//ui/base", + "//url", + ] + + if (toolkit_views) { + sources += [ + "plus_address_creation_controller_desktop.h", + "plus_address_error_dialog.h", + "plus_address_menu_model.h", + ] + + public_deps += [ + "//base", + "//components/autofill/core/browser", + "//components/autofill/core/common", + "//components/plus_addresses/metrics", + "//components/plus_addresses/settings", + "//ui/menus", + ] + + deps = [ + "//components/constrained_window", + "//components/plus_addresses/resources/strings", + "//components/plus_addresses/resources/strings:strings_grit", + ] + } +} + +source_set("impl") { + sources = [] + public_deps = [ + "//chrome/browser:browser_public_dependencies", + "//components/plus_addresses:types", + "//content/public/browser", + "//ui/base", + "//url", + ] + + if (toolkit_views) { + sources += [ + "plus_address_error_dialog.cc", + "plus_address_menu_model.cc", + ] + + public_deps += [ + "//base", + "//components/autofill/core/browser", + "//components/autofill/core/common", + "//components/plus_addresses/metrics", + "//components/plus_addresses/settings", + "//ui/menus", + ] + + deps = [ + ":plus_addresses", + "//components/constrained_window", + "//components/plus_addresses/resources/strings", + "//components/plus_addresses/resources/strings:strings_grit", + ] + } +} + +source_set("interactive_ui_tests") { + testonly = true + sources = [] + + if (!is_android && !is_chromeos_device) { + sources += [ + "plus_address_error_dialog_interactive_uitest.cc", + "views/plus_address_creation_dialog_interactive_uitest.cc", + ] + defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + deps = [ + ":plus_addresses", + "//base", + "//base/test:test_support", + "//chrome/browser/plus_addresses", + "//chrome/test:test_support", + "//chrome/test:test_support_ui", + "//components/plus_addresses:test_support", + "//components/plus_addresses/resources/strings:strings_grit", + "//components/plus_addresses/settings:test_support", + "//components/signin/public/identity_manager:test_support", + "//components/sync:test_support", + "//content/test:test_support", + "//ui/views:test_support", + ] + } +} + +source_set("unit_tests") { + testonly = true + sources = [] + + if (!is_android) { + sources += [ + "plus_address_creation_controller_desktop_unittest.cc", + "plus_address_menu_model_unittest.cc", + ] + deps = [ + ":plus_addresses", + "//base", + "//base/test:test_support", + "//chrome/browser/plus_addresses", + "//chrome/browser/ui/hats", + "//chrome/test:test_support", + "//components/autofill/content/browser:test_support", + "//components/autofill/core/common", + "//components/plus_addresses", + "//components/plus_addresses:features", + "//components/plus_addresses:prefs", + "//components/plus_addresses:test_support", + "//components/plus_addresses:types", + "//components/plus_addresses/metrics", + "//components/plus_addresses/settings:test_support", + "//components/signin/public/identity_manager:test_support", + "//components/sync_preferences:test_support", + "//content/public/browser", + "//content/test:test_support", + "//testing/gmock", + "//testing/gtest", + ] + } +}
diff --git a/chrome/browser/ui/tabs/BUILD.gn b/chrome/browser/ui/tabs/BUILD.gn index 74e3e358..912c65f 100644 --- a/chrome/browser/ui/tabs/BUILD.gn +++ b/chrome/browser/ui/tabs/BUILD.gn
@@ -255,11 +255,8 @@ "pinned_tab_codec.h", "pinned_tab_service.h", "pinned_tab_service_factory.h", - "split_tab_collection.h", - "split_tab_data.h", "split_tab_menu_model.h", "split_tab_util.h", - "split_tab_visual_data.h", "tab_collection_node.h", "tab_renderer_data.h", "tab_style.h", @@ -309,11 +306,8 @@ "pinned_tab_service.cc", "pinned_tab_service_factory.cc", "recent_tabs_sub_menu_model.cc", - "split_tab_collection.cc", - "split_tab_data.cc", "split_tab_menu_model.cc", "split_tab_util.cc", - "split_tab_visual_data.cc", "tab_collection_node.cc", "tab_dialog_manager.cc", "tab_features.cc",
diff --git a/chrome/browser/ui/tabs/public/tab_dialog_manager.h b/chrome/browser/ui/tabs/public/tab_dialog_manager.h index 5106dfc5..82bb4fe 100644 --- a/chrome/browser/ui/tabs/public/tab_dialog_manager.h +++ b/chrome/browser/ui/tabs/public/tab_dialog_manager.h
@@ -51,12 +51,14 @@ // TODO(kylixrd): // (1) Call-sites expect to own the Widget using CLIENT_OWNS_WIDGET and be // updated accordingly. - void ShowDialogAndBlockTabInteraction(views::Widget* dialog); + void ShowDialogAndBlockTabInteraction(views::Widget* dialog, + bool close_on_navigation = true); // Combines the above two functions into a single invocation. This is the most // commonly used version. Only use the other APIs if the caller must do // something unique to the Widget before showing it. std::unique_ptr<views::Widget> CreateShowDialogAndBlockTabInteraction( - views::DialogDelegate* delegate); + views::DialogDelegate* delegate, + bool close_on_navigation = true); void CloseDialog(); @@ -90,6 +92,8 @@ std::unique_ptr<TabDialogWidgetObserver> tab_dialog_widget_observer_; std::unique_ptr<BrowserWindowWidgetObserver> browser_window_widget_observer_; std::unique_ptr<ScopedTabModalUI> showing_modal_ui_; + + bool close_on_navigation_ = true; }; } // namespace tabs
diff --git a/chrome/browser/ui/tabs/split_tab_util.cc b/chrome/browser/ui/tabs/split_tab_util.cc index 6d9ee14..5a1a683 100644 --- a/chrome/browser/ui/tabs/split_tab_util.cc +++ b/chrome/browser/ui/tabs/split_tab_util.cc
@@ -9,8 +9,8 @@ #include "base/check_op.h" #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h" #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h" -#include "chrome/browser/ui/tabs/split_tab_data.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "components/tabs/public/split_tab_data.h" #include "components/tabs/public/split_tab_id.h" namespace split_tabs {
diff --git a/chrome/browser/ui/tabs/tab_collection_unittest.cc b/chrome/browser/ui/tabs/tab_collection_unittest.cc index 4704755..4d8fe0662 100644 --- a/chrome/browser/ui/tabs/tab_collection_unittest.cc +++ b/chrome/browser/ui/tabs/tab_collection_unittest.cc
@@ -9,9 +9,6 @@ #include <optional> #include "chrome/browser/ui/tabs/features.h" -#include "chrome/browser/ui/tabs/split_tab_collection.h" -#include "chrome/browser/ui/tabs/split_tab_data.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_group_tab_collection.h" #include "chrome/browser/ui/tabs/tab_model.h" #include "chrome/browser/ui/tabs/tab_strip_collection.h" @@ -23,7 +20,10 @@ #include "chrome/test/base/testing_profile.h" #include "components/tab_groups/tab_group_visual_data.h" #include "components/tabs/public/pinned_tab_collection.h" +#include "components/tabs/public/split_tab_collection.h" +#include "components/tabs/public/split_tab_data.h" #include "components/tabs/public/split_tab_id.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_collection_storage.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_renderer_host.h"
diff --git a/chrome/browser/ui/tabs/tab_dialog_manager.cc b/chrome/browser/ui/tabs/tab_dialog_manager.cc index 73ad497..9afa89f 100644 --- a/chrome/browser/ui/tabs/tab_dialog_manager.cc +++ b/chrome/browser/ui/tabs/tab_dialog_manager.cc
@@ -184,19 +184,26 @@ widget, host_browser_window)); } +// The dialog widget should be visible if and only if the tab is in the +// foreground and activated, and the host window is not minimized. +bool GetDialogWidgetVisibility(bool activated, bool minimized) { + return activated && !minimized; +} + } // namespace // Applies positioning changes from the browser window widget to the tracked -// Widget. +// Widget. This class relies on the assumption that it is scoped to the lifetime +// of a single tab, in a single browser, and that it will be destroyed +// before the tab moves between browser windows. class BrowserWindowWidgetObserver : public views::WidgetObserver { public: - BrowserWindowWidgetObserver(BrowserWindowInterface* host_browser_window, + BrowserWindowWidgetObserver(TabInterface* tab_interface, views::Widget* dialog_widget) - : host_(host_browser_window), dialog_widget_(dialog_widget) { - CHECK(host_); + : tab_(tab_interface), dialog_widget_(dialog_widget) { CHECK(dialog_widget_); browser_window_widget_observation_.Observe( - host_browser_window->TopContainer()->GetWidget()); + tab_->GetBrowserWindowInterface()->TopContainer()->GetWidget()); } BrowserWindowWidgetObserver(const BrowserWindowWidgetObserver&) = delete; BrowserWindowWidgetObserver& operator=(const BrowserWindowWidgetObserver&) = @@ -206,17 +213,22 @@ // WidgetObserver: void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) override { - CHECK(host_); if (dialog_widget_->IsVisible()) { UpdateModalDialogPosition( - dialog_widget_, host_, + dialog_widget_, tab_->GetBrowserWindowInterface(), dialog_widget_->GetRootView()->GetPreferredSize({})); } } + void OnWidgetShowStateChanged(views::Widget* widget) override { + bool minimized = widget->IsMinimized(); + bool activated = tab_->IsActivated(); + dialog_widget_->SetVisible(GetDialogWidgetVisibility(activated, minimized)); + } + private: - // The modal host for the widget that owns this observer. - raw_ptr<BrowserWindowInterface> host_; + // The tab that owns this dialog manager. + raw_ptr<TabInterface> tab_; // The widget being tracked. raw_ptr<views::Widget> dialog_widget_; @@ -251,7 +263,10 @@ delegate, gfx::NativeWindow(), host->GetNativeView())); } -void TabDialogManager::ShowDialogAndBlockTabInteraction(views::Widget* widget) { +void TabDialogManager::ShowDialogAndBlockTabInteraction( + views::Widget* widget, + bool close_on_navigation) { + close_on_navigation_ = close_on_navigation; widget_ = widget; auto* browser_window_interface = tab_interface_->GetBrowserWindowInterface(); ConfigureDesiredBoundsDelegate(widget_.get(), browser_window_interface); @@ -268,19 +283,21 @@ tab_dialog_widget_observer_ = std::make_unique<TabDialogWidgetObserver>(this, widget_.get()); showing_modal_ui_ = tab_interface_->ShowModalUI(); - if (tab_interface_->IsActivated()) { - browser_window_widget_observer_ = - std::make_unique<BrowserWindowWidgetObserver>(browser_window_interface, - widget_.get()); - widget_->Show(); - } + browser_window_widget_observer_ = + std::make_unique<BrowserWindowWidgetObserver>(tab_interface_, + widget_.get()); + bool minimized = browser_window_interface->IsMinimized(); + bool activated = tab_interface_->IsActivated(); + widget_->Show(); + widget_->SetVisible(GetDialogWidgetVisibility(activated, minimized)); } std::unique_ptr<views::Widget> TabDialogManager::CreateShowDialogAndBlockTabInteraction( - views::DialogDelegate* delegate) { + views::DialogDelegate* delegate, + bool close_on_navigation) { auto widget = CreateTabScopedDialog(delegate); - ShowDialogAndBlockTabInteraction(widget.get()); + ShowDialogAndBlockTabInteraction(widget.get(), close_on_navigation); return widget; } @@ -328,8 +345,9 @@ back_forward_cache::DisabledReasonId::kModalDialog)); } - // Close modal dialogs if necessary. - if (!net::registry_controlled_domains::SameDomainOrHost( + // Close modal dialogs if navigation is to a new domain/host. + if (close_on_navigation_ && + !net::registry_controlled_domains::SameDomainOrHost( navigation_handle->GetPreviousPrimaryMainFrameURL(), navigation_handle->GetURL(), net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) { @@ -343,8 +361,8 @@ tab_interface_->GetBrowserWindowInterface(), widget_->GetRootView()->GetPreferredSize({})); browser_window_widget_observer_ = - std::make_unique<BrowserWindowWidgetObserver>( - tab_interface_->GetBrowserWindowInterface(), widget_.get()); + std::make_unique<BrowserWindowWidgetObserver>(tab_interface_, + widget_.get()); // Check if the tab was detached and dragged to a new browser window. This // ensures the widget is properly reparented. auto* parent_widget = @@ -352,7 +370,8 @@ if (parent_widget != widget_->parent()) { widget_->Reparent(parent_widget); } - widget_->SetVisible(true); + widget_->SetVisible( + GetDialogWidgetVisibility(/*activated=*/true, widget_->IsMinimized())); } }
diff --git a/chrome/browser/ui/tabs/tab_iterator_unittest.cc b/chrome/browser/ui/tabs/tab_iterator_unittest.cc index fea7fb2..cee8d577 100644 --- a/chrome/browser/ui/tabs/tab_iterator_unittest.cc +++ b/chrome/browser/ui/tabs/tab_iterator_unittest.cc
@@ -5,8 +5,6 @@ #include <memory> #include <utility> -#include "chrome/browser/ui/tabs/split_tab_collection.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_group_tab_collection.h" #include "chrome/browser/ui/tabs/tab_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -14,6 +12,8 @@ #include "chrome/browser/ui/tabs/test_util.h" #include "chrome/browser/ui/tabs/unpinned_tab_collection.h" #include "chrome/test/base/testing_profile.h" +#include "components/tabs/public/split_tab_collection.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_collection.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_task_environment.h"
diff --git a/chrome/browser/ui/tabs/tab_model.cc b/chrome/browser/ui/tabs/tab_model.cc index cc096e3f..f1b2cd5 100644 --- a/chrome/browser/ui/tabs/tab_model.cc +++ b/chrome/browser/ui/tabs/tab_model.cc
@@ -15,13 +15,13 @@ #include "chrome/browser/ui/tabs/features.h" #include "chrome/browser/ui/tabs/public/tab_dialog_manager.h" #include "chrome/browser/ui/tabs/public/tab_features.h" -#include "chrome/browser/ui/tabs/split_tab_collection.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_group_tab_collection.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" #include "chrome/browser/ui/ui_features.h" #include "components/constrained_window/constrained_window_views.h" +#include "components/tabs/public/split_tab_collection.h" #include "components/tabs/public/split_tab_id.h" #include "components/tabs/public/tab_collection.h" #include "components/web_modal/modal_dialog_host.h" @@ -265,6 +265,10 @@ return GetModelForTabInterface()->delegate()->GetBrowserWindowInterface(); } +const BrowserWindowInterface* TabModel::GetBrowserWindowInterface() const { + return GetModelForTabInterface()->delegate()->GetBrowserWindowInterface(); +} + tabs::TabFeatures* TabModel::GetTabFeatures() { return tab_features_.get(); }
diff --git a/chrome/browser/ui/tabs/tab_model.h b/chrome/browser/ui/tabs/tab_model.h index 35ed161..7f3881b 100644 --- a/chrome/browser/ui/tabs/tab_model.h +++ b/chrome/browser/ui/tabs/tab_model.h
@@ -138,6 +138,7 @@ bool IsInNormalWindow() const override; BrowserWindowInterface* GetBrowserWindowInterface() override; + const BrowserWindowInterface* GetBrowserWindowInterface() const override; tabs::TabFeatures* GetTabFeatures() override; bool IsPinned() const override; bool IsSplit() const override;
diff --git a/chrome/browser/ui/tabs/tab_strip_api/BUILD.gn b/chrome/browser/ui/tabs/tab_strip_api/BUILD.gn index b346f7d..42f4fe9 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/BUILD.gn +++ b/chrome/browser/ui/tabs/tab_strip_api/BUILD.gn
@@ -25,16 +25,28 @@ mojom = "tabs_api.mojom.TabId.Type" cpp = "enum ::tabs_api::TabId::Type" }, + { + mojom = "tabs_api.mojom.TabAlertState" + cpp = "::TabAlertState" + }, + { + mojom = "tabs_api.mojom.TabNetworkState" + cpp = "::TabNetworkState" + }, ] traits_headers = [ "//chrome/browser/ui/tabs/tab_strip_api/tab_id.h", "//chrome/browser/ui/tabs/tab_strip_api/tab_id_traits.h", + "//chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.h", ] - traits_sources = - [ "//chrome/browser/ui/tabs/tab_strip_api/tab_id_traits.cc" ] + traits_sources = [ + "//chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.cc", + "//chrome/browser/ui/tabs/tab_strip_api/tab_id_traits.cc", + ] traits_public_deps = [ ":types", "//base", + "//chrome/browser/ui/tabs", ] }, ]
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.cc b/chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.cc new file mode 100644 index 0000000..7f91e41 --- /dev/null +++ b/chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.cc
@@ -0,0 +1,136 @@ +// 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/ui/tabs/tab_strip_api/tab_enum_traits.h" + +MojoTabNetworkState +mojo::EnumTraits<MojoTabNetworkState, NativeTabNetworkState>::ToMojom( + NativeTabNetworkState input) { + switch (input) { + case NativeTabNetworkState::kNone: + return MojoTabNetworkState::kNone; + case NativeTabNetworkState::kWaiting: + return MojoTabNetworkState::kWaiting; + case NativeTabNetworkState::kLoading: + return MojoTabNetworkState::kLoading; + case NativeTabNetworkState::kError: + return MojoTabNetworkState::kError; + } + + NOTREACHED(); +} + +bool mojo::EnumTraits<MojoTabNetworkState, NativeTabNetworkState>::FromMojom( + MojoTabNetworkState in, + NativeTabNetworkState* out) { + switch (in) { + case MojoTabNetworkState::kNone: + *out = NativeTabNetworkState::kNone; + return true; + case MojoTabNetworkState::kWaiting: + *out = NativeTabNetworkState::kWaiting; + return true; + case MojoTabNetworkState::kLoading: + *out = NativeTabNetworkState::kLoading; + return true; + case MojoTabNetworkState::kError: + *out = NativeTabNetworkState::kError; + return true; + } + + NOTREACHED(); +} + +MojoTabAlertState +mojo::EnumTraits<MojoTabAlertState, NativeTabAlertState>::ToMojom( + NativeTabAlertState input) { + switch (input) { + case NativeTabAlertState::MEDIA_RECORDING: + return MojoTabAlertState::kMediaRecording; + case NativeTabAlertState::TAB_CAPTURING: + return MojoTabAlertState::kTabCapturing; + case NativeTabAlertState::AUDIO_PLAYING: + return MojoTabAlertState::kAudioPlaying; + case NativeTabAlertState::AUDIO_MUTING: + return MojoTabAlertState::kAudioMuting; + case NativeTabAlertState::BLUETOOTH_CONNECTED: + return MojoTabAlertState::kBluetoothConnected; + case NativeTabAlertState::BLUETOOTH_SCAN_ACTIVE: + return MojoTabAlertState::kBluetoothScanActive; + case NativeTabAlertState::USB_CONNECTED: + return MojoTabAlertState::kUsbConnected; + case NativeTabAlertState::HID_CONNECTED: + return MojoTabAlertState::kHidConnected; + case NativeTabAlertState::SERIAL_CONNECTED: + return MojoTabAlertState::kSerialConnected; + case NativeTabAlertState::PIP_PLAYING: + return MojoTabAlertState::kPipPlaying; + case NativeTabAlertState::DESKTOP_CAPTURING: + return MojoTabAlertState::kDesktopCapturing; + case NativeTabAlertState::VR_PRESENTING_IN_HEADSET: + return MojoTabAlertState::kVrPresentingInHeadset; + case NativeTabAlertState::AUDIO_RECORDING: + return MojoTabAlertState::kAudioRecording; + case NativeTabAlertState::VIDEO_RECORDING: + return MojoTabAlertState::kVideoRecording; + case NativeTabAlertState::GLIC_ACCESSING: + return MojoTabAlertState::kGlicAccessing; + } + + NOTREACHED(); +} + +bool mojo::EnumTraits<MojoTabAlertState, NativeTabAlertState>::FromMojom( + MojoTabAlertState in, + NativeTabAlertState* out) { + switch (in) { + case MojoTabAlertState::kMediaRecording: + *out = NativeTabAlertState::MEDIA_RECORDING; + return true; + case MojoTabAlertState::kTabCapturing: + *out = NativeTabAlertState::TAB_CAPTURING; + return true; + case MojoTabAlertState::kAudioPlaying: + *out = NativeTabAlertState::AUDIO_PLAYING; + return true; + case MojoTabAlertState::kAudioMuting: + *out = NativeTabAlertState::AUDIO_MUTING; + return true; + case MojoTabAlertState::kBluetoothConnected: + *out = NativeTabAlertState::BLUETOOTH_CONNECTED; + return true; + case MojoTabAlertState::kBluetoothScanActive: + *out = NativeTabAlertState::BLUETOOTH_SCAN_ACTIVE; + return true; + case MojoTabAlertState::kUsbConnected: + *out = NativeTabAlertState::USB_CONNECTED; + return true; + case MojoTabAlertState::kHidConnected: + *out = NativeTabAlertState::HID_CONNECTED; + return true; + case MojoTabAlertState::kSerialConnected: + *out = NativeTabAlertState::SERIAL_CONNECTED; + return true; + case MojoTabAlertState::kPipPlaying: + *out = NativeTabAlertState::PIP_PLAYING; + return true; + case MojoTabAlertState::kDesktopCapturing: + *out = NativeTabAlertState::DESKTOP_CAPTURING; + return true; + case MojoTabAlertState::kVrPresentingInHeadset: + *out = NativeTabAlertState::VR_PRESENTING_IN_HEADSET; + return true; + case MojoTabAlertState::kAudioRecording: + *out = NativeTabAlertState::AUDIO_RECORDING; + return true; + case MojoTabAlertState::kVideoRecording: + *out = NativeTabAlertState::VIDEO_RECORDING; + return true; + case MojoTabAlertState::kGlicAccessing: + *out = NativeTabAlertState::GLIC_ACCESSING; + return true; + } + + NOTREACHED(); +}
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.h b/chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.h new file mode 100644 index 0000000..d2b547d --- /dev/null +++ b/chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.h
@@ -0,0 +1,34 @@ +// 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_UI_TABS_TAB_STRIP_API_TAB_ENUM_TRAITS_H_ +#define CHROME_BROWSER_UI_TABS_TAB_STRIP_API_TAB_ENUM_TRAITS_H_ + +#include "chrome/browser/ui/tabs/tab_enums.h" +#include "chrome/browser/ui/tabs/tab_network_state.h" +#include "chrome/browser/ui/tabs/tab_strip_api/tab_strip_api.mojom.h" +#include "mojo/public/cpp/bindings/enum_traits.h" +#include "mojo/public/cpp/bindings/struct_traits.h" + +using MojoTabNetworkState = tabs_api::mojom::TabNetworkState; +using NativeTabNetworkState = enum TabNetworkState; + +// TabNetworkState Enum mapping. +template <> +struct mojo::EnumTraits<MojoTabNetworkState, NativeTabNetworkState> { + static MojoTabNetworkState ToMojom(NativeTabNetworkState input); + static bool FromMojom(MojoTabNetworkState in, NativeTabNetworkState* out); +}; + +using MojoTabAlertState = tabs_api::mojom::TabAlertState; +using NativeTabAlertState = enum TabAlertState; + +// TabAlertState Enum mapping. +template <> +struct mojo::EnumTraits<MojoTabAlertState, NativeTabAlertState> { + static MojoTabAlertState ToMojom(NativeTabAlertState input); + static bool FromMojom(MojoTabAlertState in, NativeTabAlertState* out); +}; + +#endif // CHROME_BROWSER_UI_TABS_TAB_STRIP_API_TAB_ENUM_TRAITS_H_
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_api.mojom b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_api.mojom index ceaaba5d4..4a3db38 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_api.mojom +++ b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_api.mojom
@@ -7,6 +7,35 @@ import "mojo/public/mojom/base/error.mojom"; import "url/mojom/url.mojom"; +// In C++, this enum is typemapped to +// "//chrome/browser/ui/tabs/tab_enums.h" +enum TabAlertState { + kMediaRecording, + kTabCapturing, + kAudioPlaying, + kAudioMuting, + kBluetoothConnected, + kBluetoothScanActive, + kUsbConnected, + kHidConnected, + kSerialConnected, + kPipPlaying, + kDesktopCapturing, + kVrPresentingInHeadset, + kAudioRecording, + kVideoRecording, + kGlicAccessing, +}; + +// In C++, this enum is typemapped to +// "//chrome/browser/ui/tabs/tab_network_state.h" +enum TabNetworkState { + kNone, + kWaiting, + kLoading, + kError, +}; + // References a tab object. The id can refer to different types of underlying // resource. The |type| field can be used to differentiate between the type // of underlying resources. @@ -31,6 +60,19 @@ Type type; }; +struct Tab { + TabId id; + string title; + url.mojom.Url url; + + // TODO(crbug.com/414630734). The favicon should be typemapped to ImageModel + // in c++. Leave this as a data uri for now. + url.mojom.Url favicon_url; + + array<TabAlertState> alert_states; + TabNetworkState network_state; +}; + // Position is an ephemeral object that should not be saved nor act as an // identifier. It is purely used in this API to determine the position within // the TabstripModel. @@ -49,13 +91,14 @@ // empty, the new tab will be appended to the end of the Tabstrip. // Url specifies what is loaded in the Tab. If url is empty, then the new // tab-page is loaded instead. - // - // TODO (crbug.com/409821664). Returns a result type of bool for success or - // Error for errors. The success type is temporary and will be changed once - // it is defined. [Sync] CreateTabAt(Position? pos, url.mojom.Url? url) => result<bool, mojo_base.mojom.Error>; + + // Get tab data based on the Tab id. Currently the TabId refers to the Tab + // handle value. + [Sync] + GetTab(TabId id) => result<Tab, mojo_base.mojom.Error>; }; // TODO (crbug.com/412955607)
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.cc b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.cc index d83db22..6479652 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.cc +++ b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.cc
@@ -3,11 +3,15 @@ // found in the LICENSE file. #include "chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" #include "base/types/expected.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" +#include "chrome/browser/ui/tabs/tab_renderer_data.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" +#include "chrome/browser/ui/tabs/tab_utils.h" #include "mojo/public/mojom/base/error.mojom.h" #include "url/gurl.h" @@ -64,6 +68,48 @@ index, true); } +tabs_api::mojom::TabPtr TabStripServiceImpl::ConvertTabToData( + tabs::TabInterface* tab_interface, + int index) { + auto result = tabs_api::mojom::Tab::New(); + + auto tab_renderer_data = TabRendererData::FromTabInModel(model_, index); + result->title = base::UTF16ToUTF8(tab_renderer_data.title); + // TODO(crbug.com/414630734). Integrate the favicon_url after it is + // typemapped. + result->url = tab_renderer_data.visible_url; + result->network_state = tab_renderer_data.network_state; + for (const auto alert_state : + GetTabAlertStatesForContents(tab_interface->GetContents())) { + result->alert_states.push_back(alert_state); + } + + return result; +} + +void TabStripServiceImpl::GetTab(const tabs_api::TabId& tab_mojom_id, + GetTabCallback callback) { + int32_t tab_id; + tabs_api::mojom::TabPtr tab_result; + if (base::StringToInt(tab_mojom_id.Id(), &tab_id)) { + // TODO (crbug.com/412709270) TabStripModel or TabCollections should have an + // api that can fetch id without of relying on indexes. + for (int index = 0; index < model_->count(); index++) { + tabs::TabInterface* tab = model_->GetTabAtIndex(index); + if (tab_id == tab->GetHandle().raw_value()) { + tab_result = ConvertTabToData(tab, index); + } + } + } + + if (tab_result) { + std::move(callback).Run(std::move(tab_result)); + } else { + std::move(callback).Run(base::unexpected(mojo_base::mojom::Error::New( + mojo_base::mojom::Code::kNotFound, "Tab not found"))); + } +} + void TabStripServiceImpl::OnTabStripModelChanged( TabStripModel* tab_strip_model, const TabStripModelChange& change,
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.h b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.h index 1487da99..508857c8 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.h +++ b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl.h
@@ -8,6 +8,7 @@ #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/observer_list.h" +#include "chrome/browser/ui/tabs/tab_strip_api/tab_id.h" #include "chrome/browser/ui/tabs/tab_strip_api/tab_strip_api.mojom.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "mojo/public/cpp/bindings/receiver_set.h" @@ -37,6 +38,8 @@ const std::optional<GURL>& url, CreateTabAtCallback callback) override; + void GetTab(const tabs_api::TabId& id, GetTabCallback callback) override; + // TabStripModelObserver void OnTabStripModelChanged( TabStripModel* tab_strip_model, @@ -47,6 +50,8 @@ // Helper method used to add tab. This is primarily to mock for unit tests // until there is a better way to mock chrome::AddAndReturnTabAt. virtual content::WebContents* AddTabAt(const GURL& url, int index); + tabs_api::mojom::TabPtr ConvertTabToData(tabs::TabInterface* tab_interface, + int index); private: void OnTabStripModelChangeAdded(const TabStripModelChange::Insert& change);
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl_unittest.cc b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl_unittest.cc index 9428acb..3259762 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl_unittest.cc +++ b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_service_impl_unittest.cc
@@ -86,4 +86,14 @@ ASSERT_EQ(result.error()->code, mojo_base::mojom::Code::kFailedPrecondition); } +TEST_F(TabStripServiceImplTest, GetTab) { + tabs_api::mojom::TabStripService::GetTabResult result; + tabs_api::TabId tab_id; + bool success = client_->GetTab(tab_id, &result); + + ASSERT_TRUE(success); + ASSERT_FALSE(result.has_value()); + ASSERT_EQ(result.error()->code, mojo_base::mojom::Code::kNotFound); +} + } // namespace
diff --git a/chrome/browser/ui/tabs/tab_strip_collection.cc b/chrome/browser/ui/tabs/tab_strip_collection.cc index bad3e448..8e5ead0 100644 --- a/chrome/browser/ui/tabs/tab_strip_collection.cc +++ b/chrome/browser/ui/tabs/tab_strip_collection.cc
@@ -11,12 +11,12 @@ #include "base/containers/adapters.h" #include "base/memory/ptr_util.h" -#include "chrome/browser/ui/tabs/split_tab_collection.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_group_tab_collection.h" #include "chrome/browser/ui/tabs/unpinned_tab_collection.h" #include "components/tabs/public/pinned_tab_collection.h" +#include "components/tabs/public/split_tab_collection.h" #include "components/tabs/public/split_tab_id.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_collection.h" #include "components/tabs/public/tab_collection_storage.h" #include "components/tabs/public/tab_interface.h"
diff --git a/chrome/browser/ui/tabs/tab_strip_collection.h b/chrome/browser/ui/tabs/tab_strip_collection.h index 5cecf97..5a3d3a52 100644 --- a/chrome/browser/ui/tabs/tab_strip_collection.h +++ b/chrome/browser/ui/tabs/tab_strip_collection.h
@@ -9,8 +9,8 @@ #include <optional> #include <unordered_map> -#include "chrome/browser/ui/tabs/split_tab_data.h" #include "components/tab_groups/tab_group_id.h" +#include "components/tabs/public/split_tab_data.h" #include "components/tabs/public/split_tab_id.h" #include "components/tabs/public/tab_collection.h"
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc index 5b3911c..54a0471c 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.cc +++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -61,9 +61,6 @@ #include "chrome/browser/ui/tabs/organization/tab_organization_service.h" #include "chrome/browser/ui/tabs/organization/tab_organization_service_factory.h" #include "chrome/browser/ui/tabs/organization/tab_organization_session.h" -#include "chrome/browser/ui/tabs/split_tab_collection.h" -#include "chrome/browser/ui/tabs/split_tab_data.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_change_type.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_group.h" @@ -93,7 +90,10 @@ #include "components/reading_list/core/reading_list_model.h" #include "components/tab_groups/tab_group_id.h" #include "components/tab_groups/tab_group_visual_data.h" +#include "components/tabs/public/split_tab_collection.h" +#include "components/tabs/public/split_tab_data.h" #include "components/tabs/public/split_tab_id.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_interface.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/webapps/common/web_app_id.h" @@ -421,7 +421,7 @@ CHECK(!group_model_->ContainsTabGroup(group->collection_->GetTabGroupId())); // Notify tab is added to model. - for (tabs::TabInterface* tab : group->collection_->GetTabsRecursive()) { + for (tabs::TabInterface* tab : *(group->collection_)) { static_cast<tabs::TabModel*>(tab)->OnAddedToModel(this); } @@ -525,7 +525,7 @@ group_model_->RemoveTabGroup(group_id, base::PassKey<TabStripModel>()); // Notify tab is removed from model - for (tabs::TabInterface* tab : group_collection->GetTabsRecursive()) { + for (tabs::TabInterface* tab : *group_collection) { static_cast<tabs::TabModel*>(tab)->OnRemovedFromModel(); } @@ -564,7 +564,7 @@ detached_group->collection_->GetTabGroupId(); tabs::TabGroupTabCollection* group_collection = detached_group->collection_.get(); - for (tabs::TabInterface* tab : group_collection->GetTabsRecursive()) { + for (const tabs::TabInterface* tab : *group_collection) { delegate()->WillAddWebContents(tab->GetContents()); } @@ -593,7 +593,7 @@ ValidateTabStripModel(); - for (tabs::TabInterface* tab : group_collection->GetTabsRecursive()) { + for (tabs::TabInterface* tab : *group_collection) { static_cast<tabs::TabModel*>(tab)->DidInsert( base::PassKey<TabStripModel>()); } @@ -898,11 +898,12 @@ } int TabStripModel::GetIndexOfWebContents(const WebContents* contents) const { - std::vector<tabs::TabInterface*> tabs = contents_data_->GetTabsRecursive(); - for (size_t i = 0; i < tabs.size(); i++) { - if (tabs[i]->GetContents() == contents) { - return i; + int index = 0; + for (const tabs::TabInterface* tab : *this) { + if (tab->GetContents() == contents) { + return index; } + index++; } return kNoTab; } @@ -984,7 +985,7 @@ } bool TabStripModel::TabsNeedLoadingUI() const { - for (tabs::TabInterface* tab : contents_data_->GetTabsRecursive()) { + for (const tabs::TabInterface* tab : *this) { if (tab->GetContents()->ShouldShowLoadingUI()) { return true; } @@ -2674,7 +2675,7 @@ } void TabStripModel::ForgetAllOpeners() { - for (tabs::TabInterface* tab : contents_data_->GetTabsRecursive()) { + for (tabs::TabInterface* tab : *this) { static_cast<tabs::TabModel*>(tab)->set_opener(nullptr); } } @@ -3322,7 +3323,7 @@ } DCHECK([&]() { - for (tabs::TabInterface* tab : contents_data_->GetTabsRecursive()) { + for (const tabs::TabInterface* tab : *this) { if (tab->GetGroup() == new_group) { return false; } @@ -4113,9 +4114,8 @@ void TabStripModel::FixOpeners(int index) { tabs::TabModel* old_tab = GetTabModelAtIndex(index); tabs::TabInterface* new_opener = old_tab ? old_tab->opener() : nullptr; - std::vector<tabs::TabInterface*> tabs = contents_data_->GetTabsRecursive(); - for (tabs::TabInterface* tab : tabs) { + for (tabs::TabInterface* tab : *this) { auto* tab_model = static_cast<tabs::TabModel*>(tab); if (tab_model->opener() != old_tab) { continue; @@ -4128,7 +4128,7 @@ // Sanity check that none of the tabs' openers refer |old_tab| or // themselves. DCHECK([&]() { - return std::none_of(tabs.begin(), tabs.end(), [&](tabs::TabInterface* tab) { + return std::none_of(begin(), end(), [&](tabs::TabInterface* tab) { tabs::TabInterface* opener = static_cast<tabs::TabModel*>(tab)->opener(); return opener == old_tab || opener == tab; }); @@ -4465,9 +4465,8 @@ // All the tabs in a split should be contiguous. Instead of using // GetIndexOfTab multiple times, call it on the first tab, then increment by // one for each subsequent tab. - std::vector<tabs::TabInterface*> tabs = split->GetTabsRecursive(); - for (size_t index = GetIndexOfTab(tabs[0]); - tabs::TabInterface* split_tab : tabs) { + for (size_t index = GetIndexOfTab(split->GetTabAtIndexRecursive(0)); + tabs::TabInterface* split_tab : *split) { split_tabs_with_indices.emplace_back(split_tab, index++); } @@ -4482,9 +4481,8 @@ return gfx::Range(); } - std::vector<tabs::TabInterface*> tabs = split->GetTabsRecursive(); - size_t start = GetIndexOfTab(tabs[0]); - return gfx::Range(start, start + tabs.size()); + size_t start = GetIndexOfTab(split->GetTabAtIndexRecursive(0)); + return gfx::Range(start, start + split->TabCountRecursive()); } TabStripModel::ScopedTabStripModalUIImpl::ScopedTabStripModalUIImpl(
diff --git a/chrome/browser/ui/tabs/tab_strip_model_browsertest.cc b/chrome/browser/ui/tabs/tab_strip_model_browsertest.cc index e09fca2d..e4469b8 100644 --- a/chrome/browser/ui/tabs/tab_strip_model_browsertest.cc +++ b/chrome/browser/ui/tabs/tab_strip_model_browsertest.cc
@@ -19,7 +19,6 @@ #include "chrome/browser/ui/tabs/organization/tab_organization_service.h" #include "chrome/browser/ui/tabs/organization/tab_organization_service_factory.h" #include "chrome/browser/ui/tabs/organization/tab_organization_session.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h" @@ -35,6 +34,7 @@ #include "components/policy/policy_constants.h" #include "components/saved_tab_groups/public/features.h" #include "components/tab_groups/tab_group_id.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_interface.h" #include "components/webapps/common/web_app_id.h" #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/tabs/tab_strip_model_observer.cc b/chrome/browser/ui/tabs/tab_strip_model_observer.cc index 1a785f5..631865d 100644 --- a/chrome/browser/ui/tabs/tab_strip_model_observer.cc +++ b/chrome/browser/ui/tabs/tab_strip_model_observer.cc
@@ -9,10 +9,10 @@ #include "base/check_op.h" #include "base/trace_event/trace_event.h" -#include "chrome/browser/ui/tabs/split_tab_collection.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_group_tab_collection.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "components/tabs/public/split_tab_collection.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_interface.h" #include "content/public/browser/web_contents.h" #include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
diff --git a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc index 9214c67..b2e88e1 100644 --- a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc +++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
@@ -32,8 +32,6 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h" #include "chrome/browser/ui/tabs/features.h" -#include "chrome/browser/ui/tabs/split_tab_data.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_model.h" @@ -51,6 +49,8 @@ #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/tab_groups/tab_group_color.h" #include "components/tab_groups/tab_group_id.h" +#include "components/tabs/public/split_tab_data.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_interface.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
diff --git a/chrome/browser/ui/tabs/test/mock_tab_interface.h b/chrome/browser/ui/tabs/test/mock_tab_interface.h index d3002206..44590d1 100644 --- a/chrome/browser/ui/tabs/test/mock_tab_interface.h +++ b/chrome/browser/ui/tabs/test/mock_tab_interface.h
@@ -70,6 +70,10 @@ GetBrowserWindowInterface, (), (override)); + MOCK_METHOD(const BrowserWindowInterface*, + GetBrowserWindowInterface, + (), + (const override)); MOCK_METHOD(TabFeatures*, GetTabFeatures, (), (override)); MOCK_METHOD(bool, IsPinned, (), (const override)); MOCK_METHOD(bool, IsSplit, (), (const override));
diff --git a/chrome/browser/ui/tabs/test/split_tabs_interactive_test_mixin.h b/chrome/browser/ui/tabs/test/split_tabs_interactive_test_mixin.h index 400ea52..9bcec0e 100644 --- a/chrome/browser/ui/tabs/test/split_tabs_interactive_test_mixin.h +++ b/chrome/browser/ui/tabs/test/split_tabs_interactive_test_mixin.h
@@ -16,6 +16,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/interaction/interaction_test_util_browser.h" #include "chrome/test/interaction/interactive_browser_test.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "ui/base/interaction/interactive_test.h" // Template to be used as a mixin class for split tabs tests extending
diff --git a/chrome/browser/ui/toasts/api/toast_id.cc b/chrome/browser/ui/toasts/api/toast_id.cc index 086f6f8..efecbd6be 100644 --- a/chrome/browser/ui/toasts/api/toast_id.cc +++ b/chrome/browser/ui/toasts/api/toast_id.cc
@@ -40,6 +40,8 @@ return "TabGroupSyncRemovedFromGroup"; case ToastId::kVideoFrameCopied: return "VideoFrameCopied"; + case ToastId::kClosePinnedTab: + return "ClosePinnedTab"; } NOTREACHED();
diff --git a/chrome/browser/ui/toasts/api/toast_id.h b/chrome/browser/ui/toasts/api/toast_id.h index 8e8905e..af2e4f6 100644 --- a/chrome/browser/ui/toasts/api/toast_id.h +++ b/chrome/browser/ui/toasts/api/toast_id.h
@@ -35,7 +35,8 @@ kTabGroupSyncUserJoined = 13, kTabGroupSyncRemovedFromGroup = 14, kVideoFrameCopied = 15, - kMaxValue = kVideoFrameCopied + kClosePinnedTab = 16, + kMaxValue = kClosePinnedTab }; // LINT.ThenChange(/tools/metrics/histograms/metadata/toasts/enums.xml:ToastId)
diff --git a/chrome/browser/ui/toasts/api/toast_specification.cc b/chrome/browser/ui/toasts/api/toast_specification.cc index dd7ff67..fc59f5a 100644 --- a/chrome/browser/ui/toasts/api/toast_specification.cc +++ b/chrome/browser/ui/toasts/api/toast_specification.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/toasts/api/toast_specification.h" #include <memory> +#include <string> #include "base/check.h" #include "base/functional/callback.h" @@ -52,6 +53,15 @@ return *this; } +ToastSpecification::Builder& ToastSpecification::Builder::AddAccelerator( + ui::Accelerator accelerator, + base::RepeatingClosure callback) { + CHECK(!callback.is_null()); + toast_specification_->AddAccelerator(std::move(accelerator), + std::move(callback)); + return *this; +} + std::unique_ptr<ToastSpecification> ToastSpecification::Builder::Build() { ValidateSpecification(); return std::move(toast_specification_); @@ -102,3 +112,9 @@ void ToastSpecification::AddGlobalScope() { is_global_scope_ = true; } + +void ToastSpecification::AddAccelerator(ui::Accelerator accelerator, + base::RepeatingClosure callback) { + accelerator_ = std::move(accelerator); + accelerator_callback_ = std::move(callback); +}
diff --git a/chrome/browser/ui/toasts/api/toast_specification.h b/chrome/browser/ui/toasts/api/toast_specification.h index 813f30b..3e2a34e6a 100644 --- a/chrome/browser/ui/toasts/api/toast_specification.h +++ b/chrome/browser/ui/toasts/api/toast_specification.h
@@ -12,9 +12,10 @@ #include "base/functional/callback_forward.h" #include "base/memory/raw_ref.h" #include "base/types/pass_key.h" +#include "ui/base/accelerators/accelerator.h" #include "ui/gfx/vector_icon_types.h" -// ToastSpecification details what the toast should contain when shown. +// ToastSpecification details the supported actions and elements it contains. class ToastSpecification { public: class Builder final { @@ -48,6 +49,11 @@ // dismiss. Builder& AddGlobalScoped(); + // Adds the accelerator that is used to trigger an action when this toast is + // displayed. The accelerator is handled by the view. + Builder& AddAccelerator(ui::Accelerator accelerator, + base::RepeatingClosure callback); + std::unique_ptr<ToastSpecification> Build(); private: @@ -72,13 +78,21 @@ base::RepeatingClosure action_button_callback() const { return action_button_closure_; } + const ui::Accelerator& accelerator() const { return accelerator_; } + base::RepeatingClosure accelerator_callback() const { + return accelerator_callback_; + } + bool has_menu() const { return has_menu_; } bool is_global_scope() const { return is_global_scope_; } + bool has_accelerator() const { return !accelerator_.IsEmpty(); } void AddCloseButton(); void AddActionButton(int string_id, base::RepeatingClosure closure); void AddMenu(); void AddGlobalScope(); + void AddAccelerator(ui::Accelerator accelerator, + base::RepeatingClosure callback); private: const base::raw_ref<const gfx::VectorIcon> icon_; @@ -88,6 +102,8 @@ std::optional<int> action_button_string_id_; base::RepeatingClosure action_button_closure_; bool is_global_scope_ = false; + ui::Accelerator accelerator_; + base::RepeatingClosure accelerator_callback_; }; #endif // CHROME_BROWSER_UI_TOASTS_API_TOAST_SPECIFICATION_H_
diff --git a/chrome/browser/ui/toasts/toast_controller.cc b/chrome/browser/ui/toasts/toast_controller.cc index a174ef2a..f29acde 100644 --- a/chrome/browser/ui/toasts/toast_controller.cc +++ b/chrome/browser/ui/toasts/toast_controller.cc
@@ -267,6 +267,12 @@ const ui::ImageModel* image_override = params.image_override.has_value() ? ¶ms.image_override.value() : nullptr; + + if (spec->has_accelerator()) { + params.body_string_replacement_params.emplace_back( + spec->accelerator().GetShortcutText()); + } + const std::u16string body_string = params.body_string_override.has_value() ? params.body_string_override.value() @@ -296,6 +302,11 @@ toast_view->AddMenu(std::move(params.menu_model)); } + if (spec->has_accelerator()) { + toast_view->AddAcceleratorCallback(spec->accelerator(), + spec->accelerator_callback()); + } + toast_view_ = toast_view.get(); toast_widget_ = views::BubbleDialogDelegateView::CreateBubble(std::move(toast_view)); @@ -320,7 +331,12 @@ toast_widget_->SetFocusTraversableParentView(anchor_view); if (!is_omnibox_popup_showing_) { - toast_widget_->ShowInactive(); + if (spec->has_accelerator()) { + toast_widget_->Show(); + } else { + toast_widget_->ShowInactive(); + } + toast_view_->AnimateIn(); } else { toast_widget_->Hide();
diff --git a/chrome/browser/ui/toasts/toast_controller_interactive_ui_test.cc b/chrome/browser/ui/toasts/toast_controller_interactive_ui_test.cc index 93a4479..cd79b237 100644 --- a/chrome/browser/ui/toasts/toast_controller_interactive_ui_test.cc +++ b/chrome/browser/ui/toasts/toast_controller_interactive_ui_test.cc
@@ -121,6 +121,7 @@ {toast_features::kToastFramework, toast_features::kToastRefinements, toast_features::kLinkCopiedToast, toast_features::kImageCopiedToast, toast_features::kReadingListToast, + toast_features::kPinnedTabToastOnClose, plus_addresses::features::kPlusAddressesEnabled, plus_addresses::features::kPlusAddressFullFormFill}, {}); @@ -556,3 +557,58 @@ toast_controller->MaybeShowToast(ToastParams(ToastId::kLinkCopied))); } } + +#if BUILDFLAG(IS_MAC) +// TODO(crbug.com/416316768): Fix disabled tests on mac. +#define MAYBE_DISABLED(name) DISABLED_##name +#else +#define MAYBE_DISABLED(name) name +#endif // BUILDFLAG(IS_MAC) + +IN_PROC_BROWSER_TEST_F( + ToastControllerInteractiveTest, + MAYBE_DISABLED(ShowPinnedTabToastOnTabCloseViaKeyboardShortcut)) { + ui::Accelerator close_tab_accelerator; + ASSERT_TRUE(BrowserView::GetBrowserViewForBrowser(browser())->GetAccelerator( + IDC_CLOSE_TAB, &close_tab_accelerator)); + + RunTestSequence( + // Add a pinned tab. + InstrumentTab(kFirstTab), WaitForShow(kFirstTab), + AddInstrumentedTab(kSecondTab, GetURL()), + SelectTab(kTabStripElementId, 0), + Do([&]() { browser()->tab_strip_model()->SetTabPinned(0, true); }), + // Expect that closing the tab with an accelerator will show a toast. + SendAccelerator(kBrowserViewElementId, close_tab_accelerator), + WaitForShow(toasts::ToastView::kToastViewId), + ActivateSurface(toasts::ToastView::kToastViewId), + CheckResult([&]() { return browser()->tab_strip_model()->count(); }, 2), + // Expect that we can close the tab by pressing the accelerator again. + SendAccelerator(toasts::ToastView::kToastViewId, close_tab_accelerator), + WaitForHide(toasts::ToastView::kToastViewId), + CheckResult([&]() { return browser()->tab_strip_model()->count(); }, 1)); +} + +IN_PROC_BROWSER_TEST_F(ToastControllerInteractiveTest, + DismissToastWithEscapeKey) { + ui::Accelerator escape_accelerator(ui::VKEY_ESCAPE, ui::EF_NONE); + ui::Accelerator close_tab_accelerator; + ASSERT_TRUE(BrowserView::GetBrowserViewForBrowser(browser())->GetAccelerator( + IDC_CLOSE_TAB, &close_tab_accelerator)); + + RunTestSequence( + // Add a pinned tab. + InstrumentTab(kFirstTab), WaitForShow(kFirstTab), + AddInstrumentedTab(kSecondTab, GetURL()), + SelectTab(kTabStripElementId, 0), + Do([&]() { browser()->tab_strip_model()->SetTabPinned(0, true); }), + // Expect that closing the tab with an accelerator will show a toast. + SendAccelerator(kBrowserViewElementId, close_tab_accelerator), + WaitForShow(toasts::ToastView::kToastViewId), + ActivateSurface(toasts::ToastView::kToastViewId), + CheckResult([&]() { return browser()->tab_strip_model()->count(); }, 2), + // Expect that we can dismiss the toast by pressing the escape key. + SendAccelerator(toasts::ToastView::kToastViewId, escape_accelerator), + WaitForHide(toasts::ToastView::kToastViewId), + CheckResult([&]() { return browser()->tab_strip_model()->count(); }, 2)); +}
diff --git a/chrome/browser/ui/toasts/toast_features.cc b/chrome/browser/ui/toasts/toast_features.cc index a6e6b345..da35feb 100644 --- a/chrome/browser/ui/toasts/toast_features.cc +++ b/chrome/browser/ui/toasts/toast_features.cc
@@ -66,6 +66,11 @@ "ClearBrowsingDataToast", base::FEATURE_DISABLED_BY_DEFAULT); +// Enables the pinned tab closing notification toast. +BASE_FEATURE(kPinnedTabToastOnClose, + "PinnedTabToastOnClose", + base::FEATURE_DISABLED_BY_DEFAULT); + // static bool IsEnabled(const base::Feature& feature) { return kToastDemoMode.Get() || base::FeatureList::IsEnabled(feature);
diff --git a/chrome/browser/ui/toasts/toast_features.h b/chrome/browser/ui/toasts/toast_features.h index a2ba1d5..99824d99 100644 --- a/chrome/browser/ui/toasts/toast_features.h +++ b/chrome/browser/ui/toasts/toast_features.h
@@ -36,6 +36,7 @@ BASE_DECLARE_FEATURE(kReadingListToast); BASE_DECLARE_FEATURE(kLensOverlayToast); BASE_DECLARE_FEATURE(kClearBrowsingDataToast); +BASE_DECLARE_FEATURE(kPinnedTabToastOnClose); // Wrapper function used to check if a specific toast feature is enabled. Must // be used for toasts that are part of demo mode.
diff --git a/chrome/browser/ui/toasts/toast_service.cc b/chrome/browser/ui/toasts/toast_service.cc index 7018bad..2622469 100644 --- a/chrome/browser/ui/toasts/toast_service.cc +++ b/chrome/browser/ui/toasts/toast_service.cc
@@ -8,8 +8,10 @@ #include "base/feature_list.h" #include "base/functional/bind.h" +#include "chrome/app/chrome_command_ids.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/chrome_pages.h" @@ -21,6 +23,8 @@ #include "chrome/browser/ui/toasts/api/toast_registry.h" #include "chrome/browser/ui/toasts/api/toast_specification.h" #include "chrome/browser/ui/toasts/toast_controller.h" +#include "chrome/browser/ui/toasts/toast_features.h" +#include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/side_panel/side_panel_entry_id.h" #include "chrome/browser/ui/views/side_panel/side_panel_enums.h" #include "chrome/browser/ui/views/side_panel/side_panel_ui.h" @@ -37,6 +41,7 @@ #include "components/strings/grit/components_strings.h" #include "components/tabs/public/tab_interface.h" #include "components/vector_icons/vector_icons.h" +#include "ui/base/accelerators/accelerator.h" #include "ui/menus/simple_menu_model.h" #if BUILDFLAG(GOOGLE_CHROME_BRANDING) @@ -252,4 +257,23 @@ .AddGlobalScoped() .Build()); } -} + + if (toast_features::IsEnabled(toast_features::kPinnedTabToastOnClose)) { + BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser( + browser_window_interface->GetBrowserForMigrationOnly()); + + auto callback = base::BindRepeating( + [](TabStripModel* model) { model->CloseSelectedTabs(); }, + browser_window_interface->GetTabStripModel()); + + ui::Accelerator accelerator; + CHECK( + browser_view->GetAcceleratorForCommandId(IDC_CLOSE_TAB, &accelerator)); + toast_registry_->RegisterToast( + ToastId::kClosePinnedTab, + ToastSpecification::Builder(kKeepIcon, IDS_CLOSE_PINNED_TAB_TOAST_BODY) + .AddAccelerator(accelerator, std::move(callback)) + .Build()); + } + +} // RegisterToasts() end.
diff --git a/chrome/browser/ui/toasts/toast_service_browsertest.cc b/chrome/browser/ui/toasts/toast_service_browsertest.cc index ab3540a..4efa08c0 100644 --- a/chrome/browser/ui/toasts/toast_service_browsertest.cc +++ b/chrome/browser/ui/toasts/toast_service_browsertest.cc
@@ -45,7 +45,8 @@ plus_addresses::features::kPlusAddressesEnabled, plus_addresses::features::kPlusAddressFullFormFill, safe_browsing::kEsbAsASyncedSetting, - data_sharing::features::kDataSharingFeature}, + data_sharing::features::kDataSharingFeature, + toast_features::kPinnedTabToastOnClose}, /*disabled_features*/ {}); InProcessBrowserTest::SetUp(); }
diff --git a/chrome/browser/ui/toasts/toast_view.cc b/chrome/browser/ui/toasts/toast_view.cc index 4c559e3..634d4f3 100644 --- a/chrome/browser/ui/toasts/toast_view.cc +++ b/chrome/browser/ui/toasts/toast_view.cc
@@ -18,6 +18,7 @@ #include "chrome/grit/generated_resources.h" #include "components/strings/grit/components_strings.h" #include "components/vector_icons/vector_icons.h" +#include "ui/base/accelerators/accelerator.h" #include "ui/base/interaction/element_identifier.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" @@ -115,7 +116,7 @@ image_override_(image_override), render_toast_over_web_contents_(render_toast_over_web_contents), toast_close_callback_(std::move(toast_close_callback)) { - set_background_color(ui::kColorToastBackgroundProminent); + SetBackgroundColor(ui::kColorToastBackgroundProminent); SetPaintClientToLayer(true); SetShowCloseButton(false); DialogDelegate::SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone)); @@ -156,6 +157,15 @@ ToastCloseReason::kMenuItemClick)); } +void ToastView::AddAcceleratorCallback(ui::Accelerator accelerator, + base::RepeatingClosure callback) { + has_accelerator_ = true; + accelerator_ = accelerator; + accelerator_callback_ = std::move(callback); + + AddAccelerator(accelerator); +} + int ToastView::GetIconSize() { const ChromeLayoutProvider* lp = ChromeLayoutProvider::Get(); return lp->GetDistanceMetric(DISTANCE_TOAST_BUBBLE_ICON_SIZE); @@ -306,7 +316,8 @@ top_margin, lp->GetDistanceMetric(DISTANCE_TOAST_BUBBLE_MARGIN_LEFT), total_vertical_margins - top_margin, right_margin)); - if (has_action_button_ || has_close_button_ || menu_model_) { + if (has_action_button_ || has_close_button_ || menu_model_ || + has_accelerator_) { SetFocusTraversesOut(true); } else { set_focus_traversable_from_anchor_view(false); @@ -433,6 +444,15 @@ } } +bool ToastView::AcceleratorPressed(const ui::Accelerator& accelerator) { + if (accelerator == accelerator_) { + accelerator_callback_.Run(); + return true; + } + + return false; +} + void ToastView::AnimateOut(base::OnceClosure callback, bool show_height_animation) { if (!gfx::Animation::ShouldRenderRichAnimation()) {
diff --git a/chrome/browser/ui/toasts/toast_view.h b/chrome/browser/ui/toasts/toast_view.h index 269f0a3..ec4f380 100644 --- a/chrome/browser/ui/toasts/toast_view.h +++ b/chrome/browser/ui/toasts/toast_view.h
@@ -12,6 +12,7 @@ #include "base/functional/callback_forward.h" #include "base/functional/callback_helpers.h" #include "base/memory/raw_ptr.h" +#include "ui/base/accelerators/accelerator.h" #include "ui/base/interaction/element_identifier.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/widget/widget.h" @@ -79,6 +80,13 @@ // views::BubbleDialogDelegateView::CreateBubble). void AddMenu(std::unique_ptr<ui::MenuModel> model); + // Adds the accelerator that runs `callback` when triggered. The accelerator + // is handled in this view when it has focus. + // Must be called prior to Init + // (which is called from views::BubbleDialogDelegateView::CreateBubble). + void AddAcceleratorCallback(ui::Accelerator accelerator, + base::RepeatingClosure callback); + // views::BubbleDialogDelegateView: void Init() override; @@ -104,6 +112,7 @@ // views::BubbleDialogDelegateView: gfx::Rect GetBubbleBounds() override; void OnThemeChanged() override; + bool AcceleratorPressed(const ui::Accelerator& accelerator) override; private: void AnimateOut(base::OnceClosure callback, bool show_height_animation); @@ -126,10 +135,13 @@ bool render_toast_over_web_contents_; bool has_close_button_ = false; bool has_action_button_ = false; + bool has_accelerator_ = false; std::u16string action_button_text_; base::RepeatingClosure action_button_callback_; base::RepeatingClosure close_button_callback_; base::RepeatingCallback<void(ToastCloseReason)> toast_close_callback_; + ui::Accelerator accelerator_; + base::RepeatingClosure accelerator_callback_; std::unique_ptr<ui::MenuModel> menu_model_; // Wraps `menu_model_` and triggers closing the toast after executing menu // commands.
diff --git a/chrome/browser/ui/views/autofill/payments/payments_view_util.cc b/chrome/browser/ui/views/autofill/payments/payments_view_util.cc index 0324e06d..a8113344 100644 --- a/chrome/browser/ui/views/autofill/payments/payments_view_util.cc +++ b/chrome/browser/ui/views/autofill/payments/payments_view_util.cc
@@ -38,6 +38,7 @@ #include "ui/views/controls/label.h" #include "ui/views/controls/separator.h" #include "ui/views/controls/styled_label.h" +#include "ui/views/controls/textfield/textfield.h" #include "ui/views/controls/theme_tracking_image_view.h" #include "ui/views/controls/throbber.h" #include "ui/views/layout/box_layout.h" @@ -345,4 +346,25 @@ } #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) +std::unique_ptr<views::View> CreateLabelAndTextfieldView( + const std::u16string& text) { + auto view_builder = + views::Builder<views::BoxLayoutView>() + .SetOrientation(views::BoxLayout::Orientation::kVertical) + .SetBetweenChildSpacing( + ChromeLayoutProvider::Get()->GetDistanceMetric( + DISTANCE_RELATED_CONTROL_VERTICAL_SMALL)); + + view_builder.AddChild(views::Builder<views::Label>() + .SetText(text) + .SetTextContext(views::style::CONTEXT_LABEL) + .SetTextStyle(views::style::STYLE_PRIMARY) + .SetHorizontalAlignment(gfx::ALIGN_TO_HEAD)); + + view_builder.AddChild( + views::Builder<views::Textfield>().SetAccessibleName(text)); + + return std::move(view_builder).Build(); +} + } // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/payments/payments_view_util.h b/chrome/browser/ui/views/autofill/payments/payments_view_util.h index 83a82ac9..4a27f86 100644 --- a/chrome/browser/ui/views/autofill/payments/payments_view_util.h +++ b/chrome/browser/ui/views/autofill/payments/payments_view_util.h
@@ -110,6 +110,11 @@ const ui::ColorProvider* provider); #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) +// Creates a view containing a label and a textfield. The view is arranged +// vertically with the label positioned above the textfield. +std::unique_ptr<views::View> CreateLabelAndTextfieldView( + const std::u16string& text); + } // namespace autofill #endif // CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_PAYMENTS_VIEW_UTIL_H_
diff --git a/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog_views.cc b/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog_views.cc index 15a31cf..cfe7880 100644 --- a/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog_views.cc +++ b/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog_views.cc
@@ -6,8 +6,16 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/ui/autofill/payments/payments_view_factory.h" +#include "chrome/browser/ui/views/autofill/payments/payments_view_util.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" #include "components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller.h" #include "components/constrained_window/constrained_window_views.h" +#include "components/strings/grit/components_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/mojom/dialog_button.mojom.h" +#include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/bubble/bubble_frame_view.h" +#include "ui/views/controls/textfield/textfield.h" namespace autofill { @@ -15,6 +23,14 @@ base::WeakPtr<SaveAndFillDialogController> controller) : controller_(controller) { SetModalType(ui::mojom::ModalType::kChild); + set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH)); + SetButtons(static_cast<int>(ui::mojom::DialogButton::kOk) | + static_cast<int>(ui::mojom::DialogButton::kCancel)); + SetButtonLabel(ui::mojom::DialogButton::kOk, + controller_->GetAcceptButtonText()); + SetShowCloseButton(false); + InitViews(); } SaveAndFillDialogViews::~SaveAndFillDialogViews() = default; @@ -31,4 +47,44 @@ return dialog_view->GetWeakPtr(); } +void SaveAndFillDialogViews::AddedToWidget() { + if (controller_->IsUploadSaveAndFill()) { + GetBubbleFrameView()->SetTitleView( + std::make_unique<TitleWithIconAfterLabelView>( + GetWindowTitle(), TitleWithIconAfterLabelView::Icon::GOOGLE_PAY)); + } else { + auto title_view = std::make_unique<views::Label>( + GetWindowTitle(), views::style::CONTEXT_DIALOG_TITLE); + title_view->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD); + title_view->SetMultiLine(true); + GetBubbleFrameView()->SetTitleView(std::move(title_view)); + } +} + +std::u16string SaveAndFillDialogViews::GetWindowTitle() const { + return controller_ ? controller_->GetWindowTitle() : std::u16string(); +} + +void SaveAndFillDialogViews::InitViews() { + auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical, gfx::Insets(), + ChromeLayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_UNRELATED_CONTROL_VERTICAL))); + layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kCenter); + set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType( + views::DialogContentType::kControl, views::DialogContentType::kControl)); + + AddChildView(views::Builder<views::Label>() + .SetText(controller_->GetExplanatoryMessage()) + .SetTextContext(views::style::CONTEXT_DIALOG_BODY_TEXT) + .SetTextStyle(views::style::STYLE_SECONDARY) + .SetMultiLine(true) + .SetHorizontalAlignment(gfx::ALIGN_TO_HEAD) + .Build()); + // Create a container for the card number label and textfield. + AddChildView(CreateLabelAndTextfieldView(controller_->GetCardNumberLabel())); + // Create a container for the cardholder name label and textfield. + AddChildView(CreateLabelAndTextfieldView(controller_->GetNameOnCardLabel())); +} + } // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog_views.h b/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog_views.h index 28e4df9..630ab9b 100644 --- a/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog_views.h +++ b/chrome/browser/ui/views/autofill/payments/save_and_fill_dialog_views.h
@@ -24,7 +24,14 @@ // SaveAndFillDialogView: base::WeakPtr<SaveAndFillDialogView> GetWeakPtr() override; + // DialogDelegateView: + void AddedToWidget() override; + std::u16string GetWindowTitle() const override; + private: + // Initialize the dialog's contents. + void InitViews(); + base::WeakPtr<SaveAndFillDialogController> controller_; base::WeakPtrFactory<SaveAndFillDialogViews> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc index 24a4f8e..5e907e3 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
@@ -459,6 +459,7 @@ case SuggestionType::kCreditCardEntry: case SuggestionType::kDevtoolsTestAddresses: case SuggestionType::kFillAutofillAi: + case SuggestionType::kLoyaltyCardEntry: case SuggestionType::kPasswordEntry: return true; case SuggestionType::kAccountStoragePasswordEntry: @@ -480,7 +481,6 @@ case SuggestionType::kFillPassword: case SuggestionType::kGeneratePasswordEntry: case SuggestionType::kIbanEntry: - case SuggestionType::kLoyaltyCardEntry: case SuggestionType::kInsecureContextPaymentDisabledMessage: case SuggestionType::kManageAddress: case SuggestionType::kManageAutofillAi:
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc index f59cb45..33fee6e 100644 --- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc +++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc
@@ -274,8 +274,8 @@ void SavedTabGroupBar::OnInitialized() { RemoveAllChildViews(); - LoadAllButtonsFromModel(); overflow_button_ = AddChildView(CreateOverflowButton()); + LoadAllButtonsFromModel(); InvalidateLayout(); }
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_unittest.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_unittest.cc index 1385c9a..1f70cd6 100644 --- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_unittest.cc +++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_unittest.cc
@@ -586,4 +586,23 @@ EXPECT_EQ(1u, saved_tab_group_bar()->children().size()); } +TEST_F(SavedTabGroupBarUnitTest, GroupLoadFromModelInOrder) { + base::Uuid uuid1 = AddGroupFromLocal(); + base::Uuid uuid2 = AddGroupFromLocal(); + base::Uuid uuid3 = AddGroupFromLocal(); + + auto saved_tab_group_bar = + std::make_unique<SavedTabGroupBar>(browser(), false); + auto children = saved_tab_group_bar->children(); + + // Verify groups are shown in reverse order(last added groups show first). + EXPECT_EQ(4u, children.size()); + EXPECT_EQ(uuid3, + views::AsViewClass<SavedTabGroupButton>(children[0])->guid()); + EXPECT_EQ(uuid2, + views::AsViewClass<SavedTabGroupButton>(children[1])->guid()); + EXPECT_EQ(uuid1, + views::AsViewClass<SavedTabGroupButton>(children[2])->guid()); +} + } // namespace tab_groups
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 535891e..559a149 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -90,8 +90,6 @@ #include "chrome/browser/ui/sync/one_click_signin_links_delegate_impl.h" #include "chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_tab_data.h" #include "chrome/browser/ui/tabs/saved_tab_groups/shared_tab_group_feedback_controller.h" -#include "chrome/browser/ui/tabs/split_tab_data.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_menu_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -219,6 +217,8 @@ #include "components/sessions/core/tab_restore_service.h" #include "components/startup_metric_utils/browser/startup_metric_utils.h" #include "components/sync/service/sync_service.h" +#include "components/tabs/public/split_tab_data.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_interface.h" #include "components/translate/core/browser/language_state.h" #include "components/translate/core/browser/translate_manager.h"
diff --git a/chrome/browser/ui/views/frame/browser_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_view_browsertest.cc index 933a264..b2d0d089 100644 --- a/chrome/browser/ui/views/frame/browser_view_browsertest.cc +++ b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
@@ -26,8 +26,6 @@ #include "chrome/browser/ui/tab_modal_confirm_dialog.h" #include "chrome/browser/ui/tab_ui_helper.h" #include "chrome/browser/ui/tabs/public/tab_features.h" -#include "chrome/browser/ui/tabs/split_tab_collection.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_user_gesture_details.h" #include "chrome/browser/ui/test/test_browser_ui.h" @@ -55,6 +53,8 @@ #include "components/policy/core/common/policy_types.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/core/browser/realtime/fake_url_lookup_service.h" +#include "components/tabs/public/split_tab_collection.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "content/public/browser/invalidate_type.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h"
diff --git a/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc index cbba3036..4b6aa7c 100644 --- a/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc
@@ -6,8 +6,6 @@ #include "base/test/scoped_feature_list.h" #include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/browser_tabstrip.h" -#include "chrome/browser/ui/tabs/split_tab_collection.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/test/split_tabs_interactive_test_mixin.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" @@ -16,6 +14,8 @@ #include "chrome/common/webui_url_constants.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/interaction/interactive_browser_test.h" +#include "components/tabs/public/split_tab_collection.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "third_party/blink/public/common/input/web_mouse_event.h"
diff --git a/chrome/browser/ui/views/lens/lens_region_search_instructions_view.cc b/chrome/browser/ui/views/lens/lens_region_search_instructions_view.cc index fea6c9e6..aca802b 100644 --- a/chrome/browser/ui/views/lens/lens_region_search_instructions_view.cc +++ b/chrome/browser/ui/views/lens/lens_region_search_instructions_view.cc
@@ -75,7 +75,7 @@ SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone)); set_close_on_deactivate(false); set_corner_radius(kCornerRadius); - set_background_color(kColorFeatureLensPromoBubbleBackground); + SetBackgroundColor(kColorFeatureLensPromoBubbleBackground); // Add the leading drag selection icon. auto selection_icon_view =
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 ff8696b..d4c52b491 100644 --- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc +++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_browsertest.cc
@@ -14,6 +14,7 @@ #include "base/scoped_observation.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/with_feature_override.h" #include "base/time/time.h" @@ -1465,6 +1466,7 @@ #endif IN_PROC_BROWSER_TEST_P(AvatarToolbarButtonHistorySyncOptinClickBrowserTest, MAYBE_CollapsesOnClickAndTriggersProfileMenuStartup) { + base::HistogramTester histogram_tester; AvatarToolbarButton* avatar = GetAvatarToolbarButton(browser()); // Normal state. ASSERT_TRUE(avatar->GetText().empty()); @@ -1479,9 +1481,25 @@ EXPECT_EQ( avatar->GetText(), l10n_util::GetStringUTF16(GetParam().expected_history_sync_message_id)); + // `Signin.SyncOptIn.IdentityPill.Shown` should be recorded with the correct + // access point. + histogram_tester.ExpectBucketCount( + "Signin.SyncOptIn.IdentityPill.Shown", + signin_metrics::AccessPoint::kHistorySyncOptinExpansionPillOnStartup, + /*expected_count=*/1); + histogram_tester.ExpectBucketCount( + "Signin.SyncOptIn.IdentityPill.Shown", + signin_metrics::AccessPoint::kHistorySyncOptinExpansionPillOnInactivity, + /*expected_count=*/0); // The button action should be overridden. EXPECT_TRUE(avatar->HasExplicitButtonAction()); + histogram_tester.ExpectTotalCount( + "Signin.SyncOptIn.IdentityPill.DurationBeforeClick", + /*expected_count=*/0); Click(avatar); + histogram_tester.ExpectTotalCount( + "Signin.SyncOptIn.IdentityPill.DurationBeforeClick", + /*expected_count=*/1); auto* coordinator = ProfileMenuCoordinator::FromBrowser(browser()); ASSERT_NE(coordinator, nullptr); EXPECT_TRUE(coordinator->IsShowing()); @@ -1516,6 +1534,7 @@ #endif IN_PROC_BROWSER_TEST_P(AvatarToolbarButtonHistorySyncOptinClickBrowserTest, MAYBE_CollapsesOnClickAndTriggersProfileMenuInactivity) { + base::HistogramTester histogram_tester; AvatarToolbarButton* avatar = GetAvatarToolbarButton(browser()); // Normal state. ASSERT_TRUE(avatar->GetText().empty()); @@ -1530,6 +1549,16 @@ EXPECT_EQ( avatar->GetText(), l10n_util::GetStringUTF16(GetParam().expected_history_sync_message_id)); + // `Signin.SyncOptIn.IdentityPill.Shown` should be recorded with the correct + // access point. + histogram_tester.ExpectBucketCount( + "Signin.SyncOptIn.IdentityPill.Shown", + signin_metrics::AccessPoint::kHistorySyncOptinExpansionPillOnStartup, + /*expected_count=*/1); + histogram_tester.ExpectBucketCount( + "Signin.SyncOptIn.IdentityPill.Shown", + signin_metrics::AccessPoint::kHistorySyncOptinExpansionPillOnInactivity, + /*expected_count=*/0); EXPECT_TRUE(avatar->HasExplicitButtonAction()); avatar->TriggerTimeoutForTesting(AvatarDelayType::kHistorySyncOptin); // The button comes back to the normal state. @@ -1543,9 +1572,25 @@ EXPECT_EQ( avatar->GetText(), l10n_util::GetStringUTF16(GetParam().expected_history_sync_message_id)); + // `Signin.SyncOptIn.IdentityPill.Shown` should be recorded with the correct + // access point. + histogram_tester.ExpectBucketCount( + "Signin.SyncOptIn.IdentityPill.Shown", + signin_metrics::AccessPoint::kHistorySyncOptinExpansionPillOnStartup, + /*expected_count=*/1); + histogram_tester.ExpectBucketCount( + "Signin.SyncOptIn.IdentityPill.Shown", + signin_metrics::AccessPoint::kHistorySyncOptinExpansionPillOnInactivity, + /*expected_count=*/1); // The button action should be overridden. EXPECT_TRUE(avatar->HasExplicitButtonAction()); + histogram_tester.ExpectTotalCount( + "Signin.SyncOptIn.IdentityPill.DurationBeforeClick", + /*expected_count=*/0); Click(avatar); + histogram_tester.ExpectTotalCount( + "Signin.SyncOptIn.IdentityPill.DurationBeforeClick", + /*expected_count=*/1); auto* coordinator = ProfileMenuCoordinator::FromBrowser(browser()); ASSERT_NE(coordinator, nullptr); EXPECT_TRUE(coordinator->IsShowing()); @@ -1640,6 +1685,7 @@ IN_PROC_BROWSER_TEST_P( AvatarToolbarButtonHistorySyncOptinClickBrowserTest, MAYBE_TriggersAndCollapsesConsistentlyAcrossMultipleBrowsers) { + base::HistogramTester histogram_tester; Profile* profile = browser()->profile(); Browser* browser_1 = browser(); AvatarToolbarButton* avatar_1 = GetAvatarToolbarButton(browser_1); @@ -1663,6 +1709,16 @@ EXPECT_EQ( avatar_2->GetText(), l10n_util::GetStringUTF16(GetParam().expected_history_sync_message_id)); + // `Signin.SyncOptIn.IdentityPill.Shown` histogram should be recorded only + // once. + histogram_tester.ExpectBucketCount( + "Signin.SyncOptIn.IdentityPill.Shown", + signin_metrics::AccessPoint::kHistorySyncOptinExpansionPillOnStartup, + /*expected_count=*/1); + histogram_tester.ExpectBucketCount( + "Signin.SyncOptIn.IdentityPill.Shown", + signin_metrics::AccessPoint::kHistorySyncOptinExpansionPillOnInactivity, + /*expected_count=*/0); avatar_1->TriggerTimeoutForTesting(AvatarDelayType::kHistorySyncOptin); // The button in both browsers comes back to the normal state. EXPECT_TRUE(avatar_1->GetText().empty()); @@ -1686,9 +1742,24 @@ EXPECT_EQ( avatar_3->GetText(), l10n_util::GetStringUTF16(GetParam().expected_history_sync_message_id)); + // `Signin.SyncOptIn.IdentityPill.Shown` histogram should be recorded only + // once. + histogram_tester.ExpectBucketCount( + "Signin.SyncOptIn.IdentityPill.Shown", + signin_metrics::AccessPoint::kHistorySyncOptinExpansionPillOnStartup, + /*expected_count=*/1); + histogram_tester.ExpectBucketCount( + "Signin.SyncOptIn.IdentityPill.Shown", + signin_metrics::AccessPoint::kHistorySyncOptinExpansionPillOnInactivity, + /*expected_count=*/1); // Clicking the button on any browser should collapse the history sync opt-in // in all browsers. Click(avatar_2); + // `Signin.SyncOptIn.IdentityPill.DurationBeforeClick` histogram should be + // recorded only once. + histogram_tester.ExpectTotalCount( + "Signin.SyncOptIn.IdentityPill.DurationBeforeClick", + /*expected_count=*/1); EXPECT_TRUE(avatar_1->GetText().empty()); EXPECT_TRUE(avatar_2->GetText().empty()); EXPECT_TRUE(avatar_3->GetText().empty());
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 90d7a2e..c46d045 100644 --- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc +++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
@@ -15,6 +15,7 @@ #include "base/functional/callback_helpers.h" #include "base/memory/raw_ref.h" #include "base/memory/weak_ptr.h" +#include "base/metrics/histogram_functions.h" #include "base/notreached.h" #include "base/scoped_observation.h" #include "base/strings/utf_string_conversions.h" @@ -533,6 +534,10 @@ } void PromoUsed() { + CHECK(before_promo_used_elapsed_timer_.has_value()); + base::UmaHistogramMediumTimes( + "Signin.SyncOptIn.IdentityPill.DurationBeforeClick", + before_promo_used_elapsed_timer_->Elapsed()); sync_promo_identity_pill_manager_.RecordPromoUsed(); Collapse(); } @@ -629,6 +634,7 @@ collapse_timer_.Stop(); } triggered_ = false; + before_promo_used_elapsed_timer_.reset(); state_changed_callbacks.Notify(); } @@ -638,8 +644,11 @@ // `HistorySyncOptin` in the next browser window(s). return; } + before_promo_used_elapsed_timer_.emplace(); has_been_shown_since_startup_ = true; sync_promo_identity_pill_manager_.RecordPromoShown(); + base::UmaHistogramEnumeration("Signin.SyncOptIn.IdentityPill.Shown", + access_point_); collapse_timer_.Start(FROM_HERE, g_history_sync_optin_duration_for_testing.value_or( kHistorySyncOptinDuration), @@ -683,6 +692,9 @@ bool has_been_shown_since_startup_ = false; base::OneShotTimer collapse_timer_; + // Timer to measure the time between the promo being shown and used (clicked). + std::optional<base::ElapsedTimer> before_promo_used_elapsed_timer_; + const raw_ref<Profile> profile_; signin::SyncPromoIdentityPillManager sync_promo_identity_pill_manager_;
diff --git a/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.cc b/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.cc index 65cde6f..428d8c7 100644 --- a/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.cc +++ b/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.cc
@@ -53,7 +53,7 @@ DCHECK(anchor_view); DCHECK(controller); - set_background_color(ui::kColorMenuBackground); + SetBackgroundColor(ui::kColorMenuBackground); SetAccessibleTitle(l10n_util::GetStringUTF16(IDS_SHARING_HUB_TOOLTIP)); SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone)); set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric(
diff --git a/chrome/browser/ui/views/side_panel/customize_chrome/customize_chrome_utils.cc b/chrome/browser/ui/views/side_panel/customize_chrome/customize_chrome_utils.cc index 5075ce8..d2d2759 100644 --- a/chrome/browser/ui/views/side_panel/customize_chrome/customize_chrome_utils.cc +++ b/chrome/browser/ui/views/side_panel/customize_chrome/customize_chrome_utils.cc
@@ -15,6 +15,7 @@ #include "extensions/browser/disable_reason.h" #include "extensions/browser/extension_registrar.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" namespace customize_chrome { @@ -55,4 +56,19 @@ {extensions::disable_reason::DISABLE_USER_ACTION}); } +bool IsExtensionNtp(const GURL& url, Profile* profile) { + if (!url.SchemeIs(extensions::kExtensionScheme)) { + return false; + } + + const extensions::Extension* extension_managing_ntp = + extensions::GetExtensionOverridingNewTabPage(profile); + + if (!extension_managing_ntp) { + return false; + } + + return extension_managing_ntp->id() == url.host(); +} + } // namespace customize_chrome
diff --git a/chrome/browser/ui/views/side_panel/customize_chrome/customize_chrome_utils.h b/chrome/browser/ui/views/side_panel/customize_chrome/customize_chrome_utils.h index fdb5725..2dcdde48 100644 --- a/chrome/browser/ui/views/side_panel/customize_chrome/customize_chrome_utils.h +++ b/chrome/browser/ui/views/side_panel/customize_chrome/customize_chrome_utils.h
@@ -5,6 +5,9 @@ #ifndef CHROME_BROWSER_UI_VIEWS_SIDE_PANEL_CUSTOMIZE_CHROME_CUSTOMIZE_CHROME_UTILS_H_ #define CHROME_BROWSER_UI_VIEWS_SIDE_PANEL_CUSTOMIZE_CHROME_CUSTOMIZE_CHROME_UTILS_H_ +#include "chrome/browser/profiles/profile.h" +#include "url/gurl.h" + namespace content { class BrowserContext; } @@ -19,6 +22,9 @@ void MaybeDisableExtensionOverridingNtp( content::BrowserContext* browser_context); +// Returns whether `url` belongs to an extension NTP. +bool IsExtensionNtp(const GURL& url, Profile* profile); + } // namespace customize_chrome #endif // CHROME_BROWSER_UI_VIEWS_SIDE_PANEL_CUSTOMIZE_CHROME_CUSTOMIZE_CHROME_UTILS_H_
diff --git a/chrome/browser/ui/views/side_panel/customize_chrome/side_panel_controller_views.cc b/chrome/browser/ui/views/side_panel/customize_chrome/side_panel_controller_views.cc index 5254f69b..d10e30d9 100644 --- a/chrome/browser/ui/views/side_panel/customize_chrome/side_panel_controller_views.cc +++ b/chrome/browser/ui/views/side_panel/customize_chrome/side_panel_controller_views.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/tabs/public/tab_features.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/side_panel/customize_chrome/customize_chrome_utils.h" #include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h" #include "chrome/browser/ui/views/side_panel/side_panel_web_ui_view.h" #include "chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h" @@ -97,26 +98,11 @@ } bool SidePanelControllerViews::ShouldEnableEditTheme(const GURL& url) const { - return NewTabPageUI::IsNewTabPageOrigin(url) || - (base::FeatureList::IsEnabled(ntp_features::kNtpFooter) && - IsExtensionNtp(url)); -} - -bool SidePanelControllerViews::IsExtensionNtp(const GURL& url) const { - if (!url.SchemeIs(extensions::kExtensionScheme)) { - return false; - } - Profile* const profile = Profile::FromBrowserContext(tab_->GetContents()->GetBrowserContext()); - const extensions::Extension* extension_managing_ntp = - extensions::GetExtensionOverridingNewTabPage(profile); - - if (!extension_managing_ntp) { - return false; - } - - return extension_managing_ntp->id() == url.host(); + return NewTabPageUI::IsNewTabPageOrigin(url) || + (base::FeatureList::IsEnabled(ntp_features::kNtpFooter) && + customize_chrome::IsExtensionNtp(url, profile)); } void SidePanelControllerViews::DidFinishNavigation( @@ -134,8 +120,7 @@ if (CanShowOnURL(url)) { CreateAndRegisterEntry(); if (customize_chrome_ui_) { - customize_chrome_ui_->AttachedTabStateUpdated( - NewTabPageUI::IsNewTabPageOrigin(url)); + customize_chrome_ui_->AttachedTabStateUpdated(url); customize_chrome_ui_->UpdateThemeEditable(ShouldEnableEditTheme(url)); } } else { @@ -241,8 +226,7 @@ entry = tab_->GetContents()->GetController().GetVisibleEntry(); } const GURL& url = entry->GetURL(); - customize_chrome_ui_->AttachedTabStateUpdated( - NewTabPageUI::IsNewTabPageOrigin(url)); + customize_chrome_ui_->AttachedTabStateUpdated(url); customize_chrome_ui_->UpdateThemeEditable(ShouldEnableEditTheme(url)); return customize_chrome_web_view;
diff --git a/chrome/browser/ui/views/side_panel/customize_chrome/side_panel_controller_views.h b/chrome/browser/ui/views/side_panel/customize_chrome/side_panel_controller_views.h index 7ec206b1..9842ad05 100644 --- a/chrome/browser/ui/views/side_panel/customize_chrome/side_panel_controller_views.h +++ b/chrome/browser/ui/views/side_panel/customize_chrome/side_panel_controller_views.h
@@ -66,9 +66,6 @@ // Returns true for 1P NTP or extension NTP, otherwise returns false. bool ShouldEnableEditTheme(const GURL& url) const; - // Helper function to check if the URL belongs to an extension NTP. - bool IsExtensionNtp(const GURL& url) const; - // Generates the view for the SidePanel contents. This is the WebUI for the // SidePanel. Used by the SidepanelRegistry to create the view. std::unique_ptr<views::View> CreateCustomizeChromeWebView(
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc index 0e70124a..cc04e1d 100644 --- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc +++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -32,9 +32,7 @@ #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/tab_ui_helper.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h" -#include "chrome/browser/ui/tabs/split_tab_data.h" #include "chrome/browser/ui/tabs/split_tab_util.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.h" @@ -67,7 +65,9 @@ #include "components/tab_groups/tab_group_color.h" #include "components/tab_groups/tab_group_id.h" #include "components/tab_groups/tab_group_visual_data.h" +#include "components/tabs/public/split_tab_data.h" #include "components/tabs/public/split_tab_id.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_interface.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h"
diff --git a/chrome/browser/ui/views/tabs/groups/avatar_container_view.cc b/chrome/browser/ui/views/tabs/groups/avatar_container_view.cc index be77ce9..57764330 100644 --- a/chrome/browser/ui/views/tabs/groups/avatar_container_view.cc +++ b/chrome/browser/ui/views/tabs/groups/avatar_container_view.cc
@@ -26,6 +26,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/views/layout/box_layout.h" #include "ui/views/style/typography.h" +#include "ui/views/style/typography_provider.h" #include "ui/views/view_class_properties.h" #include "ui/views/widget/widget.h" @@ -78,8 +79,9 @@ int number, SkColor text_color, int font_size) { - gfx::FontList font_list({"Google Sans", "Roboto"}, gfx::Font::NORMAL, - font_size, gfx::Font::Weight::NORMAL); + const auto& font_list = views::TypographyProvider::Get().GetFont( + views::style::TextContext::CONTEXT_DIALOG_BODY_TEXT, + views::style::TextStyle::STYLE_CAPTION_MEDIUM); gfx::Rect text_bounds(0, 0, diameter, diameter); canvas.DrawStringRectWithFlags( base::UTF8ToUTF16("+" + base::NumberToString(number)), font_list,
diff --git a/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view.cc b/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view.cc index 83b2d6f..e7ab4ce 100644 --- a/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view.cc +++ b/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view.cc
@@ -107,21 +107,6 @@ return user; } -// Gets the string for the metadata line to describe an event. -std::u16string GetMetadataText(const ActivityLogItem& item) { - if (item.description_text == u"") { - // If there is no description, the line simply contains elapsed time - // since the action. - return item.time_delta_text; - } else { - // The metadata line contains the item's description, a bullet point, - // and the elapsed time since the action, separated by spaces. - std::u16string_view separator = u" "; - return base::JoinString( - {item.description_text, kBulletPoint, item.time_delta_text}, separator); - } -} - // TODO(crbug.com/392150086): Refactor this into utilities. std::optional<tab_groups::LocalTabGroupID> UnwrapGroupId( const ActivityLogItem& item) { @@ -389,24 +374,64 @@ // Let hover button process events. label_container->SetCanProcessEventsWithinSubtree(false); - activity_text_ = item.title_text; auto* activity_label = label_container->AddChildView(std::make_unique<views::Label>()); - activity_label->SetText(activity_text_); + activity_label->SetText(item.title_text); activity_label->SetTextStyle(views::style::TextStyle::STYLE_BODY_4_MEDIUM); activity_label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); - metadata_text_ = GetMetadataText(item_); - auto* metadata_label = - label_container->AddChildView(std::make_unique<views::Label>()); - metadata_label->SetText(metadata_text_); - metadata_label->SetTextStyle(views::style::TextStyle::STYLE_BODY_5); - metadata_label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); - metadata_label->SetEnabledColor(ui::kColorSysOnSurfaceSubtle); + auto* metadata_container = + label_container->AddChildView(std::make_unique<views::View>()); + auto* metadata_layout = metadata_container->SetLayoutManager( + std::make_unique<views::FlexLayout>()); + metadata_layout->SetOrientation(views::LayoutOrientation::kHorizontal); + + auto* description_label = metadata_container->AddChildView( + std::make_unique<views::Label>(item.description_text)); + description_label->SetTextStyle(views::style::TextStyle::STYLE_BODY_5); + description_label->SetHorizontalAlignment( + gfx::HorizontalAlignment::ALIGN_LEFT); + description_label->SetEnabledColor(ui::kColorSysOnSurfaceSubtle); + + // The email will be elided by using up all available space in the layout. + description_label->SetProperty( + views::kFlexBehaviorKey, + views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero, + views::MaximumFlexSizeRule::kPreferred)); + + // The time text is not elided and takes up as much space as possible. It only + // has a delimiter if there is a description. + std::u16string time_text; + if (item.description_text.size() > 0) { + time_text += kBulletPoint + u" "; + } + time_text += item_.time_delta_text; + + auto* time_label = metadata_container->AddChildView( + std::make_unique<views::Label>(time_text)); + time_label->SetTextStyle(views::style::TextStyle::STYLE_BODY_5); + time_label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_RIGHT); + time_label->SetEnabledColor(ui::kColorSysOnSurfaceSubtle); + + // The time value will be completely shown on the right. + time_label->SetProperty( + views::kFlexBehaviorKey, + views::FlexSpecification(views::MinimumFlexSizeRule::kPreferred, + views::MaximumFlexSizeRule::kPreferred)); + + // Add extra padding matching the ImageView on the left. + gfx::Insets margins; + margins.set_right(ChromeLayoutProvider::Get() + ->GetInsetsMetric(INSETS_RECENT_ACTIVITY_IMAGE_MARGIN) + .left()); + time_label->SetProperty(views::kMarginsKey, margins); GetViewAccessibility().SetRole(ax::mojom::Role::kRow); - GetViewAccessibility().SetName(activity_text_); - GetViewAccessibility().SetDescription(metadata_text_); + GetViewAccessibility().SetName(item.title_text); + GetViewAccessibility().SetDescription((item_.description_text.size() > 0 + ? item_.description_text + u" " + : u"") + + time_text); SetFocusBehavior(FocusBehavior::ALWAYS); SetFocusBehavior(views::PlatformStyle::kDefaultFocusBehavior); SetEnabled(GetActionEnabledForItem(item_));
diff --git a/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view.h b/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view.h index a042299..3898e4a 100644 --- a/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view.h +++ b/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view.h
@@ -95,8 +95,6 @@ void ButtonPressed(); RecentActivityRowImageView* image_view() const { return image_view_; } - const std::u16string& activity_text() const { return activity_text_; } - const std::u16string& metadata_text() const { return metadata_text_; } // RecentActivityAction handlers. // Focuses the open tab in the tab strip. @@ -109,8 +107,6 @@ void ManageSharing(); private: - std::u16string activity_text_; - std::u16string metadata_text_; raw_ptr<RecentActivityRowImageView> image_view_ = nullptr; ActivityLogItem item_; const raw_ptr<Profile> profile_ = nullptr;
diff --git a/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view_browsertest.cc b/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view_browsertest.cc index a57368a..eccd3a63 100644 --- a/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/tabs/recent_activity_bubble_dialog_view_browsertest.cc
@@ -324,27 +324,29 @@ EXPECT_EQ(bubble->GetWindowTitle(), u"Recent activity"); #endif - EXPECT_EQ(bubble->GetRowForTesting(0)->activity_text(), u"You changed a tab"); - EXPECT_EQ(bubble->GetRowForTesting(0)->metadata_text(), + EXPECT_EQ(bubble->GetRowForTesting(0)->GetAccessibleName(), + u"You changed a tab"); + EXPECT_EQ(bubble->GetRowForTesting(0)->GetAccessibleDescription(), u"airbnb.com \u2022 5h ago"); - EXPECT_EQ(bubble->GetRowForTesting(1)->activity_text(), + EXPECT_EQ(bubble->GetRowForTesting(1)->GetAccessibleName(), u"Shirley changed a tab"); - EXPECT_EQ(bubble->GetRowForTesting(1)->metadata_text(), + EXPECT_EQ(bubble->GetRowForTesting(1)->GetAccessibleDescription(), u"hotels.com \u2022 4h ago"); - EXPECT_EQ(bubble->GetRowForTesting(2)->activity_text(), + EXPECT_EQ(bubble->GetRowForTesting(2)->GetAccessibleName(), u"Elisa removed a tab"); - EXPECT_EQ(bubble->GetRowForTesting(2)->metadata_text(), + EXPECT_EQ(bubble->GetRowForTesting(2)->GetAccessibleDescription(), u"expedia.com \u2022 6h ago"); - EXPECT_EQ(bubble->GetRowForTesting(3)->activity_text(), + EXPECT_EQ(bubble->GetRowForTesting(3)->GetAccessibleName(), u"Shirley joined the group"); - EXPECT_EQ(bubble->GetRowForTesting(3)->metadata_text(), + EXPECT_EQ(bubble->GetRowForTesting(3)->GetAccessibleDescription(), u"shirleys-email \u2022 8h ago"); - EXPECT_EQ(bubble->GetRowForTesting(4)->activity_text(), u"Elisa added a tab"); - EXPECT_EQ(bubble->GetRowForTesting(4)->metadata_text(), + EXPECT_EQ(bubble->GetRowForTesting(4)->GetAccessibleName(), + u"Elisa added a tab"); + EXPECT_EQ(bubble->GetRowForTesting(4)->GetAccessibleDescription(), u"expedia.com \u2022 2d ago"); }
diff --git a/chrome/browser/ui/views/tabs/tab_strip_action_container.cc b/chrome/browser/ui/views/tabs/tab_strip_action_container.cc index 48fb991..c271096 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_action_container.cc +++ b/chrome/browser/ui/views/tabs/tab_strip_action_container.cc
@@ -463,6 +463,7 @@ } ExecuteHideTabStripNudge(glic_button_); + glic_button_->SetText(std::u16string()); } void TabStripActionContainer::OnGlicButtonDismissed() {
diff --git a/chrome/browser/ui/views/toolbar/split_tabs_button.cc b/chrome/browser/ui/views/toolbar/split_tabs_button.cc index 973d28ad..c81260d 100644 --- a/chrome/browser/ui/views/toolbar/split_tabs_button.cc +++ b/chrome/browser/ui/views/toolbar/split_tabs_button.cc
@@ -14,15 +14,15 @@ #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" -#include "chrome/browser/ui/tabs/split_tab_data.h" #include "chrome/browser/ui/tabs/split_tab_menu_model.h" #include "chrome/browser/ui/tabs/split_tab_util.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/views/toolbar/toolbar_button.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "components/prefs/pref_service.h" +#include "components/tabs/public/split_tab_data.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_interface.h" #include "ui/base/interaction/element_identifier.h" #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/views/toolbar/split_tabs_button_interactive_ui_test.cc b/chrome/browser/ui/views/toolbar/split_tabs_button_interactive_ui_test.cc index 1c79efd..62a5597 100644 --- a/chrome/browser/ui/views/toolbar/split_tabs_button_interactive_ui_test.cc +++ b/chrome/browser/ui/views/toolbar/split_tabs_button_interactive_ui_test.cc
@@ -9,9 +9,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_element_identifiers.h" -#include "chrome/browser/ui/tabs/split_tab_collection.h" #include "chrome/browser/ui/tabs/split_tab_menu_model.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_menu_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" @@ -27,6 +25,8 @@ #include "chrome/test/base/ui_test_utils.h" #include "chrome/test/interaction/interactive_browser_test.h" #include "components/prefs/pref_service.h" +#include "components/tabs/public/split_tab_collection.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "content/public/test/browser_test.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h"
diff --git a/chrome/browser/ui/views/web_apps/web_app_icon_name_and_origin_view.cc b/chrome/browser/ui/views/web_apps/web_app_icon_name_and_origin_view.cc index c572ec2..a3dd763 100644 --- a/chrome/browser/ui/views/web_apps/web_app_icon_name_and_origin_view.cc +++ b/chrome/browser/ui/views/web_apps/web_app_icon_name_and_origin_view.cc
@@ -11,13 +11,21 @@ #include "base/strings/string_util.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/web_apps/web_app_views_utils.h" +#include "chrome/browser/ui/web_applications/web_app_dialogs.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/controls/image_view.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/layout_provider.h" +#include "ui/views/view_class_properties.h" #include "url/gurl.h" +namespace web_app { +DEFINE_ELEMENT_IDENTIFIER_VALUE(kSimpleInstallDialogAppTitle); +DEFINE_ELEMENT_IDENTIFIER_VALUE(kSimpleInstallDialogIconView); +DEFINE_ELEMENT_IDENTIFIER_VALUE(kSimpleInstallDialogOriginLabel); +} // namespace web_app + std::unique_ptr<WebAppIconNameAndOriginView> WebAppIconNameAndOriginView::Create(const gfx::ImageSkia& icon_image, std::u16string app_title, @@ -41,6 +49,8 @@ auto icon_view = std::make_unique<views::ImageView>(); icon_view->SetImage(ui::ImageModel::FromImageSkia(icon_image)); + icon_view->SetProperty(views::kElementIdentifierKey, + web_app::kSimpleInstallDialogIconView); AddChildViewRaw(icon_view.release()); views::View* labels = new views::View(); @@ -48,9 +58,16 @@ labels->SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kVertical)); - labels->AddChildViewRaw(web_app::CreateNameLabel(app_title).release()); - labels->AddChildViewRaw( - web_app::CreateOriginLabelFromStartUrl(start_url, false).release()); + auto name_label = web_app::CreateNameLabel(app_title); + name_label->SetProperty(views::kElementIdentifierKey, + web_app::kSimpleInstallDialogAppTitle); + labels->AddChildView(std::move(name_label)); + + auto origin_label = web_app::CreateOriginLabelFromStartUrl( + start_url, /*is_primary_text=*/false); + origin_label->SetProperty(views::kElementIdentifierKey, + web_app::kSimpleInstallDialogOriginLabel); + labels->AddChildView(std::move(origin_label)); } BEGIN_METADATA(WebAppIconNameAndOriginView)
diff --git a/chrome/browser/ui/views/web_apps/web_app_simple_install_dialog.cc b/chrome/browser/ui/views/web_apps/web_app_simple_install_dialog.cc index 46743ab9..91d459f 100644 --- a/chrome/browser/ui/views/web_apps/web_app_simple_install_dialog.cc +++ b/chrome/browser/ui/views/web_apps/web_app_simple_install_dialog.cc
@@ -148,8 +148,8 @@ } } -void SetAutoAcceptPWAInstallConfirmationForTesting(bool auto_accept) { - g_auto_accept_pwa_for_testing = auto_accept; +base::AutoReset<bool> SetAutoAcceptPWAInstallConfirmationForTesting() { + return base::AutoReset<bool>(&g_auto_accept_pwa_for_testing, true); } base::AutoReset<bool> SetDontCloseOnDeactivateForTesting() {
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc b/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc index 44e20b2..543b1c30 100644 --- a/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc
@@ -697,7 +697,7 @@ CreateAccountSelectionBubble(); // Set the dialog background color to white. - dialog()->set_background_color(SK_ColorWHITE); + dialog()->SetBackgroundColor(SK_ColorWHITE); const std::string kDarkBlue = "#1a73e8"; SkColor bg_color; @@ -730,7 +730,7 @@ CreateAccountSelectionBubble(); // Set the dialog background color to white. - dialog()->set_background_color(SK_ColorWHITE); + dialog()->SetBackgroundColor(SK_ColorWHITE); const std::string kWhite = "#fff"; SkColor bg_color;
diff --git a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc index 6118577..6ae9a30 100644 --- a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc +++ b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
@@ -272,6 +272,24 @@ return true; } +void CreateWebAppForBackgroundInstall( + content::WebContents* initiating_web_contents, + std::unique_ptr<webapps::MlInstallOperationTracker> tracker, + const GURL& install_url, + const std::optional<GURL>& manifest_id, + WebAppInstalledCallback installed_callback) { + auto* provider = WebAppProvider::GetForWebContents(initiating_web_contents); + CHECK(provider); + + provider->scheduler().InstallAppFromUrl( + install_url, manifest_id, initiating_web_contents->GetWeakPtr(), + base::BindOnce(&OnWebAppInstallShowInstallDialog, + WebAppInstallFlow::kInstallSite, + webapps::WebappInstallSource::WEB_INSTALL, + PwaInProductHelpState::kNotShown, std::move(tracker)), + std::move(installed_callback)); +} + void ShowPwaInstallDialog(Browser* browser) { CHECK(browser);
diff --git a/chrome/browser/ui/web_applications/web_app_dialog_utils.h b/chrome/browser/ui/web_applications/web_app_dialog_utils.h index ee88a61..46b626d 100644 --- a/chrome/browser/ui/web_applications/web_app_dialog_utils.h +++ b/chrome/browser/ui/web_applications/web_app_dialog_utils.h
@@ -51,6 +51,17 @@ WebAppInstalledCallback installed_callback, PwaInProductHelpState iph_state = PwaInProductHelpState::kNotShown); +// Starts the background install of a WebApp at `install_url`, initiated from a +// `navigator.install` call from within `initiating_web_contents`. This must be +// called from a context where `WebAppProvider` exists and is supported. +// Used for the Web Install API. +void CreateWebAppForBackgroundInstall( + content::WebContents* initiating_web_contents, + std::unique_ptr<webapps::MlInstallOperationTracker> tracker, + const GURL& install_url, + const std::optional<GURL>& manifest_id, + WebAppInstalledCallback installed_callback); + // Shows the PWA Install dialog for the active tab in the provided browser. // Records PWAInstallIcon user metric and closes the PWA install IPH // if it is showing.
diff --git a/chrome/browser/ui/web_applications/web_app_dialogs.h b/chrome/browser/ui/web_applications/web_app_dialogs.h index e5a8b3cc..2ce0e37d 100644 --- a/chrome/browser/ui/web_applications/web_app_dialogs.h +++ b/chrome/browser/ui/web_applications/web_app_dialogs.h
@@ -127,6 +127,10 @@ kNotShown }; +DECLARE_ELEMENT_IDENTIFIER_VALUE(kSimpleInstallDialogAppTitle); +DECLARE_ELEMENT_IDENTIFIER_VALUE(kSimpleInstallDialogIconView); +DECLARE_ELEMENT_IDENTIFIER_VALUE(kSimpleInstallDialogOriginLabel); + // Shows the PWA installation confirmation bubble anchored off the PWA install // icon in the omnibox. // @@ -165,7 +169,7 @@ // Sets whether |ShowSimpleInstallDialogForWebApps| should accept immediately // without any user interaction. -void SetAutoAcceptPWAInstallConfirmationForTesting(bool auto_accept); +base::AutoReset<bool> SetAutoAcceptPWAInstallConfirmationForTesting(); // Sets whether |ShowDiyInstallDialogForWebApps| should accept immediately // without any user interaction.
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc index 1a567b40..a7e8a8a 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc +++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
@@ -53,6 +53,7 @@ #include "components/user_education/common/feature_promo/feature_promo_result.h" #include "components/user_education/common/user_education_data.h" #include "components/webapps/browser/installable/installable_metrics.h" +#include "components/webapps/browser/installable/ml_install_operation_tracker.h" #include "components/webapps/browser/uninstall_result_code.h" #include "components/webapps/common/web_app_id.h" #include "content/public/browser/clear_site_data_utils.h" @@ -424,6 +425,17 @@ web_app::CreateWebAppFromManifest(web_contents, source, std::move(callback)); } +void WebAppUiManagerImpl::TriggerInstallDialogForBackgroundInstall( + content::WebContents* initiating_web_contents, + std::unique_ptr<webapps::MlInstallOperationTracker> tracker, + const GURL& install_url, + const std::optional<GURL>& manifest_id, + InstallCallback callback) { + web_app::CreateWebAppForBackgroundInstall(initiating_web_contents, + std::move(tracker), install_url, + manifest_id, std::move(callback)); +} + void WebAppUiManagerImpl::PresentUserUninstallDialog( const webapps::AppId& app_id, webapps::WebappUninstallSource uninstall_source,
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h index 5eee8be973..c8155c84 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h +++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
@@ -137,6 +137,12 @@ void TriggerInstallDialog(content::WebContents* web_contents, webapps::WebappInstallSource source, InstallCallback callback) override; + void TriggerInstallDialogForBackgroundInstall( + content::WebContents* initiating_web_contents, + std::unique_ptr<webapps::MlInstallOperationTracker> tracker, + const GURL& install_url, + const std::optional<GURL>& manifest_id, + InstallCallback callback) override; void PresentUserUninstallDialog( const webapps::AppId& app_id,
diff --git a/chrome/browser/ui/webid/identity_dialog_controller.cc b/chrome/browser/ui/webid/identity_dialog_controller.cc index 64e1426..1f8262d 100644 --- a/chrome/browser/ui/webid/identity_dialog_controller.cc +++ b/chrome/browser/ui/webid/identity_dialog_controller.cc
@@ -402,7 +402,7 @@ } void IdentityDialogController::CollectTrainingData(UserAction user_action) { - if (!training_request_id_ || !segmentation_platform_service_) { + if (!training_request_id_.has_value() || !segmentation_platform_service_) { return; }
diff --git a/chrome/browser/ui/webui/ash/settings/pages/about/about_section.cc b/chrome/browser/ui/webui/ash/settings/pages/about/about_section.cc index 76c6d26a..851e3ef5 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/about/about_section.cc +++ b/chrome/browser/ui/webui/ash/settings/pages/about/about_section.cc
@@ -255,6 +255,8 @@ {"aboutDiagnostics", IDS_SETTINGS_ABOUT_PAGE_DIAGNOSTICS}, {"aboutDiagnosticseDescription", IDS_OS_SETTINGS_DIAGNOSTICS_DESCRIPTION}, {"aboutFirmwareUpdates", IDS_SETTINGS_ABOUT_PAGE_FIRMWARE_UPDATES}, + {"aboutFirmwareUpdatesDisabledDescription", + IDS_OS_SETTINGS_FIRMWARE_DISABLED_DESCRIPTION}, {"aboutFirmwareUpToDateDescription", IDS_OS_SETTINGS_FIRMWARE_UP_TO_DATE_DESCRIPTION}, {"aboutFirmwareUpdateAvailableDescription",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc b/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc index 42696aa5..0ed54c2 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc +++ b/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc
@@ -471,6 +471,14 @@ {"languagesDictionaryDownloadRetryDescription", IDS_OS_SETTINGS_LANGUAGES_DICTIONARY_DOWNLOAD_RETRY_DESCRIPTION}, {"editDictionaryLabel", IDS_OS_SETTINGS_LANGUAGES_EDIT_DICTIONARY_LABEL}, + {"japaneseClearPersonalizationData", + IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_CLEAR_PERSONALIZATION_DATA}, + {"japaneseDeleteItems", + IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_DELETE_ITEMS}, + {"japaneseConversationHistory", + IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_CONVERSATION_HISTORY}, + {"japaneseSuggestionHistory", + IDS_SETTINGS_INPUT_METHOD_OPTIONS_JAPANESE_SUGGESTION_HISTORY}, {"japaneseManageUserDictionaryLabel", IDS_OS_SETTINGS_LANGUAGES_JAPANESE_MANAGE_USER_DICTIONARY_LABEL}, {"japaneseDictionary",
diff --git a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc index 40f8a81c..2e71397 100644 --- a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc +++ b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc
@@ -34,6 +34,11 @@ #if BUILDFLAG(IS_ANDROID) #include "chrome/browser/password_manager/android/password_manager_eviction_util.h" +#else +#include "chrome/browser/ui/browser_window/public/browser_window_interface.h" +#include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "components/autofill/content/browser/content_autofill_driver.h" #endif using autofill::LogRouter; @@ -130,6 +135,10 @@ "resetUpmEviction", base::BindRepeating(&InternalsUIHandler::OnResetUpmEviction, base::Unretained(this))); +#else + web_ui()->RegisterMessageCallback( + "setDomNodeId", base::BindRepeating(&InternalsUIHandler::SetDomNodeId, + base::Unretained(this))); #endif } @@ -253,6 +262,24 @@ FireWebUIListener("enable-reset-upm-eviction-button", base::Value(!is_user_unenrolled)); } +#else +void InternalsUIHandler::SetDomNodeId(const base::Value::List& args) { + for (auto* browser : GetAllBrowserWindowInterfaces()) { + if (!browser->GetTabStripModel()) { + continue; + } + + for (int i = 0; i < browser->GetTabStripModel()->count(); i++) { + auto* web_contents = browser->GetTabStripModel()->GetWebContentsAt(i); + autofill::AutofillDriver* driver = + ContentAutofillDriver::GetForRenderFrameHost( + web_contents->GetPrimaryMainFrame()); + if (driver) { + driver->ExposeDomNodeIDs(); + } + } + } +} #endif void InternalsUIHandler::StartSubscription() {
diff --git a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.h b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.h index 1f1abeb9..8f8936cf 100644 --- a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.h +++ b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.h
@@ -92,7 +92,11 @@ void OnGetAutofillAiCache(const base::Value::List& args); void OnLoaded(const base::Value::List& args); void OnResetCache(const base::Value::List& args); +#if BUILDFLAG(IS_ANDROID) void OnResetUpmEviction(const base::Value::List& args); +#else + void SetDomNodeId(const base::Value::List& args); +#endif void OnResetCacheDone(const std::string& message);
diff --git a/chrome/browser/ui/webui/bookmarks/bookmarks_ui.cc b/chrome/browser/ui/webui/bookmarks/bookmarks_ui.cc index 469efd3..609936a6 100644 --- a/chrome/browser/ui/webui/bookmarks/bookmarks_ui.cc +++ b/chrome/browser/ui/webui/bookmarks/bookmarks_ui.cc
@@ -9,7 +9,6 @@ #include <string> #include <utility> -#include "base/feature_list.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/webui/bookmarks/bookmarks_message_handler.h" @@ -58,8 +57,6 @@ source->AddString("undoDescription", l10n_util::GetStringFUTF16( IDS_UNDO_DESCRIPTION, undo_accelerator.GetShortcutText())); - source->AddBoolean("splitViewEnabled", - base::FeatureList::IsEnabled(features::kSideBySide)); // Localized strings (alphabetical order). static constexpr webui::LocalizedString kStrings[] = { @@ -114,7 +111,6 @@ {"menuOpenNewTabGroup", IDS_BOOKMARK_MANAGER_MENU_OPEN_IN_NEW_TAB_GROUP}, {"menuOpenNewWindow", IDS_BOOKMARK_MANAGER_MENU_OPEN_IN_NEW_WINDOW}, {"menuOpenIncognito", IDS_BOOKMARK_MANAGER_MENU_OPEN_INCOGNITO}, - {"menuOpenSplitView", IDS_BOOKMARK_MANAGER_MENU_OPEN_IN_SPLIT_VIEW}, {"menuRename", IDS_BOOKMARK_MANAGER_MENU_RENAME}, {"menuShowInFolder", IDS_BOOKMARK_MANAGER_MENU_SHOW_IN_FOLDER}, {"menuSort", IDS_BOOKMARK_MANAGER_MENU_SORT},
diff --git a/chrome/browser/ui/webui/discards/discards_ui.cc b/chrome/browser/ui/webui/discards/discards_ui.cc index 6d6dd2b2..4cb1277 100644 --- a/chrome/browser/ui/webui/discards/discards_ui.cc +++ b/chrome/browser/ui/webui/discards/discards_ui.cc
@@ -151,7 +151,7 @@ page_node, DiscardEligibilityPolicy::DiscardReason::URGENT); candidates.emplace_back(page_node->GetWeakPtr(), can_discard_result, page_node->IsVisible(), page_node->IsFocused(), - page_node->GetTimeSinceLastVisibilityChange()); + page_node->GetLastVisibilityChangeTime()); } // Sorts with ascending importance.
diff --git a/chrome/browser/ui/webui/new_tab_footer/BUILD.gn b/chrome/browser/ui/webui/new_tab_footer/BUILD.gn index 2270c12..c509cd82 100644 --- a/chrome/browser/ui/webui/new_tab_footer/BUILD.gn +++ b/chrome/browser/ui/webui/new_tab_footer/BUILD.gn
@@ -23,8 +23,12 @@ "new_tab_footer_handler.cc", "new_tab_footer_ui.cc", ] + + public_deps = [ "//chrome/browser:browser_public_dependencies" ] + deps = [ ":new_tab_footer", + "//chrome/browser:browser_process", "//chrome/browser/extensions", "//chrome/browser/profiles", "//chrome/browser/resources/new_tab_footer:resources_grit", @@ -40,6 +44,7 @@ deps = [ ":new_tab_footer", "//base/test:test_support", + "//chrome/browser/ui:ui_features", "//chrome/test:test_support", ] }
diff --git a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer.mojom b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer.mojom index cf9a315..4ea73ef 100644 --- a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer.mojom +++ b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer.mojom
@@ -14,12 +14,20 @@ string name; }; +// Enterprise browser management notice +struct ManagementNotice { + // Human readable string for notice text. This will indicate that the browser + // is managed and the entity managing the browser, which is customizable via + // the `EnterpriseCustomLabel` policy. + string text; +}; + // Used by the WebUI document to bootstrap bidirectional communication. interface NewTabFooterHandlerFactory { // The WebUI page's |BrowserProxy| singleton calls this method when the // document is first initialized. CreateNewTabFooterHandler(pending_remote<NewTabFooterDocument> document, - pending_receiver<NewTabFooterHandler> handler); + pending_receiver<NewTabFooterHandler> handler); }; // Browser-side handler for requests from WebUI document. @@ -27,7 +35,14 @@ // Gets the attribution for an extension overriding the new tab // page, if there is one. GetNtpExtensionAttribution() => (ExtensionAttribution? attribution); + + // Requests an update to the enterprise management notice for a managed + // browser. + UpdateManagementNotice(); }; // WebUI-side handler for requests from the browser. -interface NewTabFooterDocument {}; +interface NewTabFooterDocument { + // Sets the enterprise management notice for a managed browser. + SetManagementNotice(ManagementNotice? notice); +};
diff --git a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc index b18d6ed..0f5438b0 100644 --- a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc +++ b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc
@@ -6,11 +6,24 @@ #include <utility> +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/enterprise/util/managed_browser_utils.h" #include "chrome/browser/extensions/settings_api_helpers.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/managed_ui.h" #include "chrome/browser/ui/webui/new_tab_footer/new_tab_footer.mojom.h" +#include "chrome/common/pref_names.h" #include "chrome/common/webui_url_constants.h" +#include "chrome/grit/branded_strings.h" +#include "chrome/grit/generated_resources.h" +#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h" +#include "components/prefs/pref_service.h" +#include "components/strings/grit/components_strings.h" +#include "content/public/browser/web_contents.h" #include "net/base/url_util.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/webui/web_ui_util.h" NewTabFooterHandler::NewTabFooterHandler( mojo::PendingReceiver<new_tab_footer::mojom::NewTabFooterHandler> @@ -41,3 +54,34 @@ attribution->name = ntp_extension->name(); std::move(callback).Run(std::move(attribution)); } + +void NewTabFooterHandler::UpdateManagementNotice() { + if (!enterprise_util::CanShowEnterpriseBadgingForNTPFooter(profile_)) { + document_->SetManagementNotice(nullptr); + return; + } + + auto notice = new_tab_footer::mojom::ManagementNotice::New(); + notice->text = GetManagementNoticeText(); + document_->SetManagementNotice(std::move(notice)); +} + +std::string NewTabFooterHandler::GetManagementNoticeText() { + CHECK(enterprise_util::CanShowEnterpriseBadgingForNTPFooter(profile_)); + + // Return "Managed by <label>" if custom label is set. + std::string custom_label = g_browser_process->local_state()->GetString( + prefs::kEnterpriseCustomLabelForBrowser); + if (!custom_label.empty()) { + return l10n_util::GetStringFUTF8(IDS_MANAGED_BY, + base::UTF8ToUTF16(custom_label)); + } + + // Return "Managed by <management domain>" if a cloud manager is known. + // Otherwise return the generic "Managed by your organization" message. + std::optional<std::string> cloud_policy_manager = GetDeviceManagerIdentity(); + return cloud_policy_manager && !cloud_policy_manager->empty() + ? l10n_util::GetStringFUTF8( + IDS_MANAGED_BY, base::UTF8ToUTF16(*cloud_policy_manager)) + : l10n_util::GetStringUTF8(IDS_MANAGED); +}
diff --git a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.h b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.h index d03c112..4409e12 100644 --- a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.h +++ b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.h
@@ -31,8 +31,11 @@ // new_tab_footer::mojom::NewTabFooterHandler: void GetNtpExtensionAttribution( GetNtpExtensionAttributionCallback callback) override; + void UpdateManagementNotice() override; private: + std::string GetManagementNoticeText(); + const raw_ptr<Profile> profile_; raw_ptr<content::WebContents> web_contents_; mojo::Remote<new_tab_footer::mojom::NewTabFooterDocument> document_;
diff --git a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc index 91c349b..1c93bdb9 100644 --- a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc +++ b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
@@ -20,6 +20,40 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/enterprise/browser_management/management_service_factory.h" +#include "chrome/browser/ui/managed_ui.h" +#include "chrome/browser/ui/ui_features.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "components/policy/core/common/management/scoped_management_service_override_for_testing.h" +#include "content/public/test/browser_task_environment.h" +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) + +using testing::_; + +class MockNewTabFooterDocument + : public new_tab_footer::mojom::NewTabFooterDocument { + public: + MockNewTabFooterDocument() = default; + ~MockNewTabFooterDocument() override = default; + + mojo::PendingRemote<new_tab_footer::mojom::NewTabFooterDocument> + BindAndGetRemote() { + DCHECK(!receiver_.is_bound()); + return receiver_.BindNewPipeAndPassRemote(); + } + + void FlushForTesting() { receiver_.FlushForTesting(); } + + MOCK_METHOD(void, + SetManagementNotice, + (new_tab_footer::mojom::ManagementNoticePtr)); + mojo::Receiver<new_tab_footer::mojom::NewTabFooterDocument> receiver_{this}; +}; + class NewTabFooterHandlerExtensionTest : public extensions::ExtensionServiceTestBase { public: @@ -37,7 +71,7 @@ NewTabFooterHandler& handler() { return *handler_; } - private: + protected: std::unique_ptr<content::WebContents> web_contents_; std::unique_ptr<NewTabFooterHandler> handler_; }; @@ -90,3 +124,104 @@ net::AppendOrReplaceQueryParameter( GURL(chrome::kChromeUIExtensionsURL), "id", extension->id())); } + +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) +class NewTabFooterHandlerEnterpriseTest : public testing::Test { + public: + void SetUp() override { + profile_manager_ = std::make_unique<TestingProfileManager>( + TestingBrowserProcess::GetGlobal()); + ASSERT_TRUE(profile_manager_->SetUp()); + profile_ = profile_manager_->CreateTestingProfile("Test Profile"); + web_contents_ = content::WebContents::Create( + content::WebContents::CreateParams(profile_)); + feature_list_.InitAndEnableFeature( + features::kEnterpriseBadgingForNtpFooter); + handler_ = std::make_unique<NewTabFooterHandler>( + mojo::PendingReceiver<new_tab_footer::mojom::NewTabFooterHandler>(), + document_.BindAndGetRemote(), web_contents_.get()); + } + + void TearDown() override { + // Ensure that the handler is destroyed before the profile. + handler_.reset(); + web_contents_.reset(); + profile_ = nullptr; + profile_manager_->DeleteAllTestingProfiles(); + profile_manager_.reset(); + } + + NewTabFooterHandler& handler() { return *handler_; } + Profile* profile() { return profile_; } + + protected: + content::BrowserTaskEnvironment task_environment_; + std::unique_ptr<content::WebContents> web_contents_; + std::unique_ptr<NewTabFooterHandler> handler_; + std::unique_ptr<TestingProfileManager> profile_manager_; + raw_ptr<TestingProfile> profile_; + testing::NiceMock<MockNewTabFooterDocument> document_; + base::test::ScopedFeatureList feature_list_; +}; + +TEST_F(NewTabFooterHandlerEnterpriseTest, SetManagementNoticeWithDefaultText) { + // Simulate browser management. + policy::ScopedManagementServiceOverrideForTesting + profile_supervised_management( + policy::ManagementServiceFactory::GetForProfile(profile()), + policy::EnterpriseManagementAuthority::DOMAIN_LOCAL); + + // Browser management is local, so no domain is indicated in the managent + // notice text. + EXPECT_CALL(document_, SetManagementNotice) + .WillOnce([](new_tab_footer::mojom::ManagementNoticePtr notice) { + EXPECT_EQ("Managed by your organization", notice->text); + }); + handler().UpdateManagementNotice(); + + document_.FlushForTesting(); + testing::Mock::VerifyAndClearExpectations(&document_); +} + +TEST_F(NewTabFooterHandlerEnterpriseTest, SetManagementNoticeWithCustomtext) { + // Simulate browser management. + policy::ScopedManagementServiceOverrideForTesting + profile_supervised_management( + policy::ManagementServiceFactory::GetForProfile(profile()), + policy::EnterpriseManagementAuthority::DOMAIN_LOCAL); + + // Set a custom label policy, which will be used in the management notice + // text. + profile_manager_->local_state()->Get()->SetString( + prefs::kEnterpriseCustomLabelForBrowser, "custom label"); + EXPECT_CALL(document_, SetManagementNotice) + .WillOnce([](new_tab_footer::mojom::ManagementNoticePtr notice) { + EXPECT_EQ("Managed by custom label", notice->text); + }); + handler().UpdateManagementNotice(); + + document_.FlushForTesting(); + testing::Mock::VerifyAndClearExpectations(&document_); +} + +TEST_F(NewTabFooterHandlerEnterpriseTest, SetManagementNoticeWithDomainText) { + // Simulate browser management. + const std::string managing_domain = "example.com"; + + // Simulate that the browser is managed by a cloud domain. The domain will be + // indicated in the management notice text. + ScopedDeviceManagerForTesting device_manager_for_testing( + managing_domain.c_str()); + policy::ScopedManagementServiceOverrideForTesting profile_management( + policy::ManagementServiceFactory::GetForProfile(profile()), + policy::EnterpriseManagementAuthority::DOMAIN_LOCAL); + EXPECT_CALL(document_, SetManagementNotice) + .WillOnce([](new_tab_footer::mojom::ManagementNoticePtr notice) { + EXPECT_EQ("Managed by example.com", notice->text); + }); + handler().UpdateManagementNotice(); + + document_.FlushForTesting(); + testing::Mock::VerifyAndClearExpectations(&document_); +} +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc index 3eaa1b39..15bf631 100644 --- a/chrome/browser/ui/webui/settings/about_handler.cc +++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -71,6 +71,7 @@ #include "chrome/browser/ui/webui/ash/extended_updates/extended_updates_dialog.h" #include "chrome/browser/ui/webui/help/help_utils_chromeos.h" #include "chrome/browser/ui/webui/help/version_updater_chromeos.h" +#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h" #include "chromeos/ash/components/dbus/update_engine/update_engine_client.h" #include "chromeos/ash/components/fwupd/firmware_update_manager.h" #include "chromeos/ash/components/network/network_state.h" @@ -125,6 +126,25 @@ : IDS_UPGRADE_NETWORK_LIST_CELLULAR_ALLOWED); } +// Returns true if current user can change firmware, false otherwise. +bool CanChangeFirmware(Profile* profile) { + if (policy::ManagementServiceFactory::GetForPlatform()->IsManaged()) { + bool value = false; + // On a managed machine we allow firmware changes only if enabled by policy + if (!ash::CrosSettings::Get()->GetBoolean( + ash::kDeviceUserInitiatedFirmwareUpdatesEnabled, &value)) { + // This can occur if the lookup for the policy's value fails, + // for example if the policy is not present on the current version. + // In this case, default to false. + LOG(ERROR) << "Failed to get device setting."; + return false; + } + return value; + } + return user_manager::UserManager::Get()->IsOwnerUser( + ash::BrowserContextHelper::Get()->GetUserByBrowserContext(profile)); +} + // Returns true if current user can change channel, false otherwise. bool CanChangeChannel(Profile* profile) { if (policy::ManagementServiceFactory::GetForPlatform()->IsManaged()) { @@ -339,6 +359,10 @@ "getChannelInfo", base::BindRepeating(&AboutHandler::HandleGetChannelInfo, base::Unretained(this))); web_ui()->RegisterMessageCallback( + "canChangeFirmware", + base::BindRepeating(&AboutHandler::HandleCanChangeFirmware, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "canChangeChannel", base::BindRepeating(&AboutHandler::HandleCanChangeChannel, base::Unretained(this))); @@ -618,6 +642,13 @@ weak_factory_.GetWeakPtr(), callback_id)); } +void AboutHandler::HandleCanChangeFirmware(const base::Value::List& args) { + CHECK_EQ(1U, args.size()); + const std::string& callback_id = args[0].GetString(); + ResolveJavascriptCallback(base::Value(callback_id), + base::Value(CanChangeFirmware(profile_))); +} + void AboutHandler::HandleCanChangeChannel(const base::Value::List& args) { CHECK_EQ(1U, args.size()); const std::string& callback_id = args[0].GetString();
diff --git a/chrome/browser/ui/webui/settings/about_handler.h b/chrome/browser/ui/webui/settings/about_handler.h index 5cc5142..57401c61 100644 --- a/chrome/browser/ui/webui/settings/about_handler.h +++ b/chrome/browser/ui/webui/settings/about_handler.h
@@ -109,6 +109,9 @@ // Retrieves channel info. void HandleGetChannelInfo(const base::Value::List& args); + // Checks whether we can update the firmware. + void HandleCanChangeFirmware(const base::Value::List& args); + // Checks whether we can change the current channel. void HandleCanChangeChannel(const base::Value::List& args);
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom index e23bca0..8996d03 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom
@@ -111,6 +111,17 @@ kShopping, }; +// Types of New Tabs that CustomizeChromePage can attach to. +enum NewTabPageType { + kFirstPartyWebUI, + kThirdPartyWebUI, + kThirdPartyRemote, + kExtension, + kIncognito, + kGuestMode, + kNone, +}; + // Used by the WebUI page to bootstrap bidirectional communication. interface CustomizeChromePageHandlerFactory { // The WebUI calls this method when the page is first initialized. @@ -226,7 +237,7 @@ // |CustomizeChromePageHandler.UpdateScrollToSection()|. ScrollToSection(CustomizeChromeSection section); // Sets Information about the tab that is attached to the CustomizeChromePage. - AttachedTabStateUpdated(bool is_source_tab_first_party_ntp); + AttachedTabStateUpdated(NewTabPageType ntp_type); // Sets the name of the system that manages the new tab page if there is one. // If not, empty string should be provided. NtpManagedByNameUpdated(string ntp_managed_by_name);
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_interactive_uitest.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_interactive_uitest.cc index 13bc5ed..fa4acd6 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_interactive_uitest.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_interactive_uitest.cc
@@ -5,6 +5,7 @@ #include "base/test/scoped_feature_list.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/extensions/chrome_test_extension_loader.h" +#include "chrome/browser/extensions/install_verifier.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_element_identifiers.h" @@ -67,12 +68,12 @@ extensions::ChromeTestExtensionLoader extension_loader(profile); extension_loader.set_ignore_manifest_warnings(true); - // TODO(temao) Not blocking the test, but note that LoadExtension() - // occasionally returns null. - extension_loader.LoadExtension(extension_dir.Pack()).get(); + const extensions::Extension* extension = + extension_loader.LoadExtension(extension_dir.Pack()).get(); + ASSERT_TRUE(extension); } - void OpenExtensionNewTabPage() { + void OpenNewTabPage() { chrome::NewTab(browser()); content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); @@ -84,6 +85,7 @@ protected: base::test::ScopedFeatureList scoped_feature_list_; + extensions::ScopedInstallVerifierBypassForTest install_verifier_bypass_; }; } // namespace @@ -98,8 +100,7 @@ InstallExtension(browser()->profile()); RunTestSequence( // 2. Open extension new tab page. - Do(base::BindLambdaForTesting( - [&, this]() { OpenExtensionNewTabPage(); })), + Do(base::BindLambdaForTesting([&, this]() { OpenNewTabPage(); })), // 3. Open customize chrome side panel. OpenCustomizeChromeSidePanel(kLocalCustomizeChromeElementId), // 4. Check edit theme is enabled in customize chrome side panel. @@ -108,3 +109,38 @@ WaitForElementToRender(kLocalCustomizeChromeElementId, kEditThemeButton))); } + +IN_PROC_BROWSER_TEST_F(CustomizeChromeInteractiveTest, + ShowsFooterSectionForExtensionNtp) { + DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kLocalCustomizeChromeElementId); + const DeepQuery kFooterSection = {"customize-chrome-app", "#footer", + "customize-chrome-footer", + "#showToggleContainer"}; + // 1. Load extension that overrides NTP. + InstallExtension(browser()->profile()); + RunTestSequence( + // 2. Open extension new tab page. + Do(base::BindLambdaForTesting([&, this]() { OpenNewTabPage(); })), + // 3. Open customize chrome side panel. + OpenCustomizeChromeSidePanel(kLocalCustomizeChromeElementId), + // 4. Check that the footer section exists. + Steps( + WaitForElementExists(kLocalCustomizeChromeElementId, kFooterSection), + WaitForElementToRender(kLocalCustomizeChromeElementId, + kFooterSection))); +} + +IN_PROC_BROWSER_TEST_F(CustomizeChromeInteractiveTest, + FooterSectionNotShownForNonExtensionNtp) { + DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kLocalCustomizeChromeElementId); + const DeepQuery kFooterSection = {"customize-chrome-app", "#footer", + "customize-chrome-footer", + "#showToggleContainer"}; + RunTestSequence( + // 1. Open non-extension new tab page. + Do(base::BindLambdaForTesting([&, this]() { OpenNewTabPage(); })), + // 2. Open customize chrome side panel. + OpenCustomizeChromeSidePanel(kLocalCustomizeChromeElementId), + // 3. Check that the footer section does not exist. + EnsureNotPresent(kLocalCustomizeChromeElementId, kFooterSection)); +}
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc index 01fcf2f3..981d88d2 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc
@@ -29,7 +29,10 @@ #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/search/ntp_user_data_types.h" #include "chrome/browser/ui/views/side_panel/customize_chrome/customize_chrome_utils.h" +#include "chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h" #include "chrome/browser/ui/webui/new_tab_page/ntp_pref_names.h" +#include "chrome/browser/ui/webui/new_tab_page_third_party/new_tab_page_third_party_ui.h" +#include "chrome/browser/ui/webui/ntp/new_tab_ui.h" #include "chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_section.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" @@ -183,10 +186,9 @@ page_->ScrollToSection(mojo_section); } -void CustomizeChromePageHandler::AttachedTabStateUpdated( - bool is_source_tab_first_party_ntp) { - last_is_source_tab_first_party_ntp_ = is_source_tab_first_party_ntp; - page_->AttachedTabStateUpdated(is_source_tab_first_party_ntp); +void CustomizeChromePageHandler::AttachedTabStateUpdated(const GURL& url) { + last_source_url_ = url; + page_->AttachedTabStateUpdated(GetNewTabPageType(url)); } bool CustomizeChromePageHandler::IsNtpManagedByThirdPartySearchEngine() const { @@ -539,7 +541,7 @@ } void CustomizeChromePageHandler::UpdateAttachedTabState() { - AttachedTabStateUpdated(last_is_source_tab_first_party_ntp_); + AttachedTabStateUpdated(last_source_url_); } void CustomizeChromePageHandler::UpdateNtpManagedByName() { @@ -726,3 +728,22 @@ LogEvent(NTP_BACKGROUND_UPLOAD_CANCEL); std::move(choose_local_custom_background_callback_).Run(false); } + +side_panel::mojom::NewTabPageType CustomizeChromePageHandler::GetNewTabPageType( + const GURL& url) { + if (NewTabPageUI::IsNewTabPageOrigin(url)) { + return side_panel::mojom::NewTabPageType::kFirstPartyWebUI; + } else if (customize_chrome::IsExtensionNtp(url, profile_)) { + return side_panel::mojom::NewTabPageType::kExtension; + } else if (NewTabPageThirdPartyUI::IsNewTabPageOrigin(url)) { + return side_panel::mojom::NewTabPageType::kThirdPartyWebUI; + } else if (IsNtpManagedByThirdPartySearchEngine()) { + return side_panel::mojom::NewTabPageType::kThirdPartyRemote; + } else if (NewTabUI::IsNewTab(url)) { + return profile_->IsGuestSession() + ? side_panel::mojom::NewTabPageType::kGuestMode + : side_panel::mojom::NewTabPageType::kIncognito; + } + + return side_panel::mojom::NewTabPageType::kNone; +}
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h index a128141..460c8dd 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h
@@ -21,6 +21,7 @@ #include "chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom.h" #include "chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_section.h" #include "chrome/common/search/ntp_logging_events.h" +#include "chrome/common/webui_url_constants.h" #include "components/prefs/pref_change_registrar.h" #include "components/search_engines/template_url_service_observer.h" #include "components/themes/ntp_background_service.h" @@ -90,7 +91,7 @@ void ScrollToSection(CustomizeChromeSection section); // Passes AttachedTabStateUpdated calls to the CustomizeChromePage. - void AttachedTabStateUpdated(bool is_source_tab_first_party_ntp); + void AttachedTabStateUpdated(const GURL& url); // Helper method to determine if the search engine is overriding the first // party NTP. @@ -145,6 +146,9 @@ std::u16string GetManagingThirdPartyName() const; + // Returns the type of New Tab Page the SidePanel is attached to. + side_panel::mojom::NewTabPageType GetNewTabPageType(const GURL& url); + // ui::NativeThemeObserver: void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override; @@ -190,7 +194,7 @@ // Caches the attached tab state provided to the handler, in cases where the // value needs to be requeried by the page. - bool last_is_source_tab_first_party_ntp_ = true; + GURL last_source_url_{GURL(chrome::kChromeUINewTabPageURL)}; PrefChangeRegistrar pref_change_registrar_; base::ScopedObservation<ui::NativeTheme, ui::NativeThemeObserver>
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc index 43e2f3b..f0b26493 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc
@@ -169,7 +169,9 @@ MOCK_METHOD(void, ScrollToSection, (side_panel::mojom::CustomizeChromeSection)); - MOCK_METHOD(void, AttachedTabStateUpdated, (bool)); + MOCK_METHOD(void, + AttachedTabStateUpdated, + (side_panel::mojom::NewTabPageType)); MOCK_METHOD(void, NtpManagedByNameUpdated, (const std::string&)); MOCK_METHOD(void, SetFooterSettings, (bool visible)); @@ -810,18 +812,38 @@ EXPECT_EQ(side_panel::mojom::CustomizeChromeSection::kAppearance, section); } +// Ensures that url's are correctly mapped to their NewTabPage type. +// Does not include test for `side_panel::mojom::NewTabPageType::kExtension` +// See `CustomizeChromeInteractiveTest.FooterSectionForExtensionNtp` for +// confirming Customize Chrome shows the footer section for Extension NTPs. TEST_F(CustomizeChromePageHandlerTest, AttachedTabStateUpdated) { - bool kIsSourceTabFirstPartyNtpValue = false; + std::vector<std::pair<side_panel::mojom::NewTabPageType, GURL>> + ntp_types_and_urls = { + {side_panel::mojom::NewTabPageType::kNone, + GURL("https://www.google.com/")}, + {side_panel::mojom::NewTabPageType::kFirstPartyWebUI, + GURL(chrome::kChromeUINewTabPageURL)}, + {side_panel::mojom::NewTabPageType::kThirdPartyWebUI, + GURL(chrome::kChromeUINewTabPageThirdPartyURL)}, + {side_panel::mojom::NewTabPageType::kIncognito, + GURL(chrome::kChromeUINewTabURL)}, + {side_panel::mojom::NewTabPageType::kGuestMode, + GURL(chrome::kChromeUINewTabURL)}}; - bool isSourceTabFirstPartyNtp; - EXPECT_CALL(mock_page_, AttachedTabStateUpdated) - .Times(1) - .WillOnce(SaveArg<0>(&isSourceTabFirstPartyNtp)); + for (const auto& ntp_type_and_url : ntp_types_and_urls) { + if (ntp_type_and_url.first == + side_panel::mojom::NewTabPageType::kGuestMode) { + profile().SetGuestSession(true); + } - handler().AttachedTabStateUpdated(kIsSourceTabFirstPartyNtpValue); - mock_page_.FlushForTesting(); - - EXPECT_EQ(kIsSourceTabFirstPartyNtpValue, isSourceTabFirstPartyNtp); + side_panel::mojom::NewTabPageType source_tab; + EXPECT_CALL(mock_page_, AttachedTabStateUpdated) + .Times(1) + .WillOnce(SaveArg<0>(&source_tab)); + handler().AttachedTabStateUpdated(ntp_type_and_url.second); + mock_page_.FlushForTesting(); + EXPECT_EQ(ntp_type_and_url.first, source_tab); + } } TEST_F(CustomizeChromePageHandlerTest, ScrollToUnspecifiedSection) {
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc index 1c9e0c1..05502f4 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc
@@ -305,13 +305,11 @@ } } -void CustomizeChromeUI::AttachedTabStateUpdated( - bool is_source_tab_first_party_ntp) { +void CustomizeChromeUI::AttachedTabStateUpdated(const GURL& url) { if (customize_chrome_page_handler_) { - customize_chrome_page_handler_->AttachedTabStateUpdated( - is_source_tab_first_party_ntp); + customize_chrome_page_handler_->AttachedTabStateUpdated(url); } else { - is_source_tab_first_party_ntp_ = is_source_tab_first_party_ntp; + source_tab_url_ = url; } } @@ -409,10 +407,8 @@ customize_chrome_page_handler_->ScrollToSection(*section_); section_.reset(); } - if (is_source_tab_first_party_ntp_.has_value()) { - customize_chrome_page_handler_->AttachedTabStateUpdated( - is_source_tab_first_party_ntp_.value()); - is_source_tab_first_party_ntp_.reset(); + if (!source_tab_url_.is_empty()) { + customize_chrome_page_handler_->AttachedTabStateUpdated(source_tab_url_); } if (is_theme_editable_.has_value()) { customize_chrome_page_handler_->UpdateThemeEditable(
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.h b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.h index 8445464..33bc34fe 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.h +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.h
@@ -83,7 +83,7 @@ void ScrollToSection(CustomizeChromeSection section); // Passthrough that calls the CustomizeChromePage's AttachedTabStateUpdated. - void AttachedTabStateUpdated(bool is_attached_tab_first_party_ntp); + void AttachedTabStateUpdated(const GURL& url); // Passthrough that calls to CustomizeChromePage's UpdateThemeEditable. void UpdateThemeEditable(bool is_theme_editable); @@ -187,7 +187,7 @@ // Caches a request to scroll to a section in case the request happens before // the front-end is ready to receive the request. std::optional<CustomizeChromeSection> section_; - std::optional<bool> is_source_tab_first_party_ntp_; + GURL source_tab_url_; std::optional<bool> is_theme_editable_; std::unique_ptr<user_education::HelpBubbleHandler> help_bubble_handler_;
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc index 3463616..2c8b260 100644 --- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
@@ -23,8 +23,6 @@ #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h" #include "chrome/browser/ui/tabs/organization/tab_declutter_controller.h" -#include "chrome/browser/ui/tabs/split_tab_data.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_utils.h" #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h" @@ -43,7 +41,9 @@ #include "components/tab_groups/tab_group_color.h" #include "components/tab_groups/tab_group_id.h" #include "components/tab_groups/tab_group_visual_data.h" +#include "components/tabs/public/split_tab_data.h" #include "components/tabs/public/split_tab_id.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_interface.h" #include "content/public/test/navigation_simulator.h" #include "content/public/test/test_web_ui.h"
diff --git a/chrome/browser/ui/webui/version/version_ui.cc b/chrome/browser/ui/webui/version/version_ui.cc index f9c2e60..c10d6937 100644 --- a/chrome/browser/ui/webui/version/version_ui.cc +++ b/chrome/browser/ui/webui/version/version_ui.cc
@@ -260,8 +260,6 @@ version_ui::kTargetSdkVersion, base::NumberToString( base::android::BuildInfo::GetInstance()->target_sdk_version())); - html_source->AddString(version_ui::kTargetsU, - AndroidAboutAppInfo::GetTargetsUInfo()); html_source->AddString(version_ui::kGmsVersion, AndroidAboutAppInfo::GetGmsInfo()); html_source->AddString(
diff --git a/chrome/browser/ui/webui/webui_allowlist_provider_unittest.cc b/chrome/browser/ui/webui/webui_allowlist_provider_unittest.cc index 99ff3bb5..fdf7a61 100644 --- a/chrome/browser/ui/webui/webui_allowlist_provider_unittest.cc +++ b/chrome/browser/ui/webui/webui_allowlist_provider_unittest.cc
@@ -276,31 +276,34 @@ // cookies. EXPECT_TRUE(cookies_settings->IsFullCookieAccessAllowed( third_party_url, net::SiteForCookies::FromUrl(top_level_url), - url::Origin::Create(top_level_url), net::CookieSettingOverrides())); + url::Origin::Create(top_level_url), net::CookieSettingOverrides(), + /*cookie_partition_key=*/std::nullopt)); // Allowlisted origin on its own can't use cookies. EXPECT_FALSE(cookies_settings->IsFullCookieAccessAllowed( third_party_url, net::SiteForCookies::FromUrl(third_party_url), - url::Origin::Create(third_party_url), net::CookieSettingOverrides())); + url::Origin::Create(third_party_url), net::CookieSettingOverrides(), + /*cookie_partition_key=*/std::nullopt)); // Allowlisted origin embedded in Web top-level origin can't use cookies. EXPECT_FALSE(cookies_settings->IsFullCookieAccessAllowed( GURL("https://example2.com"), net::SiteForCookies::FromUrl(third_party_url), - url::Origin::Create(third_party_url), net::CookieSettingOverrides())); + url::Origin::Create(third_party_url), net::CookieSettingOverrides(), + /*cookie_partition_key=*/std::nullopt)); // Allowlisted origin making subresource request (e.g. image) can't use // cookies. EXPECT_FALSE(cookies_settings->IsFullCookieAccessAllowed( third_party_url, net::SiteForCookies(), std::nullopt, - net::CookieSettingOverrides())); + net::CookieSettingOverrides(), /*cookie_partition_key=*/std::nullopt)); // Allowlisted origin embedded in the wrong WebUI origin can't use cookies. const GURL url_no_permission_webui = GURL("chrome-untrusted://no-perm"); EXPECT_FALSE(cookies_settings->IsFullCookieAccessAllowed( third_party_url, net::SiteForCookies::FromUrl(url_no_permission_webui), url::Origin::Create(url_no_permission_webui), - net::CookieSettingOverrides())); + net::CookieSettingOverrides(), /*cookie_partition_key=*/std::nullopt)); // Other permissions aren't affected. EXPECT_EQ(CONTENT_SETTING_BLOCK, @@ -328,31 +331,34 @@ EXPECT_TRUE(cookies_settings->IsFullCookieAccessAllowed( third_party_url, net::SiteForCookies::FromUrl(top_level_url), - url::Origin::Create(top_level_url), net::CookieSettingOverrides())); + url::Origin::Create(top_level_url), net::CookieSettingOverrides(), + /*cookie_partition_key=*/std::nullopt)); // Allowlisted origin on its own can use cookies, because only third-party // cookies are blocked. EXPECT_TRUE(cookies_settings->IsFullCookieAccessAllowed( third_party_url, net::SiteForCookies::FromUrl(third_party_url), - url::Origin::Create(third_party_url), net::CookieSettingOverrides())); + url::Origin::Create(third_party_url), net::CookieSettingOverrides(), + /*cookie_partition_key=*/std::nullopt)); // Allowlisted origin embedded in Web top-level origin can't use cookies. EXPECT_FALSE(cookies_settings->IsFullCookieAccessAllowed( GURL("https://example2.com"), net::SiteForCookies::FromUrl(third_party_url), - url::Origin::Create(third_party_url), net::CookieSettingOverrides())); + url::Origin::Create(third_party_url), net::CookieSettingOverrides(), + /*cookie_partition_key=*/std::nullopt)); // Allowlisted origin embedded in the wrong WebUI origin can't use cookies. const GURL url_no_permission_webui = GURL("chrome-untrusted://no-perm"); EXPECT_FALSE(cookies_settings->IsFullCookieAccessAllowed( third_party_url, net::SiteForCookies::FromUrl(url_no_permission_webui), url::Origin::Create(url_no_permission_webui), - net::CookieSettingOverrides())); + net::CookieSettingOverrides(), /*cookie_partition_key=*/std::nullopt)); // Allowlisted origin making subresource request (e.g. image) can't use // cookies. EXPECT_FALSE(cookies_settings->IsFullCookieAccessAllowed( third_party_url, net::SiteForCookies(), std::nullopt, - net::CookieSettingOverrides())); + net::CookieSettingOverrides(), /*cookie_partition_key=*/std::nullopt)); // Other permissions aren't affected. EXPECT_EQ(CONTENT_SETTING_BLOCK, @@ -424,7 +430,8 @@ // Check that settings are applied before creating an allowlist entry. EXPECT_FALSE(cookie_settings->IsFullCookieAccessAllowed( url, net::SiteForCookies::FromUrl(top_level_url), - url::Origin::Create(top_level_url), {})); + url::Origin::Create(top_level_url), {}, + /*cookie_partition_key=*/std::nullopt)); EXPECT_TRUE(cookie_settings->IsCookieSessionOnly(url)); EXPECT_TRUE(cookie_settings->ShouldDeleteCookieOnExit( cookie_settings->GetCookieSettings(), url.host(), @@ -445,7 +452,8 @@ EXPECT_TRUE(cookie_settings->IsFullCookieAccessAllowed( url, net::SiteForCookies::FromUrl(top_level_url), - url::Origin::Create(top_level_url), {})); + url::Origin::Create(top_level_url), {}, + /*cookie_partition_key=*/std::nullopt)); EXPECT_TRUE(cookie_settings->IsCookieSessionOnly(url)); EXPECT_TRUE(cookie_settings->ShouldDeleteCookieOnExit( cookie_settings->GetCookieSettings(), url.host(),
diff --git a/chrome/browser/updates/announcement_notification/announcement_notification_delegate.h b/chrome/browser/updates/announcement_notification/announcement_notification_delegate.h index 142d6a4..148a41ba 100644 --- a/chrome/browser/updates/announcement_notification/announcement_notification_delegate.h +++ b/chrome/browser/updates/announcement_notification/announcement_notification_delegate.h
@@ -11,7 +11,8 @@ class NotificationDisplayService; // Id of the announcement notification. -constexpr char kAnnouncementNotificationId[] = "announcement_notification"; +inline constexpr char kAnnouncementNotificationId[] = + "announcement_notification"; // Default delegate for AnnouncementNotificationService that works on // non-Android platforms.
diff --git a/chrome/browser/updates/announcement_notification/announcement_notification_service.h b/chrome/browser/updates/announcement_notification/announcement_notification_service.h index 7cb43ea..b764258 100644 --- a/chrome/browser/updates/announcement_notification/announcement_notification_service.h +++ b/chrome/browser/updates/announcement_notification/announcement_notification_service.h
@@ -24,41 +24,41 @@ // The Finch parameter name for a boolean value that whether to show // notification on first run. -constexpr char kSkipFirstRun[] = "skip_first_run"; +inline constexpr char kSkipFirstRun[] = "skip_first_run"; // The Finch parameter name for a string value that represents a time. // If first run happens after this time, notification will not show. // The string defined in Finch config should specify the time zone. // e.g. 02 Feb 2020 13:00:00 GMT. -constexpr char kSkipFirstRunAfterTime[] = "skip_first_run_after_time"; +inline constexpr char kSkipFirstRunAfterTime[] = "skip_first_run_after_time"; // The Finch parameter name for a boolean value that whether to show // notification for new profile. -constexpr char kSkipNewProfile[] = "skip_new_profile"; +inline constexpr char kSkipNewProfile[] = "skip_new_profile"; // The Finch parameter to control whether to skip notification display. -constexpr char kSkipDisplay[] = "skip_display"; +inline constexpr char kSkipDisplay[] = "skip_display"; // The Finch parameter to define the latest version number of the notification. -constexpr char kVersion[] = "version"; +inline constexpr char kVersion[] = "version"; // The Finch parameter to define whether to show the announcement to users not // signed in. -constexpr char kRequireSignout[] = "require_sign_out"; +inline constexpr char kRequireSignout[] = "require_sign_out"; // The Finch parameter to define whether to show the announcement to users not // signed in. -constexpr char kShowOneAllProfiles[] = "show_one_all_profiles"; +inline constexpr char kShowOneAllProfiles[] = "show_one_all_profiles"; // The Finch parameter to define the announcement URL. -constexpr char kAnnouncementUrl[] = "announcement_url"; +inline constexpr char kAnnouncementUrl[] = "announcement_url"; // Preference name to persist the current version sent from Finch parameter. -constexpr char kCurrentVersionPrefName[] = +inline constexpr char kCurrentVersionPrefName[] = "announcement_notification_service_current_version"; // Preference name to persist the time of Chrome first run. -constexpr char kAnnouncementFirstRunTimePrefName[] = +inline constexpr char kAnnouncementFirstRunTimePrefName[] = "announcement_notification_service_first_run_time"; // Used to show a notification when the version defined in Finch parameter is
diff --git a/chrome/browser/web_applications/commands/web_install_from_url_command.cc b/chrome/browser/web_applications/commands/web_install_from_url_command.cc index 69cc24b..991a7d4 100644 --- a/chrome/browser/web_applications/commands/web_install_from_url_command.cc +++ b/chrome/browser/web_applications/commands/web_install_from_url_command.cc
@@ -21,6 +21,7 @@ #include "chrome/browser/web_applications/web_app_helpers.h" #include "chrome/browser/web_applications/web_app_install_finalizer.h" #include "chrome/browser/web_applications/web_app_install_info.h" +#include "chrome/browser/web_applications/web_app_install_params.h" #include "chrome/browser/web_applications/web_app_install_utils.h" #include "chrome/browser/web_applications/web_app_logging.h" #include "chrome/browser/web_applications/web_app_registrar.h" @@ -32,6 +33,8 @@ #include "components/webapps/browser/installable/installable_logging.h" #include "components/webapps/browser/installable/installable_metrics.h" #include "components/webapps/browser/installable/installable_params.h" +#include "components/webapps/browser/installable/ml_install_operation_tracker.h" +#include "components/webapps/browser/installable/ml_installability_promoter.h" #include "components/webapps/browser/web_contents/web_app_url_loader.h" #include "components/webapps/common/web_app_id.h" #include "content/public/browser/web_contents.h" @@ -46,6 +49,8 @@ Profile& profile, const GURL& install_url, const std::optional<GURL>& manifest_id, + base::WeakPtr<content::WebContents> web_contents, + WebAppInstallDialogCallback dialog_callback, WebInstallFromUrlCommandCallback installed_callback) : WebAppCommand<SharedWebContentsLock, const webapps::AppId&, @@ -60,6 +65,8 @@ profile_(profile), manifest_id_(manifest_id), install_url_(install_url), + web_contents_(web_contents), + dialog_callback_(std::move(dialog_callback)), install_error_log_entry_(/*background_installation=*/false, kInstallSource) { if (manifest_id_.has_value()) { @@ -237,16 +244,27 @@ install_error_log_entry_.LogDownloadedIconsErrors( *web_app_info_, result, icons_map, icons_http_results); - // TODO(crbug.com/333795265): Show install dialog. - OnInstallDialogCompleted(/*user_accepted=*/true); + // TODO(crbug.com/415825168): Support detailed install dialog for background + // installs. For now, pass `nullptr` to the screenshot_fetcher which will + // always show the simple dialog. + std::move(dialog_callback_) + .Run( + /*screenshot_fetcher=*/nullptr, web_contents_.get(), + std::move(web_app_info_), + base::BindOnce(&WebInstallFromUrlCommand::OnInstallDialogCompleted, + weak_ptr_factory_.GetWeakPtr())); } -void WebInstallFromUrlCommand::OnInstallDialogCompleted(bool user_accepted) { +void WebInstallFromUrlCommand::OnInstallDialogCompleted( + bool user_accepted, + std::unique_ptr<WebAppInstallInfo> web_app_info) { if (!user_accepted) { Abort(webapps::InstallResultCode::kUserInstallDeclined); return; } + web_app_info_ = std::move(web_app_info); + web_app_info_->user_display_mode = web_app::mojom::UserDisplayMode::kStandalone; WebAppInstallFinalizer::FinalizeOptions finalize_options(kInstallSource);
diff --git a/chrome/browser/web_applications/commands/web_install_from_url_command.h b/chrome/browser/web_applications/commands/web_install_from_url_command.h index b83e7690a..83b9c50 100644 --- a/chrome/browser/web_applications/commands/web_install_from_url_command.h +++ b/chrome/browser/web_applications/commands/web_install_from_url_command.h
@@ -12,6 +12,7 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/web_applications/commands/web_app_command.h" #include "chrome/browser/web_applications/locks/shared_web_contents_lock.h" +#include "chrome/browser/web_applications/web_app_install_params.h" #include "chrome/browser/web_applications/web_app_logging.h" #include "components/webapps/common/web_app_id.h" #include "third_party/blink/public/mojom/manifest/manifest.mojom-forward.h" @@ -70,6 +71,8 @@ WebInstallFromUrlCommand(Profile& profile, const GURL& install_url, const std::optional<GURL>& manifest_id, + base::WeakPtr<content::WebContents> web_contents, + WebAppInstallDialogCallback dialog_callback, WebInstallFromUrlCommandCallback installed_callback); ~WebInstallFromUrlCommand() override; @@ -90,7 +93,9 @@ IconsDownloadedResult result, IconsMap icons_map, DownloadedIconsHttpResults icons_http_results); - void OnInstallDialogCompleted(bool user_accepted); + void OnInstallDialogCompleted( + bool user_accepted, + std::unique_ptr<WebAppInstallInfo> web_app_info); void InstallApp(); void OnAppInstalled(const webapps::AppId& app_id, webapps::InstallResultCode code); @@ -102,6 +107,10 @@ // Unset if the WebInstall API's 1-parameter signature was called. std::optional<GURL> manifest_id_; GURL install_url_; + // The WebContents that initiated the install. This is used only to show the + // install dialog. + base::WeakPtr<content::WebContents> web_contents_; + WebAppInstallDialogCallback dialog_callback_; InstallErrorLogEntry install_error_log_entry_; std::unique_ptr<SharedWebContentsLock> web_contents_lock_;
diff --git a/chrome/browser/web_applications/commands/web_install_from_url_command_browsertest.cc b/chrome/browser/web_applications/commands/web_install_from_url_command_browsertest.cc index 3fb12266..3b7d5361 100644 --- a/chrome/browser/web_applications/commands/web_install_from_url_command_browsertest.cc +++ b/chrome/browser/web_applications/commands/web_install_from_url_command_browsertest.cc
@@ -4,20 +4,27 @@ #include "chrome/browser/web_applications/commands/web_install_from_url_command.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/path_service.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_future.h" +#include "base/threading/thread_restrictions.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/web_applications/web_app_browsertest_base.h" +#include "chrome/browser/ui/web_applications/web_app_dialogs.h" #include "chrome/browser/web_applications/test/command_metrics_test_helper.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" #include "chrome/browser/web_applications/web_app_command_manager.h" #include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/common/chrome_paths.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/permissions/permission_request_manager.h" +#include "components/url_formatter/elide_url.h" #include "components/webapps/browser/install_result_code.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" @@ -25,9 +32,17 @@ #include "content/public/test/test_renderer_host.h" #include "net/base/url_util.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "skia/ext/image_operations.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features_generated.h" +#include "ui/base/models/image_model.h" +#include "ui/gfx/codec/png_codec.h" +#include "ui/gfx/image/image_unittest_util.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/interaction/element_tracker_views.h" +#include "ui/views/widget/any_widget_observer.h" namespace { constexpr webapps::WebappInstallSource kInstallSource = @@ -143,6 +158,8 @@ std::string install_url = https_server()->GetURL("/banners/manifest_with_id_test_page.html").spec(); + auto auto_accept_pwa_install_confirmation = + SetAutoAcceptPWAInstallConfirmationForTesting(); SetPermissionResponse(/*permission_granted=*/true); base::HistogramTester histograms; ASSERT_TRUE(TryInstallApp(install_url)); @@ -177,6 +194,8 @@ std::string install_url = GetInstallableAppURL().spec(); std::string manifest_id = install_url; + auto auto_accept_pwa_install_confirmation = + SetAutoAcceptPWAInstallConfirmationForTesting(); SetPermissionResponse(/*permission_granted=*/true); base::HistogramTester histograms; ASSERT_TRUE(TryInstallApp(install_url, manifest_id)); @@ -214,6 +233,9 @@ std::string install_url = GetInstallableAppURL().spec(); std::string manifest_id = install_url; base::HistogramTester histograms; + + auto auto_accept_pwa_install_confirmation = + SetAutoAcceptPWAInstallConfirmationForTesting(); SetPermissionResponse(/*permission_granted=*/true); ASSERT_TRUE(TryInstallApp(install_url, manifest_id)); @@ -268,8 +290,12 @@ std::string manifest_id = secondary_server_.GetURL("/banners/manifest_test_page.html").spec(); base::HistogramTester histograms; + + auto auto_accept_pwa_install_confirmation = + SetAutoAcceptPWAInstallConfirmationForTesting(); SetPermissionResponse(/*permission_granted=*/true); ASSERT_TRUE(TryInstallApp(install_url, manifest_id)); + EXPECT_TRUE(ResultExists()); EXPECT_EQ(GetManifestIdResult(), manifest_id); EXPECT_FALSE(ErrorExists()); @@ -506,4 +532,97 @@ webapps::WebappInstallSource::WEB_INSTALL, 1)))); } +class WebInstallFromUrlCommandDialogTest + : public WebInstallFromUrlCommandBrowserTest { + public: + SkBitmap ReadImageFile(const base::FilePath& file_path) { + base::ScopedAllowBlockingForTesting allow_blocking; + + std::optional<std::vector<uint8_t>> file_contents = + base::ReadFileToBytes(file_path); + + return gfx::PNGCodec::Decode(file_contents.value()); + } + + std::u16string GetAppTitle() { + return u"Manifest test app with id specified"; + } + + base::FilePath GetIconPath() { + base::FilePath path; + base::PathService::Get(chrome::DIR_TEST_DATA, &path); + return path.AppendASCII("banners").AppendASCII("launcher-icon-1x.png"); + } +}; + +IN_PROC_BROWSER_TEST_F(WebInstallFromUrlCommandDialogTest, + VerifyInstallDialogContents) { + // Go to /simple.html + NavigateToValidUrl(); + + // Target a different page to install. + const GURL install_url = + https_server()->GetURL("/banners/manifest_with_id_test_page.html"); + + SetPermissionResponse(/*permission_granted=*/true); + + views::NamedWidgetShownWaiter widget_waiter( + views::test::AnyWidgetTestPasskey{}, "WebAppSimpleInstallDialog"); + + // We don't actually care about the result of the install, and EvalJs blocks + // until the promise resolves, which only happens after the dialog is closed. + // Execute the install asynchronously so we can actually check the dialog + // contents without the promise timing out. + ExecuteScriptAsync(web_contents(), + "navigator.install('" + install_url.spec() + "');"); + + // Wait for the install dialog to show. + views::Widget* widget = widget_waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); + + views::ElementTrackerViews* tracker_views = + views::ElementTrackerViews::GetInstance(); + ui::ElementContext context = + views::ElementTrackerViews::GetContextForWidget(widget); + + // Get the icon from the dialog. + views::ImageView* icon_view = + tracker_views->GetUniqueViewAs<views::ImageView>( + kSimpleInstallDialogIconView, context); + ASSERT_NE(icon_view, nullptr); + + // Convert to a bitmap. + const ui::ImageModel& icon_view_model = icon_view->GetImageModel(); + ASSERT_FALSE(icon_view_model.IsEmpty()); + ASSERT_TRUE(icon_view_model.IsImage()); + const SkBitmap* dialog_icon_bitmap = icon_view_model.GetImage().ToSkBitmap(); + CHECK(!dialog_icon_bitmap->isNull()); + + // Read the expected bitmap from the test data directory. + base::FilePath path = GetIconPath(); + SkBitmap bitmap_from_png = ReadImageFile(path); + CHECK(!bitmap_from_png.isNull()); + // The dialog resizes the icon. Resize the png to match. + bitmap_from_png = skia::ImageOperations::Resize( + bitmap_from_png, skia::ImageOperations::RESIZE_BEST, + dialog_icon_bitmap->width(), dialog_icon_bitmap->height()); + + EXPECT_TRUE( + gfx::test::AreBitmapsClose(*dialog_icon_bitmap, bitmap_from_png, 3)); + + // Verify the app title label. + views::Label* app_title_view = tracker_views->GetUniqueViewAs<views::Label>( + kSimpleInstallDialogAppTitle, context); + ASSERT_NE(app_title_view, nullptr); + EXPECT_EQ(app_title_view->GetText(), GetAppTitle()); + + // Verify the origin label. + views::Label* start_url_view = tracker_views->GetUniqueViewAs<views::Label>( + kSimpleInstallDialogOriginLabel, context); + ASSERT_NE(start_url_view, nullptr); + EXPECT_EQ( + start_url_view->GetText(), + url_formatter::FormatUrlForDisplayOmitSchemePathAndTrivialSubdomains( + install_url)); +} } // namespace web_app
diff --git a/chrome/browser/web_applications/navigation_capturing_browser_navigator_browsertest.cc b/chrome/browser/web_applications/navigation_capturing_browser_navigator_browsertest.cc index 4b78809..4cfcee5 100644 --- a/chrome/browser/web_applications/navigation_capturing_browser_navigator_browsertest.cc +++ b/chrome/browser/web_applications/navigation_capturing_browser_navigator_browsertest.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/ui/web_applications/web_app_browser_controller.h" #include "chrome/browser/ui/web_applications/web_app_browsertest_base.h" #include "chrome/browser/web_applications/mojom/user_display_mode.mojom-shared.h" +#include "chrome/browser/web_applications/navigation_capturing_metrics.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/web_app_command_scheduler.h" #include "chrome/browser/web_applications/web_app_provider.h" @@ -193,6 +194,21 @@ metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); } + std::vector<NavigationCapturingDisplayModeResult> + GetNavigationCapturingFinalDisplayMetric( + const base::HistogramTester& tester) { + std::vector<base::Bucket> display_result_buckets = + tester.GetAllSamples("Webapp.NavigationCapturing.FinalDisplay.Result"); + std::vector<NavigationCapturingDisplayModeResult> bucket_list; + for (const base::Bucket& bucket : display_result_buckets) { + for (int count = 0; count < bucket.count; count++) { + bucket_list.push_back( + static_cast<NavigationCapturingDisplayModeResult>(bucket.min)); + } + } + return bucket_list; + } + base::test::ScopedFeatureList feature_list_; std::vector<base::test::FeatureRefAndParams> enabled_features; }; @@ -228,6 +244,10 @@ histograms.ExpectUniqueSample( "WebApp.LaunchSource", apps::LaunchSource::kFromNavigationCapturing, 1); histograms.ExpectTotalCount(kLaunchParamsEnqueueMetric, 1); + EXPECT_THAT( + GetNavigationCapturingFinalDisplayMetric(histograms), + testing::ElementsAre( + NavigationCapturingDisplayModeResult::kAppBrowserTabFinalBrowserTab)); ASSERT_TRUE(new_tab); @@ -285,6 +305,11 @@ histograms.ExpectUniqueSample( "WebApp.LaunchSource", apps::LaunchSource::kFromNavigationCapturing, 1); + EXPECT_THAT( + GetNavigationCapturingFinalDisplayMetric(histograms), + testing::ElementsAre( + NavigationCapturingDisplayModeResult::kAppStandaloneFinalStandalone)); + // This is measured twice, once for each launch param obtained. histograms.ExpectTotalCount(kLaunchParamsEnqueueMetric, 2); } @@ -345,6 +370,11 @@ histograms.ExpectUniqueSample( "WebApp.LaunchSource", apps::LaunchSource::kFromNavigationCapturing, 1); + EXPECT_THAT( + GetNavigationCapturingFinalDisplayMetric(histograms), + testing::ElementsAre( + NavigationCapturingDisplayModeResult::kAppStandaloneFinalStandalone)); + // This is measured twice, once for each launch param obtained. histograms.ExpectTotalCount(kLaunchParamsEnqueueMetric, 2); } @@ -395,6 +425,10 @@ histograms.ExpectUniqueSample( "WebApp.LaunchSource", apps::LaunchSource::kFromNavigationCapturing, 1); histograms.ExpectTotalCount(kLaunchParamsEnqueueMetric, 1); + EXPECT_THAT( + GetNavigationCapturingFinalDisplayMetric(histograms), + testing::ElementsAre( + NavigationCapturingDisplayModeResult::kAppStandaloneFinalStandalone)); } IN_PROC_BROWSER_TEST_F(NavigationCapturingBrowserNavigatorBrowserTest, @@ -441,6 +475,10 @@ histograms.ExpectUniqueSample( "WebApp.LaunchSource", apps::LaunchSource::kFromNavigationCapturing, 1); histograms.ExpectTotalCount(kLaunchParamsEnqueueMetric, 1); + EXPECT_THAT( + GetNavigationCapturingFinalDisplayMetric(histograms), + testing::ElementsAre( + NavigationCapturingDisplayModeResult::kAppStandaloneFinalStandalone)); } IN_PROC_BROWSER_TEST_F(NavigationCapturingBrowserNavigatorBrowserTest, @@ -493,6 +531,10 @@ histograms.ExpectUniqueSample( "WebApp.LaunchSource", apps::LaunchSource::kFromNavigationCapturing, 1); histograms.ExpectTotalCount(kLaunchParamsEnqueueMetric, 1); + EXPECT_THAT( + GetNavigationCapturingFinalDisplayMetric(histograms), + testing::ElementsAre( + NavigationCapturingDisplayModeResult::kAppBrowserTabFinalBrowserTab)); EXPECT_NE(contents_navigation_happened_in, new_browser->tab_strip_model()->GetActiveWebContents()); @@ -548,6 +590,11 @@ // enqueued, and hence this metric will not be measured. histograms.ExpectTotalCount(kLaunchParamsEnqueueMetric, 0); + EXPECT_THAT( + GetNavigationCapturingFinalDisplayMetric(histograms), + testing::ElementsAre( + NavigationCapturingDisplayModeResult::kAppBrowserTabFinalBrowserTab)); + // browser() should still be at the GetAppUrl() page. EXPECT_EQ(GetAppNoManifestUrl(), browser() ->tab_strip_model() @@ -615,6 +662,11 @@ "WebApp.LaunchSource", apps::LaunchSource::kFromNavigationCapturing, 1); histograms.ExpectTotalCount(kLaunchParamsEnqueueMetric, 1); + EXPECT_THAT( + GetNavigationCapturingFinalDisplayMetric(histograms), + testing::ElementsAre( + NavigationCapturingDisplayModeResult::kAppBrowserTabFinalStandalone)); + EXPECT_EQ(contents_navigation_happened_in, app_browser_to_use->tab_strip_model()->GetActiveWebContents()); EXPECT_EQ(0, app_browser_to_use->tab_strip_model()->GetIndexOfWebContents( @@ -673,6 +725,10 @@ histograms.ExpectUniqueSample( "WebApp.LaunchSource", apps::LaunchSource::kFromNavigationCapturing, 1); histograms.ExpectTotalCount(kLaunchParamsEnqueueMetric, 1); + EXPECT_THAT( + GetNavigationCapturingFinalDisplayMetric(histograms), + testing::ElementsAre( + NavigationCapturingDisplayModeResult::kAppBrowserTabFinalBrowserTab)); EXPECT_EQ(GetFocusExistingUrl(), app_browser_to_use->tab_strip_model() ->GetActiveWebContents() @@ -729,6 +785,59 @@ testing::ElementsAre(GetLandingPage())); } +using LaunchContainerMetricMeasurementTest = + NavigationCapturingBrowserNavigatorBrowserTest; + +IN_PROC_BROWSER_TEST_F(LaunchContainerMetricMeasurementTest, + NavigateExistingStandaloneToTab) { + // Load 'kNavigateExistingUrl` and `kFocusExistingUrl` in new tabs. + chrome::NewTab(browser()); + ASSERT_TRUE( + ui_test_utils::NavigateToURL(browser(), GetNavigateExistingUrl())); + content::WebContents* target_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + chrome::NewTab(browser()); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetFocusExistingUrl())); + + // Install both apps. + const webapps::AppId& source_app = + InstallWebAppFromPageAndCloseAppBrowser(browser(), GetFocusExistingUrl()); + const webapps::AppId& dest_app = InstallWebAppFromPageAndCloseAppBrowser( + browser(), GetNavigateExistingUrl()); + +#if BUILDFLAG(IS_CHROMEOS) + EXPECT_EQ(apps::test::EnableLinkCapturingByUser(profile(), dest_app), + base::ok()); +#endif + + // Trigger a navigation to `kNavigateExistingUrl`. This should end up in the + // browser tab. + base::HistogramTester histograms; + { + NavigateParams params(profile(), GetNavigateExistingUrl(), + ui::PAGE_TRANSITION_LINK); + params.source_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; + Navigate(¶ms); + LoadURLInContents(target_contents, GetNavigateExistingUrl(), params); + } + + content::WaitForLoadStop(target_contents); + apps::test::FlushLaunchQueuesForAllBrowserTabs(); + AwaitMetricsAvailableFromRenderer(); + + // Verify that navigation did indeed end up in the browser tab via navigation + // capturing. + histograms.ExpectUniqueSample( + "WebApp.LaunchSource", apps::LaunchSource::kFromNavigationCapturing, 1); + + EXPECT_THAT( + GetNavigationCapturingFinalDisplayMetric(histograms), + testing::ElementsAre( + NavigationCapturingDisplayModeResult::kAppStandaloneFinalBrowserTab)); +} + class NavigationCapturingWithRedirectionBrowserNavigatorTest : public NavigationCapturingBrowserNavigatorBrowserTest { public: @@ -799,6 +908,11 @@ // Make sure that web contents is a tab in `browser()` and not `new_browser`. EXPECT_NE(browser()->tab_strip_model()->GetIndexOfWebContents(new_tab), TabStripModel::kNoTab); + + EXPECT_THAT( + GetNavigationCapturingFinalDisplayMetric(histograms), + testing::ElementsAre( + NavigationCapturingDisplayModeResult::kAppBrowserTabFinalBrowserTab)); } IN_PROC_BROWSER_TEST_F(NavigationCapturingWithRedirectionBrowserNavigatorTest, @@ -831,10 +945,13 @@ histograms.ExpectUniqueSample( "WebApp.LaunchSource", apps::LaunchSource::kFromNavigationCapturing, 0); histograms.ExpectTotalCount(kLaunchParamsEnqueueMetric, 0); + EXPECT_THAT(GetNavigationCapturingFinalDisplayMetric(histograms), + testing::IsEmpty()); // Make sure that web contents is a tab in `browser()` and not `new_browser`. EXPECT_NE(browser()->tab_strip_model()->GetIndexOfWebContents(new_tab), TabStripModel::kNoTab); } + } // namespace } // namespace web_app
diff --git a/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc b/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc index 9ea5829..c3c66d3 100644 --- a/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc +++ b/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc
@@ -208,6 +208,15 @@ webapps::InstallResultCode::kWebAppProviderNotReady); } +void FakeWebAppUiManager::TriggerInstallDialogForBackgroundInstall( + content::WebContents* initiating_web_contents, + std::unique_ptr<webapps::MlInstallOperationTracker> tracker, + const GURL& install_url, + const std::optional<GURL>& manifest_id, + InstallCallback callback) { + NOTIMPLEMENTED(); +} + void FakeWebAppUiManager::PresentUserUninstallDialog( const webapps::AppId& app_id, webapps::WebappUninstallSource uninstall_source,
diff --git a/chrome/browser/web_applications/test/fake_web_app_ui_manager.h b/chrome/browser/web_applications/test/fake_web_app_ui_manager.h index a30ef867..8072ab0 100644 --- a/chrome/browser/web_applications/test/fake_web_app_ui_manager.h +++ b/chrome/browser/web_applications/test/fake_web_app_ui_manager.h
@@ -15,6 +15,7 @@ #include "base/values.h" #include "chrome/browser/web_applications/web_app_ui_manager.h" #include "components/services/app_service/public/cpp/app_launch_util.h" +#include "components/webapps/browser/installable/ml_install_operation_tracker.h" #include "components/webapps/common/web_app_id.h" class Browser; @@ -23,6 +24,9 @@ class FilePath; } // namespace base +namespace webapps { +class MlInstallOperationTracker; +} // namespace webapps namespace web_app { class FakeWebAppUiManager : public WebAppUiManager { @@ -113,6 +117,12 @@ void TriggerInstallDialog(content::WebContents* web_contents, webapps::WebappInstallSource source, InstallCallback callback) override; + void TriggerInstallDialogForBackgroundInstall( + content::WebContents* initiating_web_contents, + std::unique_ptr<webapps::MlInstallOperationTracker> tracker, + const GURL& install_url, + const std::optional<GURL>& manifest_id, + InstallCallback callback) override; void PresentUserUninstallDialog( const webapps::AppId& app_id,
diff --git a/chrome/browser/web_applications/test/web_app_test_utils.cc b/chrome/browser/web_applications/test/web_app_test_utils.cc index f261c55..067bbc6e 100644 --- a/chrome/browser/web_applications/test/web_app_test_utils.cc +++ b/chrome/browser/web_applications/test/web_app_test_utils.cc
@@ -1182,13 +1182,13 @@ webapps::AppId InstallPwaForCurrentUrl(Browser* browser) { // Depending on the installability criteria, different dialogs can be used. SetAutoAcceptWebAppDialogForTesting(true, true); - SetAutoAcceptPWAInstallConfirmationForTesting(true); + auto auto_accept_pwa_install_confirmation = + SetAutoAcceptPWAInstallConfirmationForTesting(); SetAutoAcceptDiyAppsInstallDialogForTesting(true); WebAppTestInstallWithOsHooksObserver observer(browser->profile()); observer.BeginListening(); CHECK(chrome::ExecuteCommand(browser, IDC_INSTALL_PWA)); webapps::AppId app_id = observer.Wait(); - SetAutoAcceptPWAInstallConfirmationForTesting(false); SetAutoAcceptWebAppDialogForTesting(false, false); SetAutoAcceptDiyAppsInstallDialogForTesting(false); return app_id;
diff --git a/chrome/browser/web_applications/web_app_command_scheduler.cc b/chrome/browser/web_applications/web_app_command_scheduler.cc index 4a3cc14..c718919 100644 --- a/chrome/browser/web_applications/web_app_command_scheduler.cc +++ b/chrome/browser/web_applications/web_app_command_scheduler.cc
@@ -83,6 +83,7 @@ #include "components/keep_alive_registry/keep_alive_types.h" #include "components/keep_alive_registry/scoped_keep_alive.h" #include "components/webapps/browser/installable/installable_metrics.h" +#include "components/webapps/browser/installable/ml_install_operation_tracker.h" #include "components/webapps/browser/web_contents/web_app_url_loader.h" #include "content/public/browser/storage_partition_config.h" #include "content/public/browser/web_contents.h" @@ -689,12 +690,14 @@ void WebAppCommandScheduler::InstallAppFromUrl( const GURL& install_url, const std::optional<GURL>& manifest_id, + base::WeakPtr<content::WebContents> web_contents, + WebAppInstallDialogCallback dialog_callback, WebInstallFromUrlCommandCallback installed_callback, const base::Location& location) { provider_->command_manager().ScheduleCommand( - std::make_unique<WebInstallFromUrlCommand>(profile_.get(), install_url, - manifest_id, - std::move(installed_callback)), + std::make_unique<WebInstallFromUrlCommand>( + profile_.get(), install_url, manifest_id, web_contents, + std::move(dialog_callback), std::move(installed_callback)), location); }
diff --git a/chrome/browser/web_applications/web_app_command_scheduler.h b/chrome/browser/web_applications/web_app_command_scheduler.h index 0be38c4..2388358 100644 --- a/chrome/browser/web_applications/web_app_command_scheduler.h +++ b/chrome/browser/web_applications/web_app_command_scheduler.h
@@ -585,11 +585,14 @@ WebAppIconDiagnosticResultCallback result_callback, const base::Location& location = FROM_HERE); - // Installs the web content at `install_url`, verifying that it has the - // given resolved `manifest_id`. Returns the `InstallResultCode` and the - // computed manifest id if successful. Used by Web Install API. + // User initiated install uses the shared web contents to install the content + // at `install_url`, with optional `manifest_id`. + // Calls `installed_callback` with the `InstallResultCode` and the computed + // manifest id if successful. Used by Web Install API. void InstallAppFromUrl(const GURL& install_url, const std::optional<GURL>& manifest_id, + base::WeakPtr<content::WebContents> web_contents, + WebAppInstallDialogCallback dialog_callback, WebInstallFromUrlCommandCallback installed_callback, const base::Location& location = FROM_HERE);
diff --git a/chrome/browser/web_applications/web_app_ui_manager.h b/chrome/browser/web_applications/web_app_ui_manager.h index 7ae5ccf8..0b6da649 100644 --- a/chrome/browser/web_applications/web_app_ui_manager.h +++ b/chrome/browser/web_applications/web_app_ui_manager.h
@@ -37,6 +37,9 @@ class NavigationHandle; } // namespace content +namespace webapps { +class MlInstallOperationTracker; +} namespace web_app { class WithAppResources; @@ -253,6 +256,17 @@ webapps::WebappInstallSource source, InstallCallback callback) = 0; + // Triggers the web app install dialog for a background install of the + // contents at `install_url`, with the optional `manifest_id`. The dialog will + // be anchored to `initiating_web_contents`. This assumes the app is not + // already installed. Used for the Web Install API. + virtual void TriggerInstallDialogForBackgroundInstall( + content::WebContents* initiating_web_contents, + std::unique_ptr<webapps::MlInstallOperationTracker> tracker, + const GURL& install_url, + const std::optional<GURL>& manifest_id, + InstallCallback callback) = 0; + // The uninstall dialog will be modal to |parent_window|, or a non-modal if // |parent_window| is nullptr. Use this API if a Browser window needs to be // passed in along with an UninstallCompleteCallback.
diff --git a/chrome/browser/web_applications/web_app_utils.h b/chrome/browser/web_applications/web_app_utils.h index 2dcd328d..f982a05 100644 --- a/chrome/browser/web_applications/web_app_utils.h +++ b/chrome/browser/web_applications/web_app_utils.h
@@ -42,10 +42,10 @@ namespace error_page { // |alternative_error_page_params| dictionary key values in the // |AlternativeErrorPageOverrideInfo| mojom struct. -const char kMessage[] = "web_app_error_page_message"; -const char kAppShortName[] = "app_short_name"; -const char kIconUrl[] = "icon_url"; -const char kSupplementaryIcon[] = "supplementary_icon"; +inline constexpr char kMessage[] = "web_app_error_page_message"; +inline constexpr char kAppShortName[] = "app_short_name"; +inline constexpr char kIconUrl[] = "icon_url"; +inline constexpr char kSupplementaryIcon[] = "supplementary_icon"; // This must match the HTML element id of the svg to show as a supplementary // icon on the default offline error page.
diff --git a/chrome/browser/web_applications/web_install_browsertest.cc b/chrome/browser/web_applications/web_install_browsertest.cc index 8a1a7c4..b8c7bbf 100644 --- a/chrome/browser/web_applications/web_install_browsertest.cc +++ b/chrome/browser/web_applications/web_install_browsertest.cc
@@ -118,8 +118,6 @@ webapps::TestAppBannerManagerDesktop::FromWebContents(web_contents()); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), current_doc_url)); manager->WaitForInstallableCheck(); - - SetAutoAcceptPWAInstallConfirmationForTesting(true); } content::WebContents* web_contents() { @@ -171,6 +169,8 @@ GenerateManifestId("some_id", current_doc_url).spec(); NavigateAndConfigureCurrentDocumentForInstall(current_doc_url); + auto auto_accept_pwa_install_confirmation = + SetAutoAcceptPWAInstallConfirmationForTesting(); base::test::TestFuture<const webapps::AppId&, webapps::InstallResultCode> install_future;
diff --git a/chrome/browser/web_applications/web_install_service_impl.cc b/chrome/browser/web_applications/web_install_service_impl.cc index 6ec68017..58a24d5 100644 --- a/chrome/browser/web_applications/web_install_service_impl.cc +++ b/chrome/browser/web_applications/web_install_service_impl.cc
@@ -27,6 +27,8 @@ #include "components/webapps/browser/installable/installable_logging.h" #include "components/webapps/browser/installable/installable_metrics.h" #include "components/webapps/browser/installable/installable_params.h" +#include "components/webapps/browser/installable/ml_install_operation_tracker.h" +#include "components/webapps/browser/installable/ml_installability_promoter.h" #include "components/webapps/common/web_app_id.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" @@ -295,12 +297,38 @@ GURL()); return; } - auto* profile = - Profile::FromBrowserContext(render_frame_host().GetBrowserContext()); - auto* provider = WebAppProvider::GetForWebApps(profile); - provider->scheduler().InstallAppFromUrl( - install_target, manifest_id, + auto* web_contents = + content::WebContents::FromRenderFrameHost(&render_frame_host()); + + webapps::MLInstallabilityPromoter* promoter = + webapps::MLInstallabilityPromoter::FromWebContents(web_contents); + CHECK(promoter); + if (promoter->HasCurrentInstall()) { + // The current web contents is being installed via another method. Cancel + // this background install. + std::move(callback).Run(blink::mojom::WebInstallServiceResult::kAbortError, + GURL()); + return; + } + + auto* provider = WebAppProvider::GetForWebContents(web_contents); + CHECK(provider); + if (provider->command_manager().IsInstallingForWebContents(web_contents)) { + // Another install is already scheduled on the current web contents. Cancel + // this background install. + std::move(callback).Run(blink::mojom::WebInstallServiceResult::kAbortError, + GURL()); + return; + } + + // Register the background install on the current web contents. + std::unique_ptr<webapps::MlInstallOperationTracker> install_tracker = + promoter->RegisterCurrentInstallForWebContents( + webapps::WebappInstallSource::WEB_INSTALL); + + provider->ui_manager().TriggerInstallDialogForBackgroundInstall( + web_contents, std::move(install_tracker), install_target, manifest_id, base::BindOnce(&WebInstallServiceImpl::OnAppInstalled, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); }
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index c6a3ea8..a588019 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1746619131-b5f119ad34729c39bb8db97e934147dbaff50605-413ccd12abe49ad79521af08e38c1208cc19f44a.profdata +chrome-android32-main-1746683835-1595faf5cbb93723f571c4d409ff6ca1d7e84907-1bd71c758b467c65ac98df0740c3a0146a2462d1.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index a257ad1..abdadaf3 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1746631188-eb1d0ec979dc5cad49b7f79248f80823f6ca3248-9158358aef7fc7a0f62b5f98b94c2f09b8e14b32.profdata +chrome-android64-main-1746695505-489c4ca563f78bed9bbe122adc7b46e036021e1d-4e8b235a3243badf4f0e55260cd385b68f720a0b.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 8bb18b5..8c20069 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1746619131-0479134592bfcf16abb87046cc181dafa4dca288-413ccd12abe49ad79521af08e38c1208cc19f44a.profdata +chrome-linux-main-1746662394-55f9fee1514d0a324f448645c27e2709e6d6f894-fbacdb92137088dea8f53b8d1cbbe155a867b9d0.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 09b1233..2f9cbb1e 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1746633553-c187962b7e6e4b34c494431fc424b4ae91d00bf2-27ce3c2b779fe727f5ed1e7982fcc356a9b10b7f.profdata +chrome-mac-arm-main-1746697152-b484f34e46967d38e537a3f5c484b6f1dd833dda-524850a07d7849a97763c3b848063d3dfdbd653d.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 97d963af..2a58ba0 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1746619131-f0689b7c453bf66428fd1cec9c04c8fc387974a9-413ccd12abe49ad79521af08e38c1208cc19f44a.profdata +chrome-mac-main-1746683835-a60c7c5de757ff87d50998c953633c88d249b2df-1bd71c758b467c65ac98df0740c3a0146a2462d1.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index 8bdecb5..e0f8de7 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1746619131-846a6c3eac1af9e8d77dfc02e863a0f37f6238c6-413ccd12abe49ad79521af08e38c1208cc19f44a.profdata +chrome-win-arm64-main-1746683835-669257521af98d168da18a11972df7f1fc316149-1bd71c758b467c65ac98df0740c3a0146a2462d1.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index ff835751..23ebb43 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1746608342-d334b0886e62903e6e2e566b2cb4cd02de0e6fdf-deb8d871c2591efece685fe2695903c61259ee06.profdata +chrome-win32-main-1746683835-c06420b66e2ecd8b25074e50e13f6986a1354986-1bd71c758b467c65ac98df0740c3a0146a2462d1.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 4f6f07a..648488a8 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1746586632-f8dce42004d63c7802f1074010b3c7c9b792793d-f351d8b201937d9402701c01bb3ba07eb2001ae0.profdata +chrome-win64-main-1746662394-37830bc044293a0fdcf12190c695810885ce0102-fbacdb92137088dea8f53b8d1cbbe155a867b9d0.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 8dde0f01..644991d 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -415,17 +415,17 @@ BASE_FEATURE_PARAM(std::string, kGlicLauncherToggleLearnMoreURL, &kGlicLearnMoreURLConfig, - "glic-shortcuts-launcher-toggle-learn-more-url", + "glic-launcher-toggle-learn-more-url", ""); BASE_FEATURE_PARAM(std::string, kGlicLocationToggleLearnMoreURL, &kGlicLearnMoreURLConfig, - "glic-shortcuts-location-toggle-learn-more-url", + "glic-location-toggle-learn-more-url", ""); BASE_FEATURE_PARAM(std::string, kGlicTabAccessToggleLearnMoreURL, &kGlicLearnMoreURLConfig, - "glic-shortcuts-tab-access-toggle-learn-more-url", + "glic-tab-access-toggle-learn-more-url", ""); BASE_FEATURE_PARAM(std::string, kGlicSettingsPageLearnMoreURL,
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index fbb8f4c..6a635fc 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -250,8 +250,6 @@ extern const base::FeatureParam<std::string> kGlicLocationToggleLearnMoreURL; COMPONENT_EXPORT(CHROME_FEATURES) extern const base::FeatureParam<std::string> kGlicTabAccessToggleLearnMoreURL; -COMPONENT_EXPORT(CHROME_FEATURES) -extern const base::FeatureParam<std::string> kGlicSettingsPageLearnMoreURL; COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kGlicCSPConfig); COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni index e032ce6..8f1d5db 100644 --- a/chrome/common/extensions/api/api_sources.gni +++ b/chrome/common/extensions/api/api_sources.gni
@@ -13,6 +13,7 @@ # TODO(https://crbug.com/356905053): Continue moving more here. schema_sources_ = [ "activity_log_private.json", + "bookmarks.json", "cookies.json", "developer_private.idl", "identity.idl", @@ -47,7 +48,6 @@ "autofill_private.idl", "autotest_private.idl", "bookmark_manager_private.json", - "bookmarks.json", "braille_display_private.idl", "chrome_web_view_internal.json", "command_line_private.json",
diff --git a/chrome/common/extensions/api/bookmark_manager_private.json b/chrome/common/extensions/api/bookmark_manager_private.json index df1ec62..812f3729 100644 --- a/chrome/common/extensions/api/bookmark_manager_private.json +++ b/chrome/common/extensions/api/bookmark_manager_private.json
@@ -43,15 +43,6 @@ "items": {"$ref": "BookmarkNodeDataElement"} } } - }, - { - "id": "OpenInNewTabParams", - "type": "object", - "description": "Parameters for the Open In New Tab method", - "properties": { - "active": {"type": "boolean", "description": "Whether this tab should be active."}, - "split": {"type": "boolean", "description": "Whether this tab should enter into a split view alongside the active tab."} - } } ], "functions": [ @@ -280,10 +271,9 @@ "type": "string" }, { - "name": "params", - "optional": true, - "$ref": "OpenInNewTabParams", - "description": "Parameters for the new tab the given bookmark is opened into." + "name": "active", + "description": "Whether this tab should be active.", + "type": "boolean" } ] },
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index ab5e819..3682d550 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -1260,7 +1260,7 @@ // the user grants consent again, we will not record their metric in the // histogram // "ChromeOS.Settings.NumUniqueSettingsChanged.DeviceLifetime2.{Time}". -const char kHasEverRevokedMetricsConsent[] = +inline constexpr char kHasEverRevokedMetricsConsent[] = "settings.has_ever_revoked_metrics_consent"; // A boolean to store that an admin user accessed the host device remotely when
diff --git a/chrome/elevation_service/elevator.h b/chrome/elevation_service/elevator.h index 5b9bc81..44266ed 100644 --- a/chrome/elevation_service/elevator.h +++ b/chrome/elevation_service/elevator.h
@@ -32,8 +32,9 @@ 0x57}}; // Elevator Test CLSID. {416C51AC-4DEF-43CA-96E8-E735210AB257} namespace switches { -constexpr char kElevatorClsIdForTestingSwitch[] = "elevator-clsid-for-testing"; -constexpr char kFakeReencryptForTestingSwitch[] = +inline constexpr char kElevatorClsIdForTestingSwitch[] = + "elevator-clsid-for-testing"; +inline constexpr char kFakeReencryptForTestingSwitch[] = "elevator-fake-reencrypt-for-testing"; } // namespace switches
diff --git a/chrome/renderer/accessibility/read_anything/read_aloud_app_model.cc b/chrome/renderer/accessibility/read_anything/read_aloud_app_model.cc index fe7b9fe..e0203e6 100644 --- a/chrome/renderer/accessibility/read_anything/read_aloud_app_model.cc +++ b/chrome/renderer/accessibility/read_anything/read_aloud_app_model.cc
@@ -589,7 +589,9 @@ } int ReadAloudAppModel::GetCurrentTextStartIndex(const ui::AXNodeID& node_id) { - if (processed_granularities_on_current_page_.size() < 1) { + if (processed_granularities_on_current_page_.size() < 1 || + processed_granularity_index_ >= + processed_granularities_on_current_page_.size()) { return -1; } @@ -604,7 +606,9 @@ } int ReadAloudAppModel::GetCurrentTextEndIndex(const ui::AXNodeID& node_id) { - if (processed_granularities_on_current_page_.size() < 1) { + if (processed_granularities_on_current_page_.size() < 1 || + processed_granularity_index_ >= + processed_granularities_on_current_page_.size()) { return -1; }
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc b/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc index 68bc30d..2fdea11 100644 --- a/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc +++ b/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc
@@ -208,10 +208,20 @@ return need_to_draw; } - // The main panel selection contains content outside of the distilled content. - // Find the selected nodes to display instead of the distilled content. - if (const ui::AXNode *node = GetAXNode(start_.id), *end = GetAXNode(end_.id); - !node->IsInvisibleOrIgnored() && !end->IsInvisibleOrIgnored()) { + const ui::AXNode* node = GetAXNode(start_.id); + const ui::AXNode* end = GetAXNode(end_.id); + DUMP_WILL_BE_CHECK(node && end); + if (!node || !end) { + // Fail gracefully if the returned nodes are ever missing. + // This should never happen given that the AXSelection object is retrieved + // from the active tree. + return false; + } + + // The main panel selection contains content outside of the distilled + // content. Find the selected nodes to display instead of the distilled + // content. + if (!node->IsInvisibleOrIgnored() && !end->IsInvisibleOrIgnored()) { // Add all ancestor ids of start node, including the start node itself. for (base::queue<ui::AXNode*> ancestors = node->GetAncestorsCrossingTreeBoundaryAsQueue();
diff --git a/chrome/renderer/actor/type_tool.cc b/chrome/renderer/actor/type_tool.cc index 6e167d6..fa5dd00 100644 --- a/chrome/renderer/actor/type_tool.cc +++ b/chrome/renderer/actor/type_tool.cc
@@ -32,6 +32,15 @@ namespace actor { +using ::blink::WebCoalescedInputEvent; +using ::blink::WebElement; +using ::blink::WebInputEvent; +using ::blink::WebInputEventResult; +using ::blink::WebKeyboardEvent; +using ::blink::WebLocalFrame; +using ::blink::WebNode; +using ::blink::WebString; + namespace { // Structure to hold the mapping @@ -90,6 +99,13 @@ return *key_info_map; } +bool PrepareTargetForMode(WebLocalFrame& frame, mojom::TypeAction::Mode mode) { + // TODO(crbug.com/409570203): Use DELETE_EXISTING regardless of `mode` but + // we'll have to implement the different insertion modes. + frame.ExecuteCommand(WebString::FromUTF8("SelectAll")); + return true; +} + } // namespace TypeTool::TypeTool(mojom::TypeActionPtr action, content::RenderFrame& frame) @@ -132,7 +148,7 @@ // dom_key is already set correctly (it's the uppercase char) // Unmodified is lowercase params.unmodified_text = base::ToLowerASCII(c); - params.modifiers = blink::WebInputEvent::kShiftKey; + params.modifiers = WebInputEvent::kShiftKey; } else if (c >= '0' && c <= '9') { // ASCII Digits params.windows_key_code = ui::VKEY_0 + (c - '0'); @@ -153,7 +169,7 @@ // Check if this character requires shift if (info.unmodified_char != 0) { - params.modifiers = blink::WebInputEvent::kShiftKey; + params.modifiers = WebInputEvent::kShiftKey; params.unmodified_text = info.unmodified_char; } } @@ -165,11 +181,10 @@ return params; } -blink::WebInputEventResult TypeTool::CreateAndDispatchKeyEvent( - blink::WebInputEvent::Type type, +WebInputEventResult TypeTool::CreateAndDispatchKeyEvent( + WebInputEvent::Type type, KeyParams key_params) { - blink::WebKeyboardEvent key_event(type, key_params.modifiers, - ui::EventTimeForNow()); + WebKeyboardEvent key_event(type, key_params.modifiers, ui::EventTimeForNow()); key_event.windows_key_code = key_params.windows_key_code; key_event.native_key_code = key_params.native_key_code; key_event.dom_code = static_cast<int>( @@ -179,17 +194,17 @@ key_event.text[0] = key_params.text; key_event.unmodified_text[0] = key_params.unmodified_text; - blink::WebInputEventResult result = + WebInputEventResult result = frame_->GetWebFrame()->FrameWidget()->HandleInputEvent( - blink::WebCoalescedInputEvent(key_event, ui::LatencyInfo())); + WebCoalescedInputEvent(key_event, ui::LatencyInfo())); return result; } bool TypeTool::SimulateKeyPress(TypeTool::KeyParams params) { // TODO(crbug.com/402082693): Maybe add slight delay between events? - blink::WebInputEventResult down_result = CreateAndDispatchKeyEvent( - blink::WebInputEvent::Type::kRawKeyDown, params); + WebInputEventResult down_result = + CreateAndDispatchKeyEvent(WebInputEvent::Type::kRawKeyDown, params); // Only the KeyDown event will check for and report failure. The reason the // other events don't is that if the KeyDown event was dispatched to the page, @@ -199,33 +214,27 @@ // successful in terms that the tool has acted on the page. In particular, a // preventDefault()'ed KeyDown event will force suppressing the following Char // event but this is expected and common. - if (down_result == blink::WebInputEventResult::kHandledSuppressed) { + if (down_result == WebInputEventResult::kHandledSuppressed) { ACTOR_LOG() << "KeyDown event for key " << params.dom_key << " suppressed."; return false; } - blink::WebInputEventResult char_result = - CreateAndDispatchKeyEvent(blink::WebInputEvent::Type::kChar, params); - if (char_result == blink::WebInputEventResult::kHandledSuppressed) { + WebInputEventResult char_result = + CreateAndDispatchKeyEvent(WebInputEvent::Type::kChar, params); + if (char_result == WebInputEventResult::kHandledSuppressed) { ACTOR_LOG() << "Warning: Char event for key " << params.dom_key << " suppressed."; } - blink::WebInputEventResult up_result = - CreateAndDispatchKeyEvent(blink::WebInputEvent::Type::kKeyUp, params); - if (up_result == blink::WebInputEventResult::kHandledSuppressed) { + WebInputEventResult up_result = + CreateAndDispatchKeyEvent(WebInputEvent::Type::kKeyUp, params); + if (up_result == WebInputEventResult::kHandledSuppressed) { ACTOR_LOG() << "Warning: KeyUp event for key " << params.dom_key << " suppressed."; } return true; } -bool TypeTool::PrepareTargetForMode(const blink::WebNode& node, - mojom::TypeAction::Mode mode) { - // TODO(crbug.com/409570203): Implement. - return true; -} - void TypeTool::Execute(ToolFinishedCallback callback) { if (!frame_->GetWebFrame() || !frame_->GetWebFrame()->FrameWidget()) { ACTOR_LOG() << "RenderFrame or FrameWidget is invalid."; @@ -243,7 +252,7 @@ } int32_t dom_node_id = target->get_dom_node_id(); - blink::WebNode node = GetNodeFromId(frame_.get(), dom_node_id); + WebNode node = GetNodeFromId(frame_.get(), dom_node_id); if (node.IsNull()) { ACTOR_LOG() << "Cannot find dom node with id " << dom_node_id; std::move(callback).Run(false); @@ -251,12 +260,13 @@ } // Validate Node is an editable element + // TODO(crbug.com/414398425): This seems too restrictive for non-input cases. if (!node.IsElementNode()) { ACTOR_LOG() << "Target node " << node << " is not an element."; std::move(callback).Run(false); return; } - blink::WebElement element = node.To<blink::WebElement>(); + WebElement element = node.To<WebElement>(); if (!element.IsEditable()) { ACTOR_LOG() << "Target element " << element << " is not editable."; std::move(callback).Run(false); @@ -275,13 +285,19 @@ } } - if (!PrepareTargetForMode(node, action_->mode)) { + if (!PrepareTargetForMode(*frame_->GetWebFrame(), action_->mode)) { ACTOR_LOG() << "Failed to prepare target element based on mode: " << action_->mode; std::move(callback).Run(false); return; } + // Note: Focus and preparing the target performs actions which lead to script + // execution so `node` may no longer be focused (it or its frame could be + // disconnected). However, sites sometimes do unexpected things to work around + // issues so to keep those working we proceed to key dispatch without checking + // this. + if (!base::IsStringASCII(action_->text)) { // TODO(crbug.com/409032824): Add support beyond ASCII. ACTOR_LOG() << "Characters beyond ASCII not supported" << action_->text;
diff --git a/chrome/renderer/actor/type_tool.h b/chrome/renderer/actor/type_tool.h index 77e0aff..68095b2 100644 --- a/chrome/renderer/actor/type_tool.h +++ b/chrome/renderer/actor/type_tool.h
@@ -14,10 +14,6 @@ #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/platform/web_input_event_result.h" -namespace blink { -class WebNode; -} // namespace blink - namespace content { class RenderFrame; } // namespace content @@ -61,11 +57,6 @@ KeyParams key_params); bool SimulateKeyPress(TypeTool::KeyParams params); - // Attempts to prepare the target element based on the TypeMode. - // Returns true on success, false on failure. - bool PrepareTargetForMode(const blink::WebNode& node, - mojom::TypeAction::Mode mode); - // Raw ref since this is owned by ToolExecutor whose lifetime is tied to // RenderFrame. base::raw_ref<content::RenderFrame> frame_;
diff --git a/chrome/services/ipp_parser/public/cpp/ipp_converter.h b/chrome/services/ipp_parser/public/cpp/ipp_converter.h index 66c4f3b..9ac68b4 100644 --- a/chrome/services/ipp_parser/public/cpp/ipp_converter.h +++ b/chrome/services/ipp_parser/public/cpp/ipp_converter.h
@@ -29,10 +29,10 @@ using HttpHeader = std::pair<std::string, std::string>; // Carriage return; Http header-pair delimiter. -const char kCarriage[] = "\r\n"; +inline constexpr char kCarriage[] = "\r\n"; // Defined IPP end-of-message sentinel. -const char kIppSentinel[] = "\x03"; +inline constexpr char kIppSentinel[] = "\x03"; // Request line converters // Parses |status_line| into vector of 3, individual terms, returns empty
diff --git a/chrome/services/speech/soda/soda_test_paths.h b/chrome/services/speech/soda/soda_test_paths.h index 3264a5e4..c83f7d0 100644 --- a/chrome/services/speech/soda/soda_test_paths.h +++ b/chrome/services/speech/soda/soda_test_paths.h
@@ -12,42 +12,42 @@ #if BUILDFLAG(IS_MAC) -constexpr base::FilePath::CharType kSodaResourcePath[] = +inline constexpr base::FilePath::CharType kSodaResourcePath[] = FILE_PATH_LITERAL("third_party/soda-mac64/resources"); -constexpr base::FilePath::CharType kSodaTestBinaryRelativePath[] = +inline constexpr base::FilePath::CharType kSodaTestBinaryRelativePath[] = FILE_PATH_LITERAL("libsoda_for_testing.so"); #elif BUILDFLAG(IS_WIN) && defined(ARCH_CPU_64_BITS) -constexpr base::FilePath::CharType kSodaResourcePath[] = +inline constexpr base::FilePath::CharType kSodaResourcePath[] = FILE_PATH_LITERAL("third_party/soda-win64/resources"); -constexpr base::FilePath::CharType kSodaTestBinaryRelativePath[] = +inline constexpr base::FilePath::CharType kSodaTestBinaryRelativePath[] = FILE_PATH_LITERAL("SODA_for_testing.dll"); #elif BUILDFLAG(IS_WIN) && defined(ARCH_CPU_32_BITS) -constexpr base::FilePath::CharType kSodaResourcePath[] = +inline constexpr base::FilePath::CharType kSodaResourcePath[] = FILE_PATH_LITERAL("third_party/soda-win32/resources"); -constexpr base::FilePath::CharType kSodaTestBinaryRelativePath[] = +inline constexpr base::FilePath::CharType kSodaTestBinaryRelativePath[] = FILE_PATH_LITERAL("SODA_for_testing.dll"); #elif BUILDFLAG(IS_LINUX) -constexpr base::FilePath::CharType kSodaResourcePath[] = +inline constexpr base::FilePath::CharType kSodaResourcePath[] = FILE_PATH_LITERAL("third_party/soda/resources"); -constexpr base::FilePath::CharType kSodaTestBinaryRelativePath[] = +inline constexpr base::FilePath::CharType kSodaTestBinaryRelativePath[] = FILE_PATH_LITERAL("libsoda_for_testing.so"); #endif -constexpr base::FilePath::CharType kSodaLanguagePackRelativePath[] = +inline constexpr base::FilePath::CharType kSodaLanguagePackRelativePath[] = FILE_PATH_LITERAL("en_us"); -constexpr base::FilePath::CharType kSodaTestAudioRelativePath[] = +inline constexpr base::FilePath::CharType kSodaTestAudioRelativePath[] = FILE_PATH_LITERAL("hey_google.wav"); } // namespace soda
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 208c9cef..422673a 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1668,7 +1668,6 @@ "../browser/password_manager/passwords_navigation_observer.cc", "../browser/password_manager/passwords_navigation_observer.h", "../browser/policy/test/v8_optimizer_policy_browsertest.cc", - "../browser/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations_component_installer_android_browsertest.cc", "../browser/profiles/profile_browsertest_android.cc", "../browser/ssl/chrome_security_state_client_browsertest.cc", "../browser/trusted_vault/trusted_vault_encryption_keys_tab_helper_browsertest.cc", @@ -2941,6 +2940,7 @@ data += metric_integration_jsdeps sources = [ + "../../components/live_caption/views/caption_bubble_browsertest.cc", "../browser/accessibility/accessibility_labels_service_browsertest.cc", "../browser/accessibility/ax_main_node_annotator_controller_browsertest.cc", "../browser/accessibility/image_annotation_browsertest.cc", @@ -6391,8 +6391,6 @@ "../browser/site_protection/site_protection_metrics_observer_unittest.cc", "../browser/ssl/generated_https_first_mode_pref_unittest.cc", "../browser/ui/passwords/password_cross_domain_confirmation_popup_controller_impl_unittest.cc", - "../browser/ui/plus_addresses/plus_address_creation_controller_desktop_unittest.cc", - "../browser/ui/plus_addresses/plus_address_menu_model_unittest.cc", "../browser/ui/task_manager/task_manager_table_model_unittest.cc", "../browser/ui/user_education/recent_session_policy_unittest.cc", "../browser/ui/webui/profile_internals/profile_internals_handler_unittest.cc", @@ -6680,6 +6678,7 @@ "//chrome/browser/ui/hats", "//chrome/browser/ui/login:unit_tests", "//chrome/browser/ui/page_info:unit_tests", + "//chrome/browser/ui/plus_addresses:unit_tests", "//chrome/browser/ui/safety_hub:test_support", "//chrome/browser/ui/serial:test_support", "//chrome/browser/ui/webui", @@ -7749,6 +7748,7 @@ "../browser/password_manager/password_change/change_form_submission_verifier_unittest.cc", "../browser/password_manager/password_change/change_password_form_finder_unittest.cc", "../browser/password_manager/password_change/change_password_form_waiter_unittest.cc", + "../browser/password_manager/password_change/model_quality_logs_uploader_unittest.cc", "../browser/password_manager/password_change_delegate_impl_unittest.cc", "../browser/performance_manager/execution_context_priority/side_panel_loading_voter_unittest.cc", "../browser/platform_util_unittest.cc", @@ -8914,6 +8914,7 @@ # Unit tests that run on Win/Mac/Linux and Android desktop. if (enable_extensions_core) { sources += [ + "../browser/extensions/api/bookmarks/bookmarks_api_unittest.cc", "../browser/extensions/api/declarative_net_request/action_tracker_unittest.cc", "../browser/extensions/api/declarative_net_request/declarative_net_request_unittest.cc", "../browser/extensions/api/declarative_net_request/dnr_test_base.cc", @@ -8924,6 +8925,8 @@ "../browser/extensions/api/storage/policy_value_store_unittest.cc", "../browser/extensions/api/storage/settings_sync_unittest.cc", "../browser/extensions/api/storage/storage_session_unittest.cc", + "../browser/extensions/api/web_request/web_request_api_unittest.cc", + "../browser/extensions/api/web_request/web_request_event_details_unittest.cc", "../browser/extensions/api/webstore_private/extension_install_status_unittest.cc", "../browser/extensions/api/webstore_private/webstore_private_unittest.cc", "../browser/extensions/chrome_content_verifier_unittest.cc", @@ -9022,7 +9025,6 @@ "../browser/extensions/activity_log/fullstream_ui_policy_unittest.cc", "../browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc", "../browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc", - "../browser/extensions/api/bookmarks/bookmarks_api_unittest.cc", "../browser/extensions/api/browsing_data/browsing_data_unittest.cc", "../browser/extensions/api/chrome_extensions_api_client_unittest.cc", "../browser/extensions/api/cookies/cookies_helpers_unittest.cc", @@ -9092,8 +9094,6 @@ "../browser/extensions/api/tabs/tabs_api_unittest.cc", "../browser/extensions/api/tabs/windows_util_unittest.cc", "../browser/extensions/api/web_navigation/frame_navigation_state_unittest.cc", - "../browser/extensions/api/web_request/web_request_api_unittest.cc", - "../browser/extensions/api/web_request/web_request_event_details_unittest.cc", "../browser/extensions/api/web_request/web_request_permissions_unittest.cc", "../browser/extensions/blocklist_check_unittest.cc", "../browser/extensions/blocklist_extension_prefs_unittest.cc", @@ -10888,8 +10888,6 @@ "../browser/ui/omnibox/omnibox_metrics_browsertest.cc", "../browser/ui/omnibox/omnibox_view_browsertest.cc", "../browser/ui/performance_controls/tab_resource_usage_tab_helper_interactive_uitest.cc", - "../browser/ui/plus_addresses/plus_address_error_dialog_interactive_uitest.cc", - "../browser/ui/plus_addresses/views/plus_address_creation_dialog_interactive_uitest.cc", "../browser/ui/search/instant_extended_interactive_uitest.cc", "../browser/ui/search/instant_test_base.cc", "../browser/ui/search/instant_test_base.h", @@ -11050,6 +11048,7 @@ "//chrome/browser/ui/lens:interactive_ui_tests", "//chrome/browser/ui/omnibox", "//chrome/browser/ui/page_action:icon_type", + "//chrome/browser/ui/plus_addresses:interactive_ui_tests", "//chrome/browser/ui/privacy_sandbox", "//chrome/browser/ui/startup:startup_tab", "//chrome/browser/ui/tab_contents",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/Journeys.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/Journeys.java index 7c7250a..bc8882c6 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/Journeys.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/Journeys.java
@@ -214,12 +214,17 @@ PageStation previousPage = currentPage; Tab previousTab = previousPage.loadedTabElement.get(); if (i == 0 && startingPage.isIncognito() && !isIncognito) { - currentPage = currentPage.openNewTabFast().loadWebPageProgrammatically(url); + currentPage = + currentPage + .openNewTabFast() + .loadPageProgrammatically(url, pageStationFactory.get()); } else if (i == 0 && !startingPage.isIncognito() && isIncognito) { currentPage = - currentPage.openNewIncognitoTabFast().loadWebPageProgrammatically(url); + currentPage + .openNewIncognitoTabFast() + .loadPageProgrammatically(url, pageStationFactory.get()); } else { - currentPage = currentPage.openFakeLinkToWebPage(url); + currentPage = currentPage.openFakeLink(url, pageStationFactory.get()); } if (!captureThumbnails) {
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/HubBaseStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/HubBaseStation.java index 75444a2..91fc281 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/HubBaseStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/HubBaseStation.java
@@ -32,6 +32,7 @@ import org.chromium.base.test.transit.ViewElement; import org.chromium.base.test.transit.ViewSpec; import org.chromium.chrome.browser.ChromeTabbedActivity; +import org.chromium.chrome.browser.hub.HubToolbarView; import org.chromium.chrome.browser.hub.PaneId; import org.chromium.chrome.browser.hub.R; import org.chromium.chrome.browser.layouts.LayoutType; @@ -42,15 +43,14 @@ /** The base station for Hub, with several panes and a toolbar. */ public abstract class HubBaseStation extends Station<ChromeTabbedActivity> { - public static final ViewSpec<View> HUB_TOOLBAR = viewSpec(withId(R.id.hub_toolbar)); + public static final ViewSpec<HubToolbarView> HUB_TOOLBAR = + viewSpec(HubToolbarView.class, withId(R.id.hub_toolbar)); public static final ViewSpec<View> HUB_PANE_HOST = viewSpec(withId(R.id.hub_pane_host)); - public static final ViewSpec<View> HUB_MENU_BUTTON = - HUB_TOOLBAR.descendant(withId(org.chromium.chrome.R.id.menu_button)); public static final ViewSpec<TabLayout> HUB_PANE_SWITCHER = HUB_TOOLBAR.descendant(TabLayout.class, withId(R.id.pane_switcher)); public final Element<TabModelSelector> tabModelSelectorElement; - public final ViewElement<View> toolbarElement; + public final ViewElement<HubToolbarView> toolbarElement; public final ViewElement<View> paneHostElement; public final ViewElement<View> menuButtonElement; public final ViewElement<TabLayout> paneSwitcherElement; @@ -70,7 +70,10 @@ toolbarElement = declareView(HUB_TOOLBAR); paneHostElement = declareView(HUB_PANE_HOST); - menuButtonElement = hasMenuButton ? declareView(HUB_MENU_BUTTON) : null; + menuButtonElement = + hasMenuButton + ? declareView(toolbarElement.descendant(withId(R.id.menu_button))) + : null; paneSwitcherElement = declareView(HUB_PANE_SWITCHER);
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupDialogFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupDialogFacility.java index c2a3e8c..90e2b33d 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupDialogFacility.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupDialogFacility.java
@@ -44,18 +44,16 @@ */ public class TabGroupDialogFacility<HostStationT extends Station<ChromeTabbedActivity>> extends Facility<HostStationT> { - public static final ViewSpec<View> TOOLBAR = viewSpec(withId(R.id.tab_group_toolbar)); - public static final ViewSpec<View> TABS_LIST = viewSpec( withId(R.id.tab_list_recycler_view), withParent(withId(R.id.tab_grid_dialog_recycler_view_container))); - public static final ViewSpec SHARE_BUTTON = TOOLBAR.descendant(withId(R.id.share_button)); private final List<Integer> mTabIdsInGroup; private final String mTitle; private final boolean mIsIncognito; private final @Nullable @TabGroupColorId Integer mSelectedColor; + public ViewElement<View> toolbarElement; public ViewElement<View> shareButtonElement; public ViewElement<View> tabsListElement; public ViewElement<View> colorIconElement; @@ -86,6 +84,41 @@ mTitle = title; mSelectedColor = selectedColor; mIsIncognito = isIncognito; + + toolbarElement = declareView(viewSpec(withId(R.id.tab_group_toolbar))); + tabsListElement = declareView(TABS_LIST); + colorIconElement = + declareView(toolbarElement.descendant(withId(R.id.tab_group_color_icon_container))); + titleInputElement = + declareView( + toolbarElement.descendant( + withId(R.id.title), + isAssignableFrom(EditText.class), + withText(mTitle))); + newTabButtonElement = + declareView(toolbarElement.descendant(withId(R.id.toolbar_new_tab_button))); + backButtonElement = + declareView(toolbarElement.descendant(withId(R.id.toolbar_back_button))); + } + + @Override + public void declareElements(Elements.Builder elements) { + if (ChromeFeatureList.isEnabled(ChromeFeatureList.DATA_SHARING)) { + // TODO(ckitagawa): Add handling for an already shared group. + if (isAllowedToShare()) { + shareButtonElement = + declareView(toolbarElement.descendant(withId(R.id.share_button))); + } + + // Data sharing layout causes the menu button to be hidden due to the rounded corner. + listMenuButtonElement = + declareView( + toolbarElement.descendant(withId(R.id.toolbar_menu_button)), + ViewElement.displayingAtLeastOption(51)); + } else { + listMenuButtonElement = + declareView(toolbarElement.descendant(withId(R.id.toolbar_menu_button))); + } } private boolean isAllowedToShare() { @@ -104,40 +137,6 @@ .isAllowedToCreate()); } - @Override - public void declareElements(Elements.Builder elements) { - tabsListElement = elements.declareView(TABS_LIST); - colorIconElement = - elements.declareView( - TOOLBAR.descendant(withId(R.id.tab_group_color_icon_container))); - titleInputElement = - elements.declareView( - TOOLBAR.descendant( - withId(R.id.title), - isAssignableFrom(EditText.class), - withText(mTitle))); - newTabButtonElement = - elements.declareView(TOOLBAR.descendant(withId(R.id.toolbar_new_tab_button))); - backButtonElement = - elements.declareView(TOOLBAR.descendant(withId(R.id.toolbar_back_button))); - if (ChromeFeatureList.isEnabled(ChromeFeatureList.DATA_SHARING)) { - // TODO(ckitagawa): Add handling for an already shared group. - if (isAllowedToShare()) { - shareButtonElement = - elements.declareView(TOOLBAR.descendant(withId(R.id.share_button))); - } - - // Data sharing layout causes the menu button to be hidden due to the rounded corner. - listMenuButtonElement = - elements.declareView( - TOOLBAR.descendant(withId(R.id.toolbar_menu_button)), - ViewElement.displayingAtLeastOption(51)); - } else { - listMenuButtonElement = - elements.declareView(TOOLBAR.descendant(withId(R.id.toolbar_menu_button))); - } - } - /** Input a new group name. */ public TabGroupDialogFacility<HostStationT> inputName(String newTabGroupName) { return mHostStation.swapFacilitySync(
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherCardFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherCardFacility.java index bce8ae3..497e6bff 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherCardFacility.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherCardFacility.java
@@ -63,7 +63,6 @@ } protected ViewElement<View> declareActionButton(Elements.Builder elements) { - return elements.declareView( - cardViewElement.getViewSpec().descendant(withId(R.id.action_button))); + return elements.declareView(cardViewElement.descendant(withId(R.id.action_button))); } }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java index addd7a7c..5e676a51 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java
@@ -24,13 +24,11 @@ import org.hamcrest.Matcher; import org.chromium.base.test.transit.Condition; -import org.chromium.base.test.transit.Elements; import org.chromium.base.test.transit.Transition; import org.chromium.base.test.transit.ViewElement; import org.chromium.base.test.transit.ViewSpec; import org.chromium.base.test.util.ViewActionOnDescendant; import org.chromium.chrome.browser.hub.HubToolbarMediator; -import org.chromium.chrome.browser.hub.HubToolbarView; import org.chromium.chrome.browser.hub.PaneId; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; @@ -47,8 +45,6 @@ public abstract class TabSwitcherStation extends HubBaseStation { public static final ViewSpec<RecyclerView> TAB_LIST_RECYCLER_VIEW = HUB_PANE_HOST.descendant(RecyclerView.class, withId(R.id.tab_list_recycler_view)); - - public static final ViewSpec<View> TOOLBAR = viewSpec(instanceOf(HubToolbarView.class)); public static final ViewSpec<View> TAB_GROUP_COLOR_ICON_VIEW = viewSpec( allOf( @@ -81,20 +77,16 @@ boolean isIncognito, boolean regularTabsExist, boolean incognitoTabsExist) { super(regularTabsExist, incognitoTabsExist, /* hasMenuButton= */ true); mIsIncognito = isIncognito; - } - - @Override - public void declareElements(Elements.Builder elements) { - super.declareElements(elements); newTabButtonElement = - elements.declareView(TOOLBAR.descendant(withId(R.id.toolbar_action_button))); + declareView(toolbarElement.descendant(withId(R.id.toolbar_action_button))); if (OmniboxFeatures.sAndroidHubSearch.isEnabled()) { - elements.declareElementFactory( + declareElementFactory( mActivityElement, delayedElements -> { ViewSpec<View> searchBox = viewSpec(withId(R.id.search_box)); - ViewSpec<View> searchLoupe = TOOLBAR.descendant(withId(R.id.search_loupe)); + ViewSpec<View> searchLoupe = + toolbarElement.descendant(withId(R.id.search_loupe)); if (shouldHubSearchBoxBeVisible()) { searchElement = delayedElements.declareView(searchLoupe); delayedElements.declareNoView(searchBox); @@ -104,7 +96,7 @@ } }); } - recyclerViewElement = elements.declareView(TAB_LIST_RECYCLER_VIEW); + recyclerViewElement = declareView(TAB_LIST_RECYCLER_VIEW); } public boolean isIncognito() {
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/TabSwitcherActionMenuFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/TabSwitcherActionMenuFacility.java index a11fdb4..6c5d624f 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/TabSwitcherActionMenuFacility.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/TabSwitcherActionMenuFacility.java
@@ -21,7 +21,6 @@ import org.chromium.base.test.transit.Station; import org.chromium.base.test.transit.Transition; import org.chromium.base.test.transit.ViewElement; -import org.chromium.base.test.transit.ViewSpec; import org.chromium.chrome.R; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.tabmodel.TabModelSelector; @@ -42,30 +41,30 @@ @Override public void declareElements(Elements.Builder elements) { - ViewSpec<View> menuList = viewSpec(withId(R.id.app_menu_list)); - appMenuListElement = elements.declareView(menuList); + appMenuListElement = declareView(viewSpec(withId(R.id.app_menu_list))); closeTabMenuItemElement = - elements.declareView(menuList.descendant(withText(R.string.close_tab))); + declareView(appMenuListElement.descendant(withText(R.string.close_tab))); newTabMenuItemElement = - elements.declareView(menuList.descendant(withText(R.string.menu_new_tab))); + declareView(appMenuListElement.descendant(withText(R.string.menu_new_tab))); newIncognitoTabMenuItemElement = - elements.declareView( - menuList.descendant(withText(R.string.menu_new_incognito_tab))); + declareView( + appMenuListElement.descendant(withText(R.string.menu_new_incognito_tab))); if (ChromeFeatureList.sTabStripIncognitoMigration.isEnabled()) { if (mHostStation.isIncognito() && mHostStation.getActivity().getTabModelSelector().getModel(false).getCount() > 0) { switchOutOfIncognitoMenuItemElement = - elements.declareView( - menuList.descendant( + declareView( + appMenuListElement.descendant( withText(R.string.menu_switch_out_of_incognito))); } else if (!mHostStation.isIncognito() && mHostStation.getActivity().getTabModelSelector().getModel(true).getCount() > 0) { switchToIncognitoMenuItemElement = - elements.declareView( - menuList.descendant(withText(R.string.menu_switch_to_incognito))); + declareView( + appMenuListElement.descendant( + withText(R.string.menu_switch_to_incognito))); } } }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/quick_delete/QuickDeleteDialogFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/quick_delete/QuickDeleteDialogFacility.java index 444b7c1..24c8545 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/quick_delete/QuickDeleteDialogFacility.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/quick_delete/QuickDeleteDialogFacility.java
@@ -18,7 +18,6 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.transit.ConditionStatus; -import org.chromium.base.test.transit.Elements; import org.chromium.base.test.transit.Facility; import org.chromium.base.test.transit.Station; import org.chromium.base.test.transit.UiThreadCondition; @@ -54,41 +53,39 @@ public QuickDeleteDialogFacility(@TimePeriod int timePeriod) { mTimePeriod = timePeriod; - } - @Override - public void declareElements(Elements.Builder elements) { - ViewSpec<ModalDialogView> dialog = - viewSpec(ModalDialogView.class, withId(R.id.modal_dialog_view)); - dialogElement = elements.declareView(dialog); + dialogElement = + declareView(viewSpec(ModalDialogView.class, withId(R.id.modal_dialog_view))); customViewElement = - elements.declareView(dialog.descendant(withId(R.id.custom_view_not_in_scrollable))); - elements.declareView(dialog.descendant(withText(R.string.quick_delete_dialog_title))); + declareView(dialogElement.descendant(withId(R.id.custom_view_not_in_scrollable))); + declareView(dialogElement.descendant(withText(R.string.quick_delete_dialog_title))); spinnerElement = - elements.declareView( - dialog.descendant(Spinner.class, withId(R.id.quick_delete_spinner))); + declareView( + dialogElement.descendant(Spinner.class, withId(R.id.quick_delete_spinner))); historyInfoElement = - elements.declareView( - dialog.descendant( + declareView( + dialogElement.descendant( TextView.class, withId(R.id.quick_delete_history_row_title))); tabsInfoElement = - elements.declareView( - dialog.descendant(TextView.class, withId(R.id.quick_delete_tabs_row_title)), + declareView( + dialogElement.descendant( + TextView.class, withId(R.id.quick_delete_tabs_row_title)), ViewElement.allowDisabledOption()); - elements.declareView( - dialog.descendant( + declareView( + dialogElement.descendant( withText( R.string .quick_delete_dialog_cookies_cache_and_other_site_data_text))); moreOptionsElement = - elements.declareView(dialog.descendant(withId(R.id.quick_delete_more_options))); + declareView(dialogElement.descendant(withId(R.id.quick_delete_more_options))); cancelButtonElement = - elements.declareView( - dialog.descendant(withId(R.id.negative_button), withText("Cancel"))); + declareView( + dialogElement.descendant(withId(R.id.negative_button), withText("Cancel"))); deleteButtonElement = - elements.declareView( - dialog.descendant(withId(R.id.positive_button), withText("Delete data"))); - elements.declareEnterCondition(new TimePeriodSelectedCondition()); + declareView( + dialogElement.descendant( + withId(R.id.positive_button), withText("Delete data"))); + declareEnterCondition(new TimePeriodSelectedCondition()); } /** Click Cancel to close the dialog with no action. */ @@ -183,43 +180,25 @@ public class SearchHistoryDisambiguiationFacility extends Facility<Station<ChromeTabbedActivity>> { - private final boolean mExpectPresent; - public SearchHistoryDisambiguiationFacility(boolean expectPresent) { - mExpectPresent = expectPresent; - } - - @Override - public void declareElements(Elements.Builder elements) { ViewSpec<View> spec = - dialogElement - .getViewSpec() - .descendant(withId(R.id.search_history_disambiguation)); - if (mExpectPresent) { - elements.declareView(spec); + dialogElement.descendant(withId(R.id.search_history_disambiguation)); + if (expectPresent) { + declareView(spec); } else { - elements.declareNoView(spec); + declareNoView(spec); } } } public class SitesSubtitleFacility extends Facility<Station<ChromeTabbedActivity>> { - private final boolean mExpectPresent; - public SitesSubtitleFacility(boolean expectPresent) { - mExpectPresent = expectPresent; - } - - @Override - public void declareElements(Elements.Builder elements) { ViewSpec spec = - dialogElement - .getViewSpec() - .descendant(withId(R.id.quick_delete_history_row_subtitle)); - if (mExpectPresent) { - elements.declareView(spec); + dialogElement.descendant(withId(R.id.quick_delete_history_row_subtitle)); + if (expectPresent) { + declareView(spec); } else { - elements.declareNoView(spec); + declareNoView(spec); } } }
diff --git a/chrome/test/chromedriver/test/run_py_tests.pydeps b/chrome/test/chromedriver/test/run_py_tests.pydeps index a3d6407b..af399c7c 100644 --- a/chrome/test/chromedriver/test/run_py_tests.pydeps +++ b/chrome/test/chromedriver/test/run_py_tests.pydeps
@@ -53,7 +53,6 @@ ../../../../third_party/catapult/devil/devil/devil_env.py ../../../../third_party/catapult/devil/devil/utils/__init__.py ../../../../third_party/catapult/devil/devil/utils/cmd_helper.py -../../../../third_party/catapult/devil/devil/utils/host_utils.py ../../../../third_party/catapult/devil/devil/utils/lazy/__init__.py ../../../../third_party/catapult/devil/devil/utils/lazy/weak_constant.py ../../../../third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/chrome/test/data/actor/input.html b/chrome/test/data/actor/input.html index 47d8ea7..8562cd5a 100644 --- a/chrome/test/data/actor/input.html +++ b/chrome/test/data/actor/input.html
@@ -13,6 +13,7 @@ <!-- method=dialog prevents the form from navigating the page --> <form id="form" method="dialog"> <input type="text" name="input" id="input"> + <input type="text" name="input2" id="input2"> <input type="submit" id="submit"> </form> <script>
diff --git a/chrome/test/data/pdf/ink2_annotation_text_mixin_test.ts b/chrome/test/data/pdf/ink2_annotation_text_mixin_test.ts index 577afa3..72ba65f6 100644 --- a/chrome/test/data/pdf/ink2_annotation_text_mixin_test.ts +++ b/chrome/test/data/pdf/ink2_annotation_text_mixin_test.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {hexToColor, Ink2Manager, InkAnnotationTextMixin, TEXT_COLORS, TEXT_SIZES, TextAlignment, TextStyle} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; +import {hexToColor, Ink2Manager, InkAnnotationTextMixin, TEXT_COLORS, TEXT_SIZES, TextAlignment, TextStyle, TextTypeface} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; import {CrLitElement, html} from 'chrome://resources/lit/v3_0/lit.rollup.js'; import {eventToPromise} from 'chrome://webui-test/test_util.js'; @@ -21,8 +21,8 @@ override render() { return html` <select @change="${this.onTypefaceSelected}"> - <option value="Roboto"></option> - <option value="Serif"></option> + <option value="${TextTypeface.SANS_SERIF}"></option> + <option value="${TextTypeface.SERIF}"></option> </select> <select @change="${this.onSizeSelected}"> <option value="${TEXT_SIZES[0]}"></option> @@ -32,24 +32,22 @@ } } -const initializationPromise = eventToPromise('attributes-changed', manager); customElements.define(TestElement.is, TestElement); const testElement = document.createElement('test-element') as TestElement; document.body.appendChild(testElement); chrome.test.runTests([ - async function testInitialization() { - // The mixin should request the fonts from the backend initially, and - // update its text parameters based on the values in the manager. This - // is asynchronous (eventually, the fonts will be requested from the - // plugin). - const initEvent = await initializationPromise; - const expectedFonts = ['Roboto', 'Serif', 'Sans', 'Monospace']; + function testInitialization() { + // Test that the mixin initializes the fonts and other properties correctly. + const expectedFonts = [ + TextTypeface.SANS_SERIF, + TextTypeface.SERIF, + TextTypeface.MONOSPACE, + ]; assertDeepEquals(expectedFonts, testElement.fontNames); - assertDeepEquals(testElement.currentColor, initEvent.detail.color); - chrome.test.assertEq( - testElement.currentTypeface, initEvent.detail.typeface); - chrome.test.assertEq(testElement.currentSize, initEvent.detail.size); + assertDeepEquals({r: 0, b: 0, g: 0}, testElement.currentColor); + chrome.test.assertEq(TextTypeface.SANS_SERIF, testElement.currentTypeface); + chrome.test.assertEq(TEXT_SIZES[3]!, testElement.currentSize); chrome.test.succeed(); }, @@ -71,11 +69,11 @@ chrome.test.assertEq(2, selects.length); whenChanged = eventToPromise('attributes-changed', manager); const fontSelect = selects[0]!; - fontSelect.value = 'Serif'; + fontSelect.value = TextTypeface.SERIF; fontSelect.dispatchEvent( new CustomEvent('change', {bubbles: true, composed: true})); changedEvent = await whenChanged; - chrome.test.assertEq('Serif', changedEvent.detail.typeface); + chrome.test.assertEq(TextTypeface.SERIF, changedEvent.detail.typeface); // Test firing a change event from a <select> with onSizeSelected // registered as the listener calls the manager and results in an event. @@ -94,13 +92,12 @@ // Initial state const initialColor = hexToColor(TEXT_COLORS[0]!.color); assertDeepEquals(initialColor, testElement.currentColor); - chrome.test.assertEq(12, testElement.currentSize); - // First font returned by the current dummy code. - chrome.test.assertEq('Roboto', testElement.currentTypeface); + chrome.test.assertEq(TEXT_SIZES[3]!, testElement.currentSize); + chrome.test.assertEq(TextTypeface.SANS_SERIF, testElement.currentTypeface); const newColor = hexToColor(TEXT_COLORS[1]!.color); testElement.onTextAttributesChanged({ - typeface: 'Serif', + typeface: TextTypeface.SERIF, size: TEXT_SIZES[1]!, color: newColor, alignment: TextAlignment.LEFT, @@ -111,7 +108,7 @@ }); assertDeepEquals(newColor, testElement.currentColor); chrome.test.assertEq(TEXT_SIZES[1]!, testElement.currentSize); - chrome.test.assertEq('Serif', testElement.currentTypeface); + chrome.test.assertEq(TextTypeface.SERIF, testElement.currentTypeface); chrome.test.succeed(); }, @@ -125,11 +122,13 @@ chrome.test.assertTrue(testElement.isSelectedSize(TEXT_SIZES[0]!)); // Test that isSelectedTypeface returns the expected value. - chrome.test.assertTrue(testElement.isSelectedTypeface('Serif')); - chrome.test.assertFalse(testElement.isSelectedTypeface('Roboto')); - testElement.currentTypeface = 'Roboto'; - chrome.test.assertFalse(testElement.isSelectedTypeface('Serif')); - chrome.test.assertTrue(testElement.isSelectedTypeface('Roboto')); + chrome.test.assertTrue(testElement.isSelectedTypeface(TextTypeface.SERIF)); + chrome.test.assertFalse( + testElement.isSelectedTypeface(TextTypeface.SANS_SERIF)); + testElement.currentTypeface = TextTypeface.SANS_SERIF; + chrome.test.assertFalse(testElement.isSelectedTypeface(TextTypeface.SERIF)); + chrome.test.assertTrue( + testElement.isSelectedTypeface(TextTypeface.SANS_SERIF)); chrome.test.succeed(); },
diff --git a/chrome/test/data/pdf/ink2_manager_test.ts b/chrome/test/data/pdf/ink2_manager_test.ts index 11cf6a6c..980beb6 100644 --- a/chrome/test/data/pdf/ink2_manager_test.ts +++ b/chrome/test/data/pdf/ink2_manager_test.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. import type {AnnotationBrush, TextAnnotation, TextAttributes, TextBoxInit} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; -import {AnnotationBrushType, DEFAULT_TEXTBOX_HEIGHT, DEFAULT_TEXTBOX_WIDTH, Ink2Manager, PluginController, PluginControllerEventType, TextAlignment} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; +import {AnnotationBrushType, DEFAULT_TEXTBOX_HEIGHT, DEFAULT_TEXTBOX_WIDTH, Ink2Manager, PluginController, PluginControllerEventType, TextAlignment, TextTypeface} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; import {assert} from 'chrome://resources/js/assert.js'; import {eventToPromise} from 'chrome://webui-test/test_util.js'; @@ -15,7 +15,7 @@ function getTestAnnotation(): TextAnnotation { return { textAttributes: { - typeface: 'Roboto', + typeface: TextTypeface.SANS_SERIF, size: 12, color: {r: 0, g: 100, b: 0}, alignment: TextAlignment.LEFT, @@ -120,33 +120,6 @@ chrome.test.succeed(); }, - async function testGetTextAnnotationFontNames() { - // Checks that requesting the fonts for the first time retrieves the - // fonts from the plugin and fires a attributes-changed event with the font - // set to the first font returned. - const whenChanged = eventToPromise('attributes-changed', manager); - const fontNames = await manager.getTextAnnotationFontNames(); - - // For now, these are hardcoded in controller.ts. - const expectedFontNames = ['Roboto', 'Serif', 'Sans', 'Monospace']; - chrome.test.assertEq(fontNames.length, expectedFontNames.length); - for (let i = 0; i < expectedFontNames.length; i++) { - chrome.test.assertEq(fontNames[i], expectedFontNames[i]); - } - - // Check that the manager requested the fonts. - const getTextAnnotFontNamesMessage = - mockPlugin.findMessage('getTextAnnotFontNames'); - chrome.test.assertTrue(getTextAnnotFontNamesMessage !== undefined); - chrome.test.assertEq( - 'getTextAnnotFontNames', getTextAnnotFontNamesMessage.type); - - // Check that an event was fired. - const changedEvent = await whenChanged; - chrome.test.assertEq('Roboto', changedEvent.detail.typeface); - chrome.test.succeed(); - }, - function testSetFontProperties() { const fontUpdates: TextAttributes[] = []; manager.addEventListener('attributes-changed', e => { @@ -164,9 +137,9 @@ // Update font. Note the other `expectedAttributes` values come from the // defaults set in ink2_manager.ts. - manager.setTextTypeface('Serif'); + manager.setTextTypeface(TextTypeface.SERIF); const expectedAttributes = { - typeface: 'Serif', + typeface: TextTypeface.SERIF, size: 12, color: {r: 0, g: 0, b: 0}, alignment: TextAlignment.LEFT,
diff --git a/chrome/test/data/pdf/ink2_text_bottom_toolbar_test.ts b/chrome/test/data/pdf/ink2_text_bottom_toolbar_test.ts index c1e6ddbd..ba693c3 100644 --- a/chrome/test/data/pdf/ink2_text_bottom_toolbar_test.ts +++ b/chrome/test/data/pdf/ink2_text_bottom_toolbar_test.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {AnnotationMode, hexToColor, Ink2Manager, TEXT_COLORS, TextAlignment, UserAction} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; +import {AnnotationMode, hexToColor, Ink2Manager, TEXT_COLORS, TextAlignment, TextTypeface, UserAction} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; import type {Color} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; import {assert} from 'chrome://resources/js/assert.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; @@ -51,7 +51,7 @@ // Font and size selects const selects = toolbar.shadowRoot.querySelectorAll('select'); chrome.test.assertEq(2, selects.length); - chrome.test.assertEq('Roboto', selects[0]!.value); + chrome.test.assertEq(TextTypeface.SANS_SERIF, selects[0]!.value); chrome.test.assertEq('12', selects[1]!.value); // Style selector @@ -86,7 +86,7 @@ const whenChanged = eventToPromise('attributes-changed', Ink2Manager.getInstance()); - const newValue = 'Serif'; + const newValue = TextTypeface.SERIF; fontSelect.focus(); fontSelect.value = newValue; fontSelect.dispatchEvent(new CustomEvent('change'));
diff --git a/chrome/test/data/pdf/ink2_text_box_test.ts b/chrome/test/data/pdf/ink2_text_box_test.ts index cc8edb8..f52418e 100644 --- a/chrome/test/data/pdf/ink2_text_box_test.ts +++ b/chrome/test/data/pdf/ink2_text_box_test.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {hexToColor, Ink2Manager, PluginController, PluginControllerEventType, TEXT_COLORS, TextAlignment, TextBoxState, TextStyle} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; +import {hexToColor, Ink2Manager, PluginController, PluginControllerEventType, TEXT_COLORS, TextAlignment, TextBoxState, TextStyle, TextTypeface} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; import type {TextAnnotation} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; import {isVisible, microtasksFinished} from 'chrome://webui-test/test_util.js'; @@ -11,8 +11,6 @@ // Set up a dummy viewport so that we can get a predictable initial state. const {viewport, mockPlugin} = setupTestViewportAndMockPluginForInk(); const manager = Ink2Manager.getInstance(); -// Initialize a typeface, since this starts out empty. -manager.setTextTypeface('Roboto'); const textbox = document.createElement('ink-text-box'); document.body.appendChild(textbox); @@ -24,7 +22,7 @@ text: existing ? 'Hello World' : '', textAttributes: { size: 12, - typeface: 'Roboto', + typeface: TextTypeface.SANS_SERIF, styles: { [TextStyle.BOLD]: false, [TextStyle.ITALIC]: false, @@ -112,7 +110,7 @@ // Initial state chrome.test.assertEq('12px', textboxStyles.getPropertyValue('font-size')); chrome.test.assertEq( - 'Roboto', textboxStyles.getPropertyValue('font-family')); + 'sans-serif', textboxStyles.getPropertyValue('font-family')); chrome.test.assertEq('400', textboxStyles.getPropertyValue('font-weight')); chrome.test.assertEq( 'normal', textboxStyles.getPropertyValue('font-style')); @@ -126,7 +124,7 @@ // Confirm updating styles in the manager updates the style of the textbox. // Each type of update should independently trigger a change. // Typeface - manager.setTextTypeface('Serif'); + manager.setTextTypeface(TextTypeface.SERIF); await microtasksFinished(); chrome.test.assertEq( 'serif', textboxStyles.getPropertyValue('font-family')); @@ -159,7 +157,7 @@ chrome.test.assertEq('right', textboxStyles.getPropertyValue('text-align')); // Reset everything for later tests. - manager.setTextTypeface('Roboto'); + manager.setTextTypeface(TextTypeface.SANS_SERIF); manager.setTextSize(12); manager.setTextStyles({ [TextStyle.BOLD]: false, @@ -403,7 +401,7 @@ pageNumber: 0, textAttributes: { size: 12, - typeface: 'Roboto', + typeface: TextTypeface.SANS_SERIF, styles: { [TextStyle.BOLD]: false, [TextStyle.ITALIC]: false, @@ -448,13 +446,13 @@ // Any modifications to font are an edit. chrome.test.assertTrue(isVisible(textbox)); - manager.setTextTypeface('Monospace'); + manager.setTextTypeface(TextTypeface.MONOSPACE); await microtasksFinished(); - testAnnotation.textAttributes.typeface = 'Monospace'; + testAnnotation.textAttributes.typeface = TextTypeface.MONOSPACE; startNewAnnotationAndVerifyMessage(); await microtasksFinished(); // Reset expectation. - testAnnotation.textAttributes.typeface = 'Roboto'; + testAnnotation.textAttributes.typeface = TextTypeface.SANS_SERIF; // If all the text is deleted, there is also no commit message. chrome.test.assertTrue(isVisible(textbox));
diff --git a/chrome/test/data/pdf/ink2_text_side_panel_test.ts b/chrome/test/data/pdf/ink2_text_side_panel_test.ts index bb5c20a..7ad6040 100644 --- a/chrome/test/data/pdf/ink2_text_side_panel_test.ts +++ b/chrome/test/data/pdf/ink2_text_side_panel_test.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {AnnotationMode, hexToColor, Ink2Manager, TEXT_COLORS, UserAction} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; +import {AnnotationMode, hexToColor, Ink2Manager, TEXT_COLORS, TextTypeface, UserAction} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; import type {Color} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js'; import {assert} from 'chrome://resources/js/assert.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; @@ -49,7 +49,7 @@ const whenChanged = eventToPromise('attributes-changed', Ink2Manager.getInstance()); - const newValue = 'Serif'; + const newValue = TextTypeface.SERIF; fontSelect.focus(); fontSelect.value = newValue; fontSelect.dispatchEvent(new CustomEvent('change'));
diff --git a/chrome/test/data/web_apps/simple_focus_existing/manifest.json b/chrome/test/data/web_apps/simple_focus_existing/manifest.json index 58b9cba8..eeef4ed 100644 --- a/chrome/test/data/web_apps/simple_focus_existing/manifest.json +++ b/chrome/test/data/web_apps/simple_focus_existing/manifest.json
@@ -15,8 +15,7 @@ "start_url": "index.html", "display": "standalone", "launch_handler": { - "client_mode": "focus-existing", - "client_mode_valid_and_specified": true + "client_mode": "focus-existing" }, "scope": "." }
diff --git a/chrome/test/data/web_apps/simple_navigate_existing/manifest.json b/chrome/test/data/web_apps/simple_navigate_existing/manifest.json index 58acd07..440e53ea 100644 --- a/chrome/test/data/web_apps/simple_navigate_existing/manifest.json +++ b/chrome/test/data/web_apps/simple_navigate_existing/manifest.json
@@ -15,8 +15,7 @@ "start_url": "index.html", "display": "standalone", "launch_handler": { - "client_mode": "navigate-existing", - "client_mode_valid_and_specified": true + "client_mode": "navigate-existing" }, "scope": "." }
diff --git a/chrome/test/data/webui/bookmarks/command_manager_test.ts b/chrome/test/data/webui/bookmarks/command_manager_test.ts index 812f7a7..8dcffb1 100644 --- a/chrome/test/data/webui/bookmarks/command_manager_test.ts +++ b/chrome/test/data/webui/bookmarks/command_manager_test.ts
@@ -4,7 +4,6 @@ import type {BookmarksFolderNodeElement, BookmarksItemElement, BookmarksListElement, SelectFolderAction, SelectItemsAction} from 'chrome://bookmarks/bookmarks.js'; import {BookmarkManagerApiProxyImpl, BookmarksApiProxyImpl, BookmarksCommandManagerElement, Command, createBookmark, DialogFocusManager, getDisplayedList, MenuSource, selectFolder, setDebouncerForTesting} from 'chrome://bookmarks/bookmarks.js'; -import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {isMac} from 'chrome://resources/js/platform.js'; import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {pressAndReleaseKeyOn} from 'chrome://webui-test/keyboard_mock_interactions.js'; @@ -24,10 +23,6 @@ let bookmarkManagerProxy: TestBookmarkManagerApiProxy; setup(function() { - loadTimeData.overrideValues({ - splitViewEnabled: true, - }); - const bulkChildren = []; for (let i = 1; i <= 20; i++) { const id = '3' + i; @@ -314,21 +309,6 @@ assertEquals(20, ids.length); }); - test('"Open in Split View" passes correct args', async function() { - const items = new Set(['141']); - assertTrue(commandManager.canExecute(Command.OPEN_SPLIT_VIEW, items)); - - commandManager.handle(Command.OPEN_SPLIT_VIEW, items); - await microtasksFinished(); - - const [id, {active, split}] = - await bookmarkManagerProxy.whenCalled('openInNewTab'); - - assertEquals('141', id); - assertFalse(active); - assertTrue(split); - }); - test( 'cannot execute "Open in New Tab" on folders with no items', async () => { const items = new Set(['2']); @@ -358,10 +338,6 @@ assertTrue(commandItem[Command.OPEN_INCOGNITO].disabled); assertFalse(commandItem[Command.OPEN_INCOGNITO].hidden); - assertTrue(!!commandItem[Command.OPEN_SPLIT_VIEW]); - assertTrue(commandItem[Command.OPEN_SPLIT_VIEW].disabled); - assertFalse(commandItem[Command.OPEN_SPLIT_VIEW].hidden); - assertTrue(!!commandItem[Command.OPEN_NEW_GROUP]); assertTrue(commandItem[Command.OPEN_NEW_GROUP].disabled); assertFalse(commandItem[Command.OPEN_NEW_GROUP].hidden); @@ -569,10 +545,10 @@ test('double click opens items in foreground tab', async function() { simulateDoubleClick(items[1]!); - const [id, params] = await bookmarkManagerProxy.whenCalled('openInNewTab'); + const [id, active] = await bookmarkManagerProxy.whenCalled('openInNewTab'); assertEquals('12', id); - assertEquals(undefined, params); + assertTrue(active); }); test('shift-double click opens full selection', function() { @@ -623,12 +599,10 @@ // Only the middle-clicked item is opened. simulateMiddleClick(item2); - const [id, {active, split}] = - await bookmarkManagerProxy.whenCalled('openInNewTab'); + const [id, active] = await bookmarkManagerProxy.whenCalled('openInNewTab'); assertEquals('13', id); assertFalse(active); - assertEquals(undefined, split); }); test('middle-click does not open folders', function() { @@ -646,10 +620,10 @@ assertTrue(!!item); simulateMiddleClick(item, {shiftKey: true}); - const [id, params] = await bookmarkManagerProxy.whenCalled('openInNewTab'); + const [id, active] = await bookmarkManagerProxy.whenCalled('openInNewTab'); assertEquals('12', id); - assertEquals(undefined, params); + assertTrue(active); }); test(
diff --git a/chrome/test/data/webui/bookmarks/test_bookmark_manager_api_proxy.ts b/chrome/test/data/webui/bookmarks/test_bookmark_manager_api_proxy.ts index 40f438b..be142f0 100644 --- a/chrome/test/data/webui/bookmarks/test_bookmark_manager_api_proxy.ts +++ b/chrome/test/data/webui/bookmarks/test_bookmark_manager_api_proxy.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import type {BookmarkManagerApiProxy, OpenInNewTabParams} from 'chrome://bookmarks/bookmarks.js'; +import type {BookmarkManagerApiProxy} from 'chrome://bookmarks/bookmarks.js'; import {FakeChromeEvent} from 'chrome://webui-test/fake_chrome_event.js'; import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; @@ -55,8 +55,8 @@ this.methodCalled('openInNewWindow', [idList, incognito]); } - openInNewTab(id: string, params?: OpenInNewTabParams) { - this.methodCalled('openInNewTab', [id, params]); + openInNewTab(id: string, active: boolean) { + this.methodCalled('openInNewTab', [id, active]); } openInNewTabGroup(idList: string[]) {
diff --git a/chrome/test/data/webui/chromeos/settings/os_about_page/test_about_page_browser_proxy.ts b/chrome/test/data/webui/chromeos/settings/os_about_page/test_about_page_browser_proxy.ts index 5861df2..87c3b2dd 100644 --- a/chrome/test/data/webui/chromeos/settings/os_about_page/test_about_page_browser_proxy.ts +++ b/chrome/test/data/webui/chromeos/settings/os_about_page/test_about_page_browser_proxy.ts
@@ -26,6 +26,7 @@ isLts: false, }; private canChangeChannel_ = true; + private canChangeFirmware_ = true; private regulatoryInfo_: RegulatoryInfo|null = null; private tpmFirmwareUpdateStatus_: TpmFirmwareUpdateStatusChangedEvent = { updateAvailable: false, @@ -52,6 +53,7 @@ 'openHelpPage', 'openFeedbackDialog', 'canChangeChannel', + 'canChangeFirmware', 'getChannelInfo', 'getVersionInfo', 'getRegulatoryInfo', @@ -132,6 +134,10 @@ this.canChangeChannel_ = canChangeChannel; } + setCanChangeFirmware(canChangeFirmware: boolean): void { + this.canChangeFirmware_ = canChangeFirmware; + } + setChannels(current: BrowserChannel, target: BrowserChannel): void { this.channelInfo_.currentChannel = current; this.channelInfo_.targetChannel = target; @@ -175,6 +181,11 @@ return Promise.resolve(this.canChangeChannel_); } + canChangeFirmware(): Promise<boolean> { + this.methodCalled('canChangeFirmware'); + return Promise.resolve(this.canChangeFirmware_); + } + checkInternetConnection(): Promise<boolean> { this.methodCalled('checkInternetConnection'); return Promise.resolve(this.hasInternetConnection_);
diff --git a/chrome/test/data/webui/new_tab_footer/app_test.ts b/chrome/test/data/webui/new_tab_footer/app_test.ts index c1daccd..76194bb8 100644 --- a/chrome/test/data/webui/new_tab_footer/app_test.ts +++ b/chrome/test/data/webui/new_tab_footer/app_test.ts
@@ -6,6 +6,7 @@ import type {NewTabFooterAppElement} from 'chrome://newtab-footer/app.js'; import {NewTabFooterDocumentProxy} from 'chrome://newtab-footer/browser_proxy.js'; +import type {ManagementNotice, NewTabFooterDocumentRemote} from 'chrome://newtab-footer/new_tab_footer.mojom-webui.js'; import {NewTabFooterDocumentCallbackRouter, NewTabFooterHandlerRemote} from 'chrome://newtab-footer/new_tab_footer.mojom-webui.js'; import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {TestMock} from 'chrome://webui-test/test_mock.js'; @@ -14,18 +15,22 @@ suite('NewTabFooterAppTest', () => { let element: NewTabFooterAppElement; let handler: TestMock<NewTabFooterHandlerRemote>&NewTabFooterHandlerRemote; + let callbackRouter: NewTabFooterDocumentRemote; setup(() => { document.body.innerHTML = window.trustedTypes!.emptyHTML; handler = TestMock.fromClass(NewTabFooterHandlerRemote); NewTabFooterDocumentProxy.setInstance( handler, new NewTabFooterDocumentCallbackRouter()); + callbackRouter = NewTabFooterDocumentProxy.getInstance() + .callbackRouter.$.bindNewPipeAndPassRemote(); }); async function initializeElement() { element = document.createElement('new-tab-footer-app'); document.body.appendChild(element); await microtasksFinished(); + await handler.whenCalled('updateManagementNotice'); } test('Get extension attibution on initialization', async () => { @@ -43,4 +48,24 @@ assertEquals(attributionLink!.href, 'chrome://extensions/?id=1234'); assertEquals(attributionLink!.innerText, 'foo'); }); + + test('Get management notice on initialization', async () => { + // Arrange. + await initializeElement(); + const managementNotice: + ManagementNotice = {text: 'Managed by your organization'}; + callbackRouter.setManagementNotice(managementNotice); + await callbackRouter.$.flushForTesting(); + + // Assert. + // const managementNoticeContainer = + // element.shadowRoot.querySelector('#managementNoticeContainer'); + // assertTrue(!!managementNoticeContainer); + const managementNoticeText = + element.shadowRoot.querySelector('#managementNoticeText'); + assertTrue(!!managementNoticeText); + + assertEquals( + managementNoticeText.textContent, 'Managed by your organization'); + }); });
diff --git a/chrome/test/data/webui/new_tab_page/app_test.ts b/chrome/test/data/webui/new_tab_page/app_test.ts index 44f7ccda..3f6386f 100644 --- a/chrome/test/data/webui/new_tab_page/app_test.ts +++ b/chrome/test/data/webui/new_tab_page/app_test.ts
@@ -744,44 +744,21 @@ }); test('container is hidden', () => { - const modules = $$(app, 'ntp-modules-v2')!; + const modules = $$(app, 'ntp-modules')!; assertTrue(!!modules); assertStyle(modules, 'display', 'none'); }); test(`clicking records click`, () => { // Act. - $$<HTMLElement>(app, 'ntp-modules-v2')!.click(); + $$<HTMLElement>(app, 'ntp-modules')!.click(); // Assert. assertEquals(1, metrics.count('NewTabPage.Click')); assertEquals(1, metrics.count('NewTabPage.Click', NtpElement.MODULE)); }); - modulesCommonTests('ntp-modules-v2'); - }); - - suite('v2 modules', () => { - suiteSetup(() => { - loadTimeData.overrideValues({ - modulesEnabled: true, - }); - }); - - test('container is hidden', () => { - const modules = $$(app, 'ntp-modules-v2')!; - assertTrue(!!modules); - assertStyle(modules, 'display', 'none'); - }); - - test(`clicking records click`, () => { - // Act. - $$<HTMLElement>(app, 'ntp-modules-v2')!.click(); - - // Assert. - assertEquals(1, metrics.count('NewTabPage.Click')); - assertEquals(1, metrics.count('NewTabPage.Click', NtpElement.MODULE)); - }); + modulesCommonTests('ntp-modules'); }); suite('CounterfactualModules', () => {
diff --git a/chrome/test/data/webui/new_tab_page/modules/module_wrapper_test.ts b/chrome/test/data/webui/new_tab_page/modules/module_wrapper_test.ts index f40a4ef..87416ae 100644 --- a/chrome/test/data/webui/new_tab_page/modules/module_wrapper_test.ts +++ b/chrome/test/data/webui/new_tab_page/modules/module_wrapper_test.ts
@@ -3,10 +3,11 @@ // found in the LICENSE file. import {ModuleDescriptor, ModuleWrapperElement} from 'chrome://new-tab-page/lazy_load.js'; +import type {ModuleInstance} from 'chrome://new-tab-page/lazy_load.js'; import {NewTabPageProxy, WindowProxy} from 'chrome://new-tab-page/new_tab_page.js'; import {PageCallbackRouter, PageHandlerRemote} from 'chrome://new-tab-page/new_tab_page.mojom-webui.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {assertDeepEquals, assertEquals, assertThrows} from 'chrome://webui-test/chai_assert.js'; +import {assertDeepEquals, assertEquals} from 'chrome://webui-test/chai_assert.js'; import type {MetricsTracker} from 'chrome://webui-test/metrics_test_support.js'; import {fakeMetricsPrivate} from 'chrome://webui-test/metrics_test_support.js'; import type {TestMock} from 'chrome://webui-test/test_mock.js'; @@ -16,7 +17,6 @@ suite('NewTabPageModulesModuleWrapperTest', () => { let handler: TestMock<PageHandlerRemote>; - let moduleWrapper: ModuleWrapperElement; let metrics: MetricsTracker; let windowProxy: TestMock<WindowProxy>; @@ -31,56 +31,51 @@ NewTabPageProxy.setInstance(mock, new PageCallbackRouter())); metrics = fakeMetricsPrivate(); windowProxy = installMock(WindowProxy); - moduleWrapper = new ModuleWrapperElement(); - document.body.appendChild(moduleWrapper); }); + function createModuleWrapper(module: ModuleInstance): ModuleWrapperElement { + const moduleWrapper: ModuleWrapperElement = new ModuleWrapperElement(); + moduleWrapper.module = module; + return moduleWrapper; + } + test('renders module descriptor', async () => { // Arrange. const moduleElement = createElement(); moduleElement.style.height = '100px'; + const moduleWrapper = createModuleWrapper({ + descriptor: new ModuleDescriptor('foo', initNullModule), + element: moduleElement, + initialized: false, + impressed: false, + }); const detectedImpression = eventToPromise('detect-impression', moduleWrapper); + document.body.appendChild(moduleWrapper); windowProxy.setResultFor('now', 123); // Act. - moduleWrapper.module = { - descriptor: new ModuleDescriptor('foo', initNullModule), - element: moduleElement, - }; await detectedImpression; // Assert. assertEquals(100, moduleWrapper.$.moduleElement.offsetHeight); - assertDeepEquals(moduleElement, moduleWrapper.$.moduleElement.children[0]); + assertDeepEquals(moduleElement, moduleWrapper.querySelector('div')); assertEquals(1, metrics.count('NewTabPage.Modules.Impression')); assertEquals(1, metrics.count('NewTabPage.Modules.Impression.foo')); assertEquals(1, metrics.count('NewTabPage.Modules.Impression', 123)); assertEquals(1, metrics.count('NewTabPage.Modules.Impression.foo', 123)); }); - - test('descriptor can only be set once', () => { - const moduleElement = createElement(); - moduleWrapper.module = { - descriptor: new ModuleDescriptor('foo', initNullModule), - element: moduleElement, - }; - assertThrows(() => { - moduleWrapper.module = { - descriptor: new ModuleDescriptor('foo', initNullModule), - element: moduleElement, - }; - }); - }); - test('receiving usage events records usage', () => { // Arrange. const moduleElement = createElement(); - moduleWrapper.module = { + const moduleWrapper = createModuleWrapper({ descriptor: new ModuleDescriptor('foo', initNullModule), element: moduleElement, - }; + initialized: false, + impressed: false, + }); + document.body.appendChild(moduleWrapper); // Act. moduleElement.dispatchEvent(new Event('usage', {bubbles: true})); @@ -90,38 +85,38 @@ assertEquals(1, metrics.count('NewTabPage.Modules.Usage.foo')); }); - suite('Redesigned modules', () => { - suiteSetup(() => { - loadTimeData.overrideValues({modulesRedesignedEnabled: true}); - }); - - ['usage', 'menu-button-click'].forEach((eventName: string) => { - test( - `module ${eventName} event triggers onModuleUsed + ['usage', 'menu-button-click'].forEach((eventName: string) => { + test( + `module ${eventName} event triggers onModuleUsed function`, - () => { - const moduleId = 'foo'; - const moduleElement = createElement(); - moduleWrapper.module = { - descriptor: new ModuleDescriptor(moduleId, initNullModule), - element: moduleElement, - }; - - moduleElement.dispatchEvent(new Event(eventName, {bubbles: true})); - - assertEquals(1, handler.getCallCount('onModuleUsed')); - assertEquals(moduleId, handler.getArgs('onModuleUsed')[0]); + () => { + const moduleId = 'foo'; + const moduleElement = createElement(); + const moduleWrapper = createModuleWrapper({ + descriptor: new ModuleDescriptor(moduleId, initNullModule), + element: moduleElement, + initialized: false, + impressed: false, }); - }); + document.body.appendChild(moduleWrapper); + + moduleElement.dispatchEvent(new Event(eventName, {bubbles: true})); + + assertEquals(1, handler.getCallCount('onModuleUsed')); + assertEquals(moduleId, handler.getArgs('onModuleUsed')[0]); + }); }); test('clicking info button records click and module id', () => { // Arrange. const moduleElement = createElement(); - moduleWrapper.module = { + const moduleWrapper = createModuleWrapper({ descriptor: new ModuleDescriptor('foo', initNullModule), element: moduleElement, - }; + initialized: false, + impressed: false, + }); + document.body.appendChild(moduleWrapper); // Act. moduleElement.dispatchEvent(new Event('info-button-click'));
diff --git a/chrome/test/data/webui/new_tab_page/modules/v2/modules_test.ts b/chrome/test/data/webui/new_tab_page/modules/v2/modules_test.ts index 2ca228d..0b545821 100644 --- a/chrome/test/data/webui/new_tab_page/modules/v2/modules_test.ts +++ b/chrome/test/data/webui/new_tab_page/modules/v2/modules_test.ts
@@ -3,16 +3,17 @@ // found in the LICENSE file. import type {Module, ModuleWrapperElement, NamedWidth} from 'chrome://new-tab-page/lazy_load.js'; -import {ModuleDescriptor, ModuleRegistry, ModulesV2Element, SUPPORTED_MODULE_WIDTHS} from 'chrome://new-tab-page/lazy_load.js'; +import {ModuleDescriptor, ModuleRegistry, ModulesElement, SUPPORTED_MODULE_WIDTHS} from 'chrome://new-tab-page/lazy_load.js'; import {NewTabPageProxy} from 'chrome://new-tab-page/new_tab_page.js'; import type {PageRemote} from 'chrome://new-tab-page/new_tab_page.mojom-webui.js'; import {PageCallbackRouter, PageHandlerRemote} from 'chrome://new-tab-page/new_tab_page.mojom-webui.js'; +import {assert} from 'chrome://resources/js/assert.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import type {MetricsTracker} from 'chrome://webui-test/metrics_test_support.js'; import {fakeMetricsPrivate} from 'chrome://webui-test/metrics_test_support.js'; -import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; import type {TestMock} from 'chrome://webui-test/test_mock.js'; +import {microtasksFinished} from 'chrome://webui-test/test_util.js'; import {assertNotStyle, assertStyle, createElement, initNullModule, installMock} from '../../test_support.js'; @@ -45,7 +46,7 @@ async function createModulesElement( modules: Module[], enabled: boolean, width: number, - disabledModuleIds: string[] = []): Promise<ModulesV2Element> { + disabledModuleIds: string[] = []): Promise<ModulesElement> { if (!enabled) { assertTrue( modules.length === 0, @@ -59,10 +60,11 @@ }); moduleRegistry.setResultFor('initializeModulesHavingIds', modulesPromise); - const element = new ModulesV2Element(); + const element = new ModulesElement(); document.body.style.width = `${width}px`; document.body.appendChild(element); await modulesPromise; + await microtasksFinished(); return element; } @@ -196,9 +198,8 @@ }, ], true, scenario.width); - await waitAfterNextRender(modulesElement); - const wrappers = modulesElement.shadowRoot!.querySelectorAll( + const wrappers = modulesElement.shadowRoot.querySelectorAll( 'ntp-module-wrapper:not([hidden])'); assertEquals(scenario.count, wrappers.length); @@ -206,7 +207,7 @@ scenario.rows.forEach((expectedRowWidths, i) => { expectedRowWidths.forEach((expectedWidth, j) => { const wrapper = wrappers[index]! as ModuleWrapperElement; - const instance = wrapper.$.moduleElement.lastChild! as HTMLElement; + const instance = wrapper.lastChild! as HTMLElement; assertEquals(expectedWidth.name, instance.getAttribute('format')); assertEquals( expectedWidth.value, wrapper.clientWidth, @@ -226,12 +227,11 @@ {id: barDescriptor.id, name: barDescriptor.id}, ], }); + const modulesElement = await createModulesElement([], false, SAMPLE_SCREEN_WIDTH); - await waitAfterNextRender(modulesElement); - const moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); + modulesElement.shadowRoot.querySelectorAll('ntp-module-wrapper'); assertEquals(0, moduleWrappers.length); assertEquals(1, metrics.count('NewTabPage.Modules.LoadedModulesCount', 0)); assertEquals(1, metrics.count('NewTabPage.Modules.InstanceCount', 0)); @@ -264,7 +264,7 @@ true, SAMPLE_SCREEN_WIDTH); const moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); + modulesElement.shadowRoot.querySelectorAll('ntp-module-wrapper'); assertEquals(4, moduleWrappers.length); assertEquals(1, metrics.count('NewTabPage.Modules.LoadedModulesCount')); assertEquals(1, metrics.count('NewTabPage.Modules.InstanceCount', 4)); @@ -282,53 +282,6 @@ 0, metrics.count('NewTabPage.Modules.LoadedWith.bar', 'bar')); }); - test('modules maxium instance count works correctly', async () => { - const SAMPLE_MAX_MODULE_INSTANCE_COUNT = 2; - loadTimeData.overrideValues({ - modulesMaxColumnCount: MAX_COLUMN_COUNT, - multipleLoadedModulesMaxModuleInstanceCount: - SAMPLE_MAX_MODULE_INSTANCE_COUNT, - }); - - const fooDescriptor = new ModuleDescriptor('foo', initNullModule); - const barDescriptor = new ModuleDescriptor('bar', initNullModule); - const descriptors = [ - fooDescriptor, - barDescriptor, - ]; - const modulesElement = await createModulesElementFromDescriptors( - descriptors, SAMPLE_MAX_MODULE_INSTANCE_COUNT + 1); - const moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); - assertEquals( - descriptors.length * SAMPLE_MAX_MODULE_INSTANCE_COUNT, - moduleWrappers.length); - }); - - test('modules maxium instance capped to maximum column count', async () => { - const SAMPLE_MAX_COLUMN_COUNT = 3; - const SAMPLE_MAX_MODULE_INSTANCE_COUNT = 3; - loadTimeData.overrideValues({ - modulesMaxColumnCount: SAMPLE_MAX_COLUMN_COUNT, - multipleLoadedModulesMaxModuleInstanceCount: - SAMPLE_MAX_MODULE_INSTANCE_COUNT, - }); - - const fooDescriptor = new ModuleDescriptor('foo', initNullModule); - const barDescriptor = new ModuleDescriptor('bar', initNullModule); - const bazDescriptor = new ModuleDescriptor('baz', initNullModule); - const descriptors = [ - fooDescriptor, - barDescriptor, - bazDescriptor, - ]; - const modulesElement = await createModulesElementFromDescriptors( - descriptors, SAMPLE_MAX_MODULE_INSTANCE_COUNT); - const moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); - assertEquals(SAMPLE_MAX_COLUMN_COUNT, moduleWrappers.length); - }); - enum UndoStrategy { BUTTON_ACTIVATION = 'button activation', SHORTCUT_KEY = 'shortcut key', @@ -356,26 +309,26 @@ true, SAMPLE_SCREEN_WIDTH); // Assert. - const moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll( - 'ntp-module-wrapper'); + const moduleWrappers = modulesElement.shadowRoot.querySelectorAll( + 'ntp-module-wrapper'); assertEquals(1, moduleWrappers.length); assertNotStyle(moduleWrappers[0]!, 'display', 'none'); assertFalse(modulesElement.$.undoToast.open); // Act. let restoreCalled = false; - moduleWrappers[0]!.dispatchEvent( - new CustomEvent('disable-module', { - bubbles: true, - composed: true, - detail: { - message: 'Foo', - restoreCallback: () => { - restoreCalled = true; - }, - }, - })); + const moduleElement = + moduleWrappers[0]!.lastChild! as HTMLElement; + moduleElement.dispatchEvent(new CustomEvent('disable-module', { + bubbles: true, + composed: true, + detail: { + message: 'Foo', + restoreCallback: () => { + restoreCalled = true; + }, + }, + })); // Assert. assertDeepEquals( @@ -399,10 +352,10 @@ assertFalse(restoreCalled); // Act. - await waitAfterNextRender(modulesElement); + await microtasksFinished(); if (undoStrategy === UndoStrategy.BUTTON_ACTIVATION) { const undoButton = - modulesElement.shadowRoot!.querySelector<HTMLElement>( + modulesElement.shadowRoot.querySelector<HTMLElement>( '#undoButton'); assertTrue(!!undoButton); undoButton.click(); @@ -450,7 +403,8 @@ }], true, SAMPLE_SCREEN_WIDTH); - let moduleWrappers = modulesElement.shadowRoot!.querySelectorAll( + assert(modulesElement.shadowRoot); + let moduleWrappers = modulesElement.shadowRoot.querySelectorAll( 'ntp-module-wrapper'); assertEquals(1, moduleWrappers.length); assertFalse(modulesElement.$.undoToast.open); @@ -467,10 +421,11 @@ }, }, })); + await microtasksFinished(); assertEquals( 0, - modulesElement.shadowRoot! + modulesElement.shadowRoot .querySelectorAll('ntp-module-wrapper') .length); assertTrue(modulesElement.$.undoToast.open); @@ -478,10 +433,11 @@ assertEquals(1, handler.getCallCount('onDismissModule')); assertEquals(moduleId, handler.getArgs('onDismissModule')[0]); - await waitAfterNextRender(modulesElement); + await microtasksFinished(); if (undoStrategy === UndoStrategy.BUTTON_ACTIVATION) { + assert(modulesElement.shadowRoot); const undoButton = - modulesElement.shadowRoot!.querySelector<HTMLElement>( + modulesElement.shadowRoot.querySelector<HTMLElement>( '#undoButton'); assertTrue(!!undoButton); undoButton.click(); @@ -492,7 +448,8 @@ })); } - moduleWrappers = modulesElement.shadowRoot!.querySelectorAll( + await microtasksFinished(); + moduleWrappers = modulesElement.shadowRoot.querySelectorAll( 'ntp-module-wrapper'); assertEquals(1, moduleWrappers.length); assertFalse(modulesElement.$.undoToast.open); @@ -512,13 +469,13 @@ {id: fooDescriptor.id, name: fooDescriptor.id}, ], }); - const modulesElement = await createModulesElement( + await createModulesElement( [{ descriptor: fooDescriptor, elements: [createElement()], }], true, SAMPLE_SCREEN_WIDTH); - await waitAfterNextRender(modulesElement); + await microtasksFinished(); // Act. window.dispatchEvent(new KeyboardEvent('keydown', { @@ -537,7 +494,7 @@ scenario.rows.forEach((expectedRowWidths, i) => { expectedRowWidths.forEach((expectedWidth, j) => { const wrapper = moduleWrappers[index]!; - const instance = wrapper.$.moduleElement.lastChild! as HTMLElement; + const instance = wrapper.lastChild! as HTMLElement; assertEquals(expectedWidth.name, instance.getAttribute('format')); assertEquals( expectedWidth.value, wrapper.clientWidth, @@ -612,30 +569,31 @@ }); const modulesElement = await createModulesElement(modules, true, SAMPLE_SCREEN_WIDTH); - await waitAfterNextRender(modulesElement); + await microtasksFinished(); const moduleWrappers = Array.from( - modulesElement.shadowRoot!.querySelectorAll<HTMLElement>( + modulesElement.shadowRoot.querySelectorAll<HTMLElement>( 'ntp-module-wrapper')) as ModuleWrapperElement[]; assertContainerLayout(moduleWrappers, layoutChangeScenario.before); - moduleWrappers[0]!.dispatchEvent(new CustomEvent('disable-module', { - bubbles: true, - composed: true, - detail: { - message: 'Foo', - }, - })); + moduleWrappers[0]!.lastChild!.dispatchEvent( + new CustomEvent('disable-module', { + bubbles: true, + composed: true, + detail: { + message: 'Foo', + }, + })); assertDeepEquals( ['foo', true], handler.getArgs('setModuleDisabled')[0]); callbackRouterRemote.setDisabledModules(false, ['foo']); await callbackRouterRemote.$.flushForTesting(); - await waitAfterNextRender(modulesElement); + await microtasksFinished(); assertContainerLayout( Array.from( - modulesElement.shadowRoot!.querySelectorAll<HTMLElement>( + modulesElement.shadowRoot.querySelectorAll<HTMLElement>( 'ntp-module-wrapper:not([hidden])')) as ModuleWrapperElement[], layoutChangeScenario.after); @@ -704,11 +662,12 @@ }); const modulesElement = await createModulesElement(modules, true, SAMPLE_SCREEN_WIDTH); - await waitAfterNextRender(modulesElement); + await microtasksFinished(); + assert(modulesElement.shadowRoot); const moduleWrappers = Array.from( - modulesElement.shadowRoot!.querySelectorAll<HTMLElement>( + modulesElement.shadowRoot.querySelectorAll<HTMLElement>( 'ntp-module-wrapper')) as ModuleWrapperElement[]; assertContainerLayout(moduleWrappers, layoutChangeScenario.before); @@ -725,11 +684,11 @@ }, })); assertFalse(restoreCalled); - await waitAfterNextRender(modulesElement); + await microtasksFinished(); assertContainerLayout( Array.from( - modulesElement.shadowRoot!.querySelectorAll<HTMLElement>( + modulesElement.shadowRoot.querySelectorAll<HTMLElement>( 'ntp-module-wrapper')) as ModuleWrapperElement[], layoutChangeScenario.after); }); @@ -773,22 +732,24 @@ const modulesElement = await createModulesElement( [], true, SAMPLE_SCREEN_WIDTH, /*disabledModuleIds=*/[fooDescriptor.id]); - await waitAfterNextRender(modulesElement); + await microtasksFinished(); let moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); + modulesElement.shadowRoot.querySelectorAll('ntp-module-wrapper'); assertEquals(0, moduleWrappers.length); + // Mock required data for loading foo module. const fooModulePromise = getModulePromise(fooDescriptor); moduleRegistry.setResultFor('initializeModuleById', fooModulePromise); - // Act - Remove foo module from disabled modules list. + // Act - Remove foo module from disabled modules list and trigger a + // reload operation. callbackRouterRemote.setDisabledModules(false, []); + callbackRouterRemote.setModulesLoadable(); await fooModulePromise; - await waitAfterNextRender(modulesElement); + await microtasksFinished(); - // Assert - Foo module loaded. moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); + modulesElement.shadowRoot.querySelectorAll('ntp-module-wrapper'); assertEquals(1, moduleWrappers.length); assertEquals( fooDescriptor.id, @@ -799,46 +760,43 @@ 1, metrics.count('NewTabPage.Modules.ReloadedModulesCount', 1)); }); - test('enabling module while container is being loaded', async () => { - // Arrange. - loadTimeData.overrideValues({ - // Prevent initial module loading to ensure module enabling during - // container load is tested. - waitToLoadModules: true, - }); - const fooDescriptor = new ModuleDescriptor('foo', initNullModule); - const barDescriptor = new ModuleDescriptor('bar', initNullModule); - const bazDescriptor = new ModuleDescriptor('baz', initNullModule); - // Initial state: foo and bar enabled, baz disabled. - const enabledDescriptors = [fooDescriptor, barDescriptor]; - const modulesElement = await createModulesElementFromDescriptors( - enabledDescriptors, /*instanceCount=*/ 1, [bazDescriptor]); - const bazReloadPromise = getModulePromise(bazDescriptor); - moduleRegistry.setResultFor('initializeModuleById', bazReloadPromise); + test( + 'enabling module after container has loaded with some modules', + async () => { + // Arrange. + loadTimeData.overrideValues({ + modulesReloadable: true, + // Prevent initial module loading to ensure module enabling during + // container load is tested. + waitToLoadModules: true, + }); + const fooDescriptor = new ModuleDescriptor('foo', initNullModule); + const barDescriptor = new ModuleDescriptor('bar', initNullModule); + const bazDescriptor = new ModuleDescriptor('baz', initNullModule); + // Initial state: foo and bar enabled, baz disabled. + const enabledDescriptors = [fooDescriptor, barDescriptor]; + const modulesElement = await createModulesElementFromDescriptors( + enabledDescriptors, /*instanceCount=*/ 1, [bazDescriptor]); + callbackRouterRemote.setModulesLoadable(); + await microtasksFinished(); - // Act - Start module load, then enable baz by clearing the disabled - // modules list. - callbackRouterRemote.setModulesLoadable(); - callbackRouterRemote.setDisabledModules(false, []); - callbackRouterRemote.$.flushForTesting(); + const bazReloadPromise = getModulePromise(bazDescriptor); + moduleRegistry.setResultFor( + 'initializeModuleById', bazReloadPromise); - await bazReloadPromise; - await waitAfterNextRender(modulesElement); + // Act - Enable baz by clearing the disabled modules list and + // trigger a reload operation. + callbackRouterRemote.setDisabledModules(false, []); + callbackRouterRemote.setModulesLoadable(); + await bazReloadPromise; + await microtasksFinished(); - // Assert. - const moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); - assertEquals(3, moduleWrappers.length); - assertEquals( - fooDescriptor.id, - (moduleWrappers[0] as ModuleWrapperElement).module.descriptor.id); - assertEquals( - barDescriptor.id, - (moduleWrappers[1] as ModuleWrapperElement).module.descriptor.id); - assertEquals( - bazDescriptor.id, - (moduleWrappers[2] as ModuleWrapperElement).module.descriptor.id); - }); + // Assert. + assert(modulesElement.shadowRoot); + const moduleWrappers = modulesElement.shadowRoot.querySelectorAll( + 'ntp-module-wrapper'); + assertEquals(3, moduleWrappers.length); + }); test('reloads module container after initial load', async () => { // Arrange. @@ -851,8 +809,9 @@ enabledDescriptors, /*instanceCount=*/ 1, [barDescriptor, bazDescriptor]); // Ensure only foo module loaded. + assert(modulesElement.shadowRoot); let moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); + modulesElement.shadowRoot.querySelectorAll('ntp-module-wrapper'); assertEquals(1, moduleWrappers.length); assertEquals( fooDescriptor.id, @@ -872,14 +831,15 @@ })); // Act - Enable the bar module by removing it from the disabled modules - // list. + // list and trigger a reload operation. callbackRouterRemote.setDisabledModules(false, [bazDescriptor.id]); + callbackRouterRemote.setModulesLoadable(); await barModulePromise; - await waitAfterNextRender(modulesElement); + await microtasksFinished(); // Assert. moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); + modulesElement.shadowRoot.querySelectorAll('ntp-module-wrapper'); assertEquals(2, moduleWrappers.length); // Ensure the 'foo' module loads last, as it was not included in the // module order returned by |getModulesOrder()|. @@ -910,12 +870,15 @@ const barDescriptor = new ModuleDescriptor('bar', initNullModule); // Initial state: foo enabled, bar disabled. const modulesElement = await createModulesElementFromDescriptors( - /*enabledDescriptors=*/[fooDescriptor], /*instanceCount=*/ 1, + /*enabledDescriptors=*/[fooDescriptor], + /*instanceCount=*/ 1, /*disabledDescriptors=*/[barDescriptor]); // Ensure foo module shows. - let moduleWrappers = modulesElement.shadowRoot!.querySelectorAll( + assert(modulesElement.shadowRoot); + let moduleWrappers = modulesElement.shadowRoot.querySelectorAll( 'ntp-module-wrapper'); assertEquals(1, moduleWrappers.length); + let fooModule = moduleWrappers[0] as ModuleWrapperElement; assertEquals(fooDescriptor.id, fooModule.module.descriptor.id); assertNotStyle(fooModule, 'display', 'none'); @@ -935,7 +898,7 @@ await callbackRouterRemote.$.flushForTesting(); // Assert - Foo module shows and bar module never loaded. - moduleWrappers = modulesElement.shadowRoot!.querySelectorAll( + moduleWrappers = modulesElement.shadowRoot.querySelectorAll( 'ntp-module-wrapper'); assertEquals(1, moduleWrappers.length); fooModule = moduleWrappers[0] as ModuleWrapperElement; @@ -951,8 +914,9 @@ const modulesElement = await createModulesElementFromDescriptors( [fooDescriptor], /*instanceCount=*/ 1, [barDescriptor]); // Ensure only foo module loaded. + assert(modulesElement.shadowRoot); let moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); + modulesElement.shadowRoot.querySelectorAll('ntp-module-wrapper'); assertEquals(1, moduleWrappers.length); assertEquals( fooDescriptor.id, @@ -962,18 +926,20 @@ moduleRegistry.setResultFor('initializeModuleById', barModulePromise); // Set the module order, to be verified later. handler.setResultFor( - 'getModulesOrder', Promise.resolve({moduleIds: []})); + 'getModulesOrder', + Promise.resolve({moduleIds: [fooDescriptor.id, barDescriptor.id]})); // Act - Clear the disabled modules list multiple times. callbackRouterRemote.setDisabledModules(false, []); callbackRouterRemote.setDisabledModules(false, []); callbackRouterRemote.setDisabledModules(false, []); + callbackRouterRemote.setModulesLoadable(); await barModulePromise; - await flushTasks(); + await microtasksFinished(); // Assert - Ensure only one instance of the bar module populated. moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); + modulesElement.shadowRoot.querySelectorAll('ntp-module-wrapper'); assertEquals(2, moduleWrappers.length); assertEquals( fooDescriptor.id, @@ -1001,7 +967,7 @@ }], true, SAMPLE_SCREEN_WIDTH, /*disabledModuleIds=*/[barDescriptor.id]); - await waitAfterNextRender(modulesElement); + await microtasksFinished(); const barReloadPromise = getModulePromise(barDescriptor); moduleRegistry.setResultFor( 'initializeModuleById', barReloadPromise); @@ -1010,10 +976,10 @@ // modules list. callbackRouterRemote.setDisabledModules(false, []); await barReloadPromise; - await waitAfterNextRender(modulesElement); + await microtasksFinished(); // Assert - Foo module shows and bar module never loaded. - const moduleWrappers = modulesElement.shadowRoot!.querySelectorAll( + const moduleWrappers = modulesElement.shadowRoot.querySelectorAll( 'ntp-module-wrapper'); assertEquals(1, moduleWrappers.length); const fooModule = moduleWrappers[0] as ModuleWrapperElement; @@ -1033,11 +999,12 @@ // Act. const modulesElement = await createModulesElementFromDescriptors( /*enabledDescriptors=*/[fooDescriptor]); - await waitAfterNextRender(modulesElement); + await microtasksFinished(); // Assert. + assert(modulesElement.shadowRoot); const moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); + modulesElement.shadowRoot.querySelectorAll('ntp-module-wrapper'); if (waitToLoadModules) { assertEquals(0, moduleWrappers.length); } else { @@ -1057,19 +1024,20 @@ const fooDescriptor = new ModuleDescriptor('foo', initNullModule); const modulesElement = await createModulesElementFromDescriptors( /*enabledDescriptors=*/[fooDescriptor]); - await waitAfterNextRender(modulesElement); + await microtasksFinished(); + assert(modulesElement.shadowRoot); let moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); + modulesElement.shadowRoot.querySelectorAll('ntp-module-wrapper'); assertEquals(0, moduleWrappers.length); // Act. callbackRouterRemote.setModulesLoadable(); await callbackRouterRemote.$.flushForTesting(); - await waitAfterNextRender(modulesElement); + await microtasksFinished(); // Assert. moduleWrappers = - modulesElement.shadowRoot!.querySelectorAll('ntp-module-wrapper'); + modulesElement.shadowRoot.querySelectorAll('ntp-module-wrapper'); assertEquals(1, moduleWrappers.length); const fooModule = moduleWrappers[0] as ModuleWrapperElement; assertEquals(fooDescriptor.id, fooModule.module.descriptor.id);
diff --git a/chrome/test/data/webui/print_preview/destination_dialog_interactive_test.ts b/chrome/test/data/webui/print_preview/destination_dialog_interactive_test.ts index 05f869c..d325475 100644 --- a/chrome/test/data/webui/print_preview/destination_dialog_interactive_test.ts +++ b/chrome/test/data/webui/print_preview/destination_dialog_interactive_test.ts
@@ -6,7 +6,6 @@ import {NativeLayerImpl, State} from 'chrome://print/print_preview.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {keyDownOn} from 'chrome://webui-test/keyboard_mock_interactions.js'; -import {fakeDataBind} from 'chrome://webui-test/polymer_test_util.js'; import {eventToPromise} from 'chrome://webui-test/test_util.js'; import {NativeLayerStub} from './native_layer_stub.js'; @@ -34,10 +33,8 @@ // Create destination settings, so that the user manager is created. const destinationSettings = document.createElement('print-preview-destination-settings'); - destinationSettings.settings = model.settings; destinationSettings.state = State.READY; destinationSettings.disabled = false; - fakeDataBind(model, destinationSettings, 'settings'); document.body.appendChild(destinationSettings); // Initialize
diff --git a/chrome/test/data/webui/print_preview/destination_select_test.ts b/chrome/test/data/webui/print_preview/destination_select_test.ts index ba507117..c441e2e 100644 --- a/chrome/test/data/webui/print_preview/destination_select_test.ts +++ b/chrome/test/data/webui/print_preview/destination_select_test.ts
@@ -4,8 +4,8 @@ import type {PrintPreviewDestinationSelectElement} from 'chrome://print/print_preview.js'; import {Destination, DestinationOrigin, getSelectDropdownBackground, IconsetMap} from 'chrome://print/print_preview.js'; -import {assertEquals} from 'chrome://webui-test/chai_assert.js'; -import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; +import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; import {selectOption} from './print_preview_test_utils.js'; @@ -71,4 +71,28 @@ compareIcon(selectEl, enterpriseIcon); }); }); + + test('ShowsSelectedDestination', async function() { + const select = destinationSelect.shadowRoot!.querySelector('select'); + assertTrue(!!select); + + const destination = recentDestinationList[0]!; + destinationSelect.loaded = true; + destinationSelect.destination = destination; + destinationSelect.updateDestination(); + await flushTasks(); + + assertEquals(destination.key, select.value); + assertEquals(destination.key, destinationSelect.selectedValue); + + const newDestination = + new Destination('ID2', DestinationOrigin.LOCAL, 'Two'); + destinationSelect.recentDestinationList = [newDestination]; + destinationSelect.destination = newDestination; + destinationSelect.updateDestination(); + await flushTasks(); + + assertEquals(newDestination.key, select.value); + assertEquals(newDestination.key, destinationSelect.selectedValue); + }); });
diff --git a/chrome/test/data/webui/print_preview/destination_settings_test.ts b/chrome/test/data/webui/print_preview/destination_settings_test.ts index 79acd9c..329cd37 100644 --- a/chrome/test/data/webui/print_preview/destination_settings_test.ts +++ b/chrome/test/data/webui/print_preview/destination_settings_test.ts
@@ -2,30 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'chrome://print/print_preview.js'; + import type {LocalDestinationInfo, PrintPreviewDestinationSettingsElement, RecentDestination} from 'chrome://print/print_preview.js'; import {Destination, DestinationErrorType, DestinationOrigin, DestinationState, DestinationStoreEventType, Error, GooglePromotedDestinationId, makeRecentDestination, NativeLayerImpl, NUM_PERSISTED_DESTINATIONS, State} from 'chrome://print/print_preview.js'; import {assert} from 'chrome://resources/js/assert.js'; -import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; -import {fakeDataBind, waitBeforeNextRender} from 'chrome://webui-test/polymer_test_util.js'; -import {eventToPromise} from 'chrome://webui-test/test_util.js'; +import {eventToPromise, microtasksFinished} from 'chrome://webui-test/test_util.js'; import {NativeLayerStub} from './native_layer_stub.js'; import {getDestinations, getSaveAsPdfDestination, setupTestListenerElement} from './print_preview_test_utils.js'; suite('DestinationSettingsTest', function() { let destinationSettings: PrintPreviewDestinationSettingsElement; - let nativeLayer: NativeLayerStub; - let recentDestinations: RecentDestination[] = []; - let localDestinations: LocalDestinationInfo[] = []; - let destinations: Destination[] = []; - const extraDestinations: Destination[] = []; - let pdfPrinterDisabled: boolean = false; suiteSetup(function() { @@ -54,10 +48,8 @@ destinationSettings = document.createElement('print-preview-destination-settings'); - destinationSettings.settings = model.settings; destinationSettings.state = State.NOT_READY; destinationSettings.disabled = true; - fakeDataBind(model, destinationSettings, 'settings'); document.body.appendChild(destinationSettings); }); @@ -81,20 +73,23 @@ DestinationStoreEventType .SELECTED_DESTINATION_CAPABILITIES_READY, destinationSettings.getDestinationStoreForTest()) - .then(() => { + .then(async () => { // The capabilities ready event results in |destinationState| // changing to SELECTED, which enables and shows the dropdown even // though |state| has not yet transitioned to READY. This is to // prevent brief losses of focus when the destination changes. + await microtasksFinished(); assertFalse(dropdown.disabled); assertTrue(dropdown.loaded); destinationSettings.state = State.READY; destinationSettings.disabled = false; + await microtasksFinished(); // Simulate setting a setting to an invalid value. Dropdown is // disabled due to validation error on another control. destinationSettings.state = State.ERROR; destinationSettings.disabled = true; + await microtasksFinished(); assertTrue(dropdown.disabled); // Simulate the user fixing the validation error, and then @@ -102,17 +97,19 @@ // user can fix the error. destinationSettings.state = State.READY; destinationSettings.disabled = false; + await microtasksFinished(); destinationSettings.getDestinationStoreForTest().dispatchEvent( new CustomEvent( DestinationStoreEventType.ERROR, {detail: DestinationErrorType.INVALID})); - flush(); + await microtasksFinished(); assertEquals( DestinationState.ERROR, destinationSettings.destinationState); assertEquals(Error.INVALID_PRINTER, destinationSettings.error); destinationSettings.state = State.ERROR; destinationSettings.disabled = true; + await microtasksFinished(); assertFalse(dropdown.disabled); // Simulate the user having no printers. @@ -120,13 +117,14 @@ new CustomEvent( DestinationStoreEventType.ERROR, {detail: DestinationErrorType.NO_DESTINATIONS})); - flush(); + await microtasksFinished(); assertEquals( DestinationState.ERROR, destinationSettings.destinationState); assertEquals(Error.NO_DESTINATIONS, destinationSettings.error); destinationSettings.state = State.FATAL_ERROR; destinationSettings.disabled = true; + await microtasksFinished(); assertTrue(dropdown.disabled); }); }); @@ -139,7 +137,11 @@ * Initializes the destination store and destination settings using * |destinations| and |recentDestinations|. */ - function initialize() { + function initialize(): Promise<void> { + const whenCapabilitiesSet = eventToPromise( + DestinationStoreEventType.SELECTED_DESTINATION_CAPABILITIES_READY, + destinationSettings.getDestinationStoreForTest()); + // Initialize destination settings. destinationSettings.setSetting('recentDestinations', recentDestinations); destinationSettings.init( @@ -147,6 +149,9 @@ '' /* serializedDefaultDestinationSelectionRulesStr */); destinationSettings.state = State.READY; destinationSettings.disabled = false; + + // Only resolved when `pdfPrinterDisabled` is false. + return whenCapabilitiesSet; } /** @@ -174,19 +179,17 @@ // Tests that the dropdown contains the appropriate destinations when there // are no recent destinations. - test( - 'NoRecentDestinations', function() { - initialize(); - return nativeLayer.whenCalled('getPrinterCapabilities').then(() => { - // This will result in the destination store setting the Save as - // PDF destination. - assertEquals( - GooglePromotedDestinationId.SAVE_AS_PDF, - destinationSettings.destination.id); - assertFalse(destinationSettings.$.destinationSelect.disabled); - assertDropdownItems(['Save as PDF/local/']); - }); - }); + test('NoRecentDestinations', async function() { + await initialize(); + // This will result in the destination store setting the Save as + // PDF destination. + assertTrue(!!destinationSettings.destination); + assertEquals( + GooglePromotedDestinationId.SAVE_AS_PDF, + destinationSettings.destination.id); + assertFalse(destinationSettings.$.destinationSelect.disabled); + assertDropdownItems(['Save as PDF/local/']); + }); // Tests that the dropdown contains the appropriate destinations when there // are 5 recent destinations. @@ -195,18 +198,12 @@ recentDestinations = destinations.slice(0, 5).map( destination => makeRecentDestination(destination)); - const whenCapabilitiesDone = - nativeLayer.whenCalled('getPrinterCapabilities'); - initialize(); - // Wait for the destinations to be inserted into the store. - return whenCapabilitiesDone - .then(() => { - return waitBeforeNextRender(destinationSettings); - }) - .then(() => { + return initialize().then( + () => { // This will result in the destination store setting the most // recent destination. + assertTrue(!!destinationSettings.destination); assertEquals('ID1', destinationSettings.destination.id); assertFalse(destinationSettings.$.destinationSelect.disabled); const dropdownItems = [ @@ -225,19 +222,13 @@ destination => makeRecentDestination(destination)); localDestinations.splice(1, 1); nativeLayer.setLocalDestinations(localDestinations); - const whenCapabilitiesDone = - nativeLayer.whenCalled('getPrinterCapabilities'); - - initialize(); // Wait for the destinations to be inserted into the store. - return whenCapabilitiesDone - .then(() => { - return waitBeforeNextRender(destinationSettings); - }) - .then(() => { + return initialize().then( + () => { // This will result in the destination store setting the most // recent destination. + assertTrue(!!destinationSettings.destination); assertEquals('ID1', destinationSettings.destination.id); assertFalse(destinationSettings.$.destinationSelect.disabled); const dropdownItems = [ @@ -255,17 +246,12 @@ destination => makeRecentDestination(destination)); recentDestinations.splice( 1, 1, makeRecentDestination(getSaveAsPdfDestination())); - const whenCapabilitiesDone = - nativeLayer.whenCalled('getPrinterCapabilities'); - initialize(); - return whenCapabilitiesDone - .then(() => { - return waitBeforeNextRender(destinationSettings); - }) - .then(() => { + return initialize().then( + () => { // This will result in the destination store setting the most recent // destination. + assertTrue(!!destinationSettings.destination); assertEquals('ID1', destinationSettings.destination.id); assertFalse(destinationSettings.$.destinationSelect.disabled); const dropdownItems = [ @@ -284,19 +270,14 @@ destination => makeRecentDestination(destination)); recentDestinations.splice( 1, 1, makeRecentDestination(getSaveAsPdfDestination())); - const whenCapabilitiesDone = - nativeLayer.whenCalled('getPrinterCapabilities'); - initialize(); const dropdown = destinationSettings.$.destinationSelect; - return whenCapabilitiesDone - .then(() => { - return waitBeforeNextRender(destinationSettings); - }) + return initialize() .then(() => { // This will result in the destination store setting the most recent // destination. + assertTrue(!!destinationSettings.destination); assertEquals('ID1', destinationSettings.destination.id); assertFalse(dropdown.disabled); const dropdownItems = [ @@ -319,6 +300,7 @@ return whenDestinationSelect; }) .then(() => { + assertTrue(!!destinationSettings.destination); assertEquals( GooglePromotedDestinationId.SAVE_AS_PDF, destinationSettings.destination.id); @@ -332,18 +314,13 @@ 'SelectRecentDestination', function() { recentDestinations = destinations.slice(0, 5).map( destination => makeRecentDestination(destination)); - const whenCapabilitiesDone = - nativeLayer.whenCalled('getPrinterCapabilities'); - initialize(); const dropdown = destinationSettings.$.destinationSelect; - return whenCapabilitiesDone - .then(() => { - return waitBeforeNextRender(destinationSettings); - }) + return initialize() .then(() => { // This will result in the destination store setting the most // recent destination. + assertTrue(!!destinationSettings.destination); assertEquals('ID1', destinationSettings.destination.id); assertFalse(dropdown.disabled); const dropdownItems = [ @@ -364,6 +341,7 @@ return whenDestinationSelect; }) .then(() => { + assertTrue(!!destinationSettings.destination); assertEquals('ID2', destinationSettings.destination.id); }); }); @@ -372,18 +350,13 @@ test('OpenDialog', function() { recentDestinations = destinations.slice(0, 5).map( destination => makeRecentDestination(destination)); - const whenCapabilitiesDone = - nativeLayer.whenCalled('getPrinterCapabilities'); - initialize(); const dropdown = destinationSettings.$.destinationSelect; - return whenCapabilitiesDone - .then(() => { - return waitBeforeNextRender(destinationSettings); - }) + return initialize() .then(() => { // This will result in the destination store setting the most recent // destination. + assertTrue(!!destinationSettings.destination); assertEquals('ID1', destinationSettings.destination.id); assertFalse(dropdown.disabled); const dropdownItems = [ @@ -395,7 +368,7 @@ dropdown.dispatchEvent(new CustomEvent( 'selected-option-change', {bubbles: true, composed: true, detail: 'seeMore'})); - return waitBeforeNextRender(destinationSettings); + return microtasksFinished(); }) .then(() => { assertTrue(destinationSettings.$.destinationDialog.get().isOpen()); @@ -416,13 +389,16 @@ } function selectDestination(destination: Destination) { + const whenCapabilitiesSet = eventToPromise( + DestinationStoreEventType.SELECTED_DESTINATION_CAPABILITIES_READY, + destinationSettings.getDestinationStoreForTest()); const storeDestination = destinationSettings.getDestinationStoreForTest().destinations().find( d => d.key === destination.key); assert(storeDestination); destinationSettings.getDestinationStoreForTest().selectDestination( storeDestination); - flush(); + return whenCapabilitiesSet; } /** @@ -430,14 +406,12 @@ * destinations array. */ test( - 'UpdateRecentDestinations', function() { + 'UpdateRecentDestinations', async function() { // Recent destinations start out empty. assertRecentDestinations([]); assertEquals(0, nativeLayer.getCallCount('getPrinterCapabilities')); - initialize(); - - return nativeLayer.whenCalled('getPrinterCapabilities') + return initialize() .then(() => { assertRecentDestinations(['Save as PDF']); assertEquals( @@ -450,11 +424,11 @@ return nativeLayer.whenCalled('getPrinters'); }) .then(() => { + nativeLayer.resetResolver('getPrinterCapabilities'); // Simulate setting a destination from the dialog. - selectDestination(destinations[0]!); - return nativeLayer.whenCalled('getPrinterCapabilities'); + return selectDestination(destinations[0]!); }) - .then(() => { + .then(async () => { assertRecentDestinations(['ID1', 'Save as PDF']); assertEquals( 1, nativeLayer.getCallCount('getPrinterCapabilities')); @@ -468,7 +442,7 @@ composed: true, detail: 'Save as PDF/local/', })); - flush(); + await microtasksFinished(); assertRecentDestinations(['Save as PDF', 'ID1']); // No additional capabilities call, since the destination was // previously selected. @@ -476,8 +450,7 @@ 0, nativeLayer.getCallCount('getPrinterCapabilities')); // Select a third destination. - selectDestination(destinations[1]!); - return nativeLayer.whenCalled('getPrinterCapabilities'); + return selectDestination(destinations[1]!); }) .then(() => { assertRecentDestinations(['ID2', 'Save as PDF', 'ID1']); @@ -510,24 +483,19 @@ 'DisabledSaveAsPdf', function() { // Initialize destination settings with the PDF printer disabled. pdfPrinterDisabled = true; - initialize(); - return nativeLayer.whenCalled('getPrinterCapabilities') - .then(() => { - return waitBeforeNextRender(destinationSettings); - }) - .then(() => { - // Because the 'Save as PDF' fallback is unavailable, the first - // destination is selected. - const expectedDestination = makeLocalDestinationKey('ID1'); - assertDropdownItems([expectedDestination]); - }); + return initialize().then(() => { + // Because the 'Save as PDF' fallback is unavailable, the first + // destination is selected. + const expectedDestination = makeLocalDestinationKey('ID1'); + assertDropdownItems([expectedDestination]); + }); }); // Tests that disabling the 'Save as PDF' destination and exposing no // printers to the native layer results in a 'No destinations' option in the // dropdown. - test('NoDestinations', function() { + test('NoDestinations', async function() { nativeLayer.setLocalDestinations([]); // Initialize destination settings with the PDF printer disabled. @@ -537,13 +505,8 @@ // 'getPrinters' will be called because there are no printers known to // the destination store and the 'Save as PDF' fallback is // unavailable. - return Promise - .all([ - nativeLayer.whenCalled('getPrinters'), - // TODO (rbpotter): remove this wait once user manager is fully - // removed. - waitBeforeNextRender(destinationSettings), - ]) - .then(() => assertDropdownItems(['noDestinations'])); + await nativeLayer.whenCalled('getPrinters'); + await microtasksFinished(); + assertDropdownItems(['noDestinations']); }); });
diff --git a/chrome/test/data/webui/print_preview/preview_generation_test.ts b/chrome/test/data/webui/print_preview/preview_generation_test.ts index 7563ee5..7443e06 100644 --- a/chrome/test/data/webui/print_preview/preview_generation_test.ts +++ b/chrome/test/data/webui/print_preview/preview_generation_test.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. import type {NativeInitialSettings, PreviewTicket, PrintPreviewAppElement, PrintPreviewDestinationSettingsElement, Range, Settings} from 'chrome://print/print_preview.js'; -import {ColorMode, CustomMarginsOrientation, Destination, DestinationOrigin, DestinationState, Margins, MarginsType, NativeLayerImpl, PluginProxyImpl, ScalingType} from 'chrome://print/print_preview.js'; +import {ColorMode, CustomMarginsOrientation, Destination, DestinationOrigin, Margins, MarginsType, NativeLayerImpl, PluginProxyImpl, ScalingType} from 'chrome://print/print_preview.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {NativeLayerStub} from './native_layer_stub.js'; @@ -564,6 +564,7 @@ page.shadowRoot!.querySelector('print-preview-sidebar')! .shadowRoot.querySelector( 'print-preview-destination-settings')!; + assertTrue(!!destinationSettings.destination); assertEquals('FooDevice', destinationSettings.destination.id); assertEquals('FooDevice', originalTicket.deviceName); const barDestination = @@ -581,13 +582,12 @@ }; barDestination.capabilities = capabilities; nativeLayer.resetResolver('getPreview'); - destinationSettings.destinationState = DestinationState.SET; destinationSettings.getDestinationStoreForTest().selectDestination( barDestination); - destinationSettings.destinationState = DestinationState.UPDATED; return nativeLayer.whenCalled('getPreview'); }) .then(function(args) { + assertTrue(!!destinationSettings.destination); assertEquals('BarDevice', destinationSettings.destination.id); const ticket: PreviewTicket = JSON.parse(args.printTicket); assertEquals('BarDevice', ticket.deviceName);
diff --git a/chrome/test/data/webui/print_preview/system_dialog_test.ts b/chrome/test/data/webui/print_preview/system_dialog_test.ts index 1110a83..2a0426d8 100644 --- a/chrome/test/data/webui/print_preview/system_dialog_test.ts +++ b/chrome/test/data/webui/print_preview/system_dialog_test.ts
@@ -60,7 +60,7 @@ 'FooDevice', sidebar.shadowRoot .querySelector( - 'print-preview-destination-settings')!.destination.id); + 'print-preview-destination-settings')!.destination!.id); // <if expr="is_win"> link = linkContainer.$.systemDialogLink; // </if>
diff --git a/chrome/test/data/webui/print_preview/test_plugin_proxy.ts b/chrome/test/data/webui/print_preview/test_plugin_proxy.ts index fbfbd28f..50c718f 100644 --- a/chrome/test/data/webui/print_preview/test_plugin_proxy.ts +++ b/chrome/test/data/webui/print_preview/test_plugin_proxy.ts
@@ -25,7 +25,7 @@ this.loadCompleteCallback_ = loadCompleteCallback; } - setPreloadCallback(preloadCallback: (() => void)|null) { + setPreloadCallback(preloadCallback: () => void) { this.preloadCallback_ = preloadCallback; }
diff --git a/chrome/test/data/webui/settings/settings_browsertest.cc b/chrome/test/data/webui/settings/settings_browsertest.cc index 58bb010..122859de 100644 --- a/chrome/test/data/webui/settings/settings_browsertest.cc +++ b/chrome/test/data/webui/settings/settings_browsertest.cc
@@ -411,8 +411,7 @@ scoped_feature_list_.InitWithFeaturesAndParameters( {{features::kGlicLearnMoreURLConfig, { - {"glic-shortcuts-launcher-toggle-learn-more-url", - "https://google.com/"}, + {"glic-launcher-toggle-learn-more-url", "https://google.com/"}, }}}, /*disabled_features=*/{}); } @@ -433,8 +432,7 @@ scoped_feature_list_.InitWithFeaturesAndParameters( {{features::kGlicLearnMoreURLConfig, { - {"glic-shortcuts-location-toggle-learn-more-url", - "https://google.com/"}, + {"glic-location-toggle-learn-more-url", "https://google.com/"}, }}}, /*disabled_features=*/{}); } @@ -456,8 +454,7 @@ scoped_feature_list_.InitWithFeaturesAndParameters( {{features::kGlicLearnMoreURLConfig, { - {"glic-shortcuts-tab-access-toggle-learn-more-url", - "https://google.com/"}, + {"glic-tab-access-toggle-learn-more-url", "https://google.com/"}, }}}, /*disabled_features=*/{}); }
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts index 6d06f6f..64f2981 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts +++ b/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts
@@ -7,7 +7,7 @@ import type {AppElement} from 'chrome://customize-chrome-side-panel.top-chrome/app.js'; import {CustomizeChromeImpression} from 'chrome://customize-chrome-side-panel.top-chrome/common.js'; import type {BackgroundCollection, CustomizeChromePageRemote} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome.mojom-webui.js'; -import {CustomizeChromePageCallbackRouter, CustomizeChromePageHandlerRemote, CustomizeChromeSection} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome.mojom-webui.js'; +import {CustomizeChromePageCallbackRouter, CustomizeChromePageHandlerRemote, CustomizeChromeSection, NewTabPageType} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome.mojom-webui.js'; import {CustomizeChromeApiProxy} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome_api_proxy.js'; import {CustomizeToolbarClientCallbackRouter, CustomizeToolbarHandlerRemote} from 'chrome://customize-chrome-side-panel.top-chrome/customize_toolbar.mojom-webui.js'; import type {CustomizeToolbarHandlerInterface} from 'chrome://customize-chrome-side-panel.top-chrome/customize_toolbar.mojom-webui.js'; @@ -230,7 +230,7 @@ }); }); - test('isSourceTabFirstPartyNtp should update the cards', async () => { + test('source tab type should update the cards', async () => { const idsControlledByIsSourceTabFirstPartyNtp = [ '#shortcuts', '#modules', @@ -249,19 +249,29 @@ '#buttonContainer', ]; - const checkIdsVisibility = (isSourceTabFirstPartyNtp: boolean) => { + const newTabPageTypes = [ + NewTabPageType.kFirstPartyWebUI, + NewTabPageType.kThirdPartyWebUI, + NewTabPageType.kThirdPartyRemote, + NewTabPageType.kExtension, + NewTabPageType.kIncognito, + NewTabPageType.kGuestMode, + NewTabPageType.kNone, + ]; + + const checkIdsVisibility = (sourceTabType: NewTabPageType) => { idsControlledByIsSourceTabFirstPartyNtp.forEach( id => assertEquals( - isSourceTabFirstPartyNtp, + sourceTabType === NewTabPageType.kFirstPartyWebUI, !!customizeChromeApp.shadowRoot.querySelector(id))); idsNotControlledByIsSourceTabFirstPartyNtp.forEach( id => assertTrue(!!customizeChromeApp.shadowRoot.querySelector(id))); }; - await[true, false].forEach(async b => { - callbackRouter.attachedTabStateUpdated(b); + await newTabPageTypes.forEach(async t => { + callbackRouter.attachedTabStateUpdated(t); await microtasksFinished(); - checkIdsVisibility(b); + checkIdsVisibility(t); }); }); @@ -301,7 +311,7 @@ 'selected')); assertEquals(customizeChromeApp, document.activeElement); - callbackRouter.attachedTabStateUpdated(false); + callbackRouter.attachedTabStateUpdated(NewTabPageType.kExtension); callbackRouter.setThemeEditable(false); await microtasksFinished(); @@ -326,7 +336,7 @@ customizeChromeApp.shadowRoot.querySelector('#toolbarPage')! .classList.contains('selected')); - callbackRouter.attachedTabStateUpdated(false); + callbackRouter.attachedTabStateUpdated(NewTabPageType.kExtension); await microtasksFinished(); // Current page should now be toolbar.
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts index ae64285..b2dc801b 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts +++ b/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts
@@ -7,7 +7,7 @@ import type {AppearanceElement} from 'chrome://customize-chrome-side-panel.top-chrome/appearance.js'; import {CustomizeChromeAction} from 'chrome://customize-chrome-side-panel.top-chrome/common.js'; import type {CustomizeChromePageRemote} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome.mojom-webui.js'; -import {CustomizeChromePageCallbackRouter, CustomizeChromePageHandlerRemote} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome.mojom-webui.js'; +import {CustomizeChromePageCallbackRouter, CustomizeChromePageHandlerRemote, NewTabPageType} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome.mojom-webui.js'; import {CustomizeChromeApiProxy} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome_api_proxy.js'; import type {ManagedDialogElement} from 'chrome://resources/cr_components/managed_dialog/managed_dialog.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; @@ -619,7 +619,7 @@ }); }); - test('isSourceTabFirstPartyNtp should update the content', async () => { + test('source tab type should update the content', async () => { const idsControlledByIsSourceTabFirstPartyNtp = [ '#editButtonsContainer', '#themeSnapshot', @@ -637,19 +637,29 @@ '#editThemeIcon', ]; - const checkIdsVisibility = (isSourceTabFirstPartyNtp: boolean) => { + const newTabPageTypes = [ + NewTabPageType.kFirstPartyWebUI, + NewTabPageType.kThirdPartyWebUI, + NewTabPageType.kThirdPartyRemote, + NewTabPageType.kExtension, + NewTabPageType.kIncognito, + NewTabPageType.kGuestMode, + NewTabPageType.kNone, + ]; + + const checkIdsVisibility = (sourceTabType: NewTabPageType) => { idsControlledByIsSourceTabFirstPartyNtp.forEach( id => assertEquals( - isSourceTabFirstPartyNtp, + sourceTabType === NewTabPageType.kFirstPartyWebUI, !!appearanceElement.shadowRoot.querySelector(id))); idsNotControlledByIsSourceTabFirstPartyNtp.forEach( id => assertTrue(!!appearanceElement.shadowRoot.querySelector(id))); }; - await[true, false].forEach(async b => { - callbackRouterRemote.attachedTabStateUpdated(b); + await newTabPageTypes.forEach(async t => { + callbackRouterRemote.attachedTabStateUpdated(t); await microtasksFinished(); - checkIdsVisibility(b); + checkIdsVisibility(t); }); }); });
diff --git a/chrome/test/data/webui/side_panel/read_anything/BUILD.gn b/chrome/test/data/webui/side_panel/read_anything/BUILD.gn index feee120..857e8e3 100644 --- a/chrome/test/data/webui/side_panel/read_anything/BUILD.gn +++ b/chrome/test/data/webui/side_panel/read_anything/BUILD.gn
@@ -64,7 +64,6 @@ "voice_pack_controller_test.ts", "voice_pack_model_test.ts", "voice_selection_menu_test.ts", - "voice_selection_test.ts", "word_boundaries_speech_test.ts", "word_boundaries_test.ts", "word_highlighting_test.ts",
diff --git a/chrome/test/data/webui/side_panel/read_anything/highlighter_test.ts b/chrome/test/data/webui/side_panel/read_anything/highlighter_test.ts index b323d3b..28844881 100644 --- a/chrome/test/data/webui/side_panel/read_anything/highlighter_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/highlighter_test.ts
@@ -52,6 +52,8 @@ test('isInvalidHighlightForWordHighlighting', () => { assertTrue(highlighter.isInvalidHighlightForWordHighlighting()); assertTrue(highlighter.isInvalidHighlightForWordHighlighting('')); + assertTrue(highlighter.isInvalidHighlightForWordHighlighting(' ')); + assertTrue(highlighter.isInvalidHighlightForWordHighlighting(' ')); assertTrue(highlighter.isInvalidHighlightForWordHighlighting('!')); assertTrue(highlighter.isInvalidHighlightForWordHighlighting('()?!?')); assertFalse(highlighter.isInvalidHighlightForWordHighlighting('hello !!!')); @@ -133,6 +135,42 @@ id); }); + test('word highlight across multiple nodes with engine length', () => { + chrome.readingMode.onHighlightGranularityChanged( + chrome.readingMode.wordHighlighting); + // speechUtteranceLength should extend across multiple nodes. + wordBoundaries.updateBoundary(0, 4); + + const bold = document.createElement('b'); + const text1 = 'I\'m'; + bold.appendChild(document.createTextNode(text1)); + const sentence = document.createElement('p'); + // A space is intentionally inserted into the beginning of this segment. + const text2 = ' slipping into the lava.'; + sentence.appendChild(document.createTextNode(text2)); + const id1 = 10; + const id2 = 12; + chrome.readingMode.getHighlightForCurrentSegmentIndex = () => + [{nodeId: id1, start: 0, length: 3}, + {nodeId: id2, start: 0, length: 1}]; + nodeStore.setDomNode(bold, id1); + nodeStore.setDomNode(sentence, id2); + chrome.readingMode.getCurrentTextStartIndex = () => 0; + chrome.readingMode.getCurrentTextEndIndex = () => + text1.length + text2.length; + + highlighter.highlightCurrentGranularity( + [id1, id2], /*scrollIntoView=*/ false, + /*shouldUpdateSentenceHighlight=*/ true); + + assertTrue(highlighter.hasCurrentHighlights()); + + // Only "I'm" is highlighted. The rest of the sentence, including the space + // after "I'm" remains unhighlighted. + assertHtml('<span class="current-read-highlight">I\'m</span>', id1); + assertHtml(' slipping into the lava.', id2); + }); + test('phrase highlight', () => { chrome.readingMode.onHighlightGranularityChanged( chrome.readingMode.autoHighlighting);
diff --git a/chrome/test/data/webui/side_panel/read_anything/language_change_test.ts b/chrome/test/data/webui/side_panel/read_anything/language_change_test.ts index 0e69c6a..a2008bd 100644 --- a/chrome/test/data/webui/side_panel/read_anything/language_change_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/language_change_test.ts
@@ -109,7 +109,7 @@ app.languageChanged(); await microtasksFinished(); - assertEquals(otherVoice, app.getSpeechSynthesisVoice()); + assertEquals(otherVoice, voicePackController.getCurrentVoice()); }); test('enables the stored voice language', async () => { @@ -124,7 +124,7 @@ await microtasksFinished(); assertTrue(voicePackController.isLangEnabled(voice.lang)); - assertEquals(voice, app.getSpeechSynthesisVoice()); + assertEquals(voice, voicePackController.getCurrentVoice()); }); suite('when there is no stored voice for this language', () => { @@ -142,19 +142,20 @@ app, ToolbarEvent.VOICE, {detail: {selectedVoice: otherVoice}}); app.languageChanged(); await microtasksFinished(); - assertEquals(otherVoice, app.getSpeechSynthesisVoice()); + assertEquals(otherVoice, voicePackController.getCurrentVoice()); }); test('to a natural voice if there\'s no current voice', async () => { app.languageChanged(); await microtasksFinished(); - assertEquals(naturalVoiceWithLang3, app.getSpeechSynthesisVoice()); + assertEquals( + naturalVoiceWithLang3, voicePackController.getCurrentVoice()); }); test('to the device default if there\'s no natural', () => { setVoices(app, speech, voices.filter(v => v !== naturalVoiceWithLang3)); app.languageChanged(); - assertEquals(defaultVoice, app.getSpeechSynthesisVoice()); + assertEquals(defaultVoice, voicePackController.getCurrentVoice()); }); }); @@ -167,7 +168,7 @@ app.languageChanged(); - assertEquals(voice, app.getSpeechSynthesisVoice()); + assertEquals(voice, voicePackController.getCurrentVoice()); }); test('to a voice in the available locale for this base language', () => { @@ -179,14 +180,15 @@ app.languageChanged(); - assertEquals(voice, app.getSpeechSynthesisVoice()); + assertEquals(voice, voicePackController.getCurrentVoice()); }); suite('and this locale is enabled', () => { test('to a natural voice for this language', () => { chrome.readingMode.baseLanguageForSpeech = lang3; app.languageChanged(); - assertEquals(naturalVoiceWithLang3, app.getSpeechSynthesisVoice()); + assertEquals( + naturalVoiceWithLang3, voicePackController.getCurrentVoice()); }); test( @@ -194,7 +196,8 @@ () => { chrome.readingMode.baseLanguageForSpeech = lang1; app.languageChanged(); - assertEquals(defaultVoiceWithLang1, app.getSpeechSynthesisVoice()); + assertEquals( + defaultVoiceWithLang1, voicePackController.getCurrentVoice()); }); test( @@ -202,7 +205,8 @@ () => { chrome.readingMode.baseLanguageForSpeech = lang2; app.languageChanged(); - assertEquals(firstVoiceWithLang2, app.getSpeechSynthesisVoice()); + assertEquals( + firstVoiceWithLang2, voicePackController.getCurrentVoice()); }); }); @@ -213,7 +217,8 @@ app.languageChanged(); assertTrue(voicePackController.isLangEnabled(lang3)); - assertEquals(naturalVoiceWithLang3, app.getSpeechSynthesisVoice()); + assertEquals( + naturalVoiceWithLang3, voicePackController.getCurrentVoice()); }); test( @@ -224,7 +229,8 @@ app.languageChanged(); assertTrue(voicePackController.isLangEnabled(lang1)); - assertEquals(defaultVoiceWithLang1, app.getSpeechSynthesisVoice()); + assertEquals( + defaultVoiceWithLang1, voicePackController.getCurrentVoice()); }); @@ -239,7 +245,7 @@ app.languageChanged(); - assertEquals(voice, app.getSpeechSynthesisVoice()); + assertEquals(voice, voicePackController.getCurrentVoice()); }); test('to natural enabled voice if no same locale', () => { @@ -249,7 +255,8 @@ app.languageChanged(); - assertEquals(naturalVoiceWithLang3, app.getSpeechSynthesisVoice()); + assertEquals( + naturalVoiceWithLang3, voicePackController.getCurrentVoice()); }); test('to default enabled voice if no natural voice', () => { @@ -259,10 +266,11 @@ app.languageChanged(); - assertEquals(defaultVoiceWithLang1, app.getSpeechSynthesisVoice()); + assertEquals( + defaultVoiceWithLang1, voicePackController.getCurrentVoice()); }); - test('to undefined if no enabled languages', () => { + test('to null if no enabled languages', () => { chrome.readingMode.baseLanguageForSpeech = lang2; for (const lang of voicePackController.getEnabledLangs()) { voicePackController.disableLang(lang); @@ -270,9 +278,7 @@ app.languageChanged(); - assertEquals( - undefined, app.getSpeechSynthesisVoice(), - app.getSpeechSynthesisVoice()?.name); + assertFalse(!!voicePackController.getCurrentVoice()); }); }); }); @@ -316,7 +322,7 @@ test('but doesn\'t if the language is already installing', () => { const lang = 'bn-bd'; const voicePackLang = convertLangOrLocaleForVoicePackManager(lang); - assertTrue(voicePackLang !== undefined); + assertTrue(!!voicePackLang); app.updateVoicePackStatus(lang, 'kInstalling'); app.languageChanged();
diff --git a/chrome/test/data/webui/side_panel/read_anything/phrase_highlighting_test.ts b/chrome/test/data/webui/side_panel/read_anything/phrase_highlighting_test.ts index 0757eb30..0014774 100644 --- a/chrome/test/data/webui/side_panel/read_anything/phrase_highlighting_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/phrase_highlighting_test.ts
@@ -4,7 +4,7 @@ import type {CrIconButtonElement} from '//resources/cr_elements/cr_icon_button/cr_icon_button.js'; import type {AppElement, ReadAnythingToolbarElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; -import {SpeechController, WordBoundaries} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; +import {ReadAloudHighlighter, SpeechController, VoicePackController, WordBoundaries} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; import {assertEquals, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js'; import {microtasksFinished} from 'chrome-untrusted://webui-test/test_util.js'; @@ -66,9 +66,12 @@ chrome.readingMode.onConnected = () => {}; SpeechController.setInstance(new SpeechController()); + VoicePackController.setInstance(new VoicePackController()); + wordBoundaries = new WordBoundaries(); + WordBoundaries.setInstance(wordBoundaries); + ReadAloudHighlighter.setInstance(new ReadAloudHighlighter()); metrics = mockMetrics(); app = await createApp(); - wordBoundaries = WordBoundaries.getInstance(); // Use a tree with just one sentence. For the actual implementation of // phrase segmentation, a more realistic example would be to use
diff --git a/chrome/test/data/webui/side_panel/read_anything/prefs_test.ts b/chrome/test/data/webui/side_panel/read_anything/prefs_test.ts index 2f625548..9aba687b7 100644 --- a/chrome/test/data/webui/side_panel/read_anything/prefs_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/prefs_test.ts
@@ -100,7 +100,7 @@ // Set synthesis to have no available voices setVoices(app, speech, []); - app.resetVoiceForTesting(); + voicePackController.setCurrentVoice(null); }); test('with no settings, voice selected in onVoicesChanged', () => { @@ -109,41 +109,40 @@ // When there's no voices available, there shouldn't be a speech // synthesis voice selected. app.restoreSettingsFromPrefs(); - assertFalse(!!app.getSpeechSynthesisVoice()); + assertFalse(!!voicePackController.getCurrentVoice()); // Update the speech synthesis engine with voices. setupBasicSpeech(app, speech); // Once voices are available, settings should be restored. - assertTrue(!!app.getSpeechSynthesisVoice()); + assertTrue(!!voicePackController.getCurrentVoice()); + }); + + test('with no settings, dfferent language voice selected', () => { + chrome.readingMode.getStoredVoice = () => ''; + + // When there's no voices available, there shouldn't be a speech + // synthesis voice selected. + app.restoreSettingsFromPrefs(); + assertFalse(!!voicePackController.getCurrentVoice()); + + // Update the speech synthesis engine with voices. + setupBasicSpeech(app, speech); + + // Once voices are available, settings should be restored. + assertTrue(!!voicePackController.getCurrentVoice()); }); test( - 'with no settings, dfferent language voice selected in onVoicesChanged', - () => { - chrome.readingMode.getStoredVoice = () => ''; - - // When there's no voices available, there shouldn't be a speech - // synthesis voice selected. - app.restoreSettingsFromPrefs(); - assertFalse(!!app.getSpeechSynthesisVoice()); - - // Update the speech synthesis engine with voices. - setupBasicSpeech(app, speech); - - // Once voices are available, settings should be restored. - assertTrue(!!app.getSpeechSynthesisVoice()); - }); - - test( - 'with no initial voices and previously selected voice, correct voice selected after onVoicesChanged', + 'with no initial voices and previously selected voice, correct ' + + 'voice selected after onVoicesChanged', () => { chrome.readingMode.getStoredVoice = () => 'Google Kristi'; // When there's no voices available, there shouldn't be a speech // synthesis voice selected. app.restoreSettingsFromPrefs(); - assertFalse(!!app.getSpeechSynthesisVoice()); + assertFalse(!!voicePackController.getCurrentVoice()); // Update the speech synthesis engine with voices. createAndSetVoices(app, speech, [ @@ -153,7 +152,7 @@ ]); // Once voices are available, settings should be restored. - const selectedVoice = app.getSpeechSynthesisVoice(); + const selectedVoice = voicePackController.getCurrentVoice(); assertTrue(!!selectedVoice); assertEquals('Google Kristi', selectedVoice.name); }); @@ -166,7 +165,7 @@ // When there's no voices available, there shouldn't be a speech // synthesis voice selected. app.restoreSettingsFromPrefs(); - assertFalse(!!app.getSpeechSynthesisVoice()); + assertFalse(!!voicePackController.getCurrentVoice()); const futureSelectedVoice = createSpeechSynthesisVoice({lang: 'en', name: 'Google Kristi'}); @@ -179,14 +178,14 @@ ]); // Once voices are available, settings should be restored. - let selectedVoice = app.getSpeechSynthesisVoice(); + let selectedVoice = voicePackController.getCurrentVoice(); assertTrue(!!selectedVoice); assertEquals('Google Shari', selectedVoice.name); emitEvent( app, ToolbarEvent.VOICE, {detail: {selectedVoice: futureSelectedVoice}}); - selectedVoice = app.getSpeechSynthesisVoice(); + selectedVoice = voicePackController.getCurrentVoice(); assertTrue(!!selectedVoice); assertEquals('Google Kristi', selectedVoice.name); @@ -197,7 +196,7 @@ // After onVoicesChanged, the most recently selected voice should // be used. - selectedVoice = app.getSpeechSynthesisVoice(); + selectedVoice = voicePackController.getCurrentVoice(); assertTrue(!!selectedVoice); assertEquals('Google Kristi', selectedVoice.name); }); @@ -233,98 +232,5 @@ [langs[1], locales[1]], voicePackController.getEnabledLangs()); }); }); - - suite('initializes voice', () => { - const langForDefaultVoice = 'en'; - const lang1 = 'zh'; - const lang2 = 'tr'; - const langWithNoVoices = 'elvish'; - - const defaultVoice = createSpeechSynthesisVoice({ - lang: langForDefaultVoice, - name: 'Google Kristi', - default: true, - }); - const firstVoiceWithLang1 = - createSpeechSynthesisVoice({lang: lang1, name: 'Google Lauren'}); - const defaultVoiceWithLang1 = createSpeechSynthesisVoice({ - lang: lang1, - name: 'Google Eitan', - default: true, - }); - const firstVoiceWithLang2 = - createSpeechSynthesisVoice({lang: lang2, name: 'Google Yu'}); - const secondVoiceWithLang2 = - createSpeechSynthesisVoice({lang: lang2, name: 'Google Xiang'}); - const otherVoice = - createSpeechSynthesisVoice({lang: 'it', name: 'Google Shari'}); - const voices = [ - defaultVoice, - firstVoiceWithLang1, - defaultVoiceWithLang1, - otherVoice, - firstVoiceWithLang2, - secondVoiceWithLang2, - ]; - - setup(() => { - setVoices(app, speech, voices); - }); - - test('to the stored voice for this language if there is one', () => { - chrome.readingMode.getStoredVoice = () => otherVoice.name; - app.restoreSettingsFromPrefs(); - assertEquals(otherVoice, app.getSpeechSynthesisVoice()); - }); - - test('to a default voice if the stored voice is invalid', () => { - chrome.readingMode.getStoredVoice = () => 'Matt'; - voicePackController.enableLang(langForDefaultVoice); - app.restoreSettingsFromPrefs(); - assertEquals(defaultVoice, app.getSpeechSynthesisVoice()); - }); - - suite('when there is no stored voice for this language', () => { - setup(() => { - chrome.readingMode.getStoredVoice = () => ''; - }); - - test('to the default voice for this language', () => { - voicePackController.enableLang(lang1); - voicePackController.setCurrentLanguage(lang1); - app.restoreSettingsFromPrefs(); - assertEquals(defaultVoiceWithLang1, app.getSpeechSynthesisVoice()); - }); - - test('uses current voice if there\'s none for this language', () => { - voicePackController.setCurrentLanguage(langWithNoVoices); - emitEvent( - app, ToolbarEvent.VOICE, {detail: {selectedVoice: otherVoice}}); - voicePackController.enableLang(otherVoice.lang); - app.restoreSettingsFromPrefs(); - assertEquals(otherVoice, app.getSpeechSynthesisVoice()); - }); - - test('uses the device default if there\'s no current voice', () => { - voicePackController.setCurrentLanguage(langWithNoVoices); - voicePackController.enableLang(langForDefaultVoice); - voicePackController.enableLang(otherVoice.lang); - app.restoreSettingsFromPrefs(); - assertEquals(defaultVoice, app.getSpeechSynthesisVoice()); - }); - - test( - 'to the first listed voice for this language if there\'s no default', - () => { - voicePackController.enableLang(lang2); - voicePackController.setCurrentLanguage(lang2); - app.restoreSettingsFromPrefs(); - const currentSelectedVoice = app.getSpeechSynthesisVoice(); - assertTrue(!!currentSelectedVoice); - assertEquals(firstVoiceWithLang2.name, currentSelectedVoice.name); - assertEquals(firstVoiceWithLang2.lang, currentSelectedVoice.lang); - }); - }); - }); }); });
diff --git a/chrome/test/data/webui/side_panel/read_anything/read_aloud_highlighting_test.ts b/chrome/test/data/webui/side_panel/read_anything/read_aloud_highlighting_test.ts index 72b2af6a..083eb8b 100644 --- a/chrome/test/data/webui/side_panel/read_anything/read_aloud_highlighting_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/read_aloud_highlighting_test.ts
@@ -4,7 +4,7 @@ import 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; import type {AppElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; -import {PauseActionSource, playFromSelectionTimeout, SpeechController, ToolbarEvent} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; +import {PauseActionSource, playFromSelectionTimeout, SpeechController, ToolbarEvent, VoicePackController} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; import {assertEquals, assertFalse} from 'chrome-untrusted://webui-test/chai_assert.js'; import {MockTimer} from 'chrome-untrusted://webui-test/mock_timer.js'; @@ -67,6 +67,7 @@ chrome.readingMode.onConnected = () => {}; speechController = new SpeechController(); SpeechController.setInstance(speechController); + VoicePackController.setInstance(new VoicePackController()); app = await createApp(); chrome.readingMode.setContentForTesting(axTree, leafIds);
diff --git a/chrome/test/data/webui/side_panel/read_anything/read_anything_browsertest.cc b/chrome/test/data/webui/side_panel/read_anything/read_anything_browsertest.cc index 6fdf8e5..9ad2a6a 100644 --- a/chrome/test/data/webui/side_panel/read_anything/read_anything_browsertest.cc +++ b/chrome/test/data/webui/side_panel/read_anything/read_anything_browsertest.cc
@@ -191,11 +191,6 @@ "mocha.run()"); } -IN_PROC_BROWSER_TEST_F(ReadAnythingMochaTest, VoiceSelection) { - RunSidePanelTest("side_panel/read_anything/voice_selection_test.js", - "mocha.run()"); -} - IN_PROC_BROWSER_TEST_F(ReadAnythingMochaTest, Prefs) { RunSidePanelTest("side_panel/read_anything/prefs_test.js", "mocha.run()"); }
diff --git a/chrome/test/data/webui/side_panel/read_anything/read_anything_logger_test.ts b/chrome/test/data/webui/side_panel/read_anything/read_anything_logger_test.ts index f773b17..96c69788 100644 --- a/chrome/test/data/webui/side_panel/read_anything/read_anything_logger_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/read_anything_logger_test.ts
@@ -207,7 +207,7 @@ const expectedTime = 100; await new Promise(resolve => setTimeout(resolve, expectedTime)); - logger.logSpeechPlaySession(startTime, undefined); + logger.logSpeechPlaySession(startTime, null); // The playback length should be at least the amount of time we waited above // and less than the starting time (i.e. we should be recording length of
diff --git a/chrome/test/data/webui/side_panel/read_anything/speech_test.ts b/chrome/test/data/webui/side_panel/read_anything/speech_test.ts index 97f73c8..ad9de934 100644 --- a/chrome/test/data/webui/side_panel/read_anything/speech_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/speech_test.ts
@@ -423,6 +423,11 @@ test('on text-too-long error smaller text segment plays', () => { createAndSetVoices( app, speech, [{lang: 'en', name: 'Google Bob', localService: true}]); + emitEvent(app, ToolbarEvent.VOICE, { + detail: { + selectedVoice: speech.getVoices()[0], + }, + }); const accessibleTextLength = app.getAccessibleTextLength(longSentences); app.playSpeech(); assertEquals(longSentences, getSpokenText()); @@ -512,7 +517,7 @@ assertTrue(app.$.toolbar.isReadAloudPlayable); }); - test('selects default voice on language-unavailable', async () => { + test('stops speech on language-unavailable', async () => { const pageLanguage = 'es'; assertNotEquals( chrome.readingMode.defaultLanguageForSpeech, pageLanguage); @@ -532,87 +537,31 @@ assertEquals(0, speech.getCallCount('pause')); assertEquals(0, speech.getCallCount('speak')); assertEquals( - chrome.readingMode.defaultLanguageForSpeech, - voicePackController.getCurrentLanguage()); - assertEquals( chrome.readingMode.engineErrorStopSource, await metrics.whenCalled('recordSpeechStopSource')); }); - suite('voice change to unavailable voice', () => { - let utterance: SpeechSynthesisUtterance; + test('stops speech on voice-unavailable', async () => { + const pageLanguage = 'es'; + assertNotEquals( + chrome.readingMode.defaultLanguageForSpeech, pageLanguage); + assertNotEquals( + chrome.readingMode.defaultLanguageForSpeech, + voicePackController.getCurrentLanguage()); + chrome.readingMode.setLanguageForTesting(pageLanguage); + app.playSpeech(); + assertEquals(1, speech.getCallCount('speak'), 'speak'); + const utterance = speech.getArgs('speak')[0]; + speech.reset(); - setup(() => { - app.playSpeech(); - assertEquals(1, speech.getCallCount('speak')); - utterance = speech.getArgs('speak')[0]; - }); + utterance.onerror(createSpeechErrorEvent(utterance, 'voice-unavailable')); - test('cancels and selects default voice', async () => { - chrome.readingMode.setLanguageForTesting('en'); - emitEvent(app, ToolbarEvent.VOICE, { - detail: { - selectedVoice: - createSpeechSynthesisVoice({lang: 'en', name: 'Lisie'}), - }, - }); - speech.reset(); - - assertTrue(!!utterance.onerror); - utterance.onerror( - createSpeechErrorEvent(utterance, 'voice-unavailable')); - - assertEquals(1, speech.getCallCount('cancel')); - assertEquals(0, speech.getCallCount('pause')); - assertEquals(0, speech.getCallCount('speak')); - assertEquals(speech.getVoices()[0], app.getSpeechSynthesisVoice()); - assertEquals( - chrome.readingMode.engineErrorStopSource, - await metrics.whenCalled('recordSpeechStopSource')); - }); - - test('still in getVoices(), cancels and selects another voice', () => { - chrome.readingMode.setLanguageForTesting('en'); - createAndSetVoices(app, speech, [ - {lang: 'en', name: 'Google George'}, - {lang: 'en', name: 'Google Connie'}, - ]); - emitEvent(app, ToolbarEvent.VOICE, { - detail: {selectedVoice: speech.getVoices()[0]}, - }); - speech.reset(); - - assertTrue(!!utterance.onerror); - utterance.onerror( - createSpeechErrorEvent(utterance, 'voice-unavailable')); - - assertEquals(1, speech.getCallCount('cancel')); - assertEquals(0, speech.getCallCount('pause')); - assertEquals(0, speech.getCallCount('speak')); - assertEquals(speech.getVoices()[1], app.getSpeechSynthesisVoice()); - }); - - test( - 'continues to select default voice if no voices available in language', - () => { - chrome.readingMode.setLanguageForTesting('elvish'); - emitEvent(app, ToolbarEvent.VOICE, { - detail: { - selectedVoice: createSpeechSynthesisVoice( - {lang: 'en', name: 'Google Lauren'}), - }, - }); - speech.reset(); - - assertTrue(!!utterance.onerror); - utterance.onerror( - createSpeechErrorEvent(utterance, 'voice-unavailable')); - - assertEquals(1, speech.getCallCount('cancel')); - assertEquals(0, speech.getCallCount('pause')); - assertEquals(0, speech.getCallCount('speak')); - assertEquals(speech.getVoices()[0], app.getSpeechSynthesisVoice()); - }); + assertEquals(2, speech.getCallCount('cancel')); + assertEquals(0, speech.getCallCount('pause')); + assertEquals(0, speech.getCallCount('speak')); + assertEquals( + chrome.readingMode.engineErrorStopSource, + await metrics.whenCalled('recordSpeechStopSource')); }); test('invalid argument cancels and uses default rate', () => {
diff --git a/chrome/test/data/webui/side_panel/read_anything/update_voice_pack_test.ts b/chrome/test/data/webui/side_panel/read_anything/update_voice_pack_test.ts index dd843c46..fc228265 100644 --- a/chrome/test/data/webui/side_panel/read_anything/update_voice_pack_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/update_voice_pack_test.ts
@@ -371,7 +371,7 @@ setNaturalVoicesForLang(lang); app.updateVoicePackStatus(lang, 'kInstalled'); - const selectedVoice = app.getSpeechSynthesisVoice(); + const selectedVoice = voicePackController.getCurrentVoice(); assertTrue(!!selectedVoice); assertEquals(lang, selectedVoice.lang); assertTrue(selectedVoice.name.includes('Natural')); @@ -397,7 +397,7 @@ app.updateVoicePackStatus(installedLang, 'kInstalled'); // The selected voice should stay the same as it was. - assertEquals(currentVoice, app.getSpeechSynthesisVoice()); + assertEquals(currentVoice, voicePackController.getCurrentVoice()); }); test('with error code marks the status', () => {
diff --git a/chrome/test/data/webui/side_panel/read_anything/voice_pack_controller_test.ts b/chrome/test/data/webui/side_panel/read_anything/voice_pack_controller_test.ts index 9a86d35..96474d3 100644 --- a/chrome/test/data/webui/side_panel/read_anything/voice_pack_controller_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/voice_pack_controller_test.ts
@@ -20,6 +20,7 @@ let listener: VoiceLanguageListener; let onEnabledLangsChange: boolean; let onAvailableVoicesChange: boolean; + let onCurrentVoiceChange: boolean; setup(() => { // Clearing the DOM should always be done first. @@ -32,6 +33,7 @@ voicePackController = new VoicePackController(); onEnabledLangsChange = false; onAvailableVoicesChange = false; + onCurrentVoiceChange = false; listener = { onEnabledLangsChange() { onEnabledLangsChange = true; @@ -39,6 +41,9 @@ onAvailableVoicesChange() { onAvailableVoicesChange = true; }, + onCurrentVoiceChange() { + onCurrentVoiceChange = true; + }, }; voicePackController.addListener(listener); }); @@ -141,6 +146,185 @@ assertTrue(voicePackController.isLangEnabled('NO')); }); + test('setCurrentVoice', () => { + const voice = createSpeechSynthesisVoice({lang: 'tr', name: 'Zebra'}); + voicePackController.setCurrentVoice(voice); + assertTrue(onCurrentVoiceChange); + assertEquals(voice, voicePackController.getCurrentVoice()); + + onCurrentVoiceChange = false; + voicePackController.setCurrentVoice(voice); + assertFalse(onCurrentVoiceChange); + assertEquals(voice, voicePackController.getCurrentVoice()); + }); + + test('setUserPreferredVoice', () => { + let sentVoiceName = ''; + let sentLang = ''; + chrome.readingMode.onVoiceChange = (name, lang) => { + sentVoiceName = name; + sentLang = lang; + }; + const voice = createSpeechSynthesisVoice({lang: 'tr', name: 'Lion'}); + + voicePackController.setUserPreferredVoice(voice); + + assertTrue(onCurrentVoiceChange); + assertEquals(voice, voicePackController.getCurrentVoice()); + assertEquals(voice.name, sentVoiceName); + assertEquals(voice.lang, sentLang); + }); + + suite('setUserPreferredVoiceFromPrefs', () => { + const langForDefaultVoice = 'en'; + const lang1 = 'zh'; + const lang2 = 'tr'; + const langWithNoVoices = 'elvish'; + + const defaultVoice = createSpeechSynthesisVoice({ + lang: langForDefaultVoice, + name: 'Google Kristi', + default: true, + }); + const firstVoiceWithLang1 = + createSpeechSynthesisVoice({lang: lang1, name: 'Google Monkey'}); + const defaultVoiceWithLang1 = createSpeechSynthesisVoice({ + lang: lang1, + name: 'Google Llama', + default: true, + }); + const firstVoiceWithLang2 = + createSpeechSynthesisVoice({lang: lang2, name: 'Google Parrot'}); + const secondVoiceWithLang2 = + createSpeechSynthesisVoice({lang: lang2, name: 'Google Panda'}); + const otherVoice = + createSpeechSynthesisVoice({lang: 'it', name: 'Google Elephant'}); + const voices = [ + defaultVoice, + firstVoiceWithLang1, + defaultVoiceWithLang1, + otherVoice, + firstVoiceWithLang2, + secondVoiceWithLang2, + ]; + + setup(() => { + speech.setVoices(voices); + }); + + test('enables the lang for the chosen voice', () => { + chrome.readingMode.getStoredVoice = () => otherVoice.name; + voicePackController.setUserPreferredVoiceFromPrefs(); + assertTrue(voicePackController.isLangEnabled(otherVoice.lang)); + }); + + test('uses the stored voice for this language if there is one', () => { + chrome.readingMode.getStoredVoice = () => otherVoice.name; + + voicePackController.setUserPreferredVoiceFromPrefs(); + + assertTrue(onCurrentVoiceChange); + assertEquals(otherVoice, voicePackController.getCurrentVoice()); + }); + + test('uses the default voice if the stored voice is invalid', () => { + chrome.readingMode.getStoredVoice = () => 'Matt'; + voicePackController.enableLang(langForDefaultVoice); + + voicePackController.setUserPreferredVoiceFromPrefs(); + + assertTrue(onCurrentVoiceChange); + assertEquals(defaultVoice, voicePackController.getCurrentVoice()); + }); + + suite('when there is no stored voice for this language', () => { + setup(() => { + chrome.readingMode.getStoredVoice = () => ''; + }); + + test('uses the default voice for this language', () => { + voicePackController.enableLang(lang1); + voicePackController.setCurrentLanguage(lang1); + + voicePackController.setUserPreferredVoiceFromPrefs(); + + assertTrue(onCurrentVoiceChange); + assertEquals( + defaultVoiceWithLang1, voicePackController.getCurrentVoice()); + }); + + test('uses current voice if there\'s none for this language', () => { + voicePackController.setCurrentLanguage(langWithNoVoices); + voicePackController.setCurrentVoice(otherVoice); + voicePackController.enableLang(otherVoice.lang); + + voicePackController.setUserPreferredVoiceFromPrefs(); + + assertTrue(onCurrentVoiceChange); + assertEquals(otherVoice, voicePackController.getCurrentVoice()); + }); + + test('uses the device default if there\'s no current voice', () => { + voicePackController.setCurrentLanguage(langWithNoVoices); + voicePackController.enableLang(langForDefaultVoice); + voicePackController.enableLang(otherVoice.lang); + + voicePackController.setUserPreferredVoiceFromPrefs(); + + assertTrue(onCurrentVoiceChange); + assertEquals(defaultVoice, voicePackController.getCurrentVoice()); + }); + + test( + 'uses the first voice for this language if there\'s no default', + () => { + voicePackController.enableLang(lang2); + voicePackController.setCurrentLanguage(lang2); + + voicePackController.setUserPreferredVoiceFromPrefs(); + + assertTrue(onCurrentVoiceChange); + assertEquals( + firstVoiceWithLang2, voicePackController.getCurrentVoice()); + }); + }); + }); + + test( + 'updateAutoSelectedVoiceToNaturalVoice with auto selected voice, ' + + 'switches to a Natural voice', + () => { + chrome.readingMode.getStoredVoice = () => ''; + const voice = createSpeechSynthesisVoice({lang: 'ja', name: 'Eagle'}); + const naturalVoice = + createSpeechSynthesisVoice({lang: 'ja', name: 'Horse (Natural)'}); + voicePackController.setCurrentVoice(voice); + voicePackController.setCurrentLanguage(voice.lang); + voicePackController.setAvailableVoices([voice, naturalVoice]); + + voicePackController.updateAutoSelectedVoiceToNaturalVoice(); + + assertEquals(naturalVoice, voicePackController.getCurrentVoice()); + }); + + test( + 'updateAutoSelectedVoiceToNaturalVoice with a user selected voice, does' + + ' not switch to a Natural voice', + () => { + const name = 'Emu'; + chrome.readingMode.getStoredVoice = () => name; + const voice = createSpeechSynthesisVoice({lang: 'ja', name: name}); + const naturalVoice = + createSpeechSynthesisVoice({lang: 'ja', name: 'Ostrich (Natural)'}); + voicePackController.setCurrentVoice(voice); + voicePackController.setCurrentLanguage(voice.lang); + voicePackController.setAvailableVoices([voice, naturalVoice]); + + voicePackController.updateAutoSelectedVoiceToNaturalVoice(); + + assertEquals(voice, voicePackController.getCurrentVoice()); + }); + test('restoreEnabledLanguagesFromPref', () => { const lang1 = 'en-gb'; const lang2 = 'fr'; @@ -336,13 +520,7 @@ VoiceNotificationManager.getInstance().addListener(notificationListener); }); - test('refreshVoicePackStatuses with no languages does nothing', () => { - voicePackController.refreshVoicePackStatuses(); - - assertArrayEquals([], requestInfoLangs); - }); - - test('refreshVoicePackStatuses with languages requests info', () => { + test('updateUnavailableVoiceToDefaultVoice requests info', () => { const lang1 = 'fi'; const lang2 = 'id'; const lang3 = 'da'; @@ -353,21 +531,20 @@ voicePackController.setServerStatus( lang3, mojoVoicePackStatusToVoicePackStatusEnum('kNotInstalled')); - voicePackController.refreshVoicePackStatuses(); + voicePackController.updateUnavailableVoiceToDefaultVoice(); assertArrayEquals([lang1, lang2, lang3], requestInfoLangs); }); test( - 'refreshVoicePackStatuses with languages waits for engine timeout', - () => { + 'updateUnavailableVoiceToDefaultVoice waits for engine timeout', () => { const lang = 'fi'; voicePackController.setServerStatus( lang, mojoVoicePackStatusToVoicePackStatusEnum('kInstalled')); const mockTimer = new MockTimer(); mockTimer.install(); - voicePackController.refreshVoicePackStatuses(); + voicePackController.updateUnavailableVoiceToDefaultVoice(); mockTimer.tick(EXTENSION_RESPONSE_TIMEOUT_MS); mockTimer.uninstall(); @@ -376,6 +553,40 @@ }); test( + 'updateUnavailableVoiceToDefaultVoice does nothing when current voice' + + ' still available', + () => { + const voice = createSpeechSynthesisVoice({lang: 'id', name: 'Dog'}); + voicePackController.enableLang(voice.lang); + voicePackController.setCurrentVoice(voice); + voicePackController.setAvailableVoices([voice]); + onCurrentVoiceChange = false; + + voicePackController.updateUnavailableVoiceToDefaultVoice(); + + assertFalse(onCurrentVoiceChange); + assertEquals(voice, voicePackController.getCurrentVoice()); + }); + + test( + 'updateUnavailableVoiceToDefaultVoice gets default voice when current' + + ' voice unavailable', + () => { + const voice = createSpeechSynthesisVoice({lang: 'id', name: 'Cat'}); + const defaultVoice = + createSpeechSynthesisVoice({lang: 'id', name: 'Komodo'}); + voicePackController.enableLang(voice.lang); + voicePackController.setCurrentVoice(voice); + voicePackController.setAvailableVoices([defaultVoice]); + onCurrentVoiceChange = false; + + voicePackController.updateUnavailableVoiceToDefaultVoice(); + + assertTrue(onCurrentVoiceChange); + assertEquals(defaultVoice, voicePackController.getCurrentVoice()); + }); + + test( 'stopWaitingForSpeechExtension stops waiting for engine timeout', () => { const lang = 'fi'; @@ -392,7 +603,7 @@ const mockTimer = new MockTimer(); mockTimer.install(); - voicePackController.refreshVoicePackStatuses(); + voicePackController.updateUnavailableVoiceToDefaultVoice(); voicePackController.stopWaitingForSpeechExtension(); mockTimer.tick(EXTENSION_RESPONSE_TIMEOUT_MS); mockTimer.uninstall(); @@ -536,4 +747,42 @@ assertArrayEquals([], installedLangs); }); }); + + test('voiceUnavailable selects default voice', () => { + const voice = + createSpeechSynthesisVoice({lang: 'en', name: 'Google Giraffe'}); + speech.setVoices([voice]); + + voicePackController.onVoiceUnavailableError(); + + assertEquals(voice, voicePackController.getCurrentVoice()); + }); + + test( + 'voiceUnavailable default voice is current voice, selects another voice', + () => { + const voice1 = + createSpeechSynthesisVoice({lang: 'en', name: 'Google George'}); + const voice2 = + createSpeechSynthesisVoice({lang: 'en', name: 'Google Connie'}); + voicePackController.setCurrentVoice(voice1); + speech.setVoices([voice1, voice2]); + + voicePackController.onVoiceUnavailableError(); + + assertEquals(voice2, voicePackController.getCurrentVoice()); + }); + + test( + 'voiceUnavailable continues to select default voice if no voices ' + + 'available in language', + () => { + const voice = + createSpeechSynthesisVoice({lang: 'en', name: 'Google Penguin'}); + speech.setVoices([voice]); + + voicePackController.onVoiceUnavailableError(); + + assertEquals(voice, voicePackController.getCurrentVoice()); + }); });
diff --git a/chrome/test/data/webui/side_panel/read_anything/voice_selection_test.ts b/chrome/test/data/webui/side_panel/read_anything/voice_selection_test.ts deleted file mode 100644 index 6750597..0000000 --- a/chrome/test/data/webui/side_panel/read_anything/voice_selection_test.ts +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright 2024 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {BrowserProxy, SpeechBrowserProxyImpl, VoicePackController} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; -import type {AppElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; -import {assertEquals} from 'chrome-untrusted://webui-test/chai_assert.js'; - -import {createApp, createSpeechSynthesisVoice, setVoices} from './common.js'; -import {FakeReadingMode} from './fake_reading_mode.js'; -import {TestColorUpdaterBrowserProxy} from './test_color_updater_browser_proxy.js'; -import {TestSpeechBrowserProxy} from './test_speech_browser_proxy.js'; - -suite('Automatic voice selection', () => { - const defaultLang = 'en-us'; - const pageLang = 'en'; - const differentLang = 'zh'; - - const firstVoiceWithLang = createSpeechSynthesisVoice({ - lang: defaultLang, - name: 'Google Kristi', - }); - const secondVoiceWithLang = - createSpeechSynthesisVoice({lang: defaultLang, name: 'Google Lauren'}); - const defaultVoiceForDifferentLang = createSpeechSynthesisVoice({ - lang: differentLang, - name: 'Google Eitan', - default: true, - }); - const voices = [ - firstVoiceWithLang, - secondVoiceWithLang, - defaultVoiceForDifferentLang, - ]; - - let app: AppElement; - let speech: TestSpeechBrowserProxy; - - function addNaturalVoices() { - setVoices( - app, speech, - voices.concat( - createSpeechSynthesisVoice( - {lang: defaultLang, name: 'Google Wall-e (Natural)'}), - createSpeechSynthesisVoice( - {lang: defaultLang, name: 'Google Andy (Natural)'}), - )); - } - - setup(async () => { - // Clearing the DOM should always be done first. - document.body.innerHTML = window.trustedTypes!.emptyHTML; - BrowserProxy.setInstance(new TestColorUpdaterBrowserProxy()); - const readingMode = new FakeReadingMode(); - chrome.readingMode = readingMode as unknown as typeof chrome.readingMode; - chrome.readingMode.baseLanguageForSpeech = pageLang; - chrome.readingMode.isReadAloudEnabled = true; - speech = new TestSpeechBrowserProxy(); - SpeechBrowserProxyImpl.setInstance(speech); - VoicePackController.setInstance(new VoicePackController()); - - app = await createApp(); - setVoices(app, speech, voices); - - // Initializes some class variables needed for voice selection logic - app.restoreEnabledLanguagesFromPref(); - }); - - test( - 'with no user selected voices, switches to a Natural voice if it later ' + - 'becomes available', - () => { - chrome.readingMode.getStoredVoice = () => ''; - app.selectPreferredVoice(); - assertEquals(firstVoiceWithLang, app.getSpeechSynthesisVoice()); - - addNaturalVoices(); - - assertEquals( - 'Google Wall-e (Natural)', app.getSpeechSynthesisVoice()?.name); - }); - - test( - 'with a user selected voices, does not switch to a Natural voice if it ' + - 'later becomes available', - () => { - chrome.readingMode.getStoredVoice = () => secondVoiceWithLang.name; - app.selectPreferredVoice(); - assertEquals(secondVoiceWithLang, app.getSpeechSynthesisVoice()); - - addNaturalVoices(); - - assertEquals(secondVoiceWithLang, app.getSpeechSynthesisVoice()); - }); -});
diff --git a/chrome/test/data/webui/side_panel/read_anything/word_boundaries_speech_test.ts b/chrome/test/data/webui/side_panel/read_anything/word_boundaries_speech_test.ts index 0100e3c..bd94ce2 100644 --- a/chrome/test/data/webui/side_panel/read_anything/word_boundaries_speech_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/word_boundaries_speech_test.ts
@@ -14,6 +14,7 @@ let app: AppElement; let wordBoundaries: WordBoundaries; let speechController: SpeechController; + let voicePackController: VoicePackController; // root htmlTag='#document' id=1 // ++link htmlTag='a' url='http://www.google.com' id=2 @@ -65,7 +66,8 @@ chrome.readingMode.onConnected = () => {}; const speech = new TestSpeechBrowserProxy(); SpeechBrowserProxyImpl.setInstance(speech); - VoicePackController.setInstance(new VoicePackController()); + voicePackController = new VoicePackController(); + VoicePackController.setInstance(voicePackController); speechController = new SpeechController(); SpeechController.setInstance(speechController); @@ -106,7 +108,7 @@ const state: WordBoundaryState = wordBoundaries.state; assertTrue(wordBoundaries.hasBoundaries()); - assertTrue(!!app.getSpeechSynthesisVoice()); + assertTrue(!!voicePackController.getCurrentVoice()); assertEquals(10, state.speechUtteranceStartIndex); assertEquals(0, state.previouslySpokenIndex); assertEquals(5, state.speechUtteranceLength);
diff --git a/chrome/test/data/webui/side_panel/read_anything/word_highlighting_test.ts b/chrome/test/data/webui/side_panel/read_anything/word_highlighting_test.ts index 4148bcd..c20466c 100644 --- a/chrome/test/data/webui/side_panel/read_anything/word_highlighting_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/word_highlighting_test.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. import type {AppElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; -import {PauseActionSource, SpeechBrowserProxyImpl, SpeechController, ToolbarEvent, WordBoundaries} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; +import {PauseActionSource, ReadAloudHighlighter, SpeechBrowserProxyImpl, SpeechController, ToolbarEvent, VoicePackController, WordBoundaries} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js'; import {createApp, createSpeechSynthesisVoice, emitEvent, playFromSelectionWithMockTimer, setSimpleAxTreeWithText} from './common.js'; @@ -67,9 +67,12 @@ SpeechBrowserProxyImpl.setInstance(speech); speechController = new SpeechController(); SpeechController.setInstance(speechController); + VoicePackController.setInstance(new VoicePackController()); + wordBoundaries = new WordBoundaries(); + WordBoundaries.setInstance(wordBoundaries); + ReadAloudHighlighter.setInstance(new ReadAloudHighlighter()); app = await createApp(); - wordBoundaries = WordBoundaries.getInstance(); chrome.readingMode.setContentForTesting(axTree, [2, 4]); chrome.readingMode.onSpeechRateChange(1); });
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index 67198ae..c915f3c 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -509,16 +509,6 @@ prefs->viewport_style = blink::mojom::ViewportStyle::kTelevision; #endif // BUILDFLAG(IS_ANDROID) - // Disable WebSQL databases by default. - prefs->databases_enabled = false; - if (web_contents) { - chromecast::CastWebContents* cast_web_contents = - chromecast::CastWebContents::FromWebContents(web_contents); - if (cast_web_contents && cast_web_contents->is_websql_enabled()) { - prefs->databases_enabled = true; - } - } - prefs->preferred_color_scheme = static_cast<blink::mojom::PreferredColorScheme>( CastBrowserProcess::GetInstance()->pref_service()->GetInteger(
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 8fc4e55..1fe9cf60 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -16276.0.0-1068704 \ No newline at end of file +16277.0.0-1068716 \ No newline at end of file
diff --git a/chromeos/ash/components/kcer/kcer_token_impl.cc b/chromeos/ash/components/kcer/kcer_token_impl.cc index f4deca5..94d4f69 100644 --- a/chromeos/ash/components/kcer/kcer_token_impl.cc +++ b/chromeos/ash/components/kcer/kcer_token_impl.cc
@@ -301,52 +301,6 @@ return DigestWithPrefix(std::vector<uint8_t>(digest, digest + digest_len)); } -// The EC signature returned by Chaps is a concatenation of two numbers r and s -// (see PKCS#11 v2.40: 2.3.1 EC Signatures). Kcer needs to return it as a DER -// encoding of the following ASN.1 notations: -// Ecdsa-Sig-Value ::= SEQUENCE { -// r INTEGER, -// s INTEGER -// } -// (according to the RFC 8422, Section 5.4). -// This function reencodes the signature. -base::expected<std::vector<uint8_t>, Error> ReencodeEcSignature( - base::span<const uint8_t> signature) { - if (signature.size() % 2 != 0) { - return base::unexpected(Error::kFailedToSignBadSignatureLength); - } - size_t order_size_bytes = signature.size() / 2; - base::span<const uint8_t> r_bytes = signature.first(order_size_bytes); - base::span<const uint8_t> s_bytes = signature.subspan(order_size_bytes); - - // Convert the RAW ECDSA signature to a DER-encoded ECDSA-Sig-Value. - bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new()); - if (!sig || !BN_bin2bn(r_bytes.data(), r_bytes.size(), sig->r) || - !BN_bin2bn(s_bytes.data(), s_bytes.size(), sig->s)) { - return base::unexpected(Error::kFailedToDerEncode); - } - - std::vector<uint8_t> result_signature; - - { - const int len = i2d_ECDSA_SIG(sig.get(), nullptr); - if (len <= 0) { - return base::unexpected(Error::kFailedToSignBadSignatureLength); - } - result_signature.resize(len); - } - - { - uint8_t* ptr = result_signature.data(); - const int len = i2d_ECDSA_SIG(sig.get(), &ptr); - if (len <= 0) { - return base::unexpected(Error::kFailedToDerEncode); - } - } - - return result_signature; -} - std::vector<uint8_t> GetPssSignParams(SigningScheme kcer_signing_scheme) { chromeos::PKCS11_CK_RSA_PKCS_PSS_PARAMS pss_params; @@ -1736,7 +1690,7 @@ uint64_t mechanism = SigningSchemeToPkcs11Mechanism(task.signing_scheme); if (mechanism == chromeos::PKCS11_CKM_ECDSA) { base::expected<std::vector<uint8_t>, Error> reencoded_signature = - ReencodeEcSignature(std::move(signature)); + ReencodeEcSignatureAsAsn1(std::move(signature)); if (!reencoded_signature.has_value()) { return std::move(task.callback) .Run(base::unexpected(reencoded_signature.error()));
diff --git a/chromeos/ash/components/kcer/kcer_utils.cc b/chromeos/ash/components/kcer/kcer_utils.cc index 7c9efe3..b76494f 100644 --- a/chromeos/ash/components/kcer/kcer_utils.cc +++ b/chromeos/ash/components/kcer/kcer_utils.cc
@@ -44,4 +44,41 @@ return result; } +base::expected<std::vector<uint8_t>, Error> ReencodeEcSignatureAsAsn1( + base::span<const uint8_t> signature) { + if (signature.size() % 2 != 0) { + return base::unexpected(Error::kFailedToSignBadSignatureLength); + } + size_t order_size_bytes = signature.size() / 2; + base::span<const uint8_t> r_bytes = signature.first(order_size_bytes); + base::span<const uint8_t> s_bytes = signature.subspan(order_size_bytes); + + // Convert the RAW ECDSA signature to a DER-encoded ECDSA-Sig-Value. + bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new()); + if (!sig || !BN_bin2bn(r_bytes.data(), r_bytes.size(), sig->r) || + !BN_bin2bn(s_bytes.data(), s_bytes.size(), sig->s)) { + return base::unexpected(Error::kFailedToDerEncode); + } + + std::vector<uint8_t> result_signature; + + { + const int len = i2d_ECDSA_SIG(sig.get(), nullptr); + if (len <= 0) { + return base::unexpected(Error::kFailedToSignBadSignatureLength); + } + result_signature.resize(len); + } + + { + uint8_t* ptr = result_signature.data(); + const int len = i2d_ECDSA_SIG(sig.get(), &ptr); + if (len <= 0) { + return base::unexpected(Error::kFailedToDerEncode); + } + } + + return result_signature; +} + } // namespace kcer
diff --git a/chromeos/ash/components/kcer/kcer_utils.h b/chromeos/ash/components/kcer/kcer_utils.h index 9f3e7852..cede43a 100644 --- a/chromeos/ash/components/kcer/kcer_utils.h +++ b/chromeos/ash/components/kcer/kcer_utils.h
@@ -14,6 +14,19 @@ std::vector<SigningScheme> GetSupportedSigningSchemes(bool supports_pss, KeyType key_type); +// The EC signature returned by Chaps is a concatenation of two numbers r and s +// (see PKCS#11 v2.40: 2.3.1 EC Signatures). Kcer needs to return it as a DER +// encoding of the following ASN.1 notations: +// Ecdsa-Sig-Value ::= SEQUENCE { +// r INTEGER, +// s INTEGER +// } +// (according to the RFC 8422, Section 5.4). +// This function reencodes the signature. +COMPONENT_EXPORT(KCER) +base::expected<std::vector<uint8_t>, Error> ReencodeEcSignatureAsAsn1( + base::span<const uint8_t> signature); + } // namespace kcer #endif // CHROMEOS_ASH_COMPONENTS_KCER_KCER_UTILS_H_
diff --git a/chromeos/ash/experiences/arc/compat_mode/arc_splash_screen_dialog_view.cc b/chromeos/ash/experiences/arc/compat_mode/arc_splash_screen_dialog_view.cc index b83053a0..7de5c38 100644 --- a/chromeos/ash/experiences/arc/compat_mode/arc_splash_screen_dialog_view.cc +++ b/chromeos/ash/experiences/arc/compat_mode/arc_splash_screen_dialog_view.cc
@@ -160,7 +160,7 @@ bool is_for_unresizable) : anchor_(anchor), close_callback_(std::move(close_callback)) { // Setup delegate. - set_background_color(cros_tokens::kCrosSysDialogContainer); + SetBackgroundColor(cros_tokens::kCrosSysDialogContainer); SetArrow(views::BubbleBorder::Arrow::BOTTOM_CENTER); SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone)); set_parent_window(parent);
diff --git a/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.cc b/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.cc index cb0bb99..aca50c2 100644 --- a/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.cc +++ b/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.cc
@@ -289,7 +289,7 @@ delegate_view->SetAccessibleWindowRole(ax::mojom::Role::kMenu); // Clear root view's background color. We use the color in // `background_view`. - delegate_view->set_background_color(SK_ColorTRANSPARENT); + delegate_view->SetBackgroundColor(SK_ColorTRANSPARENT); // Setup view. delegate_view->SetUseDefaultFillLayout(true);
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt index 97350fff..bd961538 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.7161.0-r1-redacted.afdo.xz +chromeos-chrome-arm-none-138-7137.0-1746411594-benchmark-138.0.7166.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt index 4199d11..d7ce078 100644 --- a/chromeos/profiles/atom.afdo.newest.txt +++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-atom-137-7103.40-1745806155-benchmark-138.0.7155.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-atom-138-7137.0-1746412216-benchmark-138.0.7166.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt index 4ab69b6..e78d7ba 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.7164.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-bigcore-138-7137.0-1746414666-benchmark-138.0.7166.0-r1-redacted.afdo.xz
diff --git a/clank b/clank index 4326f34..72050536 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 4326f348545fb5ef5cbb59389e7e3a903d2320eb +Subproject commit 72050536a13f233b345a2f22647ff5c1a289b42f
diff --git a/components/BUILD.gn b/components/BUILD.gn index 5c59002..0bb5e83 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -730,7 +730,7 @@ deps += [ "//components/guest_view/browser:unit_tests" ] } - if (!is_android && !is_ios && (!is_fuchsia || !optimize_for_size)) { + if (!is_android && !is_ios && !is_fuchsia) { deps += [ "//components/autofill_ai/core/browser:unit_tests" ] }
diff --git a/components/android_autofill/browser/android_autofill_features.cc b/components/android_autofill/browser/android_autofill_features.cc index f1afcd1..018d922 100644 --- a/components/android_autofill/browser/android_autofill_features.cc +++ b/components/android_autofill/browser/android_autofill_features.cc
@@ -23,7 +23,8 @@ const base::Feature* const kFeaturesExposedToJava[] = { &kAndroidAutofillDeprecateAccessibilityApi, &kAutofillVirtualViewStructureAndroidInCct, - &kAndroidAutofillLazyFrameworkWrapper}; + &kAndroidAutofillLazyFrameworkWrapper, + &kAutofillVirtualViewStructureAndroidPasskeyLongPress}; } // namespace
diff --git a/components/android_autofill/browser/android_autofill_provider.cc b/components/android_autofill/browser/android_autofill_provider.cc index 410d556..fb3d4ab 100644 --- a/components/android_autofill/browser/android_autofill_provider.cc +++ b/components/android_autofill/browser/android_autofill_provider.cc
@@ -388,6 +388,26 @@ : PrefillRequestState::kRequestSentStructureNotProvided); } +bool AndroidAutofillProvider::HasPasskeyRequest() { + if (!manager_ || !form_ || + !GetCredManDelegate(GetRenderFrameHost(manager_.get()))) { + return false; + } + const FormFieldData* field = + form_->form().FindFieldByGlobalId(current_field_.id); + return field && AllowCredManOnField(*field); +} + +void AndroidAutofillProvider::OnTriggerPasskeyRequest() { + if (manager_) { + if (content::RenderFrameHost* rfh = GetRenderFrameHost(manager_.get())) { + if (WebAuthnCredManDelegate* delegate = GetCredManDelegate(rfh)) { + delegate->TriggerCredManUi(RequestPasswords(false)); + } + } + } +} + void AndroidAutofillProvider::OnTextFieldValueChanged( AndroidAutofillManager* manager, const FormData& form,
diff --git a/components/android_autofill/browser/android_autofill_provider.h b/components/android_autofill/browser/android_autofill_provider.h index f0309a9..9dffe6d 100644 --- a/components/android_autofill/browser/android_autofill_provider.h +++ b/components/android_autofill/browser/android_autofill_provider.h
@@ -127,6 +127,8 @@ const gfx::RectF& bounds) override; void OnShowBottomSheetResult(bool is_shown, bool provided_autofill_structure) override; + bool HasPasskeyRequest() override; + void OnTriggerPasskeyRequest() override; // content::WebContentsObserver: void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
diff --git a/components/android_autofill/browser/android_autofill_provider_bridge.h b/components/android_autofill/browser/android_autofill_provider_bridge.h index 65ac651..e270931 100644 --- a/components/android_autofill/browser/android_autofill_provider_bridge.h +++ b/components/android_autofill/browser/android_autofill_provider_bridge.h
@@ -41,6 +41,14 @@ const gfx::RectF& bounds) = 0; virtual void OnShowBottomSheetResult(bool is_shown, bool provided_autofill_structure) = 0; + + // Asks whether passkeys options are available that should be triggered when + // `OnTriggerPasskeyRequest` is called. + virtual bool HasPasskeyRequest() = 0; + + // The user explicitly requested passkeys to be shown. Even if no passkeys + // are available, call the framework to allow using fallback entry points. + virtual void OnTriggerPasskeyRequest() = 0; }; // A helper struct to reference a field in a form.
diff --git a/components/android_autofill/browser/android_autofill_provider_bridge_impl.cc b/components/android_autofill/browser/android_autofill_provider_bridge_impl.cc index f2252d2..9c3949c 100644 --- a/components/android_autofill/browser/android_autofill_provider_bridge_impl.cc +++ b/components/android_autofill/browser/android_autofill_provider_bridge_impl.cc
@@ -234,6 +234,10 @@ java_ref_.reset(); } +jboolean AndroidAutofillProviderBridgeImpl::HasPasskeyRequest(JNIEnv* env) { + return delegate_->HasPasskeyRequest(); +} + void AndroidAutofillProviderBridgeImpl::OnAutofillAvailable(JNIEnv* env) { delegate_->OnAutofillAvailable(); } @@ -260,4 +264,9 @@ jboolean provided_autofill_structure) { delegate_->OnShowBottomSheetResult(is_shown, provided_autofill_structure); } + +void AndroidAutofillProviderBridgeImpl::OnTriggerPasskeyRequest(JNIEnv* env) { + delegate_->OnTriggerPasskeyRequest(); +} + } // namespace autofill
diff --git a/components/android_autofill/browser/android_autofill_provider_bridge_impl.h b/components/android_autofill/browser/android_autofill_provider_bridge_impl.h index 8333e98..7829fb6 100644 --- a/components/android_autofill/browser/android_autofill_provider_bridge_impl.h +++ b/components/android_autofill/browser/android_autofill_provider_bridge_impl.h
@@ -52,6 +52,9 @@ // about to be destroyed. void DetachFromJavaAutofillProvider(JNIEnv* env); + // Asks the `Delegate` whether passkeys options are available. + jboolean HasPasskeyRequest(JNIEnv* env); + // Informs the `Delegate` that the linked form should be sent to the renderer // for filling. Invoked when the user has accepted Autofill. void OnAutofillAvailable(JNIEnv* env); @@ -78,6 +81,9 @@ jboolean is_shown, jboolean provided_autofill_structure); + // Informs the `Delegate` that the user explicitly requested passkeys options. + void OnTriggerPasskeyRequest(JNIEnv* env); + private: // The delegate of the bridge. raw_ref<Delegate> delegate_;
diff --git a/components/android_autofill/browser/android_autofill_provider_unittest.cc b/components/android_autofill/browser/android_autofill_provider_unittest.cc index 70fc272f..6c34acf 100644 --- a/components/android_autofill/browser/android_autofill_provider_unittest.cc +++ b/components/android_autofill/browser/android_autofill_provider_unittest.cc
@@ -1002,6 +1002,22 @@ FocusFormField(webauthn_email_field()); } +TEST_F(AndroidAutofillProviderWithCredManTest, OfferLongPressOption) { + FocusFormField(webauthn_email_field()); + EXPECT_TRUE(provider_bridge_delegate().HasPasskeyRequest()); +} + +TEST_F(AndroidAutofillProviderWithCredManTest, + OfferNoLongPressOptionWithoutAnnotation) { + FocusFormField(non_webauthn_password_field()); + EXPECT_FALSE(provider_bridge_delegate().HasPasskeyRequest()); +} + +TEST_F(AndroidAutofillProviderWithCredManTest, + OfferNoLongPressOptionWithoutField) { + EXPECT_FALSE(provider_bridge_delegate().HasPasskeyRequest()); +} + TEST_F(AndroidAutofillProviderWithCredManTest, NotifyFocusOnCredManError) { EXPECT_CALL(cred_man_delegate(), TriggerCredManUi); base::RepeatingCallback<void(bool)> completed_callback;
diff --git a/components/android_autofill/browser/java/src/org/chromium/components/autofill/AndroidAutofillFeatures.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AndroidAutofillFeatures.java index 179e3f4..ea15267 100644 --- a/components/android_autofill/browser/java/src/org/chromium/components/autofill/AndroidAutofillFeatures.java +++ b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AndroidAutofillFeatures.java
@@ -23,9 +23,11 @@ "AndroidAutofillDeprecateAccessibilityApi"; public static final String ANDROID_AUTOFILL_LAZY_FRAMEWORK_WRAPPER_NAME = "AndroidAutofillLazyFrameworkWrapper"; - public static final String ANDROID_AUTOFILL_VIRTUAL_VIEW_STRUCTURE_ANDROID_IN_CCT_NAME = "AutofillVirtualViewStructureAndroidInCct"; + public static final String ANDROID_AUTOFILL_VIRTUAL_VIEW_STRUCTURE_PASSKEY_LONG_PRESS_NAME = + "AutofillVirtualViewStructureAndroidPasskeyLongPress"; + public static final AndroidAutofillFeatures ANDROID_AUTOFILL_DEPRECATE_ACCESSIBILITY_API = new AndroidAutofillFeatures(0, ANDROID_AUTOFILL_DEPRECATE_ACCESSIBILITY_API_NAME); public static final AndroidAutofillFeatures @@ -34,6 +36,11 @@ 1, ANDROID_AUTOFILL_VIRTUAL_VIEW_STRUCTURE_ANDROID_IN_CCT_NAME); public static final AndroidAutofillFeatures ANDROID_AUTOFILL_LAZY_FRAMEWORK_WRAPPER = new AndroidAutofillFeatures(2, ANDROID_AUTOFILL_LAZY_FRAMEWORK_WRAPPER_NAME); + public static final AndroidAutofillFeatures + ANDROID_AUTOFILL_VIRTUAL_VIEW_STRUCTURE_PASSKEY_LONG_PRESS = + new AndroidAutofillFeatures( + 3, ANDROID_AUTOFILL_VIRTUAL_VIEW_STRUCTURE_PASSKEY_LONG_PRESS_NAME); + private final int mOrdinal; private AndroidAutofillFeatures(int ordinal, String name) {
diff --git a/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProvider.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProvider.java index 2cc1a4e6..74a1ed83 100644 --- a/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProvider.java +++ b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProvider.java
@@ -224,6 +224,20 @@ && !getAutofillManagerWrapper().isAutofillInputUiShowing(); } + public boolean shouldOfferPasskeyEntry() { + if (!AndroidAutofillFeatures.ANDROID_AUTOFILL_VIRTUAL_VIEW_STRUCTURE_PASSKEY_LONG_PRESS + .isEnabled()) { + return false; + } + return AutofillProviderJni.get().hasPasskeyRequest(mNativeAutofillProvider); + } + + public void triggerPasskeyRequest() { + if (mNativeAutofillProvider != 0) { + AutofillProviderJni.get().onTriggerPasskeyRequest(mNativeAutofillProvider); + } + } + public void queryAutofillSuggestion() { if (shouldQueryAutofillSuggestion()) { FocusField focusField = mRequest.getFocusField(); @@ -841,6 +855,8 @@ void detachFromJavaAutofillProvider(long nativeAndroidAutofillProviderBridgeImpl); + boolean hasPasskeyRequest(long nativeAndroidAutofillProviderBridgeImpl); + void onAutofillAvailable(long nativeAndroidAutofillProviderBridgeImpl); void onAcceptDataListSuggestion( @@ -859,5 +875,7 @@ long nativeAndroidAutofillProviderBridgeImpl, boolean isShown, boolean providedAutofillStructure); + + void onTriggerPasskeyRequest(long nativeAndroidAutofillProviderBridgeImpl); } }
diff --git a/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillSelectionMenuItemHelper.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillSelectionMenuItemHelper.java index 6d9063ea..f273e982 100644 --- a/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillSelectionMenuItemHelper.java +++ b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillSelectionMenuItemHelper.java
@@ -39,17 +39,28 @@ public List<SelectionMenuItem> getAdditionalItems() { List<SelectionMenuItem> autofillItems = new ArrayList<>(); - if (mAutofillMenuItemTitle == 0 || !mAutofillProvider.shouldQueryAutofillSuggestion()) { - return autofillItems; + if (mAutofillProvider.shouldOfferPasskeyEntry()) { + autofillItems.add( + new SelectionMenuItem.Builder("Use Passkey") + .setId(Menu.NONE) + .setOrderInCategory(Menu.FIRST) + .setShowAsActionFlags( + MenuItem.SHOW_AS_ACTION_ALWAYS + | MenuItem.SHOW_AS_ACTION_WITH_TEXT) + .setClickListener(v -> mAutofillProvider.triggerPasskeyRequest()) + .build()); } - autofillItems.add( - new SelectionMenuItem.Builder(mAutofillMenuItemTitle) - .setId(android.R.id.autofill) - .setOrderInCategory(Menu.CATEGORY_SECONDARY) - .setShowAsActionFlags( - MenuItem.SHOW_AS_ACTION_NEVER | MenuItem.SHOW_AS_ACTION_WITH_TEXT) - .setClickListener(v -> mAutofillProvider.queryAutofillSuggestion()) - .build()); + if (mAutofillMenuItemTitle != 0 && mAutofillProvider.shouldQueryAutofillSuggestion()) { + autofillItems.add( + new SelectionMenuItem.Builder(mAutofillMenuItemTitle) + .setId(android.R.id.autofill) + .setOrderInCategory(Menu.CATEGORY_SECONDARY) + .setShowAsActionFlags( + MenuItem.SHOW_AS_ACTION_NEVER + | MenuItem.SHOW_AS_ACTION_WITH_TEXT) + .setClickListener(v -> mAutofillProvider.queryAutofillSuggestion()) + .build()); + } return autofillItems; } }
diff --git a/components/android_autofill/browser/junit/src/org/chromium/components/autofill/AutofillProviderTest.java b/components/android_autofill/browser/junit/src/org/chromium/components/autofill/AutofillProviderTest.java index e2b4c1d0..665e2836 100644 --- a/components/android_autofill/browser/junit/src/org/chromium/components/autofill/AutofillProviderTest.java +++ b/components/android_autofill/browser/junit/src/org/chromium/components/autofill/AutofillProviderTest.java
@@ -55,7 +55,8 @@ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) @Features.EnableFeatures({ - AndroidAutofillFeatures.ANDROID_AUTOFILL_VIRTUAL_VIEW_STRUCTURE_ANDROID_IN_CCT_NAME + AndroidAutofillFeatures.ANDROID_AUTOFILL_VIRTUAL_VIEW_STRUCTURE_ANDROID_IN_CCT_NAME, + AndroidAutofillFeatures.ANDROID_AUTOFILL_VIRTUAL_VIEW_STRUCTURE_PASSKEY_LONG_PRESS_NAME }) public class AutofillProviderTest { private static final float EXPECTED_DIP_SCALE = 2; @@ -391,6 +392,18 @@ verify(mNativeMock, never()).onShowBottomSheetResult(anyLong(), anyBoolean(), anyBoolean()); } + @Test + public void testCallsNativeToTriggerPasskeys() { + mAutofillProvider.triggerPasskeyRequest(); + verify(mNativeMock).onTriggerPasskeyRequest(eq(mMockedNativeAndroidAutofillProvider)); + } + + @Test + public void testCallsNativeToProvidePasskeyAvailability() { + mAutofillProvider.shouldOfferPasskeyEntry(); + verify(mNativeMock).hasPasskeyRequest(eq(mMockedNativeAndroidAutofillProvider)); + } + FormData setupPrefillRequest(int sessionId) { FormFieldDataBuilder field1Builder = new FormFieldDataBuilder(); field1Builder.mBounds =
diff --git a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html index 6b8c6947..6cda11f 100644 --- a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html +++ b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
@@ -326,6 +326,7 @@ <span id="reset-cache-fake-button" class="fake-button" style="display: none">Reset Cache</span> <span id="download-fake-button" class="fake-button">Download Log</span> <span id="download-submitted-forms-json-data-fake-button" class="fake-button" style="display: none">Download submitted forms JSON data</span> + <span id="set-dom-node-id" class="fake-button" style="display: none">Set DOM node id attribute</span> <div id="settings-checkbox-placeholder"></div> <span id="reset-upm-eviction-fake-button" class="fake-button" style="display: none">Reset UPM eviction</span> <div id="tab-links" style="display:none">Tabs: </div>
diff --git a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.ts b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.ts index e374833..8971155 100644 --- a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.ts +++ b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.ts
@@ -262,6 +262,7 @@ setUpSettingCheckboxe(); setUpMarker(); setUpSubmittedFormsJSONDataDownload(); + setUpButtonForDomNodeIdCapture(); setUpDownload('autofill'); if (autofillAiEnabled) { addAutofillTabs(); @@ -526,6 +527,16 @@ // </if> } +function setUpButtonForDomNodeIdCapture() { + // <if expr="not is_android and not is_ios" > + const button = document.getElementById('set-dom-node-id')!; + button.style.display = 'inline'; + button.addEventListener('click', () => { + chrome.send('setDomNodeId'); + }); + // </if> +} + interface CheckboxInfo { id: string; label?: string;
diff --git a/components/autofill/core/browser/data_model/addresses/autofill_profile.cc b/components/autofill/core/browser/data_model/addresses/autofill_profile.cc index 6acdcd8..d70fb44 100644 --- a/components/autofill/core/browser/data_model/addresses/autofill_profile.cc +++ b/components/autofill/core/browser/data_model/addresses/autofill_profile.cc
@@ -1254,14 +1254,6 @@ return account_profile; } -AutofillProfile AutofillProfile::DowngradeToAccountProfile() const { - CHECK(record_type() == RecordType::kAccountHome || - record_type() == RecordType::kAccountWork); - AutofillProfile account_profile = *this; - account_profile.record_type_ = RecordType::kAccount; - return account_profile; -} - FieldTypeSet AutofillProfile::FindInaccessibleProfileValues() const { FieldTypeSet inaccessible_fields; const std::string stored_country =
diff --git a/components/autofill/core/browser/data_model/addresses/autofill_profile.h b/components/autofill/core/browser/data_model/addresses/autofill_profile.h index ec5289b..e621a15 100644 --- a/components/autofill/core/browser/data_model/addresses/autofill_profile.h +++ b/components/autofill/core/browser/data_model/addresses/autofill_profile.h
@@ -346,11 +346,6 @@ // set. AutofillProfile ConvertToAccountProfile() const; - // Converts a kAccount(Home|Work) address back to a regular kAccount address. - // This is necessary to resolve inconsistencies between server and client, to - // ensure that only a single H/W address can exist each. - AutofillProfile DowngradeToAccountProfile() const; - // Checks for non-empty setting-inaccessible fields and returns all that were // found. FieldTypeSet FindInaccessibleProfileValues() const;
diff --git a/components/autofill/core/browser/filling/form_autofill_history.cc b/components/autofill/core/browser/filling/form_autofill_history.cc index 4096064..1200814 100644 --- a/components/autofill/core/browser/filling/form_autofill_history.cc +++ b/components/autofill/core/browser/filling/form_autofill_history.cc
@@ -4,6 +4,8 @@ #include "components/autofill/core/browser/filling/form_autofill_history.h" +#include <algorithm> + #include "base/types/zip.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/field_types.h" @@ -37,23 +39,11 @@ FormAutofillHistory::FieldFillingEntry::FieldFillingEntry(FieldFillingEntry&&) = default; -const FormAutofillHistory::FieldFillingEntry& -FormAutofillHistory::FillOperation::GetFieldFillingEntry( - FieldGlobalId field_id) const { - auto it = iterator_->field_filling_entries.find(field_id); - CHECK(it != iterator_->field_filling_entries.end()); - return it->second; -} - -FormAutofillHistory::FormFillingEntry::FormFillingEntry() = default; - -FormAutofillHistory::FormFillingEntry::~FormFillingEntry() = default; - FormAutofillHistory::FormAutofillHistory() = default; FormAutofillHistory::~FormAutofillHistory() = default; -void FormAutofillHistory::AddFormFillEntry( +void FormAutofillHistory::AddFormFillingEntry( base::span<const FormFieldData* const> filled_fields, base::span<const AutofillField* const> filled_autofill_fields, FillingProduct filling_product, @@ -63,12 +53,10 @@ // - If the original fill had `filled_fields.size() > // kMaxStorableFieldFillHistory`, then `history_` might be empty. // - If a previous fill had `filled_fields.empty()`, we could save memory. - if (history_.empty() || - (!is_refill && !history_.front().field_filling_entries.empty())) { + if (history_.empty() || (!is_refill && !history_.front().empty())) { history_.emplace_front(); } - history_.front().filling_product = filling_product; for (const auto [field, autofill_field] : base::zip(filled_fields, filled_autofill_fields)) { // During refills, a field that was previously filled in the original @@ -78,7 +66,6 @@ // this is what happened from a user's perspective. size_ += history_.front() - .field_filling_entries .emplace(field->global_id(), FieldFillingEntry( field->value(), field->is_autofilled(), @@ -96,26 +83,35 @@ } // Drop the last history entry while the history size exceeds the limit. while (size_ > kMaxStorableFieldFillHistory) { - EraseFormFillEntry(FillOperation(--history_.end())); + EraseFormFillEntry(--history_.end()); } } -void FormAutofillHistory::EraseFormFillEntry(FillOperation fill_operation) { - size_ -= fill_operation.iterator_->field_filling_entries.size(); - history_.erase(fill_operation.iterator_); +void FormAutofillHistory::EraseFieldFillingEntry( + std::list<FormFillingEntry>::iterator fill_operation, + FieldGlobalId field_id) { + fill_operation->erase(field_id); + if (fill_operation->empty()) { + EraseFormFillEntry(fill_operation); + } } -FormAutofillHistory::FillOperation -FormAutofillHistory::GetLastFillingOperationForField( - FieldGlobalId field_id) const { - return FillOperation(std::ranges::find_if( - history_, [&field_id](const FormFillingEntry& operation) { - return operation.field_filling_entries.contains(field_id); - })); +void FormAutofillHistory::EraseFormFillEntry( + std::list<FormFillingEntry>::iterator filling_entry) { + size_ -= filling_entry->size(); + history_.erase(filling_entry); +} + +std::list<FormAutofillHistory::FormFillingEntry>::iterator +FormAutofillHistory::GetLastFormFillingEntryForField(FieldGlobalId field_id) { + return std::ranges::find_if(history_, + [&field_id](const FormFillingEntry& operation) { + return operation.contains(field_id); + }); } bool FormAutofillHistory::HasHistory(FieldGlobalId field_id) const { - return GetLastFillingOperationForField(field_id).iterator_ != history_.end(); + return GetLastFormFillingEntryForField(field_id) != history_.end(); } void FormAutofillHistory::Reset() {
diff --git a/components/autofill/core/browser/filling/form_autofill_history.h b/components/autofill/core/browser/filling/form_autofill_history.h index 9e9fc557..bfa8f3a 100644 --- a/components/autofill/core/browser/filling/form_autofill_history.h +++ b/components/autofill/core/browser/filling/form_autofill_history.h
@@ -75,36 +75,7 @@ bool ignore_is_autofilled; }; - struct FormFillingEntry { - FormFillingEntry(); - ~FormFillingEntry(); - - FillingProduct filling_product = FillingProduct::kNone; - std::map<FieldGlobalId, FieldFillingEntry> field_filling_entries = {}; - }; - - class FillOperation { - public: - // Returns the field value and autofill state stored in history for - // `field_id`. Assumes the underlying map contains a entry with key - // `field_id`. - const FieldFillingEntry& GetFieldFillingEntry(FieldGlobalId field_id) const; - - FillingProduct get_filling_product() const { - return iterator_->filling_product; - } - - friend bool operator==(const FillOperation& lhs, - const FillOperation& rhs) = default; - - private: - friend class FormAutofillHistory; - - explicit FillOperation(std::list<FormFillingEntry>::const_iterator iterator) - : iterator_(iterator) {} - - std::list<FormFillingEntry>::const_iterator iterator_; - }; + using FormFillingEntry = std::map<FieldGlobalId, FieldFillingEntry>; FormAutofillHistory(); @@ -118,18 +89,30 @@ // FormFieldData's are needed to get the most recent value of a field. // AutofillField's are needed to get the type of a field. // TODO(crbug.com/40232021): Only pass AutofillFields. - void AddFormFillEntry( + void AddFormFillingEntry( base::span<const FormFieldData* const> filled_fields, base::span<const AutofillField* const> filled_autofill_fields, FillingProduct filling_product, bool is_refill); - // Erases the history entry from the list represented by `fill_operation`. - void EraseFormFillEntry(FillOperation fill_operation); + // Erases the field history information corresponding to `field_id` in + // `fill_operation`. If the form filling entry becomes empty afterwards, the + // function also removes it from `history_`. + void EraseFieldFillingEntry( + std::list<FormFillingEntry>::iterator fill_operation, + FieldGlobalId field_id); - // Finds the latest history entry where the field represented by `field_id` - // was affected. - FillOperation GetLastFillingOperationForField(FieldGlobalId field_id) const; + // Returns the first entry in `history_` (corresponding to the last + // chronological entry) that has information about the field represented by + // `field_id`, if any exist. Note that this means that the returned iterator + // is either `history_.end()` or satisfies `it->contains(field_id)`. + std::list<FormFillingEntry>::iterator GetLastFormFillingEntryForField( + FieldGlobalId field_id); + std::list<FormFillingEntry>::const_iterator GetLastFormFillingEntryForField( + FieldGlobalId field_id) const { + return const_cast<FormAutofillHistory*>(this) + ->GetLastFormFillingEntryForField(field_id); + } // Checks whether the field represented by `field_id` has some registered // value in any history entry. @@ -142,6 +125,9 @@ bool empty() const { return history_.empty(); } private: + // Erases the history entry from the list represented by `fill_operation`. + void EraseFormFillEntry(std::list<FormFillingEntry>::iterator filling_entry); + // Holds, for each filling operation in reverse chronological order, a map // from the IDs of the fields that were affected by the corresponding filling // operation to the value and autofill state of the field prior to the
diff --git a/components/autofill/core/browser/filling/form_autofill_history_unittest.cc b/components/autofill/core/browser/filling/form_autofill_history_unittest.cc index d3aace19..2247c88 100644 --- a/components/autofill/core/browser/filling/form_autofill_history_unittest.cc +++ b/components/autofill/core/browser/filling/form_autofill_history_unittest.cc
@@ -54,8 +54,8 @@ for (const AutofillField& autofill_field : filled_autofill_fields_) { autofill_fields.push_back(&autofill_field); } - form_autofill_history_.AddFormFillEntry(fields, autofill_fields, - FillingProduct::kNone, is_refill); + form_autofill_history_.AddFormFillingEntry( + fields, autofill_fields, FillingProduct::kNone, is_refill); } std::vector<FormFieldData> filled_fields_; @@ -66,8 +66,9 @@ test::AutofillUnitTestEnvironment autofill_test_environment_; }; -// Tests the function FormAutofillHistory::AddFormFillEntry upon a normal fill. -TEST_F(FormAutofillHistoryTest, AddFormFillEntry_NormalFill) { +// Tests the function FormAutofillHistory::AddFormFillingEntry upon a normal +// fill. +TEST_F(FormAutofillHistoryTest, AddFormFillingEntry_NormalFill) { FieldGlobalId first_name_id = AddNewFieldFilling("first name", "first name", "some-value", FormControlType::kInputText, NAME_FIRST); @@ -75,8 +76,8 @@ ASSERT_TRUE(form_autofill_history_.HasHistory(first_name_id)); EXPECT_EQ( - form_autofill_history_.GetLastFillingOperationForField(first_name_id) - .GetFieldFillingEntry(first_name_id), + form_autofill_history_.GetLastFormFillingEntryForField(first_name_id) + ->at(first_name_id), FormAutofillHistory::FieldFillingEntry( u"some-value", false, kGuid, /*field_autofilled_type=*/std::nullopt, FillingProduct::kNone, /*ignore_is_autofilled=*/false)); @@ -85,8 +86,8 @@ EXPECT_FALSE(form_autofill_history_.HasHistory(first_name_id)); } -// Tests the function FormAutofillHistory::AddFormFillEntry upon a refill. -TEST_F(FormAutofillHistoryTest, AddFormFillEntry_Refill) { +// Tests the function FormAutofillHistory::AddFormFillingEntry upon a refill. +TEST_F(FormAutofillHistoryTest, AddFormFillingEntry_Refill) { FieldGlobalId first_name_id = AddNewFieldFilling("first name", "first name", "some-first-name", FormControlType::kInputText, NAME_FIRST); @@ -103,34 +104,31 @@ EXPECT_TRUE(form_autofill_history_.HasHistory(last_name_id)); EXPECT_EQ( - form_autofill_history_.GetLastFillingOperationForField(first_name_id), - form_autofill_history_.GetLastFillingOperationForField(last_name_id)); + form_autofill_history_.GetLastFormFillingEntryForField(first_name_id), + form_autofill_history_.GetLastFormFillingEntryForField(last_name_id)); ASSERT_TRUE(form_autofill_history_.HasHistory(first_name_id)); EXPECT_EQ( - form_autofill_history_.GetLastFillingOperationForField(first_name_id) - .GetFieldFillingEntry(first_name_id), + form_autofill_history_.GetLastFormFillingEntryForField(first_name_id) + ->at(first_name_id), FormAutofillHistory::FieldFillingEntry( u"some-first-name", false, kGuid, /*field_autofilled_type=*/std::nullopt, FillingProduct::kNone, /*ignore_is_autofilled=*/false)); ASSERT_TRUE(form_autofill_history_.HasHistory(last_name_id)); - EXPECT_EQ(form_autofill_history_.GetLastFillingOperationForField(last_name_id) - .GetFieldFillingEntry(last_name_id), - FormAutofillHistory::FieldFillingEntry( - u"some-other-last-name", true, kGuid, - /*field_autofilled_type=*/std::nullopt, FillingProduct::kNone, - /*ignore_is_autofilled=*/false)); - - form_autofill_history_.EraseFormFillEntry( - form_autofill_history_.GetLastFillingOperationForField(first_name_id)); - EXPECT_TRUE(form_autofill_history_.empty()); + EXPECT_EQ( + form_autofill_history_.GetLastFormFillingEntryForField(last_name_id) + ->at(last_name_id), + FormAutofillHistory::FieldFillingEntry( + u"some-other-last-name", true, kGuid, + /*field_autofilled_type=*/std::nullopt, FillingProduct::kNone, + /*ignore_is_autofilled=*/false)); } -// Tests how the function FormAutofillHistory::AddFormFillEntry clears values to -// remain within the size limit. -TEST_F(FormAutofillHistoryTest, AddFormFillEntry_HistoryLimit) { +// Tests how the function FormAutofillHistory::AddFormFillingEntry clears values +// to remain within the size limit. +TEST_F(FormAutofillHistoryTest, AddFormFillingEntry_HistoryLimit) { std::vector<FieldGlobalId> fields_id(kMaxStorableFieldFillHistory); for (size_t i = 0; i < kMaxStorableFieldFillHistory; ++i) { fields_id[i] = @@ -158,9 +156,9 @@ } } -// Tests how the function FormAutofillHistory::AddFormFillEntry handles a form -// entry bigger than the history size limit. -TEST_F(FormAutofillHistoryTest, AddFormFillEntry_FormBiggerThanLimit) { +// Tests how the function FormAutofillHistory::AddFormFillingEntry handles a +// form entry bigger than the history size limit. +TEST_F(FormAutofillHistoryTest, AddFormFillingEntry_FormBiggerThanLimit) { // Adding a few form fill entries. for (int i = 0; i < 5; ++i) { AddNewFieldFilling(("field-label" + base::NumberToString(i)).c_str(), @@ -185,9 +183,9 @@ EXPECT_TRUE(form_autofill_history_.empty()); } -// Tests how the function FormAutofillHistory::AddFormFillEntry reuses space +// Tests how the function FormAutofillHistory::AddFormFillingEntry reuses space // after adding an empty form fill entry. -TEST_F(FormAutofillHistoryTest, AddFormFillEntry_ReuseEmptyFillEntries) { +TEST_F(FormAutofillHistoryTest, AddFormFillingEntry_ReuseEmptyFillEntries) { // No fields were added to `filled_fields`, hence this form filling is empty. AddFormFilling(/*is_refill=*/false); EXPECT_EQ(form_autofill_history_.size(), 1u); @@ -199,9 +197,9 @@ EXPECT_TRUE(form_autofill_history_.HasHistory(field_id)); } -// Tests how the function FormAutofillHistory::AddFormFillEntry reuses space +// Tests how the function FormAutofillHistory::AddFormFillingEntry reuses space // after adding an empty form fill entry. -TEST_F(FormAutofillHistoryTest, AddFormFillEntry_RefillOnEmptyHistory) { +TEST_F(FormAutofillHistoryTest, AddFormFillingEntry_RefillOnEmptyHistory) { // Adding a form fill entry bigger than current size limit. std::vector<FieldGlobalId> fields_id(kMaxStorableFieldFillHistory + 1); for (size_t i = 0; i < kMaxStorableFieldFillHistory + 1; ++i) {
diff --git a/components/autofill/core/browser/filling/form_filler.cc b/components/autofill/core/browser/filling/form_filler.cc index 25370c32..a0420404 100644 --- a/components/autofill/core/browser/filling/form_filler.cc +++ b/components/autofill/core/browser/filling/form_filler.cc
@@ -473,21 +473,21 @@ return skip_reasons; } -FillingProduct FormFiller::UndoAutofill( - mojom::ActionPersistence action_persistence, - FormData form, - FormStructure& form_structure, - const FormFieldData& trigger_field) { +void FormFiller::UndoAutofill(mojom::ActionPersistence action_persistence, + FormData form, + FormStructure& form_structure, + const FormFieldData& trigger_field, + FillingProduct filling_product) { if (!form_autofill_history_.HasHistory(trigger_field.global_id())) { LOG_AF(log_manager()) << "Could not undo the filling operation on field " << trigger_field.global_id() << " because history was dropped upon reaching history limit of " << kMaxStorableFieldFillHistory; - return FillingProduct::kNone; } - FormAutofillHistory::FillOperation operation = - form_autofill_history_.GetLastFillingOperationForField( + + const auto fill_operation_it = + form_autofill_history_.GetLastFormFillingEntryForField( trigger_field.global_id()); std::vector<FormFieldData> fields = form.ExtractFields(); @@ -497,30 +497,41 @@ [](const std::unique_ptr<AutofillField>& field) { return std::make_pair(field->global_id(), field.get()); }); + // Remove the fields to be skipped so that we only pass fields to be modified // by the renderer. - std::erase_if( - fields, [this, &operation, &cached_fields](const FormFieldData& field) { - return - // Skip fields whose last autofill operation is different - // than the one of the trigger field. - form_autofill_history_.GetLastFillingOperationForField( - field.global_id()) != operation || - // Skip not-autofilled fields as undo only acts on autofilled - // fields. Only exception is the fields that were emptied due to - // suggestion swapping. - (!field.is_autofilled() && !field.value().empty() && - operation.GetFieldFillingEntry(field.global_id()) - .ignore_is_autofilled) || - // Skip fields that are not cached to avoid unexpected outcomes. - !cached_fields.contains(field.global_id()); - }); + std::erase_if(fields, [&](const FormFieldData& field) { + const auto field_fill_operation_it = + form_autofill_history_.GetLastFormFillingEntryForField( + field.global_id()); + return + // Skip fields whose last autofill operation is different + // than the one of the trigger field. + field_fill_operation_it != fill_operation_it || + // Skip not-autofilled fields as undo only acts on autofilled + // fields. Only exception is the fields that were emptied due to + // suggestion swapping. + // Note that `field_fill_operation` is guaranteed to have an entry for + // `field.global_id()` because of the condition right above. + (!field.is_autofilled() && !field.value().empty() && + field_fill_operation_it->at(field.global_id()).ignore_is_autofilled) || + // Skip fields that are not cached to avoid unexpected outcomes. + !cached_fields.contains(field.global_id()) || + // Skip fields which have a different filling product than the trigger + // field. This is to avoid modifying a field that was autofilled later + // with a filling product that doesn't support Undo (e.g., + // Autocomplete). + cached_fields[field.global_id()]->filling_product() != filling_product; + }); for (FormFieldData& field : fields) { AutofillField& autofill_field = CHECK_DEREF(cached_fields[field.global_id()]); - const FormAutofillHistory::FieldFillingEntry& previous_state = - operation.GetFieldFillingEntry(field.global_id()); + auto it = fill_operation_it->find(field.global_id()); + // See comments in the `erase_if` block for why this is guaranteed. + CHECK(it != fill_operation_it->end()); + const FormAutofillHistory::FieldFillingEntry& previous_state = it->second; + // Update the FormFieldData to be sent for the renderer. field.set_value(previous_state.value); field.set_is_autofilled(previous_state.is_autofilled); @@ -533,6 +544,13 @@ previous_state.autofill_source_profile_guid); autofill_field.set_autofilled_type(previous_state.autofilled_type); autofill_field.set_filling_product(previous_state.filling_product); + + // The filling history is not cleared on previews as it might be used for + // future previews or for the filling. it is also cleared field by field + // because some fields in the current entry might not be used now but + // could still be valuable (see crbug.com/416019464). + form_autofill_history_.EraseFieldFillingEntry(fill_operation_it, + field.global_id()); } } form.set_fields(std::move(fields)); @@ -550,14 +568,6 @@ action_persistence, form.fields(), url::Origin(), /*field_type_map=*/{}); - - FillingProduct filling_product = operation.get_filling_product(); - if (action_persistence != mojom::ActionPersistence::kPreview) { - // History is not cleared on previews as it might be used for future - // previews or for the filling. - form_autofill_history_.EraseFormFillEntry(std::move(operation)); - } - return filling_product; } void FormFiller::FillOrPreviewField(mojom::ActionPersistence action_persistence, @@ -580,7 +590,7 @@ if (ShouldRecordFillingHistory(filling_product)) { // TODO(crbug.com/40232021): Only use AutofillField. - form_autofill_history_.AddFormFillEntry( + form_autofill_history_.AddFormFillingEntry( std::to_array<const FormFieldData*>({&field}), std::to_array<const AutofillField*>({autofill_field}), filling_product, @@ -797,7 +807,7 @@ // Save filling history to support undoing it later if needed. if (action_persistence == mojom::ActionPersistence::kFill && ShouldRecordFillingHistory(filling_product)) { - form_autofill_history_.AddFormFillEntry( + form_autofill_history_.AddFormFillingEntry( safe_filled_fields.old_values, safe_filled_fields.cached, filling_product, refill_trigger_reason.has_value()); }
diff --git a/components/autofill/core/browser/filling/form_filler.h b/components/autofill/core/browser/filling/form_filler.h index ebb6b56..4b2be7f 100644 --- a/components/autofill/core/browser/filling/form_filler.h +++ b/components/autofill/core/browser/filling/form_filler.h
@@ -120,12 +120,13 @@ // Reverts the last autofill operation on `form` that affected // `trigger_field`. `renderer_action` denotes whether this is an actual - // filling or a preview operation on the renderer side. Returns the filling - // product of the operation being undone. - FillingProduct UndoAutofill(mojom::ActionPersistence action_persistence, - FormData form, - FormStructure& form_structure, - const FormFieldData& trigger_field); + // filling or a preview operation on the renderer side. + // TODO(crbug.com/40227496): Keep only one of `form` and `form_structure`. + void UndoAutofill(mojom::ActionPersistence action_persistence, + FormData form, + FormStructure& form_structure, + const FormFieldData& trigger_field, + FillingProduct filling_product); // Records filling information if possible and routes back to the renderer. void FillOrPreviewField(mojom::ActionPersistence action_persistence,
diff --git a/components/autofill/core/browser/filling/form_filler_test_api.h b/components/autofill/core/browser/filling/form_filler_test_api.h index ad377cd4..e4e326c 100644 --- a/components/autofill/core/browser/filling/form_filler_test_api.h +++ b/components/autofill/core/browser/filling/form_filler_test_api.h
@@ -20,12 +20,12 @@ form_filler_->limit_before_refill_ = limit; } - void AddFormFillEntry( + void AddFormFillingEntry( base::span<const FormFieldData* const> filled_fields, base::span<const AutofillField* const> filled_autofill_fields, FillingProduct filling_product, bool is_refill) { - form_filler_->form_autofill_history_.AddFormFillEntry( + form_filler_->form_autofill_history_.AddFormFillingEntry( filled_fields, filled_autofill_fields, filling_product, is_refill); }
diff --git a/components/autofill/core/browser/filling/form_filler_unittest.cc b/components/autofill/core/browser/filling/form_filler_unittest.cc index 2f4ae079..195b0b6 100644 --- a/components/autofill/core/browser/filling/form_filler_unittest.cc +++ b/components/autofill/core/browser/filling/form_filler_unittest.cc
@@ -185,14 +185,12 @@ return browser_autofill_manager_->GetAutofillField(form_id, field_id); } - // Lets `BrowserAutofillManager` fill `form` with `filling_payload` and + // Lets `BrowserAutofillManager` fill `form` using `trigger`` and // returns `form` as it would be extracted from the renderer afterwards, i.e., // with the autofilled `FormFieldData::value`s. - FormData FillAutofillFormData( + FormData ApplyFormAction( FormData form, - const FormFieldData& trigger_field, - FillingPayload filling_payload, - AutofillTriggerSource trigger_source = AutofillTriggerSource::kPopup) { + base::FunctionRef<void(const FormData& form)> trigger) { std::vector<FormFieldData> filled_fields; std::vector<FieldGlobalId> global_ids; for (const FormFieldData& field : form.fields()) { @@ -204,11 +202,7 @@ EXPECT_CALL(autofill_driver_, ApplyFormAction) .WillOnce( DoAll(SaveArgElementsTo<2>(&filled_fields), Return(global_ids))); - form_filler().FillOrPreviewForm( - mojom::ActionPersistence::kFill, form, filling_payload, - *GetFormStructure(form), - *GetAutofillField(form.global_id(), trigger_field.global_id()), - trigger_source); + trigger(form); // Copy the filled data into the form. for (FormFieldData& field : test_api(form).fields()) { if (auto it = std::ranges::find(filled_fields, field.global_id(), @@ -220,6 +214,54 @@ return form; } + // Lets `BrowserAutofillManager` fill `form` with `filling_payload` and + // returns `form` as it would be extracted from the renderer afterwards, i.e., + // with the autofilled `FormFieldData::value`s. + FormData FillAutofillFormData( + FormData form, + const FormFieldData& trigger_field, + FillingPayload filling_payload, + AutofillTriggerSource trigger_source = AutofillTriggerSource::kPopup) { + return ApplyFormAction(std::move(form), [&](const FormData& form) { + form_filler().FillOrPreviewForm( + mojom::ActionPersistence::kFill, form, filling_payload, + *GetFormStructure(form), + *GetAutofillField(form.global_id(), trigger_field.global_id()), + trigger_source); + }); + } + + // Lets `BrowserAutofillManager` undo the last filling operation performed on + // `trigger_field`, which belongs to `form`, and returns `form` as it would be + // extracted from the renderer afterwards, i.e., with the autofilled + // `FormFieldData::value`s. + FormData UndoAutofill(FormData form, const FormFieldData& trigger_field) { + return ApplyFormAction(std::move(form), [&](const FormData& form) { + browser_autofill_manager_->UndoAutofill(mojom::ActionPersistence::kFill, + form, trigger_field); + }); + } + + // Lets `BrowserAutofillManager` fill `trigger_field` with `value` and + // modifies `form` to reflect this filling. + FormData FillField(FormData form, + const FormFieldData& trigger_field, + FillingProduct filling_product, + std::u16string value) { + form_filler().FillOrPreviewField( + mojom::ActionPersistence::kFill, mojom::FieldActionType::kReplaceAll, + trigger_field, + GetAutofillField(form.global_id(), trigger_field.global_id()), value, + filling_product, /*field_type_used=*/std::nullopt); + + FormFieldData& field = + *std::ranges::find(test_api(form).fields(), trigger_field.global_id(), + &FormFieldData::global_id); + field.set_is_autofilled(true); + field.set_value(value); + return form; + } + std::vector<FormFieldData> PreviewVirtualCardDataAndGetResults( const FormData& form, const FormFieldData& field, @@ -446,7 +488,7 @@ AutofillField filled_autofill_field(form.fields().front()); test_api(form).field(0).set_is_autofilled(false); test_api(form_filler()) - .AddFormFillEntry( + .AddFormFillingEntry( std::to_array<const FormFieldData*>({&form.fields().front()}), std::to_array<const AutofillField*>({&filled_autofill_field}), FillingProduct::kAddress, /*is_refill=*/false); @@ -1867,4 +1909,111 @@ .triggers_refill = false, })); +// Test that, if after an initial form filling, some field is autofilled again, +// Undoing the first filling operation doesn't change that field. +TEST_F(FormFillerTest, UndoSkipsFieldsAutofilledFurther) { + FormData form = test::GetFormData( + {.fields = { + {.role = NAME_FIRST, .autocomplete_attribute = "given-name"}, + {.role = NAME_LAST, .autocomplete_attribute = "family-name"}}}); + FormsSeen({form}); + FormStructure* form_structure = GetFormStructure(form); + ASSERT_TRUE(form_structure); + + // Fill the form with an address profile. + AutofillProfile profile1 = test::GetFullProfile(); + form = FillAutofillFormData(form, form.fields()[0], &profile1); + EXPECT_THAT(form.fields()[0], AutofilledWith(u"John")); + EXPECT_THAT(form.fields()[1], AutofilledWith(u"Doe")); + + // Simulate a field swapping operation on the second field. + form = FillField(form, form.fields()[1], FillingProduct::kAddress, u"Other"); + EXPECT_THAT(form.fields()[0], AutofilledWith(u"John")); + EXPECT_THAT(form.fields()[1], AutofilledWith(u"Other")); + + // Now Undo the first filling operation on the first field. + form = UndoAutofill(form, form.fields()[0]); + EXPECT_TRUE(form.fields()[0].value().empty()); + EXPECT_FALSE(form.fields()[0].is_autofilled()); + // The second field should not change, because the last operation that + // modified it isn't the one that is being currently undone. + EXPECT_THAT(form.fields()[1], AutofilledWith(u"Other")); +} + +// Regression test for crbug.com/416019464 +TEST_F(FormFillerTest, MultipleUndoOperations) { + FormData form = test::GetFormData( + {.fields = { + {.role = NAME_FIRST, .autocomplete_attribute = "given-name"}, + {.role = NAME_LAST, .autocomplete_attribute = "family-name"}}}); + FormsSeen({form}); + FormStructure* form_structure = GetFormStructure(form); + ASSERT_TRUE(form_structure); + + // Fill the form with an address profile. + AutofillProfile profile1 = test::GetFullProfile(); + form = FillAutofillFormData(form, form.fields()[0], &profile1); + EXPECT_THAT(form.fields()[0], AutofilledWith(u"John")); + EXPECT_THAT(form.fields()[1], AutofilledWith(u"Doe")); + + // Simulate a field swapping operation on the second field. + form = FillField(form, form.fields()[1], FillingProduct::kAddress, u"Other"); + EXPECT_THAT(form.fields()[0], AutofilledWith(u"John")); + EXPECT_THAT(form.fields()[1], AutofilledWith(u"Other")); + + // Now Undo the first filling operation on the first field. + form = UndoAutofill(form, form.fields()[0]); + // The first field should be cleared, as this was its initial state. + EXPECT_TRUE(form.fields()[0].value().empty()); + EXPECT_FALSE(form.fields()[0].is_autofilled()); + // The second field should not change. + EXPECT_THAT(form.fields()[1], AutofilledWith(u"Other")); + + // Now Undo the second filling operation on the second field. + form = UndoAutofill(form, form.fields()[1]); + EXPECT_TRUE(form.fields()[0].value().empty()); + EXPECT_FALSE(form.fields()[0].is_autofilled()); + // The second field should restore the value of the first filling operation. + EXPECT_THAT(form.fields()[1], AutofilledWith(u"Doe")); + + // Now Undo the first filling operation on the second field. + form = UndoAutofill(form, form.fields()[1]); + EXPECT_TRUE(form.fields()[0].value().empty()); + EXPECT_FALSE(form.fields()[0].is_autofilled()); + // The second field should be cleared, as this was its initial state. + EXPECT_TRUE(form.fields()[1].value().empty()); + EXPECT_FALSE(form.fields()[1].is_autofilled()); +} + +// Tests that Undoing a filling operation on a field discards other fields that +// changed filling product (i.e. were autofilled afterwards using some other +// filling product). +TEST_F(FormFillerTest, UndoDiscardsFieldsThatChangedFillingProduct) { + FormData form = test::GetFormData( + {.fields = { + {.role = NAME_FIRST, .autocomplete_attribute = "given-name"}, + {.role = NAME_LAST, .autocomplete_attribute = "family-name"}}}); + FormsSeen({form}); + FormStructure* form_structure = GetFormStructure(form); + ASSERT_TRUE(form_structure); + + // Fill the form with an address profile. + AutofillProfile profile1 = test::GetFullProfile(); + form = FillAutofillFormData(form, form.fields()[0], &profile1); + EXPECT_THAT(form.fields()[0], AutofilledWith(u"John")); + EXPECT_THAT(form.fields()[1], AutofilledWith(u"Doe")); + + // Simulate a field swapping operation on the second field. + form = FillField(form, form.fields()[1], FillingProduct::kAutocomplete, + u"Other"); + EXPECT_THAT(form.fields()[0], AutofilledWith(u"John")); + EXPECT_THAT(form.fields()[1], AutofilledWith(u"Other")); + + // Now Undo the first filling operation on the first field. + form = UndoAutofill(form, form.fields()[0]); + EXPECT_TRUE(form.fields()[0].value().empty()); + EXPECT_FALSE(form.fields()[0].is_autofilled()); + EXPECT_THAT(form.fields()[1], AutofilledWith(u"Other")); +} + } // namespace autofill
diff --git a/components/autofill/core/browser/form_parsing/internal_resources b/components/autofill/core/browser/form_parsing/internal_resources index ee4b7f29..3fb8783 160000 --- a/components/autofill/core/browser/form_parsing/internal_resources +++ b/components/autofill/core/browser/form_parsing/internal_resources
@@ -1 +1 @@ -Subproject commit ee4b7f29de55d7867a004208580a994e5da35ed0 +Subproject commit 3fb8783d75611c5ada2ee094ad2be8331e9bd233
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.cc b/components/autofill/core/browser/foundations/browser_autofill_manager.cc index 6a303d270..b47fcd0 100644 --- a/components/autofill/core/browser/foundations/browser_autofill_manager.cc +++ b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
@@ -1726,10 +1726,15 @@ if (!form_structure) { return; } - // This will apply the undo operation and return information about the - // operation being undone, for metric purposes. - FillingProduct filling_product = form_filler_->UndoAutofill( - action_persistence, form, *form_structure, trigger_field); + const AutofillField* autofill_trigger_field = + form_structure->GetFieldById(trigger_field.global_id()); + if (!autofill_trigger_field) { + return; + } + + FillingProduct filling_product = autofill_trigger_field->filling_product(); + form_filler_->UndoAutofill(action_persistence, form, *form_structure, + trigger_field, filling_product); // The remaining logic is only relevant for filling. if (action_persistence != mojom::ActionPersistence::kPreview) {
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.h b/components/autofill/core/browser/foundations/browser_autofill_manager.h index 45af9fb..380025bb 100644 --- a/components/autofill/core/browser/foundations/browser_autofill_manager.h +++ b/components/autofill/core/browser/foundations/browser_autofill_manager.h
@@ -165,7 +165,7 @@ FieldType field_type_used_to_build_suggestion, const std::string& profile_used_guid); - // Calls UndoAutofillImpl and logs metrics. Virtual for testing. + // Calls FormFiller::UndoAutofill and logs metrics. Virtual for testing. virtual void UndoAutofill(mojom::ActionPersistence action_persistence, const FormData& form, const FormFieldData& trigger_field);
diff --git a/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator.cc b/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator.cc index e5add97..1732938 100644 --- a/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator.cc +++ b/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator.cc
@@ -128,4 +128,27 @@ return suggestions; } +void ExtendEmailSuggestionsWithLoyaltyCardSuggestions( + std::vector<Suggestion>& email_suggestions, + const ValuablesDataManager& valuables_manager, + const GURL& url) { + std::vector<Suggestion> loyalty_card_suggestions = + GetLoyaltyCardSuggestions(valuables_manager, url); + if (loyalty_card_suggestions.empty()) { + return; + } + + // TODO(crbug.com/404436027): Replace with i18n string. + Suggestion submenu_suggestion = + Suggestion(u"Loyalty cards", SuggestionType::kLoyaltyCardEntry); + submenu_suggestion.acceptability = Suggestion::Acceptability::kUnacceptable; + submenu_suggestion.children = loyalty_card_suggestions; + + // There is at least one email, separator and manage addresses suggestion. + CHECK(email_suggestions.size() >= 3); + email_suggestions.insert(email_suggestions.end() - 1, submenu_suggestion); + email_suggestions.insert(email_suggestions.end() - 1, + Suggestion(SuggestionType::kSeparator)); +} + } // namespace autofill
diff --git a/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator.h b/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator.h index 1da81058..bfaeeb23 100644 --- a/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator.h +++ b/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator.h
@@ -24,6 +24,16 @@ const ValuablesDataManager& valuables_manager, const GURL& url); +// Extends `email_suggestions` with loyalty cards suggestions placed in a +// submenu. +// +// Loyalty cards suggestions are retrieved and follow the same logic as +// `GetLoyaltyCardSuggestions()`. +void ExtendEmailSuggestionsWithLoyaltyCardSuggestions( + std::vector<Suggestion>& email_suggestions, + const ValuablesDataManager& valuables_manager, + const GURL& url); + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_SUGGESTIONS_VALUABLES_VALUABLE_SUGGESTION_GENERATOR_H_
diff --git a/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator_unittest.cc b/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator_unittest.cc index ce377e8..e6da56b 100644 --- a/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator_unittest.cc +++ b/components/autofill/core/browser/suggestions/valuables/valuable_suggestion_generator_unittest.cc
@@ -160,6 +160,83 @@ SuggestionIconHasImageOrUrl(fake_image, program_logo)); } +TEST_F(ValuableSuggestionGeneratorTest, + ExtendEmailSuggestionsWithLoyaltyCardSuggestions_ExistingLoyaltyCards) { + const std::vector<LoyaltyCard> loyalty_cards = {LoyaltyCard( + /*loyalty_card_id=*/ValuableId("loyalty_card_id_1"), + /*merchant_name=*/"CVS Pharmacy", + /*program_name=*/"CVS Extra", + /*program_logo=*/GURL("https://empty.url.com"), + /*loyalty_card_number=*/"987654321987654321", + {GURL("https://domain1.example"), + GURL("https://common-domain.example")})}; + + test_api(valuables_data_manager()).SetLoyaltyCards(loyalty_cards); + + std::vector<Suggestion> email_suggestions = { + Suggestion(u"test-email1@domain1.example", SuggestionType::kAddressEntry), + Suggestion(u"test-email2@domain2.example", SuggestionType::kAddressEntry), + Suggestion(SuggestionType::kSeparator), + Suggestion(u"Manage addresses...", SuggestionType::kManageAddress)}; + + ExtendEmailSuggestionsWithLoyaltyCardSuggestions( + email_suggestions, valuables_data_manager(), + GURL("https://common-domain.example/test")); + + EXPECT_THAT( + email_suggestions, + testing::ElementsAre( + EqualsSuggestion(SuggestionType::kAddressEntry, + u"test-email1@domain1.example"), + EqualsSuggestion(SuggestionType::kAddressEntry, + u"test-email2@domain2.example"), + EqualsSuggestion(SuggestionType::kSeparator), + EqualsSuggestion(SuggestionType::kLoyaltyCardEntry, u"Loyalty cards"), + EqualsSuggestion(SuggestionType::kSeparator), + EqualsSuggestion(SuggestionType::kManageAddress, + u"Manage addresses..."))); + + const Suggestion& lc_submenu_suggestion = email_suggestions[3]; + EXPECT_EQ(lc_submenu_suggestion.acceptability, + Suggestion::Acceptability::kUnacceptable); + EXPECT_THAT(lc_submenu_suggestion.children, + testing::ElementsAre( + EqualsSuggestion( + SuggestionType::kLoyaltyCardEntry, u"987654321987654321", + /*is_main_text_primary=*/true, Suggestion::Icon::kNoIcon, + {{Suggestion::Text(u"CVS Pharmacy")}}, + Suggestion::Guid("loyalty_card_id_1")), + EqualsSuggestion(SuggestionType::kSeparator), + EqualsSuggestion(SuggestionType::kManageLoyaltyCard, + u"Manage loyalty cards...", + Suggestion::Icon::kSettings))); +} + +TEST_F(ValuableSuggestionGeneratorTest, + ExtendEmailSuggestionsWithLoyaltyCardSuggestions_NoLoyaltyCards) { + test_api(valuables_data_manager()).SetLoyaltyCards({}); + + std::vector<Suggestion> email_suggestions = { + Suggestion(u"test-email1@domain1.example", SuggestionType::kAddressEntry), + Suggestion(u"test-email2@domain2.example", SuggestionType::kAddressEntry), + Suggestion(SuggestionType::kSeparator), + Suggestion(u"Manage addresses...", SuggestionType::kManageAddress)}; + + ExtendEmailSuggestionsWithLoyaltyCardSuggestions( + email_suggestions, valuables_data_manager(), + GURL("https://common-domain.example/test")); + + EXPECT_THAT( + email_suggestions, + testing::ElementsAre(EqualsSuggestion(SuggestionType::kAddressEntry, + u"test-email1@domain1.example"), + EqualsSuggestion(SuggestionType::kAddressEntry, + u"test-email2@domain2.example"), + EqualsSuggestion(SuggestionType::kSeparator), + EqualsSuggestion(SuggestionType::kManageAddress, + u"Manage addresses..."))); +} + #if !BUILDFLAG(IS_ANDROID) TEST_F(ValuableSuggestionGeneratorTest, GetLoyaltyCardSuggestions_SuggestionsIPH) {
diff --git a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller.h b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller.h index 7750ef06..f0adaf7 100644 --- a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller.h +++ b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller.h
@@ -15,6 +15,13 @@ public: virtual ~SaveAndFillDialogController() = default; + virtual std::u16string GetWindowTitle() const = 0; + virtual std::u16string GetExplanatoryMessage() const = 0; + virtual std::u16string GetCardNumberLabel() const = 0; + virtual std::u16string GetNameOnCardLabel() const = 0; + virtual std::u16string GetAcceptButtonText() const = 0; + virtual bool IsUploadSaveAndFill() const = 0; + virtual base::WeakPtr<SaveAndFillDialogController> GetWeakPtr() = 0; };
diff --git a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc index 3de0ad1..86c9ad7 100644 --- a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc +++ b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc
@@ -5,6 +5,9 @@ #include "components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h" #include "base/memory/weak_ptr.h" +#include "base/strings/utf_string_conversions.h" +#include "components/strings/grit/components_strings.h" +#include "ui/base/l10n/l10n_util.h" namespace autofill { @@ -18,6 +21,37 @@ CHECK(dialog_view_); } +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +std::u16string SaveAndFillDialogControllerImpl::GetWindowTitle() const { + return l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_TITLE); +} + +std::u16string SaveAndFillDialogControllerImpl::GetExplanatoryMessage() const { + return l10n_util::GetStringUTF16( + IsUploadSaveAndFill() + ? IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_UPLOAD + : IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_LOCAL); +} + +std::u16string SaveAndFillDialogControllerImpl::GetCardNumberLabel() const { + return l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_CARD_NUMBER_LABEL); +} + +std::u16string SaveAndFillDialogControllerImpl::GetNameOnCardLabel() const { + return l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_NAME_ON_CARD_LABEL); +} + +std::u16string SaveAndFillDialogControllerImpl::GetAcceptButtonText() const { + return l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_ACCEPT); +} +#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) + +bool SaveAndFillDialogControllerImpl::IsUploadSaveAndFill() const { + return is_upload_save_and_fill_; +} + base::WeakPtr<SaveAndFillDialogController> SaveAndFillDialogControllerImpl::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr();
diff --git a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h index 44f9a5b..db8b6f7 100644 --- a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h +++ b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h
@@ -26,11 +26,25 @@ void ShowDialog(base::OnceCallback<base::WeakPtr<SaveAndFillDialogView>()> create_and_show_view_callback); + +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) + std::u16string GetWindowTitle() const override; + std::u16string GetExplanatoryMessage() const override; + std::u16string GetCardNumberLabel() const override; + std::u16string GetNameOnCardLabel() const override; + std::u16string GetAcceptButtonText() const override; +#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) + bool IsUploadSaveAndFill() const override; + base::WeakPtr<SaveAndFillDialogController> GetWeakPtr() override; private: base::WeakPtr<SaveAndFillDialogView> dialog_view_; + // Determines whether the local or upload save version of the UI should be + // shown. + bool is_upload_save_and_fill_ = false; + base::WeakPtrFactory<SaveAndFillDialogControllerImpl> weak_ptr_factory_{this}; };
diff --git a/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.cc b/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.cc index 75c935e..d71b1a5 100644 --- a/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.cc +++ b/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.cc
@@ -121,10 +121,6 @@ // Since the specifics are guaranteed to be valid by // `IsEntityDataValid()`, the conversion will succeed. DCHECK(remote); - if (!EnsureUniquenessOfHomeAndWork(*remote)) { - return syncer::ModelError(FROM_HERE, - "Failed to ensure uniqueness of H/W."); - } // Since the distinction between adds and updates is not always clear, // we check the existence of the profile manually and act accordingly. // TODO(crbug.com/40100455): Consider adding an AddOrUpdate() function @@ -373,22 +369,6 @@ change_processor()->ModelReadyToSync(std::move(batch)); } -bool ContactInfoSyncBridge::EnsureUniquenessOfHomeAndWork( - const AutofillProfile& profile) { - if (profile.record_type() != AutofillProfile::RecordType::kAccountHome && - profile.record_type() != AutofillProfile::RecordType::kAccountWork) { - return true; - } - std::vector<AutofillProfile> existing_profiles; - AddressAutofillTable& table = *GetAutofillTable(); - return table.GetAutofillProfiles({profile.record_type()}, - existing_profiles) && - std::ranges::all_of(existing_profiles, [&](const AutofillProfile& p) { - return p.guid() == profile.guid() || - table.UpdateAutofillProfile(p.DowngradeToAccountProfile()); - }); -} - void ContactInfoSyncBridge::FlushPendingAccountProfileChanges() { CHECK(change_processor()->IsTrackingMetadata()); while (!pending_account_profile_changes_.empty()) {
diff --git a/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.h b/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.h index eea9ff1..a25ba7d 100644 --- a/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.h +++ b/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge.h
@@ -100,20 +100,6 @@ // the processor so it can start tracking changes. void LoadMetadata(); - // Ensures that at most one address in the storage can be labeled as home and - // work each. If `profile` is H/W and a different address of the same record - // type already exists in the storage, this function downgrades it to a - // regular one. The change is intentionally not re-uploaded, because: - // - The logic is meant to catch inconsistencies due to failed writes, which - // are not reflected on the server to begin with. E.g, it can happen that an - // address is promoted to H/W in Chrome, but persisting it on the backend - // fails. Then, a different address might be promoted to H/W from outside of - // Chrome. Since CONTACT_INFO doesn't have a way to propagate errors back to - // the client, this would result in duplicate H/W addresses. - // - It avoids a potential ping-pong. - // Returns false if storage operations fail. - bool EnsureUniquenessOfHomeAndWork(const AutofillProfile& profile); - // Uploads all `pending_profile_changes_`. void FlushPendingAccountProfileChanges();
diff --git a/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge_unittest.cc index 3f20b77..26dcb9f6 100644 --- a/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge_unittest.cc +++ b/components/autofill/core/browser/webdata/addresses/contact_info_sync_bridge_unittest.cc
@@ -264,61 +264,6 @@ profile.usage_history().modification_date()); } -// Tests that `ApplyIncrementalSyncChanges()` ensures that at most one H/W -// address exists after a profile addition. -TEST_F(ContactInfoSyncBridgeTest, - ApplyIncrementalSyncChanges_DuplicateHomeAndWork_Add) { - ASSERT_TRUE(StartSyncing(/*remote_profiles=*/{})); - - // Simulate that a home address exists and that a new home address with a - // different storage key is received from sync. - AutofillProfile local = - TestProfile(kGUID1, AutofillProfile::RecordType::kAccountHome); - AddAutofillProfilesToTable({local}); - - AutofillProfile remote = - TestProfile(kGUID2, AutofillProfile::RecordType::kAccountHome); - syncer::EntityChangeList entity_change_list; - entity_change_list.push_back( - syncer::EntityChange::CreateAdd(kGUID2, ProfileToEntity(remote))); - // `ApplyIncrementalSyncChanges()` returns an error if it fails. - EXPECT_FALSE(bridge().ApplyIncrementalSyncChanges( - bridge().CreateMetadataChangeList(), std::move(entity_change_list))); - - // Expect that `local` still exists, but is no longer kAccountHome. - EXPECT_THAT(GetAllDataFromTable(), - UnorderedElementsAre(local.DowngradeToAccountProfile(), remote)); -} - -// Tests that `ApplyIncrementalSyncChanges()` ensures that at most one H/W -// address exists after a profile gets updated to H/W. -TEST_F(ContactInfoSyncBridgeTest, - ApplyIncrementalSyncChanges_DuplicateHomeAndWork_Update) { - ASSERT_TRUE(StartSyncing(/*remote_profiles=*/{})); - - // Simulate that a home address exists and that an existing regular address - // gets upgraded to home. - AutofillProfile local_home = - TestProfile(kGUID1, AutofillProfile::RecordType::kAccountHome); - AutofillProfile local_regular = - TestProfile(kGUID2, AutofillProfile::RecordType::kAccountHome); - AddAutofillProfilesToTable({local_home, local_regular}); - - AutofillProfile remote = - TestProfile(kGUID2, AutofillProfile::RecordType::kAccountHome); - syncer::EntityChangeList entity_change_list; - entity_change_list.push_back( - syncer::EntityChange::CreateUpdate(kGUID2, ProfileToEntity(remote))); - // `ApplyIncrementalSyncChanges()` returns an error if it fails. - EXPECT_FALSE(bridge().ApplyIncrementalSyncChanges( - bridge().CreateMetadataChangeList(), std::move(entity_change_list))); - - // Expect that `local_home` still exists, but is no longer kAccountHome. - EXPECT_THAT( - GetAllDataFromTable(), - UnorderedElementsAre(local_home.DowngradeToAccountProfile(), remote)); -} - // Tests that `GetDataForCommit()` returns all local profiles of matching GUID. TEST_F(ContactInfoSyncBridgeTest, GetDataForCommit) { const AutofillProfile profile1 = TestProfile(kGUID1);
diff --git a/components/autofill/ios/browser/autofill_agent.mm b/components/autofill/ios/browser/autofill_agent.mm index df3d6e70..87082217 100644 --- a/components/autofill/ios/browser/autofill_agent.mm +++ b/components/autofill/ios/browser/autofill_agent.mm
@@ -1003,6 +1003,16 @@ fieldToFormLookupMap:fieldToFormLookupMap]; } + if (base::FeatureList::IsEnabled(kAutofillRefillForFormsIos) && + base::FeatureList::IsEnabled( + autofill::features::kAutofillAcrossIframesIos)) { + auto* driver = + autofill::AutofillDriverIOS::FromWebStateAndWebFrame(_webState, frame); + if (driver && driver->is_processed()) { + driver->ScanForms(); + } + } + [self recordFormFillingSuccessMetrics:!fillingResults.empty()]; }
diff --git a/components/autofill/ios/browser/autofill_driver_ios.h b/components/autofill/ios/browser/autofill_driver_ios.h index c8826f0..efb1f00 100644 --- a/components/autofill/ios/browser/autofill_driver_ios.h +++ b/components/autofill/ios/browser/autofill_driver_ios.h
@@ -140,6 +140,9 @@ bool is_processed() const { return processed_; } void set_processed(bool processed) { processed_ = processed; } web::WebFrame* web_frame() const; + base::WeakPtr<AutofillDriverIOS> GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } // Methods routed by AutofillDriverRouter. These are a subset of the methods // in mojom::AutofillDriver; that interface is content-specific, but to
diff --git a/components/autofill/ios/browser/autofill_driver_ios_factory.mm b/components/autofill/ios/browser/autofill_driver_ios_factory.mm index 422e94c4..b5aa211 100644 --- a/components/autofill/ios/browser/autofill_driver_ios_factory.mm +++ b/components/autofill/ios/browser/autofill_driver_ios_factory.mm
@@ -53,8 +53,13 @@ for (auto& observer : AutofillDriverFactory::observers()) { observer.OnAutofillDriverFactoryDestroyed(*this); } - base::UmaHistogramCounts1000("Autofill.NumberOfDriversPerFactory", - max_drivers_); + if (web_state() && web_state()->IsRealized()) { + // Only count the max number of drivers for realized web states because + // unrealized web states do not have loaded frames which can heavily skew + // the data towards 0 frames. + base::UmaHistogramCounts1000("Autofill.NumberOfDriversPerFactory", + max_drivers_); + } } // The AutofillClientIOS contract guarantees that WebStateDestroyed() is called
diff --git a/components/autofill/ios/common/features.h b/components/autofill/ios/common/features.h index 8e8683e1..152c9836 100644 --- a/components/autofill/ios/common/features.h +++ b/components/autofill/ios/common/features.h
@@ -61,6 +61,10 @@ // the FormSuggestionController. BASE_DECLARE_FEATURE(kAutofillPaymentsSheetV3Ios); +// Enables the refill functionality to allow autofilling of dynamically +// expanding forms. +BASE_DECLARE_FEATURE(kAutofillRefillForFormsIos); + // Makes the autofill and password infobars sticky on iOS. The sticky infobar // sticks there until navigating from an explicit user gesture (e.g. reload or // load a new page from the omnibox). This includes the infobar UI and the
diff --git a/components/autofill/ios/common/features.mm b/components/autofill/ios/common/features.mm index 7e582d0..3fe47794 100644 --- a/components/autofill/ios/common/features.mm +++ b/components/autofill/ios/common/features.mm
@@ -62,6 +62,10 @@ "AutofillPaymentsSheetV3Ios", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kAutofillRefillForFormsIos, + "AutofillRefillForFormsIos", + base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kAutofillStickyInfobarIos, "AutofillStickyInfobarIos", base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp index 435e64e..5495c1f2 100644 --- a/components/autofill_payments_strings.grdp +++ b/components/autofill_payments_strings.grdp
@@ -232,6 +232,38 @@ Saving IBAN info </message> + <!-- Autofill Save and Fill dialog related strings --> + <if expr="not is_ios and not is_android"> + <message name="IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_TITLE" desc="Title for the Save and Fill dialog. It is shown when a user accepts the` Save and Fill` suggestion shown in the Autofill dropdown for users who don't have any cards saved in Autofill. This always users to save and fill a credit card with a single click"> + Save card for faster checkout + </message> + <if expr="_google_chrome"> + <message name="IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_LOCAL" desc="Explanation text for the Autofill Save and Fill dialog for cards that will be saved locally."> + Autofill this card for purchases made in Chrome when it's saved on this device + </message> + <message name="IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_UPLOAD" desc="Explanation text for the Autofill Save and Fill dialog for cards that will be saved to the GPay server."> + Autofill this card for purchases made in Chrome when it's saved to use with Google Pay + </message> + </if> + <if expr="not _google_chrome"> + <message name="IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_LOCAL" desc="Explanation text for the Autofill Save and Fill dialog for cards that will be saved locally."> + Autofill this card for purchases made in Chromium when it's saved on this device + </message> + <message name="IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_UPLOAD" desc="Explanation text for the Autofill Save and Fill dialog for cards that will be saved to the GPay server."> + Autofill this card for purchases made in Chromium when it's saved to use with Google Pay + </message> + </if> + <message name="IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_CARD_NUMBER_LABEL" desc="The label text for the card number textfield."> + Card number + </message> + <message name="IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_NAME_ON_CARD_LABEL" desc="The label text for the name on card textfield."> + Name on card + </message> + <message name="IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_ACCEPT" desc="Text to show for the Autofill Save and Fill dialog accept button."> + Save and autofill + </message> + </if> + <!-- Autofill error dialog related strings --> <message name="IDS_AUTOFILL_MASKED_SERVER_CARD_RISK_BASED_UNMASKING_ERROR_TITLE" desc="Text to be displayed as the title of the error dialog during credit card risk-based unmasking."> Something went wrong
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_ACCEPT.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_ACCEPT.png.sha1 new file mode 100644 index 0000000..c11af72 --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_ACCEPT.png.sha1
@@ -0,0 +1 @@ +843654a6384cf11d701664d19c373387f8714310 \ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_CARD_NUMBER_LABEL.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_CARD_NUMBER_LABEL.png.sha1 new file mode 100644 index 0000000..c11af72 --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_CARD_NUMBER_LABEL.png.sha1
@@ -0,0 +1 @@ +843654a6384cf11d701664d19c373387f8714310 \ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_LOCAL.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_LOCAL.png.sha1 new file mode 100644 index 0000000..c11af72 --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_LOCAL.png.sha1
@@ -0,0 +1 @@ +843654a6384cf11d701664d19c373387f8714310 \ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_UPLOAD.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_UPLOAD.png.sha1 new file mode 100644 index 0000000..fa4133f --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_EXPLANATION_UPLOAD.png.sha1
@@ -0,0 +1 @@ +584925b5f8bf1bab94d3ec605137d4a6cd32d05c \ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_NAME_ON_CARD_LABEL.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_NAME_ON_CARD_LABEL.png.sha1 new file mode 100644 index 0000000..c11af72 --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_NAME_ON_CARD_LABEL.png.sha1
@@ -0,0 +1 @@ +843654a6384cf11d701664d19c373387f8714310 \ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_TITLE.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_TITLE.png.sha1 new file mode 100644 index 0000000..c11af72 --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_TITLE.png.sha1
@@ -0,0 +1 @@ +843654a6384cf11d701664d19c373387f8714310 \ No newline at end of file
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingsResources.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingsResources.java index 371b87b7..183df6b 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingsResources.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingsResources.java
@@ -133,11 +133,6 @@ return mDisabledPrimaryText == 0 ? getDisabledSummary() : mDisabledPrimaryText; } - private int getEnabledDescriptionText() { - // TODO(crbug.com/414413495): Remove function. - return 0; - } - private int getDisabledDescriptionText() { return mDisabledDescriptionText; } @@ -1013,7 +1008,7 @@ int[] descriptionIDs = { getResourceItem(contentType).getEnabledPrimaryText(), getResourceItem(contentType).getDisabledPrimaryText(), - getResourceItem(contentType).getEnabledDescriptionText(), + 0, getResourceItem(contentType).getDisabledDescriptionText() }; return descriptionIDs;
diff --git a/components/cdm/common/BUILD.gn b/components/cdm/common/BUILD.gn index 4cc79e6..687d501 100644 --- a/components/cdm/common/BUILD.gn +++ b/components/cdm/common/BUILD.gn
@@ -2,8 +2,15 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/buildflag_header.gni") +import("//components/cdm/common/playready.gni") import("//third_party/widevine/cdm/widevine.gni") +buildflag_header("buildflags") { + header = "buildflags.h" + flags = [ "ENABLE_PLAYREADY=$enable_playready" ] +} + static_library("common") { sources = [] @@ -39,6 +46,10 @@ ] } + if (enable_playready) { + sources += [ "playready_cdm_common.h" ] + } + if (enable_library_cdms) { sources += [ "cdm_manifest.cc",
diff --git a/components/cdm/common/playready.gni b/components/cdm/common/playready.gni new file mode 100644 index 0000000..c5f0803 --- /dev/null +++ b/components/cdm/common/playready.gni
@@ -0,0 +1,13 @@ +# 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. + +import("//build/config/chrome_build.gni") + +declare_args() { + # Enables PlayReady key system support. + # TODO(crbug.com/1498137): This feature is still in development. + enable_playready = is_win && is_chrome_branded +} + +assert(!enable_playready || is_win, "PlayReady is only supported on Windows.")
diff --git a/components/cdm/common/playready_cdm_common.h b/components/cdm/common/playready_cdm_common.h new file mode 100644 index 0000000..2c55b78d --- /dev/null +++ b/components/cdm/common/playready_cdm_common.h
@@ -0,0 +1,52 @@ +// 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_CDM_COMMON_PLAYREADY_CDM_COMMON_H_ +#define COMPONENTS_CDM_COMMON_PLAYREADY_CDM_COMMON_H_ + +#include <array> +#include <string> + +#include "base/containers/contains.h" +#include "base/stl_util.h" +#include "base/token.h" +#include "media/cdm/cdm_type.h" + +inline constexpr char kPlayReadyCdmDisplayName[] = + "PlayReady Content Decryption Module"; + +inline constexpr media::CdmType kPlayReadyCdmType{0xCAF6576F591C4162ull, + 0xB70FB8AE9AECD2B9ull}; + +// PlayReady KeySystem Strings +// https://learn.microsoft.com/en-us/playready/overview/key-system-strings +// +// "com.microsoft.playready.recommendation" without any robustness level +// specified represents a software secure (security level 2000) key system. +// If a robustness of "3000" is specified with this key system string then +// hardware secure (security level 3000) is used. Only hardware secure +// is supported. +// +// "com.microsoft.playready.recommendation.3000" does not require a robustness +// level to be specified. This always represents hardware secure (security +// level 3000). If a robustness of "3000" is specified with this key system +// string then it is ignored. +inline constexpr char kPlayReadyKeySystemRecommendationDefault[] = + "com.microsoft.playready.recommendation"; +inline constexpr char kPlayReadyKeySystemRecommendationHwSecure[] = + "com.microsoft.playready.recommendation.3000"; + +inline constexpr std::array<const char*, 2> kPlayReadyKeySystems = { + kPlayReadyKeySystemRecommendationDefault, + kPlayReadyKeySystemRecommendationHwSecure}; + +inline bool IsPlayReadyHwSecureKeySystem(const std::string& key_system) { + return key_system == kPlayReadyKeySystemRecommendationHwSecure; +} + +inline bool IsPlayReadyKeySystem(const std::string& name) { + return base::Contains(kPlayReadyKeySystems, name); +} + +#endif // COMPONENTS_CDM_COMMON_PLAYREADY_CDM_COMMON_H_
diff --git a/components/cdm/renderer/BUILD.gn b/components/cdm/renderer/BUILD.gn index b3d270e..fbe2ec2 100644 --- a/components/cdm/renderer/BUILD.gn +++ b/components/cdm/renderer/BUILD.gn
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//components/cdm/common/playready.gni") import("//third_party/widevine/cdm/widevine.gni") static_library("renderer") { @@ -21,6 +22,7 @@ ] deps = [ "//base", + "//components/cdm/common:buildflags", "//content/public/renderer", "//media", "//media:media_buildflags", @@ -48,4 +50,12 @@ ] deps += [ "//third_party/widevine/cdm:headers" ] } + + if (enable_playready) { + sources += [ + "playready_key_system_info.cc", + "playready_key_system_info.h", + ] + deps += [ "//components/cdm/common" ] + } }
diff --git a/components/cdm/renderer/playready_key_system_info.cc b/components/cdm/renderer/playready_key_system_info.cc new file mode 100644 index 0000000..4a81fe4 --- /dev/null +++ b/components/cdm/renderer/playready_key_system_info.cc
@@ -0,0 +1,127 @@ +// 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/cdm/renderer/playready_key_system_info.h" + +#include "base/logging.h" +#include "base/trace_event/trace_event.h" +#include "components/cdm/common/buildflags.h" +#include "components/cdm/common/playready_cdm_common.h" + +#if !BUILDFLAG(ENABLE_PLAYREADY) +#error This file should only be built when PlayReady is enabled. +#endif + +using media::EmeConfig; +using media::EmeConfigRuleState; +using media::EmeFeatureSupport; +using media::EmeInitDataType; +using media::EmeMediaType; +using media::SupportedCodecs; + +namespace cdm { + +PlayReadyKeySystemInfo::PlayReadyKeySystemInfo( + media::SupportedCodecs hw_secure_codecs, + base::flat_set<media::EncryptionScheme> hw_secure_encryption_schemes) + : hw_secure_codecs_(hw_secure_codecs), + hw_secure_encryption_schemes_(std::move(hw_secure_encryption_schemes)) {} + +PlayReadyKeySystemInfo::~PlayReadyKeySystemInfo() = default; + +std::string PlayReadyKeySystemInfo::GetBaseKeySystemName() const { + return kPlayReadyKeySystemRecommendationDefault; +} + +bool PlayReadyKeySystemInfo::IsSupportedKeySystem( + const std::string& key_system) const { + return IsPlayReadyKeySystem(key_system); +} + +bool PlayReadyKeySystemInfo::ShouldUseBaseKeySystemName() const { + return true; +} + +bool PlayReadyKeySystemInfo::IsSupportedInitDataType( + EmeInitDataType init_data_type) const { + // Here we assume that support for a container imples support for the + // associated initialization data type. KeySystems handles validating + // |init_data_type| x |container| pairings. + + // To make KeySystemConfigSelector::GetSupportedConfiguration work correctly, + // use the hardware secure codecs since there are no supported software codecs + // in Chromium. If software secure codecs (aka. codecs_) is used here when + // the keysystem is "com.microsoft.playready.recommendation", then this will + // always return false which is not correct when robustness=3000. + const media::SupportedCodecs codecs = hw_secure_codecs_; + + if (init_data_type == EmeInitDataType::WEBM) { + return (codecs & media::EME_CODEC_WEBM_ALL) != 0; + } + if (init_data_type == EmeInitDataType::CENC) { + return (codecs & media::EME_CODEC_MP4_ALL) != 0; + } + if (init_data_type == EmeInitDataType::KEYIDS) { + return true; + } + + return false; +} + +EmeConfig::Rule PlayReadyKeySystemInfo::GetEncryptionSchemeConfigRule( + media::EncryptionScheme encryption_scheme) const { + if (hw_secure_encryption_schemes_.count(encryption_scheme)) { + return EmeConfig{.hw_secure_codecs = EmeConfigRuleState::kRequired}; + } + + return EmeConfig::UnsupportedRule(); +} + +SupportedCodecs PlayReadyKeySystemInfo::GetSupportedCodecs() const { + return media::EME_CODEC_NONE; +} + +SupportedCodecs PlayReadyKeySystemInfo::GetSupportedHwSecureCodecs() const { + return hw_secure_codecs_; +} + +// `hw_secure_requirement` is not used here because the +// implementation only supports hardware secure PlayReady +// key systems. Software secure is not supported. +EmeConfig::Rule PlayReadyKeySystemInfo::GetRobustnessConfigRule( + const std::string& key_system, + EmeMediaType media_type, + const std::string& requested_robustness, + const bool* hw_secure_requirement) const { + if (IsPlayReadyHwSecureKeySystem(key_system) && + (requested_robustness.empty() || requested_robustness == "3000")) { + return EmeConfig{.hw_secure_codecs = EmeConfigRuleState::kRequired}; + } + + // Passing the robustness value of "3000" with the recommendation + // key system also implies hardware secure PlayReady. + if (key_system == kPlayReadyKeySystemRecommendationDefault && + requested_robustness == "3000") { + return EmeConfig{.hw_secure_codecs = EmeConfigRuleState::kRequired}; + } + + // Software secure PlayReady is not supported in Chromium. + return EmeConfig::UnsupportedRule(); +} + +EmeConfig::Rule PlayReadyKeySystemInfo::GetPersistentLicenseSessionSupport() + const { + return EmeConfig::UnsupportedRule(); +} + +EmeFeatureSupport PlayReadyKeySystemInfo::GetPersistentStateSupport() const { + return EmeFeatureSupport::ALWAYS_ENABLED; +} + +EmeFeatureSupport PlayReadyKeySystemInfo::GetDistinctiveIdentifierSupport() + const { + return EmeFeatureSupport::ALWAYS_ENABLED; +} + +} // namespace cdm
diff --git a/components/cdm/renderer/playready_key_system_info.h b/components/cdm/renderer/playready_key_system_info.h new file mode 100644 index 0000000..48978f6 --- /dev/null +++ b/components/cdm/renderer/playready_key_system_info.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 COMPONENTS_CDM_RENDERER_PLAYREADY_KEY_SYSTEM_INFO_H_ +#define COMPONENTS_CDM_RENDERER_PLAYREADY_KEY_SYSTEM_INFO_H_ + +#include <string> +#include <vector> + +#include "base/containers/flat_set.h" +#include "media/base/key_system_info.h" + +namespace cdm { + +// Implementation of KeySystemInfo for all PlayReady key systems. +class PlayReadyKeySystemInfo : public media::KeySystemInfo { + public: + PlayReadyKeySystemInfo( + media::SupportedCodecs hw_secure_codecs, + base::flat_set<media::EncryptionScheme> hw_secure_encryption_schemes); + ~PlayReadyKeySystemInfo() override; + + std::string GetBaseKeySystemName() const override; + bool IsSupportedKeySystem(const std::string& key_system) const override; + bool ShouldUseBaseKeySystemName() const override; + bool IsSupportedInitDataType( + media::EmeInitDataType init_data_type) const override; + media::EmeConfig::Rule GetEncryptionSchemeConfigRule( + media::EncryptionScheme encryption_scheme) const override; + media::SupportedCodecs GetSupportedCodecs() const override; + media::SupportedCodecs GetSupportedHwSecureCodecs() const override; + media::EmeConfig::Rule GetRobustnessConfigRule( + const std::string& key_system, + media::EmeMediaType media_type, + const std::string& requested_robustness, + const bool* hw_secure_requirement) const override; + media::EmeConfig::Rule GetPersistentLicenseSessionSupport() const override; + media::EmeConfig GetPersistentUsageRecordSessionSupport() const; + media::EmeFeatureSupport GetPersistentStateSupport() const override; + media::EmeFeatureSupport GetDistinctiveIdentifierSupport() const override; + + private: + const media::SupportedCodecs hw_secure_codecs_; + const base::flat_set<media::EncryptionScheme> hw_secure_encryption_schemes_; +}; + +} // namespace cdm + +#endif // COMPONENTS_CDM_RENDERER_PLAYREADY_KEY_SYSTEM_INFO_H_
diff --git a/components/collaboration/internal/BUILD.gn b/components/collaboration/internal/BUILD.gn index 9a8d12cd..bb69c1d 100644 --- a/components/collaboration/internal/BUILD.gn +++ b/components/collaboration/internal/BUILD.gn
@@ -253,6 +253,7 @@ "//build/android:build_java", "//components/collaboration/public:java", "//components/data_sharing/public:public_java", + "//components/saved_tab_groups/public:java", "//third_party/jni_zero:jni_zero_java", "//url:url_java", ]
diff --git a/components/collaboration/internal/android/collaboration_service_android.cc b/components/collaboration/internal/android/collaboration_service_android.cc index 2514ade1..9529bb9 100644 --- a/components/collaboration/internal/android/collaboration_service_android.cc +++ b/components/collaboration/internal/android/collaboration_service_android.cc
@@ -15,6 +15,7 @@ #include "components/collaboration/public/collaboration_service.h" #include "components/data_sharing/public/android/conversion_utils.h" #include "components/saved_tab_groups/public/android/tab_group_sync_conversions_bridge.h" +#include "components/saved_tab_groups/public/android/tab_group_sync_conversions_utils.h" #include "url/android/gurl_android.h" // Must come after all headers that specialize FromJniType() / ToJniType(). @@ -88,11 +89,11 @@ JNIEnv* env, jlong delegateNativePtr, const JavaParamRef<jstring>& j_sync_group_id, + const JavaParamRef<jobject>& j_local_group_id, jint entry) { - std::string sync_group_id_str = - base::android::ConvertJavaStringToUTF8(env, j_sync_group_id); tab_groups::EitherGroupID either_id = - base::Uuid::ParseLowercase(sync_group_id_str); + tab_groups::JavaSyncOrLocalGroupIdToEitherGroupId(env, j_sync_group_id, + j_local_group_id); collaboration_service_->StartShareOrManageFlow( conversion::GetDelegateUniquePtrFromJava(delegateNativePtr), either_id, @@ -103,11 +104,11 @@ JNIEnv* env, jlong delegateNativePtr, const JavaParamRef<jstring>& j_sync_group_id, + const JavaParamRef<jobject>& j_local_group_id, jint entry) { - std::string sync_group_id_str = - base::android::ConvertJavaStringToUTF8(env, j_sync_group_id); tab_groups::EitherGroupID either_id = - base::Uuid::ParseLowercase(sync_group_id_str); + tab_groups::JavaSyncOrLocalGroupIdToEitherGroupId(env, j_sync_group_id, + j_local_group_id); collaboration_service_->StartLeaveOrDeleteFlow( conversion::GetDelegateUniquePtrFromJava(delegateNativePtr), either_id,
diff --git a/components/collaboration/internal/android/collaboration_service_android.h b/components/collaboration/internal/android/collaboration_service_android.h index 685131c4..8f0a8902 100644 --- a/components/collaboration/internal/android/collaboration_service_android.h +++ b/components/collaboration/internal/android/collaboration_service_android.h
@@ -31,11 +31,13 @@ JNIEnv* env, jlong delegate, const base::android::JavaParamRef<jstring>& j_sync_group_id, + const base::android::JavaParamRef<jobject>& j_local_group_id, jint entry); void StartLeaveOrDeleteFlow( JNIEnv* env, jlong delegate, const base::android::JavaParamRef<jstring>& j_sync_group_id, + const base::android::JavaParamRef<jobject>& j_local_group_id, jint entry); base::android::ScopedJavaLocalRef<jobject> GetServiceStatus(JNIEnv* env); jint GetCurrentUserRoleForGroup(
diff --git a/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/CollaborationServiceImpl.java b/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/CollaborationServiceImpl.java index ff97c4eb..33f9ff3 100644 --- a/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/CollaborationServiceImpl.java +++ b/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/CollaborationServiceImpl.java
@@ -14,6 +14,8 @@ import org.chromium.build.annotations.Nullable; import org.chromium.components.data_sharing.GroupData; import org.chromium.components.data_sharing.member_role.MemberRole; +import org.chromium.components.tab_group_sync.EitherId.EitherGroupId; +import org.chromium.components.tab_group_sync.LocalTabGroupId; import org.chromium.url.GURL; /** @@ -48,19 +50,37 @@ @Override public void startShareOrManageFlow( CollaborationControllerDelegate delegate, - String syncId, + EitherGroupId eitherId, @CollaborationServiceShareOrManageEntryPoint int entry) { + String syncId = null; + LocalTabGroupId localId = null; + if (eitherId.isSyncId()) { + syncId = eitherId.getSyncId(); + } else { + localId = eitherId.getLocalId(); + } + CollaborationServiceImplJni.get() - .startShareOrManageFlow(mNativePtr, delegate.getNativePtr(), syncId, entry); + .startShareOrManageFlow( + mNativePtr, delegate.getNativePtr(), syncId, localId, entry); } @Override public void startLeaveOrDeleteFlow( CollaborationControllerDelegate delegate, - String syncId, + EitherGroupId eitherId, @CollaborationServiceLeaveOrDeleteEntryPoint int entry) { + String syncId = null; + LocalTabGroupId localId = null; + if (eitherId.isSyncId()) { + syncId = eitherId.getSyncId(); + } else { + localId = eitherId.getLocalId(); + } + CollaborationServiceImplJni.get() - .startLeaveOrDeleteFlow(mNativePtr, delegate.getNativePtr(), syncId, entry); + .startLeaveOrDeleteFlow( + mNativePtr, delegate.getNativePtr(), syncId, localId, entry); } @Override @@ -122,13 +142,15 @@ void startShareOrManageFlow( long nativeCollaborationServiceAndroid, long delegateNativePtr, - String syncId, + @Nullable String syncId, + @Nullable LocalTabGroupId localId, int entry); void startLeaveOrDeleteFlow( long nativeCollaborationServiceAndroid, long delegateNativePtr, - String syncId, + @Nullable String syncId, + @Nullable LocalTabGroupId localId, int entry); ServiceStatus getServiceStatus(long nativeCollaborationServiceAndroid);
diff --git a/components/collaboration/internal/collaboration_service_impl.cc b/components/collaboration/internal/collaboration_service_impl.cc index aac1e79..e3b350f 100644 --- a/components/collaboration/internal/collaboration_service_impl.cc +++ b/components/collaboration/internal/collaboration_service_impl.cc
@@ -296,6 +296,11 @@ return SyncStatus::kNotSyncing; } + if (sync_service_->IsSetupInProgress()) { + // Do not update sync status when setup is in progress. + return current_status_.sync_status; + } + syncer::SyncUserSettings* user_settings = sync_service_->GetUserSettings(); // The mapping between the selected type and what is actually sync'ed is done // in `GetUserSelectableTypeInfo()`.
diff --git a/components/collaboration/internal/collaboration_service_impl_unittest.cc b/components/collaboration/internal/collaboration_service_impl_unittest.cc index ec3bb1d..5601097 100644 --- a/components/collaboration/internal/collaboration_service_impl_unittest.cc +++ b/components/collaboration/internal/collaboration_service_impl_unittest.cc
@@ -297,6 +297,18 @@ } } +TEST_F(CollaborationServiceImplTest, SyncStatusChanges_SettingInProgress) { + // By default the test sync service is signed in with sync and every DataType + // enabled. + EXPECT_EQ(service_->GetServiceStatus().sync_status, SyncStatus::kSyncEnabled); + + // Setup in progress does not change sync status. + test_sync_service_->SetSetupInProgress(); + test_sync_service_->SetSignedOut(); + test_sync_service_->FireStateChanged(); + EXPECT_EQ(service_->GetServiceStatus().sync_status, SyncStatus::kSyncEnabled); +} + TEST_F(CollaborationServiceImplTest, ConsumerSigninChanges) { EXPECT_EQ(service_->GetServiceStatus().signin_status, SigninStatus::kNotSignedIn);
diff --git a/components/collaboration/public/android/java/src/org/chromium/components/collaboration/CollaborationService.java b/components/collaboration/public/android/java/src/org/chromium/components/collaboration/CollaborationService.java index 6befab7..92d4b993 100644 --- a/components/collaboration/public/android/java/src/org/chromium/components/collaboration/CollaborationService.java +++ b/components/collaboration/public/android/java/src/org/chromium/components/collaboration/CollaborationService.java
@@ -11,6 +11,7 @@ import org.chromium.build.annotations.Nullable; import org.chromium.components.data_sharing.GroupData; import org.chromium.components.data_sharing.member_role.MemberRole; +import org.chromium.components.tab_group_sync.EitherId.EitherGroupId; import org.chromium.url.GURL; /** @@ -52,24 +53,24 @@ * Starts a new collaboration share or manage flow. * * @param delegate The delegate to perform action on the Android UI. - * @param either_id The ID to identify a tab group. + * @param eitherId The ID to identify a tab group. * @param entry The entry point of the flow. */ void startShareOrManageFlow( CollaborationControllerDelegate delegate, - String syncId, + EitherGroupId eitherId, @CollaborationServiceShareOrManageEntryPoint int entry); /** * Starts a new collaboration leave or delete flow. * * @param delegate The delegate to perform action on the Android UI. - * @param either_id The ID to identify a tab group. + * @param eitherId The ID to identify a tab group. * @param entry The entry point of the flow. */ void startLeaveOrDeleteFlow( CollaborationControllerDelegate delegate, - String syncId, + EitherGroupId eitherId, @CollaborationServiceLeaveOrDeleteEntryPoint int entry); /** Returns the current {@link ServiceStatus} of the service. */
diff --git a/components/device_signals/core/browser/signals_types.h b/components/device_signals/core/browser/signals_types.h index b560846..e6bcb14 100644 --- a/components/device_signals/core/browser/signals_types.h +++ b/components/device_signals/core/browser/signals_types.h
@@ -252,8 +252,13 @@ safe_browsing::SafeBrowsingState safe_browsing_protection_level; bool site_isolation_enabled; - // Enterprise cloud content analysis exclusive + // Enterprise cloud content analysis exclusives enterprise_connectors::EnterpriseRealTimeUrlCheckMode realtime_url_check_mode; + std::vector<std::string> file_downloaded_providers{}; + std::vector<std::string> file_attached_providers{}; + std::vector<std::string> bulk_data_entry_providers{}; + std::vector<std::string> print_providers{}; + std::vector<std::string> security_event_providers{}; }; struct FileSystemInfoResponse : BaseSignalResponse {
diff --git a/components/enterprise/BUILD.gn b/components/enterprise/BUILD.gn index bbaad51..502a582 100644 --- a/components/enterprise/BUILD.gn +++ b/components/enterprise/BUILD.gn
@@ -175,6 +175,7 @@ "common/proto:connectors_proto", "//base/test:test_support", "//components/device_signals/core/browser:test_support", + "//components/device_signals/core/common:features", "//components/enterprise/browser/identifiers", "//components/enterprise/browser/identifiers:test_support", "//components/enterprise/signin:unit_tests",
diff --git a/components/enterprise/browser/reporting/chrome_profile_request_generator.cc b/components/enterprise/browser/reporting/chrome_profile_request_generator.cc index a72ee29..a3677fd 100644 --- a/components/enterprise/browser/reporting/chrome_profile_request_generator.cc +++ b/components/enterprise/browser/reporting/chrome_profile_request_generator.cc
@@ -241,6 +241,23 @@ profile_signals.safe_browsing_protection_level)); profile_signals_report->set_site_isolation_enabled( profile_signals.site_isolation_enabled); + + profile_signals_report->mutable_file_downloaded_providers()->Add( + profile_signals.file_downloaded_providers.begin(), + profile_signals.file_downloaded_providers.end()); + profile_signals_report->mutable_file_attached_providers()->Add( + profile_signals.file_attached_providers.begin(), + profile_signals.file_attached_providers.end()); + profile_signals_report->mutable_bulk_data_entry_providers()->Add( + profile_signals.bulk_data_entry_providers.begin(), + profile_signals.bulk_data_entry_providers.end()); + profile_signals_report->mutable_print_providers()->Add( + profile_signals.print_providers.begin(), + profile_signals.print_providers.end()); + profile_signals_report->mutable_security_event_providers()->Add( + profile_signals.security_event_providers.begin(), + profile_signals.security_event_providers.end()); + profile_report->set_allocated_profile_signals_report( profile_signals_report.release()); }
diff --git a/components/enterprise/browser/reporting/report_scheduler.cc b/components/enterprise/browser/reporting/report_scheduler.cc index 0bcb9ae..55fb4f4 100644 --- a/components/enterprise/browser/reporting/report_scheduler.cc +++ b/components/enterprise/browser/reporting/report_scheduler.cc
@@ -107,6 +107,11 @@ return active_trigger_; } +ReportGenerationConfig ReportScheduler::GetActiveGenerationConfigForTesting() + const { + return active_report_generation_config_; +} + void ReportScheduler::QueueReportUploaderForTesting( std::unique_ptr<ReportUploader> uploader) { report_uploaders_for_test_.push_back(std::move(uploader));
diff --git a/components/enterprise/browser/reporting/report_scheduler.h b/components/enterprise/browser/reporting/report_scheduler.h index 4abb99d..365375b 100644 --- a/components/enterprise/browser/reporting/report_scheduler.h +++ b/components/enterprise/browser/reporting/report_scheduler.h
@@ -117,6 +117,7 @@ bool IsNextReportScheduledForTesting() const; ReportTrigger GetActiveTriggerForTesting() const; + ReportGenerationConfig GetActiveGenerationConfigForTesting() const; void QueueReportUploaderForTesting(std::unique_ptr<ReportUploader> uploader); Delegate* GetDelegateForTesting();
diff --git a/components/enterprise/browser/reporting/report_util.cc b/components/enterprise/browser/reporting/report_util.cc index 44e1ef8..9c99b75 100644 --- a/components/enterprise/browser/reporting/report_util.cc +++ b/components/enterprise/browser/reporting/report_util.cc
@@ -241,6 +241,23 @@ profile_signals_report.safe_browsing_protection_level())); signals_dict.Set("site_isolation_enabled", profile_signals_report.site_isolation_enabled()); + + // Providers section + signals_dict.Set("file_downloaded_providers", + RepeatedFieldptrToList( + profile_signals_report.file_downloaded_providers())); + signals_dict.Set("file_attached_providers", + RepeatedFieldptrToList( + profile_signals_report.file_attached_providers())); + signals_dict.Set("bulk_data_entry_providers", + RepeatedFieldptrToList( + profile_signals_report.bulk_data_entry_providers())); + signals_dict.Set( + "print_providers", + RepeatedFieldptrToList(profile_signals_report.print_providers())); + signals_dict.Set("security_event_providers", + RepeatedFieldptrToList( + profile_signals_report.security_event_providers())); } base::JSONWriter::WriteWithOptions(
diff --git a/components/enterprise/browser/reporting/user_security_signals_service_unittest.cc b/components/enterprise/browser/reporting/user_security_signals_service_unittest.cc index 76775a1..3af9e492 100644 --- a/components/enterprise/browser/reporting/user_security_signals_service_unittest.cc +++ b/components/enterprise/browser/reporting/user_security_signals_service_unittest.cc
@@ -5,8 +5,10 @@ #include "components/enterprise/browser/reporting/user_security_signals_service.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/time/time.h" +#include "components/device_signals/core/common/signals_features.h" #include "components/enterprise/browser/reporting/common_pref_names.h" #include "components/enterprise/browser/reporting/report_util.h" #include "components/prefs/pref_registry_simple.h" @@ -82,14 +84,25 @@ testing_prefs_.SetBoolean(kUserSecurityAuthenticatedReporting, use_auth); } - void CreateUserSecuritySignalsService(bool start_service = false) { + void CreateAndRunSignalsService(bool expect_reporting_enabled = true, + bool expect_using_cookie = false) { + // Creation of the service with the pref value already enabled will trigger + // an upload. + EXPECT_CALL(delegate_, OnReportEventTriggered(_)) + .Times(expect_reporting_enabled ? 1 : 0); + + if (expect_using_cookie) { + EXPECT_CALL(delegate_, GetCookieManager()); + } + service_ = std::make_unique<UserSecuritySignalsService>(&testing_prefs_, &delegate_); + service_->Start(); + task_environment_.RunUntilIdle(); - if (start_service) { - service_->Start(); - task_environment_.RunUntilIdle(); - } + ASSERT_EQ(service_->IsSecuritySignalsReportingEnabled(), + expect_reporting_enabled); + ASSERT_EQ(service_->ShouldUseCookies(), expect_using_cookie); } void FastForwardTimeToTrigger() { @@ -104,6 +117,10 @@ base::Seconds(1)); } + void FastForwardCustomTime(base::TimeDelta time) { + task_environment_.FastForwardBy(time); + } + void TriggerValidCookieInsert() { test_cookie_manager_.DispatchCookieChange(net::CookieChangeInfo( GetTestCookie(GaiaUrls::GetInstance()->secure_google_url(), @@ -117,6 +134,14 @@ } } + // Note: Cadence unit is hours. + void OverrideSecurityUploadCadence(base::TimeDelta new_cadence) { + feature_list_.InitAndEnableFeatureWithParameters( + enterprise_signals::features::kProfileSignalsReportingEnabled, + {{enterprise_signals::features::kProfileSignalsReportingInterval.name, + base::ToString(new_cadence.InHours()) + "h"}}); + } + base::test::TaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; @@ -125,10 +150,12 @@ testing::StrictMock<MockUserSecuritySignalsServiceDelegate> delegate_; network::TestCookieManager test_cookie_manager_; base::HistogramTester histogram_tester_; + base::test::ScopedFeatureList feature_list_; }; TEST_F(UserSecuritySignalsServiceTest, NotStarted) { - CreateUserSecuritySignalsService(); + service_ = + std::make_unique<UserSecuritySignalsService>(&testing_prefs_, &delegate_); EXPECT_FALSE(service_->IsSecuritySignalsReportingEnabled()); EXPECT_FALSE(service_->ShouldUseCookies()); @@ -148,10 +175,7 @@ TEST_F(UserSecuritySignalsServiceTest, PolicyDefault) { EXPECT_CALL(delegate_, OnReportEventTriggered(_)).Times(0); - CreateUserSecuritySignalsService(/*start_service=*/true); - - EXPECT_FALSE(service_->IsSecuritySignalsReportingEnabled()); - EXPECT_FALSE(service_->ShouldUseCookies()); + CreateAndRunSignalsService(/*expect_reporting_enabled=*/false); // No trigger should occur even if we fast forward. FastForwardTimeToTrigger(); @@ -161,15 +185,8 @@ TEST_F(UserSecuritySignalsServiceTest, PolicyEnabledWithoutCookies) { SetEnabledPolicy(true); - // Creation of the service with the pref value already enabled will trigger an - // upload. - EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) - .Times(1); + CreateAndRunSignalsService(); - CreateUserSecuritySignalsService(/*start_service=*/true); - - EXPECT_TRUE(service_->IsSecuritySignalsReportingEnabled()); - EXPECT_FALSE(service_->ShouldUseCookies()); histogram_tester_.ExpectUniqueSample(kReportTriggerMetricName, SecurityReportTrigger::kTimer, 1); } @@ -178,24 +195,17 @@ SetEnabledPolicy(true); SetUseAuthPolicy(true); - // A upload should occur first on service creation. - EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) - .Times(1); - EXPECT_CALL(delegate_, GetCookieManager()); - - CreateUserSecuritySignalsService(/*start_service=*/true); - - EXPECT_TRUE(service_->IsSecuritySignalsReportingEnabled()); - EXPECT_TRUE(service_->ShouldUseCookies()); + CreateAndRunSignalsService(/*expect_reporting_enabled=*/true, + /*expect_using_cookie=*/true); + Mock::VerifyAndClearExpectations(&delegate_); // Fast forwarding should trigger another upload. - Mock::VerifyAndClearExpectations(&delegate_); EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) .Times(1); FastForwardTimeToTrigger(); + Mock::VerifyAndClearExpectations(&delegate_); // Fast forwarding again should trigger another upload. - Mock::VerifyAndClearExpectations(&delegate_); EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) .Times(1); FastForwardTimeToTrigger(); @@ -212,18 +222,12 @@ SetEnabledPolicy(true); SetUseAuthPolicy(true); - // A upload should occur first on service creation. - EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) - .Times(1); - EXPECT_CALL(delegate_, GetCookieManager()); - CreateUserSecuritySignalsService(/*start_service=*/true); - - EXPECT_TRUE(service_->IsSecuritySignalsReportingEnabled()); - EXPECT_TRUE(service_->ShouldUseCookies()); + CreateAndRunSignalsService(/*expect_reporting_enabled=*/true, + /*expect_using_cookie=*/true); + Mock::VerifyAndClearExpectations(&delegate_); // Signaling that a report was uploaded after waiting a halftime means waiting // another halftime should not result in a second report being triggered. - Mock::VerifyAndClearExpectations(&delegate_); EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) .Times(0); FastForwardByHalfTimeToTrigger(); @@ -235,7 +239,7 @@ } TEST_F(UserSecuritySignalsServiceTest, PolicyBecomesEnabledWithoutCookies) { - CreateUserSecuritySignalsService(/*start_service=*/true); + CreateAndRunSignalsService(/*expect_reporting_enabled=*/false); EXPECT_FALSE(service_->IsSecuritySignalsReportingEnabled()); EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) .Times(0); @@ -266,7 +270,10 @@ // Having a broken cookie manager should not cause crashes. EXPECT_CALL(delegate_, GetCookieManager()).WillOnce(Return(nullptr)); - CreateUserSecuritySignalsService(/*start_service=*/true); + service_ = + std::make_unique<UserSecuritySignalsService>(&testing_prefs_, &delegate_); + service_->Start(); + task_environment_.RunUntilIdle(); EXPECT_TRUE(service_->IsSecuritySignalsReportingEnabled()); EXPECT_TRUE(service_->ShouldUseCookies()); @@ -280,15 +287,8 @@ SetEnabledPolicy(true); SetUseAuthPolicy(true); - // A upload should occur first on service creation. - EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) - .Times(1); - EXPECT_CALL(delegate_, GetCookieManager()); - - CreateUserSecuritySignalsService(/*start_service=*/true); - - EXPECT_TRUE(service_->IsSecuritySignalsReportingEnabled()); - EXPECT_TRUE(service_->ShouldUseCookies()); + CreateAndRunSignalsService(/*expect_reporting_enabled=*/true, + /*expect_using_cookie=*/true); EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kCookieChange)) @@ -297,7 +297,6 @@ // Fake that the first-party authentication cookie was inserted for the first // time. TriggerValidCookieInsert(); - FlushForTesting(); histogram_tester_.ExpectBucketCount(kReportTriggerMetricName, @@ -311,15 +310,8 @@ SetEnabledPolicy(true); SetUseAuthPolicy(true); - // A upload should occur first on service creation. - EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) - .Times(1); - EXPECT_CALL(delegate_, GetCookieManager()); - - CreateUserSecuritySignalsService(/*start_service=*/true); - - EXPECT_TRUE(service_->IsSecuritySignalsReportingEnabled()); - EXPECT_TRUE(service_->ShouldUseCookies()); + CreateAndRunSignalsService(/*expect_reporting_enabled=*/true, + /*expect_using_cookie=*/true); EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kCookieChange)) @@ -333,8 +325,8 @@ GetTestCookie(GaiaUrls::GetInstance()->secure_google_url(), GaiaConstants::kGaiaSigninCookieName), net::CookieAccessResult(), net::CookieChangeCause::OVERWRITE)); - TriggerValidCookieInsert(); + TriggerValidCookieInsert(); FlushForTesting(); histogram_tester_.ExpectBucketCount(kReportTriggerMetricName, @@ -348,15 +340,8 @@ SetEnabledPolicy(true); SetUseAuthPolicy(true); - // A upload should occur first on service creation. - EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) - .Times(1); - EXPECT_CALL(delegate_, GetCookieManager()); - - CreateUserSecuritySignalsService(/*start_service=*/true); - - EXPECT_TRUE(service_->IsSecuritySignalsReportingEnabled()); - EXPECT_TRUE(service_->ShouldUseCookies()); + CreateAndRunSignalsService(/*expect_reporting_enabled=*/true, + /*expect_using_cookie=*/true); // Fake that various cookie change events were triggered, none with "INSERT". // This means no additional report should be triggered. @@ -399,11 +384,7 @@ SetEnabledPolicy(true); SetUseAuthPolicy(false); - // A upload should occur first on service creation. - EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) - .Times(1); - - CreateUserSecuritySignalsService(/*start_service=*/true); + CreateAndRunSignalsService(); // Auth policy is not enabled, so this should not trigger any report. TriggerValidCookieInsert(); @@ -429,4 +410,79 @@ SecurityReportTrigger::kCookieChange, 1); } +// Test that verifies if the feature flag param overrides the upload cadence +// correctly. +TEST_F(UserSecuritySignalsServiceTest, FlagOverrideCadence) { + auto default_security_upload_cadence = + UserSecuritySignalsService::GetSecurityUploadCadence(); + + // Overwrite the feature flag parameter to double the upload interval. + OverrideSecurityUploadCadence(default_security_upload_cadence * 2); + + SetEnabledPolicy(true); + + CreateAndRunSignalsService(); + Mock::VerifyAndClearExpectations(&delegate_); + + // Fast forwarding should not trigger another upload, since the internval is + // overwritten. + EXPECT_CALL(delegate_, OnReportEventTriggered(_)).Times(0); + FastForwardCustomTime(default_security_upload_cadence); + Mock::VerifyAndClearExpectations(&delegate_); + + // Fast forwarding again should trigger another upload. + EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) + .Times(1); + FastForwardCustomTime(default_security_upload_cadence); + + histogram_tester_.ExpectUniqueSample(kReportTriggerMetricName, + SecurityReportTrigger::kTimer, 2); +} + +// Test that verifies if the feature flag param overrides the upload cadence +// correctly, even when the timer has already started. Note that this affects +// the timer on next upload while the currently running timer is unaffected. +TEST_F(UserSecuritySignalsServiceTest, FlagOverrideCadenceWhileRunning) { + auto default_security_upload_cadence = + UserSecuritySignalsService::GetSecurityUploadCadence(); + + SetEnabledPolicy(true); + + CreateAndRunSignalsService(); + Mock::VerifyAndClearExpectations(&delegate_); + + // Fast forwarding should trigger another upload, since the interval is still + // at default value. + EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) + .Times(1); + FastForwardCustomTime(default_security_upload_cadence); + Mock::VerifyAndClearExpectations(&delegate_); + + // Overwrite the feature flag parameter to double the upload interval. + OverrideSecurityUploadCadence(default_security_upload_cadence * 2); + + // Fast forwarding should trigger another upload because the timer started + // before we overwrite the interval, so it would be using the old value (i.e + // not doubled). + EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) + .Times(1); + FastForwardCustomTime(default_security_upload_cadence); + Mock::VerifyAndClearExpectations(&delegate_); + + // No upload trigger on first fast forward because interval is already + // doubled now. + EXPECT_CALL(delegate_, OnReportEventTriggered(_)).Times(0); + FastForwardCustomTime(default_security_upload_cadence); + Mock::VerifyAndClearExpectations(&delegate_); + + // Fast forward again should trigger an upload since we reached the new, + // doubled upload deadline. + EXPECT_CALL(delegate_, OnReportEventTriggered(SecurityReportTrigger::kTimer)) + .Times(1); + FastForwardCustomTime(default_security_upload_cadence); + + histogram_tester_.ExpectUniqueSample(kReportTriggerMetricName, + SecurityReportTrigger::kTimer, 4); +} + } // namespace enterprise_reporting
diff --git a/components/enterprise/client_certificates/core/features.cc b/components/enterprise/client_certificates/core/features.cc index 2c36229a..c1e64cf5 100644 --- a/components/enterprise/client_certificates/core/features.cc +++ b/components/enterprise/client_certificates/core/features.cc
@@ -22,4 +22,12 @@ return base::FeatureList::IsEnabled(kManagedBrowserClientCertificateEnabled); } +BASE_FEATURE(kManagedUserClientCertificateInPrefs, + "ManagedUserClientCertificateInPrefs", + base::FEATURE_DISABLED_BY_DEFAULT); + +bool IsManagedUserClientCertificateInPrefsEnabled() { + return base::FeatureList::IsEnabled(kManagedUserClientCertificateInPrefs); +} + } // namespace client_certificates::features
diff --git a/components/enterprise/client_certificates/core/features.h b/components/enterprise/client_certificates/core/features.h index 93e3035..5a63a68 100644 --- a/components/enterprise/client_certificates/core/features.h +++ b/components/enterprise/client_certificates/core/features.h
@@ -23,6 +23,12 @@ // Return true if the managed browser's client cert feature is enabled. bool IsManagedBrowserClientCertificateEnabled(); +// Controls whether user client certs storage relies on prefs or LevelDB. +BASE_DECLARE_FEATURE(kManagedUserClientCertificateInPrefs); + +// Return true if the managed user certificate should be stored in prefs. +bool IsManagedUserClientCertificateInPrefsEnabled(); + } // namespace client_certificates::features #endif // COMPONENTS_ENTERPRISE_CLIENT_CERTIFICATES_CORE_FEATURES_H_
diff --git a/components/enterprise/client_certificates/core/leveldb_certificate_store.cc b/components/enterprise/client_certificates/core/leveldb_certificate_store.cc index 9e54ace..2370731 100644 --- a/components/enterprise/client_certificates/core/leveldb_certificate_store.cc +++ b/components/enterprise/client_certificates/core/leveldb_certificate_store.cc
@@ -13,6 +13,7 @@ #include "base/memory/weak_ptr.h" #include "base/pickle.h" #include "base/task/thread_pool.h" +#include "components/enterprise/client_certificates/core/metrics_util.h" #include "components/enterprise/client_certificates/core/private_key.h" #include "components/enterprise/client_certificates/core/private_key_factory.h" #include "components/enterprise/client_certificates/proto/client_certificates_database.pb.h" @@ -170,7 +171,7 @@ std::move(callback))); } -void LevelDbCertificateStore::InitializeDatabase() { +void LevelDbCertificateStore::InitializeDatabase(bool retry_on_failure) { if (database_state_ != DatabaseState::kUninitialized) { return; } @@ -178,15 +179,25 @@ database_state_ = DatabaseState::kInitializing; database_->Init( base::BindOnce(&LevelDbCertificateStore::OnDatabaseInitialized, - weak_factory_.GetWeakPtr())); + weak_factory_.GetWeakPtr(), retry_on_failure)); } void LevelDbCertificateStore::OnDatabaseInitialized( + bool retry_on_failure, leveldb_proto::Enums::InitStatus status) { database_state_ = status == leveldb_proto::Enums::InitStatus::kOK ? DatabaseState::kInitialized : DatabaseState::kUninitialized; + // Log the status. `retry_on_failure` is only true for the first call. + LogLevelDBInitStatus(status, /*with_retry=*/!retry_on_failure); + + if (retry_on_failure && database_state_ == DatabaseState::kUninitialized) { + // Retry failed DB initialization at least once. + InitializeDatabase(/*retry_on_failure=*/false); + return; + } + for (auto& operation : pending_operations_) { std::move(operation).Run(); }
diff --git a/components/enterprise/client_certificates/core/leveldb_certificate_store.h b/components/enterprise/client_certificates/core/leveldb_certificate_store.h index b9aedc8..7959fc4 100644 --- a/components/enterprise/client_certificates/core/leveldb_certificate_store.h +++ b/components/enterprise/client_certificates/core/leveldb_certificate_store.h
@@ -88,11 +88,12 @@ // Will start the initialization of the Database. Is a no-op is the database // is already initialized. - void InitializeDatabase(); + void InitializeDatabase(bool retry_on_failure = true); // Invoked as callback when the database is done initializing with `status` as // result. - void OnDatabaseInitialized(leveldb_proto::Enums::InitStatus status); + void OnDatabaseInitialized(bool retry_on_failure, + leveldb_proto::Enums::InitStatus status); // Will wait for the database to be initialized and then retrieve the entry // with `identity_name`. If successful, will invoke `callback` with
diff --git a/components/enterprise/client_certificates/core/leveldb_certificate_store_unittest.cc b/components/enterprise/client_certificates/core/leveldb_certificate_store_unittest.cc index ca6d169..279da2cd 100644 --- a/components/enterprise/client_certificates/core/leveldb_certificate_store_unittest.cc +++ b/components/enterprise/client_certificates/core/leveldb_certificate_store_unittest.cc
@@ -177,17 +177,47 @@ ExpectNoDatabaseEntry(""); } -// Tests that no key is returned when failing to initialize the database. -TEST_F(LevelDbCertificateStoreTest, CreatePrivateKey_DatabaseInitFail) { +// Tests that no key is returned when failing to initialize the database, and +// the retry fails. +TEST_F(LevelDbCertificateStoreTest, + CreatePrivateKey_DatabaseInitFail_RetryFail) { base::test::TestFuture<StoreErrorOr<scoped_refptr<PrivateKey>>> test_future; store_->CreatePrivateKey(kTestIdentityName, test_future.GetCallback()); fake_db_->InitStatusCallback(InitStatus::kCorrupt); + fake_db_->InitStatusCallback(InitStatus::kCorrupt); EXPECT_THAT(test_future.Get(), ErrorIs(StoreError::kInvalidDatabaseState)); ExpectNoDatabaseEntry(kTestIdentityName); } +// Tests that no key is returned when failing to initialize the database, but +// the retry succeeds. +TEST_F(LevelDbCertificateStoreTest, + CreatePrivateKey_DatabaseInitFail_RetrySucceeds) { + client_certificates_pb::PrivateKey proto_key = CreateFakeProtoKey(); + + auto mocked_private_key = base::MakeRefCounted<StrictMock<MockPrivateKey>>(); + EXPECT_CALL(*mocked_private_key, ToProto()).WillOnce(Return(proto_key)); + + EXPECT_CALL(*mock_key_factory_, CreatePrivateKey(_)) + .WillOnce(RunOnceCallback<0>(mocked_private_key)); + + base::test::TestFuture<StoreErrorOr<scoped_refptr<PrivateKey>>> test_future; + store_->CreatePrivateKey(kTestIdentityName, test_future.GetCallback()); + + fake_db_->InitStatusCallback(InitStatus::kCorrupt); + fake_db_->InitStatusCallback(InitStatus::kOK); + fake_db_->GetCallback(/*success=*/true); + fake_db_->UpdateCallback(/*success=*/true); + + EXPECT_THAT(test_future.Get(), ValueIs(mocked_private_key)); + + client_certificates_pb::ClientIdentity proto_identity; + *proto_identity.mutable_private_key() = proto_key; + ExpectDatabaseEntry(kTestIdentityName, proto_identity); +} + // Tests that no key is returned when failing to verify that the database // doesn't already have an identity with the same name. TEST_F(LevelDbCertificateStoreTest, CreatePrivateKey_GetIdentityFail) { @@ -328,6 +358,7 @@ test_future.GetCallback()); fake_db_->InitStatusCallback(InitStatus::kCorrupt); + fake_db_->InitStatusCallback(InitStatus::kCorrupt); EXPECT_EQ(test_future.Get(), StoreError::kInvalidDatabaseState); ExpectNoDatabaseEntry(kTestIdentityName); @@ -452,6 +483,7 @@ test_future.GetCallback()); fake_db_->InitStatusCallback(InitStatus::kCorrupt); + fake_db_->InitStatusCallback(InitStatus::kCorrupt); EXPECT_EQ(test_future.Get(), StoreError::kInvalidDatabaseState); ExpectNoDatabaseEntry(kOtherTestIdentityName); @@ -673,6 +705,7 @@ store_->GetIdentity(kTestIdentityName, test_future.GetCallback()); fake_db_->InitStatusCallback(InitStatus::kCorrupt); + fake_db_->InitStatusCallback(InitStatus::kCorrupt); EXPECT_THAT(test_future.Get(), ErrorIs(StoreError::kInvalidDatabaseState)); }
diff --git a/components/enterprise/client_certificates/core/metrics_util.cc b/components/enterprise/client_certificates/core/metrics_util.cc index 3df04cc..0c9cdf3 100644 --- a/components/enterprise/client_certificates/core/metrics_util.cc +++ b/components/enterprise/client_certificates/core/metrics_util.cc
@@ -27,6 +27,10 @@ return success ? "Success" : "Failure"; } +std::string_view WithRetryToString(bool with_retry) { + return with_retry ? "WithRetry" : "NoRetry"; +} + } // namespace void LogProvisioningError(const std::string& logging_context, @@ -108,4 +112,14 @@ source); } +void LogLevelDBInitStatus(leveldb_proto::Enums::InitStatus status, + bool with_retry) { + static constexpr char kLevelDBInitHistogramFormat[] = + "Enterprise.CertificateStore.LevelDB.InitStatus.%s"; + base::UmaHistogramSparse( + base::StringPrintf(kLevelDBInitHistogramFormat, + WithRetryToString(with_retry).data()), + status); +} + } // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/metrics_util.h b/components/enterprise/client_certificates/core/metrics_util.h index 0769049e..b62f3db 100644 --- a/components/enterprise/client_certificates/core/metrics_util.h +++ b/components/enterprise/client_certificates/core/metrics_util.h
@@ -11,6 +11,7 @@ #include "components/enterprise/client_certificates/core/private_key_types.h" #include "components/enterprise/client_certificates/core/store_error.h" #include "components/enterprise/client_certificates/core/upload_client_error.h" +#include "components/leveldb_proto/public/proto_database.h" namespace client_certificates { @@ -54,6 +55,9 @@ void LogPrivateKeyCreationSource(const std::string& logging_context, PrivateKeySource source); +void LogLevelDBInitStatus(leveldb_proto::Enums::InitStatus status, + bool with_retry); + } // namespace client_certificates #endif // COMPONENTS_ENTERPRISE_CLIENT_CERTIFICATES_CORE_METRICS_UTIL_H_
diff --git a/components/enterprise/client_certificates/core/prefs.cc b/components/enterprise/client_certificates/core/prefs.cc index 178962c..fcc5ce4 100644 --- a/components/enterprise/client_certificates/core/prefs.cc +++ b/components/enterprise/client_certificates/core/prefs.cc
@@ -20,6 +20,8 @@ registry->RegisterIntegerPref( prefs::kProvisionManagedClientCertificateForUserPrefs, /*default_value=*/0); + registry->RegisterDictionaryPref(kManagedProfileIdentityName); + registry->RegisterDictionaryPref(kTemporaryManagedProfileIdentityName); } void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
diff --git a/components/enterprise/common/proto/BUILD.gn b/components/enterprise/common/proto/BUILD.gn index d1144a66..f3c7005 100644 --- a/components/enterprise/common/proto/BUILD.gn +++ b/components/enterprise/common/proto/BUILD.gn
@@ -25,6 +25,7 @@ sources = [ "connectors.proto" ] deps = [ + ":connectors_proto", "//components/safe_browsing/core/common/proto:csd_proto", "//components/safe_browsing/core/common/proto:csd_proto_to_value", ]
diff --git a/components/enterprise/common/proto/connectors.proto b/components/enterprise/common/proto/connectors.proto index ca5efc2..e67ca2ce 100644 --- a/components/enterprise/common/proto/connectors.proto +++ b/components/enterprise/common/proto/connectors.proto
@@ -97,6 +97,10 @@ // The email of the currently active user in the content area. Only populated // for Workspace sites. optional string content_area_account_email = 15; + + // The parent URL chain of the frame from which the action was triggered, + // ordered from current frame URL to tab URL, inclusive. + repeated string frame_url_chain = 16; } message ClientMetadata {
diff --git a/components/enterprise/connectors/core/features.cc b/components/enterprise/connectors/core/features.cc index 1ab9014f..d3b864fd 100644 --- a/components/enterprise/connectors/core/features.cc +++ b/components/enterprise/connectors/core/features.cc
@@ -22,4 +22,8 @@ "EnterpriseActiveUserDetection", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kEnterpriseIframeDlpRulesSupport, + "EnterpriseIframeDlpRulesSupport", + base::FEATURE_DISABLED_BY_DEFAULT); + } // namespace enterprise_connectors
diff --git a/components/enterprise/connectors/core/features.h b/components/enterprise/connectors/core/features.h index 6ed39fd..c67a14a 100644 --- a/components/enterprise/connectors/core/features.h +++ b/components/enterprise/connectors/core/features.h
@@ -23,6 +23,10 @@ // content area user email to DLP/reporting requests on Workspace sites. BASE_DECLARE_FEATURE(kEnterpriseActiveUserDetection); +// Controls whether the iFrame parent url chain initiated from the active frame +// will be attached to DLP scan requests. +BASE_DECLARE_FEATURE(kEnterpriseIframeDlpRulesSupport); + } // namespace enterprise_connectors #endif // COMPONENTS_ENTERPRISE_CONNECTORS_CORE_FEATURES_H_
diff --git a/components/facilitated_payments/core/features/features.cc b/components/facilitated_payments/core/features/features.cc index 56f5721..8ffc686 100644 --- a/components/facilitated_payments/core/features/features.cc +++ b/components/facilitated_payments/core/features/features.cc
@@ -25,6 +25,12 @@ "DisableFacilitatedPaymentsMerchantAllowlist", base::FEATURE_DISABLED_BY_DEFAULT); +// When enabled, Chrome will prompt users without linked Pix accounts to link +// their Pix accounts to Google Wallet. +BASE_FEATURE(kEnablePixAccountLinking, + "EnablePixAccountLinking", + base::FEATURE_DISABLED_BY_DEFAULT); + // When enabled, Chrome will offer to pay with eWallet accounts if a payment // link is detected. BASE_FEATURE(kEwalletPayments,
diff --git a/components/facilitated_payments/core/features/features.h b/components/facilitated_payments/core/features/features.h index 4caf5e0..726daca 100644 --- a/components/facilitated_payments/core/features/features.h +++ b/components/facilitated_payments/core/features/features.h
@@ -14,6 +14,7 @@ BASE_DECLARE_FEATURE(kEnablePixPaymentsInLandscapeMode); #if BUILDFLAG(IS_ANDROID) BASE_DECLARE_FEATURE(kDisableFacilitatedPaymentsMerchantAllowlist); +BASE_DECLARE_FEATURE(kEnablePixAccountLinking); BASE_DECLARE_FEATURE(kEwalletPayments); #endif // BUILDFLAG(IS_ANDROID) BASE_DECLARE_FEATURE(kSupportMultipleServerRequestsForPixPayments);
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc index b7ed803..88327f95 100644 --- a/components/feature_engagement/public/feature_constants.cc +++ b/components/feature_engagement/public/feature_constants.cc
@@ -74,6 +74,24 @@ BASE_FEATURE(kIPHExtensionsRequestAccessButtonFeature, "IPH_ExtensionsRequestAccessButton", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kIPHExtensionsZeroStatePromoFeature, + "IPH_ExtensionsZeroStatePromo", + base::FEATURE_DISABLED_BY_DEFAULT); +const base::FeatureParam<IPHExtensionsZeroStatePromoVariant>::Option + kIPHExtensionsZeroStatePromoVariantOptions[] = { + {IPHExtensionsZeroStatePromoVariant::kCustomActionIph, + "custom-action-iph"}, + {IPHExtensionsZeroStatePromoVariant::kCustomUiChipIph, + "custom-ui-chip-iph"}, + {IPHExtensionsZeroStatePromoVariant::kCustomUIPlainLinkIph, + "custom-ui-plain-link-iph"}}; +BASE_FEATURE_ENUM_PARAM( + IPHExtensionsZeroStatePromoVariant, + kIPHExtensionsZeroStatePromoVariantParam, + &feature_engagement::kIPHExtensionsZeroStatePromoFeature, + "iph-variant", + IPHExtensionsZeroStatePromoVariant::kCustomUiChipIph, + &kIPHExtensionsZeroStatePromoVariantOptions); #endif BASE_FEATURE(kIPHFocusHelpBubbleScreenReaderPromoFeature, "IPH_FocusHelpBubbleScreenReaderPromo",
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h index 38a5379..ec58e1a 100644 --- a/components/feature_engagement/public/feature_constants.h +++ b/components/feature_engagement/public/feature_constants.h
@@ -49,6 +49,23 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHExtensionsMenuFeature); FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHExtensionsRequestAccessButtonFeature); +FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHExtensionsZeroStatePromoFeature); +// The variant of In-Product-Help (IPH) shown to users with zero extensions +// installed. +enum IPHExtensionsZeroStatePromoVariant { + // A custom action IPH. Triggering the action opens a new tab to the Chrome + // Web Store home page. + kCustomActionIph, + // A custom UI IPH, presenting the user with different collections of + // extension collections in cr-chip buttons. + kCustomUiChipIph, + // A custom UI IPH, presenting the user with different collections of + // extension collections in plain text links. + kCustomUIPlainLinkIph, +}; +COMPONENT_EXPORT(FEATURE_ENGAGEMENT_FEATURE_CONSTANTS) +BASE_DECLARE_FEATURE_PARAM(IPHExtensionsZeroStatePromoVariant, + kIPHExtensionsZeroStatePromoVariantParam); #endif FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHFocusHelpBubbleScreenReaderPromoFeature); FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHGlicPromoFeature);
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc index 4c6b202..0b126003 100644 --- a/components/feature_engagement/public/feature_list.cc +++ b/components/feature_engagement/public/feature_list.cc
@@ -210,6 +210,7 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) &kIPHExtensionsMenuFeature, &kIPHExtensionsRequestAccessButtonFeature, + &kIPHExtensionsZeroStatePromoFeature, #endif &kIPHFocusHelpBubbleScreenReaderPromoFeature, &kIPHGMCCastStartStopFeature,
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h index 3172cc3..41a90a8 100644 --- a/components/feature_engagement/public/feature_list.h +++ b/components/feature_engagement/public/feature_list.h
@@ -367,6 +367,8 @@ DEFINE_VARIATION_PARAM(kIPHExtensionsMenuFeature, "IPH_ExtensionsMenu"); DEFINE_VARIATION_PARAM(kIPHExtensionsRequestAccessButtonFeature, "IPH_ExtensionsRequestAccessButton"); +DEFINE_VARIATION_PARAM(kIPHExtensionsZeroStatePromoFeature, + "IPH_ExtensionsZeroStatePromo"); #endif DEFINE_VARIATION_PARAM(kIPHGMCCastStartStopFeature, "IPH_GMCCastStartStop"); DEFINE_VARIATION_PARAM(kIPHGMCLocalMediaCastingFeature,
diff --git a/components/ip_protection/common/ip_protection_telemetry.h b/components/ip_protection/common/ip_protection_telemetry.h index 776c83a6..edad6b4c 100644 --- a/components/ip_protection/common/ip_protection_telemetry.h +++ b/components/ip_protection/common/ip_protection_telemetry.h
@@ -82,6 +82,14 @@ }; // LINT.ThenChange(//tools/metrics/histograms/metadata/network/enums.xml:IpProtectionGetAuthTokenResultForGeo) +// An enumeration of events affecting the token count. +enum class IpProtectionTokenCountEvent { + kIssued = 0, + kSpent = 1, + kExpired = 2, + kMaxValue = kExpired, +}; + // An abstract interface for all of the telemetry associated with IP Protection. // // This is implemented by each telemetry platform, and a singleton made @@ -216,6 +224,12 @@ // QUIC proxies failed and the fallback HTTPS proxies succeeded. The argument // is the number of requests made with QUIC proxies before this failure. virtual void QuicProxiesFailed(int after_requests) = 0; + + // Records the number of tokens involved in a specific event (request, spend, + // expiration). `count` is the number of tokens. + virtual void RecordTokenCountEvent(ProxyLayer layer, + IpProtectionTokenCountEvent event, + int count) = 0; }; // Get the singleton instance of this type. This will be implemented by each
diff --git a/components/ip_protection/common/ip_protection_telemetry_uma.cc b/components/ip_protection/common/ip_protection_telemetry_uma.cc index 7566e9e..27b3ec2 100644 --- a/components/ip_protection/common/ip_protection_telemetry_uma.cc +++ b/components/ip_protection/common/ip_protection_telemetry_uma.cc
@@ -55,6 +55,20 @@ } } +// Converts an IpProtectionTokenCountEvent enum value to its corresponding +// string representation for histogram naming. +std::string TokenCountEventToString(IpProtectionTokenCountEvent event) { + switch (event) { + case IpProtectionTokenCountEvent::kIssued: + return "Issued"; + case IpProtectionTokenCountEvent::kSpent: + return "Spent"; + case IpProtectionTokenCountEvent::kExpired: + return "Expired"; + } + NOTREACHED(); +} + } // namespace IpProtectionTelemetry& Telemetry() { @@ -325,4 +339,23 @@ after_requests); } +void IpProtectionTelemetryUma::RecordTokenCountEvent( + ProxyLayer layer, + IpProtectionTokenCountEvent event, + int count) { + // Construct the histogram name dynamically based on the layer and event type. + // Example: "NetworkService.IpProtection.ProxyA.TokenCount.Issued" + std::string histogram_name = base::StrCat({ + "NetworkService.IpProtection.", + ProxyLayerToString(layer), + ".TokenCount.", + TokenCountEventToString(event), + }); + + // Using a maximum of 1000 counts, since the maximum number of tokens per + // event would generally be around the batch or cache size which is typically + // much less than 1000. + base::UmaHistogramCounts1000(histogram_name, count); +} + } // namespace ip_protection
diff --git a/components/ip_protection/common/ip_protection_telemetry_uma.h b/components/ip_protection/common/ip_protection_telemetry_uma.h index 9ec839b..f8b7309 100644 --- a/components/ip_protection/common/ip_protection_telemetry_uma.h +++ b/components/ip_protection/common/ip_protection_telemetry_uma.h
@@ -59,6 +59,9 @@ void ProbabilisticRevealTokenRandomizationTime( base::TimeDelta duration) override; void QuicProxiesFailed(int after_requests) override; + void RecordTokenCountEvent(ProxyLayer layer, + IpProtectionTokenCountEvent event, + int count) override; }; } // namespace ip_protection
diff --git a/components/ip_protection/common/ip_protection_token_manager_impl.cc b/components/ip_protection/common/ip_protection_token_manager_impl.cc index 809cc36..ec2d7ff8 100644 --- a/components/ip_protection/common/ip_protection_token_manager_impl.cc +++ b/components/ip_protection/common/ip_protection_token_manager_impl.cc
@@ -304,6 +304,10 @@ std::deque<BlindSignedAuthToken>& cache = cache_by_geo_[geo_id_from_token]; + // Log the number of tokens successfully fetched. + Telemetry().RecordTokenCountEvent( + proxy_layer_, IpProtectionTokenCountEvent::kIssued, tokens->size()); + cache.insert(cache.end(), std::make_move_iterator(tokens->begin()), std::make_move_iterator(tokens->end())); std::sort(cache.begin(), cache.end(), @@ -366,6 +370,8 @@ result.emplace(std::move(it->second.front())); it->second.pop_front(); tokens_spent_++; + Telemetry().RecordTokenCountEvent(proxy_layer_, + IpProtectionTokenCountEvent::kSpent, 1); } Telemetry().GetAuthTokenResultForGeo( @@ -384,11 +390,20 @@ std::deque<BlindSignedAuthToken>& tokens = it->second; // Remove expired tokens from each geo. Tokens are sorted and sooner // expirations are toward the front of the deque. + int64_t intial_tokens_expired = tokens_expired_; while (!tokens.empty() && tokens.front().expiration <= fresh_after) { tokens.pop_front(); tokens_expired_++; } + // Only emit expired token metric if tokens actually expired. + int64_t tokens_expired_delta = tokens_expired_ - intial_tokens_expired; + if (tokens_expired_delta > 0) { + Telemetry().RecordTokenCountEvent(proxy_layer_, + IpProtectionTokenCountEvent::kExpired, + tokens_expired_delta); + } + // A map entry should be removed if the entry contains no tokens and the // current geo does not match. if (tokens.empty()) {
diff --git a/components/ip_protection/common/ip_protection_token_manager_impl_unittest.cc b/components/ip_protection/common/ip_protection_token_manager_impl_unittest.cc index a9a9b510..ab84b75 100644 --- a/components/ip_protection/common/ip_protection_token_manager_impl_unittest.cc +++ b/components/ip_protection/common/ip_protection_token_manager_impl_unittest.cc
@@ -47,6 +47,18 @@ "NetworkService.IpProtection.TokenBatchGenerationTime"; constexpr char kGetAuthTokenResultForGeoHistogram[] = "NetworkService.IpProtection.GetAuthTokenResultForGeo"; +constexpr char kProxyATokenCountIssuedHistogram[] = + "NetworkService.IpProtection.ProxyA.TokenCount.Issued"; +constexpr char kProxyATokenCountSpentHistogram[] = + "NetworkService.IpProtection.ProxyA.TokenCount.Spent"; +constexpr char kProxyATokenCountExpiredHistogram[] = + "NetworkService.IpProtection.ProxyA.TokenCount.Expired"; +constexpr char kProxyBTokenCountIssuedHistogram[] = + "NetworkService.IpProtection.ProxyB.TokenCount.Issued"; +constexpr char kProxyBTokenCountSpentHistogram[] = + "NetworkService.IpProtection.ProxyB.TokenCount.Spent"; +constexpr char kProxyBTokenCountExpiredHistogram[] = + "NetworkService.IpProtection.ProxyB.TokenCount.Expired"; constexpr base::TimeDelta kTokenLimitExceededDelay = base::Minutes(10); constexpr base::TimeDelta kTokenRateMeasurementInterval = base::Minutes(5); @@ -472,7 +484,8 @@ CallTryGetAuthTokensAndWait(ProxyLayer::kProxyA); ASSERT_TRUE(ipp_proxy_a_token_fetcher_->GotAllExpectedMockCalls()); - auto got_token = ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); + std::optional<BlindSignedAuthToken> got_token = + ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); EXPECT_EQ(got_token.value().token, "good-token"); EXPECT_EQ(got_token.value().expiration, kFutureExpiration); EXPECT_EQ(got_token.value().geo_hint, kMountainViewGeo); @@ -490,7 +503,8 @@ CallTryGetAuthTokensAndWait(ProxyLayer::kProxyA); ASSERT_TRUE(ipp_proxy_a_token_fetcher_->GotAllExpectedMockCalls()); - auto got_token = ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); + std::optional<BlindSignedAuthToken> got_token = + ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); EXPECT_EQ(got_token.value().token, "token-0"); EXPECT_LT(got_token.value().expiration, kFutureExpiration); EXPECT_EQ(got_token.value().geo_hint, kMountainViewGeo); @@ -529,7 +543,7 @@ // Get four tokens from the batch. for (int i = 0; i < 4; i++) { - auto got_token = + std::optional<BlindSignedAuthToken> got_token = ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); EXPECT_EQ(got_token.value().token, base::StringPrintf("token-%d", i)); EXPECT_EQ(got_token.value().expiration, kFutureExpiration); @@ -542,7 +556,8 @@ histogram_tester_.ExpectUniqueSample(kProxyATokenSpendRateHistogram, 48, 1); // Get the remaining token in the batch. - auto got_token = ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); + std::optional<BlindSignedAuthToken> got_token = + ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); EXPECT_EQ(got_token.value().token, "token-4"); EXPECT_EQ(got_token.value().expiration, kFutureExpiration); @@ -567,7 +582,8 @@ ASSERT_TRUE(ipp_proxy_a_token_fetcher_->GotAllExpectedMockCalls()); // Try to get a token, which will incidentally record the expired tokens. - auto got_token = ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); + std::optional<BlindSignedAuthToken> got_token = + ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); EXPECT_FALSE(got_token); // Fast-forward to run the measurement timer. @@ -598,7 +614,7 @@ // Get four tokens from the batch. for (int i = 0; i < 4; i++) { - auto got_token = + std::optional<BlindSignedAuthToken> got_token = ipp_proxy_b_token_manager_->GetAuthToken(kMountainViewGeoId); EXPECT_EQ(got_token.value().token, base::StringPrintf("token-%d", i)); EXPECT_EQ(got_token.value().expiration, kFutureExpiration); @@ -611,7 +627,8 @@ histogram_tester_.ExpectUniqueSample(kProxyBTokenSpendRateHistogram, 48, 1); // Get the remaining token in the batch. - auto got_token = ipp_proxy_b_token_manager_->GetAuthToken(kMountainViewGeoId); + std::optional<BlindSignedAuthToken> got_token = + ipp_proxy_b_token_manager_->GetAuthToken(kMountainViewGeoId); EXPECT_EQ(got_token.value().token, "token-4"); EXPECT_EQ(got_token.value().expiration, kFutureExpiration); @@ -636,7 +653,8 @@ ASSERT_TRUE(ipp_proxy_b_token_fetcher_->GotAllExpectedMockCalls()); // Try to get a token, which will incidentally record the expired tokens. - auto got_token = ipp_proxy_b_token_manager_->GetAuthToken(kMountainViewGeoId); + std::optional<BlindSignedAuthToken> got_token = + ipp_proxy_b_token_manager_->GetAuthToken(kMountainViewGeoId); EXPECT_FALSE(got_token); // Fast-forward to run the measurement timer. @@ -779,7 +797,8 @@ ipp_proxy_a_token_manager_->IsAuthTokenAvailable(kMountainViewGeoId)); // The un-expired token should be returned. - auto got_token = ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); + std::optional<BlindSignedAuthToken> got_token = + ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); EXPECT_EQ(got_token.value().token, "exp3"); // Histogram should have no samples because after the initial fill there was @@ -1108,5 +1127,129 @@ histogram_tester_.ExpectBucketCount(kGeoChangeTokenPresence, true, 1); histogram_tester_.ExpectBucketCount(kGeoChangeTokenPresence, false, 1); } + +// Verify that requesting tokens logs the correct histogram count. +TEST_F(IpProtectionTokenManagerImplTest, TokenCountRequested) { + const int batch_size = 5; + ipp_proxy_a_token_fetcher_->ExpectTryGetAuthTokensCall( + expected_batch_size_, + TokenBatch(batch_size, kFutureExpiration, kMountainViewGeo)); + CallTryGetAuthTokensAndWait(ProxyLayer::kProxyA); + ASSERT_TRUE(ipp_proxy_a_token_fetcher_->GotAllExpectedMockCalls()); + + // Verify that 5 tokens were recorded as issued for ProxyA. + histogram_tester_.ExpectUniqueSample(kProxyATokenCountIssuedHistogram, + batch_size, 1); + // Verify other histograms were not recorded. + histogram_tester_.ExpectTotalCount(kProxyATokenCountSpentHistogram, 0); + histogram_tester_.ExpectTotalCount(kProxyATokenCountExpiredHistogram, 0); + histogram_tester_.ExpectTotalCount(kProxyBTokenCountIssuedHistogram, 0); +} + +// Verify that spending a token logs the correct histogram count. +TEST_F(IpProtectionTokenManagerImplTest, TokenCountSpent) { + // Fill the cache. + ipp_proxy_a_token_fetcher_->ExpectTryGetAuthTokensCall( + expected_batch_size_, TokenBatch(1, kFutureExpiration, kMountainViewGeo)); + CallTryGetAuthTokensAndWait(ProxyLayer::kProxyA); + ASSERT_TRUE(ipp_proxy_a_token_fetcher_->GotAllExpectedMockCalls()); + histogram_tester_.ExpectUniqueSample(kProxyATokenCountIssuedHistogram, 1, 1); + + // Get the token. + std::optional<BlindSignedAuthToken> got_token = + ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); + ASSERT_TRUE(got_token); + + // Verify that 1 token was recorded as spent for ProxyA. + histogram_tester_.ExpectUniqueSample(kProxyATokenCountSpentHistogram, 1, 1); + // Verify other histograms were not recorded (beyond the initial issue). + histogram_tester_.ExpectTotalCount(kProxyATokenCountExpiredHistogram, 0); + histogram_tester_.ExpectTotalCount(kProxyBTokenCountSpentHistogram, 0); +} + +// Verify that expired tokens log the correct histogram count. +TEST_F(IpProtectionTokenManagerImplTest, TokenCountExpired) { + const int expired_count = 3; + // Fill the cache with expired tokens. + ipp_proxy_a_token_fetcher_->ExpectTryGetAuthTokensCall( + expected_batch_size_, + TokenBatch(expired_count, kPastExpiration, kMountainViewGeo)); + CallTryGetAuthTokensAndWait(ProxyLayer::kProxyA); + ASSERT_TRUE(ipp_proxy_a_token_fetcher_->GotAllExpectedMockCalls()); + histogram_tester_.ExpectUniqueSample(kProxyATokenCountIssuedHistogram, + expired_count, 1); + + // Attempt to get a token, which triggers RemoveExpiredTokens. + std::optional<BlindSignedAuthToken> got_token = + ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId); + ASSERT_FALSE(got_token); + + // Verify that 3 tokens were recorded as expired (each logged individually). + histogram_tester_.ExpectUniqueSample(kProxyATokenCountExpiredHistogram, + expired_count, + /*expected_bucket_count=*/1); + // Verify other histograms were not recorded (beyond the initial issue). + histogram_tester_.ExpectTotalCount(kProxyATokenCountSpentHistogram, 0); + histogram_tester_.ExpectTotalCount(kProxyBTokenCountExpiredHistogram, 0); +} + +// Verify that events for different proxy layers are recorded separately. +TEST_F(IpProtectionTokenManagerImplTest, TokenCountProxyLayerSeparation) { + // Issue 5 tokens for Proxy A. + ipp_proxy_a_token_fetcher_->ExpectTryGetAuthTokensCall( + expected_batch_size_, TokenBatch(5, kFutureExpiration, kMountainViewGeo)); + CallTryGetAuthTokensAndWait(ProxyLayer::kProxyA); + ASSERT_TRUE(ipp_proxy_a_token_fetcher_->GotAllExpectedMockCalls()); + + // Issue 3 tokens for Proxy B. + ipp_proxy_b_token_fetcher_->ExpectTryGetAuthTokensCall( + expected_batch_size_, TokenBatch(3, kFutureExpiration, kMountainViewGeo)); + CallTryGetAuthTokensAndWait(ProxyLayer::kProxyB); + ASSERT_TRUE(ipp_proxy_b_token_fetcher_->GotAllExpectedMockCalls()); + + // Spend 1 token for Proxy A. + ASSERT_TRUE(ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId)); + + // Spend 1 token for Proxy B. + ASSERT_TRUE(ipp_proxy_b_token_manager_->GetAuthToken(kMountainViewGeoId)); + + // Verify Proxy A counts. + histogram_tester_.ExpectUniqueSample(kProxyATokenCountIssuedHistogram, 5, 1); + histogram_tester_.ExpectUniqueSample(kProxyATokenCountSpentHistogram, 1, 1); + histogram_tester_.ExpectTotalCount(kProxyATokenCountExpiredHistogram, 0); + + // Verify Proxy B counts. + histogram_tester_.ExpectUniqueSample(kProxyBTokenCountIssuedHistogram, 3, 1); + histogram_tester_.ExpectUniqueSample(kProxyBTokenCountSpentHistogram, 1, 1); + histogram_tester_.ExpectTotalCount(kProxyBTokenCountExpiredHistogram, 0); +} + +// Verify multiple event types are recorded correctly within one manager. +TEST_F(IpProtectionTokenManagerImplTest, TokenCountMultipleEvents) { + // Issue 5 tokens, 2 of which are already expired. + std::vector<BlindSignedAuthToken> tokens = + TokenBatch(3, kFutureExpiration, kMountainViewGeo); + std::vector<BlindSignedAuthToken> expired_tokens = + TokenBatch(2, kPastExpiration, kMountainViewGeo); + tokens.insert(tokens.end(), std::make_move_iterator(expired_tokens.begin()), + std::make_move_iterator(expired_tokens.end())); + + ipp_proxy_a_token_fetcher_->ExpectTryGetAuthTokensCall(expected_batch_size_, + std::move(tokens)); + CallTryGetAuthTokensAndWait(ProxyLayer::kProxyA); + ASSERT_TRUE(ipp_proxy_a_token_fetcher_->GotAllExpectedMockCalls()); + + // Spend 1 token (this also triggers removal of expired tokens). + ASSERT_TRUE(ipp_proxy_a_token_manager_->GetAuthToken(kMountainViewGeoId)); + + // Verify counts. + histogram_tester_.ExpectUniqueSample(kProxyATokenCountIssuedHistogram, 5, + 1); // 3 good + 2 expired + histogram_tester_.ExpectUniqueSample(kProxyATokenCountSpentHistogram, 1, 1); + histogram_tester_.ExpectUniqueSample( + kProxyATokenCountExpiredHistogram, /*sample=*/2, + /*expected_bucket_count=*/1); // 2 expired tokens removed +} + } // namespace } // namespace ip_protection
diff --git a/components/live_caption/views/DEPS b/components/live_caption/views/DEPS new file mode 100644 index 0000000..21a3fd6 --- /dev/null +++ b/components/live_caption/views/DEPS
@@ -0,0 +1,7 @@ +specific_include_rules = { + "caption_bubble_browsertest.cc": [ + "+chrome/browser/ui", + "+chrome/test", + "+content/public", + ] +}
diff --git a/components/live_caption/views/caption_bubble.cc b/components/live_caption/views/caption_bubble.cc index 92ec2326..dbebcc6 100644 --- a/components/live_caption/views/caption_bubble.cc +++ b/components/live_caption/views/caption_bubble.cc
@@ -982,7 +982,7 @@ } // Call this after SetCaptionButtonStyle(), not before, since - // SetCaptionButtonStyle() calls set_background_color(), which + // SetCaptionButtonStyle() calls SetBackgroundColor(), which // OnThemeChanged() will trigger a read of. views::BubbleDialogDelegateView::OnThemeChanged(); } @@ -1491,7 +1491,7 @@ &background_color, color_provider); } - set_background_color(background_color); + views::BubbleDialogDelegateView::SetBackgroundColor(background_color); GetWidget()->SetColorModeOverride(ui::ColorProviderKey::ColorMode::kDark); }
diff --git a/components/live_caption/views/caption_bubble_browsertest.cc b/components/live_caption/views/caption_bubble_browsertest.cc new file mode 100644 index 0000000..0eaecbc68 --- /dev/null +++ b/components/live_caption/views/caption_bubble_browsertest.cc
@@ -0,0 +1,144 @@ +// 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/live_caption/views/caption_bubble.h" + +#include <memory> +#include <utility> + +#include "base/cfi_buildflags.h" +#include "base/functional/callback.h" +#include "base/functional/callback_forward.h" +#include "base/scoped_observation.h" +#include "base/strings/strcat.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "base/task/bind_post_task.h" +#include "base/task/thread_pool/thread_pool_instance.h" +#include "base/test/bind.h" +#include "base/test/metrics/user_action_tester.h" +#include "base/test/scoped_feature_list.h" +#include "base/test/test_future.h" +#include "base/test/test_timeouts.h" +#include "base/types/expected.h" +#include "build/build_config.h" +#include "caption_bubble_model.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/confirm_bubble.h" +#include "chrome/browser/ui/test/test_browser_ui.h" +#include "chrome/browser/ui/views/accessibility/caption_bubble_context_views.h" +#include "chrome/test/base/interactive_test_utils.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/live_caption/caption_bubble_context.h" +#include "components/live_caption/caption_bubble_controller.h" +#include "components/live_caption/caption_bubble_settings.h" +#include "components/live_caption/live_caption_bubble_settings.h" +#include "components/live_caption/pref_names.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" +#include "components/prefs/testing_pref_service.h" +#include "content/public/test/browser_test.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/test/ui_controls.h" + +namespace captions { +namespace { + +constexpr char kEnglishLanguage[] = "en-US"; + +class CaptionBubbleBrowserTest : public UiBrowserTest { + protected: + CaptionBubbleBrowserTest() = default; + + void SetUpOnMainThread() override { + pref_service_.registry()->RegisterBooleanPref( + prefs::kLiveCaptionBubbleExpanded, false); + pref_service_.registry()->RegisterBooleanPref(prefs::kLiveTranslateEnabled, + false); + pref_service_.registry()->RegisterBooleanPref(prefs::kLiveCaptionEnabled, + false); + pref_service_.registry()->RegisterStringPref( + prefs::kLiveCaptionLanguageCode, kEnglishLanguage); + pref_service_.registry()->RegisterStringPref( + prefs::kLiveTranslateTargetLanguageCode, kEnglishLanguage); + UiBrowserTest::SetUpOnMainThread(); + } + + void TearDownOnMainThread() override { + context_.reset(); + UiBrowserTest::TearDownOnMainThread(); + } + + // UiBrowserTest: + void ShowUi(const std::string& name) override { + context_ = std::make_unique<CaptionBubbleContextViews>( + browser()->GetActiveTabInterface()->GetContents()); + OnCaptionBubbleClosedCallback callback; + model_ = std::make_unique<CaptionBubbleModel>(context_.get(), + std::move(callback)); + settings_ = std::make_unique<LiveCaptionBubbleSettings>(&pref_service_); + settings_->SetLiveCaptionBubbleExpanded(true); + + const std::string application_locale; + base::OnceClosure destroyed_callback; + auto bubble = std::make_unique<CaptionBubble>( + settings_.get(), application_locale, std::move(destroyed_callback)); + bubble_ = bubble.get(); + views::BubbleDialogDelegateView::CreateBubble(std::move(bubble))->Show(); + bubble_->SetModel(model_.get()); + model_->SetPartialText("ABCDEF"); + model_->CommitPartialText(); + } + + // These next two are not necessary if subclassing DialogBrowserTest. + bool VerifyUi() override { + views::Widget* widget = GetWidgetForScreenshot(); + + auto* const test_info = + testing::UnitTest::GetInstance()->current_test_info(); + const std::string screenshot_name = + base::StrCat({test_info->test_suite_name(), "_", test_info->name()}); + + return VerifyPixelUi(widget, "CaptureBubblePixelTest", screenshot_name) != + ui::test::ActionResult::kFailed; + } + + void DismissUi() override { + if (bubble_) { + bubble_->SetModel(nullptr); + bubble_ = nullptr; + } + IgnoreNetworkServiceCrashes(); + } + + void WaitForUserDismissal() override { + /* Block until the UI has been dismissed. */ + ui_test_utils::WaitForBrowserToClose(); + if (bubble_) { + bubble_->SetModel(nullptr); + bubble_ = nullptr; + } + IgnoreNetworkServiceCrashes(); + } + + private: + views::Widget* GetWidgetForScreenshot() { return bubble_->GetWidget(); } + + TestingPrefServiceSimple pref_service_; + + std::unique_ptr<CaptionBubbleContextViews> context_; + std::unique_ptr<CaptionBubbleModel> model_; + std::unique_ptr<LiveCaptionBubbleSettings> settings_; + raw_ptr<CaptionBubble> bubble_; +}; + +// Test that calls ShowUi("default"). +IN_PROC_BROWSER_TEST_F(CaptionBubbleBrowserTest, InvokeUi_default) { + ShowAndVerifyUi(); +} + +} // namespace +} // namespace captions
diff --git a/components/omnibox/browser/autocomplete_grouper_sections.cc b/components/omnibox/browser/autocomplete_grouper_sections.cc index 268b6be..f8f5583 100644 --- a/components/omnibox/browser/autocomplete_grouper_sections.cc +++ b/components/omnibox/browser/autocomplete_grouper_sections.cc
@@ -10,8 +10,13 @@ #include "base/containers/contains.h" #include "base/dcheck_is_on.h" +#include "base/debug/dump_without_crashing.h" +#include "base/notreached.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" #include "components/omnibox/browser/autocomplete_grouper_groups.h" #include "components/omnibox/browser/autocomplete_match.h" +#include "components/omnibox/browser/autocomplete_match_type.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/common/omnibox_feature_configs.h" #include "third_party/omnibox_proto/groups.pb.h" @@ -108,6 +113,61 @@ : Section(limit, std::move(groups), group_configs, side_type) {} void ZpsSection::InitFromMatches(ACMatches& matches) { + // Ensure matches are sorted in the order of their potential containing + // groups. E.g., if `groups_ = {group 1, group 2}, matches that can be added + // to group 1 must appear before those that can only be added to group 2. + size_t last_group_index = 0; + for (const auto& match : matches) { + auto group_itr = FindGroup(match); + if (group_itr == groups_.end()) { + continue; + } + size_t current_group_index = std::distance(groups_.begin(), group_itr); + if (current_group_index < last_group_index) { + const std::string match_type = + AutocompleteMatchType::ToString(match.type); + const std::string match_group_id = + omnibox::GroupId_Name(match.suggestion_group_id.value()); + const std::string match_relevance = base::NumberToString(match.relevance); + const std::string group_description = base::JoinString( + [&]() { + std::vector<std::string> transformed; + std::ranges::transform( + group_itr->group_id_limits_and_counts(), + std::back_inserter(transformed), [](const auto& pair) { + return omnibox::GroupId_Name(pair.first) + " (" + + base::NumberToString( + static_cast<int>(pair.second.limit)) + + ")"; + }); + return transformed; + }(), + ", "); + SCOPED_CRASH_KEY_STRING32("ZpsSection", "match-type", match_type); + SCOPED_CRASH_KEY_STRING32("ZpsSection", "match-group-id", match_group_id); + SCOPED_CRASH_KEY_STRING32("ZpsSection", "match-relevance", + match_relevance); + SCOPED_CRASH_KEY_STRING32("ZpsSection", "group-description", + group_description); + base::debug::DumpWithoutCrashing(); +#if DCHECK_IS_ON() + NOTREACHED() << "Match with type " << match_type << " and group id " + << match_group_id << " and relevance " << match_relevance + << " is not sorted correctly while being added to Group " + << group_description; +#endif // DCHECK_IS_ON() + } + last_group_index = current_group_index; + } +} + +ZpsSectionWithLocalHistory::ZpsSectionWithLocalHistory( + size_t limit, + Groups groups, + omnibox::GroupConfigMap& group_configs) + : ZpsSection(limit, std::move(groups), group_configs) {} + +void ZpsSectionWithLocalHistory::InitFromMatches(ACMatches& matches) { // Sort matches in the order of their potential containing groups. E.g., if // `groups_ = {group 1, group 2}, this sorts all matches that can be added to // group 1 before those that can only be added to group 2. @@ -116,6 +176,7 @@ // those matches won't be added to the section anyways. return std::distance(groups_.begin(), FindGroup(match)); }); + ZpsSection::InitFromMatches(matches); } // Number of matches that fit in the visible section of the screen. @@ -168,8 +229,7 @@ show_only_search_suggestions ? 0 : 14}, }), }, - group_configs, - omnibox::GroupConfig_SideType_DEFAULT_PRIMARY) {} + group_configs) {} void AndroidNonZPSSection::InitFromMatches(ACMatches& matches) { auto rich_answer_match = std::ranges::find_if( @@ -207,8 +267,7 @@ {omnibox::GROUP_MOBILE_OPEN_TABS, 5}, }), }, - group_configs, - omnibox::GroupConfig_SideType_DEFAULT_PRIMARY) {} + group_configs) {} AndroidHubNonZPSSection::AndroidHubNonZPSSection( omnibox::GroupConfigMap& group_configs) @@ -236,12 +295,11 @@ {omnibox::GROUP_SEARCH, 5}, }), }, - group_configs, - omnibox::GroupConfig_SideType_DEFAULT_PRIMARY) {} + group_configs) {} AndroidNTPZpsSection::AndroidNTPZpsSection( omnibox::GroupConfigMap& group_configs) - : ZpsSection( + : ZpsSectionWithLocalHistory( 30, { Group(1, @@ -328,18 +386,19 @@ DesktopNTPZpsSection::DesktopNTPZpsSection( omnibox::GroupConfigMap& group_configs, size_t limit) - : ZpsSection(limit, - { - Group(8, - { - {omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST, 8}, - }), - Group(8, - { - {omnibox::GROUP_TRENDS, 8}, - }), - }, - group_configs) {} + : ZpsSectionWithLocalHistory( + limit, + { + Group(8, + { + {omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST, 8}, + }), + Group(8, + { + {omnibox::GROUP_TRENDS, 8}, + }), + }, + group_configs) {} DesktopNTPZpsIPHSection::DesktopNTPZpsIPHSection( omnibox::GroupConfigMap& group_configs) @@ -481,8 +540,7 @@ contextual_search_limit}, }), }, - group_configs, - omnibox::GroupConfig_SideType_DEFAULT_PRIMARY) {} + group_configs) {} DesktopWebZpsActionsSection::DesktopWebZpsActionsSection( omnibox::GroupConfigMap& group_configs) @@ -542,8 +600,7 @@ {omnibox::GROUP_OTHER_NAVS, 7}, }), }, - group_configs, - omnibox::GroupConfig_SideType_DEFAULT_PRIMARY) {} + group_configs) {} void DesktopNonZpsSection::InitFromMatches(ACMatches& matches) { auto& default_group = groups_[0]; @@ -605,22 +662,23 @@ } IOSNTPZpsSection::IOSNTPZpsSection(omnibox::GroupConfigMap& group_configs) - : ZpsSection(26, - { - Group(1, - { - {omnibox::GROUP_MOBILE_CLIPBOARD, 1}, - }), - Group(20, - { - {omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST, 20}, - }), - Group(5, - { - {omnibox::GROUP_TRENDS, 5}, - }), - }, - group_configs) {} + : ZpsSectionWithLocalHistory( + 26, + { + Group(1, + { + {omnibox::GROUP_MOBILE_CLIPBOARD, 1}, + }), + Group(20, + { + {omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST, 20}, + }), + Group(5, + { + {omnibox::GROUP_TRENDS, 5}, + }), + }, + group_configs) {} IOSSRPZpsSection::IOSSRPZpsSection(omnibox::GroupConfigMap& group_configs) : ZpsSectionWithMVTiles( @@ -693,23 +751,24 @@ size_t trends_count, size_t total_count, omnibox::GroupConfigMap& group_configs) - : ZpsSection(total_count, - { - Group(1, - { - {omnibox::GROUP_MOBILE_CLIPBOARD, 1}, - }), - Group(total_count - trends_count - 1, - { - {omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST, - total_count - trends_count - 1}, - }), - Group(trends_count, - { - {omnibox::GROUP_TRENDS, trends_count}, - }), - }, - group_configs) {} + : ZpsSectionWithLocalHistory( + total_count, + { + Group(1, + { + {omnibox::GROUP_MOBILE_CLIPBOARD, 1}, + }), + Group(total_count - trends_count - 1, + { + {omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST, + total_count - trends_count - 1}, + }), + Group(trends_count, + { + {omnibox::GROUP_TRENDS, trends_count}, + }), + }, + group_configs) {} IOSIpadSRPZpsSection::IOSIpadSRPZpsSection( size_t total_count,
diff --git a/components/omnibox/browser/autocomplete_grouper_sections.h b/components/omnibox/browser/autocomplete_grouper_sections.h index b70354147..51bae80 100644 --- a/components/omnibox/browser/autocomplete_grouper_sections.h +++ b/components/omnibox/browser/autocomplete_grouper_sections.h
@@ -26,7 +26,8 @@ explicit Section(size_t limit, Groups groups, omnibox::GroupConfigMap& group_configs, - omnibox::GroupConfig_SideType side_type); + omnibox::GroupConfig_SideType side_type = + omnibox::GroupConfig_SideType_DEFAULT_PRIMARY); virtual ~Section(); // Returns `matches` ranked and culled according to `sections`. All `matches` // should have `suggestion_group_id` set and be sorted by relevance. @@ -55,9 +56,8 @@ omnibox::GroupConfig_SideType side_type_; }; -// Base section for ZPS limits and grouping. Ensures that matches with higher -// relevance scores do not fill up the section if others with lower scores are -// expected to be placed earlier based on their `Group`'s position. +// Base section for ZPS limits and grouping. Asserts that matches are sorted by +// their `Group`s position. class ZpsSection : public Section { public: ZpsSection(size_t limit, @@ -69,6 +69,21 @@ void InitFromMatches(ACMatches& matches) override; }; +// Base section for ZPS limits and grouping where local history zero-prefix +// suggestions are enabled. Sorts the matches by their `Group`s position to +// ensure zero-prefix suggestions from local history backfill remote +// personalized zero-prefix suggestions. +// TODO(crbug.com/409810808): Find a more general solution for accommodating +// local history backfill and remove this class. +class ZpsSectionWithLocalHistory : public ZpsSection { + protected: + explicit ZpsSectionWithLocalHistory(size_t limit, + Groups groups, + omnibox::GroupConfigMap& group_configs); + // Section: + void InitFromMatches(ACMatches& matches) override; +}; + // A ZpsSection that automatically counts all MV Tiles as one suggestion when // applying the total limit. class ZpsSectionWithMVTiles : public ZpsSection { @@ -121,7 +136,7 @@ // - up to 1 clipboard suggestion. // - up to 15 personalized suggestions. // - up to 5 trending search suggestions. -class AndroidNTPZpsSection : public ZpsSection { +class AndroidNTPZpsSection : public ZpsSectionWithLocalHistory { public: explicit AndroidNTPZpsSection(omnibox::GroupConfigMap& group_configs); }; @@ -155,7 +170,7 @@ // suggestion being the IPH). // - up to 8 personalized suggestions. // - up to 8 trending search suggestions. -class DesktopNTPZpsSection : public ZpsSection { +class DesktopNTPZpsSection : public ZpsSectionWithLocalHistory { public: explicit DesktopNTPZpsSection(omnibox::GroupConfigMap& group_configs, size_t limit); @@ -217,10 +232,6 @@ // - up to `limit` page related or personalized search suggestions. // - up to `contextual_action_limit` contextual search action suggestions. // - up to `contextual_search_limit` contextual search suggestions. -// TODO(crbug.com/409810808): Extending `ZpsSection` would reorder the matches -// demoting contextual search suggestions in `ZpsSection::InitFromMatches()`. -// This is not the desired behavior as those matches should take precedence over -// the other search suggestions, despite visually appearing after them. class DesktopWebSearchZpsSection : public Section { public: explicit DesktopWebSearchZpsSection(omnibox::GroupConfigMap& group_configs, @@ -276,7 +287,7 @@ // - up to 1 clipboard suggestion. // - up to `psuggest_count` personalized suggestions. // - up to `max_trending_queries` trending suggestions. -class IOSNTPZpsSection : public ZpsSection { +class IOSNTPZpsSection : public ZpsSectionWithLocalHistory { public: explicit IOSNTPZpsSection(omnibox::GroupConfigMap& group_configs); }; @@ -318,7 +329,7 @@ // - up to 10 suggestions total. // - up to 1 clipboard suggestion. // - up to 10 personalized suggestions. -class IOSIpadNTPZpsSection : public ZpsSection { +class IOSIpadNTPZpsSection : public ZpsSectionWithLocalHistory { public: explicit IOSIpadNTPZpsSection(size_t trends_count, size_t total_count,
diff --git a/components/omnibox/browser/autocomplete_grouper_sections_unittest.cc b/components/omnibox/browser/autocomplete_grouper_sections_unittest.cc index cf9fe19..f043f54 100644 --- a/components/omnibox/browser/autocomplete_grouper_sections_unittest.cc +++ b/components/omnibox/browser/autocomplete_grouper_sections_unittest.cc
@@ -82,43 +82,43 @@ test({CreateMatch(1, omnibox::GROUP_SEARCH)}, {}); } -// Tests rules for ZpsSection. -TEST(AutocompleteGrouperGroupsTest, ZpsSection) { - class TestZpsSection : public ZpsSection { +// Tests rules for Section. +TEST(AutocompleteGrouperGroupsTest, Section) { + class TestSection : public Section { public: // Up to 2 items of the following types. - explicit TestZpsSection(omnibox::GroupConfigMap& group_configs) - : ZpsSection( - 2, - { - Group(1, - { - {omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX, 1}, - }), - Group(1, - { - {omnibox::GROUP_MOBILE_CLIPBOARD, 1}, - }), - Group(1, - { - {omnibox::GROUP_MOBILE_MOST_VISITED, 1}, - }), - Group(1, - { - {omnibox::GROUP_VISITED_DOC_RELATED, 1}, - }), - Group(1, - { - {omnibox::GROUP_RELATED_QUERIES, 1}, - }), - }, - group_configs) {} + explicit TestSection(omnibox::GroupConfigMap& group_configs) + : Section(2, + { + Group(1, + { + {omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX, 1}, + }), + Group(1, + { + {omnibox::GROUP_MOBILE_CLIPBOARD, 1}, + }), + Group(1, + { + {omnibox::GROUP_MOBILE_MOST_VISITED, 1}, + }), + Group(1, + { + {omnibox::GROUP_VISITED_DOC_RELATED, 1}, + }), + Group(1, + { + {omnibox::GROUP_RELATED_QUERIES, 1}, + }), + }, + group_configs, + omnibox::GroupConfig_SideType_DEFAULT_PRIMARY) {} }; auto test = [](ACMatches matches, std::vector<int> expected_relevances) { PSections sections; omnibox::GroupConfigMap group_configs; - sections.push_back(std::make_unique<TestZpsSection>(group_configs)); + sections.push_back(std::make_unique<TestSection>(group_configs)); auto out_matches = Section::GroupMatches(std::move(sections), matches); VerifyMatches(out_matches, expected_relevances); }; @@ -135,7 +135,7 @@ CreateMatch(2, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), CreateMatch(1, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), }, - {2, 3}); + {5, 6}); } } @@ -165,11 +165,10 @@ {98}); } { - SCOPED_TRACE( - "Matches should be ranked by group, not relevance or add order."); + SCOPED_TRACE("Personalized suggestions get precedence over trending ones"); test( { - // `GROUP_TRENDS` matches come 2rd and should not be added. + // `GROUP_TRENDS` matches are more relevant but will not be added. CreateMatch(90, omnibox::GROUP_TRENDS), CreateMatch(89, omnibox::GROUP_TRENDS), CreateMatch(88, omnibox::GROUP_TRENDS), @@ -180,8 +179,7 @@ CreateMatch(83, omnibox::GROUP_TRENDS), CreateMatch(82, omnibox::GROUP_TRENDS), CreateMatch(81, omnibox::GROUP_TRENDS), - // `GROUP_PERSONALIZED_ZERO_SUGGEST` matches come 1st and should be - // added. + // `GROUP_PERSONALIZED_ZERO_SUGGEST` matches should be added. CreateMatch(80, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(79, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(78, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), @@ -192,17 +190,6 @@ CreateMatch(73, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(72, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(71, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - // `GROUP_PREVIOUS_SEARCH_RELATED` matches should not be added. - CreateMatch(70, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(69, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(68, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(67, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(66, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(65, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(64, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(63, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(62, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(61, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), }, { 80, @@ -246,8 +233,7 @@ test( { // `GROUP_TRENDS` matches should be added up to the remaining - // section limit - // (3). + // section limit (3). CreateMatch(90, omnibox::GROUP_TRENDS), CreateMatch(89, omnibox::GROUP_TRENDS), CreateMatch(88, omnibox::GROUP_TRENDS), @@ -259,18 +245,18 @@ CreateMatch(82, omnibox::GROUP_TRENDS), CreateMatch(81, omnibox::GROUP_TRENDS), // `GROUP_PERSONALIZED_ZERO_SUGGEST` matches should all be added. - CreateMatch(80, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(79, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(78, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(77, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(76, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), + CreateMatch(75, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), + CreateMatch(74, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), }, { - 80, - 79, 78, 77, 76, + 75, + 74, 90, 89, 88, @@ -308,11 +294,10 @@ {98}); } { - SCOPED_TRACE( - "Matches should be ranked by group, not relevance or add order."); + SCOPED_TRACE("Personalized suggestions get precedence over trending ones"); test( { - // `GROUP_TRENDS` matches come 2nd and should not be added. + // `GROUP_TRENDS` matches are more relevant but will not be added. CreateMatch(90, omnibox::GROUP_TRENDS), CreateMatch(89, omnibox::GROUP_TRENDS), CreateMatch(88, omnibox::GROUP_TRENDS), @@ -323,8 +308,7 @@ CreateMatch(83, omnibox::GROUP_TRENDS), CreateMatch(82, omnibox::GROUP_TRENDS), CreateMatch(81, omnibox::GROUP_TRENDS), - // `GROUP_PERSONALIZED_ZERO_SUGGEST` matches come 1st and should be - // added. + // `GROUP_PERSONALIZED_ZERO_SUGGEST` matches should be added. CreateMatch(80, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(79, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(78, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), @@ -392,8 +376,7 @@ test( { // `GROUP_TRENDS` matches should be added up to the remaining - // section limit - // (2). + // section limit (2). CreateMatch(90, omnibox::GROUP_TRENDS), CreateMatch(89, omnibox::GROUP_TRENDS), CreateMatch(88, omnibox::GROUP_TRENDS), @@ -774,7 +757,6 @@ } { SCOPED_TRACE("Android/ZPS with extra searches."); - // Verify that the Clipboard suggestion is retained on top. test( { CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), @@ -799,9 +781,12 @@ } { SCOPED_TRACE("Android/ZPS with Clipboard entries."); - // Verify that the Clipboard suggestion is retained on top. + // Verify that up to one Clipboard suggestion is retained on top. test( { + CreateMatch(200, omnibox::GROUP_MOBILE_CLIPBOARD), + CreateMatch(199, omnibox::GROUP_MOBILE_CLIPBOARD), + CreateMatch(198, omnibox::GROUP_MOBILE_CLIPBOARD), CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(99, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(98, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), @@ -819,18 +804,17 @@ CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(85, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(84, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(3, omnibox::GROUP_MOBILE_CLIPBOARD), - // Bogus, repetitive, only one allowed. - CreateMatch(2, omnibox::GROUP_MOBILE_CLIPBOARD), - CreateMatch(1, omnibox::GROUP_MOBILE_CLIPBOARD), }, - {3, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87}); + {200, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87}); } { SCOPED_TRACE("Android/ZPS with Search Ready Omnibox."); - // Verify that the Clipboard suggestion is retained on top. + // Verify that up to one SRO suggestion is retained on top. test( { + CreateMatch(200, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), + CreateMatch(199, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), + CreateMatch(198, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(99, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(98, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), @@ -848,16 +832,12 @@ CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(85, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(84, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - // Not allowed. - CreateMatch(2, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), - CreateMatch(1, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), - CreateMatch(0, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), }, - {2, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87}); + {200, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87}); } { SCOPED_TRACE("Android/ZPS on SRP with recent searches only."); - // Verify that the Clipboard suggestion is retained on top. + // Verify that recent searches are shown up to the section limit. test( { CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), @@ -877,15 +857,17 @@ CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(85, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(84, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(2, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), }, - {2, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87}); + {100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86}); } { SCOPED_TRACE("Android/ZPS with MV Tiles."); - // Verify that the Clipboard suggestion is retained on top. + // Verify that the MV suggestions are not allowed. test( { + CreateMatch(300, omnibox::GROUP_MOBILE_MOST_VISITED), + CreateMatch(299, omnibox::GROUP_MOBILE_MOST_VISITED), + CreateMatch(298, omnibox::GROUP_MOBILE_MOST_VISITED), CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(99, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(98, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), @@ -903,82 +885,43 @@ CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(85, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(84, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - // Not allowed. - CreateMatch(4, omnibox::GROUP_MOBILE_MOST_VISITED), - CreateMatch(3, omnibox::GROUP_MOBILE_MOST_VISITED), - CreateMatch(2, omnibox::GROUP_MOBILE_MOST_VISITED), }, {100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86}); } { SCOPED_TRACE("Android/ZPS with multiple auxiliary suggestions."); - // Verify that the Clipboard suggestion is retained on top. test( { - CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), + // Up to one SRO should be shown first. + CreateMatch(300, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), + CreateMatch(299, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), + // Up to one Clipboard should be shown after SRO. + CreateMatch(298, omnibox::GROUP_MOBILE_CLIPBOARD), + CreateMatch(297, omnibox::GROUP_MOBILE_CLIPBOARD), + // MV Tiles are not allowed. + CreateMatch(296, omnibox::GROUP_MOBILE_MOST_VISITED), + CreateMatch(295, omnibox::GROUP_MOBILE_MOST_VISITED), + // Previous Search Related and recent searches should be shown up to + // the remaining section limit. + CreateMatch(100, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), CreateMatch(99, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(98, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), + CreateMatch(98, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), CreateMatch(97, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(96, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), + CreateMatch(96, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), CreateMatch(95, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(94, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), + CreateMatch(94, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), CreateMatch(93, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), CreateMatch(92, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(91, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), + CreateMatch(91, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(90, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(89, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), + CreateMatch(89, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(88, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(87, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), + CreateMatch(87, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(85, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), + CreateMatch(85, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(84, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - // SRO should always be shown first, despite low relevance. - // Only one item permitted. - CreateMatch(2, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), - CreateMatch(1, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), - // Clipboard should always be shown after SRO, if both are present. - // Only one item permitted. - CreateMatch(20, omnibox::GROUP_MOBILE_CLIPBOARD), - CreateMatch(19, omnibox::GROUP_MOBILE_CLIPBOARD), - // MV Tiles should always be on the third position if both SRO and - // Clipboard are present. - // Currently only one item is permitted. - CreateMatch(40, omnibox::GROUP_MOBILE_MOST_VISITED), - CreateMatch(39, omnibox::GROUP_MOBILE_MOST_VISITED), }, - // Observe that PERSONALIZED_ZERO_SUGGEST and VISITED_DOC suggestions - // are grouped together. VISITED_DOC_RELATED are prioritized over the - // PERSONALIZED_ZERO_SUGGEST because these are more context relevant. - {2, 20, 99, 97, 95, 93, 91, 89, 87, 85, 100, 98, 96, 94, 92}); - } - { - SCOPED_TRACE("No Inspire Me content shown in the core ZPS content"); - test( - { - CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(99, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(98, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(97, omnibox::GROUP_RELATED_QUERIES), - CreateMatch(96, omnibox::GROUP_TRENDS), - CreateMatch(95, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(94, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(93, omnibox::GROUP_RELATED_QUERIES), - CreateMatch(92, omnibox::GROUP_TRENDS), - CreateMatch(91, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(90, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(89, omnibox::GROUP_RELATED_QUERIES), - CreateMatch(88, omnibox::GROUP_TRENDS), - CreateMatch(87, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(85, omnibox::GROUP_RELATED_QUERIES), - CreateMatch(84, omnibox::GROUP_TRENDS), - // Auxiliary suggestions. - CreateMatch(2, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), - CreateMatch(3, omnibox::GROUP_MOBILE_CLIPBOARD), - // Not allowed. - CreateMatch(4, omnibox::GROUP_MOBILE_MOST_VISITED), - }, - {2, 3, 99, 95, 91, 87, 100, 98, 94, 90, 86}); + {300, 298, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88}); } } @@ -998,7 +941,6 @@ } { SCOPED_TRACE("Android/ZPS with extra searches."); - // Verify that the Clipboard suggestion is retained on top. test( { CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), @@ -1023,9 +965,12 @@ } { SCOPED_TRACE("Android/ZPS with Clipboard entries."); - // Verify that the Clipboard suggestion is retained on top. + // Verify that up to one Clipboard suggestion is retained on top. test( { + CreateMatch(200, omnibox::GROUP_MOBILE_CLIPBOARD), + CreateMatch(199, omnibox::GROUP_MOBILE_CLIPBOARD), + CreateMatch(198, omnibox::GROUP_MOBILE_CLIPBOARD), CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(99, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(98, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), @@ -1043,18 +988,17 @@ CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(85, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(84, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(3, omnibox::GROUP_MOBILE_CLIPBOARD), - // Bogus, repetitive, only one allowed. - CreateMatch(2, omnibox::GROUP_MOBILE_CLIPBOARD), - CreateMatch(1, omnibox::GROUP_MOBILE_CLIPBOARD), }, - {3, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87}); + {200, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87}); } { SCOPED_TRACE("Android/ZPS with Search Ready Omnibox."); - // Verify that the Clipboard suggestion is retained on top. + // Verify that up to one SRO suggestion is retained on top. test( { + CreateMatch(200, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), + CreateMatch(199, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), + CreateMatch(198, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(99, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(98, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), @@ -1072,44 +1016,18 @@ CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(85, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(84, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(2, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), - // Bogus, repetitive, only one allowed. - CreateMatch(1, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), - CreateMatch(0, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), }, - {2, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87}); - } - { - SCOPED_TRACE("Android/ZPS on Web with recent searches only."); - // Verify that the Clipboard suggestion is retained on top. - test( - { - CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(99, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(98, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(97, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(96, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(95, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(94, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(93, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(92, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(91, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(90, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(89, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(88, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(87, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(85, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(84, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(2, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), - }, - {2, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87}); + {200, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87}); } { SCOPED_TRACE("Android/ZPS with MV Tiles."); - // Verify that the Clipboard suggestion is retained on top. + // Verify that the MV suggestions are retained on top. test( { + // Slotted in horizontal render group, taking up 1 row. + CreateMatch(300, omnibox::GROUP_MOBILE_MOST_VISITED), + CreateMatch(299, omnibox::GROUP_MOBILE_MOST_VISITED), + CreateMatch(298, omnibox::GROUP_MOBILE_MOST_VISITED), CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(99, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(98, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), @@ -1127,81 +1045,46 @@ CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(85, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(84, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - // Slotted in horizontal render group. - CreateMatch(4, omnibox::GROUP_MOBILE_MOST_VISITED), - CreateMatch(3, omnibox::GROUP_MOBILE_MOST_VISITED), - CreateMatch(2, omnibox::GROUP_MOBILE_MOST_VISITED), }, - {4, 3, 2, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87}); + {300, 299, 298, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, + 87}); } { SCOPED_TRACE("Android/ZPS with multiple auxiliary suggestions."); - // Verify that the Clipboard suggestion is retained on top. test( { - CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), + // Up to one SRO should be shown first. + CreateMatch(300, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), + CreateMatch(299, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), + // Up to one Clipboard should be shown after SRO. + CreateMatch(298, omnibox::GROUP_MOBILE_CLIPBOARD), + CreateMatch(297, omnibox::GROUP_MOBILE_CLIPBOARD), + CreateMatch(297, omnibox::GROUP_MOBILE_CLIPBOARD), + // MV Tiles are slotted in horizontal render group, taking up 1 + // row. + CreateMatch(296, omnibox::GROUP_MOBILE_MOST_VISITED), + CreateMatch(295, omnibox::GROUP_MOBILE_MOST_VISITED), + // Visited Doc Related and recent searches should be shown up to + // the remaining section limit. + CreateMatch(100, omnibox::GROUP_VISITED_DOC_RELATED), CreateMatch(99, omnibox::GROUP_VISITED_DOC_RELATED), - CreateMatch(98, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), + CreateMatch(98, omnibox::GROUP_VISITED_DOC_RELATED), CreateMatch(97, omnibox::GROUP_VISITED_DOC_RELATED), - CreateMatch(96, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), + CreateMatch(96, omnibox::GROUP_VISITED_DOC_RELATED), CreateMatch(95, omnibox::GROUP_VISITED_DOC_RELATED), - CreateMatch(94, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), + CreateMatch(94, omnibox::GROUP_VISITED_DOC_RELATED), CreateMatch(93, omnibox::GROUP_VISITED_DOC_RELATED), CreateMatch(92, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(91, omnibox::GROUP_VISITED_DOC_RELATED), + CreateMatch(91, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(90, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(89, omnibox::GROUP_VISITED_DOC_RELATED), + CreateMatch(89, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(88, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(87, omnibox::GROUP_VISITED_DOC_RELATED), + CreateMatch(87, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(85, omnibox::GROUP_VISITED_DOC_RELATED), + CreateMatch(85, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(84, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - // SRO should always be shown first, despite low relevance. - // Only one item permitted. - CreateMatch(2, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), - CreateMatch(1, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), - // Clipboard should always be shown after SRO, if both are present. - // Only one item permitted. - CreateMatch(20, omnibox::GROUP_MOBILE_CLIPBOARD), - CreateMatch(19, omnibox::GROUP_MOBILE_CLIPBOARD), - // MV Tiles should always be on the third position if both SRO and - // Clipboard are present. - // Slotted in horizontal render group. - CreateMatch(40, omnibox::GROUP_MOBILE_MOST_VISITED), - CreateMatch(39, omnibox::GROUP_MOBILE_MOST_VISITED), }, - // Observe that PERSONALIZED_ZERO_SUGGEST and VISITED_DOC suggestions - // are grouped together. VISITED_DOC_RELATED are prioritized over the - // PERSONALIZED_ZERO_SUGGEST because these are more context relevant. - {2, 20, 40, 39, 99, 97, 95, 93, 91, 89, 87, 85, 100, 98, 96, 94}); - } - { - SCOPED_TRACE("No Inspire Me content shown in the core ZPS content"); - test( - { - CreateMatch(100, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(99, omnibox::GROUP_VISITED_DOC_RELATED), - CreateMatch(98, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(97, omnibox::GROUP_RELATED_QUERIES), - CreateMatch(96, omnibox::GROUP_TRENDS), - CreateMatch(95, omnibox::GROUP_VISITED_DOC_RELATED), - CreateMatch(94, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(93, omnibox::GROUP_RELATED_QUERIES), - CreateMatch(92, omnibox::GROUP_TRENDS), - CreateMatch(91, omnibox::GROUP_VISITED_DOC_RELATED), - CreateMatch(90, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(89, omnibox::GROUP_RELATED_QUERIES), - CreateMatch(88, omnibox::GROUP_TRENDS), - CreateMatch(87, omnibox::GROUP_VISITED_DOC_RELATED), - CreateMatch(86, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), - CreateMatch(85, omnibox::GROUP_RELATED_QUERIES), - CreateMatch(84, omnibox::GROUP_TRENDS), - // Auxiliary suggestions. - CreateMatch(2, omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX), - CreateMatch(3, omnibox::GROUP_MOBILE_CLIPBOARD), - CreateMatch(4, omnibox::GROUP_MOBILE_MOST_VISITED), - }, - {2, 3, 4, 99, 95, 91, 87, 100, 98, 94, 90, 86}); + {300, 298, 296, 295, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89}); } } @@ -1742,31 +1625,31 @@ { SCOPED_TRACE( "Given 12 srp zps matches, the group should respect the search " - "suggestion limit as well as show them first in the suggestion list."); + "suggestion limit"); test( { - CreateMatch(100, omnibox::GROUP_MOST_VISITED), - CreateMatch(99, omnibox::GROUP_MOST_VISITED), - CreateMatch(98, omnibox::GROUP_MOST_VISITED), - CreateMatch(97, omnibox::GROUP_MOST_VISITED), - CreateMatch(96, omnibox::GROUP_MOST_VISITED), - CreateMatch(95, omnibox::GROUP_MOST_VISITED), - CreateMatch(94, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(93, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(92, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(91, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(90, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), - CreateMatch(89, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), + CreateMatch(100, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), + CreateMatch(99, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), + CreateMatch(98, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), + CreateMatch(97, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), + CreateMatch(96, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), + CreateMatch(95, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), + CreateMatch(94, omnibox::GROUP_MOST_VISITED), + CreateMatch(93, omnibox::GROUP_MOST_VISITED), + CreateMatch(92, omnibox::GROUP_MOST_VISITED), + CreateMatch(91, omnibox::GROUP_MOST_VISITED), + CreateMatch(89, omnibox::GROUP_MOST_VISITED), + CreateMatch(88, omnibox::GROUP_MOST_VISITED), }, - {94, 93, 92, 91, 100, 99, 98, 97}); + {100, 99, 98, 97, 94, 93, 92, 91}); } { SCOPED_TRACE( - "Given 12 srp zps matches, if there aren't enough serach suggestions, " - "backfill with max_url_suggestions suggestions"); + "Given 12 srp zps matches, the group should respect the url suggestion " + "limit"); test( { - CreateMatch(100, omnibox::GROUP_MOST_VISITED), + CreateMatch(100, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), CreateMatch(99, omnibox::GROUP_MOST_VISITED), CreateMatch(98, omnibox::GROUP_MOST_VISITED), CreateMatch(97, omnibox::GROUP_MOST_VISITED), @@ -1774,12 +1657,12 @@ CreateMatch(95, omnibox::GROUP_MOST_VISITED), CreateMatch(94, omnibox::GROUP_MOST_VISITED), CreateMatch(93, omnibox::GROUP_MOST_VISITED), + CreateMatch(92, omnibox::GROUP_MOST_VISITED), CreateMatch(91, omnibox::GROUP_MOST_VISITED), CreateMatch(90, omnibox::GROUP_MOST_VISITED), CreateMatch(89, omnibox::GROUP_MOST_VISITED), - CreateMatch(88, omnibox::GROUP_PREVIOUS_SEARCH_RELATED), }, - {88, 100, 99, 98, 97}); + {100, 99, 98, 97, 96}); } } @@ -1800,7 +1683,8 @@ // Max 4 url suggestions. sections.push_back( std::make_unique<DesktopWebURLZpsSection>(group_configs, 4u)); - // Max 4 search suggestions. + // Max 4 suggestions, with an upper limit of 4 contextual search + // suggestions and no contextual actions. sections.push_back(std::make_unique<DesktopWebSearchZpsSection>( group_configs, /*limit=*/4u, /*contextual_action_limit=*/0u, /*contextual_search_limit=*/4u)); @@ -1859,15 +1743,16 @@ // Max 3 suggestions, with an upper limit of 3 url suggestions. sections.push_back( std::make_unique<DesktopWebURLZpsSection>(group_configs, 3u)); - // Max 3 suggestions, with an upper limit of 3 search suggestions. + // Max 3 suggestions, with an upper limit of 3 contextual search + // suggestions and one contextual action. sections.push_back(std::make_unique<DesktopWebSearchZpsSection>( - group_configs, /*limit=*/4u, /*contextual_action_limit=*/1u, + group_configs, /*limit=*/3u, /*contextual_action_limit=*/1u, /*contextual_search_limit=*/3u)); auto out_matches = Section::GroupMatches(std::move(sections), matches); VerifyMatches(out_matches, expected_relevances); }; { - SCOPED_TRACE("ZPS action matches group after contextual search matches"); + SCOPED_TRACE("ZPS action matches group before contextual search matches"); test( { CreateMatch(300, omnibox::GROUP_CONTEXTUAL_SEARCH_ACTION), @@ -1887,8 +1772,8 @@ CreateMatch(90, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), CreateMatch(89, omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST), }, - // 3 URLs, 1 other search, 1 action, 2 contextual searches. - {100, 99, 98, 94, 300, 200, 199}); + // 3 URLs, 1 action, 2 contextual searches. + {100, 99, 98, 300, 200, 199}); } }
diff --git a/components/omnibox/browser/autocomplete_result_unittest.cc b/components/omnibox/browser/autocomplete_result_unittest.cc index 54683c2..c3fbe08 100644 --- a/components/omnibox/browser/autocomplete_result_unittest.cc +++ b/components/omnibox/browser/autocomplete_result_unittest.cc
@@ -286,9 +286,15 @@ void AutocompleteResultTest::AssertResultMatches( const AutocompleteResult& result, base::span<const TestData> expected) { - ASSERT_EQ(expected.size(), result.size()); - for (size_t i = 0; i < expected.size(); ++i) - AssertMatch(*(result.begin() + i), expected[i], i); + std::vector<int> relevances = {}; + std::ranges::transform( + expected, std::back_inserter(relevances), + [](const auto& test_data) { return test_data.relevance; }); + std::vector<int> expected_relevances = {}; + std::ranges::transform( + result, std::back_inserter(expected_relevances), + [&](const AutocompleteMatch& match) { return match.relevance; }); + EXPECT_THAT(relevances, testing::ElementsAreArray(expected_relevances)); } void AutocompleteResultTest::AssertMatch(AutocompleteMatch match, @@ -2580,24 +2586,9 @@ scoped_config.Get().max_url_suggestions = 4U; scoped_config.Get().max_search_suggestions = 4U; - const auto group1 = omnibox::GROUP_MOST_VISITED; - const auto group2 = omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST; - TestData data[] = { - {0, 1, 500, false, {}, AutocompleteMatchType::HISTORY_URL, group1}, - {1, 1, 490, false, {}, AutocompleteMatchType::HISTORY_URL, group1}, - {2, 1, 480, false, {}, AutocompleteMatchType::HISTORY_URL, group1}, - {3, 1, 470, false, {}, AutocompleteMatchType::HISTORY_URL, group1}, - {4, 1, 460, false, {}, AutocompleteMatchType::HISTORY_URL, group1}, - {5, 1, 450, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, - {6, 1, 440, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, - {7, 1, 430, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, - {8, 1, 420, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, - {9, 1, 420, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, - }; - ACMatches matches; - PopulateAutocompleteMatches(data, std::size(data), &matches); - // Suggestion groups have the omnibox::SECTION_DEFAULT by default. + const auto group1 = omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST; + const auto group2 = omnibox::GROUP_MOST_VISITED; omnibox::GroupConfigMap suggestion_groups_map; suggestion_groups_map[group1]; suggestion_groups_map[group2]; @@ -2613,23 +2604,38 @@ { SCOPED_TRACE("Query from omnibox in srp"); + TestData data[] = { + {0, 1, 500, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {1, 1, 490, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {2, 1, 480, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {3, 1, 470, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {4, 1, 460, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {5, 1, 450, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {6, 1, 440, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {7, 1, 430, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {8, 1, 420, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {9, 1, 410, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + }; + ACMatches matches; + PopulateAutocompleteMatches(data, std::size(data), &matches); + AutocompleteResult result; result.MergeSuggestionGroupsMap(suggestion_groups_map); result.AppendMatches(matches); result.SortAndCull(omnibox_srp_zps_input, &template_url_service(), triggered_feature_service()); - // There should be 8 total suggestions, 4 from the group2 and 4 from group1. - // Group 1 should follow group 2 since this is a search results page. + // There should be 8 total suggestions, 4 from the group 1 and 4 from group + // 2. Group 2 should follow group 1 since this is a search results page. const std::array<TestData, 8> expected_data{{ - {5, 1, 450, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, - {6, 1, 440, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, - {7, 1, 430, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, - {8, 1, 420, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, - {0, 1, 500, false, {}, AutocompleteMatchType::HISTORY_URL, group1}, - {1, 1, 490, false, {}, AutocompleteMatchType::HISTORY_URL, group1}, - {2, 1, 480, false, {}, AutocompleteMatchType::HISTORY_URL, group1}, - {3, 1, 470, false, {}, AutocompleteMatchType::HISTORY_URL, group1}, + {5, 1, 500, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {6, 1, 490, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {7, 1, 480, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {8, 1, 470, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {0, 1, 450, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {1, 1, 440, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {2, 1, 430, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {3, 1, 420, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, }}; AssertResultMatches(result, expected_data); } @@ -2647,19 +2653,35 @@ { SCOPED_TRACE("Query from web page"); + + TestData data[] = { + {0, 1, 500, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {1, 1, 490, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {2, 1, 480, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {3, 1, 470, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {4, 1, 460, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {5, 1, 450, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {6, 1, 440, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {7, 1, 430, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {8, 1, 420, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {9, 1, 410, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + }; + ACMatches matches; + PopulateAutocompleteMatches(data, std::size(data), &matches); + AutocompleteResult result; result.MergeSuggestionGroupsMap(suggestion_groups_map); result.AppendMatches(matches); result.SortAndCull(web_zps_input, &template_url_service(), triggered_feature_service()); - // There should be 6 suggestions total, 2 from group1 (url) and 4 from - // group2 (search), since search suggestions backfill url suggestions. + // There should be 4 total suggestions, 2 from the group 1 and 2 from group + // 2. Group 1 should follow group 2 since this is a web page. const std::array<TestData, 4> expected_data{{ - {0, 1, 500, false, {}, AutocompleteMatchType::HISTORY_URL, group1}, - {1, 1, 490, false, {}, AutocompleteMatchType::HISTORY_URL, group1}, - {5, 1, 450, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, - {6, 1, 440, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {0, 1, 500, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {1, 1, 490, false, {}, AutocompleteMatchType::HISTORY_URL, group2}, + {5, 1, 450, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, + {6, 1, 440, false, {}, AutocompleteMatchType::SEARCH_HISTORY, group1}, }}; AssertResultMatches(result, expected_data); }
diff --git a/components/omnibox/browser/clipboard_provider.cc b/components/omnibox/browser/clipboard_provider.cc index 7f7f11b..c8cf52e 100644 --- a/components/omnibox/browser/clipboard_provider.cc +++ b/components/omnibox/browser/clipboard_provider.cc
@@ -28,6 +28,7 @@ #include "components/omnibox/browser/autocomplete_provider_listener.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/page_classification_functions.h" +#include "components/omnibox/browser/suggestion_group_util.h" #include "components/omnibox/browser/verbatim_match.h" #include "components/omnibox/common/omnibox_features.h" #include "components/open_from_clipboard/clipboard_recent_content.h" @@ -49,12 +50,6 @@ const size_t kMaxClipboardSuggestionShownNumTimesSimpleSize = 20; -// Clipboard suggestion is placed either in a dedicated -// SECTION_MOBILE_CLIPBOARD, or SECTION_PERSONALIZED_ZERO_SUGGEST. -// The score for the former is irrelevant, but for the latter we need to be -// confident the suggestion shows up on top. -const int kClipboardMatchRelevanceScore = 1600; - bool IsMatchDeletionEnabled() { return base::FeatureList::IsEnabled( omnibox::kOmniboxRemoveSuggestionsFromClipboard); @@ -447,7 +442,7 @@ } AutocompleteMatch ClipboardProvider::NewBlankURLMatch() { - AutocompleteMatch match(this, kClipboardMatchRelevanceScore, + AutocompleteMatch match(this, omnibox::kClipboardMatchZeroSuggestRelevance, IsMatchDeletionEnabled(), AutocompleteMatchType::CLIPBOARD_URL); @@ -466,7 +461,7 @@ } AutocompleteMatch ClipboardProvider::NewBlankTextMatch() { - AutocompleteMatch match(this, kClipboardMatchRelevanceScore, + AutocompleteMatch match(this, omnibox::kClipboardMatchZeroSuggestRelevance, IsMatchDeletionEnabled(), AutocompleteMatchType::CLIPBOARD_TEXT); // Any path leading here should first verify whether @@ -495,7 +490,7 @@ } AutocompleteMatch ClipboardProvider::NewBlankImageMatch() { - AutocompleteMatch match(this, kClipboardMatchRelevanceScore, + AutocompleteMatch match(this, omnibox::kClipboardMatchZeroSuggestRelevance, IsMatchDeletionEnabled(), AutocompleteMatchType::CLIPBOARD_IMAGE); // Any path leading here should first verify whether
diff --git a/components/omnibox/browser/contextual_search_provider.cc b/components/omnibox/browser/contextual_search_provider.cc index 0340c02..ea48f45c 100644 --- a/components/omnibox/browser/contextual_search_provider.cc +++ b/components/omnibox/browser/contextual_search_provider.cc
@@ -36,6 +36,7 @@ #include "components/omnibox/browser/page_classification_functions.h" #include "components/omnibox/browser/remote_suggestions_service.h" #include "components/omnibox/browser/search_suggestion_parser.h" +#include "components/omnibox/browser/suggestion_group_util.h" #include "components/omnibox/browser/zero_suggest_provider.h" #include "components/omnibox/common/omnibox_feature_configs.h" #include "components/omnibox/common/omnibox_features.h" @@ -53,15 +54,8 @@ namespace { -// Relevance for pedal-like action matches to be provided when not in keyword -// mode and input is empty. -constexpr int kAdvertActionRelevance = 10000; - // The internal default verbatim match relevance. -constexpr int kDefaultMatchRelevance = 1500; - -// Relevance value to use if it was not set explicitly by the server. -constexpr int kDefaultSuggestResultRelevance = 100; +constexpr int kDefaultVerbatimMatchRelevance = 1500; // Populates |results| with the response if it can be successfully parsed for // |input|. Returns true if the response can be successfully parsed. @@ -82,7 +76,7 @@ return SearchSuggestionParser::ParseSuggestResults( *response_data, input, client->GetSchemeClassifier(), - /*default_result_relevance=*/kDefaultSuggestResultRelevance, + /*default_result_relevance=*/omnibox::kDefaultRemoteZeroSuggestRelevance, /*is_keyword_result=*/true, results); } @@ -309,8 +303,8 @@ void ContextualSearchProvider::AddPageSearchActionMatches( const AutocompleteInput& input) { // These matches are effectively pedals that don't require any query matching. - AutocompleteMatch match(this, kAdvertActionRelevance, false, - AutocompleteMatchType::PEDAL); + AutocompleteMatch match(this, omnibox::kContextualActionZeroSuggestRelevance, + false, AutocompleteMatchType::PEDAL); match.contents_class = {{0, ACMatchClassification::NONE}}; match.transition = ui::PAGE_TRANSITION_GENERATED; match.suggest_type = omnibox::SuggestType::TYPE_NATIVE_CHROME; @@ -341,7 +335,7 @@ const TemplateURL* template_url = GetKeywordTemplateURL(); std::u16string text = base::CollapseWhitespace(input.text(), false); - AutocompleteMatch match(this, kDefaultMatchRelevance, false, + AutocompleteMatch match(this, kDefaultVerbatimMatchRelevance, false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED); if (text.empty()) { // Inert/static keyword mode helper text match for empty input. This match @@ -369,7 +363,7 @@ /*subtypes=*/{omnibox::SUBTYPE_CONTEXTUAL_SEARCH}, /*from_keyword=*/true, /*navigational_intent=*/omnibox::NAV_INTENT_NONE, - /*relevance=*/kDefaultMatchRelevance, + /*relevance=*/kDefaultVerbatimMatchRelevance, /*relevance_from_server=*/false, /*input_text=*/text); match = CreateSearchSuggestion(
diff --git a/components/omnibox/browser/featured_search_provider.cc b/components/omnibox/browser/featured_search_provider.cc index 64969c3..5dcf8e5 100644 --- a/components/omnibox/browser/featured_search_provider.cc +++ b/components/omnibox/browser/featured_search_provider.cc
@@ -28,6 +28,7 @@ #include "components/omnibox/browser/keyword_provider.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/omnibox_prefs.h" +#include "components/omnibox/browser/suggestion_group_util.h" #include "components/omnibox/common/omnibox_feature_configs.h" #include "components/optimization_guide/core/optimization_guide_features.h" #include "components/prefs/pref_service.h" @@ -451,7 +452,7 @@ /*matched_term=*/u"@gemini", /*iph_link_text=*/u"", /*iph_link_url=*/{}, - /*relevance=*/kIPHRelevance, + /*relevance=*/omnibox::kIPHZeroSuggestRelevance, /*deletable=*/true); } @@ -498,7 +499,7 @@ /*matched_term=*/u"", /*iph_link_text=*/u"", /*iph_link_url=*/{}, - /*relevance=*/kIPHRelevance, + /*relevance=*/omnibox::kIPHZeroSuggestRelevance, /*deletable=*/true); } @@ -584,7 +585,7 @@ /*matched_term=*/u"@history", /*iph_link_text=*/u"", /*iph_link_url=*/{}, - /*relevance=*/kIPHRelevance, + /*relevance=*/omnibox::kIPHZeroSuggestRelevance, /*deletable=*/true); } @@ -604,6 +605,6 @@ /*matched_term=*/u"@history", /*iph_link_text=*/u"", /*iph_link_url=*/{}, - /*relevance=*/kIPHRelevance, + /*relevance=*/omnibox::kIPHZeroSuggestRelevance, /*deletable=*/true); }
diff --git a/components/omnibox/browser/local_history_zero_suggest_provider.cc b/components/omnibox/browser/local_history_zero_suggest_provider.cc index bf4a103..e01a895 100644 --- a/components/omnibox/browser/local_history_zero_suggest_provider.cc +++ b/components/omnibox/browser/local_history_zero_suggest_provider.cc
@@ -36,6 +36,7 @@ #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/omnibox_prefs.h" #include "components/omnibox/browser/page_classification_functions.h" +#include "components/omnibox/browser/suggestion_group_util.h" #include "components/omnibox/browser/zero_suggest_provider.h" #include "components/omnibox/common/omnibox_features.h" #include "components/search/search.h" @@ -211,8 +212,7 @@ "Omnibox.LocalHistoryZeroSuggest.SearchTermsExtractionTimeV2", db_query_timer.Elapsed()); - int relevance = - OmniboxFieldTrial::kLocalHistoryZeroSuggestRelevanceScore.Get(); + int relevance = omnibox::kLocalHistoryZeroSuggestRelevance; for (const auto& result : results) { SearchSuggestionParser::SuggestResult suggestion( /*suggestion=*/result->normalized_term,
diff --git a/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc b/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc index 31c0565..c6e6a2b 100644 --- a/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc +++ b/components/omnibox/browser/local_history_zero_suggest_provider_unittest.cc
@@ -28,6 +28,7 @@ #include "components/omnibox/browser/autocomplete_provider_listener.h" #include "components/omnibox/browser/autocomplete_result.h" #include "components/omnibox/browser/fake_autocomplete_provider_client.h" +#include "components/omnibox/browser/suggestion_group_util.h" #include "components/omnibox/common/omnibox_features.h" #include "components/search_engines/search_engines_test_util.h" #include "components/search_engines/template_url.h" @@ -38,7 +39,6 @@ using base::Time; using metrics::OmniboxEventProto; -using OmniboxFieldTrial::kLocalHistoryZeroSuggestRelevanceScore; namespace { @@ -244,8 +244,7 @@ "Omnibox.LocalHistoryZeroSuggest.SearchTermsExtractionTimeV2", 0); StartProviderAndWaitUntilDone(); - ExpectMatches( - {{"hello world", kLocalHistoryZeroSuggestRelevanceScore.Get()}}); + ExpectMatches({{"hello world", omnibox::kLocalHistoryZeroSuggestRelevance}}); // Following histograms should be logged when zero-prefix suggestions are // allowed and the keyword search terms database is queried. @@ -281,8 +280,7 @@ .WillRepeatedly(testing::Return(false)); StartProviderAndWaitUntilDone(); - ExpectMatches( - {{"hello world", kLocalHistoryZeroSuggestRelevanceScore.Get()}}); + ExpectMatches({{"hello world", omnibox::kLocalHistoryZeroSuggestRelevance}}); } // Tests that suggestions are allowed in the eligibile entry points. @@ -299,7 +297,7 @@ // Local history zero-prefix suggestions are enabled by default. ExpectMatches( - {{"hello world", kLocalHistoryZeroSuggestRelevanceScore.Get()}}); + {{"hello world", omnibox::kLocalHistoryZeroSuggestRelevance}}); } { // Disable local history zero-prefix suggestions beyond NTP. @@ -334,7 +332,7 @@ #endif // Local history zero-prefix suggestions are enabled for on-focus SRP. ExpectMatches( - {{"hello world", kLocalHistoryZeroSuggestRelevanceScore.Get()}}); + {{"hello world", omnibox::kLocalHistoryZeroSuggestRelevance}}); } } @@ -350,8 +348,7 @@ }); StartProviderAndWaitUntilDone(); - ExpectMatches( - {{"hello world", kLocalHistoryZeroSuggestRelevanceScore.Get()}}); + ExpectMatches({{"hello world", omnibox::kLocalHistoryZeroSuggestRelevance}}); template_url_service->SetUserSelectedDefaultSearchProvider( other_search_provider); @@ -381,8 +378,8 @@ StartProviderAndWaitUntilDone(); ExpectMatches( - {{"سلام دنیا", kLocalHistoryZeroSuggestRelevanceScore.Get()}, - {"hello world", kLocalHistoryZeroSuggestRelevanceScore.Get() - 1}}); + {{"سلام دنیا", omnibox::kLocalHistoryZeroSuggestRelevance}, + {"hello world", omnibox::kLocalHistoryZeroSuggestRelevance - 1}}); } // Tests that the suggestions are ranked correctly. @@ -408,9 +405,8 @@ // More recent searches are ranked higher when searches are just as frequent. StartProviderAndWaitUntilDone(); ExpectMatches( - {{"more recent search", kLocalHistoryZeroSuggestRelevanceScore.Get()}, - {"less recent search", - kLocalHistoryZeroSuggestRelevanceScore.Get() - 1}}); + {{"more recent search", omnibox::kLocalHistoryZeroSuggestRelevance}, + {"less recent search", omnibox::kLocalHistoryZeroSuggestRelevance - 1}}); // More frequent searches are ranked higher when searches are nearly as old. LoadURLs({ @@ -421,9 +417,8 @@ StartProviderAndWaitUntilDone(); ExpectMatches( - {{"less recent search", kLocalHistoryZeroSuggestRelevanceScore.Get()}, - {"more recent search", - kLocalHistoryZeroSuggestRelevanceScore.Get() - 1}}); + {{"less recent search", omnibox::kLocalHistoryZeroSuggestRelevance}, + {"more recent search", omnibox::kLocalHistoryZeroSuggestRelevance - 1}}); } // Tests that the provider supports deletion of matches. @@ -446,9 +441,9 @@ }); StartProviderAndWaitUntilDone(); - ExpectMatches({{"hello world", kLocalHistoryZeroSuggestRelevanceScore.Get()}, - {"not to be deleted", - kLocalHistoryZeroSuggestRelevanceScore.Get() - 1}}); + ExpectMatches( + {{"hello world", omnibox::kLocalHistoryZeroSuggestRelevance}, + {"not to be deleted", omnibox::kLocalHistoryZeroSuggestRelevance - 1}}); // The keyword search terms database should be queried for the search terms // submitted to the default search provider. @@ -467,12 +462,12 @@ // Make sure the deletion takes effect immediately in the provider before the // history service asynchronously performs the deletion or even before the // provider is started again. - ExpectMatches({{"not to be deleted", - kLocalHistoryZeroSuggestRelevanceScore.Get() - 1}}); + ExpectMatches( + {{"not to be deleted", omnibox::kLocalHistoryZeroSuggestRelevance - 1}}); StartProviderAndWaitUntilDone(); ExpectMatches( - {{"not to be deleted", kLocalHistoryZeroSuggestRelevanceScore.Get()}}); + {{"not to be deleted", omnibox::kLocalHistoryZeroSuggestRelevance}}); // Wait until the history service performs the deletion. history::BlockUntilHistoryProcessesPendingRequests( @@ -485,7 +480,7 @@ StartProviderAndWaitUntilDone(); ExpectMatches( - {{"not to be deleted", kLocalHistoryZeroSuggestRelevanceScore.Get()}}); + {{"not to be deleted", omnibox::kLocalHistoryZeroSuggestRelevance}}); history::URLDatabase* url_db = client_->GetHistoryService()->InMemoryDatabase();
diff --git a/components/omnibox/browser/most_visited_sites_provider.cc b/components/omnibox/browser/most_visited_sites_provider.cc index 6915ef0..d042f4e 100644 --- a/components/omnibox/browser/most_visited_sites_provider.cc +++ b/components/omnibox/browser/most_visited_sites_provider.cc
@@ -22,6 +22,7 @@ #include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/autocomplete_match_classification.h" #include "components/omnibox/browser/page_classification_functions.h" +#include "components/omnibox/browser/suggestion_group_util.h" #include "components/omnibox/browser/tab_matcher.h" #include "components/omnibox/browser/zero_suggest_provider.h" #include "components/omnibox/common/omnibox_feature_configs.h" @@ -35,22 +36,6 @@ #include "url/gurl.h" namespace { -// The relevance score for suggest tiles represented as a single tiling match. -// Suggest tiles are placed in a dedicated SECTION_MOBILE_MOST_VISITED -// making its relative relevance score not important. -constexpr const int kMostVisitedTilesAggregateRelevance = 1; - -// The relevance score for suggest tiles represented as individual matches. -// Repeatable Queries are recognized as searches, and may get merged to higher -// ranking search suggestions listed below the carousel. -constexpr const int kMostVisitedTilesIndividualHighRelevance = 1600; -// Matches known to be off-screen by default are listed as low-relevance. -// If we have additional AutocompleteMatches listed below the MV carousel -// pointing to the same destination, we want the tiles to be deduplicated to -// these matches. -constexpr const int kMostVisitedTilesIndividualLowRelevance = 100; -// Index of the last high-relevance tile. -constexpr const int kLastHighRelevanceIndividualTile = 4; constexpr const int kMaxRecordedTileIndex = 15; @@ -156,7 +141,10 @@ replacements.ClearQuery(); TemplateURLService* const url_service = client->GetTemplateURLService(); - int relevance = kMostVisitedTilesIndividualHighRelevance; + int relevance = + omnibox::IsSearchResultsPage(input.current_page_classification()) + ? omnibox::kMostVisitedTilesZeroSuggestLowRelevance + : omnibox::kMostVisitedTilesZeroSuggestHighRelevance; for (const auto& url : urls) { GURL stripped_url = StripURL(client, url.url, replacements); // Skip the match if the following is true: @@ -206,7 +194,7 @@ omnibox::kMostVisitedTilesHorizontalRenderGroup)) { auto* const url_service = client->GetTemplateURLService(); auto* const dse = url_service->GetDefaultSearchProvider(); - int relevance = kMostVisitedTilesIndividualHighRelevance; + int relevance = omnibox::kMostVisitedTilesZeroSuggestHighRelevance; for (const auto& tile : container) { // TODO(crbug.com/40279214): pass this information from History layer via // history::MostVisitedURL. @@ -243,19 +231,12 @@ } matches.emplace_back(std::move(match)); - // On phones, we fully expose a fixed number of matches. Matches beyond - // that number are partially or fully concealed by design. Drop relevance - // for these matches. - if (matches.size() == kLastHighRelevanceIndividualTile && - device_form_factor == ui::DEVICE_FORM_FACTOR_PHONE) { - relevance = kMostVisitedTilesIndividualLowRelevance; - } --relevance; } } else { AutocompleteMatch match = BuildMatch(provider, client, std::u16string(), GURL(), - kMostVisitedTilesAggregateRelevance, + omnibox::kMostVisitedTilesZeroSuggestHighRelevance, AutocompleteMatchType::TILE_NAVSUGGEST); match.suggest_tiles.reserve(container.size());
diff --git a/components/omnibox/browser/most_visited_sites_provider_unittest.cc b/components/omnibox/browser/most_visited_sites_provider_unittest.cc index 4a32087..716e203 100644 --- a/components/omnibox/browser/most_visited_sites_provider_unittest.cc +++ b/components/omnibox/browser/most_visited_sites_provider_unittest.cc
@@ -17,6 +17,7 @@ #include "components/omnibox/browser/autocomplete_enums.h" #include "components/omnibox/browser/autocomplete_provider_listener.h" #include "components/omnibox/browser/fake_autocomplete_provider_client.h" +#include "components/omnibox/browser/suggestion_group_util.h" #include "components/omnibox/browser/test_scheme_classifier.h" #include "components/omnibox/common/omnibox_feature_configs.h" #include "components/omnibox/common/omnibox_features.h" @@ -257,7 +258,7 @@ } else if (ui_type == ExpectedUiType::kIndividualTiles) { ASSERT_EQ(data.size(), NumMostVisitedMatches()) << "Unexpected number of TILE matches"; - int expected_relevance = 1600; // kMostVisitedTilesIndividualHighRelevance + int expected_relevance = omnibox::kMostVisitedTilesZeroSuggestHighRelevance; for (const auto& match : result) { if (data[match_index].is_search) { EXPECT_EQ(match.type, AutocompleteMatchType::TILE_REPEATABLE_QUERY); @@ -277,12 +278,6 @@ EXPECT_EQ(expected_relevance, match.relevance) << "Invalid Match Relevance at position " << match_index; ++match_index; - // Degrade relevance of partially visible and invisible matches. - if (match_index == 4 && - ui::GetDeviceFormFactor() == - ui::DeviceFormFactor::DEVICE_FORM_FACTOR_PHONE) { - expected_relevance = 100; // kMostVisitedTilesIndividualLowRelevance - } --expected_relevance; } } @@ -300,7 +295,7 @@ size_t match_index = 0; ASSERT_EQ(url_limit, NumMostVisitedMatches()) << "Unexpected number of TILE matches"; - int expected_relevance = 1600; // kMostVisitedTilesIndividualHighRelevance + int expected_relevance = omnibox::kMostVisitedTilesZeroSuggestHighRelevance; for (const auto& match : result) { EXPECT_EQ(match.type, AutocompleteMatchType::TILE_MOST_VISITED_SITE); EXPECT_TRUE(match.subtypes.contains(
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc index 0fe9fb9..1304e79c 100644 --- a/components/omnibox/browser/omnibox_field_trial.cc +++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -736,13 +736,6 @@ "ZeroSuggestCacheMaxSize", 5); -// The relevance score for remote zero-suggest ranges from 550-1400. A default -// value of 500 places local history zero-suggest below the remote zero-suggest. -const base::FeatureParam<int> kLocalHistoryZeroSuggestRelevanceScore( - &omnibox::kAdjustLocalHistoryZeroSuggestRelevanceScore, - "LocalHistoryZeroSuggestRelevanceScore", - 500); - bool IsZeroSuggestPrefetchingEnabled() { return base::FeatureList::IsEnabled(omnibox::kZeroSuggestPrefetching) || base::FeatureList::IsEnabled(omnibox::kZeroSuggestPrefetchingOnSRP) ||
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h index d9c3d963..ed1d3eef 100644 --- a/components/omnibox/browser/omnibox_field_trial.h +++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -405,9 +405,6 @@ // Determines the maximum number of entries stored by the in-memory ZPS cache. extern const base::FeatureParam<int> kZeroSuggestCacheMaxSize; -// Determines the relevance score for the local history zero-prefix suggestions. -extern const base::FeatureParam<int> kLocalHistoryZeroSuggestRelevanceScore; - // Returns true if any of the zero-suggest prefetching features are enabled. bool IsZeroSuggestPrefetchingEnabled();
diff --git a/components/omnibox/browser/open_tab_provider.cc b/components/omnibox/browser/open_tab_provider.cc index a2eea59..0c28a495 100644 --- a/components/omnibox/browser/open_tab_provider.cc +++ b/components/omnibox/browser/open_tab_provider.cc
@@ -9,6 +9,7 @@ #include "base/i18n/case_conversion.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "components/omnibox/browser/suggestion_group_util.h" #if BUILDFLAG(IS_ANDROID) #include "components/browser_ui/util/android/url_constants.h" #endif @@ -34,7 +35,6 @@ namespace { constexpr bool is_android = !!BUILDFLAG(IS_ANDROID); -constexpr int kOpenTabDefaultScore = 1500; int Score(const AutocompleteInput& input, const query_parser::QueryNodeVector& input_query_nodes, @@ -51,7 +51,7 @@ #endif if ((input.IsZeroSuggest() || input.text().empty()) && is_android) { - return kOpenTabDefaultScore + + return omnibox::kOpenTabMatchZeroSuggestRelevance + tab.last_shown_time.InSecondsFSinceUnixEpoch(); } // TODO(crbug.com/40211187): The bookmark provider also uses on `query_parser`
diff --git a/components/omnibox/browser/suggestion_group_util.h b/components/omnibox/browser/suggestion_group_util.h index 025c1045..0f7a5878e 100644 --- a/components/omnibox/browser/suggestion_group_util.h +++ b/components/omnibox/browser/suggestion_group_util.h
@@ -10,6 +10,43 @@ namespace omnibox { +// Verbatim suggestion is assigned the highest relevance to ensure #1 it appears +// at the top and #2 duplicate suggestions are merged to the verbatim suggestion +// and not the other way around. +inline constexpr int kVerbatimMatchZeroSuggestRelevance = 1602; +// Clipboard suggestion is assigned the 2nd highest relevance to ensure it +// appears after the verbatim suggestion. +inline constexpr int kClipboardMatchZeroSuggestRelevance = 1601; +// MostVisited suggestions on Web are assigned the 3rd highest relevance to +// ensure they appear after the Clipboard suggestion. +inline constexpr int kMostVisitedTilesZeroSuggestHighRelevance = 1600; +// OpenTab suggestions are assigned the 4th highest relevance to ensure they +// appear #1 below the MostVisited tiles and #2 above the remote zero-prefix +// suggestions which have relevance scores between 550-1400. +inline constexpr int kOpenTabMatchZeroSuggestRelevance = 1500; +// Contextual action (pedal) suggestions are assigned a relevance of 1500 to +// ensure they appear above the remote zero-prefix suggestions which have +// relevance scores between 550-1400. +inline constexpr int kContextualActionZeroSuggestRelevance = 1500; +// Remote zero-prefix suggestions are assigned a default relevance of 1400 when +// not explicitly specified by the server, ensuring consistency with their usual +// relevance scores. +inline constexpr int kDefaultRemoteZeroSuggestRelevance = 1400; +// Local History zero-prefix suggestions are assigned a default relevance of 500 +// to ensure #1 they appear below and #2 are merged into (if are duplicates) the +// remote zero-prefix suggestions which have relevance scores between 550-1400. +inline constexpr int kLocalHistoryZeroSuggestRelevance = 500; +// MostVisited suggestions on SRP are assigned a default relevance of 500 to +// ensure they appear below the remote zero-prefix suggestions which have +// relevance scores between 550-1400. +inline constexpr int kMostVisitedTilesZeroSuggestLowRelevance = 500; +// Unscoped Extension suggestions are assigned a default relevance of 400 to +// ensure they appear below all other suggestions, except for IPH suggestions. +inline constexpr int kUnscopedExtensionZeroSuggestRelevance = 400; +// IPH suggestions get a default relevance of 300 to ensure they appear at the +// bottom. +inline constexpr int kIPHZeroSuggestRelevance = 300; + using GroupConfigMap = std::unordered_map<GroupId, GroupConfig>; // Builds the pre-defined static groups that are useful for sorting suggestions.
diff --git a/components/omnibox/browser/zero_suggest_provider.cc b/components/omnibox/browser/zero_suggest_provider.cc index 0c8bc96..d519866 100644 --- a/components/omnibox/browser/zero_suggest_provider.cc +++ b/components/omnibox/browser/zero_suggest_provider.cc
@@ -33,6 +33,7 @@ #include "components/omnibox/browser/page_classification_functions.h" #include "components/omnibox/browser/remote_suggestions_service.h" #include "components/omnibox/browser/search_suggestion_parser.h" +#include "components/omnibox/browser/suggestion_group_util.h" #include "components/omnibox/browser/zero_suggest_cache_service.h" #include "components/omnibox/common/omnibox_feature_configs.h" #include "components/omnibox/common/omnibox_features.h" @@ -119,9 +120,6 @@ request_event); } -// Relevance value to use if it was not set explicitly by the server. -const int kDefaultZeroSuggestRelevance = 100; - // Called in StoreRemoteResponse() and ReadStoredResponse() to determine if the // zero suggest cache is being used to store ZPS responses received from the // remote Suggest service for the given |result_type|. @@ -168,7 +166,8 @@ if (!SearchSuggestionParser::ParseSuggestResults( *response_data, input, client->GetSchemeClassifier(), - /*default_result_relevance=*/kDefaultZeroSuggestRelevance, + /*default_result_relevance=*/ + omnibox::kDefaultRemoteZeroSuggestRelevance, /*is_keyword_result=*/false, results)) { return false; } @@ -225,7 +224,8 @@ if (!SearchSuggestionParser::ParseSuggestResults( *response_data, input, client->GetSchemeClassifier(), - /*default_result_relevance=*/kDefaultZeroSuggestRelevance, + /*default_result_relevance=*/ + omnibox::kDefaultRemoteZeroSuggestRelevance, /*is_keyword_result=*/false, results)) { return false; }
diff --git a/components/omnibox/browser/zero_suggest_verbatim_match_provider.cc b/components/omnibox/browser/zero_suggest_verbatim_match_provider.cc index c732fbc..5b2d695d 100644 --- a/components/omnibox/browser/zero_suggest_verbatim_match_provider.cc +++ b/components/omnibox/browser/zero_suggest_verbatim_match_provider.cc
@@ -16,6 +16,7 @@ #include "components/omnibox/browser/autocomplete_match_classification.h" #include "components/omnibox/browser/autocomplete_provider_client.h" #include "components/omnibox/browser/autocomplete_provider_listener.h" +#include "components/omnibox/browser/suggestion_group_util.h" #include "components/omnibox/browser/verbatim_match.h" #include "components/omnibox/common/omnibox_features.h" #include "components/search_engines/template_url_service.h" @@ -24,14 +25,6 @@ namespace { constexpr bool is_android = !!BUILDFLAG(IS_ANDROID); -// Verbatim Match is placed in a dedicated SECTION_MOBILE_VERBATIM. -// While there are no other occupants of this section, the Relevance score -// remains important, because the Verbatim Match may get de-duplicated to other, -// higher ranking suggestions listed later on the list. -// Keep the relevance high to ensure matching suggestions listed later are -// merged to the Verbatim Match, not the other way around. -const int kVerbatimMatchRelevanceScore = 1602; - // Returns whether specific context is eligible for a verbatim match. // Only offer verbatim match on a site visit and SRP (no NTP etc). bool IsVerbatimMatchEligible( @@ -123,9 +116,9 @@ verbatim_input.set_prevent_inline_autocomplete(true); verbatim_input.set_allow_exact_keyword_match(false); - AutocompleteMatch match = - VerbatimMatchForURL(this, client_, verbatim_input, input.current_url(), - std::move(page_title), kVerbatimMatchRelevanceScore); + AutocompleteMatch match = VerbatimMatchForURL( + this, client_, verbatim_input, input.current_url(), std::move(page_title), + omnibox::kVerbatimMatchZeroSuggestRelevance); // Make sure the URL is formatted the same was as most visited sites. auto format_types = AutocompleteMatch::GetFormatTypes(false, false); match.suggestion_group_id = omnibox::GROUP_MOBILE_SEARCH_READY_OMNIBOX;
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc index ddda598..4008d781 100644 --- a/components/omnibox/common/omnibox_features.cc +++ b/components/omnibox/common/omnibox_features.cc
@@ -82,13 +82,6 @@ "DisambiguateTabMatchingForEntitySuggestions", ENABLED); -// Used to adjust the relevance for the local history zero-prefix suggestions. -// If enabled, the relevance is determined by this feature's companion -// parameter, OmniboxFieldTrial::kLocalHistoryZeroSuggestRelevanceScore. -BASE_FEATURE(kAdjustLocalHistoryZeroSuggestRelevanceScore, - "AdjustLocalHistoryZeroSuggestRelevanceScore", - DISABLED); - // Enables omnibox focus as a trigger for zero-prefix suggestions on web and // SRP, subject to the same requirements and conditions as on-clobber // suggestions.
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h index 23af711b..4bd909c 100644 --- a/components/omnibox/common/omnibox_features.h +++ b/components/omnibox/common/omnibox_features.h
@@ -37,7 +37,6 @@ BASE_DECLARE_FEATURE(kDisambiguateTabMatchingForEntitySuggestions); // Local history zero-prefix (aka zero-suggest) and prefix suggestions. -BASE_DECLARE_FEATURE(kAdjustLocalHistoryZeroSuggestRelevanceScore); BASE_DECLARE_FEATURE(kFocusTriggersWebAndSRPZeroSuggest); BASE_DECLARE_FEATURE(kHideSuggestionGroupHeaders); BASE_DECLARE_FEATURE(kLocalHistoryZeroSuggestBeyondNTP);
diff --git a/components/optimization_guide/core/model_execution/on_device_execution.cc b/components/optimization_guide/core/model_execution/on_device_execution.cc index 3fe0af9..11db37b 100644 --- a/components/optimization_guide/core/model_execution/on_device_execution.cc +++ b/components/optimization_guide/core/model_execution/on_device_execution.cc
@@ -188,7 +188,8 @@ auto options = on_device_model::mojom::GenerateOptions::New(); options->max_output_tokens = opts_.token_limits.max_output_tokens; - options->constraint = std::move(constraint_); + options->constraint = constraint_ ? std::move(constraint_) + : opts_.adapter->GetResponseConstraint(); opts_.safety_checker->RunRequestChecks( last_message_,
diff --git a/components/optimization_guide/core/model_execution/on_device_model_feature_adapter.cc b/components/optimization_guide/core/model_execution/on_device_model_feature_adapter.cc index 6dc8713..da52da7 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_feature_adapter.cc +++ b/components/optimization_guide/core/model_execution/on_device_model_feature_adapter.cc
@@ -185,4 +185,20 @@ return token_limits_; } +on_device_model::mojom::ResponseConstraintPtr +OnDeviceModelFeatureAdapter::GetResponseConstraint() const { + const auto& constraint = config_.output_config().response_constraint(); + switch (constraint.format_case()) { + case proto::ResponseConstraint::kJsonSchema: + return on_device_model::mojom::ResponseConstraint::NewJsonSchema( + constraint.json_schema()); + case proto::ResponseConstraint::kRegex: + return on_device_model::mojom::ResponseConstraint::NewRegex( + constraint.regex()); + default: + // Not configured, or not supported configuration. + return nullptr; + } +} + } // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_execution/on_device_model_feature_adapter.h b/components/optimization_guide/core/model_execution/on_device_model_feature_adapter.h index 92ce8f7..d9f9f74 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_feature_adapter.h +++ b/components/optimization_guide/core/model_execution/on_device_model_feature_adapter.h
@@ -24,6 +24,7 @@ #include "components/optimization_guide/core/optimization_guide_model_executor.h" #include "components/optimization_guide/proto/features/text_safety.pb.h" #include "components/optimization_guide/proto/on_device_model_execution_config.pb.h" +#include "services/on_device_model/public/mojom/on_device_model.mojom-forward.h" namespace optimization_guide { @@ -72,6 +73,9 @@ return config_; } + // Get the configured response constraint, may be null. + on_device_model::mojom::ResponseConstraintPtr GetResponseConstraint() const; + private: friend class base::RefCounted<OnDeviceModelFeatureAdapter>; ~OnDeviceModelFeatureAdapter();
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc b/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc index b06863d..7b52335 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc +++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc
@@ -207,20 +207,6 @@ feature, std::move(opts), std::move(execute_remote_fn), config_params); } -// static -void OnDeviceModelServiceController::GetEstimatedPerformanceClass( - scoped_refptr<OnDeviceModelServiceController> controller, - base::OnceCallback<void(OnDeviceModelPerformanceClass)> callback) { - auto* raw_controller = controller.get(); - raw_controller->service_client_.Get()->GetEstimatedPerformanceClass( - base::BindOnce(&ConvertToOnDeviceModelPerformanceClass) - .Then(mojo::WrapCallbackWithDefaultInvokeIfNotRun( - std::move(callback), - OnDeviceModelPerformanceClass::kServiceCrash)) - .Then(base::OnceClosure( - base::DoNothingWithBoundArgs(std::move(controller))))); -} - void OnDeviceModelServiceController::SetLanguageDetectionModel( base::optional_ref<const ModelInfo> model_info) { safety_client_.SetLanguageDetectionModel(model_info); @@ -420,6 +406,14 @@ void OnDeviceModelServiceController::Subscribe( mojom::ModelSubscriptionOptionsPtr opts, mojo::PendingRemote<mojom::ModelSubscriber> subscriber) { + EnsurePerformanceClassAvailable(base::BindOnce( + &OnDeviceModelServiceController::SubscribeInternal, + weak_ptr_factory_.GetWeakPtr(), std::move(opts), std::move(subscriber))); +} + +void OnDeviceModelServiceController::SubscribeInternal( + mojom::ModelSubscriptionOptionsPtr opts, + mojo::PendingRemote<mojom::ModelSubscriber> subscriber) { auto feature = ToModelBasedCapabilityKey(opts->id); if (opts->mark_used && on_device_component_state_manager_) { on_device_component_state_manager_->OnDeviceEligibleFeatureUsed(feature); @@ -710,4 +704,55 @@ controller_->access_controller_->OnResponseCompleted(); } +void OnDeviceModelServiceController::EnsurePerformanceClassAvailable( + base::OnceClosure complete) { + if (!on_device_component_state_manager_ || + !on_device_component_state_manager_->NeedsPerformanceClassUpdate()) { + std::move(complete).Run(); + return; + } + + if (performance_class_state_ == PerformanceClassState::kComplete) { + std::move(complete).Run(); + return; + } + + // Use unsafe because cancellation isn't needed. + performance_class_callbacks_.AddUnsafe(std::move(complete)); + + if (performance_class_state_ == PerformanceClassState::kComputing) { + return; + } + + performance_class_state_ = PerformanceClassState::kComputing; + service_client_.Get()->GetEstimatedPerformanceClass( + base::BindOnce(&ConvertToOnDeviceModelPerformanceClass) + .Then(mojo::WrapCallbackWithDefaultInvokeIfNotRun( + base::BindOnce( + &OnDeviceModelServiceController::PerformanceClassUpdated, + base::RetainedRef(this)), + OnDeviceModelPerformanceClass::kServiceCrash))); +} + +void OnDeviceModelServiceController::PerformanceClassUpdated( + OnDeviceModelPerformanceClass perf_class) { + base::UmaHistogramEnumeration( + "OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", + perf_class); + RegisterPerformanceClassSyntheticTrial(perf_class); + + auto complete = base::BindOnce( + [](scoped_refptr<OnDeviceModelServiceController> controller) { + controller->performance_class_state_ = PerformanceClassState::kComplete; + controller->performance_class_callbacks_.Notify(); + }, + base::RetainedRef(this)); + if (on_device_component_state_manager_) { + on_device_component_state_manager_->DevicePerformanceClassChanged( + std::move(complete), perf_class); + } else { + std::move(complete).Run(); + } +} + } // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller.h b/components/optimization_guide/core/model_execution/on_device_model_service_controller.h index 071a44dc..c0f4e29 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_service_controller.h +++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller.h
@@ -11,6 +11,7 @@ #include <optional> #include <string_view> +#include "base/callback_list.h" #include "base/memory/raw_ptr.h" #include "base/memory/raw_ref.h" #include "base/memory/ref_counted.h" @@ -103,14 +104,6 @@ base::WeakPtr<OptimizationGuideLogger> logger, const std::optional<SessionConfigParams>& config_params); - // Starts the service and executes a benchmark to determine the performance - // class, returning the result via `callback`. The controller will be kept - // alive until the benchmark completes. Returns kServiceCrash if the service - // crashes. - static void GetEstimatedPerformanceClass( - scoped_refptr<OnDeviceModelServiceController> controller, - base::OnceCallback<void(OnDeviceModelPerformanceClass)> callback); - // Sets the language detection model to be used by the ODM service when text // safety evaluation is restricted to a specific set of languages. void SetLanguageDetectionModel( @@ -151,6 +144,13 @@ receivers_.Add(this, std::move(receiver)); } + // Ensures the performance class will be up to date and available when + // `complete` runs. + void EnsurePerformanceClassAvailable(base::OnceClosure complete); + + virtual void RegisterPerformanceClassSyntheticTrial( + OnDeviceModelPerformanceClass perf_class) {} + protected: ~OnDeviceModelServiceController() override; @@ -365,6 +365,12 @@ void Subscribe(mojom::ModelSubscriptionOptionsPtr opts, mojo::PendingRemote<mojom::ModelSubscriber> client) override; + void SubscribeInternal(mojom::ModelSubscriptionOptionsPtr opts, + mojo::PendingRemote<mojom::ModelSubscriber> client); + + // Called when performance class has finished updating. + void PerformanceClassUpdated(OnDeviceModelPerformanceClass perf_class); + // This may be null in the destructor, otherwise non-null. std::unique_ptr<OnDeviceModelAccessController> access_controller_; std::optional<OnDeviceModelMetadataLoader> model_metadata_loader_; @@ -388,6 +394,17 @@ mojo::ReceiverSet<mojom::ModelBroker> receivers_; + enum class PerformanceClassState { + kNotSet, + kComputing, + kComplete, + }; + PerformanceClassState performance_class_state_ = + PerformanceClassState::kNotSet; + + // Callbacks waiting for performance class to finish computing. + base::OnceClosureList performance_class_callbacks_; + // Used to get `weak_ptr_` to self. base::WeakPtrFactory<OnDeviceModelServiceController> weak_ptr_factory_{this}; };
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc b/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc index c4f8f14..f6a806b0 100644 --- a/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc +++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc
@@ -66,6 +66,7 @@ #include "services/on_device_model/public/cpp/capabilities.h" #include "services/on_device_model/public/cpp/service_client.h" #include "services/on_device_model/public/cpp/test_support/fake_service.h" +#include "services/on_device_model/public/mojom/on_device_model.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -276,7 +277,6 @@ TEST_F(OnDeviceModelServiceControllerTest, ScoreBeforeContext) { Initialize(standard_assets_); - base::HistogramTester histogram_tester; auto session = CreateSession(); ASSERT_TRUE(session); base::test::TestFuture<std::optional<float>> score_future; @@ -287,7 +287,6 @@ TEST_F(OnDeviceModelServiceControllerTest, ScorePresentAfterContext) { Initialize(standard_assets_); - base::HistogramTester histogram_tester; auto session = CreateSession(); ASSERT_TRUE(session); @@ -301,7 +300,6 @@ TEST_F(OnDeviceModelServiceControllerTest, ScoreAfterExecute) { Initialize(standard_assets_); - base::HistogramTester histogram_tester; auto session = CreateSession(); ASSERT_TRUE(session); @@ -628,7 +626,6 @@ }); // Model not yet available. - base::HistogramTester histogram_tester; auto session = CreateSession(); EXPECT_FALSE(session); @@ -679,7 +676,6 @@ EXPECT_EQ(0ull, fake_launcher_.on_device_model_receiver_count()); // Create a new session and verify it uses the new model. - base::HistogramTester histogram_tester; auto session2 = CreateSession(); ASSERT_TRUE(session2); ResponseHolder response2; @@ -2004,27 +2000,17 @@ TEST_F(OnDeviceModelServiceControllerTest, ShutsDownServiceAfterPerformanceCheck) { Initialize(standard_assets_); - base::test::TestFuture<OnDeviceModelPerformanceClass> result_future; - OnDeviceModelServiceController::GetEstimatedPerformanceClass( - test_controller_, result_future.GetCallback()); - EXPECT_EQ(OnDeviceModelPerformanceClass::kVeryHigh, result_future.Get()); + base::HistogramTester histogram_tester; + base::RunLoop run_loop; + test_controller_->EnsurePerformanceClassAvailable(run_loop.QuitClosure()); + run_loop.Run(); + histogram_tester.ExpectUniqueSample( + "OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", + OnDeviceModelPerformanceClass::kVeryHigh, 1); task_environment_.RunUntilIdle(); EXPECT_FALSE(fake_launcher_.is_service_running()); } -TEST_F(OnDeviceModelServiceControllerTest, - PerformanceCheckKeepsControllerAlive) { - Initialize(standard_assets_); - auto weak_controller = test_controller_->GetWeakPtr(); - access_controller_ = nullptr; // Avoid dangling pointer - base::test::TestFuture<OnDeviceModelPerformanceClass> result_future; - OnDeviceModelServiceController::GetEstimatedPerformanceClass( - std::move(test_controller_), result_future.GetCallback()); - EXPECT_EQ(OnDeviceModelPerformanceClass::kVeryHigh, result_future.Get()); - // Verify there wasn't something else keeping the controller alive. - EXPECT_FALSE(weak_controller); -} - TEST_F(OnDeviceModelServiceControllerTest, RedactedField) { auto config = SimpleComposeConfig(); config.set_can_skip_text_safety(true); @@ -3155,10 +3141,9 @@ Initialize({.base_model = &base_model, .adaptations = {&compose_asset}}); task_environment_.RunUntilIdle(); - base::test::TestFuture<OnDeviceModelPerformanceClass> result_future; - OnDeviceModelServiceController::GetEstimatedPerformanceClass( - test_controller_, result_future.GetCallback()); - EXPECT_EQ(OnDeviceModelPerformanceClass::kVeryHigh, result_future.Get()); + base::RunLoop run_loop; + test_controller_->EnsurePerformanceClassAvailable(run_loop.QuitClosure()); + run_loop.Run(); task_environment_.RunUntilIdle(); // Performance check sh;ould not shut down service. @@ -3187,9 +3172,8 @@ Initialize({.base_model = &base_model, .adaptations = {&compose_asset}}); task_environment_.RunUntilIdle(); - base::test::TestFuture<OnDeviceModelPerformanceClass> result_future; - OnDeviceModelServiceController::GetEstimatedPerformanceClass( - test_controller_, result_future.GetCallback()); + base::RunLoop run_loop; + test_controller_->EnsurePerformanceClassAvailable(run_loop.QuitClosure()); task_environment_.FastForwardBy(base::Seconds(1) + base::Milliseconds(1)); task_environment_.RunUntilIdle(); @@ -3200,8 +3184,8 @@ "OptimizationGuide.ModelExecution.OnDeviceModelValidationResult", OnDeviceModelValidationResult::kSuccess, 1); - EXPECT_FALSE(result_future.IsReady()); - EXPECT_EQ(OnDeviceModelPerformanceClass::kVeryHigh, result_future.Get()); + EXPECT_FALSE(run_loop.AnyQuitCalled()); + run_loop.Run(); task_environment_.RunUntilIdle(); EXPECT_FALSE(fake_launcher_.is_service_running()); } @@ -3672,6 +3656,29 @@ EXPECT_EQ(*response.value(), "Context: execute:bar max:1024\n"); } +TEST_F(OnDeviceModelServiceControllerTest, + BrokerCreateSessionRunsPerformanceClassCheck) { + base::HistogramTester histogram_tester; + mojo::PendingReceiver<mojom::ModelBroker> pending_broker; + + ModelBrokerClient broker_client( + pending_broker.InitWithNewPipeAndPassRemote(), + CreateSessionArgs(logger_.GetWeakPtr(), FailOnRemoteFallback())); + base::test::TestFuture< + std::unique_ptr<OptimizationGuideModelExecutor::Session>> + session_future; + broker_client.CreateSession(mojom::ModelBasedCapabilityKey::kCompose, + std::nullopt, session_future.GetCallback()); + + Initialize(standard_assets_); + test_controller_->BindBroker(std::move(pending_broker)); + + ASSERT_TRUE(session_future.Take()); + histogram_tester.ExpectUniqueSample( + "OptimizationGuide.ModelExecution.OnDeviceModelPerformanceClass", + OnDeviceModelPerformanceClass::kVeryHigh, 1); +} + TEST_F(OnDeviceModelServiceControllerTest, Priority) { Initialize(standard_assets_); @@ -3790,4 +3797,84 @@ EXPECT_EQ(response_.output_token_count(), strlen("execute:foo max:1024")); } +TEST_F(OnDeviceModelServiceControllerTest, ResponseConstraintOnExecute) { + Initialize(standard_assets_); + auto session = test_controller_->CreateSession( + kFeature, FailOnRemoteFallback(), logger_.GetWeakPtr(), + /*config_params=*/std::nullopt); + ASSERT_TRUE(session); + session->ExecuteModelWithResponseConstraint( + PageUrlRequest("input"), + on_device_model::mojom::ResponseConstraint::NewRegex("[A-Z]*"), + response_.GetStreamingCallback()); + ASSERT_TRUE(response_.GetFinalStatus()); + EXPECT_EQ(response_.value(), + "Constraint: regex [A-Z]*\n" + "Context: execute:input max:1024\n"); +} + +TEST_F(OnDeviceModelServiceControllerTest, ResponseConstraintConfigJson) { + FakeAdaptationAsset test_asset({ + .config = + []() { + auto config = SimpleComposeConfig(); + config.mutable_output_config() + ->mutable_response_constraint() + ->set_json_schema("{ type: \"object\"}"); + return config; + }(), + }); + + Initialize({ + .base_model = &standard_assets_.base_model, + .safety = &standard_assets_.safety, + .language = &standard_assets_.language, + .adaptations = {&test_asset}, + }); + + auto session = test_controller_->CreateSession( + kFeature, FailOnRemoteFallback(), logger_.GetWeakPtr(), + /*config_params=*/std::nullopt); + ASSERT_TRUE(session); + + session->ExecuteModel(PageUrlRequest("input"), + response_.GetStreamingCallback()); + ASSERT_TRUE(response_.GetFinalStatus()); + EXPECT_EQ(response_.value(), + "Constraint: json { type: \"object\"}\n" + "Context: execute:input max:1024\n"); +} + +TEST_F(OnDeviceModelServiceControllerTest, ResponseConstraintConfigRegex) { + FakeAdaptationAsset test_asset({ + .config = + []() { + auto config = SimpleComposeConfig(); + config.mutable_output_config() + ->mutable_response_constraint() + ->set_regex("[A-Z]*"); + return config; + }(), + }); + + Initialize({ + .base_model = &standard_assets_.base_model, + .safety = &standard_assets_.safety, + .language = &standard_assets_.language, + .adaptations = {&test_asset}, + }); + + auto session = test_controller_->CreateSession( + kFeature, FailOnRemoteFallback(), logger_.GetWeakPtr(), + /*config_params=*/std::nullopt); + ASSERT_TRUE(session); + + session->ExecuteModel(PageUrlRequest("input"), + response_.GetStreamingCallback()); + ASSERT_TRUE(response_.GetFinalStatus()); + EXPECT_EQ(response_.value(), + "Constraint: regex [A-Z]*\n" + "Context: execute:input max:1024\n"); +} + } // namespace optimization_guide
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal index d9be8fd..448e864 160000 --- a/components/optimization_guide/internal +++ b/components/optimization_guide/internal
@@ -1 +1 @@ -Subproject commit d9be8fda5a8b047287677a35f2b3a6111f5883be +Subproject commit 448e864469af5010a1dbb83b15d0cbfa1dcb5f55
diff --git a/components/optimization_guide/proto/on_device_model_execution_config.proto b/components/optimization_guide/proto/on_device_model_execution_config.proto index 82df47a..9a5a1e9d 100644 --- a/components/optimization_guide/proto/on_device_model_execution_config.proto +++ b/components/optimization_guide/proto/on_device_model_execution_config.proto
@@ -101,6 +101,18 @@ optional uint32 max_execute_tokens = 6; } +// Rules that generated output must follow. +message ResponseConstraint { + oneof format { + // A JSON Schema describing an llguidance constraint on the output. See + // https://github.com/guidance-ai/llguidance/blob/main/docs/json_schema.md + string json_schema = 1; + // A regex describing the llguidance constraint on the output. + // See https://docs.rs/regex/latest/regex/#syntax for syntax. + string regex = 2; + } +} + message OnDeviceModelExecutionOutputConfig { reserved 7; @@ -121,6 +133,9 @@ // The maximum number of tokens that can be generated as output. optional uint32 max_output_tokens = 6; + + // The response constraint to use when generating output. + optional ResponseConstraint response_constraint = 8; } message TextSafetyFallbackConfig {
diff --git a/components/page_load_metrics/browser/metrics_navigation_throttle.cc b/components/page_load_metrics/browser/metrics_navigation_throttle.cc index d722748..1a9f0dc 100644 --- a/components/page_load_metrics/browser/metrics_navigation_throttle.cc +++ b/components/page_load_metrics/browser/metrics_navigation_throttle.cc
@@ -11,9 +11,10 @@ namespace page_load_metrics { // static -std::unique_ptr<content::NavigationThrottle> MetricsNavigationThrottle::Create( - content::NavigationHandle* handle) { - return base::WrapUnique(new MetricsNavigationThrottle(handle)); +void MetricsNavigationThrottle::CreateAndAdd( + content::NavigationThrottleRegistry& registry) { + registry.AddThrottle( + base::WrapUnique(new MetricsNavigationThrottle(registry))); } MetricsNavigationThrottle::~MetricsNavigationThrottle() = default; @@ -23,8 +24,9 @@ MetricsWebContentsObserver* observer = MetricsWebContentsObserver::FromWebContents( navigation_handle()->GetWebContents()); - if (observer) + if (observer) { observer->WillStartNavigationRequest(navigation_handle()); + } return content::NavigationThrottle::PROCEED; } @@ -33,8 +35,9 @@ MetricsWebContentsObserver* observer = MetricsWebContentsObserver::FromWebContents( navigation_handle()->GetWebContents()); - if (observer) + if (observer) { observer->WillProcessNavigationResponse(navigation_handle()); + } return content::NavigationThrottle::PROCEED; } @@ -43,7 +46,7 @@ } MetricsNavigationThrottle::MetricsNavigationThrottle( - content::NavigationHandle* handle) - : content::NavigationThrottle(handle) {} + content::NavigationThrottleRegistry& registry) + : content::NavigationThrottle(registry) {} } // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/metrics_navigation_throttle.h b/components/page_load_metrics/browser/metrics_navigation_throttle.h index fc29e03..93cdcff9 100644 --- a/components/page_load_metrics/browser/metrics_navigation_throttle.h +++ b/components/page_load_metrics/browser/metrics_navigation_throttle.h
@@ -5,20 +5,17 @@ #ifndef COMPONENTS_PAGE_LOAD_METRICS_BROWSER_METRICS_NAVIGATION_THROTTLE_H_ #define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_METRICS_NAVIGATION_THROTTLE_H_ -#include <memory> - #include "content/public/browser/navigation_throttle.h" +#include "content/public/browser/navigation_throttle_registry.h" namespace page_load_metrics { // This class is used to forward calls to the MetricsWebContentsObserver. // Namely, WillStartRequest() is called on NavigationThrottles, but not on -// WebContentsObservers. Data from the NavigationHandle accessed at this point -// is used to obtain more reliable abort metrics (like page transition type). +// WebContentsObservers. class MetricsNavigationThrottle : public content::NavigationThrottle { public: - static std::unique_ptr<content::NavigationThrottle> Create( - content::NavigationHandle* handle); + static void CreateAndAdd(content::NavigationThrottleRegistry& registry); MetricsNavigationThrottle(const MetricsNavigationThrottle&) = delete; MetricsNavigationThrottle& operator=(const MetricsNavigationThrottle&) = @@ -33,7 +30,8 @@ const char* GetNameForLogging() override; private: - explicit MetricsNavigationThrottle(content::NavigationHandle* handle); + explicit MetricsNavigationThrottle( + content::NavigationThrottleRegistry& registry); }; } // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc index b30ced27..55dad9f2 100644 --- a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc +++ b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -885,11 +885,8 @@ // SubresourceFilterTestHarness:: void AppendCustomNavigationThrottles( content::NavigationThrottleRegistry& registry) override { - content::NavigationHandle& navigation_handle = - registry.GetNavigationHandle(); - if (navigation_handle.IsInMainFrame()) { - registry.AddThrottle( - MetricsNavigationThrottle::Create(&navigation_handle)); + if (registry.GetNavigationHandle().IsInMainFrame()) { + MetricsNavigationThrottle::CreateAndAdd(registry); } }
diff --git a/components/page_load_metrics/browser/page_load_metrics_test_content_browser_client.cc b/components/page_load_metrics/browser/page_load_metrics_test_content_browser_client.cc index 3349573..d379577a 100644 --- a/components/page_load_metrics/browser/page_load_metrics_test_content_browser_client.cc +++ b/components/page_load_metrics/browser/page_load_metrics_test_content_browser_client.cc
@@ -21,10 +21,8 @@ void PageLoadMetricsTestContentBrowserClient::CreateThrottlesForNavigation( content::NavigationThrottleRegistry& registry) { - content::NavigationHandle& navigation_handle = registry.GetNavigationHandle(); - if (navigation_handle.IsInMainFrame()) { - registry.AddThrottle(page_load_metrics::MetricsNavigationThrottle::Create( - &navigation_handle)); + if (registry.GetNavigationHandle().IsInMainFrame()) { + page_load_metrics::MetricsNavigationThrottle::CreateAndAdd(registry); } }
diff --git a/components/payments/content/android/BUILD.gn b/components/payments/content/android/BUILD.gn index 28bc62f..9e00160 100644 --- a/components/payments/content/android/BUILD.gn +++ b/components/payments/content/android/BUILD.gn
@@ -178,6 +178,7 @@ "java/src/org/chromium/components/payments/PaymentHandlerNavigationThrottle.java", "java/src/org/chromium/components/payments/PaymentManifestDownloader.java", "java/src/org/chromium/components/payments/PaymentManifestParser.java", + "java/src/org/chromium/components/payments/PaymentManifestResolver.java", "java/src/org/chromium/components/payments/PaymentManifestVerifier.java", "java/src/org/chromium/components/payments/PaymentManifestWebDataService.java", "java/src/org/chromium/components/payments/PaymentNotShownError.java", @@ -395,6 +396,7 @@ "junit/src/org/chromium/components/payments/BrowserGlobalPaymentFlowManagerUnitTest.java", "junit/src/org/chromium/components/payments/DeduplicatePaymentAppsUnitTest.java", "junit/src/org/chromium/components/payments/PaymentDetailsUpdateConnectionTest.java", + "junit/src/org/chromium/components/payments/PaymentManifestResolverTest.java", "junit/src/org/chromium/components/payments/PaymentRequestServiceTest.java", "junit/src/org/chromium/components/payments/intent/WebPaymentIntentHelperTypeConverterTest.java", ]
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/AndroidPaymentAppFinder.java b/components/payments/content/android/java/src/org/chromium/components/payments/AndroidPaymentAppFinder.java index 3c2ad97..7552348 100644 --- a/components/payments/content/android/java/src/org/chromium/components/payments/AndroidPaymentAppFinder.java +++ b/components/payments/content/android/java/src/org/chromium/components/payments/AndroidPaymentAppFinder.java
@@ -36,8 +36,11 @@ * Finds installed native Android payment apps and verifies their signatures according to the * payment method manifests. The manifests are located based on the payment method name, which is a * URL that starts with "https://" (localhosts can be "http://", however). The W3C-published non-URL - * payment method names are exceptions: these are common payment method names that do not have a + * payment method names[1] are exceptions: these are common payment method names that do not have a * manifest and can be used by any payment app. + * + * <p>[1] <a href="https://w3c.github.io/payment-method-id/#registry">Registry of standardized + * payment methods</a>. */ @NullMarked public class AndroidPaymentAppFinder implements ManifestVerifyCallback { @@ -358,9 +361,8 @@ // ("https://bobpay.com/personal", "https://alicepay.com/webpay") // // Manifests from all of these URLs will be downloaded for verification of app package - // names, versions, and signatures. - Set<GURL> urlMethodsForManifestDownload = - new HashSet<>(mMerchantRequestedUrlPaymentMethods); + // names, versions, signatures, and "supported_origins". + Set<GURL> urlMethodsForManifestDownload = new HashSet<>(); // A mapping from all known payment method names to the corresponding payment apps that // claim to support these payment methods. Example contents: @@ -433,8 +435,6 @@ methodToAppsMapping.get(defaultMethod).add(app); if (UrlUtil.isURLValid(defaultUrlMethod)) { - urlMethodsForManifestDownload.add(defaultUrlMethod); - if (!urlMethodToDefaultAppsMapping.containsKey(defaultUrlMethod)) { urlMethodToDefaultAppsMapping.put( defaultUrlMethod, new HashSet<ResolveInfo>()); @@ -468,6 +468,7 @@ String.join(", ", supportedMethods)); } + Set<GURL> supportedUrlMethods = new HashSet<>(); for (String supportedMethod : supportedMethods) { GURL supportedUrlMethod = new GURL(supportedMethod); if (!UrlUtil.isURLValid(supportedUrlMethod)) supportedUrlMethod = null; @@ -494,6 +495,8 @@ continue; } + supportedUrlMethods.add(supportedUrlMethod); + if (!mMethodToSupportedAppsMapping.containsKey(supportedUrlMethod)) { mMethodToSupportedAppsMapping.put( supportedUrlMethod, new HashSet<ResolveInfo>()); @@ -508,6 +511,12 @@ urlMethodToSupportedOriginsMapping.get(supportedUrlMethod).add(appOrigin); } + urlMethodsForManifestDownload.addAll( + PaymentManifestResolver.getManifestsToDownload( + defaultUrlMethod, + supportedUrlMethods, + mMerchantRequestedUrlPaymentMethods)); + // Record the total number of payment methods that this activity `ResolveInfo app` // declares to support in its metadata. if (!TextUtils.isEmpty(defaultMethod)) supportedMethods.add(defaultMethod);
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestResolver.java b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestResolver.java new file mode 100644 index 0000000..29b88af8 --- /dev/null +++ b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestResolver.java
@@ -0,0 +1,152 @@ +// 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. + +package org.chromium.components.payments; + +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; +import org.chromium.url.GURL; + +import java.util.HashSet; +import java.util.Set; + +/** + * Helper class for determining the set of URL payment methods whose manifests should be downloaded. + * + * <p>Websites specify the methods (URLs) they want to use in their Payment Request call. + * + * <p>Installed apps can declare both a 'default' method (URL) for their app, which acts a source of + * truth for its identity, as well as support for methods (URLs) from another origin. + * + * <p>For a given request and given app, there are then three possibilities - either the request is + * for the app itself directly (the default payment method), it is for a payment method that the app + * claims to support, or it has no overlap at all. + * + * <h2>Default payment methods</h2> + * + * <p>Use case: the merchant supports the app's default payment method. + * + * <p>Download: + * + * <ul> + * <li>The payment method and web app manifests for the app's default payment method. + * </ul> + * + * <p>Verify: + * + * <ul> + * <li>App identity (package name, version, signature). + * </ul> + * + * <p>Example: + * + * <pre> + * Merchant Website Alice Server + * Supported method: https://alice.example ---> https://alice.example/payment_manifest.json + * "default_applications" + * | + * v + * https://alice.example/web_manifest.json + * "related_applications" + * | | | + * v v v + * Alice App <----------Verify--------------- package name, version, signature + * Default method: https://alice.example + * </pre> + * + * <h2>Other payment methods</h2> + * + * <p>Use case: the merchant supports a payment method that is one of this app's other (non-default) + * payment methods. + * + * <p>Download: + * + * <ul> + * <li>The payment method and web app manifests for the app's default payment method. + * <li>The payment method manifests for the payment methods that both the merchant and the app + * support. + * </ul> + * + * <p>Verify: + * + * <ul> + * <li>App identity (package name, version, signature). + * <li>The {@code "supported_origins"} field is either {@code "*"} or a list of origins that + * includes the origin of the app's default payment method. + * </ul> + * + * <p>Example: + * + * <pre> + * Merchant Website Alice Server + * Supported method: https://alice.example ---> https://alice.example/method_manifest.json + * "supported_origins" + * | + * v + * Bob Server + * https://bob.example/web_manifest.json + * "related_applications" + * | | | + * v v v + * Bob App <------------Verify--------------- package name, version, signature + * Default method: https://bob.example + * Other method: https://alice.example + * </pre> + * + * <p>Learn more: + * + * <ul> + * <li><a href="https://web.dev/articles/android-payment-apps-developers-guide">Android payment + * apps</a>. + * <li><a href="https://web.dev/articles/setting-up-a-payment-method">Setting up a payment + * method</a>. + * <li><a href="https://w3c.github.io/payment-method-id/">Payment method identifier</a>. + * <li><a href="https://w3c.github.io/payment-method-manifest/">Payment method manifest</a>. + * </ul> + */ +@NullMarked +/* package */ class PaymentManifestResolver { + /** + * Determines the set of the URL payment methods whose manifests should be downloaded for + * verification of package name, version, signature, and "supported_origins" fields. + * + * @param appDefaultPaymentMethod The default payment method for the Android payment app. Leads + * to the web app manifest with {@code "related_applications"}, which contains this app's + * package name, version, and signature. + * @param appOtherPaymentMethods Other (non-default) payment methods of this Android payment + * app. Leads to the payment method manifest with {@code "supported_origins"}, which can be + * either {@code "*"} or a list of origins. + * @param merchantSupportedPaymentMethods The set of URI payment methods that the merchant has + * declared in the {@code "supportedMethods"} fields in the Payment Request JavaScript API + * call. + * @return The set of URI payment methods whose manifests should be downloaded for verification. + */ + /* package */ static Set<GURL> getManifestsToDownload( + @Nullable GURL appDefaultPaymentMethod, + Set<GURL> appOtherPaymentMethods, + Set<GURL> merchantSupportedPaymentMethods) { + // Find the intersection of all payment methods supported by the app, and the payment + // methods requested by the website. + Set<GURL> manifestsToDownload = new HashSet<>(appOtherPaymentMethods); + manifestsToDownload.add(appDefaultPaymentMethod); + manifestsToDownload.retainAll(merchantSupportedPaymentMethods); + manifestsToDownload.removeIf(url -> !UrlUtil.isURLValid(url)); + + if (manifestsToDownload.isEmpty()) { + return manifestsToDownload; + } + + // If the merchant requested an 'other' payment method and not the default payment method, + // then the default method will not be included in the intersection, but the default method + // still has to be downloaded to verify the app. + if (UrlUtil.isURLValid(appDefaultPaymentMethod)) { + manifestsToDownload.add(appDefaultPaymentMethod); + } + + return manifestsToDownload; + } + + // Do not instantiate. + private PaymentManifestResolver() {} +}
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/UrlUtil.java b/components/payments/content/android/java/src/org/chromium/components/payments/UrlUtil.java index 9a6a759..88d46b5a 100644 --- a/components/payments/content/android/java/src/org/chromium/components/payments/UrlUtil.java +++ b/components/payments/content/android/java/src/org/chromium/components/payments/UrlUtil.java
@@ -8,6 +8,7 @@ import org.jni_zero.NativeMethods; import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.url.GURL; @@ -21,7 +22,7 @@ * @param url The payment method name. * @return TRUE if given url is valid and not a relative URI. */ - public static boolean isURLValid(GURL url) { + public static boolean isURLValid(@Nullable GURL url) { return url != null && url.isValid() && !url.getScheme().isEmpty()
diff --git a/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentManifestResolverTest.java b/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentManifestResolverTest.java new file mode 100644 index 0000000..d4b6552 --- /dev/null +++ b/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentManifestResolverTest.java
@@ -0,0 +1,165 @@ +// 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. + +package org.chromium.components.payments; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.Feature; +import org.chromium.url.GURL; + +import java.util.HashSet; +import java.util.Set; + +/** Tests for determining the set of URL payment methods whose manifests should be downloaded. */ +@RunWith(BaseRobolectricTestRunner.class) +public class PaymentManifestResolverTest { + /** + * Download the manifest for an app's default payment method that is supported by the merchant. + */ + @Test + @Feature({"Payments"}) + public void testDownloadDefaultPaymentMethodSupportedByMerchant() throws Exception { + Set<GURL> actualManifestsToDownload = + PaymentManifestResolver.getManifestsToDownload( + /* appDefaultPaymentMethod= */ new GURL("https://alice.example"), + /* appOtherPaymentMethods= */ Set.of(), + /* merchantSupportedPaymentMethods= */ Set.of( + new GURL("https://alice.example"))); + + assertEquals(Set.of(new GURL("https://alice.example")), actualManifestsToDownload); + } + + /** + * Do not download the manifest for an app's default payment method that is not supported by the + * merchant. + */ + @Test + @Feature({"Payments"}) + public void testNoDownloadDefaultPaymentMethodNotSupportedByMerchant() throws Exception { + Set<GURL> actualManifestsToDownload = + PaymentManifestResolver.getManifestsToDownload( + /* appDefaultPaymentMethod= */ new GURL("https://bob.example"), + /* appOtherPaymentMethods= */ Set.of(), + /* merchantSupportedPaymentMethods= */ Set.of( + new GURL("https://alice.example"))); + + assertTrue(actualManifestsToDownload.isEmpty()); + } + + /** + * Download the manifests both for an app's default payment method (to verify package name, + * version, and signature) and an other (non-default) payment method, when the merchant supports + * only the other (non-default) payment method. + */ + @Test + @Feature({"Payments"}) + public void testDownloadDefaultAndOtherPaymentMethodWhenMerchantSupportsOnlyOther() + throws Exception { + Set<GURL> actualManifestsToDownload = + PaymentManifestResolver.getManifestsToDownload( + /* appDefaultPaymentMethod= */ new GURL("https://bob.example"), + /* appOtherPaymentMethods= */ Set.of( + new GURL("https://alice.example"), + new GURL("https://charlie.example")), + /* merchantSupportedPaymentMethods= */ Set.of( + new GURL("https://alice.example"), + new GURL("https://david.example"))); + + assertEquals( + Set.of(new GURL("https://alice.example"), new GURL("https://bob.example")), + actualManifestsToDownload); + } + + /** + * Do not download the manifest for an app's other (non-default) payment method that is not + * supported by the merchant. + */ + @Test + @Feature({"Payments"}) + public void testNoDownloadOtherPaymentMethodNotSupportedByMerchant() throws Exception { + Set<GURL> actualManifestsToDownload = + PaymentManifestResolver.getManifestsToDownload( + /* appDefaultPaymentMethod= */ new GURL("https://bob.example"), + /* appOtherPaymentMethods= */ Set.of( + new GURL("https://charlie.example"), + new GURL("https://david.example")), + /* merchantSupportedPaymentMethods= */ Set.of( + new GURL("https://alice.example"), + new GURL("https://evan.example"))); + + assertTrue(actualManifestsToDownload.isEmpty()); + } + + /** Do not download the manifest for a null default payment method. */ + @Test + @Feature({"Payments"}) + public void testNoDownloadNullDefaultPaymentMethod() throws Exception { + Set<GURL> merchantSupportedPaymentMethods = new HashSet<>(); + merchantSupportedPaymentMethods.add(new GURL("https://alice.example")); + merchantSupportedPaymentMethods.add(null); + + Set<GURL> actualManifestsToDownload = + PaymentManifestResolver.getManifestsToDownload( + /* appDefaultPaymentMethod= */ null, + /* appOtherPaymentMethods= */ Set.of(new GURL("https://charlie.example")), + merchantSupportedPaymentMethods); + + assertTrue(actualManifestsToDownload.isEmpty()); + } + + /** Do not download the manifest for a default payment method that is an invalid URL. */ + @Test + @Feature({"Payments"}) + public void testNoDownloadInvalidDefaultPaymentMethod() throws Exception { + Set<GURL> actualManifestsToDownload = + PaymentManifestResolver.getManifestsToDownload( + /* appDefaultPaymentMethod= */ new GURL("basic-card"), + /* appOtherPaymentMethods= */ Set.of(new GURL("https://charlie.example")), + /* merchantSupportedPaymentMethods= */ Set.of( + new GURL("https://alice.example"), new GURL("basic-card"))); + + assertTrue(actualManifestsToDownload.isEmpty()); + } + + /** Do not download the manifest for a null other (non-default) payment method. */ + @Test + @Feature({"Payments"}) + public void testNoDownloadNullOtherPaymentMethod() throws Exception { + Set<GURL> appOtherPaymentMethods = new HashSet<>(); + appOtherPaymentMethods.add(new GURL("https://david.example")); + appOtherPaymentMethods.add(null); + Set<GURL> merchantSupportedPaymentMethods = new HashSet<>(); + merchantSupportedPaymentMethods.add(new GURL("https://alice.example")); + merchantSupportedPaymentMethods.add(null); + + Set<GURL> actualManifestsToDownload = + PaymentManifestResolver.getManifestsToDownload( + /* appDefaultPaymentMethod= */ new GURL("https://bob.example"), + appOtherPaymentMethods, + merchantSupportedPaymentMethods); + + assertTrue(actualManifestsToDownload.isEmpty()); + } + + /** Do not download the manifest for an other (non-default) payment method that is invalid. */ + @Test + @Feature({"Payments"}) + public void testNoDownloadInvalidOtherPaymentMethod() throws Exception { + Set<GURL> actualManifestsToDownload = + PaymentManifestResolver.getManifestsToDownload( + /* appDefaultPaymentMethod= */ new GURL("https://bob.example"), + /* appOtherPaymentMethods= */ Set.of( + new GURL("basic-card"), new GURL("https://charlie.example")), + /* merchantSupportedPaymentMethods= */ Set.of( + new GURL("https://alice.example"), new GURL("basic-card"))); + + assertTrue(actualManifestsToDownload.isEmpty()); + } +}
diff --git a/components/performance_manager/decorators/site_data_node_data.cc b/components/performance_manager/decorators/site_data_node_data.cc index 9554f7ba..a80d33c 100644 --- a/components/performance_manager/decorators/site_data_node_data.cc +++ b/components/performance_manager/decorators/site_data_node_data.cc
@@ -168,13 +168,13 @@ return false; } CHECK(!loaded_idle_time_.is_null()); - return heuristics.IsOutsideLoadingGracePeriod( - page_node_, feature_type, - base::TimeTicks::Now() - loaded_idle_time_) && + const base::TimeTicks now = base::TimeTicks::Now(); + return heuristics.IsOutsideLoadingGracePeriod(page_node_, feature_type, + now - loaded_idle_time_) && heuristics.IsInBackground(page_node_) && heuristics.IsOutsideBackgroundingGracePeriod( page_node_, feature_type, - page_node_->GetTimeSinceLastVisibilityChange()); + now - page_node_->GetLastVisibilityChangeTime()); } void SiteDataNodeData::MaybeNotifyBackgroundFeatureUsage(
diff --git a/components/performance_manager/graph/page_node_impl.cc b/components/performance_manager/graph/page_node_impl.cc index ed5441f..7801cdd 100644 --- a/components/performance_manager/graph/page_node_impl.cc +++ b/components/performance_manager/graph/page_node_impl.cc
@@ -116,9 +116,9 @@ return is_visible_.value(); } -base::TimeDelta PageNodeImpl::GetTimeSinceLastVisibilityChange() const { +base::TimeTicks PageNodeImpl::GetLastVisibilityChangeTime() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return base::TimeTicks::Now() - visibility_change_time_; + return visibility_change_time_; } bool PageNodeImpl::IsAudible() const {
diff --git a/components/performance_manager/graph/page_node_impl.h b/components/performance_manager/graph/page_node_impl.h index 47387de..5db306b8 100644 --- a/components/performance_manager/graph/page_node_impl.h +++ b/components/performance_manager/graph/page_node_impl.h
@@ -86,7 +86,7 @@ PageType GetType() const override; bool IsFocused() const override; bool IsVisible() const override; - base::TimeDelta GetTimeSinceLastVisibilityChange() const override; + base::TimeTicks GetLastVisibilityChangeTime() const override; bool IsAudible() const override; std::optional<base::TimeDelta> GetTimeSinceLastAudibleChange() const override; bool HasPictureInPicture() const override;
diff --git a/components/performance_manager/graph/page_node_impl_unittest.cc b/components/performance_manager/graph/page_node_impl_unittest.cc index 5de4972f..3c8f4e9 100644 --- a/components/performance_manager/graph/page_node_impl_unittest.cc +++ b/components/performance_manager/graph/page_node_impl_unittest.cc
@@ -91,19 +91,19 @@ EXPECT_EQ(0u, GraphImplOperations::GetFrameNodes(page_node.get()).size()); } -TEST_F(PageNodeImplTest, GetTimeSinceLastVisibilityChange) { +TEST_F(PageNodeImplTest, GetLastVisibilityChangeTime) { MockSinglePageInSingleProcessGraph mock_graph(graph()); + base::TimeTicks t0 = base::TimeTicks::Now(); mock_graph.page->SetIsVisible(true); EXPECT_TRUE(mock_graph.page->IsVisible()); AdvanceClock(base::Seconds(42)); - EXPECT_EQ(base::Seconds(42), - mock_graph.page->GetTimeSinceLastVisibilityChange()); + EXPECT_EQ(t0, mock_graph.page->GetLastVisibilityChangeTime()); + base::TimeTicks t1 = base::TimeTicks::Now(); mock_graph.page->SetIsVisible(false); AdvanceClock(base::Seconds(23)); - EXPECT_EQ(base::Seconds(23), - mock_graph.page->GetTimeSinceLastVisibilityChange()); + EXPECT_EQ(t1, mock_graph.page->GetLastVisibilityChangeTime()); EXPECT_FALSE(mock_graph.page->IsVisible()); }
diff --git a/components/performance_manager/metrics/page_resource_monitor.cc b/components/performance_manager/metrics/page_resource_monitor.cc index 499768b..4b236f2 100644 --- a/components/performance_manager/metrics/page_resource_monitor.cc +++ b/components/performance_manager/metrics/page_resource_monitor.cc
@@ -47,17 +47,19 @@ PageMeasurementBackgroundState GetBackgroundStateForMeasurementPeriod( const PageNode* page_node, - base::TimeDelta time_since_last_measurement) { - if (page_node->GetTimeSinceLastVisibilityChange() < - time_since_last_measurement) { + base::TimeTicks now, + base::TimeTicks time_of_last_resource_usage) { + if (time_of_last_resource_usage < page_node->GetLastVisibilityChangeTime()) { return PageMeasurementBackgroundState::kMixedForegroundBackground; } if (page_node->IsVisible()) { return PageMeasurementBackgroundState::kForeground; } // Check if the page was audible for the entire measurement period. + const base::TimeDelta time_since_last_resource_usage = + now - time_of_last_resource_usage; if (page_node->GetTimeSinceLastAudibleChange().value_or( - base::TimeDelta::Max()) < time_since_last_measurement) { + base::TimeDelta::Max()) < time_since_last_resource_usage) { return PageMeasurementBackgroundState::kBackgroundMixedAudible; } if (page_node->IsAudible()) { @@ -167,7 +169,7 @@ auto ukm = ukm::builders::PerformanceManager_PageResourceUsage2(source_id); ukm.SetBackgroundState( static_cast<int64_t>(GetBackgroundStateForMeasurementPeriod( - page_node, now - time_of_last_resource_usage_))); + page_node, now, time_of_last_resource_usage_))); ukm.SetMeasurementAlgorithm( static_cast<int64_t>(PageMeasurementAlgorithm::kEvenSplitAndAggregate)); // Add CPU usage, if this page included it.
diff --git a/components/performance_manager/public/graph/page_node.h b/components/performance_manager/public/graph/page_node.h index dc3e686..a1d3450 100644 --- a/components/performance_manager/public/graph/page_node.h +++ b/components/performance_manager/public/graph/page_node.h
@@ -111,18 +111,18 @@ // See PageNodeObserver::OnIsVisibleChanged. virtual bool IsVisible() const = 0; - // Returns the time since the last visibility change. It is always well - // defined as the visibility property is set at node creation. - virtual base::TimeDelta GetTimeSinceLastVisibilityChange() const = 0; + // Returns the time of the last visibility change. It is always well defined + // as the visibility property is set at node creation. + virtual base::TimeTicks GetLastVisibilityChangeTime() const = 0; // Returns true if this page is currently audible, false otherwise. // See PageNodeObserver::OnIsAudibleChanged. virtual bool IsAudible() const = 0; // Returns the time since the last audible change. Unlike - // GetTimeSinceLastVisibilityChange(), this returns nullopt for a node which - // has never been audible. If a node is audible when created, it is considered - // to change from inaudible to audible at that point. + // GetLastVisibilityChangeTime(), this returns nullopt for a node which has + // never been audible. If a node is audible when created, it is considered to + // change from inaudible to audible at that point. virtual std::optional<base::TimeDelta> GetTimeSinceLastAudibleChange() const = 0; @@ -295,7 +295,7 @@ // Invoked when the IsVisible property changes. // - // GetTimeSinceLastVisibilityChange() will return the time since the previous + // GetLastVisibilityChangeTime() will return the time of the previous // IsVisible change. After all observers have fired it will return the time of // this property change. virtual void OnIsVisibleChanged(const PageNode* page_node) {}
diff --git a/components/performance_manager/scenario_api/BUILD.gn b/components/performance_manager/scenario_api/BUILD.gn index 97e71414..3d426c7 100644 --- a/components/performance_manager/scenario_api/BUILD.gn +++ b/components/performance_manager/scenario_api/BUILD.gn
@@ -18,6 +18,20 @@ public_deps = [ "//base" ] } +source_set("test_support") { + testonly = true + + sources = [ + "performance_scenario_test_support.cc", + "performance_scenario_test_support.h", + ] + + deps = [ + ":scenario_api", + "//testing/gtest", + ] +} + source_set("unit_tests") { testonly = true @@ -28,6 +42,7 @@ deps = [ ":scenario_api", + ":test_support", "//base/test:test_support", "//testing/gmock", "//testing/gtest",
diff --git a/components/performance_manager/scenario_api/performance_scenario_observer_unittest.cc b/components/performance_manager/scenario_api/performance_scenario_observer_unittest.cc index a8d1132f..e202d0f 100644 --- a/components/performance_manager/scenario_api/performance_scenario_observer_unittest.cc +++ b/components/performance_manager/scenario_api/performance_scenario_observer_unittest.cc
@@ -5,17 +5,16 @@ #include "components/performance_manager/scenario_api/performance_scenario_observer.h" #include <atomic> -#include <optional> +#include <memory> #include "base/barrier_closure.h" #include "base/containers/enum_set.h" #include "base/memory/read_only_shared_memory_region.h" -#include "base/memory/scoped_refptr.h" -#include "base/memory/structured_shared_memory.h" #include "base/scoped_multi_source_observation.h" #include "base/test/gmock_callback_support.h" #include "base/test/task_environment.h" #include "components/performance_manager/scenario_api/performance_scenario_memory.h" +#include "components/performance_manager/scenario_api/performance_scenario_test_support.h" #include "components/performance_manager/scenario_api/performance_scenarios.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -59,18 +58,12 @@ class PerformanceScenarioObserverTest : public ::testing::Test { public: void SetUp() override { - ASSERT_TRUE(process_shared_memory_.has_value()); - ASSERT_TRUE(global_shared_memory_.has_value()); + test_helper_ = PerformanceScenarioTestHelper::CreateWithoutMapping(); + ASSERT_TRUE(test_helper_); } protected: - // Writable shared memory regions for the scenario state. - std::optional<base::StructuredSharedMemory<ScenarioState>> - process_shared_memory_ = - base::StructuredSharedMemory<ScenarioState>::Create(); - std::optional<base::StructuredSharedMemory<ScenarioState>> - global_shared_memory_ = - base::StructuredSharedMemory<ScenarioState>::Create(); + std::unique_ptr<PerformanceScenarioTestHelper> test_helper_; base::test::TaskEnvironment task_env_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; @@ -84,8 +77,8 @@ { ScopedReadOnlyScenarioMemory scoped_process_memory( - ScenarioScope::kCurrentProcess, - process_shared_memory_->DuplicateReadOnlyRegion()); + ScenarioScope::kCurrentProcess, test_helper_->GetReadOnlyScenarioRegion( + ScenarioScope::kCurrentProcess)); EXPECT_TRUE(PerformanceScenarioObserverList::GetForScope( ScenarioScope::kCurrentProcess)); EXPECT_FALSE( @@ -94,7 +87,7 @@ { ScopedReadOnlyScenarioMemory scoped_global_memory( ScenarioScope::kGlobal, - global_shared_memory_->DuplicateReadOnlyRegion()); + test_helper_->GetReadOnlyScenarioRegion(ScenarioScope::kGlobal)); EXPECT_TRUE(PerformanceScenarioObserverList::GetForScope( ScenarioScope::kCurrentProcess)); EXPECT_TRUE( @@ -117,15 +110,16 @@ // Update the process scenario state before creating the ObserverList, to // make sure the state tracking doesn't depend on the state starting at // kNoPageLoading. - process_shared_memory_->WritableRef().loading.store( - LoadingScenario::kFocusedPageLoading, std::memory_order_relaxed); + test_helper_->SetLoadingScenario(ScenarioScope::kCurrentProcess, + LoadingScenario::kFocusedPageLoading); // Map in scenario memory. ScopedReadOnlyScenarioMemory scoped_process_memory( ScenarioScope::kCurrentProcess, - process_shared_memory_->DuplicateReadOnlyRegion()); + test_helper_->GetReadOnlyScenarioRegion(ScenarioScope::kCurrentProcess)); ScopedReadOnlyScenarioMemory scoped_global_memory( - ScenarioScope::kGlobal, global_shared_memory_->DuplicateReadOnlyRegion()); + ScenarioScope::kGlobal, + test_helper_->GetReadOnlyScenarioRegion(ScenarioScope::kGlobal)); EXPECT_FALSE(CurrentScenariosMatch(ScenarioScope::kCurrentProcess, kDefaultIdleScenarios)); @@ -159,12 +153,11 @@ input_only_observation.AddObservation(observer_list.get()); } - // Utility function that notifies observers of a change and waits for all mock - // expectations to be filled. The test should invoke `task_env_.QuitClosure()` - // when all expected observer methods are called. - auto notify_and_wait_for_expectations = [&] { + // Utility function that waits for all mock expectations to be filled. The + // test should invoke `task_env_.QuitClosure()` when all expected observer + // methods are called. + auto wait_for_expectations = [&] { using ::testing::Mock; - PerformanceScenarioObserverList::NotifyAllScopes(); task_env_.RunUntilQuit(); EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_observer)); EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_idle_observer)); @@ -197,11 +190,11 @@ OnScenarioMatchChanged(ScenarioScope::kGlobal, false)) .WillOnce(base::test::RunClosure(quit_closure)); - process_shared_memory_->WritableRef().loading.store( - LoadingScenario::kBackgroundPageLoading, std::memory_order_relaxed); - global_shared_memory_->WritableRef().loading.store( - LoadingScenario::kVisiblePageLoading, std::memory_order_relaxed); - notify_and_wait_for_expectations(); + test_helper_->SetLoadingScenario(ScenarioScope::kCurrentProcess, + LoadingScenario::kBackgroundPageLoading); + test_helper_->SetLoadingScenario(ScenarioScope::kGlobal, + LoadingScenario::kVisiblePageLoading); + wait_for_expectations(); // Toggle process scenario again without changing global scenario. // kBackgroundPageLoading (idle) -> kFocusedPageLoading (non-idle). @@ -215,9 +208,9 @@ OnScenarioMatchChanged(ScenarioScope::kCurrentProcess, false)) .WillOnce(base::test::RunClosure(quit_closure)); - process_shared_memory_->WritableRef().loading.store( - LoadingScenario::kFocusedPageLoading, std::memory_order_relaxed); - notify_and_wait_for_expectations(); + test_helper_->SetLoadingScenario(ScenarioScope::kCurrentProcess, + LoadingScenario::kFocusedPageLoading); + wait_for_expectations(); // Stop observing the process scenario, then toggle both scenarios again. // @@ -249,11 +242,11 @@ ScenarioScope::kCurrentProcess) .get()); - process_shared_memory_->WritableRef().loading.store( - LoadingScenario::kBackgroundPageLoading, std::memory_order_relaxed); - global_shared_memory_->WritableRef().loading.store( - LoadingScenario::kNoPageLoading, std::memory_order_relaxed); - notify_and_wait_for_expectations(); + test_helper_->SetLoadingScenario(ScenarioScope::kCurrentProcess, + LoadingScenario::kBackgroundPageLoading); + test_helper_->SetLoadingScenario(ScenarioScope::kGlobal, + LoadingScenario::kNoPageLoading); + wait_for_expectations(); // Update global scenario from kNoPageLoading to kBackgroundPageLoading. The // idle observer shouldn't be notified because the new scenario is still idle. @@ -263,9 +256,9 @@ LoadingScenario::kBackgroundPageLoading)) .WillOnce(base::test::RunClosure(task_env_.QuitClosure())); - global_shared_memory_->WritableRef().loading.store( - LoadingScenario::kBackgroundPageLoading, std::memory_order_relaxed); - notify_and_wait_for_expectations(); + test_helper_->SetLoadingScenario(ScenarioScope::kGlobal, + LoadingScenario::kBackgroundPageLoading); + wait_for_expectations(); // Update the global input scenario. All 3 observers will now be notified. quit_closure = base::BarrierClosure(3, task_env_.QuitClosure()); @@ -280,9 +273,9 @@ OnScenarioMatchChanged(ScenarioScope::kGlobal, false)) .WillOnce(base::test::RunClosure(quit_closure)); - global_shared_memory_->WritableRef().input.store(InputScenario::kTyping, - std::memory_order_relaxed); - notify_and_wait_for_expectations(); + test_helper_->SetInputScenario(ScenarioScope::kGlobal, + InputScenario::kTyping); + wait_for_expectations(); } } // namespace
diff --git a/components/performance_manager/scenario_api/performance_scenario_test_support.cc b/components/performance_manager/scenario_api/performance_scenario_test_support.cc new file mode 100644 index 0000000..bd7f5f3 --- /dev/null +++ b/components/performance_manager/scenario_api/performance_scenario_test_support.cc
@@ -0,0 +1,113 @@ +// 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/performance_manager/scenario_api/performance_scenario_test_support.h" + +#include <atomic> +#include <memory> +#include <optional> +#include <utility> + +#include "base/memory/ptr_util.h" +#include "base/memory/read_only_shared_memory_region.h" +#include "base/memory/structured_shared_memory.h" +#include "base/notreached.h" +#include "components/performance_manager/scenario_api/performance_scenario_memory.h" +#include "components/performance_manager/scenario_api/performance_scenario_observer.h" +#include "components/performance_manager/scenario_api/performance_scenarios.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace performance_scenarios { + +// static +std::unique_ptr<PerformanceScenarioTestHelper> +PerformanceScenarioTestHelper::Create() { + auto test_helper = CreateWithoutMapping(); + if (!test_helper) { + return nullptr; + } + auto global_region = + test_helper->GetReadOnlyScenarioRegion(ScenarioScope::kGlobal); + auto process_region = + test_helper->GetReadOnlyScenarioRegion(ScenarioScope::kCurrentProcess); + EXPECT_TRUE(global_region.IsValid()); + EXPECT_TRUE(process_region.IsValid()); + if (!global_region.IsValid() || !process_region.IsValid()) { + return nullptr; + } + test_helper->global_read_only_memory_.emplace(ScenarioScope::kGlobal, + std::move(global_region)); + test_helper->process_read_only_memory_.emplace(ScenarioScope::kCurrentProcess, + std::move(process_region)); + return test_helper; +} + +// static +std::unique_ptr<PerformanceScenarioTestHelper> +PerformanceScenarioTestHelper::CreateWithoutMapping() { + auto global_state = base::StructuredSharedMemory<ScenarioState>::Create(); + auto process_state = base::StructuredSharedMemory<ScenarioState>::Create(); + EXPECT_TRUE(global_state.has_value()); + EXPECT_TRUE(process_state.has_value()); + if (!global_state.has_value() || !process_state.has_value()) { + return nullptr; + } + return base::WrapUnique(new PerformanceScenarioTestHelper( + std::move(global_state.value()), std::move(process_state.value()))); +} + +PerformanceScenarioTestHelper::PerformanceScenarioTestHelper( + base::StructuredSharedMemory<ScenarioState> global_state, + base::StructuredSharedMemory<ScenarioState> process_state) + : global_state_(std::move(global_state)), + process_state_(std::move(process_state)) {} + +PerformanceScenarioTestHelper::~PerformanceScenarioTestHelper() = default; + +base::ReadOnlySharedMemoryRegion +PerformanceScenarioTestHelper::GetReadOnlyScenarioRegion( + ScenarioScope scope) const { + return ScenarioStateForScope(scope).DuplicateReadOnlyRegion(); +} + +void PerformanceScenarioTestHelper::SetLoadingScenario( + ScenarioScope scope, + LoadingScenario scenario) { + ScenarioStateForScope(scope).WritableRef().loading.store( + scenario, std::memory_order_relaxed); + if (auto observer_list = + PerformanceScenarioObserverList::GetForScope(scope)) { + observer_list->NotifyIfScenarioChanged(); + } +} + +void PerformanceScenarioTestHelper::SetInputScenario(ScenarioScope scope, + InputScenario scenario) { + ScenarioStateForScope(scope).WritableRef().input.store( + scenario, std::memory_order_relaxed); + if (auto observer_list = + PerformanceScenarioObserverList::GetForScope(scope)) { + observer_list->NotifyIfScenarioChanged(); + } +} + +base::StructuredSharedMemory<ScenarioState>& +PerformanceScenarioTestHelper::ScenarioStateForScope(ScenarioScope scope) { + switch (scope) { + case ScenarioScope::kGlobal: + return global_state_; + case ScenarioScope::kCurrentProcess: + return process_state_; + } + NOTREACHED(); +} + +const base::StructuredSharedMemory<ScenarioState>& +PerformanceScenarioTestHelper::ScenarioStateForScope( + ScenarioScope scope) const { + return const_cast<PerformanceScenarioTestHelper*>(this) + ->ScenarioStateForScope(scope); +} + +} // namespace performance_scenarios
diff --git a/components/performance_manager/scenario_api/performance_scenario_test_support.h b/components/performance_manager/scenario_api/performance_scenario_test_support.h new file mode 100644 index 0000000..6dd7e5f --- /dev/null +++ b/components/performance_manager/scenario_api/performance_scenario_test_support.h
@@ -0,0 +1,122 @@ +// 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_PERFORMANCE_MANAGER_SCENARIO_API_PERFORMANCE_SCENARIO_TEST_SUPPORT_H_ +#define COMPONENTS_PERFORMANCE_MANAGER_SCENARIO_API_PERFORMANCE_SCENARIO_TEST_SUPPORT_H_ + +#include <memory> +#include <optional> + +#include "base/memory/read_only_shared_memory_region.h" +#include "base/memory/structured_shared_memory.h" +#include "components/performance_manager/scenario_api/performance_scenario_memory.h" +#include "components/performance_manager/scenario_api/performance_scenarios.h" + +namespace performance_scenarios { + +// Helper to create and access performance scenario state from unit tests. +// In production the writable state is created automatically in the browser +// process, and read-only state is created automatically in child processes when +// they're launched. +// +// Usage: +// +// TEST(SomeTestSuite, TestWithNoScenarios) { +// // Observers not available. +// EXPECT_FALSE(PerformanceScenarioObserverList::GetForScope( +// ScenarioScope::kGlobal)); +// // Scenarios all return default values. +// EXPECT_EQ(GetInputScenario(ScenarioScope::kGlobal).load( +// std::memory_order_relaxed), InputScenario::kNoInput); +// } +// +// TEST(SomeTestSuite, TestWithScenarios) { +// auto test_helper = PerformanceScenarioTestHelper::Create(); +// ASSERT_TRUE(test_helper); +// +// // Observers are available. +// EXPECT_TRUE(PerformanceScenarioObserverList::GetForScope( +// ScenarioScope::kGlobal)); +// +// // Scenarios can be updated. +// test_helper->SetInputScenario(ScenarioScope::kGlobal, +// InputScenario::kTyping); +// EXPECT_EQ(GetInputScenario(ScenarioScope::kGlobal, InputScenario::kTyping); +// } +// +// TEST(SomeTestSuite, TestWithManualMapping) { +// auto test_helper = PerformanceScenarioTestHelper::CreateWithoutMapping(); +// ASSERT_TRUE(test_helper); +// test_helper->SetInputScenario(ScenarioScope::kGlobal, +// InputScenario::kTyping); +// +// // Observers aren't available until read-only memory is mapped. +// EXPECT_FALSE(PerformanceScenarioObserverList::GetForScope( +// ScenarioScope::kGlobal)); +// +// // Scenarios all return default values until read-only memory is mapped. +// EXPECT_EQ(GetInputScenario(ScenarioScope::kGlobal).load( +// std::memory_order_relaxed), InputScenario::kNoInput); +// +// ScopedReadOnlyScenarioMemory global_memory(ScenarioScope::kGlobal, +// test_helper->GetReadOnlyScenarioRegion(ScenarioScope::kGlobal)); +// +// EXPECT_TRUE(PerformanceScenarioObserverList::GetForScope( +// ScenarioScope::kGlobal)); +// EXPECT_EQ(GetInputScenario(ScenarioScope::kGlobal).load( +// std::memory_order_relaxed), InputScenario::kTyping); +// } +class PerformanceScenarioTestHelper { + public: + // Creates a PerformanceScenarioTestHelper holding writable performance + // scenario memory, along with read-only memory for all ScenarioScopes. + // Returns null if the shared memory couldn't be created or mapped. + static std::unique_ptr<PerformanceScenarioTestHelper> Create(); + + // Creates a PerformanceScenarioTestHelper holding writable performance + // scenario memory, but doesn't map any read-only memory. Tests can map + // read-only memory by passing the result of GetReadOnlyScenarioRegion() to a + // ScopedReadOnlyScenarioMemory object. Returns null if the shared memory + // couldn't be created. + static std::unique_ptr<PerformanceScenarioTestHelper> CreateWithoutMapping(); + + ~PerformanceScenarioTestHelper(); + + PerformanceScenarioTestHelper(const PerformanceScenarioTestHelper&) = delete; + PerformanceScenarioTestHelper& operator=( + const PerformanceScenarioTestHelper&) = delete; + + // Returns a read-only memory handle for the given `scope`, for tests that + // create ScopedReadOnlyScenarioMemory manually. + base::ReadOnlySharedMemoryRegion GetReadOnlyScenarioRegion( + ScenarioScope scope) const; + + // Updates the LoadingScenario for the given `scope`, and notifies all + // observers. + void SetLoadingScenario(ScenarioScope scope, LoadingScenario scenario); + + // Updates the InputScenario for the given `scope`, and notifies all + // observers. + void SetInputScenario(ScenarioScope scope, InputScenario scenario); + + private: + PerformanceScenarioTestHelper( + base::StructuredSharedMemory<ScenarioState> global_state, + base::StructuredSharedMemory<ScenarioState> process_state); + + base::StructuredSharedMemory<ScenarioState>& ScenarioStateForScope( + ScenarioScope scope); + const base::StructuredSharedMemory<ScenarioState>& ScenarioStateForScope( + ScenarioScope scope) const; + + base::StructuredSharedMemory<ScenarioState> global_state_; + base::StructuredSharedMemory<ScenarioState> process_state_; + + std::optional<ScopedReadOnlyScenarioMemory> global_read_only_memory_; + std::optional<ScopedReadOnlyScenarioMemory> process_read_only_memory_; +}; + +} // namespace performance_scenarios + +#endif // COMPONENTS_PERFORMANCE_MANAGER_SCENARIO_API_PERFORMANCE_SCENARIO_TEST_SUPPORT_H_
diff --git a/components/performance_manager/scenario_api/performance_scenarios_unittest.cc b/components/performance_manager/scenario_api/performance_scenarios_unittest.cc index 33cfbcd..60d9464 100644 --- a/components/performance_manager/scenario_api/performance_scenarios_unittest.cc +++ b/components/performance_manager/scenario_api/performance_scenarios_unittest.cc
@@ -13,6 +13,7 @@ #include "base/memory/scoped_refptr.h" #include "base/memory/structured_shared_memory.h" #include "components/performance_manager/scenario_api/performance_scenario_memory.h" +#include "components/performance_manager/scenario_api/performance_scenario_test_support.h" #include "testing/gtest/include/gtest/gtest.h" namespace performance_scenarios { @@ -60,8 +61,8 @@ ::testing::ValuesIn(InputScenarios::All())); TEST(PerformanceScenariosTest, MappedScenarioState) { - auto shared_memory = base::StructuredSharedMemory<ScenarioState>::Create(); - ASSERT_TRUE(shared_memory.has_value()); + auto test_helper = PerformanceScenarioTestHelper::CreateWithoutMapping(); + ASSERT_TRUE(test_helper); // Before the shared memory is mapped in, GetLoadingScenario should return // default values. @@ -75,14 +76,15 @@ { // Map the shared memory as the global state. ScopedReadOnlyScenarioMemory mapped_global_memory( - ScenarioScope::kGlobal, shared_memory->DuplicateReadOnlyRegion()); + ScenarioScope::kGlobal, + test_helper->GetReadOnlyScenarioRegion(ScenarioScope::kGlobal)); EXPECT_EQ(GetLoadingScenario(ScenarioScope::kGlobal) ->load(std::memory_order_relaxed), LoadingScenario::kNoPageLoading); // Updates should be visible in the global state only. - shared_memory->WritableRef().loading.store( - LoadingScenario::kFocusedPageLoading, std::memory_order_relaxed); + test_helper->SetLoadingScenario(ScenarioScope::kGlobal, + LoadingScenario::kFocusedPageLoading); EXPECT_EQ(GetLoadingScenario(ScenarioScope::kGlobal) ->load(std::memory_order_relaxed), LoadingScenario::kFocusedPageLoading); @@ -93,14 +95,14 @@ // Map the same shared memory as the per-process state. ScopedReadOnlyScenarioMemory mapped_current_memory( ScenarioScope::kCurrentProcess, - shared_memory->DuplicateReadOnlyRegion()); + test_helper->GetReadOnlyScenarioRegion(ScenarioScope::kGlobal)); EXPECT_EQ(GetLoadingScenario(ScenarioScope::kCurrentProcess) ->load(std::memory_order_relaxed), LoadingScenario::kFocusedPageLoading); // Updates should be visible in both mappings. - shared_memory->WritableRef().loading.store( - LoadingScenario::kVisiblePageLoading, std::memory_order_relaxed); + test_helper->SetLoadingScenario(ScenarioScope::kGlobal, + LoadingScenario::kVisiblePageLoading); EXPECT_EQ(GetLoadingScenario(ScenarioScope::kGlobal) ->load(std::memory_order_relaxed), LoadingScenario::kVisiblePageLoading); @@ -121,11 +123,11 @@ TEST(PerformanceScenariosTest, SharedAtomicRef) { // Create and map shared memory. - auto shared_memory = base::StructuredSharedMemory<ScenarioState>::Create(); - ASSERT_TRUE(shared_memory.has_value()); + auto test_helper = PerformanceScenarioTestHelper::CreateWithoutMapping(); + ASSERT_TRUE(test_helper); auto read_only_mapping = base::StructuredSharedMemory<ScenarioState>::MapReadOnlyRegion( - shared_memory->DuplicateReadOnlyRegion()); + test_helper->GetReadOnlyScenarioRegion(ScenarioScope::kGlobal)); ASSERT_TRUE(read_only_mapping.has_value()); // Store pointers to the atomics in the shared memory for later comparison. @@ -145,10 +147,9 @@ // The SharedAtomicRef's should keep the mapping alive. mapping_ptr.reset(); - shared_memory->WritableRef().loading.store( - LoadingScenario::kBackgroundPageLoading, std::memory_order_relaxed); - shared_memory->WritableRef().input.store(InputScenario::kNoInput, - std::memory_order_relaxed); + test_helper->SetLoadingScenario(ScenarioScope::kGlobal, + LoadingScenario::kBackgroundPageLoading); + test_helper->SetInputScenario(ScenarioScope::kGlobal, InputScenario::kTyping); // get() EXPECT_EQ(loading_ref.get(), loading_ptr); @@ -161,8 +162,7 @@ // operator-> EXPECT_EQ(loading_ref->load(std::memory_order_relaxed), LoadingScenario::kBackgroundPageLoading); - EXPECT_EQ(input_ref->load(std::memory_order_relaxed), - InputScenario::kNoInput); + EXPECT_EQ(input_ref->load(std::memory_order_relaxed), InputScenario::kTyping); } TEST_P(PerformanceScenariosAllLoadingScenariosTest, EmptyScenarioPattern) {
diff --git a/components/permissions/permission_actions_history.h b/components/permissions/permission_actions_history.h index 0b3a151..e8d5e61 100644 --- a/components/permissions/permission_actions_history.h +++ b/components/permissions/permission_actions_history.h
@@ -32,11 +32,7 @@ PermissionAction action; base::Time time; - bool operator==(const Entry that) const { - return std::tie(this->action, this->time) == - std::tie(that.action, that.time); - } - bool operator!=(const Entry that) const { return !(*this == that); } + friend bool operator==(const Entry&, const Entry&) = default; }; enum class EntryFilter {
diff --git a/components/permissions/permission_request_id.cc b/components/permissions/permission_request_id.cc index e92a1b3..1e8654f 100644 --- a/components/permissions/permission_request_id.cc +++ b/components/permissions/permission_request_id.cc
@@ -29,15 +29,6 @@ PermissionRequestID& PermissionRequestID::operator=( const PermissionRequestID&) = default; -bool PermissionRequestID::operator==(const PermissionRequestID& other) const { - return global_render_frame_host_id_ == other.global_render_frame_host_id_ && - request_local_id_ == other.request_local_id_; -} - -bool PermissionRequestID::operator!=(const PermissionRequestID& other) const { - return !operator==(other); -} - std::string PermissionRequestID::ToString() const { return base::StringPrintf( "%d,%d,%" PRId64, global_render_frame_host_id_.child_id,
diff --git a/components/permissions/permission_request_id.h b/components/permissions/permission_request_id.h index 661bd4d1..3c071ba 100644 --- a/components/permissions/permission_request_id.h +++ b/components/permissions/permission_request_id.h
@@ -50,8 +50,8 @@ return request_local_id_; } - bool operator==(const PermissionRequestID& other) const; - bool operator!=(const PermissionRequestID& other) const; + friend bool operator==(const PermissionRequestID&, + const PermissionRequestID&) = default; std::string ToString() const;
diff --git a/components/permissions/permission_usage_session.cc b/components/permissions/permission_usage_session.cc index bea926ce..4a45ac5 100644 --- a/components/permissions/permission_usage_session.cc +++ b/components/permissions/permission_usage_session.cc
@@ -8,20 +8,6 @@ namespace permissions { -bool PermissionUsageSession::operator==( - const PermissionUsageSession& other) const { - return std::tie(origin, type, usage_start, usage_end, had_user_activation, - was_foreground, had_focus) == - std::tie(other.origin, other.type, other.usage_start, other.usage_end, - other.had_user_activation, other.was_foreground, - other.had_focus); -} - -bool PermissionUsageSession::operator!=( - const PermissionUsageSession& other) const { - return !(*this == other); -} - bool PermissionUsageSession::IsValid() const { return !(origin.opaque() || usage_start.is_null() || usage_end.is_null() || usage_end < usage_start);
diff --git a/components/permissions/permission_usage_session.h b/components/permissions/permission_usage_session.h index 7d3a0f5..d4566db 100644 --- a/components/permissions/permission_usage_session.h +++ b/components/permissions/permission_usage_session.h
@@ -38,8 +38,8 @@ // usage started. bool had_focus; - bool operator==(const PermissionUsageSession& other) const; - bool operator!=(const PermissionUsageSession& other) const; + friend bool operator==(const PermissionUsageSession&, + const PermissionUsageSession&) = default; // Checks if the session satisfies the following constraints: // 1) `origin` is not opaque;
diff --git a/components/permissions/prediction_service/prediction_common.h b/components/permissions/prediction_service/prediction_common.h index 3990fad..418e74e 100644 --- a/components/permissions/prediction_service/prediction_common.h +++ b/components/permissions/prediction_service/prediction_common.h
@@ -21,10 +21,6 @@ constexpr int kCountBuckets[] = {20, 15, 12, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; -// Thresholds of the likelihood that triggers the CPSS prompts. -constexpr float kNotificationPredictionsThreshold = 0.81; -constexpr float kGeolocationPredictionsThreshold = 0.95; - // Returns the ratio rounded to the nearest 10%. It returns a value between 0 // and 1 in steps of 0.1 float GetRoundedRatio(int numerator, int denominator);
diff --git a/components/permissions/prediction_service/prediction_model_executor.cc b/components/permissions/prediction_service/prediction_model_executor.cc index 9f73604..36740808 100644 --- a/components/permissions/prediction_service/prediction_model_executor.cc +++ b/components/permissions/prediction_service/prediction_model_executor.cc
@@ -137,29 +137,21 @@ const std::vector<const TfLiteTensor*>& output_tensors) { DCHECK(request_type_ == RequestType::kNotifications || request_type_ == RequestType::kGeolocation); + + if (!model_metadata_ || !model_metadata_->has_not_grant_thresholds()) { + LOG(WARNING) + << "[CPSS] Failed to read model thresholds from metadata"; + return std::nullopt; + } + std::vector<float> data; if (!tflite::task::core::PopulateVector<float>(output_tensors[0], &data) .ok()) { return std::nullopt; } - float threshold = request_type_ == RequestType::kNotifications - ? kNotificationPredictionsThreshold - : kGeolocationPredictionsThreshold; - - // If the model has a metadata which contains a threshold value, - // use that threshold value. - if (model_metadata_ && model_metadata_->has_not_grant_thresholds()) { - // max_likely represents very likely to not grant - threshold = model_metadata_->not_grant_thresholds().max_likely(); - base::UmaHistogramEnumeration( - "Permissions.PredictionService.PredictionThresholdSource", - PermissionPredictionThresholdSource::MODEL_METADATA); - } else { - base::UmaHistogramEnumeration( - "Permissions.PredictionService.PredictionThresholdSource", - PermissionPredictionThresholdSource::HARDCODED_FALLBACK); - } + // max_likely represents very likely to not grant + float threshold = model_metadata_->not_grant_thresholds().max_likely(); GeneratePredictionsResponse response; response.mutable_prediction()
diff --git a/components/permissions/prediction_service/prediction_signature_model_executor.cc b/components/permissions/prediction_service/prediction_signature_model_executor.cc index cd511eb6..cda2b5dc6 100644 --- a/components/permissions/prediction_service/prediction_signature_model_executor.cc +++ b/components/permissions/prediction_service/prediction_signature_model_executor.cc
@@ -214,6 +214,13 @@ const std::map<std::string, const TfLiteTensor*>& output_tensors) { DCHECK(request_type_ == RequestType::kNotifications || request_type_ == RequestType::kGeolocation); + + if (!model_metadata_ || !model_metadata_->has_not_grant_thresholds()) { + LOG(WARNING) + << "[CPSS] Failed to read signature model thresholds from metadata"; + return std::nullopt; + } + auto itr = output_tensors.find("outputs"); if (itr == output_tensors.end()) { LOG(WARNING) << "[CPSS] Failed to find outputs tensor"; @@ -225,23 +232,9 @@ return std::nullopt; } - float threshold = request_type_ == RequestType::kNotifications - ? kNotificationPredictionsThreshold - : kGeolocationPredictionsThreshold; + // max_likely represents very likely to not grant + float threshold = model_metadata_->not_grant_thresholds().max_likely(); - // If the model has a metadata which contains a threshold value, - // use that threshold value. - if (model_metadata_ && model_metadata_->has_not_grant_thresholds()) { - // max_likely represents very likely to not grant - threshold = model_metadata_->not_grant_thresholds().max_likely(); - base::UmaHistogramEnumeration( - "Permissions.PredictionService.PredictionThresholdSource", - PermissionPredictionThresholdSource::MODEL_METADATA); - } else { - base::UmaHistogramEnumeration( - "Permissions.PredictionService.PredictionThresholdSource", - PermissionPredictionThresholdSource::HARDCODED_FALLBACK); - } GeneratePredictionsResponse response; response.mutable_prediction() ->Add()
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto index 9c67657..70c43a0 100644 --- a/components/policy/proto/device_management_backend.proto +++ b/components/policy/proto/device_management_backend.proto
@@ -2358,6 +2358,13 @@ // A boolean indicating whether the Site Isolation (a.k.a Site Per Process) // setting is enabled. optional bool site_isolation_enabled = 7; + + // Providers for various analysis connectors. + repeated string file_downloaded_providers = 8; + repeated string file_attached_providers = 9; + repeated string bulk_data_entry_providers = 10; + repeated string print_providers = 11; + repeated string security_event_providers = 12; } // Anti virus product information.
diff --git a/components/policy/resources/templates/policy_definitions/Arc/ArcEnabled.yaml b/components/policy/resources/templates/policy_definitions/Arc/ArcEnabled.yaml index d329122..e932142 100644 --- a/components/policy/resources/templates/policy_definitions/Arc/ArcEnabled.yaml +++ b/components/policy/resources/templates/policy_definitions/Arc/ArcEnabled.yaml
@@ -4,8 +4,6 @@ desc: Unless Ephemeral mode or multiple sign-in is on during the user's session, setting ArcEnabled to True turns ARC on for the user. Setting the policy to False or leaving it unset means enterprise users can't use ARC. - - This policy only controls <ph name="ARC_VM">ArcVM</ph> on <ph name="PRODUCT_NAME">$2<ex>Google ChromeOS</ex></ph>. For <ph name="PRODUCT_OS_FLEX_NAME">Google ChromeOS Flex</ph>, please see the <ph name="DEVICE_FLEX_ARC_PRELOAD_ENABLED_POLICY_NAME">DeviceFlexArcPreloadEnabled</ph> policy for more details. example_value: false features: dynamic_refresh: true
diff --git a/components/safe_browsing/core/common/proto/BUILD.gn b/components/safe_browsing/core/common/proto/BUILD.gn index f73e0ee8..73a4a84 100644 --- a/components/safe_browsing/core/common/proto/BUILD.gn +++ b/components/safe_browsing/core/common/proto/BUILD.gn
@@ -24,6 +24,7 @@ proto_to_value("csd_proto_to_value") { sources = [ "csd.proto" ] + deps = [ ":csd_proto" ] } proto_library("webui_proto") { @@ -44,6 +45,7 @@ deps = [ ":csd_proto", ":csd_proto_to_value", + ":realtimeapi_proto", "//components/enterprise/common/proto:connectors_proto", "//components/enterprise/common/proto:connectors_proto_to_value", ] @@ -61,4 +63,5 @@ proto_to_value("safebrowsingv5_proto_to_value") { sources = [ "safebrowsingv5.proto" ] + deps = [ ":safebrowsingv5_proto" ] }
diff --git a/components/safe_browsing/core/common/proto_to_value/proto_to_value.gni b/components/safe_browsing/core/common/proto_to_value/proto_to_value.gni index 47b6c44..1beb010 100644 --- a/components/safe_browsing/core/common/proto_to_value/proto_to_value.gni +++ b/components/safe_browsing/core/common/proto_to_value/proto_to_value.gni
@@ -3,13 +3,18 @@ # found in the LICENSE file. # Generate serializers that turn a protobuf into a base::Value. This -# does not directly generate the protobuf bindings for any language. +# does not directly generate the protobuf bindings for any language, so +# callers must include the build target for C++ bindings in the deps. # # Example: # proto_to_value("mylib_to_value") { # sources = [ # "mylib.proto", # ] +# +# deps = [ +# "mylib_proto_target" +# ] # } import("//third_party/protobuf/proto_library.gni")
diff --git a/components/safe_browsing/core/common/proto_to_value/test_proto/BUILD.gn b/components/safe_browsing/core/common/proto_to_value/test_proto/BUILD.gn index 359afaa74..646606f 100644 --- a/components/safe_browsing/core/common/proto_to_value/test_proto/BUILD.gn +++ b/components/safe_browsing/core/common/proto_to_value/test_proto/BUILD.gn
@@ -19,4 +19,6 @@ "test_proto.proto", "test_proto_dependency.proto", ] + + deps = [ ":test_proto" ] }
diff --git a/components/saved_tab_groups/public/android/java/src/org/chromium/components/tab_group_sync/EitherId.java b/components/saved_tab_groups/public/android/java/src/org/chromium/components/tab_group_sync/EitherId.java index 1b47b9b..482a76d 100644 --- a/components/saved_tab_groups/public/android/java/src/org/chromium/components/tab_group_sync/EitherId.java +++ b/components/saved_tab_groups/public/android/java/src/org/chromium/components/tab_group_sync/EitherId.java
@@ -67,14 +67,29 @@ return new EitherGroupId(null, syncId); } + @EnsuresNonNullIf("mLocalId") public boolean isLocalId() { return mLocalId != null; } - public @Nullable LocalTabGroupId getLocalId() { + public LocalTabGroupId getLocalId() { assert isLocalId(); return mLocalId; } + + @Override + public boolean equals(Object o) { + if (!(o instanceof EitherGroupId)) return false; + EitherGroupId eitherId = (EitherGroupId) o; + + boolean localIdEqual = + isLocalId() + && eitherId.isLocalId() + && getLocalId().equals(eitherId.getLocalId()); + boolean syncIdEqual = + isSyncId() && eitherId.isSyncId() && getSyncId().equals(eitherId.getSyncId()); + return localIdEqual || syncIdEqual; + } } private final @Nullable String mSyncId;
diff --git a/components/saved_tab_groups/public/android/tab_group_sync_conversions_utils.cc b/components/saved_tab_groups/public/android/tab_group_sync_conversions_utils.cc index a983e14..34ca8762 100644 --- a/components/saved_tab_groups/public/android/tab_group_sync_conversions_utils.cc +++ b/components/saved_tab_groups/public/android/tab_group_sync_conversions_utils.cc
@@ -10,6 +10,7 @@ #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" #include "base/uuid.h" +#include "components/saved_tab_groups/public/android/tab_group_sync_conversions_bridge.h" #include "components/saved_tab_groups/public/types.h" using base::android::ConvertJavaStringToUTF8; @@ -42,4 +43,20 @@ return base::Uuid::ParseLowercase(ConvertJavaStringToUTF8(env, j_uuid)); } +EitherGroupID JavaSyncOrLocalGroupIdToEitherGroupId( + JNIEnv* env, + const JavaParamRef<jstring>& j_sync_group_id, + const JavaParamRef<jobject>& j_local_group_id) { + if (j_local_group_id.is_null()) { + std::string sync_group_id_str = + ConvertJavaStringToUTF8(env, j_sync_group_id); + return base::Uuid::ParseLowercase(sync_group_id_str); + } else { + LocalTabGroupID local_group_id = + TabGroupSyncConversionsBridge::FromJavaTabGroupId(env, + j_local_group_id); + return local_group_id; + } +} + } // namespace tab_groups
diff --git a/components/saved_tab_groups/public/android/tab_group_sync_conversions_utils.h b/components/saved_tab_groups/public/android/tab_group_sync_conversions_utils.h index 7efa39d..8c9a1fa 100644 --- a/components/saved_tab_groups/public/android/tab_group_sync_conversions_utils.h +++ b/components/saved_tab_groups/public/android/tab_group_sync_conversions_utils.h
@@ -31,6 +31,12 @@ // Converts a Java string to base::Uuid. base::Uuid JavaStringToUuid(JNIEnv* env, const JavaParamRef<jstring>& j_uuid); +// Converts a Java sync or local group ID to EitherGroupID. +EitherGroupID JavaSyncOrLocalGroupIdToEitherGroupId( + JNIEnv* env, + const JavaParamRef<jstring>& j_sync_group_id, + const JavaParamRef<jobject>& j_local_group_id); + } // namespace tab_groups #endif // COMPONENTS_SAVED_TAB_GROUPS_PUBLIC_ANDROID_TAB_GROUP_SYNC_CONVERSIONS_UTILS_H_
diff --git a/components/tabs/BUILD.gn b/components/tabs/BUILD.gn index 36ac7829..505e08b 100644 --- a/components/tabs/BUILD.gn +++ b/components/tabs/BUILD.gn
@@ -5,7 +5,10 @@ source_set("public") { sources = [ "public/pinned_tab_collection.h", + "public/split_tab_collection.h", + "public/split_tab_data.h", "public/split_tab_id.h", + "public/split_tab_visual_data.h", "public/supports_handles.h", "public/tab_collection.h", "public/tab_collection_node_interface.h", @@ -25,6 +28,9 @@ source_set("tabs") { sources = [ "pinned_tab_collection.cc", + "split_tab_collection.cc", + "split_tab_data.cc", + "split_tab_visual_data.cc", "tab_collection.cc", "tab_collection_storage.cc", ]
diff --git a/chrome/browser/ui/tabs/split_tab_collection.h b/components/tabs/public/split_tab_collection.h similarity index 83% rename from chrome/browser/ui/tabs/split_tab_collection.h rename to components/tabs/public/split_tab_collection.h index 2663bd1..107fe31 100644 --- a/chrome/browser/ui/tabs/split_tab_collection.h +++ b/components/tabs/public/split_tab_collection.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 CHROME_BROWSER_UI_TABS_SPLIT_TAB_COLLECTION_H_ -#define CHROME_BROWSER_UI_TABS_SPLIT_TAB_COLLECTION_H_ +#ifndef COMPONENTS_TABS_PUBLIC_SPLIT_TAB_COLLECTION_H_ +#define COMPONENTS_TABS_PUBLIC_SPLIT_TAB_COLLECTION_H_ #include "components/tabs/public/split_tab_id.h" #include "components/tabs/public/tab_collection.h" @@ -11,7 +11,7 @@ namespace split_tabs { class SplitTabData; class SplitTabVisualData; -} +} // namespace split_tabs namespace tabs { @@ -35,4 +35,4 @@ } // namespace tabs -#endif // CHROME_BROWSER_UI_TABS_SPLIT_TAB_COLLECTION_H_ +#endif // COMPONENTS_TABS_PUBLIC_SPLIT_TAB_COLLECTION_H_
diff --git a/chrome/browser/ui/tabs/split_tab_data.h b/components/tabs/public/split_tab_data.h similarity index 77% rename from chrome/browser/ui/tabs/split_tab_data.h rename to components/tabs/public/split_tab_data.h index 170fa5b6..2b5493d 100644 --- a/chrome/browser/ui/tabs/split_tab_data.h +++ b/components/tabs/public/split_tab_data.h
@@ -2,12 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_TABS_SPLIT_TAB_DATA_H_ -#define CHROME_BROWSER_UI_TABS_SPLIT_TAB_DATA_H_ +#ifndef COMPONENTS_TABS_PUBLIC_SPLIT_TAB_DATA_H_ +#define COMPONENTS_TABS_PUBLIC_SPLIT_TAB_DATA_H_ -#include "chrome/browser/ui/tabs/split_tab_collection.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" +#include <vector> + +#include "components/tabs/public/split_tab_collection.h" #include "components/tabs/public/split_tab_id.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_interface.h" namespace split_tabs { @@ -34,4 +36,4 @@ } // namespace split_tabs -#endif // CHROME_BROWSER_UI_TABS_SPLIT_TAB_DATA_H_ +#endif // COMPONENTS_TABS_PUBLIC_SPLIT_TAB_DATA_H_
diff --git a/chrome/browser/ui/tabs/split_tab_visual_data.h b/components/tabs/public/split_tab_visual_data.h similarity index 89% rename from chrome/browser/ui/tabs/split_tab_visual_data.h rename to components/tabs/public/split_tab_visual_data.h index 10213a90..1511364 100644 --- a/chrome/browser/ui/tabs/split_tab_visual_data.h +++ b/components/tabs/public/split_tab_visual_data.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 CHROME_BROWSER_UI_TABS_SPLIT_TAB_VISUAL_DATA_H_ -#define CHROME_BROWSER_UI_TABS_SPLIT_TAB_VISUAL_DATA_H_ +#ifndef COMPONENTS_TABS_PUBLIC_SPLIT_TAB_VISUAL_DATA_H_ +#define COMPONENTS_TABS_PUBLIC_SPLIT_TAB_VISUAL_DATA_H_ namespace split_tabs { @@ -52,4 +52,4 @@ } // namespace split_tabs -#endif // CHROME_BROWSER_UI_TABS_SPLIT_TAB_VISUAL_DATA_H_ +#endif // COMPONENTS_TABS_PUBLIC_SPLIT_TAB_VISUAL_DATA_H_
diff --git a/components/tabs/public/tab_collection.h b/components/tabs/public/tab_collection.h index a3fc068..126924a 100644 --- a/components/tabs/public/tab_collection.h +++ b/components/tabs/public/tab_collection.h
@@ -39,7 +39,7 @@ public: using iterator_category = std::forward_iterator_tag; - using value_type = const tabs::TabInterface*; + using value_type = tabs::TabInterface*; using difference_type = ptrdiff_t; using pointer = value_type; using reference = value_type; @@ -80,7 +80,7 @@ }; // Points to the currently accessed tab during iteration. - raw_ptr<const tabs::TabInterface> cur_; + raw_ptr<tabs::TabInterface> cur_; // Points to the root tab collection that the iterator is traversing. raw_ptr<const tabs::TabCollection> root_; @@ -206,10 +206,6 @@ return base::PassKey<TabCollection>(); } - // Helper function for GetTabsRecursive that uses std::list, in order to take - // advantage of constant-time concatenation. - std::list<TabInterface*> GetTabsRecursiveAsList() const; - const ChildrenVector& GetChildren() const { return impl_->GetChildren(); } // Total number of tabs in the collection.
diff --git a/components/tabs/public/tab_interface.h b/components/tabs/public/tab_interface.h index b33c472..2b5c0ced 100644 --- a/components/tabs/public/tab_interface.h +++ b/components/tabs/public/tab_interface.h
@@ -191,6 +191,7 @@ // TabFeatures or BrowserWindowFeatures, you can safely assume that this is // always non-nullptr. virtual BrowserWindowInterface* GetBrowserWindowInterface() = 0; + virtual const BrowserWindowInterface* GetBrowserWindowInterface() const = 0; #endif // !BUILDFLAG(IS_ANDROID) // Returns the feature controllers scoped to this tab.
diff --git a/chrome/browser/ui/tabs/split_tab_collection.cc b/components/tabs/split_tab_collection.cc similarity index 79% rename from chrome/browser/ui/tabs/split_tab_collection.cc rename to components/tabs/split_tab_collection.cc index 4cc63459..d3d8d7f 100644 --- a/chrome/browser/ui/tabs/split_tab_collection.cc +++ b/components/tabs/split_tab_collection.cc
@@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/tabs/split_tab_collection.h" +#include "components/tabs/public/split_tab_collection.h" #include <memory> #include <optional> -#include "chrome/browser/ui/tabs/split_tab_data.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" -#include "chrome/browser/ui/tabs/tab_model.h" +#include "components/tabs/public/split_tab_data.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_collection_storage.h" namespace tabs {
diff --git a/chrome/browser/ui/tabs/split_tab_data.cc b/components/tabs/split_tab_data.cc similarity index 76% rename from chrome/browser/ui/tabs/split_tab_data.cc rename to components/tabs/split_tab_data.cc index 2c18bcb..1ef8019 100644 --- a/chrome/browser/ui/tabs/split_tab_data.cc +++ b/components/tabs/split_tab_data.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 "chrome/browser/ui/tabs/split_tab_data.h" +#include "components/tabs/public/split_tab_data.h" #include <memory> -#include "chrome/browser/ui/tabs/split_tab_collection.h" -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" -#include "chrome/browser/ui/tabs/tab_model.h" +#include "components/tabs/public/split_tab_collection.h" +#include "components/tabs/public/split_tab_visual_data.h" #include "components/tabs/public/tab_interface.h" namespace split_tabs {
diff --git a/chrome/browser/ui/tabs/split_tab_visual_data.cc b/components/tabs/split_tab_visual_data.cc similarity index 90% rename from chrome/browser/ui/tabs/split_tab_visual_data.cc rename to components/tabs/split_tab_visual_data.cc index 70b3f23..f2a8520 100644 --- a/chrome/browser/ui/tabs/split_tab_visual_data.cc +++ b/components/tabs/split_tab_visual_data.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/tabs/split_tab_visual_data.h" +#include "components/tabs/public/split_tab_visual_data.h" namespace split_tabs {
diff --git a/components/tabs/tab_collection.cc b/components/tabs/tab_collection.cc index 4052e6c..6017260c 100644 --- a/components/tabs/tab_collection.cc +++ b/components/tabs/tab_collection.cc
@@ -144,8 +144,13 @@ } std::vector<TabInterface*> TabCollection::GetTabsRecursive() const { - std::list<TabInterface*> tabs = GetTabsRecursiveAsList(); - return std::vector<TabInterface*>{tabs.begin(), tabs.end()}; + std::vector<TabInterface*> tabs; + tabs.reserve(TabCountRecursive()); + for (tabs::TabInterface* tab : *this) { + tabs.push_back(tab); + } + + return tabs; } std::optional<size_t> TabCollection::GetIndexOfCollection( @@ -257,23 +262,4 @@ } } -std::list<TabInterface*> TabCollection::GetTabsRecursiveAsList() const { - const auto& children = impl_->GetChildren(); - std::list<TabInterface*> tabs; - - for (const auto& child : children) { - if (std::holds_alternative<std::unique_ptr<TabInterface>>(child)) { - TabInterface* tab = std::get<std::unique_ptr<TabInterface>>(child).get(); - tabs.push_back(tab); - } else { - std::list<TabInterface*> tabs_to_insert = - std::get<std::unique_ptr<TabCollection>>(child) - ->GetTabsRecursiveAsList(); - tabs.splice(tabs.end(), tabs_to_insert); - } - } - - return tabs; -} - } // namespace tabs
diff --git a/components/tracing/common/tracing_switches.cc b/components/tracing/common/tracing_switches.cc index f036de5..4ab3da6 100644 --- a/components/tracing/common/tracing_switches.cc +++ b/components/tracing/common/tracing_switches.cc
@@ -18,10 +18,18 @@ // < {input txt config}.pbtxt > {output proto config}.pb const char kEnableBackgroundTracing[] = "enable-background-tracing"; -// Causes TRACE_EVENT flags to be recorded from startup. -// This flag will be ignored if --trace-startup or --trace-shutdown is provided. +// Enables startup tracing by passing a file path containing the chrome Json +// tracing config as an argument. This flag will be ignored if --trace-startup +// or --trace-shutdown is provided. const char kTraceConfigFile[] = "trace-config-file"; +// Enables startup tracing by passing a file path containing the perfetto config +// as an argument. The config is a serialized or base64 encoded proto +// `perfetto.protos.TraceConfig` defined in +// third_party/perfetto/protos/perfetto/config/trace_config.proto. This flag +// will be ignored if --trace-startup or --trace-shutdown is provided. +const char kTracePerfettoConfigFile[] = "trace-perfetto-config-file"; + // Causes TRACE_EVENT flags to be recorded from startup. Optionally, can // specify the specific trace categories to include (e.g. // --trace-startup=base,net) otherwise, all events are recorded. Setting this
diff --git a/components/tracing/common/tracing_switches.h b/components/tracing/common/tracing_switches.h index 94711d8..e8b5ee3 100644 --- a/components/tracing/common/tracing_switches.h +++ b/components/tracing/common/tracing_switches.h
@@ -11,6 +11,7 @@ TRACING_EXPORT extern const char kEnableBackgroundTracing[]; TRACING_EXPORT extern const char kTraceConfigFile[]; +TRACING_EXPORT extern const char kTracePerfettoConfigFile[]; TRACING_EXPORT extern const char kTraceStartup[]; TRACING_EXPORT extern const char kTraceConfigHandle[]; TRACING_EXPORT extern const char kEnableTracing[];
diff --git a/components/trusted_vault/BUILD.gn b/components/trusted_vault/BUILD.gn index 1d8ec41..cf151bf 100644 --- a/components/trusted_vault/BUILD.gn +++ b/components/trusted_vault/BUILD.gn
@@ -5,6 +5,8 @@ static_library("trusted_vault") { sources = [ "trusted_vault_client.h", + "trusted_vault_server_constants.cc", + "trusted_vault_server_constants.h", "trusted_vault_service.cc", "trusted_vault_service.h", ] @@ -42,6 +44,8 @@ "standalone_trusted_vault_backend.h", "standalone_trusted_vault_client.cc", "standalone_trusted_vault_client.h", + "standalone_trusted_vault_server_constants.cc", + "standalone_trusted_vault_server_constants.h", "standalone_trusted_vault_storage.cc", "standalone_trusted_vault_storage.h", "trusted_vault_access_token_fetcher.h", @@ -61,8 +65,6 @@ "trusted_vault_histograms.h", "trusted_vault_request.cc", "trusted_vault_request.h", - "trusted_vault_server_constants.cc", - "trusted_vault_server_constants.h", "trusted_vault_throttling_connection.h", "trusted_vault_throttling_connection_impl.cc", "trusted_vault_throttling_connection_impl.h", @@ -104,6 +106,7 @@ "recovery_key_store_connection_unittest.cc", "securebox_unittest.cc", "standalone_trusted_vault_backend_unittest.cc", + "standalone_trusted_vault_server_constants_unittest.cc", "standalone_trusted_vault_storage_unittest.cc", "trusted_vault_access_token_fetcher_frontend_unittest.cc", "trusted_vault_connection_impl_unittest.cc",
diff --git a/components/trusted_vault/download_keys_response_handler.cc b/components/trusted_vault/download_keys_response_handler.cc index cd21401a..d2f1957b 100644 --- a/components/trusted_vault/download_keys_response_handler.cc +++ b/components/trusted_vault/download_keys_response_handler.cc
@@ -12,6 +12,7 @@ #include "components/trusted_vault/proto/vault.pb.h" #include "components/trusted_vault/proto_string_bytes_conversion.h" #include "components/trusted_vault/securebox.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/trusted_vault_connection.h" #include "components/trusted_vault/trusted_vault_crypto.h" #include "components/trusted_vault/trusted_vault_server_constants.h"
diff --git a/components/trusted_vault/download_keys_response_handler_unittest.cc b/components/trusted_vault/download_keys_response_handler_unittest.cc index aa34eeb..94a7829f 100644 --- a/components/trusted_vault/download_keys_response_handler_unittest.cc +++ b/components/trusted_vault/download_keys_response_handler_unittest.cc
@@ -10,6 +10,7 @@ #include "components/trusted_vault/proto/vault.pb.h" #include "components/trusted_vault/proto_string_bytes_conversion.h" #include "components/trusted_vault/securebox.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/trusted_vault_connection.h" #include "components/trusted_vault/trusted_vault_crypto.h" #include "components/trusted_vault/trusted_vault_server_constants.h"
diff --git a/components/trusted_vault/icloud_keychain_recovery_factor_unittest.mm b/components/trusted_vault/icloud_keychain_recovery_factor_unittest.mm index 17667975..d6a21ab 100644 --- a/components/trusted_vault/icloud_keychain_recovery_factor_unittest.mm +++ b/components/trusted_vault/icloud_keychain_recovery_factor_unittest.mm
@@ -20,6 +20,7 @@ #include "components/trusted_vault/proto/local_trusted_vault.pb.h" #include "components/trusted_vault/proto_string_bytes_conversion.h" #include "components/trusted_vault/securebox.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/test/fake_file_access.h" #include "components/trusted_vault/test/mock_trusted_vault_throttling_connection.h" #include "components/trusted_vault/trusted_vault_connection.h"
diff --git a/components/trusted_vault/physical_device_recovery_factor_unittest.cc b/components/trusted_vault/physical_device_recovery_factor_unittest.cc index f0e3a67..a6e4c4ba 100644 --- a/components/trusted_vault/physical_device_recovery_factor_unittest.cc +++ b/components/trusted_vault/physical_device_recovery_factor_unittest.cc
@@ -18,6 +18,7 @@ #include "components/trusted_vault/local_recovery_factor.h" #include "components/trusted_vault/proto_string_bytes_conversion.h" #include "components/trusted_vault/securebox.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/standalone_trusted_vault_storage.h" #include "components/trusted_vault/test/fake_file_access.h" #include "components/trusted_vault/test/mock_trusted_vault_throttling_connection.h"
diff --git a/components/trusted_vault/standalone_trusted_vault_backend.cc b/components/trusted_vault/standalone_trusted_vault_backend.cc index cdb8ee2c..fdbe7b0 100644 --- a/components/trusted_vault/standalone_trusted_vault_backend.cc +++ b/components/trusted_vault/standalone_trusted_vault_backend.cc
@@ -29,6 +29,7 @@ #include "components/trusted_vault/proto_string_bytes_conversion.h" #include "components/trusted_vault/proto_time_conversion.h" #include "components/trusted_vault/securebox.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/standalone_trusted_vault_storage.h" #include "components/trusted_vault/trusted_vault_connection.h" #include "components/trusted_vault/trusted_vault_histograms.h"
diff --git a/components/trusted_vault/standalone_trusted_vault_backend_unittest.cc b/components/trusted_vault/standalone_trusted_vault_backend_unittest.cc index 419cfd6..460ca51 100644 --- a/components/trusted_vault/standalone_trusted_vault_backend_unittest.cc +++ b/components/trusted_vault/standalone_trusted_vault_backend_unittest.cc
@@ -29,6 +29,7 @@ #include "components/trusted_vault/proto/local_trusted_vault.pb.h" #include "components/trusted_vault/proto_string_bytes_conversion.h" #include "components/trusted_vault/securebox.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/standalone_trusted_vault_storage.h" #include "components/trusted_vault/test/fake_file_access.h" #include "components/trusted_vault/test/mock_trusted_vault_throttling_connection.h"
diff --git a/components/trusted_vault/standalone_trusted_vault_server_constants.cc b/components/trusted_vault/standalone_trusted_vault_server_constants.cc new file mode 100644 index 0000000..a4309bd --- /dev/null +++ b/components/trusted_vault/standalone_trusted_vault_server_constants.cc
@@ -0,0 +1,90 @@ +// Copyright 2021 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/trusted_vault/standalone_trusted_vault_server_constants.h" + +#include <string_view> + +#include "base/base64url.h" +#include "base/containers/fixed_flat_map.h" +#include "net/base/url_util.h" + +namespace trusted_vault { + +std::vector<uint8_t> GetConstantTrustedVaultKey() { + return std::vector<uint8_t>(16, 0); +} + +GURL GetGetSecurityDomainMembersURL(const GURL& server_url) { + // View three is `SECURITY_DOMAIN_MEMBER_METADATA`. + return GURL(server_url.spec() + kSecurityDomainMemberNamePrefix + "?view=3"); +} + +GURL GetGetSecurityDomainMemberURL(const GURL& server_url, + base::span<const uint8_t> public_key) { + std::string encoded_public_key; + base::Base64UrlEncode(std::string(public_key.begin(), public_key.end()), + base::Base64UrlEncodePolicy::OMIT_PADDING, + &encoded_public_key); + return GURL(server_url.spec() + kSecurityDomainMemberNamePrefix + + encoded_public_key + "?view=2" + + "&request_header.force_master_read=true"); +} + +GURL GetGetSecurityDomainURL(const GURL& server_url, + SecurityDomainId security_domain) { + return GURL(server_url.spec() + GetSecurityDomainPath(security_domain) + + "?view=2"); +} + +GURL GetJoinSecurityDomainURL(const GURL& server_url, + SecurityDomainId security_domain) { + return GURL(server_url.spec() + GetSecurityDomainPath(security_domain) + + ":join"); +} + +GURL GetGetSecurityDomainMembersURLForTesting( + const std::optional<std::string>& next_page_token, + const GURL& server_url) { + GURL url = GetGetSecurityDomainMembersURL(server_url); + if (next_page_token) { + url = net::AppendQueryParameter(url, "page_token", *next_page_token); + } + return net::AppendQueryParameter(url, kQueryParameterAlternateOutputKey, + kQueryParameterAlternateOutputProto); +} + +GURL GetFullJoinSecurityDomainsURLForTesting(const GURL& server_url, + SecurityDomainId security_domain) { + return net::AppendQueryParameter( + GetJoinSecurityDomainURL(server_url, security_domain), + kQueryParameterAlternateOutputKey, kQueryParameterAlternateOutputProto); +} + +GURL GetFullGetSecurityDomainMemberURLForTesting( + const GURL& server_url, + base::span<const uint8_t> public_key) { + return net::AppendQueryParameter( + GetGetSecurityDomainMemberURL(server_url, public_key), + kQueryParameterAlternateOutputKey, kQueryParameterAlternateOutputProto); +} + +GURL GetFullGetSecurityDomainURLForTesting(const GURL& server_url, + SecurityDomainId security_domain) { + return net::AppendQueryParameter( + GetGetSecurityDomainURL(server_url, security_domain), + kQueryParameterAlternateOutputKey, kQueryParameterAlternateOutputProto); +} + +std::string GetSecurityDomainPath(SecurityDomainId domain) { + switch (domain) { + case SecurityDomainId::kChromeSync: + return std::string(kSecurityDomainPathPrefix) + kSyncSecurityDomainName; + case SecurityDomainId::kPasskeys: + return std::string(kSecurityDomainPathPrefix) + + kPasskeysSecurityDomainName; + } +} + +} // namespace trusted_vault
diff --git a/components/trusted_vault/standalone_trusted_vault_server_constants.h b/components/trusted_vault/standalone_trusted_vault_server_constants.h new file mode 100644 index 0000000..84e706f --- /dev/null +++ b/components/trusted_vault/standalone_trusted_vault_server_constants.h
@@ -0,0 +1,54 @@ +// Copyright 2021 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_TRUSTED_VAULT_STANDALONE_TRUSTED_VAULT_SERVER_CONSTANTS_H_ +#define COMPONENTS_TRUSTED_VAULT_STANDALONE_TRUSTED_VAULT_SERVER_CONSTANTS_H_ + +#include <optional> +#include <string> +#include <vector> + +#include "base/containers/span.h" +#include "components/trusted_vault/trusted_vault_server_constants.h" +#include "url/gurl.h" + +namespace trusted_vault { + +inline constexpr int kUnknownConstantKeyVersion = 0; + +inline constexpr char kSecurityDomainPathPrefix[] = "users/me/securitydomains/"; +inline constexpr char kSecurityDomainMemberNamePrefix[] = "users/me/members/"; +inline constexpr char kJoinSecurityDomainsErrorDetailTypeURL[] = + "type.googleapis.com/" + "google.internal.identity.securitydomain.v1.JoinSecurityDomainErrorDetail"; + +inline constexpr char kQueryParameterAlternateOutputKey[] = "alt"; +inline constexpr char kQueryParameterAlternateOutputProto[] = "proto"; + +std::vector<uint8_t> GetConstantTrustedVaultKey(); +GURL GetGetSecurityDomainMembersURL(const GURL& server_url); +GURL GetGetSecurityDomainMemberURL(const GURL& server_url, + base::span<const uint8_t> public_key); +GURL GetGetSecurityDomainURL(const GURL& server_url, + SecurityDomainId security_domain); +GURL GetJoinSecurityDomainURL(const GURL& server_url, + SecurityDomainId security_domain); + +// Computes full URL, including alternate proto param. +GURL GetGetSecurityDomainMembersURLForTesting( + const std::optional<std::string>& next_page_token, + const GURL& server_url); +GURL GetFullJoinSecurityDomainsURLForTesting(const GURL& server_url, + SecurityDomainId security_domain); +GURL GetFullGetSecurityDomainMemberURLForTesting( + const GURL& server_url, + base::span<const uint8_t> public_key); +GURL GetFullGetSecurityDomainURLForTesting(const GURL& server_url, + SecurityDomainId security_domain); + +std::string GetSecurityDomainPath(SecurityDomainId domain); + +} // namespace trusted_vault + +#endif // COMPONENTS_TRUSTED_VAULT_STANDALONE_TRUSTED_VAULT_SERVER_CONSTANTS_H_
diff --git a/components/trusted_vault/standalone_trusted_vault_server_constants_unittest.cc b/components/trusted_vault/standalone_trusted_vault_server_constants_unittest.cc new file mode 100644 index 0000000..39d194a --- /dev/null +++ b/components/trusted_vault/standalone_trusted_vault_server_constants_unittest.cc
@@ -0,0 +1,51 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" + +#include <cstdint> +#include <vector> + +#include "components/trusted_vault/securebox.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace trusted_vault { + +namespace { + +using testing::Eq; + +TEST(StandaloneTrustedVaultServerConstantsTest, + ShouldGetGetSecurityDomainMemberURL) { + const GURL kTestUrl("https://example.com/v1/"); + + // Arbitrary key, with an appropriate length. + const std::vector<uint8_t> kPublicKey{ + 0x4, 0xF2, 0x4C, 0x45, 0xBA, 0xF4, 0xF8, 0x6C, 0xF9, 0x73, 0xCE, + 0x75, 0xC, 0xC9, 0xD4, 0xF, 0x4A, 0x53, 0xB7, 0x85, 0x46, 0x41, + 0xFB, 0x31, 0x17, 0xF, 0xEB, 0xB, 0x45, 0xE4, 0x29, 0x69, 0x9B, + 0xB2, 0x7, 0x12, 0xC1, 0x9, 0x3D, 0xEF, 0xBB, 0x57, 0xDC, 0x56, + 0x12, 0x29, 0xF2, 0x73, 0xE1, 0xC5, 0x99, 0x1C, 0x49, 0x3A, 0xA2, + 0x30, 0xF9, 0xBA, 0x3B, 0xB1, 0x83, 0xCF, 0x1B, 0x5D, 0xE8}; + + // Guard against future code changes, in case the key length changes. + ASSERT_THAT(kPublicKey.size(), Eq(SecureBoxKeyPair::GenerateRandom() + ->public_key() + .ExportToBytes() + .size())); + + // Note that production code (TrustedVaultRequest::CreateURLLoader) will + // append &alt=proto to the URL. + EXPECT_THAT(GetGetSecurityDomainMemberURL(kTestUrl, kPublicKey).spec(), + Eq("https://example.com/v1/users/me/members/" + "BPJMRbr0-Gz5c851DMnUD0pTt4VGQfsxFw_" + "rC0XkKWmbsgcSwQk977tX3FYSKfJz4cWZHEk6ojD5ujuxg88bXeg" + "?view=2" + "&request_header.force_master_read=true")); +} + +} // namespace + +} // namespace trusted_vault
diff --git a/components/trusted_vault/standalone_trusted_vault_storage.cc b/components/trusted_vault/standalone_trusted_vault_storage.cc index f3c85e2..109c66d 100644 --- a/components/trusted_vault/standalone_trusted_vault_storage.cc +++ b/components/trusted_vault/standalone_trusted_vault_storage.cc
@@ -13,6 +13,7 @@ #include "base/memory/ptr_util.h" #include "base/metrics/histogram_functions.h" #include "components/trusted_vault/proto_string_bytes_conversion.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/trusted_vault_histograms.h" #include "components/trusted_vault/trusted_vault_server_constants.h"
diff --git a/components/trusted_vault/standalone_trusted_vault_storage_unittest.cc b/components/trusted_vault/standalone_trusted_vault_storage_unittest.cc index d9bf7f0f..bc82f57d 100644 --- a/components/trusted_vault/standalone_trusted_vault_storage_unittest.cc +++ b/components/trusted_vault/standalone_trusted_vault_storage_unittest.cc
@@ -17,6 +17,7 @@ #include "components/trusted_vault/proto/local_trusted_vault.pb.h" #include "components/trusted_vault/proto_string_bytes_conversion.h" #include "components/trusted_vault/securebox.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/trusted_vault_histograms.h" #include "components/trusted_vault/trusted_vault_server_constants.h" #include "google_apis/gaia/gaia_id.h"
diff --git a/components/trusted_vault/test/fake_security_domains_server.cc b/components/trusted_vault/test/fake_security_domains_server.cc index 9b3ade5..673402b4 100644 --- a/components/trusted_vault/test/fake_security_domains_server.cc +++ b/components/trusted_vault/test/fake_security_domains_server.cc
@@ -14,6 +14,7 @@ #include "base/rand_util.h" #include "components/trusted_vault/proto_string_bytes_conversion.h" #include "components/trusted_vault/securebox.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/trusted_vault_crypto.h" #include "components/trusted_vault/trusted_vault_server_constants.h" #include "net/http/http_status_code.h"
diff --git a/components/trusted_vault/trusted_vault_connection_impl.cc b/components/trusted_vault/trusted_vault_connection_impl.cc index aa0caee..a07d46a 100644 --- a/components/trusted_vault/trusted_vault_connection_impl.cc +++ b/components/trusted_vault/trusted_vault_connection_impl.cc
@@ -21,6 +21,7 @@ #include "components/trusted_vault/proto/vault.pb.h" #include "components/trusted_vault/proto_string_bytes_conversion.h" #include "components/trusted_vault/securebox.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/trusted_vault_access_token_fetcher.h" #include "components/trusted_vault/trusted_vault_connection.h" #include "components/trusted_vault/trusted_vault_crypto.h"
diff --git a/components/trusted_vault/trusted_vault_connection_impl_unittest.cc b/components/trusted_vault/trusted_vault_connection_impl_unittest.cc index 1c19f0d..4d29a0cf 100644 --- a/components/trusted_vault/trusted_vault_connection_impl_unittest.cc +++ b/components/trusted_vault/trusted_vault_connection_impl_unittest.cc
@@ -23,6 +23,7 @@ #include "components/trusted_vault/proto/vault.pb.h" #include "components/trusted_vault/proto_string_bytes_conversion.h" #include "components/trusted_vault/securebox.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/test/fake_trusted_vault_access_token_fetcher.h" #include "components/trusted_vault/trusted_vault_access_token_fetcher.h" #include "components/trusted_vault/trusted_vault_connection.h"
diff --git a/components/trusted_vault/trusted_vault_request.cc b/components/trusted_vault/trusted_vault_request.cc index d8037f02..cb1bf2b 100644 --- a/components/trusted_vault/trusted_vault_request.cc +++ b/components/trusted_vault/trusted_vault_request.cc
@@ -10,6 +10,7 @@ #include "base/strings/stringprintf.h" #include "base/time/time.h" #include "components/signin/public/identity_manager/access_token_info.h" +#include "components/trusted_vault/standalone_trusted_vault_server_constants.h" #include "components/trusted_vault/trusted_vault_access_token_fetcher.h" #include "components/trusted_vault/trusted_vault_server_constants.h" #include "google_apis/credentials_mode.h"
diff --git a/components/trusted_vault/trusted_vault_server_constants.cc b/components/trusted_vault/trusted_vault_server_constants.cc index 0dc4cfb..b24a28cd 100644 --- a/components/trusted_vault/trusted_vault_server_constants.cc +++ b/components/trusted_vault/trusted_vault_server_constants.cc
@@ -4,89 +4,10 @@ #include "components/trusted_vault/trusted_vault_server_constants.h" -#include <string_view> - -#include "base/base64url.h" #include "base/containers/fixed_flat_map.h" -#include "net/base/url_util.h" namespace trusted_vault { -std::vector<uint8_t> GetConstantTrustedVaultKey() { - return std::vector<uint8_t>(16, 0); -} - -GURL GetGetSecurityDomainMembersURL(const GURL& server_url) { - // View three is `SECURITY_DOMAIN_MEMBER_METADATA`. - return GURL(server_url.spec() + kSecurityDomainMemberNamePrefix + "?view=3"); -} - -GURL GetGetSecurityDomainMemberURL(const GURL& server_url, - base::span<const uint8_t> public_key) { - std::string encoded_public_key; - base::Base64UrlEncode(std::string(public_key.begin(), public_key.end()), - base::Base64UrlEncodePolicy::OMIT_PADDING, - &encoded_public_key); - return GURL(server_url.spec() + kSecurityDomainMemberNamePrefix + - encoded_public_key + "?view=2" + - "&request_header.force_master_read=true"); -} - -GURL GetGetSecurityDomainURL(const GURL& server_url, - SecurityDomainId security_domain) { - return GURL(server_url.spec() + GetSecurityDomainPath(security_domain) + - "?view=2"); -} - -GURL GetJoinSecurityDomainURL(const GURL& server_url, - SecurityDomainId security_domain) { - return GURL(server_url.spec() + GetSecurityDomainPath(security_domain) + - ":join"); -} - -GURL GetGetSecurityDomainMembersURLForTesting( - const std::optional<std::string>& next_page_token, - const GURL& server_url) { - GURL url = GetGetSecurityDomainMembersURL(server_url); - if (next_page_token) { - url = net::AppendQueryParameter(url, "page_token", *next_page_token); - } - return net::AppendQueryParameter(url, kQueryParameterAlternateOutputKey, - kQueryParameterAlternateOutputProto); -} - -GURL GetFullJoinSecurityDomainsURLForTesting(const GURL& server_url, - SecurityDomainId security_domain) { - return net::AppendQueryParameter( - GetJoinSecurityDomainURL(server_url, security_domain), - kQueryParameterAlternateOutputKey, kQueryParameterAlternateOutputProto); -} - -GURL GetFullGetSecurityDomainMemberURLForTesting( - const GURL& server_url, - base::span<const uint8_t> public_key) { - return net::AppendQueryParameter( - GetGetSecurityDomainMemberURL(server_url, public_key), - kQueryParameterAlternateOutputKey, kQueryParameterAlternateOutputProto); -} - -GURL GetFullGetSecurityDomainURLForTesting(const GURL& server_url, - SecurityDomainId security_domain) { - return net::AppendQueryParameter( - GetGetSecurityDomainURL(server_url, security_domain), - kQueryParameterAlternateOutputKey, kQueryParameterAlternateOutputProto); -} - -std::string GetSecurityDomainPath(SecurityDomainId domain) { - switch (domain) { - case SecurityDomainId::kChromeSync: - return std::string(kSecurityDomainPathPrefix) + kSyncSecurityDomainName; - case SecurityDomainId::kPasskeys: - return std::string(kSecurityDomainPathPrefix) + - kPasskeysSecurityDomainName; - } -} - std::optional<SecurityDomainId> GetSecurityDomainByName(std::string_view name) { static_assert(static_cast<int>(SecurityDomainId::kMaxValue) == 1, "Update GetSecurityDomainByName and its unit tests when adding "
diff --git a/components/trusted_vault/trusted_vault_server_constants.h b/components/trusted_vault/trusted_vault_server_constants.h index 3153e7467..6b330067 100644 --- a/components/trusted_vault/trusted_vault_server_constants.h +++ b/components/trusted_vault/trusted_vault_server_constants.h
@@ -5,30 +5,15 @@ #ifndef COMPONENTS_TRUSTED_VAULT_TRUSTED_VAULT_SERVER_CONSTANTS_H_ #define COMPONENTS_TRUSTED_VAULT_TRUSTED_VAULT_SERVER_CONSTANTS_H_ -#include <cstdint> #include <optional> -#include <string> #include <string_view> -#include <vector> #include "base/containers/fixed_flat_set.h" -#include "base/containers/span.h" -#include "url/gurl.h" namespace trusted_vault { -inline constexpr int kUnknownConstantKeyVersion = 0; - -inline constexpr char kSecurityDomainPathPrefix[] = "users/me/securitydomains/"; inline constexpr char kSyncSecurityDomainName[] = "chromesync"; inline constexpr char kPasskeysSecurityDomainName[] = "hw_protected"; -inline constexpr char kSecurityDomainMemberNamePrefix[] = "users/me/members/"; -inline constexpr char kJoinSecurityDomainsErrorDetailTypeURL[] = - "type.googleapis.com/" - "google.internal.identity.securitydomain.v1.JoinSecurityDomainErrorDetail"; - -inline constexpr char kQueryParameterAlternateOutputKey[] = "alt"; -inline constexpr char kQueryParameterAlternateOutputProto[] = "proto"; // Identifies a particular security domain. // @@ -48,28 +33,6 @@ "Update kAllSecurityDomainIdValues when adding SecurityDomainId " "enum values"); -std::vector<uint8_t> GetConstantTrustedVaultKey(); -GURL GetGetSecurityDomainMembersURL(const GURL& server_url); -GURL GetGetSecurityDomainMemberURL(const GURL& server_url, - base::span<const uint8_t> public_key); -GURL GetGetSecurityDomainURL(const GURL& server_url, - SecurityDomainId security_domain); -GURL GetJoinSecurityDomainURL(const GURL& server_url, - SecurityDomainId security_domain); - -// Computes full URL, including alternate proto param. -GURL GetGetSecurityDomainMembersURLForTesting( - const std::optional<std::string>& next_page_token, - const GURL& server_url); -GURL GetFullJoinSecurityDomainsURLForTesting(const GURL& server_url, - SecurityDomainId security_domain); -GURL GetFullGetSecurityDomainMemberURLForTesting( - const GURL& server_url, - base::span<const uint8_t> public_key); -GURL GetFullGetSecurityDomainURLForTesting(const GURL& server_url, - SecurityDomainId security_domain); - -std::string GetSecurityDomainPath(SecurityDomainId domain); std::optional<SecurityDomainId> GetSecurityDomainByName( std::string_view domain); std::string_view GetSecurityDomainName(SecurityDomainId id);
diff --git a/components/trusted_vault/trusted_vault_server_constants_unittest.cc b/components/trusted_vault/trusted_vault_server_constants_unittest.cc index a5a2f89f..2e0c030 100644 --- a/components/trusted_vault/trusted_vault_server_constants_unittest.cc +++ b/components/trusted_vault/trusted_vault_server_constants_unittest.cc
@@ -4,10 +4,6 @@ #include "components/trusted_vault/trusted_vault_server_constants.h" -#include <cstdint> -#include <vector> - -#include "components/trusted_vault/securebox.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,34 +13,6 @@ using testing::Eq; -TEST(TrustedVaultServerConstantsTest, ShouldGetGetSecurityDomainMemberURL) { - const GURL kTestUrl("https://example.com/v1/"); - - // Arbitrary key, with an appropriate length. - const std::vector<uint8_t> kPublicKey{ - 0x4, 0xF2, 0x4C, 0x45, 0xBA, 0xF4, 0xF8, 0x6C, 0xF9, 0x73, 0xCE, - 0x75, 0xC, 0xC9, 0xD4, 0xF, 0x4A, 0x53, 0xB7, 0x85, 0x46, 0x41, - 0xFB, 0x31, 0x17, 0xF, 0xEB, 0xB, 0x45, 0xE4, 0x29, 0x69, 0x9B, - 0xB2, 0x7, 0x12, 0xC1, 0x9, 0x3D, 0xEF, 0xBB, 0x57, 0xDC, 0x56, - 0x12, 0x29, 0xF2, 0x73, 0xE1, 0xC5, 0x99, 0x1C, 0x49, 0x3A, 0xA2, - 0x30, 0xF9, 0xBA, 0x3B, 0xB1, 0x83, 0xCF, 0x1B, 0x5D, 0xE8}; - - // Guard against future code changes, in case the key length changes. - ASSERT_THAT(kPublicKey.size(), Eq(SecureBoxKeyPair::GenerateRandom() - ->public_key() - .ExportToBytes() - .size())); - - // Note that production code (TrustedVaultRequest::CreateURLLoader) will - // append &alt=proto to the URL. - EXPECT_THAT(GetGetSecurityDomainMemberURL(kTestUrl, kPublicKey).spec(), - Eq("https://example.com/v1/users/me/members/" - "BPJMRbr0-Gz5c851DMnUD0pTt4VGQfsxFw_" - "rC0XkKWmbsgcSwQk977tX3FYSKfJz4cWZHEk6ojD5ujuxg88bXeg" - "?view=2" - "&request_header.force_master_read=true")); -} - TEST(TrustedVaultServerConstantsTest, GetSecurityDomainByName) { EXPECT_THAT(GetSecurityDomainByName("chromesync"), Eq(SecurityDomainId::kChromeSync));
diff --git a/components/user_education/views/help_bubble_view.cc b/components/user_education/views/help_bubble_view.cc index d3c9bee5..1f5f361d 100644 --- a/components/user_education/views/help_bubble_view.cc +++ b/components/user_education/views/help_bubble_view.cc
@@ -341,7 +341,7 @@ true), delegate_(delegate), event_relay_(std::move(event_relay)) { - set_background_color(delegate_->GetHelpBubbleBackgroundColorId()); + SetBackgroundColor(delegate_->GetHelpBubbleBackgroundColorId()); if (anchor.rect.has_value()) { SetForceAnchorRect(anchor.rect.value());
diff --git a/components/viz/common/quads/compositor_frame_transition_directive.cc b/components/viz/common/quads/compositor_frame_transition_directive.cc index c1b32463..e3dbaaf 100644 --- a/components/viz/common/quads/compositor_frame_transition_directive.cc +++ b/components/viz/common/quads/compositor_frame_transition_directive.cc
@@ -87,16 +87,4 @@ CompositorFrameTransitionDirective::SharedElement::operator=(SharedElement&&) = default; -bool CompositorFrameTransitionDirective::SharedElement::operator==( - const SharedElement& other) const { - return render_pass_id == other.render_pass_id && - view_transition_element_resource_id == - other.view_transition_element_resource_id; -} - -bool CompositorFrameTransitionDirective::SharedElement::operator!=( - const SharedElement& other) const { - return !(other == *this); -} - } // namespace viz
diff --git a/components/viz/common/quads/compositor_frame_transition_directive.h b/components/viz/common/quads/compositor_frame_transition_directive.h index 9e7b551..94b7f37 100644 --- a/components/viz/common/quads/compositor_frame_transition_directive.h +++ b/components/viz/common/quads/compositor_frame_transition_directive.h
@@ -49,8 +49,8 @@ SharedElement(SharedElement&&); SharedElement& operator=(SharedElement&&); - bool operator==(const SharedElement& other) const; - bool operator!=(const SharedElement& other) const; + friend bool operator==(const SharedElement&, + const SharedElement&) = default; // The render pass corresponding to a DOM element. The id is scoped to the // same frame that the directive corresponds to.
diff --git a/components/viz/common/quads/selection.h b/components/viz/common/quads/selection.h index 0af57c9..b0ff04122 100644 --- a/components/viz/common/quads/selection.h +++ b/components/viz/common/quads/selection.h
@@ -20,20 +20,11 @@ return base::StringPrintf("Selection(%s, %s)", start.ToString().c_str(), end.ToString().c_str()); } + + friend bool operator==(const Selection<BoundType>&, + const Selection<BoundType>&) = default; }; -template <typename BoundType> -inline bool operator==(const Selection<BoundType>& lhs, - const Selection<BoundType>& rhs) { - return lhs.start == rhs.start && lhs.end == rhs.end; -} - -template <typename BoundType> -inline bool operator!=(const Selection<BoundType>& lhs, - const Selection<BoundType>& rhs) { - return !(lhs == rhs); -} - } // namespace viz #endif // COMPONENTS_VIZ_COMMON_QUADS_SELECTION_H_
diff --git a/components/viz/common/resources/transferable_resource.h b/components/viz/common/resources/transferable_resource.h index e249529..3484c3f2 100644 --- a/components/viz/common/resources/transferable_resource.h +++ b/components/viz/common/resources/transferable_resource.h
@@ -164,7 +164,6 @@ synchronization_type == o.synchronization_type && resource_source == o.resource_source; } - bool operator!=(const TransferableResource& o) const { return !(*this == o); } // TODO(danakj): Some of these fields are only GL, some are only Software, // some are both but used for different purposes (like the mailbox name).
diff --git a/components/viz/common/surfaces/region_capture_bounds.cc b/components/viz/common/surfaces/region_capture_bounds.cc index 454a38a..09fdff74 100644 --- a/components/viz/common/surfaces/region_capture_bounds.cc +++ b/components/viz/common/surfaces/region_capture_bounds.cc
@@ -38,13 +38,6 @@ bounds_.clear(); } -bool RegionCaptureBounds::operator==(const RegionCaptureBounds& rhs) const { - return bounds_ == rhs.bounds_; -} -bool RegionCaptureBounds::operator!=(const RegionCaptureBounds& rhs) const { - return !(*this == rhs); -} - std::string RegionCaptureBounds::ToString() const { std::ostringstream ss; ss << "{";
diff --git a/components/viz/common/surfaces/region_capture_bounds.h b/components/viz/common/surfaces/region_capture_bounds.h index 414fe92..a788d8f 100644 --- a/components/viz/common/surfaces/region_capture_bounds.h +++ b/components/viz/common/surfaces/region_capture_bounds.h
@@ -51,8 +51,8 @@ return bounds_; } - bool operator==(const RegionCaptureBounds& rhs) const; - bool operator!=(const RegionCaptureBounds& rhs) const; + friend bool operator==(const RegionCaptureBounds&, + const RegionCaptureBounds&) = default; std::string ToString() const; private:
diff --git a/components/viz/service/layers/layer_context_impl.cc b/components/viz/service/layers/layer_context_impl.cc index 8dbdbe67..000792de 100644 --- a/components/viz/service/layers/layer_context_impl.cc +++ b/components/viz/service/layers/layer_context_impl.cc
@@ -1308,6 +1308,8 @@ layers.set_source_frame_number(update->source_frame_number); layers.set_trace_id( cc::BeginMainFrameTraceId::FromUnsafeValue(update->trace_id)); + layers.set_primary_main_frame_item_sequence_number( + update->primary_main_frame_item_sequence_number); layers.SetDeviceViewportRect(update->device_viewport); if (update->page_scale_factor <= 0 || update->min_page_scale_factor <= 0 ||
diff --git a/components/viz/service/surfaces/surface_dependency_deadline.h b/components/viz/service/surfaces/surface_dependency_deadline.h index cebe44be..c04b2dc1 100644 --- a/components/viz/service/surfaces/surface_dependency_deadline.h +++ b/components/viz/service/surfaces/surface_dependency_deadline.h
@@ -48,9 +48,6 @@ } bool operator==(const SurfaceDependencyDeadline& other) const; - bool operator!=(const SurfaceDependencyDeadline& other) const { - return !(*this == other); - } private: raw_ptr<const base::TickClock> tick_clock_;
diff --git a/components/viz/test/begin_frame_args_test.h b/components/viz/test/begin_frame_args_test.h index 6cdb0016..495b5d3 100644 --- a/components/viz/test/begin_frame_args_test.h +++ b/components/viz/test/begin_frame_args_test.h
@@ -59,8 +59,6 @@ // operate on. // Allow "EXPECT_EQ(args1, args2);" -// We don't define operator!= because EXPECT_NE(args1, args2) isn't all that -// sensible. bool operator==(const BeginFrameArgs& lhs, const BeginFrameArgs& rhs); // Allow gtest to pretty print begin frame args.
diff --git a/components/webui/version/resources/about_version.html b/components/webui/version/resources/about_version.html index bd2914d8..e4ad426e 100644 --- a/components/webui/version/resources/about_version.html +++ b/components/webui/version/resources/about_version.html
@@ -99,10 +99,6 @@ <td class="label">APK targetSdkVersion</td> <td class="version">$i18n{target_sdk_version}</td> </tr> - <tr> - <td class="label">isAtLeastU/targetsAtLeastU</td> - <td class="version">$i18n{targets_u}</td> - </tr> <tr> <td class="label">$i18n{gms_name}</td> <td class="version" id="gms_version">
diff --git a/components/webui/version/version_ui_constants.cc b/components/webui/version/version_ui_constants.cc index 7c9bd75..3828e8e 100644 --- a/components/webui/version/version_ui_constants.cc +++ b/components/webui/version/version_ui_constants.cc
@@ -57,8 +57,6 @@ const char kVersionCode[] = "version_code"; const char kTargetSdkVersionName[] = "target_sdk_version_name"; const char kTargetSdkVersion[] = "target_sdk_version"; -const char kTargetsUName[] = "targets_u_name"; -const char kTargetsU[] = "targets_u"; const char kGmsName[] = "gms_name"; const char kGmsVersion[] = "gms_version"; #endif
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 4008b7bd..d8896295 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -261,6 +261,28 @@ base::test::ScopedFeatureList feature_list_; }; +class SelectNestedInputDumpAccessibilityTreeTest + : public DumpAccessibilityTreeTest { + protected: + SelectNestedInputDumpAccessibilityTreeTest() { + feature_list_.InitWithFeatures( + {{blink::features::kCustomizableSelect, + blink::features::kSelectParserRelaxation, + blink::features::kSelectAccessibilityNestedInput}}, + {/* disabled_features */}); + } + + ~SelectNestedInputDumpAccessibilityTreeTest() override { + // Ensure that the feature lists are destroyed in the same order they + // were created in. + scoped_feature_list_.Reset(); + feature_list_.Reset(); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + class OnScreenModeDumpAccessibilityTreeTest : public DumpAccessibilityTreeTest { }; @@ -310,6 +332,12 @@ INSTANTIATE_TEST_SUITE_P( All, + SelectNestedInputDumpAccessibilityTreeTest, + ::testing::ValuesIn(DumpAccessibilityTestBase::TreeTestPasses()), + DumpAccessibilityTreeTestPassToString()); + +INSTANTIATE_TEST_SUITE_P( + All, OnScreenModeDumpAccessibilityTreeTest, ::testing::ValuesIn(DumpAccessibilityTestBase::TreeTestPasses()), DumpAccessibilityTreeTestPassToString()); @@ -2316,6 +2344,11 @@ RunHtmlTest(FILE_PATH_LITERAL("select-with-input.html")); } +IN_PROC_BROWSER_TEST_P(SelectNestedInputDumpAccessibilityTreeTest, + AccessibilityCustomSelectWithInput) { + RunHtmlTest(FILE_PATH_LITERAL("select-with-input-2.html")); +} + IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityDd) { RunHtmlTest(FILE_PATH_LITERAL("dd.html")); }
diff --git a/content/browser/back_forward_cache_internal_browsertest.cc b/content/browser/back_forward_cache_internal_browsertest.cc index 85a599d..b2e29c8 100644 --- a/content/browser/back_forward_cache_internal_browsertest.cc +++ b/content/browser/back_forward_cache_internal_browsertest.cc
@@ -3948,472 +3948,6 @@ } } -class BackgroundForegroundProcessLimitBackForwardCacheBrowserTest - : public BackForwardCacheBrowserTest { - protected: - void SetUpCommandLine(base::CommandLine* command_line) override { - EnableFeatureAndSetParams(features::kBackForwardCache, "cache_size", - base::NumberToString(kBackForwardCacheSize)); - EnableFeatureAndSetParams( - features::kBackForwardCache, "foreground_cache_size", - base::NumberToString(kForegroundBackForwardCacheSize)); - BackForwardCacheBrowserTest::SetUpCommandLine(command_line); - } - - void ExpectCached(const RenderFrameHostImplWrapper& rfh, - bool cached, - bool backgrounded) { - EXPECT_FALSE(rfh.IsDestroyed()); - EXPECT_EQ(cached, rfh->IsInBackForwardCache()); - EXPECT_EQ(backgrounded, rfh->GetProcess()->GetPriority() == - base::Process::Priority::kBestEffort); - } - // The number of pages the BackForwardCache can hold per tab. - const size_t kBackForwardCacheSize = 4; - const size_t kForegroundBackForwardCacheSize = 2; - const size_t kPruneSize = 1u; - const NotRestoredReason kPruneReason = - NotRestoredReason::kCacheLimitPrunedOnModerateMemoryPressure; -}; - -// Test that a series of same-site navigations (which use the same process) -// uses the foreground limit. -IN_PROC_BROWSER_TEST_F( - BackgroundForegroundProcessLimitBackForwardCacheBrowserTest, - CacheEvictionSameSite) { - ASSERT_TRUE(embedded_test_server()->Start()); - - std::vector<RenderFrameHostImplWrapper> rfhs; - - for (size_t i = 0; i <= kBackForwardCacheSize * 2; ++i) { - SCOPED_TRACE(i); - GURL url(embedded_test_server()->GetURL( - "a.com", base::StringPrintf("/title1.html?i=%zu", i))); - ASSERT_TRUE(NavigateToURL(shell(), url)); - rfhs.emplace_back(current_frame_host()); - EXPECT_NE(rfhs.back()->GetProcess()->GetPriority(), - base::Process::Priority::kBestEffort); - - for (size_t j = 0; j <= i; ++j) { - SCOPED_TRACE(j); - // The last page is active, the previous |kForegroundBackForwardCacheSize| - // should be in the cache, any before that should be deleted. - if (i - j <= kForegroundBackForwardCacheSize) { - // All of the processes should be in the foreground. - ExpectCached(rfhs[j], /*cached=*/i != j, - /*backgrounded=*/false); - } else { - ASSERT_TRUE(rfhs[j].WaitUntilRenderFrameDeleted()); - } - } - } - - // Navigate back but not to the initial about:blank. - for (size_t i = 0; i <= kBackForwardCacheSize * 2 - 1; ++i) { - SCOPED_TRACE(i); - ASSERT_TRUE(HistoryGoBack(web_contents())); - // The first |kBackForwardCacheSize| navigations should be restored from the - // cache. The rest should not. - if (i < kForegroundBackForwardCacheSize) { - ExpectRestored(FROM_HERE); - } else { - ExpectNotRestored({NotRestoredReason::kForegroundCacheLimit}, {}, {}, {}, - {}, FROM_HERE); - } - } -} - -// Test that a series of cross-site navigations (which use different processes) -// use the background limit. -// -// TODO(crbug.com/40179515): This test is flaky. It has been reenabled with -// improved failure output (https://crrev.com/c/2862346). It's OK to disable it -// again when it fails. -IN_PROC_BROWSER_TEST_F( - BackgroundForegroundProcessLimitBackForwardCacheBrowserTest, - CacheEvictionCrossSite) { - ASSERT_TRUE(embedded_test_server()->Start()); - - std::vector<RenderFrameHostImplWrapper> rfhs; - - for (size_t i = 0; i <= kBackForwardCacheSize * 2; ++i) { - SCOPED_TRACE(i); - // Note: do NOT use .com domains here because a4.com is on the HSTS preload - // list, which will cause our test requests to timeout. - GURL url(embedded_test_server()->GetURL(base::StringPrintf("a%zu.test", i), - "/title1.html")); - ASSERT_TRUE(NavigateToURL(shell(), url)); - rfhs.emplace_back(current_frame_host()); - EXPECT_NE(rfhs.back()->GetProcess()->GetPriority(), - base::Process::Priority::kBestEffort); - - for (size_t j = 0; j <= i; ++j) { - SCOPED_TRACE(j); - // The last page is active, the previous |kBackgroundBackForwardCacheSize| - // should be in the cache, any before that should be deleted. - if (i - j <= kBackForwardCacheSize) { - EXPECT_FALSE(rfhs[j].IsDestroyed()); - // Pages except the active one should be cached and in the background. - ExpectCached(rfhs[j], /*cached=*/i != j, - /*backgrounded=*/i != j); - } else { - ASSERT_TRUE(rfhs[j].WaitUntilRenderFrameDeleted()); - } - } - } - - // Navigate back but not to the initial about:blank. - for (size_t i = 0; i <= kBackForwardCacheSize * 2 - 1; ++i) { - SCOPED_TRACE(i); - ASSERT_TRUE(HistoryGoBack(web_contents())); - // The first |kBackForwardCacheSize| navigations should be restored from the - // cache. The rest should not. - if (i < kBackForwardCacheSize) { - ExpectRestored(FROM_HERE); - } else { - ExpectNotRestored({NotRestoredReason::kCacheLimit}, {}, {}, {}, {}, - FROM_HERE); - } - } -} - -// Test that pruning a series of cross-site navigations (which use different -// processes) evicts the right entries with the right reason. -IN_PROC_BROWSER_TEST_F( - BackgroundForegroundProcessLimitBackForwardCacheBrowserTest, - PruneCrossSite) { - ASSERT_TRUE(embedded_test_server()->Start()); - - std::vector<RenderFrameHostImplWrapper> rfhs; - - for (size_t i = 0; i < kBackForwardCacheSize; ++i) { - SCOPED_TRACE(i); - // Note: do NOT use .com domains here because a4.com is on the HSTS preload - // list, which will cause our test requests to timeout. - GURL url(embedded_test_server()->GetURL(base::StringPrintf("a%zu.test", i), - "/title1.html")); - ASSERT_TRUE(NavigateToURL(shell(), url)); - rfhs.emplace_back(current_frame_host()); - EXPECT_NE(rfhs.back()->GetProcess()->GetPriority(), - base::Process::Priority::kBestEffort); - } - - CHECK_LE(kPruneSize, kBackForwardCacheSize); - - // Prune the BFCache entries. - web_contents()->GetController().GetBackForwardCache().Prune(kPruneSize, - kPruneReason); - - for (int i = kBackForwardCacheSize - 1 - 1 - kPruneSize; i >= 0; --i) { - SCOPED_TRACE(i); - ASSERT_TRUE(rfhs[i].WaitUntilRenderFrameDeleted()); - } - - // Navigate back but not to the initial about:blank. - for (size_t i = 0; i < kBackForwardCacheSize - 1; ++i) { - SCOPED_TRACE(i); - ASSERT_TRUE(HistoryGoBack(web_contents())); - // The first `kPruneSize` navigation should be restored from the cache. The - // rest should not. - if (i < kPruneSize) { - ExpectRestored(FROM_HERE); - } else { - ExpectNotRestored({kPruneReason}, {}, {}, {}, {}, FROM_HERE); - } - } -} - -namespace { - -const char kPrioritizedPageURL[] = "search.result"; - -} // namespace - -class BackForwardCacheLimitForPrioritizedPagesBrowserTest - : public BackgroundForegroundProcessLimitBackForwardCacheBrowserTest { - protected: - // Mock subclass of ContentBrowserClient that will determine if the url is - // prioritized by checking against `kPrioritizedPageURL`. - class MockContentBrowserClientWithPrioritizedBackForwardCacheEntry - : public ContentBrowserTestContentBrowserClient { - public: - // ContentBrowserClient overrides: - bool ShouldPrioritizeForBackForwardCache(BrowserContext* browser_context, - const GURL& url) override { - return url.DomainIs(kPrioritizedPageURL); - } - }; - - void SetUpOnMainThread() override { - BackgroundForegroundProcessLimitBackForwardCacheBrowserTest:: - SetUpOnMainThread(); - test_client_ = std::make_unique< - MockContentBrowserClientWithPrioritizedBackForwardCacheEntry>(); - } - - void SetUpCommandLine(base::CommandLine* command_line) override { - BackgroundForegroundProcessLimitBackForwardCacheBrowserTest:: - SetUpCommandLine(command_line); - feature_list_.InitAndEnableFeature( - content::kBackForwardCachePrioritizedEntry); - } - - private: - std::unique_ptr<MockContentBrowserClientWithPrioritizedBackForwardCacheEntry> - test_client_; - base::test::ScopedFeatureList feature_list_; -}; - -// Test that both prioritized entries and non-prioritized entries would be -// evicted when pruning with size 0. -IN_PROC_BROWSER_TEST_F(BackForwardCacheLimitForPrioritizedPagesBrowserTest, - PruneToZero) { - ASSERT_TRUE(embedded_test_server()->Start()); - - // We need at least 4 entries in the BFCache list for this test. - CHECK_GE(kBackForwardCacheSize, 2u); - - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("a.test", "/title1.html"))); - ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( - kPrioritizedPageURL, "/title1.html"))); - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("b.test", "/title1.html"))); - - // Now the BFCache entry list is: [a, pp, b]. - // Prune the BFCache entries to 0. - web_contents()->GetController().GetBackForwardCache().Prune(0, kPruneReason); - // All the entries should be evicted - for (size_t i = 0; i < 2; ++i) { - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectNotRestored({kPruneReason}, {}, {}, {}, {}, FROM_HERE); - } -} - -// Test that when pruning with a positive number size, the last prioritized -// entry outside the limit will not be evicted. -IN_PROC_BROWSER_TEST_F(BackForwardCacheLimitForPrioritizedPagesBrowserTest, - PruneToNonZero_PrioritizedEntryOutsideLimit) { - ASSERT_TRUE(embedded_test_server()->Start()); - - // We need at least 4 entries in the BFCache list for this test. - CHECK_GE(kBackForwardCacheSize, 4u); - - ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( - kPrioritizedPageURL, "/title1.html"))); - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("a.test", "/title1.html"))); - ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( - kPrioritizedPageURL, "/title2.html"))); - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("b.test", "/title1.html"))); - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("c.test", "/title1.html"))); - - // Now the BFCache entry list is: [pe1, a, pe2, b]. - // Prune the BFCache entries to 1, the result should be: - // [pe1(evicted), a(evicted), pe2(prioritized entry special rule), b]. - web_contents()->GetController().GetBackForwardCache().Prune(1, kPruneReason); - - // The last non-prioritized entry should be restored because it's within the - // cache limit. - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectRestored(FROM_HERE); - // The last prioritized entry should be restored since it's the special - // prioritized entry. - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectRestored(FROM_HERE); - // The other entries (including the prioritized one) should not be restored. - for (size_t i = 0; i < 2; ++i) { - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectNotRestored({kPruneReason}, {}, {}, {}, {}, FROM_HERE); - } -} - -// Test that when pruning with a positive number size, the last prioritized -// entry inside the limit should be counted as the regular cache. -IN_PROC_BROWSER_TEST_F(BackForwardCacheLimitForPrioritizedPagesBrowserTest, - PruneToNonZero_PrioritizedEntryInsideLimit) { - ASSERT_TRUE(embedded_test_server()->Start()); - - // We need at least 2 entries in the BFCache list for this test. - CHECK_GE(kBackForwardCacheSize, 2u); - - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("a.test", "/title1.html"))); - ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( - kPrioritizedPageURL, "/title2.html"))); - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("b.test", "/title1.html"))); - - // Now the BFCache entry list is: [a, pe]. - // Prune the BFCache entries to 1, the result should be: - // [a(evicted), pe]. - web_contents()->GetController().GetBackForwardCache().Prune(1, kPruneReason); - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectRestored(FROM_HERE); - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectNotRestored({kPruneReason}, {}, {}, {}, {}, FROM_HERE); -} - -// Test that when pruning with a positive number size while there is already an -// old prioritized entry kept in cache before, it will be replaced by the newer -// prioritized entry. -IN_PROC_BROWSER_TEST_F(BackForwardCacheLimitForPrioritizedPagesBrowserTest, - PruneToNonZeroTwice) { - ASSERT_TRUE(embedded_test_server()->Start()); - - // We need at least 4 entries in the BFCache list for this test. - CHECK_LE(kBackForwardCacheSize, 4u); - - ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( - kPrioritizedPageURL, "/title1.html"))); - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("a.test", "/title1.html"))); - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("b.test", "/title1.html"))); - - // Now the BFCache entry list is: [pe1, a]. - // Prune the BFCache entries to 1, the result should still be - // [pe1(prioritized entry special rule), a]. - web_contents()->GetController().GetBackForwardCache().Prune(1, kPruneReason); - - // The last non-prioritized entry should be restored because it's within the - // cache limit. - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectRestored(FROM_HERE); - // The last prioritized entry should be restored since it's the special - // prioritized entry. - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectRestored(FROM_HERE); - - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("c.test", "/title1.html"))); - ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( - kPrioritizedPageURL, "/title2.html"))); - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("d.test", "/title1.html"))); - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL("e.test", "/title1.html"))); - - // Now the BFCache entry list is: [pe1, c, pe2, d]. - // Prune the BFCache entries to 1, the result should still be - // [pe1(evicted), a(evicted), pe2(prioritized entry special rule), d]. - web_contents()->GetController().GetBackForwardCache().Prune(1, kPruneReason); - - // The last non-prioritized entry should be restored because it's within the - // cache limit. - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectRestored(FROM_HERE); - // The last prioritized entry should be restored since it's the special - // prioritized entry. - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectRestored(FROM_HERE); - // The other entries (including the prioritized one) should not be restored. - for (size_t i = 0; i < 2; ++i) { - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectNotRestored({kPruneReason}, {}, {}, {}, {}, FROM_HERE); - } -} - -// Test that the prioritized BFCache entry will not be evicted even when another -// entry is stored and exceeds the limit. -IN_PROC_BROWSER_TEST_F(BackForwardCacheLimitForPrioritizedPagesBrowserTest, - CacheLimitReached) { - ASSERT_TRUE(embedded_test_server()->Start()); - - // We need at least 1 entry in the BFCache list for this test. - CHECK_GE(kBackForwardCacheSize, 1u); - - ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( - kPrioritizedPageURL, "/title1.html"))); - - // Fill the BFCache with more entry and make it just exceeds the limit, the - // result should be: - // [pe(prioritized entry special rule), a0, a1, ...]. - for (size_t i = 0; i <= kBackForwardCacheSize; ++i) { - ASSERT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL( - base::StringPrintf("a%zu.test", i), "/title1.html"))); - } - // For the entries within cache size limit, they should be restored. - for (size_t i = 0; i < kBackForwardCacheSize; ++i) { - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectRestored(FROM_HERE); - } - // The prioritized entry should be restored as well even if it's outside the - // limit. - ASSERT_TRUE(HistoryGoBack(web_contents())); - ExpectRestored(FROM_HERE); -} - -// Test that the cache responds to processes switching from background to -// foreground. We set things up so that we have -// Cached sites: -// a0.test -// a1.test -// a2.test -// a3.test -// and the active page is a4.test. Then set the process for a[1-3] to -// foregrounded so that there are 3 entries whose processes are foregrounded. -// BFCache should evict the eldest (a1) leaving a0 because despite being older, -// it is backgrounded. Setting the priority directly is not ideal but there is -// no reliable way to cause the processes to go into the foreground just by -// navigating because proactive browsing instance swap makes it impossible to -// reliably create a new a1.test renderer in the same process as the old -// a1.test. -// -// Note that we do NOT use .com domains because a4.com is on the HSTS preload -// list. Since our test server doesn't use HTTPS, using a4.com results in the -// test timing out. -IN_PROC_BROWSER_TEST_F( - BackgroundForegroundProcessLimitBackForwardCacheBrowserTest, - ChangeToForeground) { - ASSERT_TRUE(embedded_test_server()->Start()); - - std::vector<RenderFrameHostImplWrapper> rfhs; - - // Navigate through a[0-3].com. - for (size_t i = 0; i < kBackForwardCacheSize; ++i) { - SCOPED_TRACE(i); - GURL url(embedded_test_server()->GetURL(base::StringPrintf("a%zu.test", i), - "/title1.html")); - ASSERT_TRUE(NavigateToURL(shell(), url)); - rfhs.emplace_back(current_frame_host()); - EXPECT_NE(rfhs.back()->GetProcess()->GetPriority(), - base::Process::Priority::kBestEffort); - } - // Check that a0-2 are cached and backgrounded. - for (size_t i = 0; i < kBackForwardCacheSize - 1; ++i) { - SCOPED_TRACE(i); - ExpectCached(rfhs[i], /*cached=*/true, /*backgrounded=*/true); - } - - // Navigate to a page which causes the processes for a[1-3] to be - // foregrounded. - GURL url(embedded_test_server()->GetURL("a4.test", "/title1.html")); - ASSERT_TRUE(NavigateToURL(shell(), url)); - - // Assert that we really have set up the situation we want where the processes - // are shared and in the foreground. - RenderFrameHostImpl* rfh = current_frame_host(); - ASSERT_NE(rfh->GetProcess()->GetPriority(), - base::Process::Priority::kBestEffort); - - rfhs[1]->GetProcess()->OnMediaStreamAdded(); - rfhs[2]->GetProcess()->OnMediaStreamAdded(); - rfhs[3]->GetProcess()->OnMediaStreamAdded(); - - // The page should be evicted. - ASSERT_TRUE(rfhs[1].WaitUntilRenderFrameDeleted()); - - // Check that a0 is cached and backgrounded. - ExpectCached(rfhs[0], /*cached=*/true, /*backgrounded=*/true); - // Check that a2-3 are cached and foregrounded. - ExpectCached(rfhs[2], /*cached=*/true, /*backgrounded=*/false); - ExpectCached(rfhs[3], /*cached=*/true, /*backgrounded=*/false); -} - // Test that the BackForwardCacheTimeToLiveControl feature works and takes // precedence over the default value // `kDefaultTimeToLiveInBackForwardCacheInSeconds`.
diff --git a/content/browser/back_forward_cache_limit_browsertest.cc b/content/browser/back_forward_cache_limit_browsertest.cc new file mode 100644 index 0000000..bb5a75c5 --- /dev/null +++ b/content/browser/back_forward_cache_limit_browsertest.cc
@@ -0,0 +1,481 @@ +// 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/command_line.h" +#include "base/functional/bind.h" +#include "base/strings/string_number_conversions.h" +#include "content/browser/back_forward_cache_browsertest.h" +#include "content/public/common/content_features.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/content_browser_test_utils.h" + +namespace content { + +class BackgroundForegroundProcessLimitBackForwardCacheBrowserTest + : public BackForwardCacheBrowserTest { + protected: + void SetUpCommandLine(base::CommandLine* command_line) override { + EnableFeatureAndSetParams(features::kBackForwardCache, "cache_size", + base::NumberToString(kBackForwardCacheSize)); + EnableFeatureAndSetParams( + features::kBackForwardCache, "foreground_cache_size", + base::NumberToString(kForegroundBackForwardCacheSize)); + BackForwardCacheBrowserTest::SetUpCommandLine(command_line); + } + + void ExpectCached(const RenderFrameHostImplWrapper& rfh, + bool cached, + bool backgrounded) { + EXPECT_FALSE(rfh.IsDestroyed()); + EXPECT_EQ(cached, rfh->IsInBackForwardCache()); + EXPECT_EQ(backgrounded, rfh->GetProcess()->GetPriority() == + base::Process::Priority::kBestEffort); + } + // The number of pages the BackForwardCache can hold per tab. + const size_t kBackForwardCacheSize = 4; + const size_t kForegroundBackForwardCacheSize = 2; + const size_t kPruneSize = 1u; + const NotRestoredReason kPruneReason = + NotRestoredReason::kCacheLimitPrunedOnModerateMemoryPressure; +}; + +// Test that a series of same-site navigations (which use the same process) +// uses the foreground limit. +IN_PROC_BROWSER_TEST_F( + BackgroundForegroundProcessLimitBackForwardCacheBrowserTest, + CacheEvictionSameSite) { + ASSERT_TRUE(embedded_test_server()->Start()); + + std::vector<RenderFrameHostImplWrapper> rfhs; + + for (size_t i = 0; i <= kBackForwardCacheSize * 2; ++i) { + SCOPED_TRACE(i); + GURL url(embedded_test_server()->GetURL( + "a.com", base::StringPrintf("/title1.html?i=%zu", i))); + ASSERT_TRUE(NavigateToURL(shell(), url)); + rfhs.emplace_back(current_frame_host()); + EXPECT_NE(rfhs.back()->GetProcess()->GetPriority(), + base::Process::Priority::kBestEffort); + + for (size_t j = 0; j <= i; ++j) { + SCOPED_TRACE(j); + // The last page is active, the previous |kForegroundBackForwardCacheSize| + // should be in the cache, any before that should be deleted. + if (i - j <= kForegroundBackForwardCacheSize) { + // All of the processes should be in the foreground. + ExpectCached(rfhs[j], /*cached=*/i != j, + /*backgrounded=*/false); + } else { + ASSERT_TRUE(rfhs[j].WaitUntilRenderFrameDeleted()); + } + } + } + + // Navigate back but not to the initial about:blank. + for (size_t i = 0; i <= kBackForwardCacheSize * 2 - 1; ++i) { + SCOPED_TRACE(i); + ASSERT_TRUE(HistoryGoBack(web_contents())); + // The first |kBackForwardCacheSize| navigations should be restored from the + // cache. The rest should not. + if (i < kForegroundBackForwardCacheSize) { + ExpectRestored(FROM_HERE); + } else { + ExpectNotRestored({NotRestoredReason::kForegroundCacheLimit}, {}, {}, {}, + {}, FROM_HERE); + } + } +} + +// Test that a series of cross-site navigations (which use different processes) +// use the background limit. +// +// TODO(crbug.com/40179515): This test is flaky. It has been re-enabled with +// improved failure output (https://crrev.com/c/2862346). It's OK to disable it +// again when it fails. +IN_PROC_BROWSER_TEST_F( + BackgroundForegroundProcessLimitBackForwardCacheBrowserTest, + CacheEvictionCrossSite) { + ASSERT_TRUE(embedded_test_server()->Start()); + + std::vector<RenderFrameHostImplWrapper> rfhs; + + for (size_t i = 0; i <= kBackForwardCacheSize * 2; ++i) { + SCOPED_TRACE(i); + // Note: do NOT use .com domains here because a4.com is on the HSTS preload + // list, which will cause our test requests to timeout. + GURL url(embedded_test_server()->GetURL(base::StringPrintf("a%zu.test", i), + "/title1.html")); + ASSERT_TRUE(NavigateToURL(shell(), url)); + rfhs.emplace_back(current_frame_host()); + EXPECT_NE(rfhs.back()->GetProcess()->GetPriority(), + base::Process::Priority::kBestEffort); + + for (size_t j = 0; j <= i; ++j) { + SCOPED_TRACE(j); + // The last page is active, the previous |kBackgroundBackForwardCacheSize| + // should be in the cache, any before that should be deleted. + if (i - j <= kBackForwardCacheSize) { + EXPECT_FALSE(rfhs[j].IsDestroyed()); + // Pages except the active one should be cached and in the background. + ExpectCached(rfhs[j], /*cached=*/i != j, + /*backgrounded=*/i != j); + } else { + ASSERT_TRUE(rfhs[j].WaitUntilRenderFrameDeleted()); + } + } + } + + // Navigate back but not to the initial about:blank. + for (size_t i = 0; i <= kBackForwardCacheSize * 2 - 1; ++i) { + SCOPED_TRACE(i); + ASSERT_TRUE(HistoryGoBack(web_contents())); + // The first |kBackForwardCacheSize| navigations should be restored from the + // cache. The rest should not. + if (i < kBackForwardCacheSize) { + ExpectRestored(FROM_HERE); + } else { + ExpectNotRestored({NotRestoredReason::kCacheLimit}, {}, {}, {}, {}, + FROM_HERE); + } + } +} + +// Test that pruning a series of cross-site navigations (which use different +// processes) evicts the right entries with the right reason. +IN_PROC_BROWSER_TEST_F( + BackgroundForegroundProcessLimitBackForwardCacheBrowserTest, + PruneCrossSite) { + ASSERT_TRUE(embedded_test_server()->Start()); + + std::vector<RenderFrameHostImplWrapper> rfhs; + + for (size_t i = 0; i < kBackForwardCacheSize; ++i) { + SCOPED_TRACE(i); + // Note: do NOT use .com domains here because a4.com is on the HSTS preload + // list, which will cause our test requests to timeout. + GURL url(embedded_test_server()->GetURL(base::StringPrintf("a%zu.test", i), + "/title1.html")); + ASSERT_TRUE(NavigateToURL(shell(), url)); + rfhs.emplace_back(current_frame_host()); + EXPECT_NE(rfhs.back()->GetProcess()->GetPriority(), + base::Process::Priority::kBestEffort); + } + + CHECK_LE(kPruneSize, kBackForwardCacheSize); + + // Prune the BFCache entries. + web_contents()->GetController().GetBackForwardCache().Prune(kPruneSize, + kPruneReason); + + for (int i = kBackForwardCacheSize - 1 - 1 - kPruneSize; i >= 0; --i) { + SCOPED_TRACE(i); + ASSERT_TRUE(rfhs[i].WaitUntilRenderFrameDeleted()); + } + + // Navigate back but not to the initial about:blank. + for (size_t i = 0; i < kBackForwardCacheSize - 1; ++i) { + SCOPED_TRACE(i); + ASSERT_TRUE(HistoryGoBack(web_contents())); + // The first `kPruneSize` navigation should be restored from the cache. The + // rest should not. + if (i < kPruneSize) { + ExpectRestored(FROM_HERE); + } else { + ExpectNotRestored({kPruneReason}, {}, {}, {}, {}, FROM_HERE); + } + } +} + +namespace { + +const char kPrioritizedPageURL[] = "search.result"; + +} // namespace + +class BackForwardCacheLimitForPrioritizedPagesBrowserTest + : public BackgroundForegroundProcessLimitBackForwardCacheBrowserTest { + protected: + // Mock subclass of ContentBrowserClient that will determine if the url is + // prioritized by checking against `kPrioritizedPageURL`. + class MockContentBrowserClientWithPrioritizedBackForwardCacheEntry + : public ContentBrowserTestContentBrowserClient { + public: + // ContentBrowserClient overrides: + bool ShouldPrioritizeForBackForwardCache(BrowserContext* browser_context, + const GURL& url) override { + return url.DomainIs(kPrioritizedPageURL); + } + }; + + void SetUpOnMainThread() override { + BackgroundForegroundProcessLimitBackForwardCacheBrowserTest:: + SetUpOnMainThread(); + test_client_ = std::make_unique< + MockContentBrowserClientWithPrioritizedBackForwardCacheEntry>(); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + BackgroundForegroundProcessLimitBackForwardCacheBrowserTest:: + SetUpCommandLine(command_line); + feature_list_.InitAndEnableFeature( + content::kBackForwardCachePrioritizedEntry); + } + + private: + std::unique_ptr<MockContentBrowserClientWithPrioritizedBackForwardCacheEntry> + test_client_; + base::test::ScopedFeatureList feature_list_; +}; + +// Test that both prioritized entries and non-prioritized entries would be +// evicted when pruning with size 0. +IN_PROC_BROWSER_TEST_F(BackForwardCacheLimitForPrioritizedPagesBrowserTest, + PruneToZero) { + ASSERT_TRUE(embedded_test_server()->Start()); + + // We need at least 4 entries in the BFCache list for this test. + CHECK_GE(kBackForwardCacheSize, 2u); + + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("a.test", "/title1.html"))); + ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( + kPrioritizedPageURL, "/title1.html"))); + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("b.test", "/title1.html"))); + + // Now the BFCache entry list is: [a, pp, b]. + // Prune the BFCache entries to 0. + web_contents()->GetController().GetBackForwardCache().Prune(0, kPruneReason); + // All the entries should be evicted + for (size_t i = 0; i < 2; ++i) { + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectNotRestored({kPruneReason}, {}, {}, {}, {}, FROM_HERE); + } +} + +// Test that when pruning with a positive number size, the last prioritized +// entry outside the limit will not be evicted. +IN_PROC_BROWSER_TEST_F(BackForwardCacheLimitForPrioritizedPagesBrowserTest, + PruneToNonZero_PrioritizedEntryOutsideLimit) { + ASSERT_TRUE(embedded_test_server()->Start()); + + // We need at least 4 entries in the BFCache list for this test. + CHECK_GE(kBackForwardCacheSize, 4u); + + ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( + kPrioritizedPageURL, "/title1.html"))); + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("a.test", "/title1.html"))); + ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( + kPrioritizedPageURL, "/title2.html"))); + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("b.test", "/title1.html"))); + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("c.test", "/title1.html"))); + + // Now the BFCache entry list is: [pe1, a, pe2, b]. + // Prune the BFCache entries to 1, the result should be: + // [pe1(evicted), a(evicted), pe2(prioritized entry special rule), b]. + web_contents()->GetController().GetBackForwardCache().Prune(1, kPruneReason); + + // The last non-prioritized entry should be restored because it's within the + // cache limit. + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectRestored(FROM_HERE); + // The last prioritized entry should be restored since it's the special + // prioritized entry. + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectRestored(FROM_HERE); + // The other entries (including the prioritized one) should not be restored. + for (size_t i = 0; i < 2; ++i) { + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectNotRestored({kPruneReason}, {}, {}, {}, {}, FROM_HERE); + } +} + +// Test that when pruning with a positive number size, the last prioritized +// entry inside the limit should be counted as the regular cache. +IN_PROC_BROWSER_TEST_F(BackForwardCacheLimitForPrioritizedPagesBrowserTest, + PruneToNonZero_PrioritizedEntryInsideLimit) { + ASSERT_TRUE(embedded_test_server()->Start()); + + // We need at least 2 entries in the BFCache list for this test. + CHECK_GE(kBackForwardCacheSize, 2u); + + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("a.test", "/title1.html"))); + ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( + kPrioritizedPageURL, "/title2.html"))); + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("b.test", "/title1.html"))); + + // Now the BFCache entry list is: [a, pe]. + // Prune the BFCache entries to 1, the result should be: + // [a(evicted), pe]. + web_contents()->GetController().GetBackForwardCache().Prune(1, kPruneReason); + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectRestored(FROM_HERE); + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectNotRestored({kPruneReason}, {}, {}, {}, {}, FROM_HERE); +} + +// Test that when pruning with a positive number size while there is already an +// old prioritized entry kept in cache before, it will be replaced by the newer +// prioritized entry. +IN_PROC_BROWSER_TEST_F(BackForwardCacheLimitForPrioritizedPagesBrowserTest, + PruneToNonZeroTwice) { + ASSERT_TRUE(embedded_test_server()->Start()); + + // We need at least 4 entries in the BFCache list for this test. + CHECK_LE(kBackForwardCacheSize, 4u); + + ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( + kPrioritizedPageURL, "/title1.html"))); + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("a.test", "/title1.html"))); + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("b.test", "/title1.html"))); + + // Now the BFCache entry list is: [pe1, a]. + // Prune the BFCache entries to 1, the result should still be + // [pe1(prioritized entry special rule), a]. + web_contents()->GetController().GetBackForwardCache().Prune(1, kPruneReason); + + // The last non-prioritized entry should be restored because it's within the + // cache limit. + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectRestored(FROM_HERE); + // The last prioritized entry should be restored since it's the special + // prioritized entry. + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectRestored(FROM_HERE); + + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("c.test", "/title1.html"))); + ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( + kPrioritizedPageURL, "/title2.html"))); + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("d.test", "/title1.html"))); + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("e.test", "/title1.html"))); + + // Now the BFCache entry list is: [pe1, c, pe2, d]. + // Prune the BFCache entries to 1, the result should still be + // [pe1(evicted), a(evicted), pe2(prioritized entry special rule), d]. + web_contents()->GetController().GetBackForwardCache().Prune(1, kPruneReason); + + // The last non-prioritized entry should be restored because it's within the + // cache limit. + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectRestored(FROM_HERE); + // The last prioritized entry should be restored since it's the special + // prioritized entry. + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectRestored(FROM_HERE); + // The other entries (including the prioritized one) should not be restored. + for (size_t i = 0; i < 2; ++i) { + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectNotRestored({kPruneReason}, {}, {}, {}, {}, FROM_HERE); + } +} + +// Test that the prioritized BFCache entry will not be evicted even when another +// entry is stored and exceeds the limit. +IN_PROC_BROWSER_TEST_F(BackForwardCacheLimitForPrioritizedPagesBrowserTest, + CacheLimitReached) { + ASSERT_TRUE(embedded_test_server()->Start()); + + // We need at least 1 entry in the BFCache list for this test. + CHECK_GE(kBackForwardCacheSize, 1u); + + ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( + kPrioritizedPageURL, "/title1.html"))); + + // Fill the BFCache with more entry and make it just exceeds the limit, the + // result should be: + // [pe(prioritized entry special rule), a0, a1, ...]. + for (size_t i = 0; i <= kBackForwardCacheSize; ++i) { + ASSERT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL( + base::StringPrintf("a%zu.test", i), "/title1.html"))); + } + // For the entries within cache size limit, they should be restored. + for (size_t i = 0; i < kBackForwardCacheSize; ++i) { + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectRestored(FROM_HERE); + } + // The prioritized entry should be restored as well even if it's outside the + // limit. + ASSERT_TRUE(HistoryGoBack(web_contents())); + ExpectRestored(FROM_HERE); +} + +// Test that the cache responds to processes switching from background to +// foreground. We set things up so that we have +// Cached sites: +// a0.test +// a1.test +// a2.test +// a3.test +// and the active page is a4.test. Then set the process for a[1-3] to +// foregrounded so that there are 3 entries whose processes are foregrounded. +// BFCache should evict the eldest (a1) leaving a0 because despite being older, +// it is backgrounded. Setting the priority directly is not ideal but there is +// no reliable way to cause the processes to go into the foreground just by +// navigating because proactive browsing instance swap makes it impossible to +// reliably create a new a1.test renderer in the same process as the old +// a1.test. +// +// Note that we do NOT use .com domains because a4.com is on the HSTS preload +// list. Since our test server doesn't use HTTPS, using a4.com results in the +// test timing out. +IN_PROC_BROWSER_TEST_F( + BackgroundForegroundProcessLimitBackForwardCacheBrowserTest, + ChangeToForeground) { + ASSERT_TRUE(embedded_test_server()->Start()); + + std::vector<RenderFrameHostImplWrapper> rfhs; + + // Navigate through a[0-3].com. + for (size_t i = 0; i < kBackForwardCacheSize; ++i) { + SCOPED_TRACE(i); + GURL url(embedded_test_server()->GetURL(base::StringPrintf("a%zu.test", i), + "/title1.html")); + ASSERT_TRUE(NavigateToURL(shell(), url)); + rfhs.emplace_back(current_frame_host()); + EXPECT_NE(rfhs.back()->GetProcess()->GetPriority(), + base::Process::Priority::kBestEffort); + } + // Check that a0-2 are cached and backgrounded. + for (size_t i = 0; i < kBackForwardCacheSize - 1; ++i) { + SCOPED_TRACE(i); + ExpectCached(rfhs[i], /*cached=*/true, /*backgrounded=*/true); + } + + // Navigate to a page which causes the processes for a[1-3] to be + // foregrounded. + GURL url(embedded_test_server()->GetURL("a4.test", "/title1.html")); + ASSERT_TRUE(NavigateToURL(shell(), url)); + + // Assert that we really have set up the situation we want where the processes + // are shared and in the foreground. + RenderFrameHostImpl* rfh = current_frame_host(); + ASSERT_NE(rfh->GetProcess()->GetPriority(), + base::Process::Priority::kBestEffort); + + rfhs[1]->GetProcess()->OnMediaStreamAdded(); + rfhs[2]->GetProcess()->OnMediaStreamAdded(); + rfhs[3]->GetProcess()->OnMediaStreamAdded(); + + // The page should be evicted. + ASSERT_TRUE(rfhs[1].WaitUntilRenderFrameDeleted()); + + // Check that a0 is cached and backgrounded. + ExpectCached(rfhs[0], /*cached=*/true, /*backgrounded=*/true); + // Check that a2-3 are cached and foregrounded. + ExpectCached(rfhs[2], /*cached=*/true, /*backgrounded=*/false); + ExpectCached(rfhs[3], /*cached=*/true, /*backgrounded=*/false); +} + +} // namespace content
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index f2d1e043..455c2b66 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc
@@ -164,12 +164,12 @@ void ChildProcessLauncher::SetProcessPriority( base::Process::Priority priority) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - base::Process to_pass = process_.process.Duplicate(); - GetProcessLauncherTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce( - &ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread, - helper_, std::move(to_pass), priority)); + + if (priority == priority_) { + return; + } + + SetProcessPriorityImpl(priority); } #endif // !BUILDFLAG(IS_ANDROID) @@ -186,6 +186,18 @@ if (process_.process.IsValid()) { process_start_time_ = base::TimeTicks::Now(); + +#if BUILDFLAG(IS_MAC) + // On mac, the task port is required to change the priority of the child + // process. + auto* port_provider = ChildProcessTaskPortProvider::GetInstance(); + CHECK(port_provider); + CHECK(port_provider->TaskForHandle(process_.process.Handle()) == + MACH_PORT_NULL); + scoped_port_provider_observation_.Observe(port_provider); +#endif + + // Note:: May delete |this|. client_->OnProcessLaunched(); } else { termination_info_.status = base::TERMINATION_STATUS_LAUNCH_FAILED; @@ -199,6 +211,35 @@ } } +#if BUILDFLAG(IS_MAC) +void ChildProcessLauncher::OnReceivedTaskPort( + base::ProcessHandle process_handle) { + if (!process_.process.IsValid()) { + // The process has died since. No need to keep observing for task ports. + scoped_port_provider_observation_.Reset(); + return; + } + + if (process_.process.Handle() == process_handle && priority_) { + SetProcessPriorityImpl(*priority_); + scoped_port_provider_observation_.Reset(); + } +} +#endif + +#if !BUILDFLAG(IS_ANDROID) +void ChildProcessLauncher::SetProcessPriorityImpl( + base::Process::Priority priority) { + priority_ = priority; + base::Process to_pass = process_.process.Duplicate(); + GetProcessLauncherTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce( + &ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread, + helper_, std::move(to_pass), priority)); +} +#endif + bool ChildProcessLauncher::IsStarting() { DCHECK_CURRENTLY_ON(BrowserThread::UI); return starting_;
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h index ac6f72c9..4c3d991 100644 --- a/content/browser/child_process_launcher.h +++ b/content/browser/child_process_launcher.h
@@ -39,6 +39,11 @@ #include "base/files/scoped_file.h" #endif +#if BUILDFLAG(IS_MAC) +#include "base/process/port_provider_mac.h" +#include "base/scoped_observation.h" +#endif + namespace base { class CommandLine; class UnsafeSharedMemoryRegion; @@ -208,7 +213,14 @@ // Launches a process asynchronously and notifies the client of the process // handle when it's available. It's used to avoid blocking the calling thread // on the OS since often it can take > 100 ms to create the process. -class CONTENT_EXPORT ChildProcessLauncher { + +// On MacOS, observes the PortProvider to allow re-setting the priority of the +// process when its task port is available. +class CONTENT_EXPORT ChildProcessLauncher +#if BUILDFLAG(IS_MAC) + : public base::PortProvider::Observer +#endif +{ public: class CONTENT_EXPORT Client { public: @@ -255,7 +267,11 @@ ChildProcessLauncher(const ChildProcessLauncher&) = delete; ChildProcessLauncher& operator=(const ChildProcessLauncher&) = delete; - ~ChildProcessLauncher(); + ~ChildProcessLauncher() +#if BUILDFLAG(IS_MAC) + override +#endif + ; // True if the process is being launched and so the handle isn't available. bool IsStarting(); @@ -315,6 +331,15 @@ #endif int error_code); +#if BUILDFLAG(IS_MAC) + // base::PortProvider::Observer: + void OnReceivedTaskPort(base::ProcessHandle process_handle) override; +#endif + +#if !BUILDFLAG(IS_ANDROID) + void SetProcessPriorityImpl(base::Process::Priority priority); +#endif + raw_ptr<Client> client_; // The process associated with this ChildProcessLauncher. Set in Notify by @@ -335,6 +360,18 @@ scoped_refptr<internal::ChildProcessLauncherHelper> helper_; + // The priority of the process. The state is stored to avoid changing the + // setting repeatedly. + // + // On MacOS, this is also used to re-set the priority when the task port of + // the process is available. + std::optional<base::Process::Priority> priority_; + +#if BUILDFLAG(IS_MAC) + base::ScopedObservation<base::PortProvider, base::PortProvider::Observer> + scoped_port_provider_observation_{this}; +#endif + base::WeakPtrFactory<ChildProcessLauncher> weak_factory_{this}; };
diff --git a/content/browser/child_process_launcher_helper.h b/content/browser/child_process_launcher_helper.h index 9f387b3..e65d866 100644 --- a/content/browser/child_process_launcher_helper.h +++ b/content/browser/child_process_launcher_helper.h
@@ -308,12 +308,6 @@ std::optional<base::ProcessId> process_id_ = std::nullopt; #endif // BUILDFLAG(IS_CHROMEOS) -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) - // The priority of the process. The state is stored to avoid changing the - // setting repeatedly. - std::optional<base::Process::Priority> priority_; -#endif - // The PlatformChannel that will be used to transmit an invitation to the // child process in most cases. Only used if the platform's helper // implementation doesn't return a server endpoint from
diff --git a/content/browser/child_process_launcher_helper_linux.cc b/content/browser/child_process_launcher_helper_linux.cc index add20a2f..75cafbe 100644 --- a/content/browser/child_process_launcher_helper_linux.cc +++ b/content/browser/child_process_launcher_helper_linux.cc
@@ -176,8 +176,7 @@ base::Process process, base::Process::Priority priority) { DCHECK(CurrentlyOnProcessLauncherTaskRunner()); - if (process.CanSetPriority() && priority_ != priority) { - priority_ = priority; + if (process.CanSetPriority()) { process.SetPriority(priority); } }
diff --git a/content/browser/child_process_launcher_helper_win.cc b/content/browser/child_process_launcher_helper_win.cc index cb0e7d5..0791b531 100644 --- a/content/browser/child_process_launcher_helper_win.cc +++ b/content/browser/child_process_launcher_helper_win.cc
@@ -209,8 +209,7 @@ base::Process process, base::Process::Priority priority) { DCHECK(CurrentlyOnProcessLauncherTaskRunner()); - if (process.CanSetPriority() && priority_ != priority) { - priority_ = priority; + if (process.CanSetPriority()) { process.SetPriority(priority); } }
diff --git a/content/browser/cookie_store/OWNERS b/content/browser/cookie_store/OWNERS index 20d73976..baf338e 100644 --- a/content/browser/cookie_store/OWNERS +++ b/content/browser/cookie_store/OWNERS
@@ -1,3 +1,4 @@ +dylancutler@google.com fergal@chromium.org horo@chromium.org leimy@chromium.org
diff --git a/content/browser/first_party_sets/database/first_party_sets_database.cc b/content/browser/first_party_sets/database/first_party_sets_database.cc index ad02abc..d864ad4 100644 --- a/content/browser/first_party_sets/database/first_party_sets_database.cc +++ b/content/browser/first_party_sets/database/first_party_sets_database.cc
@@ -448,8 +448,7 @@ if (site.has_value() && primary.has_value() && site_type.has_value()) { entries.emplace_back( site.value(), - net::FirstPartySetEntry(primary.value(), site_type.value(), - /*site_index=*/std::nullopt)); + net::FirstPartySetEntry(primary.value(), site_type.value())); validator.Update(site.value(), primary.value()); } } @@ -646,11 +645,10 @@ entry_override = net::FirstPartySetEntryOverride(net::FirstPartySetEntry( maybe_primary_site.value(), - // TODO(crbug.com/40186153): May change to use the - // real site_type and site_index in the future, depending on - // the design details. Use kAssociated as default site type - // and null site index for now. - net::SiteType::kAssociated, std::nullopt)); + // TODO(crbug.com/40186153): May change to use the real + // site_type in the future, depending on the design details. Use + // kAssociated as default site type for now. + net::SiteType::kAssociated)); } results.emplace_back(std::move(site).value(), std::move(entry_override)); } @@ -725,11 +723,7 @@ if (maybe_primary_site.has_value() && maybe_site_type.has_value()) { entry_override = net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - maybe_primary_site.value(), - // TODO(crbug.com/40186153): May change to use the - // real site_index in the future, depending on the design - // details. Use null site index for now. - maybe_site_type.value(), std::nullopt)); + maybe_primary_site.value(), maybe_site_type.value())); } results.emplace_back(std::move(site).value(), std::move(entry_override)); }
diff --git a/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc b/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc index d825955..9682fd65 100644 --- a/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc +++ b/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc
@@ -317,18 +317,18 @@ /*entries=*/ {{net::SchemefulSite(GURL(site)), net::FirstPartySetEntry(net::SchemefulSite(GURL(primary)), - net::SiteType::kAssociated, std::nullopt)}, + net::SiteType::kAssociated)}, {net::SchemefulSite(GURL(primary)), net::FirstPartySetEntry(net::SchemefulSite(GURL(primary)), - net::SiteType::kPrimary, std::nullopt)}}, + net::SiteType::kPrimary)}}, /*aliases=*/{}); base::flat_map<net::SchemefulSite, net::FirstPartySetEntry> manual_sets = { {net::SchemefulSite(GURL(manual_site)), net::FirstPartySetEntry(net::SchemefulSite(GURL(manual_primary)), - net::SiteType::kAssociated, std::nullopt)}, + net::SiteType::kAssociated)}, {net::SchemefulSite(GURL(manual_primary)), net::FirstPartySetEntry(net::SchemefulSite(GURL(manual_primary)), - net::SiteType::kPrimary, std::nullopt)}}; + net::SiteType::kPrimary)}}; global_sets.ApplyManuallySpecifiedSet( net::LocalSetDeclaration::Create(/*set_entries=*/manual_sets, /*aliases=*/{}) @@ -337,9 +337,9 @@ net::FirstPartySetsContextConfig config = net::FirstPartySetsContextConfig::Create( {{net::SchemefulSite(GURL(site_member1)), - net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - net::SchemefulSite(GURL(primary_site)), - net::SiteType::kAssociated, std::nullopt))}, + net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(net::SchemefulSite(GURL(primary_site)), + net::SiteType::kAssociated))}, {net::SchemefulSite(GURL(site_member2)), net::FirstPartySetEntryOverride()}}) .value(); @@ -435,19 +435,19 @@ /*entries=*/ {{net::SchemefulSite(GURL(site)), net::FirstPartySetEntry(net::SchemefulSite(GURL(primary)), - net::SiteType::kAssociated, std::nullopt)}, + net::SiteType::kAssociated)}, {net::SchemefulSite(GURL(primary)), net::FirstPartySetEntry(net::SchemefulSite(GURL(primary)), - net::SiteType::kPrimary, std::nullopt)}}, + net::SiteType::kPrimary)}}, /*aliases=*/{}); base::flat_map<net::SchemefulSite, net::FirstPartySetEntry> manual_sets = { {net::SchemefulSite(GURL(manual_site)), net::FirstPartySetEntry(net::SchemefulSite(GURL(manual_primary)), - net::SiteType::kAssociated, std::nullopt)}, + net::SiteType::kAssociated)}, {net::SchemefulSite(GURL(manual_primary)), net::FirstPartySetEntry(net::SchemefulSite(GURL(manual_primary)), - net::SiteType::kPrimary, std::nullopt)}}; + net::SiteType::kPrimary)}}; global_sets.ApplyManuallySpecifiedSet( net::LocalSetDeclaration::Create(/*set_entries=*/manual_sets, /*aliases=*/{}) @@ -456,9 +456,9 @@ net::FirstPartySetsContextConfig config = net::FirstPartySetsContextConfig::Create( {{net::SchemefulSite(GURL(site_member1)), - net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - net::SchemefulSite(GURL(primary_site)), - net::SiteType::kAssociated, std::nullopt))}, + net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(net::SchemefulSite(GURL(primary_site)), + net::SiteType::kAssociated))}, {net::SchemefulSite(GURL(site_member2)), net::FirstPartySetEntryOverride()}}) .value(); @@ -586,19 +586,19 @@ /*entries=*/ {{net::SchemefulSite(GURL(site)), net::FirstPartySetEntry(net::SchemefulSite(GURL(primary)), - net::SiteType::kAssociated, std::nullopt)}, + net::SiteType::kAssociated)}, {net::SchemefulSite(GURL(primary)), net::FirstPartySetEntry(net::SchemefulSite(GURL(primary)), - net::SiteType::kPrimary, std::nullopt)}}, + net::SiteType::kPrimary)}}, /*aliases=*/{}); base::flat_map<net::SchemefulSite, net::FirstPartySetEntry> manual_sets = { {net::SchemefulSite(GURL(manual_site)), net::FirstPartySetEntry(net::SchemefulSite(GURL(manual_primary)), - net::SiteType::kAssociated, std::nullopt)}, + net::SiteType::kAssociated)}, {net::SchemefulSite(GURL(manual_primary)), net::FirstPartySetEntry(net::SchemefulSite(GURL(manual_primary)), - net::SiteType::kPrimary, std::nullopt)}}; + net::SiteType::kPrimary)}}; global_sets.ApplyManuallySpecifiedSet( net::LocalSetDeclaration::Create(/*set_entries=*/manual_sets, /*aliases=*/{}) @@ -607,9 +607,9 @@ net::FirstPartySetsContextConfig config = net::FirstPartySetsContextConfig::Create( {{net::SchemefulSite(GURL(site_member1)), - net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - net::SchemefulSite(GURL(primary_site)), - net::SiteType::kAssociated, std::nullopt))}, + net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(net::SchemefulSite(GURL(primary_site)), + net::SiteType::kAssociated))}, {net::SchemefulSite(GURL(site_member2)), net::FirstPartySetEntryOverride()}}) .value(); @@ -720,10 +720,10 @@ /*entries=*/ {{net::SchemefulSite(GURL(site)), net::FirstPartySetEntry(net::SchemefulSite(GURL(primary)), - net::SiteType::kAssociated, std::nullopt)}, + net::SiteType::kAssociated)}, {net::SchemefulSite(GURL(primary)), net::FirstPartySetEntry(net::SchemefulSite(GURL(primary)), - net::SiteType::kPrimary, std::nullopt)}}, + net::SiteType::kPrimary)}}, /*aliases=*/{}); OpenDatabase(); @@ -989,19 +989,15 @@ net::GlobalFirstPartySets global_sets( base::Version(), /*entries=*/ - {{site, net::FirstPartySetEntry(primary, net::SiteType::kAssociated, - std::nullopt)}, - {primary, net::FirstPartySetEntry(primary, net::SiteType::kPrimary, - std::nullopt)}}, + {{site, net::FirstPartySetEntry(primary, net::SiteType::kAssociated)}, + {primary, net::FirstPartySetEntry(primary, net::SiteType::kPrimary)}}, /*aliases=*/{}); base::flat_map<net::SchemefulSite, net::FirstPartySetEntry> manual_sets = { {manual_site, - net::FirstPartySetEntry(manual_primary, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(manual_primary, net::SiteType::kAssociated)}, {manual_primary, - net::FirstPartySetEntry(manual_primary, net::SiteType::kPrimary, - std::nullopt)}}; + net::FirstPartySetEntry(manual_primary, net::SiteType::kPrimary)}}; global_sets.ApplyManuallySpecifiedSet( net::LocalSetDeclaration::Create(/*set_entries=*/manual_sets, /*aliases=*/{}) @@ -1022,12 +1018,10 @@ res->first.FindEntries({manual_site, manual_primary}, net::FirstPartySetsContextConfig()), UnorderedElementsAre( - Pair(manual_site, - net::FirstPartySetEntry( - manual_primary, net::SiteType::kAssociated, std::nullopt)), - Pair(manual_primary, - net::FirstPartySetEntry(manual_primary, net::SiteType::kPrimary, - std::nullopt)))); + Pair(manual_site, net::FirstPartySetEntry( + manual_primary, net::SiteType::kAssociated)), + Pair(manual_primary, net::FirstPartySetEntry( + manual_primary, net::SiteType::kPrimary)))); EXPECT_TRUE(res->second.empty()); } @@ -1054,13 +1048,12 @@ res = db()->GetGlobalSetsAndConfig("b0"); EXPECT_TRUE(res.has_value()); // The singleton set should be deleted. - EXPECT_THAT(res->first.FindEntries({aaa, bbb, ccc, ddd}, - net::FirstPartySetsContextConfig()), - UnorderedElementsAre( - Pair(ccc, net::FirstPartySetEntry( - ddd, net::SiteType::kAssociated, std::nullopt)), - Pair(ddd, net::FirstPartySetEntry( - ddd, net::SiteType::kPrimary, std::nullopt)))); + EXPECT_THAT( + res->first.FindEntries({aaa, bbb, ccc, ddd}, + net::FirstPartySetsContextConfig()), + UnorderedElementsAre( + Pair(ccc, net::FirstPartySetEntry(ddd, net::SiteType::kAssociated)), + Pair(ddd, net::FirstPartySetEntry(ddd, net::SiteType::kPrimary)))); EXPECT_EQ(res->second, net::FirstPartySetsContextConfig()); } @@ -1087,13 +1080,12 @@ res = db()->GetGlobalSetsAndConfig("b0"); EXPECT_TRUE(res.has_value()); // The singleton set should be deleted. - EXPECT_THAT(res->first.FindEntries({aaa, bbb, ccc, ddd}, - net::FirstPartySetsContextConfig()), - UnorderedElementsAre( - Pair(ccc, net::FirstPartySetEntry( - ddd, net::SiteType::kAssociated, std::nullopt)), - Pair(ddd, net::FirstPartySetEntry( - ddd, net::SiteType::kPrimary, std::nullopt)))); + EXPECT_THAT( + res->first.FindEntries({aaa, bbb, ccc, ddd}, + net::FirstPartySetsContextConfig()), + UnorderedElementsAre( + Pair(ccc, net::FirstPartySetEntry(ddd, net::SiteType::kAssociated)), + Pair(ddd, net::FirstPartySetEntry(ddd, net::SiteType::kPrimary)))); EXPECT_EQ(res->second, net::FirstPartySetsContextConfig()); } @@ -1119,17 +1111,14 @@ std::pair<net::GlobalFirstPartySets, net::FirstPartySetsContextConfig>> res = db()->GetGlobalSetsAndConfig("b0"); EXPECT_TRUE(res.has_value()); - EXPECT_THAT(res->first.FindEntries({aaa, bbb, ccc, ddd}, - net::FirstPartySetsContextConfig()), - UnorderedElementsAre( - Pair(aaa, net::FirstPartySetEntry( - bbb, net::SiteType::kAssociated, std::nullopt)), - Pair(bbb, net::FirstPartySetEntry( - bbb, net::SiteType::kPrimary, std::nullopt)), - Pair(ccc, net::FirstPartySetEntry( - ddd, net::SiteType::kAssociated, std::nullopt)), - Pair(ddd, net::FirstPartySetEntry( - ddd, net::SiteType::kPrimary, std::nullopt)))); + EXPECT_THAT( + res->first.FindEntries({aaa, bbb, ccc, ddd}, + net::FirstPartySetsContextConfig()), + UnorderedElementsAre( + Pair(aaa, net::FirstPartySetEntry(bbb, net::SiteType::kAssociated)), + Pair(bbb, net::FirstPartySetEntry(bbb, net::SiteType::kPrimary)), + Pair(ccc, net::FirstPartySetEntry(ddd, net::SiteType::kAssociated)), + Pair(ddd, net::FirstPartySetEntry(ddd, net::SiteType::kPrimary)))); EXPECT_EQ(res->second, net::FirstPartySetsContextConfig()); } @@ -1173,23 +1162,18 @@ version, /*entries=*/ {{associated_site, - net::FirstPartySetEntry(primary, net::SiteType::kAssociated, - std::nullopt)}, - {service_site, net::FirstPartySetEntry(primary, net::SiteType::kService, - std::nullopt)}, - {primary, net::FirstPartySetEntry(primary, net::SiteType::kPrimary, - std::nullopt)}}, + net::FirstPartySetEntry(primary, net::SiteType::kAssociated)}, + {service_site, + net::FirstPartySetEntry(primary, net::SiteType::kService)}, + {primary, net::FirstPartySetEntry(primary, net::SiteType::kPrimary)}}, /*aliases=*/{}); base::flat_map<net::SchemefulSite, net::FirstPartySetEntry> manual_sets = { {manual_associated_site, - net::FirstPartySetEntry(manual_primary, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(manual_primary, net::SiteType::kAssociated)}, {manual_service_site, - net::FirstPartySetEntry(manual_primary, net::SiteType::kService, - std::nullopt)}, + net::FirstPartySetEntry(manual_primary, net::SiteType::kService)}, {manual_primary, - net::FirstPartySetEntry(manual_primary, net::SiteType::kPrimary, - std::nullopt)}}; + net::FirstPartySetEntry(manual_primary, net::SiteType::kPrimary)}}; global_sets.ApplyManuallySpecifiedSet( net::LocalSetDeclaration::Create(/*set_entries=*/manual_sets, /*aliases=*/{}) @@ -1199,8 +1183,7 @@ net::FirstPartySetsContextConfig::Create( {{config_site_member1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - config_primary_site, net::SiteType::kAssociated, - std::nullopt))}, + config_primary_site, net::SiteType::kAssociated))}, {config_site_member2, net::FirstPartySetEntryOverride()}}) .value();
diff --git a/content/browser/first_party_sets/first_party_set_parser.cc b/content/browser/first_party_sets/first_party_set_parser.cc index f455f30..49e2df3 100644 --- a/content/browser/first_party_sets/first_party_set_parser.cc +++ b/content/browser/first_party_sets/first_party_set_parser.cc
@@ -256,9 +256,8 @@ const net::SchemefulSite& primary = primary_result.site(); std::vector<std::pair<net::SchemefulSite, net::FirstPartySetEntry>> - set_entries( - {{primary, net::FirstPartySetEntry(primary, net::SiteType::kPrimary, - std::nullopt)}}); + set_entries({{primary, net::FirstPartySetEntry( + primary, net::SiteType::kPrimary)}}); for (const SubsetDescriptor& descriptor : { SubsetDescriptor{ @@ -472,12 +471,7 @@ static_cast<int>(index) < descriptor.size_limit.value()) { set_entries.emplace_back( site_result.site(), - net::FirstPartySetEntry( - primary, descriptor.site_type, - descriptor.size_limit.has_value() - ? std::make_optional( - net::FirstPartySetEntry::SiteIndex(index)) - : std::nullopt)); + net::FirstPartySetEntry(primary, descriptor.site_type)); } // Continue parsing even after we've reached the size limit (if there is // one), in order to surface malformed input domains as errors.
diff --git a/content/browser/first_party_sets/first_party_set_parser_unittest.cc b/content/browser/first_party_sets/first_party_set_parser_unittest.cc index cdabda3..22cc4a9 100644 --- a/content/browser/first_party_sets/first_party_set_parser_unittest.cc +++ b/content/browser/first_party_sets/first_party_set_parser_unittest.cc
@@ -105,18 +105,17 @@ net::SchemefulSite example(GURL("https://example.test")); net::SchemefulSite aaaa(GURL("https://aaaa.test")); - EXPECT_EQ( - ParseSets(R"({"primary": "https://example.test",)" - R"("associatedSites": ["https://aaaa.test"]})"), - net::GlobalFirstPartySets( - kVersion, - { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, - {aaaa, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - }, - {})); + EXPECT_EQ(ParseSets(R"({"primary": "https://example.test",)" + R"("associatedSites": ["https://aaaa.test"]})"), + net::GlobalFirstPartySets( + kVersion, + { + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {aaaa, net::FirstPartySetEntry(example, + net::SiteType::kAssociated)}, + }, + {})); } TEST(FirstPartySetParser, AcceptsMinimal_Service) { @@ -129,10 +128,9 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, - {aaaa, net::FirstPartySetEntry(example, net::SiteType::kService, - std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {aaaa, net::FirstPartySetEntry(example, net::SiteType::kService)}, }, {})); } @@ -159,12 +157,10 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, - {a, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {b, net::FirstPartySetEntry(example, net::SiteType::kService, - std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {a, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {b, net::FirstPartySetEntry(example, net::SiteType::kService)}, }, {{example_cctld, example}, {a_cctld, a}, {b_cctld, b}})); histogram_tester.ExpectUniqueSample( @@ -220,10 +216,10 @@ net::GlobalFirstPartySets( kVersion, { - {example2, net::FirstPartySetEntry( - example2, net::SiteType::kPrimary, std::nullopt)}, - {associated2, net::FirstPartySetEntry( - example2, net::SiteType::kAssociated, 0)}, + {example2, + net::FirstPartySetEntry(example2, net::SiteType::kPrimary)}, + {associated2, + net::FirstPartySetEntry(example2, net::SiteType::kAssociated)}, }, {})); } @@ -247,14 +243,14 @@ net::GlobalFirstPartySets( kVersion, { - {example2, net::FirstPartySetEntry( - example2, net::SiteType::kPrimary, std::nullopt)}, - {associated2, net::FirstPartySetEntry( - example2, net::SiteType::kAssociated, 0)}, - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example2, + net::FirstPartySetEntry(example2, net::SiteType::kPrimary)}, + {associated2, + net::FirstPartySetEntry(example2, net::SiteType::kAssociated)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {aaaa, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, }, {})); histogram_tester.ExpectUniqueSample( @@ -280,10 +276,10 @@ net::GlobalFirstPartySets( kVersion, { - {example2, net::FirstPartySetEntry( - example2, net::SiteType::kPrimary, std::nullopt)}, - {associated2, net::FirstPartySetEntry( - example2, net::SiteType::kAssociated, 0)}, + {example2, + net::FirstPartySetEntry(example2, net::SiteType::kPrimary)}, + {associated2, + net::FirstPartySetEntry(example2, net::SiteType::kAssociated)}, }, {})); histogram_tester.ExpectUniqueSample( @@ -333,14 +329,14 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {associated1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {example2, net::FirstPartySetEntry( - example2, net::SiteType::kPrimary, std::nullopt)}, - {associated2, net::FirstPartySetEntry( - example2, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {example2, + net::FirstPartySetEntry(example2, net::SiteType::kPrimary)}, + {associated2, + net::FirstPartySetEntry(example2, net::SiteType::kAssociated)}, }, {})); } @@ -360,14 +356,14 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {associated1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {example2, net::FirstPartySetEntry( - example2, net::SiteType::kPrimary, std::nullopt)}, - {associated2, net::FirstPartySetEntry( - example2, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {example2, + net::FirstPartySetEntry(example2, net::SiteType::kPrimary)}, + {associated2, + net::FirstPartySetEntry(example2, net::SiteType::kAssociated)}, }, {})); } @@ -392,18 +388,18 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {associated1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {example2, net::FirstPartySetEntry( - example2, net::SiteType::kPrimary, std::nullopt)}, - {associated2, net::FirstPartySetEntry( - example2, net::SiteType::kAssociated, 0)}, - {example3, net::FirstPartySetEntry( - example3, net::SiteType::kPrimary, std::nullopt)}, - {associated3, net::FirstPartySetEntry( - example3, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {example2, + net::FirstPartySetEntry(example2, net::SiteType::kPrimary)}, + {associated2, + net::FirstPartySetEntry(example2, net::SiteType::kAssociated)}, + {example3, + net::FirstPartySetEntry(example3, net::SiteType::kPrimary)}, + {associated3, + net::FirstPartySetEntry(example3, net::SiteType::kAssociated)}, }, {})); } @@ -412,18 +408,17 @@ net::SchemefulSite example(GURL("https://example.test")); net::SchemefulSite aaaa(GURL("https://aaaa.test")); - EXPECT_EQ( - ParseSets(R"({"primary": "https://subdomain.example.test", )" - R"("associatedSites": ["https://aaaa.test"]})"), - net::GlobalFirstPartySets( - kVersion, - { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, - {aaaa, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - }, - {})); + EXPECT_EQ(ParseSets(R"({"primary": "https://subdomain.example.test", )" + R"("associatedSites": ["https://aaaa.test"]})"), + net::GlobalFirstPartySets( + kVersion, + { + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {aaaa, net::FirstPartySetEntry(example, + net::SiteType::kAssociated)}, + }, + {})); } TEST(FirstPartySetParser, TruncatesPrimaryInvalidWithAlias) { @@ -444,18 +439,17 @@ net::SchemefulSite example(GURL("https://example.test")); net::SchemefulSite aaaa(GURL("https://aaaa.test")); - EXPECT_EQ( - ParseSets(R"({"primary": "https://example.test", )" - R"("associatedSites": ["https://subdomain.aaaa.test"]})"), - net::GlobalFirstPartySets( - kVersion, - { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, - {aaaa, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - }, - {})); + EXPECT_EQ(ParseSets(R"({"primary": "https://example.test", )" + R"("associatedSites": ["https://subdomain.aaaa.test"]})"), + net::GlobalFirstPartySets( + kVersion, + { + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {aaaa, net::FirstPartySetEntry(example, + net::SiteType::kAssociated)}, + }, + {})); } TEST(FirstPartySetParser, TruncatesSubdomain_RepeatedDomain) { @@ -482,14 +476,14 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {bbbb, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 2)}, - {example2, net::FirstPartySetEntry( - example2, net::SiteType::kPrimary, std::nullopt)}, - {cccc, net::FirstPartySetEntry(example2, - net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {example2, + net::FirstPartySetEntry(example2, net::SiteType::kPrimary)}, + {cccc, + net::FirstPartySetEntry(example2, net::SiteType::kAssociated)}, }, {})); } @@ -530,14 +524,14 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {bbbb, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {example2, net::FirstPartySetEntry( - example2, net::SiteType::kPrimary, std::nullopt)}, - {cccc, net::FirstPartySetEntry(example2, - net::SiteType::kAssociated, 1)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {example2, + net::FirstPartySetEntry(example2, net::SiteType::kPrimary)}, + {cccc, + net::FirstPartySetEntry(example2, net::SiteType::kAssociated)}, }, {})); @@ -560,12 +554,12 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {bbbb, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {example3, net::FirstPartySetEntry( - example3, net::SiteType::kPrimary, std::nullopt)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {example3, + net::FirstPartySetEntry(example3, net::SiteType::kPrimary)}, }, {{example3_cctld, example3}})); @@ -586,10 +580,10 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {bbbb, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, }, {})); } @@ -609,14 +603,13 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {associated1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - std::nullopt)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)}, {associated2, - net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}, }, {})); histogram_tester.ExpectUniqueSample( @@ -645,14 +638,13 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {associated1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - std::nullopt)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)}, {associated2, - net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}, }, {})); histogram_tester.ExpectUniqueSample( @@ -689,10 +681,10 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {associated1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, }, {})); } @@ -770,14 +762,13 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {associated1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - std::nullopt)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)}, {associated2, - net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}, }, { {associated1_cctld1, associated1}, @@ -1042,21 +1033,17 @@ { { {primary2, - net::FirstPartySetEntry(primary2, net::SiteType::kPrimary, - std::nullopt)}, - {associated2, - net::FirstPartySetEntry(primary2, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary2, net::SiteType::kPrimary)}, + {associated2, net::FirstPartySetEntry( + primary2, net::SiteType::kAssociated)}, }, }, { { {primary3, - net::FirstPartySetEntry(primary3, net::SiteType::kPrimary, - std::nullopt)}, - {associated3, - net::FirstPartySetEntry(primary3, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary3, net::SiteType::kPrimary)}, + {associated3, net::FirstPartySetEntry( + primary3, net::SiteType::kAssociated)}, }, }, {})))); @@ -1099,11 +1086,9 @@ { { {primary1, - net::FirstPartySetEntry(primary1, net::SiteType::kPrimary, - std::nullopt)}, - {associated2, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kPrimary)}, + {associated2, net::FirstPartySetEntry( + primary1, net::SiteType::kAssociated)}, }, }, {}, {})))); @@ -1135,11 +1120,9 @@ { { {primary2, - net::FirstPartySetEntry(primary2, net::SiteType::kPrimary, - std::nullopt)}, - {associated2, - net::FirstPartySetEntry(primary2, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary2, net::SiteType::kPrimary)}, + {associated2, net::FirstPartySetEntry( + primary2, net::SiteType::kAssociated)}, }, }, {}, {})))); @@ -1300,18 +1283,16 @@ )"); const FirstPartySetsOverridesPolicy want_policy(net::SetsMutation( {{ - {primary1, net::FirstPartySetEntry(primary1, net::SiteType::kPrimary, - std::nullopt)}, + {primary1, + net::FirstPartySetEntry(primary1, net::SiteType::kPrimary)}, {associated_site1, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kAssociated)}, }, { - {primary2, net::FirstPartySetEntry(primary2, net::SiteType::kPrimary, - std::nullopt)}, + {primary2, + net::FirstPartySetEntry(primary2, net::SiteType::kPrimary)}, {associated_site2, - net::FirstPartySetEntry(primary2, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary2, net::SiteType::kAssociated)}, }}, {}, {})); EXPECT_THAT(FirstPartySetParser::ParseSetsFromEnterprisePolicy(policy_value), @@ -1349,25 +1330,22 @@ )"); const FirstPartySetsOverridesPolicy want_policy(net::SetsMutation( {{ - {primary1, net::FirstPartySetEntry(primary1, net::SiteType::kPrimary, - std::nullopt)}, + {primary1, + net::FirstPartySetEntry(primary1, net::SiteType::kPrimary)}, {associated_site1, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kAssociated)}, }, { - {primary2, net::FirstPartySetEntry(primary2, net::SiteType::kPrimary, - std::nullopt)}, + {primary2, + net::FirstPartySetEntry(primary2, net::SiteType::kPrimary)}, {associated_site2, - net::FirstPartySetEntry(primary2, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary2, net::SiteType::kAssociated)}, }}, {{ - {primary3, net::FirstPartySetEntry(primary3, net::SiteType::kPrimary, - std::nullopt)}, + {primary3, + net::FirstPartySetEntry(primary3, net::SiteType::kPrimary)}, {associatedSite3, - net::FirstPartySetEntry(primary3, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary3, net::SiteType::kAssociated)}, }}, {})); EXPECT_THAT(FirstPartySetParser::ParseSetsFromEnterprisePolicy(policy_value), @@ -1415,11 +1393,10 @@ )"); const FirstPartySetsOverridesPolicy want_policy(net::SetsMutation( {{ - {primary1, net::FirstPartySetEntry(primary1, net::SiteType::kPrimary, - std::nullopt)}, + {primary1, + net::FirstPartySetEntry(primary1, net::SiteType::kPrimary)}, {associated1, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kAssociated)}, }}, {}, {})); EXPECT_THAT(FirstPartySetParser::ParseSetsFromEnterprisePolicy(policy_value), @@ -1472,34 +1449,29 @@ const FirstPartySetsOverridesPolicy want_policy(net::SetsMutation( /*replacement_sets=*/ {{ - {primary1, net::FirstPartySetEntry(primary1, net::SiteType::kPrimary, - std::nullopt)}, + {primary1, + net::FirstPartySetEntry(primary1, net::SiteType::kPrimary)}, {associated_site1, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kAssociated)}, {associated_site1_cctld, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kAssociated)}, }, { - {primary2, net::FirstPartySetEntry(primary2, net::SiteType::kPrimary, - std::nullopt)}, + {primary2, + net::FirstPartySetEntry(primary2, net::SiteType::kPrimary)}, {primary2_cctld, - net::FirstPartySetEntry(primary2, net::SiteType::kPrimary, - std::nullopt)}, + net::FirstPartySetEntry(primary2, net::SiteType::kPrimary)}, {associated_site2, - net::FirstPartySetEntry(primary2, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary2, net::SiteType::kAssociated)}, }}, /*addition_sets=*/ {{ - {primary3, net::FirstPartySetEntry(primary3, net::SiteType::kPrimary, - std::nullopt)}, - {service3, net::FirstPartySetEntry(primary3, net::SiteType::kService, - std::nullopt)}, + {primary3, + net::FirstPartySetEntry(primary3, net::SiteType::kPrimary)}, + {service3, + net::FirstPartySetEntry(primary3, net::SiteType::kService)}, {service3_cctld, - net::FirstPartySetEntry(primary3, net::SiteType::kService, - std::nullopt)}, + net::FirstPartySetEntry(primary3, net::SiteType::kService)}, }}, /*aliases=*/ { @@ -1533,18 +1505,13 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, - {a, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {b, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {c, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 2)}, - {d, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 3)}, - {e, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 4)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {a, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {b, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {c, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {d, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {e, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, }, {})); } @@ -1577,22 +1544,15 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, - {a, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {d, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {e, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 2)}, - {f, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 3)}, - {g, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 4)}, - {b, net::FirstPartySetEntry(example, net::SiteType::kService, - std::nullopt)}, - {c, net::FirstPartySetEntry(example, net::SiteType::kService, - std::nullopt)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {a, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {d, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {e, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {f, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {g, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {b, net::FirstPartySetEntry(example, net::SiteType::kService)}, + {c, net::FirstPartySetEntry(example, net::SiteType::kService)}, }, {})); } @@ -1620,18 +1580,13 @@ net::GlobalFirstPartySets( kVersion, { - {example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)}, - {a, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {b, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {c, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 2)}, - {d, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 3)}, - {e, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 4)}, + {example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {a, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {b, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {c, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {d, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {e, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, }, {{a_cctld1, a}, {a_cctld2, a}})); } @@ -1666,26 +1621,20 @@ FirstPartySetParser::ParseSetsFromEnterprisePolicy(policy_value).first, base::ok(FirstPartySetsOverridesPolicy(net::SetsMutation( {{ - {primary1, net::FirstPartySetEntry( - primary1, net::SiteType::kPrimary, std::nullopt)}, + {primary1, + net::FirstPartySetEntry(primary1, net::SiteType::kPrimary)}, {associated1, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kAssociated)}, {associated2, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kAssociated)}, {associated3, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kAssociated)}, {associated4, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kAssociated)}, {associated5, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kAssociated)}, {associated6, - net::FirstPartySetEntry(primary1, net::SiteType::kAssociated, - std::nullopt)}, + net::FirstPartySetEntry(primary1, net::SiteType::kAssociated)}, }}, {}, {})))); } @@ -1720,10 +1669,10 @@ base::ok(FirstPartySetsOverridesPolicy(net::SetsMutation( {}, {{ - {primary, net::FirstPartySetEntry( - primary, net::SiteType::kPrimary, std::nullopt)}, - {alias, net::FirstPartySetEntry(primary, net::SiteType::kPrimary, - std::nullopt)}, + {primary, + net::FirstPartySetEntry(primary, net::SiteType::kPrimary)}, + {alias, + net::FirstPartySetEntry(primary, net::SiteType::kPrimary)}, }}, {{alias, primary}})))); } @@ -1757,10 +1706,10 @@ FirstPartySetParser::ParseSetsFromEnterprisePolicy(policy_dict).first, base::ok(FirstPartySetsOverridesPolicy(net::SetsMutation( {{ - {primary, net::FirstPartySetEntry( - primary, net::SiteType::kPrimary, std::nullopt)}, - {alias, net::FirstPartySetEntry(primary, net::SiteType::kPrimary, - std::nullopt)}, + {primary, + net::FirstPartySetEntry(primary, net::SiteType::kPrimary)}, + {alias, + net::FirstPartySetEntry(primary, net::SiteType::kPrimary)}, }}, {}, {{alias, primary}})))); } @@ -1807,18 +1756,15 @@ { { {primary, - net::FirstPartySetEntry(primary, net::SiteType::kPrimary, - std::nullopt)}, + net::FirstPartySetEntry(primary, net::SiteType::kPrimary)}, {associated1, net::FirstPartySetEntry( - primary, net::SiteType::kAssociated, 0)}, + primary, net::SiteType::kAssociated)}, {associated2, net::FirstPartySetEntry( - primary, net::SiteType::kAssociated, 1)}, - {associated2_cctld, - net::FirstPartySetEntry(primary, net::SiteType::kAssociated, - 1)}, + primary, net::SiteType::kAssociated)}, + {associated2_cctld, net::FirstPartySetEntry( + primary, net::SiteType::kAssociated)}, {service, - net::FirstPartySetEntry(primary, net::SiteType::kService, - std::nullopt)}, + net::FirstPartySetEntry(primary, net::SiteType::kService)}, }, }, /*addition_sets=*/{},
diff --git a/content/browser/first_party_sets/first_party_sets_handler_database_helper_unittest.cc b/content/browser/first_party_sets/first_party_sets_handler_database_helper_unittest.cc index cb79800..f8303de 100644 --- a/content/browser/first_party_sets/first_party_sets_handler_database_helper_unittest.cc +++ b/content/browser/first_party_sets/first_party_sets_handler_database_helper_unittest.cc
@@ -42,28 +42,22 @@ net::GlobalFirstPartySets old_sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, - {member1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {member3, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {member1, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {member3, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}}, /*aliases=*/{}); net::GlobalFirstPartySets current_sets( kVersion, /*entries=*/ { - {example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, + {example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {member1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, {member3, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {foo, - net::FirstPartySetEntry(foo, net::SiteType::kPrimary, std::nullopt)}, - {member2, - net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)}, + {member2, net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}, }, /*aliases=*/{}); @@ -86,24 +80,18 @@ net::GlobalFirstPartySets old_sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, - {member1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {member3, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {foo, - net::FirstPartySetEntry(foo, net::SiteType::kPrimary, std::nullopt)}, - {member2, net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)}}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {member1, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {member3, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)}, + {member2, net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}}, /*aliases=*/{}); net::GlobalFirstPartySets current_sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, - {member1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {member1, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}}, /*aliases=*/{}); // Expected diff: "https://foo.test", "https://member2.test" and @@ -125,28 +113,21 @@ net::GlobalFirstPartySets old_sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, - {member1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {foo, - net::FirstPartySetEntry(foo, net::SiteType::kPrimary, std::nullopt)}, - {member2, net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)}, - {member3, net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 1)}}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {member1, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)}, + {member2, net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}, + {member3, net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}}, /*aliases=*/{}); net::GlobalFirstPartySets current_sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, - {member1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {member3, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {foo, - net::FirstPartySetEntry(foo, net::SiteType::kPrimary, std::nullopt)}, - {member2, net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)}}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {member1, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {member3, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)}, + {member2, net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}}, /*aliases=*/{}); // Expected diff: "https://member3.test" changed primary. @@ -165,18 +146,16 @@ net::GlobalFirstPartySets old_sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, - {foo, net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {bar, net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {foo, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {bar, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}}, /*aliases=*/{}); net::GlobalFirstPartySets current_sets( kVersion, /*entries=*/ - {{foo, - net::FirstPartySetEntry(foo, net::SiteType::kPrimary, std::nullopt)}, - {bar, net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)}}, + {{foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)}, + {bar, net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}}, /*aliases=*/{}); // Expected diff: "https://example.test" left FPSs, "https://foo.test" and @@ -198,17 +177,15 @@ net::GlobalFirstPartySets old_sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, - {foo, net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {foo, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}}, /*aliases=*/{}); net::GlobalFirstPartySets current_sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)}, - {foo, - net::FirstPartySetEntry(foo, net::SiteType::kPrimary, std::nullopt)}}, + {{example, net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}, + {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)}}, /*aliases=*/{}); // Expected diff: "https://example.test" and "https://foo.test" changed @@ -229,10 +206,8 @@ net::GlobalFirstPartySets current_sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, - {member1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {member1, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}}, /*aliases=*/{}); EXPECT_THAT( @@ -251,10 +226,8 @@ net::GlobalFirstPartySets old_sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, - {member1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {member1, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}}, /*aliases=*/{}); EXPECT_THAT(FirstPartySetsHandlerDatabaseHelper::ComputeSetsDiff( @@ -271,10 +244,10 @@ net::FirstPartySetsContextConfig current_config = net::FirstPartySetsContextConfig::Create( { - {foo, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kPrimary, std::nullopt))}, + {foo, net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(foo, net::SiteType::kPrimary))}, {member2, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kAssociated, 0))}, + foo, net::SiteType::kAssociated))}, }) .value(); @@ -297,20 +270,18 @@ net::GlobalFirstPartySets sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, - {member1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {member1, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}}, /*aliases=*/{}); // "https://example.test" was removed from FPSs by policy modifications. net::FirstPartySetsContextConfig old_config = net::FirstPartySetsContextConfig::Create( { - {foo, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kPrimary, std::nullopt))}, + {foo, net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(foo, net::SiteType::kPrimary))}, {member1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kAssociated, 0))}, + foo, net::SiteType::kAssociated))}, {example, net::FirstPartySetEntryOverride()}, }) .value(); @@ -319,12 +290,12 @@ net::FirstPartySetsContextConfig current_config = net::FirstPartySetsContextConfig::Create( { - {foo, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kPrimary, std::nullopt))}, + {foo, net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(foo, net::SiteType::kPrimary))}, {member1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kAssociated, 0))}, + foo, net::SiteType::kAssociated))}, {example, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kAssociated, 0))}, + foo, net::SiteType::kAssociated))}, }) .value(); @@ -344,12 +315,12 @@ net::FirstPartySetsContextConfig old_config = net::FirstPartySetsContextConfig::Create( { - {foo, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kPrimary, std::nullopt))}, + {foo, net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(foo, net::SiteType::kPrimary))}, {member1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kAssociated, 0))}, + foo, net::SiteType::kAssociated))}, {member2, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kAssociated, 0))}, + foo, net::SiteType::kAssociated))}, }) .value(); @@ -357,10 +328,10 @@ net::FirstPartySetsContextConfig current_config = net::FirstPartySetsContextConfig::Create( { - {foo, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kPrimary, std::nullopt))}, + {foo, net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(foo, net::SiteType::kPrimary))}, {member1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kAssociated, 0))}, + foo, net::SiteType::kAssociated))}, }) .value(); @@ -379,11 +350,11 @@ net::FirstPartySetsContextConfig::Create( { {example, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt))}, + example, net::SiteType::kPrimary))}, {member1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - example, net::SiteType::kAssociated, 0))}, + example, net::SiteType::kAssociated))}, {member2, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - example, net::SiteType::kAssociated, 0))}, + example, net::SiteType::kAssociated))}, }) .value(); @@ -391,9 +362,9 @@ net::FirstPartySetsContextConfig::Create( { {member1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - member1, net::SiteType::kPrimary, std::nullopt))}, + member1, net::SiteType::kPrimary))}, {member2, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - member1, net::SiteType::kAssociated, 0))}, + member1, net::SiteType::kAssociated))}, }) .value(); @@ -419,28 +390,28 @@ net::FirstPartySetsContextConfig old_config = net::FirstPartySetsContextConfig::Create( { - {foo, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kPrimary, std::nullopt))}, + {foo, net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(foo, net::SiteType::kPrimary))}, {member1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kAssociated, 0))}, - {bar, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - bar, net::SiteType::kPrimary, std::nullopt))}, + foo, net::SiteType::kAssociated))}, + {bar, net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(bar, net::SiteType::kPrimary))}, {member2, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - bar, net::SiteType::kAssociated, 0))}, + bar, net::SiteType::kAssociated))}, }) .value(); net::FirstPartySetsContextConfig current_config = net::FirstPartySetsContextConfig::Create( { - {foo, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kPrimary, std::nullopt))}, + {foo, net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(foo, net::SiteType::kPrimary))}, {member2, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - foo, net::SiteType::kAssociated, 0))}, - {bar, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - bar, net::SiteType::kPrimary, std::nullopt))}, + foo, net::SiteType::kAssociated))}, + {bar, net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(bar, net::SiteType::kPrimary))}, {member1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - bar, net::SiteType::kAssociated, 0))}, + bar, net::SiteType::kAssociated))}, }) .value(); @@ -479,26 +450,21 @@ net::GlobalFirstPartySets( base::Version("0.0.1"), /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, {member1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, {member3, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 1)}, - {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - std::nullopt)}, - {member2, - net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)}}, + net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)}, + {member2, net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}}, /*aliases=*/{}), /*config=*/net::FirstPartySetsContextConfig()); net::GlobalFirstPartySets current_sets( kVersion, /*entries=*/ - {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}, - {member1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}}, + {{example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}, + {member1, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}}, /*aliases=*/{}); std::optional<std::pair<std::vector<net::SchemefulSite>,
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl_browsertest.cc b/content/browser/first_party_sets/first_party_sets_handler_impl_browsertest.cc index 4be93e4..1a13e6b 100644 --- a/content/browser/first_party_sets/first_party_sets_handler_impl_browsertest.cc +++ b/content/browser/first_party_sets/first_party_sets_handler_impl_browsertest.cc
@@ -69,16 +69,14 @@ IN_PROC_BROWSER_TEST_F(FirstPartySetsHandlerImplBrowserTest, LocalSwitch) { // The First-Party Sets should be: // {primary: A, associatedSites: [B, C]} - EXPECT_EQ( - GetGlobalSets().FindEntry(net::SchemefulSite(GURL(kSiteB)), - net::FirstPartySetsContextConfig()), - std::make_optional(net::FirstPartySetEntry( - net::SchemefulSite(GURL(kSiteA)), net::SiteType::kAssociated, 0))); - EXPECT_EQ( - GetGlobalSets().FindEntry(net::SchemefulSite(GURL(kSiteC)), - net::FirstPartySetsContextConfig()), - std::make_optional(net::FirstPartySetEntry( - net::SchemefulSite(GURL(kSiteA)), net::SiteType::kAssociated, 1))); + EXPECT_EQ(GetGlobalSets().FindEntry(net::SchemefulSite(GURL(kSiteB)), + net::FirstPartySetsContextConfig()), + std::make_optional(net::FirstPartySetEntry( + net::SchemefulSite(GURL(kSiteA)), net::SiteType::kAssociated))); + EXPECT_EQ(GetGlobalSets().FindEntry(net::SchemefulSite(GURL(kSiteC)), + net::FirstPartySetsContextConfig()), + std::make_optional(net::FirstPartySetEntry( + net::SchemefulSite(GURL(kSiteA)), net::SiteType::kAssociated))); } // Verify that when both `kUseFirstPartySet` and `kUseRelatedWebsiteSet` @@ -104,16 +102,14 @@ // // After the new switch is applied, the expected First-Party Sets are: // {primary: D, associatedSites: [B, C]} - EXPECT_EQ( - GetGlobalSets().FindEntry(net::SchemefulSite(GURL(kSiteB)), - net::FirstPartySetsContextConfig()), - std::make_optional(net::FirstPartySetEntry( - net::SchemefulSite(GURL(kSiteD)), net::SiteType::kAssociated, 0))); - EXPECT_EQ( - GetGlobalSets().FindEntry(net::SchemefulSite(GURL(kSiteC)), - net::FirstPartySetsContextConfig()), - std::make_optional(net::FirstPartySetEntry( - net::SchemefulSite(GURL(kSiteD)), net::SiteType::kAssociated, 1))); + EXPECT_EQ(GetGlobalSets().FindEntry(net::SchemefulSite(GURL(kSiteB)), + net::FirstPartySetsContextConfig()), + std::make_optional(net::FirstPartySetEntry( + net::SchemefulSite(GURL(kSiteD)), net::SiteType::kAssociated))); + EXPECT_EQ(GetGlobalSets().FindEntry(net::SchemefulSite(GURL(kSiteC)), + net::FirstPartySetsContextConfig()), + std::make_optional(net::FirstPartySetEntry( + net::SchemefulSite(GURL(kSiteD)), net::SiteType::kAssociated))); EXPECT_EQ(GetGlobalSets().FindEntry(net::SchemefulSite(GURL(kSiteA)), net::FirstPartySetsContextConfig()),
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl_instance_unittest.cc b/content/browser/first_party_sets/first_party_sets_handler_impl_instance_unittest.cc index dab5f83..f86fc52 100644 --- a/content/browser/first_party_sets/first_party_sets_handler_impl_instance_unittest.cc +++ b/content/browser/first_party_sets/first_party_sets_handler_impl_instance_unittest.cc
@@ -330,14 +330,13 @@ R"({"primary": "https://example.test",)" R"("associatedSites": ["https://associatedsite1.test"]})")); - EXPECT_THAT( - GetSetsAndWait().FindEntries({example, associated}, - net::FirstPartySetsContextConfig()), - UnorderedElementsAre( - Pair(example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)), - Pair(associated, net::FirstPartySetEntry( - example, net::SiteType::kAssociated, 0)))); + EXPECT_THAT(GetSetsAndWait().FindEntries({example, associated}, + net::FirstPartySetsContextConfig()), + UnorderedElementsAre( + Pair(example, net::FirstPartySetEntry( + example, net::SiteType::kPrimary)), + Pair(associated, net::FirstPartySetEntry( + example, net::SiteType::kAssociated)))); } TEST_F(FirstPartySetsHandlerImplEnabledTest, @@ -372,11 +371,9 @@ EXPECT_THAT( persisted->first.FindEntries({foo, associated}, persisted->second), UnorderedElementsAre( - Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - std::nullopt)), + Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)), Pair(associated, - net::FirstPartySetEntry(foo, net::SiteType::kAssociated, - std::nullopt)))); + net::FirstPartySetEntry(foo, net::SiteType::kAssociated)))); histogram.ExpectUniqueSample(kFirstPartySetsClearSiteDataOutcomeHistogram, /*sample=*/true, 1); histogram.ExpectTotalCount(kDelayedQueriesCountHistogram, 1); @@ -420,11 +417,9 @@ EXPECT_THAT( persisted->first.FindEntries({foo, associated}, persisted->second), UnorderedElementsAre( - Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - std::nullopt)), + Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)), Pair(associated, - net::FirstPartySetEntry(foo, net::SiteType::kAssociated, - std::nullopt)))); + net::FirstPartySetEntry(foo, net::SiteType::kAssociated)))); EXPECT_THAT( HasEntryInBrowserContextsClearedAndWait(handler, browser_context_id), Optional(true)); @@ -464,11 +459,9 @@ EXPECT_THAT( persisted->first.FindEntries({foo, associated2}, persisted->second), UnorderedElementsAre( - Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - std::nullopt)), + Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)), Pair(associated2, - net::FirstPartySetEntry(foo, net::SiteType::kAssociated, - std::nullopt)))); + net::FirstPartySetEntry(foo, net::SiteType::kAssociated)))); EXPECT_THAT( HasEntryInBrowserContextsClearedAndWait(handler, browser_context_id), Optional(true)); @@ -494,13 +487,13 @@ handler().Init( /*user_data_dir=*/{}, net::LocalSetDeclaration()); - ASSERT_THAT(GetSetsAndWait().FindEntries({foo, associated}, - net::FirstPartySetsContextConfig()), - UnorderedElementsAre( - Pair(foo, net::FirstPartySetEntry( - foo, net::SiteType::kPrimary, std::nullopt)), - Pair(associated, net::FirstPartySetEntry( - foo, net::SiteType::kAssociated, 0)))); + ASSERT_THAT( + GetSetsAndWait().FindEntries({foo, associated}, + net::FirstPartySetsContextConfig()), + UnorderedElementsAre( + Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)), + Pair(associated, + net::FirstPartySetEntry(foo, net::SiteType::kAssociated)))); ClearSiteDataOnChangedSetsForContextAndWait( context(), browser_context_id, net::FirstPartySetsContextConfig()); @@ -545,11 +538,9 @@ EXPECT_THAT( persisted->first.FindEntries({foo, associated}, persisted->second), UnorderedElementsAre( - Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - std::nullopt)), + Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)), Pair(associated, - net::FirstPartySetEntry(foo, net::SiteType::kAssociated, - std::nullopt)))); + net::FirstPartySetEntry(foo, net::SiteType::kAssociated)))); histogram.ExpectUniqueSample(kFirstPartySetsClearSiteDataOutcomeHistogram, /*sample=*/true, 1); histogram.ExpectTotalCount(kDelayedQueriesCountHistogram, 1); @@ -573,17 +564,16 @@ // Wait until initialization is complete. GetSetsAndWait(); - EXPECT_THAT( - handler() - .GetSets(base::NullCallback()) - .value() - .FindEntries({example, associated}, - net::FirstPartySetsContextConfig()), - UnorderedElementsAre( - Pair(example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)), - Pair(associated, net::FirstPartySetEntry( - example, net::SiteType::kAssociated, 0)))); + EXPECT_THAT(handler() + .GetSets(base::NullCallback()) + .value() + .FindEntries({example, associated}, + net::FirstPartySetsContextConfig()), + UnorderedElementsAre( + Pair(example, net::FirstPartySetEntry( + example, net::SiteType::kPrimary)), + Pair(associated, net::FirstPartySetEntry( + example, net::SiteType::kAssociated)))); } TEST_F(FirstPartySetsHandlerImplEnabledTest, @@ -604,26 +594,24 @@ handler().SetPublicFirstPartySets(base::Version("1.2.3"), WritePublicSetsFile(input)); - EXPECT_THAT( - future.Get().FindEntries({example, associated}, - net::FirstPartySetsContextConfig()), - UnorderedElementsAre( - Pair(example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)), - Pair(associated, net::FirstPartySetEntry( - example, net::SiteType::kAssociated, 0)))); + EXPECT_THAT(future.Get().FindEntries({example, associated}, + net::FirstPartySetsContextConfig()), + UnorderedElementsAre( + Pair(example, net::FirstPartySetEntry( + example, net::SiteType::kPrimary)), + Pair(associated, net::FirstPartySetEntry( + example, net::SiteType::kAssociated)))); - EXPECT_THAT( - handler() - .GetSets(base::NullCallback()) - .value() - .FindEntries({example, associated}, - net::FirstPartySetsContextConfig()), - UnorderedElementsAre( - Pair(example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)), - Pair(associated, net::FirstPartySetEntry( - example, net::SiteType::kAssociated, 0)))); + EXPECT_THAT(handler() + .GetSets(base::NullCallback()) + .value() + .FindEntries({example, associated}, + net::FirstPartySetsContextConfig()), + UnorderedElementsAre( + Pair(example, net::FirstPartySetEntry( + example, net::SiteType::kPrimary)), + Pair(associated, net::FirstPartySetEntry( + example, net::SiteType::kAssociated)))); } TEST_F(FirstPartySetsHandlerImplEnabledTest, @@ -704,13 +692,12 @@ set_entries.emplace_back(site, entry); return true; })); - EXPECT_THAT( - set_entries, - UnorderedElementsAre( - Pair(example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)), - Pair(associated, net::FirstPartySetEntry( - example, net::SiteType::kAssociated, 0)))); + EXPECT_THAT(set_entries, + UnorderedElementsAre( + Pair(example, net::FirstPartySetEntry( + example, net::SiteType::kPrimary)), + Pair(associated, net::FirstPartySetEntry( + example, net::SiteType::kAssociated)))); } TEST_F(FirstPartySetsHandlerImplEnabledTest, @@ -737,8 +724,8 @@ EXPECT_TRUE(handler().ForEachEffectiveSetEntry( net::FirstPartySetsContextConfig::Create( {{associated2, - net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - example, net::SiteType::kAssociated, std::nullopt))}}) + net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(example, net::SiteType::kAssociated))}}) .value(), [&](const net::SchemefulSite& site, const net::FirstPartySetEntry& entry) { @@ -748,13 +735,12 @@ EXPECT_THAT( set_entries, UnorderedElementsAre( - Pair(example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)), + Pair(example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)), Pair(associated1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)), + net::FirstPartySetEntry(example, net::SiteType::kAssociated)), Pair(associated2, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, - std::nullopt)))); + net::FirstPartySetEntry(example, net::SiteType::kAssociated)))); } class FirstPartySetsHandlerGetContextConfigForPolicyTest
diff --git a/content/browser/first_party_sets/first_party_sets_loader_unittest.cc b/content/browser/first_party_sets/first_party_sets_loader_unittest.cc index 07c778c..2a38a7fc 100644 --- a/content/browser/first_party_sets/first_party_sets_loader_unittest.cc +++ b/content/browser/first_party_sets/first_party_sets_loader_unittest.cc
@@ -103,14 +103,13 @@ WaitAndGetResult().FindEntries({example, associated1, foo, associated2}, net::FirstPartySetsContextConfig()), UnorderedElementsAre( - Pair(example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)), + Pair(example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)), Pair(associated1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)), - Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - std::nullopt)), + net::FirstPartySetEntry(example, net::SiteType::kAssociated)), + Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)), Pair(associated2, - net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)))); + net::FirstPartySetEntry(foo, net::SiteType::kAssociated)))); } TEST_F(FirstPartySetsLoaderTest, SetComponentSets_Idempotent) { @@ -139,10 +138,9 @@ WaitAndGetResult().FindEntries({example, foo, example2, foo2}, net::FirstPartySetsContextConfig()), UnorderedElementsAre( - Pair(example, net::FirstPartySetEntry( - example, net::SiteType::kPrimary, std::nullopt)), - Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - std::nullopt)))); + Pair(example, + net::FirstPartySetEntry(example, net::SiteType::kPrimary)), + Pair(foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)))); } TEST_F(FirstPartySetsLoaderTest, SetsManuallySpecified) { @@ -157,10 +155,9 @@ net::LocalSetDeclaration::Create( /*set_entries=*/base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>({ - {bar, net::FirstPartySetEntry(bar, net::SiteType::kPrimary, - std::nullopt)}, + {bar, net::FirstPartySetEntry(bar, net::SiteType::kPrimary)}, {associated2, - net::FirstPartySetEntry(bar, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(bar, net::SiteType::kAssociated)}, }), /*aliases=*/{}) .value()); @@ -168,7 +165,7 @@ EXPECT_THAT( WaitAndGetResult().FindEntry(associated2, net::FirstPartySetsContextConfig()), - Optional(net::FirstPartySetEntry(bar, net::SiteType::kAssociated, 0))); + Optional(net::FirstPartySetEntry(bar, net::SiteType::kAssociated))); } TEST_F(FirstPartySetsLoaderTest, SetsManuallySpecified_Idempotent) { @@ -180,10 +177,9 @@ net::LocalSetDeclaration::Create( /*set_entries=*/base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>({ - {bar, net::FirstPartySetEntry(bar, net::SiteType::kPrimary, - std::nullopt)}, + {bar, net::FirstPartySetEntry(bar, net::SiteType::kPrimary)}, {associated1, - net::FirstPartySetEntry(bar, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(bar, net::SiteType::kAssociated)}, }), /*aliases=*/{}) .value()); @@ -193,10 +189,9 @@ net::LocalSetDeclaration::Create( /*set_entries=*/base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>({ - {bar, net::FirstPartySetEntry(bar, net::SiteType::kPrimary, - std::nullopt)}, + {bar, net::FirstPartySetEntry(bar, net::SiteType::kPrimary)}, {associated2, - net::FirstPartySetEntry(bar, net::SiteType::kAssociated, 0)}, + net::FirstPartySetEntry(bar, net::SiteType::kAssociated)}, }), /*aliases=*/{}) .value()); @@ -209,9 +204,9 @@ associated2, }, net::FirstPartySetsContextConfig()), - UnorderedElementsAre( - Pair(associated1, net::FirstPartySetEntry( - bar, net::SiteType::kAssociated, 0)))); + UnorderedElementsAre(Pair( + associated1, + net::FirstPartySetEntry(bar, net::SiteType::kAssociated)))); } } // namespace content
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc index 6b775ebf..3153afd 100644 --- a/content/browser/gpu/compositor_util.cc +++ b/content/browser/gpu/compositor_util.cc
@@ -19,6 +19,7 @@ #include "base/system/sys_info.h" #include "base/values.h" #include "build/build_config.h" +#include "cc/base/features.h" #include "cc/base/switches.h" #include "components/viz/common/features.h" #include "content/browser/compositor/image_transport_factory.h" @@ -217,6 +218,10 @@ features.emplace_back( "webnn", SafeGetFeatureStatus(gpu_feature_info, gpu::GPU_FEATURE_TYPE_WEBNN)); + features.emplace_back("trees_in_viz", + base::FeatureList::IsEnabled(::features::kTreesInViz) + ? gpu::kGpuFeatureStatusEnabled + : gpu::kGpuFeatureStatusDisabled); return features; } @@ -289,7 +294,8 @@ gpu_feature_data.name == "vulkan" || gpu_feature_data.name == "skia_graphite" || gpu_feature_data.name == "surface_control" || - gpu_feature_data.name == "webnn") { + gpu_feature_data.name == "webnn" || + gpu_feature_data.name == "trees_in_viz") { status += "_on"; } }
diff --git a/content/browser/indexed_db/instance/backing_store.h b/content/browser/indexed_db/instance/backing_store.h index 77384e0..dd1f22c 100644 --- a/content/browser/indexed_db/instance/backing_store.h +++ b/content/browser/indexed_db/instance/backing_store.h
@@ -189,28 +189,24 @@ const blink::IndexedDBKey& key, std::unique_ptr<blink::IndexedDBKey>* found_primary_key, bool* exists) = 0; - virtual std::unique_ptr<Cursor> OpenObjectStoreKeyCursor( - int64_t object_store_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) = 0; - virtual std::unique_ptr<Cursor> OpenObjectStoreCursor( - int64_t object_store_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) = 0; - virtual std::unique_ptr<Cursor> OpenIndexKeyCursor( + virtual base::expected<std::unique_ptr<Cursor>, Status> + OpenObjectStoreKeyCursor(int64_t object_store_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) = 0; + virtual base::expected<std::unique_ptr<Cursor>, Status> + OpenObjectStoreCursor(int64_t object_store_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) = 0; + virtual base::expected<std::unique_ptr<Cursor>, Status> OpenIndexKeyCursor( int64_t object_store_id, int64_t index_id, const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) = 0; - virtual std::unique_ptr<Cursor> OpenIndexCursor( + blink::mojom::IDBCursorDirection) = 0; + virtual base::expected<std::unique_ptr<Cursor>, Status> OpenIndexCursor( int64_t object_store_id, int64_t index_id, const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) = 0; + blink::mojom::IDBCursorDirection) = 0; }; // Another interface to be implemented by a backend implementation.
diff --git a/content/browser/indexed_db/instance/database.cc b/content/browser/indexed_db/instance/database.cc index 4733fd1..3509cfd 100644 --- a/content/browser/indexed_db/instance/database.cc +++ b/content/browser/indexed_db/instance/database.cc
@@ -359,8 +359,8 @@ const IndexedDBKey* key; - Status s = Status::OK(); - std::unique_ptr<BackingStore::Cursor> backing_store_cursor; + base::expected<std::unique_ptr<BackingStore::Cursor>, Status> + backing_store_cursor; if (key_range->IsOnlyKey()) { key = &key_range->lower(); } else { @@ -370,50 +370,50 @@ backing_store_cursor = transaction->BackingStoreTransaction()->OpenObjectStoreKeyCursor( object_store_id, *key_range, - blink::mojom::IDBCursorDirection::Next, &s); + blink::mojom::IDBCursorDirection::Next); } else { backing_store_cursor = transaction->BackingStoreTransaction()->OpenObjectStoreCursor( object_store_id, *key_range, - blink::mojom::IDBCursorDirection::Next, &s); + blink::mojom::IDBCursorDirection::Next); } } else if (cursor_type == CursorType::kKeyOnly) { // Index Value Retrieval Operation backing_store_cursor = transaction->BackingStoreTransaction()->OpenIndexKeyCursor( object_store_id, index_id, *key_range, - blink::mojom::IDBCursorDirection::Next, &s); + blink::mojom::IDBCursorDirection::Next); } else { // Index Referenced Value Retrieval Operation backing_store_cursor = transaction->BackingStoreTransaction()->OpenIndexCursor( object_store_id, index_id, *key_range, - blink::mojom::IDBCursorDirection::Next, &s); + blink::mojom::IDBCursorDirection::Next); } - if (!s.ok()) { + if (!backing_store_cursor.has_value()) { std::move(callback).Run( blink::mojom::IDBDatabaseGetResult::NewErrorResult(CreateIDBErrorPtr( blink::mojom::IDBException::kUnknownError, "Corruption detected, unable to continue", transaction))); - return s; + return backing_store_cursor.error(); } - if (!backing_store_cursor) { + if (!*backing_store_cursor) { // This means we've run out of data. std::move(callback).Run( blink::mojom::IDBDatabaseGetResult::NewEmpty(true)); - return s; + return Status::OK(); } - key = &backing_store_cursor->GetKey(); + key = &(*backing_store_cursor)->GetKey(); } if (index_id == IndexedDBIndexMetadata::kInvalidId) { // Object Store Retrieval Operation IndexedDBReturnValue value; - s = transaction->BackingStoreTransaction()->GetRecord(object_store_id, *key, - &value); + Status s = transaction->BackingStoreTransaction()->GetRecord( + object_store_id, *key, &value); if (!s.ok()) { std::move(callback).Run( blink::mojom::IDBDatabaseGetResult::NewErrorResult( @@ -451,7 +451,7 @@ // From here we are dealing only with indexes. std::unique_ptr<IndexedDBKey> primary_key; - s = transaction->BackingStoreTransaction()->GetPrimaryKeyViaIndex( + Status s = transaction->BackingStoreTransaction()->GetPrimaryKeyViaIndex( object_store_id, index_id, *key, &primary_key); if (!s.ok()) { std::move(callback).Run(blink::mojom::IDBDatabaseGetResult::NewErrorResult( @@ -591,39 +591,39 @@ const IndexedDBObjectStoreMetadata& object_store_metadata = GetObjectStoreMetadata(object_store_id); - Status s = Status::OK(); - std::unique_ptr<BackingStore::Cursor> cursor; + base::expected<std::unique_ptr<BackingStore::Cursor>, Status> cursor; if (result_type == blink::mojom::IDBGetAllResultType::Keys) { // Retrieving keys if (index_id == IndexedDBIndexMetadata::kInvalidId) { // Object Store: Key Retrieval Operation cursor = transaction->BackingStoreTransaction()->OpenObjectStoreKeyCursor( - object_store_id, *key_range, direction, &s); + object_store_id, *key_range, direction); } else { // Index Value: (Primary Key) Retrieval Operation cursor = transaction->BackingStoreTransaction()->OpenIndexKeyCursor( - object_store_id, index_id, *key_range, direction, &s); + object_store_id, index_id, *key_range, direction); } } else { // Retrieving values if (index_id == IndexedDBIndexMetadata::kInvalidId) { // Object Store: Value Retrieval Operation cursor = transaction->BackingStoreTransaction()->OpenObjectStoreCursor( - object_store_id, *key_range, direction, &s); + object_store_id, *key_range, direction); } else { // Object Store: Referenced Value Retrieval Operation cursor = transaction->BackingStoreTransaction()->OpenIndexCursor( - object_store_id, index_id, *key_range, direction, &s); + object_store_id, index_id, *key_range, direction); } } - if (!s.ok()) { - DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString(); + if (!cursor.has_value()) { + DLOG(ERROR) << "Unable to open cursor operation: " + << cursor.error().ToString(); result_sink->Get()->OnError(CreateIDBErrorPtr( blink::mojom::IDBException::kUnknownError, "Corruption detected, unable to continue", transaction)); - return s; + return cursor.error(); } std::vector<blink::mojom::IDBRecordPtr> found_records; @@ -634,9 +634,9 @@ }; // No records found. - if (!cursor) { + if (!*cursor) { send_records(/*done=*/true); - return s; + return Status::OK(); } bool did_first_seek = false; @@ -654,8 +654,9 @@ int64_t num_found_items = 0; while (num_found_items++ < max_count) { bool cursor_valid; + Status s; if (did_first_seek) { - cursor_valid = cursor->Continue(&s); + cursor_valid = (*cursor)->Continue(&s); } else { // Cursor creation performs the first seek, returning a nullptr cursor // when invalid. @@ -676,13 +677,13 @@ blink::mojom::IDBRecordPtr return_record; if (result_type == blink::mojom::IDBGetAllResultType::Keys) { - return_record = blink::mojom::IDBRecord::New(cursor->GetPrimaryKey(), + return_record = blink::mojom::IDBRecord::New((*cursor)->GetPrimaryKey(), /*value=*/nullptr, /*index_key=*/std::nullopt); } else if (result_type == blink::mojom::IDBGetAllResultType::Values) { blink::mojom::IDBReturnValuePtr return_value = ExtractReturnValueFromCursorValue(bucket_context_.get(), - object_store_metadata, *cursor); + object_store_metadata, **cursor); return_record = blink::mojom::IDBRecord::New( /*primary_key=*/std::nullopt, std::move(return_value), /*index_key=*/std::nullopt); @@ -691,13 +692,13 @@ // key. blink::mojom::IDBReturnValuePtr return_value = ExtractReturnValueFromCursorValue(bucket_context_.get(), - object_store_metadata, *cursor); + object_store_metadata, **cursor); std::optional<IndexedDBKey> index_key; if (index_id != IndexedDBIndexMetadata::kInvalidId) { // The index key only exists for `IDBIndex::getAllRecords()`. - index_key = cursor->GetKey(); + index_key = (*cursor)->GetKey(); } - return_record = blink::mojom::IDBRecord::New(cursor->GetPrimaryKey(), + return_record = blink::mojom::IDBRecord::New((*cursor)->GetPrimaryKey(), std::move(return_value), std::move(index_key)); } else { @@ -712,7 +713,7 @@ } } send_records(/*done=*/true); - return s; + return Status::OK(); } Status Database::SetIndexKeysOperation( @@ -799,20 +800,18 @@ transaction->AddPreemptiveEvent(); } - Status s; - std::unique_ptr<BackingStore::Cursor> backing_store_cursor; + base::expected<std::unique_ptr<BackingStore::Cursor>, Status> + backing_store_cursor; if (params->index_id == IndexedDBIndexMetadata::kInvalidId) { if (params->cursor_type == CursorType::kKeyOnly) { DCHECK_EQ(params->task_type, blink::mojom::IDBTaskType::Normal); backing_store_cursor = transaction->BackingStoreTransaction()->OpenObjectStoreKeyCursor( - params->object_store_id, *params->key_range, params->direction, - &s); + params->object_store_id, *params->key_range, params->direction); } else { backing_store_cursor = transaction->BackingStoreTransaction()->OpenObjectStoreCursor( - params->object_store_id, *params->key_range, params->direction, - &s); + params->object_store_id, *params->key_range, params->direction); } } else { DCHECK_EQ(params->task_type, blink::mojom::IDBTaskType::Normal); @@ -820,30 +819,31 @@ backing_store_cursor = transaction->BackingStoreTransaction()->OpenIndexKeyCursor( params->object_store_id, params->index_id, *params->key_range, - params->direction, &s); + params->direction); } else { backing_store_cursor = transaction->BackingStoreTransaction()->OpenIndexCursor( params->object_store_id, params->index_id, *params->key_range, - params->direction, &s); + params->direction); } } - if (!s.ok()) { - DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString(); - return s; + if (!backing_store_cursor.has_value()) { + DLOG(ERROR) << "Unable to open cursor operation: " + << backing_store_cursor.error().ToString(); + return backing_store_cursor.error(); } - if (!backing_store_cursor) { + if (!*backing_store_cursor) { // Occurs when we've reached the end of cursor's data. std::move(params->callback) .Run(blink::mojom::IDBDatabaseOpenCursorResult::NewEmpty(true)); - return s; + return Status::OK(); } mojo::PendingAssociatedRemote<blink::mojom::IDBCursor> pending_remote; Cursor* cursor = Cursor::CreateAndBind( - std::move(backing_store_cursor), params->cursor_type, params->task_type, + std::move(*backing_store_cursor), params->cursor_type, params->task_type, transaction->AsWeakPtr(), pending_remote); transaction->RegisterOpenCursor(cursor); @@ -864,7 +864,7 @@ blink::mojom::IDBDatabaseOpenCursorValue::New( std::move(pending_remote), cursor->key(), cursor->primary_key(), std::move(mojo_value)))); - return s; + return Status::OK(); } Status Database::CountOperation( @@ -880,36 +880,40 @@ return Status::InvalidArgument("Invalid object_store_id and/or index_id."); } - uint32_t count = 0; - std::unique_ptr<BackingStore::Cursor> backing_store_cursor; - Status s = Status::OK(); + base::expected<std::unique_ptr<BackingStore::Cursor>, Status> + backing_store_cursor; if (index_id == IndexedDBIndexMetadata::kInvalidId) { backing_store_cursor = transaction->BackingStoreTransaction()->OpenObjectStoreKeyCursor( - object_store_id, *key_range, blink::mojom::IDBCursorDirection::Next, - &s); + object_store_id, *key_range, + blink::mojom::IDBCursorDirection::Next); } else { backing_store_cursor = transaction->BackingStoreTransaction()->OpenIndexKeyCursor( object_store_id, index_id, *key_range, - blink::mojom::IDBCursorDirection::Next, &s); + blink::mojom::IDBCursorDirection::Next); } - if (!s.ok()) { - DLOG(ERROR) << "Unable perform count operation: " << s.ToString(); - return s; + if (!backing_store_cursor.has_value()) { + DLOG(ERROR) << "Unable perform count operation: " + << backing_store_cursor.error().ToString(); + return backing_store_cursor.error(); } - if (backing_store_cursor) { - do { - if (!s.ok()) { - return s; - } - ++count; - } while (backing_store_cursor->Continue(&s)); + if (!*backing_store_cursor) { + std::move(callback).Run(/*success=*/true, /*count=*/0); + return Status::OK(); } + uint32_t count = 1; + Status s; + while ((*backing_store_cursor)->Continue(&s)) { + if (!s.ok()) { + return s; + } + ++count; + } std::move(callback).Run(/*success=*/true, count); - return s; + return Status::OK(); } Status Database::DeleteRangeOperation(
diff --git a/content/browser/indexed_db/instance/fake_transaction.cc b/content/browser/indexed_db/instance/fake_transaction.cc index 468c84a..ad9ae807 100644 --- a/content/browser/indexed_db/instance/fake_transaction.cc +++ b/content/browser/indexed_db/instance/fake_transaction.cc
@@ -158,44 +158,41 @@ found_primary_key, exists); } -std::unique_ptr<indexed_db::BackingStore::Cursor> +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> FakeTransaction::OpenObjectStoreKeyCursor( int64_t object_store_id, const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection direction, - Status* status) { - return wrapped_transaction_->OpenObjectStoreKeyCursor( - object_store_id, key_range, direction, status); + blink::mojom::IDBCursorDirection direction) { + return wrapped_transaction_->OpenObjectStoreKeyCursor(object_store_id, + key_range, direction); } -std::unique_ptr<indexed_db::BackingStore::Cursor> +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> FakeTransaction::OpenObjectStoreCursor( int64_t object_store_id, const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection direction, - Status* status) { + blink::mojom::IDBCursorDirection direction) { return wrapped_transaction_->OpenObjectStoreCursor(object_store_id, key_range, - direction, status); + direction); } -std::unique_ptr<indexed_db::BackingStore::Cursor> -FakeTransaction::OpenIndexKeyCursor(int64_t object_store_id, - int64_t index_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection direction, - Status* status) { +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> +FakeTransaction::OpenIndexKeyCursor( + int64_t object_store_id, + int64_t index_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection direction) { return wrapped_transaction_->OpenIndexKeyCursor(object_store_id, index_id, - key_range, direction, status); + key_range, direction); } -std::unique_ptr<indexed_db::BackingStore::Cursor> +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> FakeTransaction::OpenIndexCursor(int64_t object_store_id, int64_t index_id, const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection direction, - Status* status) { + blink::mojom::IDBCursorDirection direction) { return wrapped_transaction_->OpenIndexCursor(object_store_id, index_id, - key_range, direction, status); + key_range, direction); } } // namespace content::indexed_db
diff --git a/content/browser/indexed_db/instance/fake_transaction.h b/content/browser/indexed_db/instance/fake_transaction.h index 31d5590..ebf93edf 100644 --- a/content/browser/indexed_db/instance/fake_transaction.h +++ b/content/browser/indexed_db/instance/fake_transaction.h
@@ -81,28 +81,24 @@ const blink::IndexedDBKey& key, std::unique_ptr<blink::IndexedDBKey>* found_primary_key, bool* exists) override; - std::unique_ptr<indexed_db::BackingStore::Cursor> OpenObjectStoreKeyCursor( - int64_t object_store_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; - std::unique_ptr<indexed_db::BackingStore::Cursor> OpenObjectStoreCursor( - int64_t object_store_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; - std::unique_ptr<indexed_db::BackingStore::Cursor> OpenIndexKeyCursor( - int64_t object_store_id, - int64_t index_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; - std::unique_ptr<indexed_db::BackingStore::Cursor> OpenIndexCursor( - int64_t object_store_id, - int64_t index_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; + base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> + OpenObjectStoreKeyCursor(int64_t object_store_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) override; + base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> + OpenObjectStoreCursor(int64_t object_store_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) override; + base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> + OpenIndexKeyCursor(int64_t object_store_id, + int64_t index_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) override; + base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> + OpenIndexCursor(int64_t object_store_id, + int64_t index_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) override; private: Status result_;
diff --git a/content/browser/indexed_db/instance/leveldb/backing_store.cc b/content/browser/indexed_db/instance/leveldb/backing_store.cc index 63fd758..4406305 100644 --- a/content/browser/indexed_db/instance/leveldb/backing_store.cc +++ b/content/browser/indexed_db/instance/leveldb/backing_store.cc
@@ -2359,23 +2359,25 @@ const IndexedDBKeyRange& key_range) { // TODO(dmurph): Remove the need to create these cursors. // https://crbug.com/980678 - Status s; - std::unique_ptr<indexed_db::BackingStore::Cursor> start_cursor = - OpenObjectStoreCursor(object_store_id, key_range, - blink::mojom::IDBCursorDirection::Next, &s); - if (!s.ok()) { - return s; + auto result = OpenObjectStoreCursor(object_store_id, key_range, + blink::mojom::IDBCursorDirection::Next); + if (!result.has_value()) { + return result.error(); } + std::unique_ptr<indexed_db::BackingStore::Cursor> start_cursor = + std::move(*result); + if (!start_cursor) { return Status::OK(); // Empty range == delete success. } - std::unique_ptr<indexed_db::BackingStore::Cursor> end_cursor = - OpenObjectStoreCursor(object_store_id, key_range, - blink::mojom::IDBCursorDirection::Prev, &s); + result = OpenObjectStoreCursor(object_store_id, key_range, + blink::mojom::IDBCursorDirection::Prev); - if (!s.ok()) { - return s; + if (!result.has_value()) { + return result.error(); } + std::unique_ptr<indexed_db::BackingStore::Cursor> end_cursor = + std::move(*result); if (!end_cursor) { return Status::OK(); // Empty range == delete success. } @@ -2396,8 +2398,8 @@ return InternalInconsistencyStatus(); } - s = DeleteBlobsInRange(this, database_id(), start_blob_number.Encode(), - end_blob_number.Encode(), false); + Status s = DeleteBlobsInRange(this, database_id(), start_blob_number.Encode(), + end_blob_number.Encode(), false); if (!s.ok()) { return s; } @@ -3920,109 +3922,97 @@ return s->ok(); } -std::unique_ptr<indexed_db::BackingStore::Cursor> +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> BackingStore::Transaction::OpenObjectStoreCursor( int64_t object_store_id, const IndexedDBKeyRange& range, - blink::mojom::IDBCursorDirection direction, - Status* s) { + blink::mojom::IDBCursorDirection direction) { TRACE_EVENT0("IndexedDB", "BackingStore::OpenObjectStoreCursor"); TransactionalLevelDBTransaction* leveldb_transaction = transaction(); BackingStore::Cursor::CursorOptions cursor_options; cursor_options.mode = mode(); // TODO(cmumford): Handle this error (crbug.com/363397) + Status s; if (!ObjectStoreCursorOptions(leveldb_transaction, database_id(), object_store_id, range, direction, - &cursor_options, s)) { + &cursor_options, &s)) { + if (!s.ok()) { + return base::unexpected(s); + } return nullptr; } - std::unique_ptr<ObjectStoreCursorImpl> cursor( - std::make_unique<ObjectStoreCursorImpl>(AsWeakPtr(), database_id(), - cursor_options)); - if (!cursor->FirstSeek(s)) { - return nullptr; - } - - return std::move(cursor); + return PrepareCursor(std::make_unique<ObjectStoreCursorImpl>( + AsWeakPtr(), database_id(), cursor_options)); } -std::unique_ptr<indexed_db::BackingStore::Cursor> +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> BackingStore::Transaction::OpenObjectStoreKeyCursor( int64_t object_store_id, const IndexedDBKeyRange& range, - blink::mojom::IDBCursorDirection direction, - Status* s) { + blink::mojom::IDBCursorDirection direction) { TRACE_EVENT0("IndexedDB", "BackingStore::OpenObjectStoreKeyCursor"); TransactionalLevelDBTransaction* leveldb_transaction = transaction(); BackingStore::Cursor::CursorOptions cursor_options; cursor_options.mode = mode(); // TODO(cmumford): Handle this error (crbug.com/363397) + Status s; if (!ObjectStoreCursorOptions(leveldb_transaction, database_id(), object_store_id, range, direction, - &cursor_options, s)) { + &cursor_options, &s)) { + if (!s.ok()) { + return base::unexpected(s); + } return nullptr; } - std::unique_ptr<ObjectStoreKeyCursorImpl> cursor( - std::make_unique<ObjectStoreKeyCursorImpl>(AsWeakPtr(), database_id(), - cursor_options)); - if (!cursor->FirstSeek(s)) { - return nullptr; - } - - return std::move(cursor); + return PrepareCursor(std::make_unique<ObjectStoreKeyCursorImpl>( + AsWeakPtr(), database_id(), cursor_options)); } -std::unique_ptr<indexed_db::BackingStore::Cursor> +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> BackingStore::Transaction::OpenIndexKeyCursor( int64_t object_store_id, int64_t index_id, const IndexedDBKeyRange& range, - blink::mojom::IDBCursorDirection direction, - Status* s) { + blink::mojom::IDBCursorDirection direction) { TRACE_EVENT0("IndexedDB", "BackingStore::OpenIndexKeyCursor"); - *s = Status::OK(); TransactionalLevelDBTransaction* leveldb_transaction = transaction(); BackingStore::Cursor::CursorOptions cursor_options; cursor_options.mode = mode(); + Status s; if (!IndexCursorOptions(leveldb_transaction, database_id(), object_store_id, - index_id, range, direction, &cursor_options, s)) { + index_id, range, direction, &cursor_options, &s)) { + if (!s.ok()) { + return base::unexpected(s); + } return nullptr; } - std::unique_ptr<IndexKeyCursorImpl> cursor( - std::make_unique<IndexKeyCursorImpl>(AsWeakPtr(), database_id(), - cursor_options)); - if (!cursor->FirstSeek(s)) { - return nullptr; - } - - return std::move(cursor); + return PrepareCursor(std::make_unique<IndexKeyCursorImpl>( + AsWeakPtr(), database_id(), cursor_options)); } -std::unique_ptr<indexed_db::BackingStore::Cursor> +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> BackingStore::Transaction::OpenIndexCursor( int64_t object_store_id, int64_t index_id, const IndexedDBKeyRange& range, - blink::mojom::IDBCursorDirection direction, - Status* s) { + blink::mojom::IDBCursorDirection direction) { TRACE_EVENT0("IndexedDB", "BackingStore::OpenIndexCursor"); TransactionalLevelDBTransaction* leveldb_transaction = transaction(); BackingStore::Cursor::CursorOptions cursor_options; cursor_options.mode = mode(); + Status s; if (!IndexCursorOptions(leveldb_transaction, database_id(), object_store_id, - index_id, range, direction, &cursor_options, s)) { + index_id, range, direction, &cursor_options, &s)) { + if (!s.ok()) { + return base::unexpected(s); + } return nullptr; } - auto cursor = std::make_unique<IndexCursorImpl>(AsWeakPtr(), database_id(), - cursor_options); - if (!cursor->FirstSeek(s)) { - return nullptr; - } - - return cursor; + return PrepareCursor(std::make_unique<IndexCursorImpl>( + AsWeakPtr(), database_id(), cursor_options)); } bool BackingStore::IsBlobCleanupPending() { @@ -4276,6 +4266,20 @@ } } +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> +BackingStore::Transaction::PrepareCursor(std::unique_ptr<Cursor> cursor) { + Status s; + if (cursor->FirstSeek(&s)) { + DCHECK(s.ok()); + return cursor; + } + + if (!s.ok()) { + return base::unexpected(s); + } + return nullptr; +} + Status BackingStore::Transaction::CommitPhaseOne(BlobWriteCallback callback) { DCHECK(transaction_.get()); DCHECK(backing_store_);
diff --git a/content/browser/indexed_db/instance/leveldb/backing_store.h b/content/browser/indexed_db/instance/leveldb/backing_store.h index 5659f52..4c99960 100644 --- a/content/browser/indexed_db/instance/leveldb/backing_store.h +++ b/content/browser/indexed_db/instance/leveldb/backing_store.h
@@ -113,6 +113,8 @@ base::WeakPtrFactory<Database> weak_factory_{this}; }; + class Cursor; + // This class could be moved to the implementation file, but it's left here to // avoid needless git churn. class CONTENT_EXPORT Transaction @@ -208,28 +210,24 @@ const blink::IndexedDBKey& key, std::unique_ptr<blink::IndexedDBKey>* found_primary_key, bool* exists) override; - std::unique_ptr<indexed_db::BackingStore::Cursor> OpenObjectStoreKeyCursor( - int64_t object_store_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; - std::unique_ptr<indexed_db::BackingStore::Cursor> OpenObjectStoreCursor( - int64_t object_store_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; - std::unique_ptr<indexed_db::BackingStore::Cursor> OpenIndexKeyCursor( - int64_t object_store_id, - int64_t index_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; - std::unique_ptr<indexed_db::BackingStore::Cursor> OpenIndexCursor( - int64_t object_store_id, - int64_t index_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; + base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> + OpenObjectStoreKeyCursor(int64_t object_store_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) override; + base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> + OpenObjectStoreCursor(int64_t object_store_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) override; + base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> + OpenIndexKeyCursor(int64_t object_store_id, + int64_t index_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) override; + base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> + OpenIndexCursor(int64_t object_store_id, + int64_t index_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) override; Status PutExternalObjectsIfNeeded(const std::string& object_store_data_key, std::vector<IndexedDBExternalObject>*); @@ -284,6 +282,11 @@ void PartitionBlobsToRemove(BlobJournalType* dead_blobs, BlobJournalType* live_blobs) const; + // Prepares a cursor and returns it if successful, an error Status if + // there's an error, or null if the cursor is empty. + base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> + PrepareCursor(std::unique_ptr<Cursor> cursor); + // This does NOT mean that this class can outlive the BackingStore. // This is only to protect against security issues before this class is // refactored away and this isn't necessary.
diff --git a/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.cc b/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.cc index 3cdd7a4..7a2a491 100644 --- a/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.cc +++ b/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.cc
@@ -161,44 +161,40 @@ return Status::OK(); } -std::unique_ptr<BackingStore::Cursor> +base::expected<std::unique_ptr<BackingStore::Cursor>, Status> BackingStoreTransactionImpl::OpenObjectStoreKeyCursor( int64_t object_store_id, const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) { + blink::mojom::IDBCursorDirection) { NOTIMPLEMENTED(); return nullptr; } -std::unique_ptr<BackingStore::Cursor> +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> BackingStoreTransactionImpl::OpenObjectStoreCursor( int64_t object_store_id, const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) { + blink::mojom::IDBCursorDirection) { NOTIMPLEMENTED(); return nullptr; } -std::unique_ptr<BackingStore::Cursor> +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> BackingStoreTransactionImpl::OpenIndexKeyCursor( int64_t object_store_id, int64_t index_id, const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) { + blink::mojom::IDBCursorDirection) { NOTIMPLEMENTED(); return nullptr; } -std::unique_ptr<BackingStore::Cursor> +base::expected<std::unique_ptr<indexed_db::BackingStore::Cursor>, Status> BackingStoreTransactionImpl::OpenIndexCursor( int64_t object_store_id, int64_t index_id, const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) { + blink::mojom::IDBCursorDirection) { NOTIMPLEMENTED(); return nullptr; }
diff --git a/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.h b/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.h index 5d97093e..581a2ce 100644 --- a/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.h +++ b/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.h
@@ -81,28 +81,24 @@ const blink::IndexedDBKey& key, std::unique_ptr<blink::IndexedDBKey>* found_primary_key, bool* exists) override; - std::unique_ptr<BackingStore::Cursor> OpenObjectStoreKeyCursor( - int64_t object_store_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; - std::unique_ptr<BackingStore::Cursor> OpenObjectStoreCursor( - int64_t object_store_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; - std::unique_ptr<BackingStore::Cursor> OpenIndexKeyCursor( + base::expected<std::unique_ptr<BackingStore::Cursor>, Status> + OpenObjectStoreKeyCursor(int64_t object_store_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) override; + base::expected<std::unique_ptr<BackingStore::Cursor>, Status> + OpenObjectStoreCursor(int64_t object_store_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) override; + base::expected<std::unique_ptr<BackingStore::Cursor>, Status> + OpenIndexKeyCursor(int64_t object_store_id, + int64_t index_id, + const blink::IndexedDBKeyRange& key_range, + blink::mojom::IDBCursorDirection) override; + base::expected<std::unique_ptr<BackingStore::Cursor>, Status> OpenIndexCursor( int64_t object_store_id, int64_t index_id, const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; - std::unique_ptr<BackingStore::Cursor> OpenIndexCursor( - int64_t object_store_id, - int64_t index_id, - const blink::IndexedDBKeyRange& key_range, - blink::mojom::IDBCursorDirection, - Status*) override; + blink::mojom::IDBCursorDirection) override; protected: base::WeakPtr<BackingStoreDatabaseImpl> db_;
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc index d40f87a..0db1ac0 100644 --- a/content/browser/interest_group/auction_runner_unittest.cc +++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -1834,12 +1834,14 @@ std::set<std::string> interest_group_names; std::set<std::string> keys; base::Value::Dict additional_params; + std::optional<std::string> buyer_tkv_signals; bool operator<(const BiddingPartitionInfo& other) const { return std::tie(partition_id, interest_group_names, keys, - additional_params) < + additional_params, buyer_tkv_signals) < std::tie(other.partition_id, other.interest_group_names, - other.keys, other.additional_params); + other.keys, other.additional_params, + other.buyer_tkv_signals); } }; @@ -2001,7 +2003,10 @@ for (const auto& partition : compression_group.second) { partitions.emplace_back(BiddingPartitionInfo{ partition.partition_id, *partition.interest_group_names, - *partition.keys, partition.additional_params->Clone()}); + *partition.keys, partition.additional_params->Clone(), + partition.buyer_tkv_signals == nullptr + ? std::nullopt + : std::make_optional(*partition.buyer_tkv_signals)}); } request_info.compression_groups.emplace(compression_group.first, std::move(partitions)); @@ -2376,6 +2381,9 @@ auction_config.per_buyer_experiment_group_ids[kv.first] = kv.second; } + auction_config.non_shared_params.per_buyer_tkv_signals = + per_buyer_tkv_signals_; + auction_config.non_shared_params.all_buyers_group_limit = all_buyers_group_limit_; auction_config.non_shared_params.all_buyers_priority_signals = @@ -3848,6 +3856,7 @@ std::optional<uint16_t> seller_experiment_group_id_; std::optional<uint16_t> all_buyer_experiment_group_id_; std::map<url::Origin, uint16_t> per_buyer_experiment_group_id_; + base::flat_map<url::Origin, std::string> per_buyer_tkv_signals_; uint16_t all_buyers_group_limit_ = std::numeric_limits<std::uint16_t>::max(); std::optional<base::flat_map<std::string, double>> all_buyers_priority_signals_; @@ -27966,6 +27975,112 @@ EXPECT_EQ(GURL("https://ad1.com/"), result_.ad_descriptor->url); } +// Test that `buyer_tkv_signals` is respected in the case of trusted KVv2 +// bidding signals. This test completely depends on the checks in +// MockTrustedSignalsCache that exactly the expected signals requests were made +// to the cache. +TEST_P(AuctionRunnerTrustedSignalsTest, TrustedSignalsKVv2BuyerTKVSignals) { + // Only KVv2 request contains contextual data which is buyer_tkv_signals for + // bidding signals. + if (!UsingKVv2Signals()) { + return; + } + + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + blink::features::kFledgeTrustedSignalsKVv2ContextualData); + + per_buyer_tkv_signals_[kBidder1] = "signals"; + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeConstBidScript(1, "https://ad1.com/")); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + kMinimumDecisionScript); + + std::vector<StorageInterestGroup> bidders; + bidders.emplace_back(MakeInterestGroup( + kBidder1, kBidder1Name, kBidder1Url, kBidder1TrustedSignalsUrl, + {"k1", "k2"}, GURL("https://ad1.com"), /*ad_component_urls=*/std::nullopt, + coordinator_origin_)); + + auto bidder1_request_info = DefaultBidder1SignalsRequestInfo(); + bidder1_request_info.compression_groups[0][0].buyer_tkv_signals = "signals"; + // The actual response doesn't matter - this test depends on the logic in + // MockTrustedSignalsCache to verify all the expected requests were sent, with + // the correct parameters. + AddBiddingSignalsCacheResult(std::move(bidder1_request_info), + MakeBidder1CompressionGroupMap()); + + RunAuctionAndWait(kSellerUrl, std::move(bidders)); + EXPECT_EQ(GURL("https://ad1.com/"), result_.ad_descriptor->url); +} + +// Test that `buyer_tkv_signals` set with bidder2 will not show up in the +// request of bidder1's trusted KVv2 bidding signals. This test completely +// depends on the checks in MockTrustedSignalsCache that exactly the expected +// signals requests were made to the cache. +TEST_P(AuctionRunnerTrustedSignalsTest, + TrustedSignalsKVv2BuyerTKVSignalsWithWrongBuyer) { + // Only KVv2 request contains contextual data which is buyer_tkv_signals for + // bidding signals. + if (!UsingKVv2Signals()) { + return; + } + + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + blink::features::kFledgeTrustedSignalsKVv2ContextualData); + + // Set up per_buyer_tkv_signals with only bidder2's origin and "signals" will + // not show up in bidder1's bidding signals request. + per_buyer_tkv_signals_[kBidder2] = "signals"; + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeConstBidScript(1, "https://ad1.com/")); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + kMinimumDecisionScript); + + std::vector<StorageInterestGroup> bidders; + bidders.emplace_back(MakeInterestGroup( + kBidder1, kBidder1Name, kBidder1Url, kBidder1TrustedSignalsUrl, + {"k1", "k2"}, GURL("https://ad1.com"), /*ad_component_urls=*/std::nullopt, + coordinator_origin_)); + + AddDefaultBidder1SignalsResult(); + RunAuctionAndWait(kSellerUrl, std::move(bidders)); + EXPECT_EQ(GURL("https://ad1.com/"), result_.ad_descriptor->url); +} + +// When the feature is disabled, ensure `buyer_tkv_signals` is not included in +// bidder1's bidding signals request even have the correct bidder origin. This +// test completely depends on the checks in MockTrustedSignalsCache that exactly +// the expected signals requests were made to the cache. +TEST_P(AuctionRunnerTrustedSignalsTest, + TrustedSignalsKVv2BuyerTKVSignalsFeatureDisabled) { + // Only KVv2 request contains contextual data which is buyer_tkv_signals for + // bidding signals. + if (!UsingKVv2Signals()) { + return; + } + + per_buyer_tkv_signals_[kBidder1] = "signals"; + auction_worklet::AddJavascriptResponse( + &url_loader_factory_, kBidder1Url, + MakeConstBidScript(1, "https://ad1.com/")); + auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl, + kMinimumDecisionScript); + + std::vector<StorageInterestGroup> bidders; + bidders.emplace_back(MakeInterestGroup( + kBidder1, kBidder1Name, kBidder1Url, kBidder1TrustedSignalsUrl, + {"k1", "k2"}, GURL("https://ad1.com"), /*ad_component_urls=*/std::nullopt, + coordinator_origin_)); + + AddDefaultBidder1SignalsResult(); + RunAuctionAndWait(kSellerUrl, std::move(bidders)); + EXPECT_EQ(GURL("https://ad1.com/"), result_.ad_descriptor->url); +} + TEST_F(AuctionRunnerTest, TrustedBiddingSignalsJointBatchedRequests) { url_loader_factory_.ClearResponses(); auction_worklet::AddJavascriptResponse(
diff --git a/content/browser/interest_group/interest_group_auction.cc b/content/browser/interest_group/interest_group_auction.cc index b96ca48c..230d99d 100644 --- a/content/browser/interest_group/interest_group_auction.cc +++ b/content/browser/interest_group/interest_group_auction.cc
@@ -2392,7 +2392,7 @@ *interest_group.trusted_bidding_signals_coordinator, interest_group.trusted_bidding_signals_keys, std::move(additional_params), - /*buyer_tkv_signals=*/std::nullopt, partition_id); + auction_->GetBuyerTKVSignals(owner_), partition_id); return auction_worklet::mojom::TrustedSignalsCacheKey::New( bid_state.bidding_signals_handle->compression_group_token(), partition_id); @@ -4790,6 +4790,21 @@ return std::max(val, uint16_t{1}); } +std::optional<std::string> InterestGroupAuction::GetBuyerTKVSignals( + const url::Origin& owner) const { + if (!base::FeatureList::IsEnabled( + blink::features::kFledgeTrustedSignalsKVv2ContextualData)) { + return std::nullopt; + } + + auto it = config_->non_shared_params.per_buyer_tkv_signals.find(owner); + if (it != config_->non_shared_params.per_buyer_tkv_signals.end()) { + return it->second; + } + + return std::nullopt; +} + std::optional<uint16_t> InterestGroupAuction::GetBuyerExperimentId( const blink::AuctionConfig& config, const url::Origin& buyer) {
diff --git a/content/browser/interest_group/interest_group_auction.h b/content/browser/interest_group/interest_group_auction.h index c758e33..89751b9 100644 --- a/content/browser/interest_group/interest_group_auction.h +++ b/content/browser/interest_group/interest_group_auction.h
@@ -1210,6 +1210,10 @@ // ensuring that it's at least 1. uint16_t GetBuyerMultiBidLimit(const url::Origin& buyer); + // Gets the buyer `per-buyer-tkv-signals` in `config` for interest group + // buyer. + std::optional<std::string> GetBuyerTKVSignals(const url::Origin& buyer) const; + // ----------------------------------- // Methods not associated with a phase // -----------------------------------
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc index 7f58365c..2383ed931 100644 --- a/content/browser/interest_group/interest_group_browsertest.cc +++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -25,11 +25,13 @@ #include "base/containers/contains.h" #include "base/containers/flat_map.h" #include "base/containers/flat_set.h" +#include "base/containers/span_reader.h" #include "base/feature_list.h" #include "base/functional/callback.h" #include "base/functional/callback_forward.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" +#include "base/json/string_escape.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/run_loop.h" @@ -225,6 +227,8 @@ 0xd1, 0x8d, 0x16, 0x57, 0x5c, 0xe7, 0x3a, 0x2c, 0x60, 0x22, 0xfb, 0x44, 0xe4, 0xc8, 0x5a, 0xb5, 0x41, 0xee, 0xf9, 0x34, 0xee}; +constexpr char kNoContextualDataValue[] = "\"no contextual data\""; + std::string base64Decode(std::string_view input) { std::string bytes; CHECK(base::Base64UrlDecode( @@ -790,6 +794,7 @@ // TODO(crrev.com/c/6096602): Remove once implementation is removed. {blink::features::kFledgeDirectFromSellerSignalsWebBundles, {}}, {blink::features::kFledgeTrustedSignalsKVv1CreativeScanning, {}}, + {blink::features::kFledgeTrustedSignalsKVv2ContextualData, {}}, {features::kFledgeTextConversionHelpers, {}}, {network::features::kAdAuctionEventRegistration, {}}, // Needed for reliable handling of click ARA (and hence clickiness) @@ -6413,20 +6418,7 @@ EXPECT_TRUE(console_observer.Wait()); } -class InterestGroupContextualDataBrowserTest : public InterestGroupBrowserTest { - public: - InterestGroupContextualDataBrowserTest() { - feature_list_.InitWithFeatures( - {/*enabled_features=*/blink::features:: - kFledgeTrustedSignalsKVv2ContextualData}, - /*disabled_features=*/{}); - } - - protected: - base::test::ScopedFeatureList feature_list_; -}; - -IN_PROC_BROWSER_TEST_F(InterestGroupContextualDataBrowserTest, +IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, RunAdAuctionInvalidPerBuyerTKVSignalsOrigin) { GURL test_url = embedded_https_test_server().GetURL("a.test", "/echo"); url::Origin test_origin = url::Origin::Create(test_url); @@ -6452,7 +6444,7 @@ WaitForAccessObserved({}); } -IN_PROC_BROWSER_TEST_F(InterestGroupContextualDataBrowserTest, +IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, RunAdAuctionInvalidPerBuyerTKVSignals) { GURL test_url = embedded_https_test_server().GetURL("a.test", "/echo"); url::Origin test_origin = url::Origin::Create(test_url); @@ -6477,7 +6469,32 @@ WaitForAccessObserved({}); } -IN_PROC_BROWSER_TEST_F(InterestGroupContextualDataBrowserTest, +IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, + RunAdAuctionUndefinedPerBuyerTKVSignals) { + GURL test_url = embedded_https_test_server().GetURL("a.test", "/echo"); + url::Origin test_origin = url::Origin::Create(test_url); + GURL decision_url = embedded_https_test_server().GetURL( + "a.test", "/interest_group/decision_logic.js"); + ASSERT_TRUE(NavigateToURL(shell(), test_url)); + + AttachInterestGroupObserver(); + + EXPECT_EQ(base::StringPrintf( + "TypeError: Failed to execute 'runAdAuction' on 'Navigator': " + "perBuyerTKVSignals for AuctionAdConfig with seller '%s' must " + "be a JSON-serializable object.", + test_origin.Serialize().c_str()), + RunAuctionAndWait(JsReplace(R"({ + seller: $1, + decisionLogicURL: $2, + perBuyerTKVSignals: {'https://test.com': undefined}, + interestGroupBuyers: [] + })", + test_origin, decision_url))); + WaitForAccessObserved({}); +} + +IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, RunAdAuctionInvalidSellerTKVSignals) { GURL test_url = embedded_https_test_server().GetURL("a.test", "/echo"); url::Origin test_origin = url::Origin::Create(test_url); @@ -6506,7 +6523,7 @@ // Exercise rejection path in the renderer for promise-delivered // sellerTKVSignals. -IN_PROC_BROWSER_TEST_F(InterestGroupContextualDataBrowserTest, +IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, RunAdAuctionRejectPromiseSellerTKVSignals) { GURL test_url = embedded_https_test_server().GetURL("a.test", "/echo"); url::Origin test_origin = url::Origin::Create(test_url); @@ -6531,7 +6548,7 @@ // Exercise error-handling path in the renderer for promise-delivered // sellerTKVSignals. -IN_PROC_BROWSER_TEST_F(InterestGroupContextualDataBrowserTest, +IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, RunAdAuctionResolvePromiseInvalidSellerTKVSignals) { GURL test_url = embedded_https_test_server().GetURL("a.test", "/echo"); url::Origin test_origin = url::Origin::Create(test_url); @@ -29470,6 +29487,291 @@ EXPECT_EQ(ad_url, RunAuctionAndWaitForUrl(auction_config)); } +class InterestGroupTrustedSignalsKVv2ContextualDataBrowserTest + : public InterestGroupTrustedSignalsKVv2BrowserTest { + public: + void SetUpOnMainThread() override { + embedded_https_test_server().RegisterRequestHandler( + base::BindRepeating(&HandleTrustedKVv2Signals)); + + InterestGroupPrivateNetworkBrowserTest::SetUpOnMainThread(); + } + + void TestPerBuyerTKVSignals(const std::string& expected_bidding_key, + const std::string& buyer_tkv_signals) { + const char kPublisher[] = "a.test"; + const char kBidder[] = "b.test"; + const char kSeller[] = "c.test"; + + GURL test_url = embedded_https_test_server().GetURL( + kPublisher, "/page_with_iframe.html"); + GURL ad_url = + embedded_https_test_server().GetURL(kBidder, "/echo?render_cars"); + GURL bidder_url = embedded_https_test_server().GetURL(kBidder, "/echo"); + GURL bidder_script_url = embedded_https_test_server().GetURL( + kBidder, + "/interest_group/bidding_logic_trusted_kvv2_bidding_signals.js"); + GURL bidder_signals_url = embedded_https_test_server().GetURL( + kBidder, "/trusted_kvv2_bidding_signals"); + GURL seller_script_url = embedded_https_test_server().GetURL( + kSeller, "/interest_group/decision_logic.js"); + + ConfigureSignalsServerKeys({url::Origin::Create(bidder_signals_url)}); + + url::Origin bidder_origin = url::Origin::Create(bidder_script_url); + url::Origin seller_origin = url::Origin::Create(seller_script_url); + + // Navigate to bidder site, and add an interest group. + ASSERT_TRUE(NavigateToURL(shell(), bidder_url)); + EXPECT_EQ( + kSuccess, + JoinInterestGroupAndVerify( + blink::TestInterestGroupBuilder( + /*owner=*/bidder_origin, + /*name=*/"group") + .SetBiddingUrl(bidder_script_url) + .SetTrustedBiddingSignalsUrl(bidder_signals_url) + .SetTrustedBiddingSignalsKeys({{"bidderTKVSignals"}}) + .SetAds( + /*ads=*/{{{ad_url, /*metadata=*/std::nullopt}}}) + .SetTrustedBiddingSignalsCoordinator( + url::Origin::Create(GURL("https://coordinator.test"))) + .SetExecutionMode( + blink::InterestGroup::ExecutionMode::kGroupedByOriginMode) + .Build())); + + // Register a bidder script that only bids if `trustedBiddingSignals` is + // successfully fetched. + const char kBidderScript[] = R"( + function generateBid( + interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals, + browserSignals, directFromSellerSignals, + crossOriginTrustedBiddingSignals) { + if ('crossOriginDataVersion' in browserSignals) { + throw 'Unexpected crossOriginDataVersion in browserSignals.'; + } + + if (crossOriginTrustedBiddingSignals !== null) { + throw 'Unexpected crossOriginTrustedBiddingSignals found.'; + } + + if (trustedBiddingSignals.bidderTKVSignals !== %s) { + throw 'Unexpected trustedBiddingSignals: ' + + JSON.stringify(trustedBiddingSignals); + } + + return { + bid: 1, + render: interestGroup.ads[0].renderURL, + }; + })"; + + network_responder_->RegisterNetworkResponse( + bidder_script_url.path(), + base::StringPrintf(kBidderScript, expected_bidding_key.c_str()), + "application/javascript"); + + // Navigate to publisher. + ASSERT_TRUE( + NavigateToURL(shell(), embedded_https_test_server().GetURL( + kPublisher, "/page_with_iframe.html"))); + + const char kAuctionConfig[] = + R"({ + seller: "%s", + decisionLogicURL: "%s", + interestGroupBuyers: ["%s"], + perBuyerTKVSignals: {"%s": %s}, + })"; + + std::string auction_config = base::StringPrintf( + kAuctionConfig, seller_origin.Serialize().c_str(), + seller_script_url.spec().c_str(), bidder_origin.Serialize().c_str(), + bidder_origin.Serialize().c_str(), buyer_tkv_signals.c_str()); + + EXPECT_EQ(ad_url, RunAuctionAndWaitForUrl(auction_config)); + } + + protected: + static std::unique_ptr<net::test_server::HttpResponse> + HandleTrustedKVv2Signals(const net::test_server::HttpRequest& request) { + if (!base::StartsWith(request.relative_url, + "/trusted_kvv2_bidding_signals")) { + return nullptr; + } + + // Only posts should be sent to the KVv2 serer - no GETs or OPTIONs. + EXPECT_EQ(request.method, net::test_server::METHOD_POST); + + constexpr char kBiddingBase[] = + R"([ + { + "id": 0, + "keyGroupOutputs": [ + { + "tags": [ + "keys" + ], + "keyValues": { + "bidderTKVSignals": { + "value": "%s" + } + } + } + ] + } + ])"; + + // Decrypt the request. + auto response_key_config = quiche::ObliviousHttpHeaderKeyConfig::Create( + kTestPrivacySandboxCoordinatorId, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, + EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM); + CHECK(response_key_config.ok()) << response_key_config.status(); + + auto ohttp_gateway = quiche::ObliviousHttpGateway::Create( + GetTestPrivacySandboxCoordinatorPrivateKey(), + response_key_config.value()) + .value(); + + auto received_request = ohttp_gateway.DecryptObliviousHttpRequest( + request.content, "message/ad-auction-trusted-signals-request"); + CHECK(received_request.ok()) << received_request.status(); + + // Get the request body as a CBOR value. + base::span<const uint8_t> body_span = + base::as_byte_span(received_request->GetPlaintextData()); + base::SpanReader reader(body_span); + // Skip the first 1 byte since the request is always uncompressed. + reader.Skip(1u); + uint32_t length; + reader.ReadU32BigEndian(length); + std::optional<base::span<const uint8_t>> cbor_bytes = reader.Read(length); + CHECK(cbor_bytes); + std::optional<cbor::Value> request_body = + cbor::Reader::Read(base::span(cbor_bytes.value())); + CHECK(request_body); + + // Extract the `contextualData` from the request body. + std::string contextual_data = kNoContextualDataValue; + const cbor::Value::MapValue& request_map = request_body->GetMap(); + + auto per_partition_metadata_it = + request_map.find(cbor::Value("perPartitionMetadata")); + if (per_partition_metadata_it != request_map.end()) { + const cbor::Value::ArrayValue& contextual_data_array = + per_partition_metadata_it->second.GetMap() + .at(cbor::Value("contextualData")) + .GetArray(); + + // With current browser test framework setup, there should only be one + // contextual data entry. + CHECK(contextual_data_array.size() == 1u); + contextual_data = contextual_data_array[0] + .GetMap() + .at(cbor::Value("value")) + .GetString(); + } + + // Construct the response body. + std::string escaped_contextual_data; + CHECK(base::EscapeJSONString(contextual_data, + /*put_in_quotes=*/false, + &escaped_contextual_data)); + std::string content = + base::StringPrintf(kBiddingBase, escaped_contextual_data.c_str()); + + cbor::Value::MapValue compression_group; + compression_group.try_emplace(cbor::Value("compressionGroupId"), + cbor::Value(0)); + compression_group.try_emplace( + cbor::Value("content"), + cbor::Value(auction_worklet::test::ToCborVector(content))); + + cbor::Value::ArrayValue compression_groups; + compression_groups.emplace_back(std::move(compression_group)); + + cbor::Value::MapValue body_map; + body_map.try_emplace(cbor::Value("compressionGroups"), + cbor::Value(std::move(compression_groups))); + + cbor::Value body_value(std::move(body_map)); + std::optional<std::vector<uint8_t>> maybe_body_bytes = + cbor::Writer::Write(body_value); + + std::string response_body = auction_worklet::test::CreateKVv2ResponseBody( + base::as_string_view(maybe_body_bytes.value())); + auto response_context = + std::move(received_request).value().ReleaseContext(); + + // Encrypt the response body. + auto maybe_response = ohttp_gateway.CreateObliviousHttpResponse( + std::move(response_body), response_context, + "message/ad-auction-trusted-signals-response"); + EXPECT_TRUE(maybe_response.ok()) << maybe_response.status(); + + auto response = std::make_unique<net::test_server::BasicHttpResponse>(); + response->set_content_type("message/ad-auction-trusted-signals-response"); + response->set_content(maybe_response->EncapsulateAndSerialize()); + response->AddCustomHeader("Ad-Auction-Allowed", "true"); + + return response; + } + + const url::Origin kCoordinatorOrigin = + url::Origin::Create(GURL("https://coordinator.test")); +}; + +INSTANTIATE_TEST_SUITE_P( + All, + InterestGroupTrustedSignalsKVv2ContextualDataBrowserTest, + testing::Values(true)); + +IN_PROC_BROWSER_TEST_P(InterestGroupTrustedSignalsKVv2ContextualDataBrowserTest, + PerBuyerTKVSignalsIsInteger) { + TestPerBuyerTKVSignals(/*expected_bidding_key=*/"100", + /*buyer_tkv_signals=*/"100"); +} + +IN_PROC_BROWSER_TEST_P(InterestGroupTrustedSignalsKVv2ContextualDataBrowserTest, + PerBuyerTKVSignalsIsString) { + TestPerBuyerTKVSignals(/*expected_bidding_key=*/"\"contextual data\"", + /*buyer_tkv_signals=*/"\"contextual data\""); +} + +IN_PROC_BROWSER_TEST_P(InterestGroupTrustedSignalsKVv2ContextualDataBrowserTest, + PerBuyerTKVSignalsIsArray) { + TestPerBuyerTKVSignals(/*expected_bidding_key=*/"\"[1, 2, 3]\"", + /*buyer_tkv_signals=*/"\"[1, 2, 3]\""); +} + +IN_PROC_BROWSER_TEST_P(InterestGroupTrustedSignalsKVv2ContextualDataBrowserTest, + PerBuyerTKVSignalsIsNull) { + TestPerBuyerTKVSignals(/*expected_bidding_key=*/"null", + /*buyer_tkv_signals=*/"null"); +} + +class DisableKVv2ContextualDataBrowserTest + : public InterestGroupTrustedSignalsKVv2ContextualDataBrowserTest { + public: + DisableKVv2ContextualDataBrowserTest() { + feature_list_.InitAndDisableFeature( + blink::features::kFledgeTrustedSignalsKVv2ContextualData); + } + + protected: + base::test::ScopedFeatureList feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P(All, + DisableKVv2ContextualDataBrowserTest, + testing::Values(true)); + +IN_PROC_BROWSER_TEST_P(DisableKVv2ContextualDataBrowserTest, + PerBuyerTKVSignalsWithDisabledFeature) { + TestPerBuyerTKVSignals(/*expected_bidding_key=*/kNoContextualDataValue, + /*buyer_tkv_signals=*/"\"contextual data\""); +} + class DisableLocalAuctionInterestGroupBrowserTest : public InterestGroupBrowserTest { public: @@ -29524,9 +29826,9 @@ DisableLocalAuctions) { SetUpTestWithOneInterestGroup(); // If local auctions are disable via kFledgeDisableLocalAdsAuctions and - // there's no "serverResponse" key in the auctionConfig, runAdAuction will not - // throw an error. It will return nullptr, which matches what happens when - // there is no auction winner. + // there's no "serverResponse" key in the auctionConfig, runAdAuction will + // not throw an error. It will return nullptr, which matches what happens + // when there is no auction winner. EXPECT_EQ(nullptr, RunAuctionAndWait(JsReplace( R"({ seller: $1,
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 4e4dd67..f5534e1b 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -1630,11 +1630,14 @@ perfetto::Track::Global(kGlobalInstantTrackId)); // Define a helper to log both a trace event slice and a corresponding metric - // for one stage of a navigation. + // for one stage of a navigation. If `histogram_name` is specified, it will be + // used for the histogram name instead of `name`. If `url` is specified, it + // will be emitted as page_load.url argument along the trace event. auto log_trace_event_and_uma = - [&](const std::string& name, const perfetto::NamedTrack track, + [&](perfetto::StaticString name, const perfetto::NamedTrack track, const base::TimeTicks& begin_time, const base::TimeTicks& end_time, - const std::string& histogram_name = std::string()) { + const std::string& histogram_name = std::string(), + const std::string& url = std::string()) { if (begin_time.is_null() || end_time.is_null()) { return; } @@ -1657,8 +1660,15 @@ return; } - TRACE_EVENT_BEGIN("navigation", perfetto::DynamicString{name}, track, - begin_time); + TRACE_EVENT_BEGIN("navigation", name, track, begin_time, + [&](perfetto::EventContext& ctx) { + if (url.empty()) { + return; + } + perfetto::protos::pbzero::PageLoad* page_load = + ctx.event<ChromeTrackEvent>()->set_page_load(); + page_load->set_url(url); + }); TRACE_EVENT_END("navigation", track, end_time); // When provided, `histogram_name` is used to avoid including variable @@ -1668,23 +1678,32 @@ // URL in metric names for UMA. base::UmaHistogramTimes( "Navigation.Timeline." + - (histogram_name.empty() ? name : histogram_name) + ".Duration", + (histogram_name.empty() ? std::string(name.value) + : histogram_name) + + ".Duration", end_time - begin_time); }; // Actual navigation events are logged below in contiguous (or nested) // intervals. - // Record a top-level "Navigation: url" trace event with the duration of the + // Record a top-level "Navigation" trace event with the duration of the // full navigation, and then break it down into nested intervals which will - // show up under it. Do not include `url` in the histogram name. Note that - // `url` is the committing URL, which might differ from the starting URL, e.g. - // due to redirects. + // show up under it. Note that `url` is the committing URL, which might differ + // from the starting URL, e.g. due to redirects. // TODO(crbug.com/405437928): Overlapping navigations may incorrectly appear // to be nested, using the wrong end times. + log_trace_event_and_uma("NavigationTotal", track1, timeline.start, + timeline.finish, + /*histogram_name=*/"Total", /*url=*/url.spec()); + // Emit a trace event with url in the name for convenience. + // TODO(crbug.com/415720503): Remove once Perfetto navigation plugins + // surfaces urls. std::string top_level_trace_event_name = "Navigation: " + url.spec(); - log_trace_event_and_uma(top_level_trace_event_name, track1, timeline.start, - timeline.finish, /*histogram_name=*/"Total"); + TRACE_EVENT_BEGIN("navigation", + perfetto::DynamicString(top_level_trace_event_name), track1, + timeline.start); + TRACE_EVENT_END("navigation", track1, timeline.finish); if (!timeline.begin_navigation.is_null()) { // Most navigations (other than synchronous renderer commits) go through @@ -9956,7 +9975,7 @@ if (!shown_contents) { // These point to freed memory, so null them out to prevent inadvertent - // UAF in the feature (see NOTE above). + // UAF in the future (see NOTE above). new_frame_tree = nullptr; new_main_rfh = nullptr; new_rwh = nullptr; @@ -9966,7 +9985,7 @@ new_main_rfh->GetView()->GetViewBounds()); reply->window_screen_rect.emplace( new_main_rfh->GetView()->GetBoundsInRootWindow()); - reply->visual_properties = new_rwh->GetInitialVisualProperties(); + reply->visual_properties = new_rwh->GetVisualProperties(); } }
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 86a8079..70acc7b 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -740,6 +740,10 @@ const gfx::Size& min_size, const gfx::Size& max_size); + // Generates a filled in VisualProperties struct representing the current + // properties of this widget. + blink::VisualProperties GetVisualProperties(); + // Returns the result of GetVisualProperties(), resetting and storing that // value as what has been sent to the renderer. This should be called when // getting VisualProperties that will be sent in order to create a @@ -1134,10 +1138,6 @@ void ResetStateForCreatedRenderWidget( const blink::VisualProperties& initial_props); - // Generates a filled in VisualProperties struct representing the current - // properties of this widget. - blink::VisualProperties GetVisualProperties(); - // Returns true if the |new_visual_properties| differs from // |old_page_visual_properties| in a way that indicates a size changed. static bool DidVisualPropertiesSizeChange(
diff --git a/content/browser/resources/gpu/info_view.ts b/content/browser/resources/gpu/info_view.ts index 130a9ba..efb0bba 100644 --- a/content/browser/resources/gpu/info_view.ts +++ b/content/browser/resources/gpu/info_view.ts
@@ -672,6 +672,7 @@ 'webgpu': 'WebGPU', 'skia_graphite': 'Skia Graphite', 'webnn': 'WebNN', + 'trees_in_viz': 'TreesInViz', }; const statusMap: Record<string, {label: string, class: string}> = {
diff --git a/content/browser/speech/network_speech_recognition_engine_impl.cc b/content/browser/speech/network_speech_recognition_engine_impl.cc index 4328465..a138840 100644 --- a/content/browser/speech/network_speech_recognition_engine_impl.cc +++ b/content/browser/speech/network_speech_recognition_engine_impl.cc
@@ -129,8 +129,7 @@ void NetworkSpeechRecognitionEngineImpl::UpdateRecognitionContext( const media::SpeechRecognitionRecognitionContext& recognition_context) { - Abort(media::mojom::SpeechRecognitionErrorCode:: - kRecognitionContextNotSupported); + Abort(media::mojom::SpeechRecognitionErrorCode::kPhrasesNotSupported); } void NetworkSpeechRecognitionEngineImpl::EndRecognition() {
diff --git a/content/browser/speech/speech_recognition_manager_impl.cc b/content/browser/speech/speech_recognition_manager_impl.cc index 4b762dc..b1136a2 100644 --- a/content/browser/speech/speech_recognition_manager_impl.cc +++ b/content/browser/speech/speech_recognition_manager_impl.cc
@@ -233,8 +233,7 @@ // Set the error if on-device speech recognition is not used but recognition // context is set. if (config.recognition_context.has_value()) { - error = media::mojom::SpeechRecognitionErrorCode:: - kRecognitionContextNotSupported; + error = media::mojom::SpeechRecognitionErrorCode::kPhrasesNotSupported; } }
diff --git a/content/browser/speech/speech_recognition_manager_impl_unittest.cc b/content/browser/speech/speech_recognition_manager_impl_unittest.cc index 6181cf87..e42e6b5 100644 --- a/content/browser/speech/speech_recognition_manager_impl_unittest.cc +++ b/content/browser/speech/speech_recognition_manager_impl_unittest.cc
@@ -189,7 +189,7 @@ })); } -TEST_F(SpeechRecognitionManagerImplTest, RecognitionContextNotSupportedError) { +TEST_F(SpeechRecognitionManagerImplTest, PhrasesNotSupportedError) { SpeechRecognitionSessionConfig config; config.on_device = false; config.language = "en-US"; @@ -199,8 +199,8 @@ receiver_.BindNewPipeAndPassRemote(), std::nullopt); EXPECT_TRUE(base::test::RunUntil([&]() { - return error_ == media::mojom::SpeechRecognitionErrorCode:: - kRecognitionContextNotSupported && + return error_ == + media::mojom::SpeechRecognitionErrorCode::kPhrasesNotSupported && ended_; })); } @@ -214,10 +214,10 @@ EXPECT_CALL( listener_, - OnRecognitionError(_, media::mojom::SpeechRecognitionError( - media::mojom::SpeechRecognitionErrorCode:: - kRecognitionContextNotSupported, - media::mojom::SpeechAudioErrorDetails::kNone))); + OnRecognitionError( + _, media::mojom::SpeechRecognitionError( + media::mojom::SpeechRecognitionErrorCode::kPhrasesNotSupported, + media::mojom::SpeechAudioErrorDetails::kNone))); EXPECT_CALL(listener_, OnRecognitionEnd(_)); manager_->CreateSession(config, mojo::NullReceiver(), mojo::NullRemote(), std::nullopt);
diff --git a/content/browser/speech/speech_recognizer_impl_android.cc b/content/browser/speech/speech_recognizer_impl_android.cc index cf4a6d2..38491cc 100644 --- a/content/browser/speech/speech_recognizer_impl_android.cc +++ b/content/browser/speech/speech_recognizer_impl_android.cc
@@ -67,10 +67,10 @@ } DCHECK_CURRENTLY_ON(BrowserThread::IO); listener()->OnRecognitionError( - session_id(), media::mojom::SpeechRecognitionError( - media::mojom::SpeechRecognitionErrorCode:: - kRecognitionContextNotSupported, - media::mojom::SpeechAudioErrorDetails::kNone)); + session_id(), + media::mojom::SpeechRecognitionError( + media::mojom::SpeechRecognitionErrorCode::kPhrasesNotSupported, + media::mojom::SpeechAudioErrorDetails::kNone)); } void SpeechRecognizerImplAndroid::StartRecognitionOnUIThread(
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc index 1bd76e3..f8c1355 100644 --- a/content/browser/webid/federated_auth_request_impl.cc +++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -1423,27 +1423,6 @@ // TODO(yigu): Clean up the client metadata related errors for metrics and // console logs. - if (!idp_info->metadata.brand_background_color && - idp_info->metadata.brand_text_color) { - idp_info->metadata.brand_text_color = std::nullopt; - render_frame_host().AddMessageToConsole( - blink::mojom::ConsoleMessageLevel::kWarning, - "The FedCM text color is ignored because background color was not " - "provided"); - } - if (idp_info->metadata.brand_background_color && - idp_info->metadata.brand_text_color) { - float text_contrast_ratio = color_utils::GetContrastRatio( - *idp_info->metadata.brand_background_color, - *idp_info->metadata.brand_text_color); - if (text_contrast_ratio < color_utils::kMinimumReadableContrastRatio) { - idp_info->metadata.brand_text_color = std::nullopt; - render_frame_host().AddMessageToConsole( - blink::mojom::ConsoleMessageLevel::kWarning, - "The FedCM text color is ignored because it does not contrast enough " - "with the provided background color"); - } - } FetchAccountPicturesAndBrandIcons(std::move(idp_info), std::move(accounts), std::move(client_metadata)); } @@ -2975,8 +2954,9 @@ for (const auto& json : sd_jwt->disclosures) { data_decoder::DataDecoder::ParseJsonIsolated( - json, base::BindOnce(&FederatedAuthRequestImpl::OnDisclosureParsed, - weak_ptr_factory_.GetWeakPtr(), callback, json)); + json.value(), + base::BindOnce(&FederatedAuthRequestImpl::OnDisclosureParsed, + weak_ptr_factory_.GetWeakPtr(), callback, json.value())); } } @@ -2996,7 +2976,7 @@ return; } - disclosures_.push_back({disclosure->name, json}); + disclosures_.push_back({disclosure->name, sdjwt::JSONString(json)}); cb.Run(); }
diff --git a/content/browser/webid/federated_auth_request_impl.h b/content/browser/webid/federated_auth_request_impl.h index 688067a..59b1139 100644 --- a/content/browser/webid/federated_auth_request_impl.h +++ b/content/browser/webid/federated_auth_request_impl.h
@@ -692,7 +692,7 @@ // A list of discloures that were parsed in the token response, when // the token's format is "vc+sd-jwt". - std::vector<std::pair<std::string, std::string>> disclosures_; + std::vector<std::pair<std::string, content::sdjwt::JSONString>> disclosures_; base::WeakPtrFactory<FederatedAuthRequestImpl> weak_ptr_factory_{this}; };
diff --git a/content/browser/webid/federated_provider_fetcher.cc b/content/browser/webid/federated_provider_fetcher.cc index 495cf08..5d260361 100644 --- a/content/browser/webid/federated_provider_fetcher.cc +++ b/content/browser/webid/federated_provider_fetcher.cc
@@ -8,6 +8,8 @@ #include "content/browser/webid/flags.h" #include "content/browser/webid/webid_utils.h" #include "net/base/schemeful_site.h" +#include "third_party/blink/public/mojom/devtools/console_message.mojom-shared.h" +#include "ui/gfx/color_utils.h" namespace content { @@ -200,6 +202,25 @@ } } + if (!idp_metadata.brand_background_color && idp_metadata.brand_text_color) { + idp_metadata.brand_text_color = std::nullopt; + render_frame_host_->AddMessageToConsole( + blink::mojom::ConsoleMessageLevel::kWarning, + "The FedCM text color is ignored because background color was not " + "provided"); + } + if (idp_metadata.brand_background_color && idp_metadata.brand_text_color) { + float text_contrast_ratio = color_utils::GetContrastRatio( + *idp_metadata.brand_background_color, *idp_metadata.brand_text_color); + if (text_contrast_ratio < color_utils::kMinimumReadableContrastRatio) { + idp_metadata.brand_text_color = std::nullopt; + render_frame_host_->AddMessageToConsole( + blink::mojom::ConsoleMessageLevel::kWarning, + "The FedCM text color is ignored because it does not contrast enough " + "with the provided background color"); + } + } + fetch_result.endpoints = endpoints; fetch_result.metadata = idp_metadata;
diff --git a/content/browser/webid/jwt_signer_unittest.cc b/content/browser/webid/jwt_signer_unittest.cc index 84a66a80..e09bc19 100644 --- a/content/browser/webid/jwt_signer_unittest.cc +++ b/content/browser/webid/jwt_signer_unittest.cc
@@ -111,24 +111,25 @@ payload.sub = "goto@google.com"; Jwt issued; - issued.header = *header.Serialize(); - issued.payload = *payload.Serialize(); + issued.header = JSONString(header.Serialize()->value()); + issued.payload = JSONString(payload.Serialize()->value()); auto success = issued.Sign(CreateJwtSigner(std::move(private_key))); EXPECT_TRUE(success); auto signature = base::Base64UrlDecode( - issued.signature, base::Base64UrlDecodePolicy::IGNORE_PADDING); + issued.signature.value(), base::Base64UrlDecodePolicy::IGNORE_PADDING); EXPECT_TRUE(signature); std::string header_base64; - base::Base64UrlEncode( - issued.header, base::Base64UrlEncodePolicy::OMIT_PADDING, &header_base64); + base::Base64UrlEncode(issued.header.value(), + base::Base64UrlEncodePolicy::OMIT_PADDING, + &header_base64); std::string payload_base64; - base::Base64UrlEncode(issued.payload, + base::Base64UrlEncode(issued.payload.value(), base::Base64UrlEncodePolicy::OMIT_PADDING, &payload_base64); @@ -166,15 +167,15 @@ EXPECT_TRUE(issuer_json->Serialize()); Jwt issued; - issued.header = *header.Serialize(); - issued.payload = *payload.Serialize(); + issued.header = JSONString(header.Serialize()->value()); + issued.payload = JSONString(payload.Serialize()->value()); auto signer = CreateJwtSigner(std::move(issuer_private_key)); auto success = issued.Sign(std::move(signer)); EXPECT_TRUE(success); - auto presentation = - SdJwt::Disclose({{name.name, name.Serialize()}}, {"name"}); + auto presentation = SdJwt::Disclose( + {{name.name, JSONString(name.Serialize().value())}}, {"name"}); EXPECT_TRUE(presentation); SdJwt sd_jwt;
diff --git a/content/browser/webid/sd_jwt.cc b/content/browser/webid/sd_jwt.cc index c0d02d1..a23ccd7b 100644 --- a/content/browser/webid/sd_jwt.cc +++ b/content/browser/webid/sd_jwt.cc
@@ -32,11 +32,11 @@ return str; } -base64_t Base64UrlEncode(const std::string_view& str) { - base64_t base64; +Base64String Base64UrlEncode(const std::string_view& str) { + std::string base64; base::Base64UrlEncode(str, base::Base64UrlEncodePolicy::OMIT_PADDING, &base64); - return base64; + return Base64String(base64); } } // namespace @@ -82,7 +82,7 @@ return result; } -std::optional<json_t> Jwk::Serialize() const { +std::optional<std::string> Jwk::Serialize() const { base::Value::Dict result; result.Set("kty", kty); @@ -122,43 +122,49 @@ } Disclosure result; - result.salt = list[0].GetString(); + result.salt = Base64String(list[0].GetString()); result.name = list[1].GetString(); result.value = list[2].GetString(); return result; } -std::optional<json_t> Disclosure::ToJson() const { +std::optional<JSONString> Disclosure::ToJson() const { base::Value::List list; - list.Append(salt); + list.Append(salt.value()); list.Append(name); list.Append(value); - return base::WriteJson(list); + auto result = base::WriteJson(list); + + if (!result) { + return std::nullopt; + } + + return JSONString(*result); } -base64_t Disclosure::Serialize() const { - return Base64UrlEncode(*ToJson()); +Base64String Disclosure::Serialize() const { + return Base64UrlEncode(ToJson()->value()); } -std::optional<base64_t> Disclosure::Digest(Hasher hasher) const { - auto disclosure_base64 = Serialize(); +std::optional<Base64String> Disclosure::Digest(Hasher hasher) const { + Base64String disclosure = Serialize(); std::string result; - base::Base64UrlEncode(hasher.Run(disclosure_base64), + base::Base64UrlEncode(hasher.Run(disclosure.value()), base::Base64UrlEncodePolicy::OMIT_PADDING, &result); - return result; + return Base64String(result); } // static -base64_t Disclosure::CreateSalt() { +Base64String Disclosure::CreateSalt() { const size_t salt_size = 32; std::array<uint8_t, salt_size> salt_bytes; crypto::RandBytes(salt_bytes); - base64_t salt_base64; + std::string salt; base::Base64UrlEncode(salt_bytes, base::Base64UrlEncodePolicy::OMIT_PADDING, - &salt_base64); - return salt_base64; + &salt); + return Base64String(salt); } std::optional<SdJwt> SdJwt::From(const base::Value::List& list) { @@ -175,13 +181,13 @@ return std::nullopt; } - std::vector<json_t> disclosures; + std::vector<JSONString> disclosures; for (auto& disclosure : list[1].GetList()) { if (!disclosure.is_string()) { return std::nullopt; } - disclosures.push_back(disclosure.GetString()); + disclosures.push_back(JSONString(disclosure.GetString())); } SdJwt result; @@ -263,21 +269,27 @@ return result; } -std::optional<json_t> Header::ToJson() const { +std::optional<JSONString> Header::ToJson() const { base::Value::Dict header_dict; header_dict.Set("typ", typ); header_dict.Set("alg", alg); - return base::WriteJson(header_dict); + auto result = base::WriteJson(header_dict); + + if (!result) { + return std::nullopt; + } + + return JSONString(*result); } -std::optional<base64_t> Header::Serialize() const { +std::optional<Base64String> Header::Serialize() const { auto header_json = ToJson(); if (!header_json) { return std::nullopt; } - return Base64UrlEncode(*header_json); + return Base64UrlEncode(header_json->value()); } ConfirmationKey::ConfirmationKey() = default; @@ -341,7 +353,7 @@ auto* sd_hash = json.FindString("sd_hash"); if (sd_hash) { - result.sd_hash = *sd_hash; + result.sd_hash = Base64String(*sd_hash); } auto* _sd_alg = json.FindString("_sd_alg"); @@ -354,14 +366,14 @@ if (!el.is_string()) { return std::nullopt; } - result._sd.push_back(el.GetString()); + result._sd.push_back(Base64String(el.GetString())); } } return result; } -std::optional<json_t> Payload::ToJson() const { +std::optional<JSONString> Payload::ToJson() const { base::Value::Dict payload_dict; if (!iss.empty()) { @@ -406,14 +418,14 @@ payload_dict.Set("exp", (int)exp->ToTimeT()); } - if (!sd_hash.empty()) { - payload_dict.Set("sd_hash", sd_hash); + if (!sd_hash.value().empty()) { + payload_dict.Set("sd_hash", sd_hash.value()); } if (_sd.size() > 0) { base::Value::List list; for (auto disclosure : _sd) { - list.Append(disclosure); + list.Append(disclosure.value()); } payload_dict.Set("_sd", std::move(list)); } @@ -422,29 +434,35 @@ payload_dict.Set("_sd_alg", _sd_alg); } - return base::WriteJson(payload_dict); + auto result = base::WriteJson(payload_dict); + + if (!result) { + return std::nullopt; + } + + return JSONString(*result); } -std::optional<base64_t> Payload::Serialize() const { +std::optional<Base64String> Payload::Serialize() const { auto payload_json = ToJson(); if (!payload_json) { return std::nullopt; } - return Base64UrlEncode(*payload_json); + return Base64UrlEncode(payload_json->value()); } Jwt::Jwt() = default; Jwt::~Jwt() = default; Jwt::Jwt(const Jwt& other) = default; -std::string Jwt::Serialize() const { +JSONString Jwt::Serialize() const { std::string result; - result += Base64UrlEncode(header); + result += Base64UrlEncode(header.value()).value(); result += "."; - result += Base64UrlEncode(payload); + result += Base64UrlEncode(payload.value()).value(); result += "."; - result += signature; - return result; + result += signature.value(); + return JSONString(result); } // static @@ -458,9 +476,9 @@ } Jwt result; - result.header = list[0].GetString(); - result.payload = list[1].GetString(); - result.signature = list[2].GetString(); + result.header = JSONString(list[0].GetString()); + result.payload = JSONString(list[1].GetString()); + result.signature = Base64String(list[2].GetString()); return result; } @@ -498,8 +516,8 @@ } bool Jwt::Sign(Signer signer) { - std::string message = - Base64UrlEncode(header) + "." + Base64UrlEncode(payload); + std::string message = Base64UrlEncode(header.value()).value() + "." + + Base64UrlEncode(payload.value()).value(); auto sig = std::move(signer).Run(message); if (!sig) { @@ -507,7 +525,7 @@ } base::Base64UrlEncode(*sig, base::Base64UrlEncodePolicy::OMIT_PADDING, - &signature); + &signature.value()); return true; } @@ -518,12 +536,12 @@ std::string SdJwt::Serialize() const { std::string result; - result += jwt.Serialize(); + result += jwt.Serialize().value(); result += "~"; - for (const json_t& disclosure : disclosures) { - result += Base64UrlEncode(disclosure); + for (const JSONString& disclosure : disclosures) { + result += Base64UrlEncode(disclosure.value()).value(); result += "~"; } @@ -533,7 +551,7 @@ std::string SdJwtKb::Serialize() const { std::string result; result += sd_jwt.Serialize(); - result += kb_jwt.Serialize(); + result += kb_jwt.Serialize().value(); return result; } @@ -543,18 +561,18 @@ SdJwtKb::SdJwtKb(const SdJwtKb& other) = default; // static -std::optional<std::vector<json_t>> SdJwt::Disclose( - const std::vector<std::pair<std::string, json_t>>& disclosures, +std::optional<std::vector<JSONString>> SdJwt::Disclose( + const std::vector<std::pair<std::string, JSONString>>& disclosures, const std::vector<std::string>& selector) { // Implements the selective disclosure: // https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-13.html#name-disclosing-to-a-verifier - std::map<std::string, json_t> disclosures_by_name; - for (const std::pair<std::string, json_t>& disclosure : disclosures) { + std::map<std::string, JSONString> disclosures_by_name; + for (const std::pair<std::string, JSONString>& disclosure : disclosures) { disclosures_by_name[disclosure.first] = disclosure.second; } - std::vector<json_t> result; + std::vector<JSONString> result; for (const std::string& name : selector) { if (disclosures_by_name.count(name)) { result.push_back(disclosures_by_name[name]); @@ -587,7 +605,7 @@ payload.aud = aud; payload.nonce = nonce; payload.iat = iat; - payload.sd_hash = hash; + payload.sd_hash = Base64String(hash); Jwt kb_jwt; auto header_json = header.ToJson();
diff --git a/content/browser/webid/sd_jwt.h b/content/browser/webid/sd_jwt.h index 47ee34c..74f978a 100644 --- a/content/browser/webid/sd_jwt.h +++ b/content/browser/webid/sd_jwt.h
@@ -12,6 +12,7 @@ #include "base/functional/callback.h" #include "base/memory/raw_ref.h" #include "base/time/time.h" +#include "base/types/strong_alias.h" #include "base/values.h" #include "content/common/content_export.h" @@ -51,8 +52,8 @@ original value. Reverting back to the original value is important because they are signed and need to be verified. - So, a Jwt gets parsed into a json_t header and json_t payload, - which represent a string containing JSON, and a base64_t + So, a Jwt gets parsed into a JSON header and JSON payload, + which represent a string containing JSON, and a Base64 signature, which represents a string containing a base64url encoded blob. @@ -72,7 +73,7 @@ An SdJwt gets parsed into the issued Jwt as well as into the list of selective disclosures. Like a Jwt, the selective disclosures - are represented as json_t so that they can be serialized back to + are represented as JSON so that they can be serialized back to their original values. SdJwt sd_jwt = SdJwt::From(SdJwt::Parse(encoding)) @@ -112,9 +113,9 @@ }; // A string that can be parsed as application/json. -typedef std::string json_t; +using JSONString = base::StrongAlias<class JSONStringTag, std::string>; // A string that is base64url encoded. -typedef std::string base64_t; +using Base64String = base::StrongAlias<class Base64StringTag, std::string>; // https://datatracker.ietf.org/doc/html/rfc7519#section-5 struct CONTENT_EXPORT Header { @@ -128,8 +129,8 @@ static std::optional<Header> From(const base::Value::Dict& json); - std::optional<json_t> ToJson() const; - std::optional<base64_t> Serialize() const; + std::optional<JSONString> ToJson() const; + std::optional<Base64String> Serialize() const; }; // This struct holds the JWK in the "cnf" [1] parameter in the @@ -170,11 +171,11 @@ std::string vct; // Used in the Issued JWT - std::vector<base64_t> _sd; + std::vector<Base64String> _sd; std::string _sd_alg; // Used in the Key Binding JWT - base64_t sd_hash; + Base64String sd_hash; Payload(); ~Payload(); @@ -182,8 +183,8 @@ static std::optional<Payload> From(const base::Value::Dict& json); - std::optional<json_t> ToJson() const; - std::optional<base64_t> Serialize() const; + std::optional<JSONString> ToJson() const; + std::optional<Base64String> Serialize() const; }; /** @@ -197,9 +198,9 @@ // https://datatracker.ietf.org/doc/html/rfc7519 struct CONTENT_EXPORT Jwt { - json_t header; - json_t payload; - base64_t signature; + JSONString header; + JSONString payload; + Base64String signature; Jwt(); ~Jwt(); @@ -209,7 +210,7 @@ static std::optional<Jwt> From(const base::Value::List& json); static std::optional<base::Value::List> Parse(const std::string_view& jwt); - json_t Serialize() const; + JSONString Serialize() const; }; /** @@ -233,7 +234,7 @@ * can create disclosures as issuers. */ struct CONTENT_EXPORT Disclosure { - base64_t salt; + Base64String salt; std::string name; std::string value; @@ -245,17 +246,17 @@ // Creates a random value with the following requirements: // https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-13.html#name-entropy-of-the-salt - static base64_t CreateSalt(); + static Base64String CreateSalt(); - base64_t Serialize() const; - std::optional<json_t> ToJson() const; - std::optional<base64_t> Digest(Hasher hasher) const; + Base64String Serialize() const; + std::optional<JSONString> ToJson() const; + std::optional<Base64String> Digest(Hasher hasher) const; }; // https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-13.html struct CONTENT_EXPORT SdJwt { Jwt jwt; - std::vector<json_t> disclosures; + std::vector<JSONString> disclosures; SdJwt(); ~SdJwt(); @@ -264,8 +265,8 @@ static std::optional<SdJwt> From(const base::Value::List& json); static std::optional<base::Value::List> Parse(const std::string_view& sdjwt); - static std::optional<std::vector<json_t>> Disclose( - const std::vector<std::pair<std::string, json_t>>& disclosures, + static std::optional<std::vector<JSONString>> Disclose( + const std::vector<std::pair<std::string, JSONString>>& disclosures, const std::vector<std::string>& selector); std::string Serialize() const;
diff --git a/content/browser/webid/sd_jwt_unittest.cc b/content/browser/webid/sd_jwt_unittest.cc index d34f4c51..439318d 100644 --- a/content/browser/webid/sd_jwt_unittest.cc +++ b/content/browser/webid/sd_jwt_unittest.cc
@@ -81,7 +81,7 @@ auto disclosure = Disclosure::From(base::JSONReader::Read(json)->GetList()); EXPECT_TRUE(disclosure); - EXPECT_EQ(disclosure->salt, "_26bc4LT-ac6q2KI6cBW5es"); + EXPECT_EQ(disclosure->salt, Base64String("_26bc4LT-ac6q2KI6cBW5es")); EXPECT_EQ(disclosure->name, "family_name"); EXPECT_EQ(disclosure->value, "Möbius"); } @@ -91,11 +91,11 @@ // https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-13.html#section-4.2.1 Disclosure disclosure; - disclosure.salt = "_26bc4LT-ac6q2KI6cBW5es"; + disclosure.salt = Base64String("_26bc4LT-ac6q2KI6cBW5es"); disclosure.name = "family_name"; disclosure.value = "Möbius"; - auto base64 = disclosure.Serialize(); + Base64String base64 = disclosure.Serialize(); // This value is different from what's in the spec, but that's because // our JSON serialization strips whitespaces between array elements @@ -108,7 +108,7 @@ std::string expected = "WyJfMjZiYzRMVC1hYzZxMktJNmNCVzVlcyIsImZhbWlseV9uYW1lIiwiTcO2Yml1cyJd"; - EXPECT_STREQ(base64.c_str(), expected.c_str()); + EXPECT_STREQ(base64->c_str(), expected.c_str()); } TEST_F(SdJwtTest, JwtParsing) { @@ -119,9 +119,9 @@ auto token = Jwt::From(*Jwt::Parse(jwt)); EXPECT_TRUE(token); - EXPECT_EQ(token->header, "header"); - EXPECT_EQ(token->payload, "payload"); - EXPECT_EQ(token->signature, "signature"); + EXPECT_EQ(token->header, JSONString("header")); + EXPECT_EQ(token->payload, JSONString("payload")); + EXPECT_EQ(token->signature, Base64String("signature")); } TEST_F(SdJwtTest, JwtParsingInvalid) { @@ -141,13 +141,13 @@ TEST_F(SdJwtTest, JwtSerializing) { Jwt token; - token.header = "header"; - token.payload = "payload"; - token.signature = "signature"; + token.header = JSONString("header"); + token.payload = JSONString("payload"); + token.signature = Base64String("signature"); // Jwt's top level structure: // Base64UrlEncode(header) . Base64UrlEncode(payload) . signature - EXPECT_EQ(token.Serialize(), "aGVhZGVy.cGF5bG9hZA.signature"); + EXPECT_EQ(token.Serialize(), JSONString("aGVhZGVy.cGF5bG9hZA.signature")); } TEST_F(SdJwtTest, HeaderParsingAndSerializing) { @@ -155,9 +155,10 @@ header.alg = "foo"; header.typ = "bar"; - EXPECT_EQ(header.ToJson(), R"({"alg":"foo","typ":"bar"})"); + EXPECT_EQ(header.ToJson(), JSONString(R"({"alg":"foo","typ":"bar"})")); // The serializion of the header is a base64 encoding of the JSON. - EXPECT_EQ(header.Serialize(), "eyJhbGciOiJmb28iLCJ0eXAiOiJiYXIifQ"); + EXPECT_EQ(header.Serialize(), + Base64String("eyJhbGciOiJmb28iLCJ0eXAiOiJiYXIifQ")); // Test that we can go back from base64 to value. auto parsed = @@ -171,9 +172,9 @@ Payload payload; payload.sub = "foo"; - EXPECT_EQ(payload.ToJson(), R"({"sub":"foo"})"); + EXPECT_EQ(payload.ToJson(), JSONString(R"({"sub":"foo"})")); // The serializion of the header is a base64 encoding of the JSON. - EXPECT_EQ(payload.Serialize(), "eyJzdWIiOiJmb28ifQ"); + EXPECT_EQ(payload.Serialize(), Base64String("eyJzdWIiOiJmb28ifQ")); // Test that we can go back from base64 to value. auto parsed = Payload::From(*base::JSONReader::ReadDict(R"({"sub":"foo"})")); @@ -207,10 +208,11 @@ auto token = Jwt::From(*Jwt::Parse(jwt)); EXPECT_TRUE(token); - EXPECT_EQ(token->header, R"({"alg": "ES256", "typ": "example+sd-jwt"})"); + EXPECT_EQ(token->header, + JSONString(R"({"alg": "ES256", "typ": "example+sd-jwt"})")); EXPECT_EQ(token->signature, - "oQ0UNJB1E1agYouB1yfGXfYLyWueHhfMFuicSV-n_" - "GLXHtX0XK99sfDDERiWKukCUzadGTT4QbCwXe6JvVmZWw"); + Base64String("oQ0UNJB1E1agYouB1yfGXfYLyWueHhfMFuicSV-n_" + "GLXHtX0XK99sfDDERiWKukCUzadGTT4QbCwXe6JvVmZWw")); std::string expected = R"({)" @@ -237,15 +239,17 @@ R"("y": "ZxjiWWbZMQGHVWKVQ4hbSIirsVfuecCE6t4jT9F2HZQ"}})" R"(})"; - EXPECT_STREQ(token->payload.c_str(), expected.c_str()); + EXPECT_STREQ(token->payload.value().c_str(), expected.c_str()); - auto header = Header::From(*base::JSONReader::ReadDict(token->header)); + auto header = + Header::From(*base::JSONReader::ReadDict(token->header.value())); EXPECT_TRUE(header); EXPECT_EQ(header->typ, "example+sd-jwt"); EXPECT_EQ(header->alg, "ES256"); - auto payload = Payload::From(*base::JSONReader::ReadDict(token->payload)); + auto payload = + Payload::From(*base::JSONReader::ReadDict(token->payload.value())); EXPECT_TRUE(payload); EXPECT_EQ(payload->iss, "https://issuer.example.com"); @@ -269,15 +273,15 @@ auto token = SdJwt::From(*SdJwt::Parse(jwt)); EXPECT_TRUE(token); - EXPECT_EQ(token->jwt.header, "header"); - EXPECT_EQ(token->jwt.payload, "payload"); - EXPECT_EQ(token->jwt.signature, "signature"); + EXPECT_EQ(token->jwt.header, JSONString("header")); + EXPECT_EQ(token->jwt.payload, JSONString("payload")); + EXPECT_EQ(token->jwt.signature, Base64String("signature")); EXPECT_EQ(token->disclosures.size(), 2ul); - EXPECT_EQ(token->disclosures[0], "disclosure1"); - EXPECT_EQ(token->disclosures[1], "disclosure2"); + EXPECT_EQ(token->disclosures[0], JSONString("disclosure1")); + EXPECT_EQ(token->disclosures[1], JSONString("disclosure2")); // Asserts that we can serialize the token again. - token->jwt.header = "new-header"; + token->jwt.header = JSONString("new-header"); EXPECT_EQ( token->Serialize(), "bmV3LWhlYWRlcg.cGF5bG9hZA.signature~ZGlzY2xvc3VyZTE~ZGlzY2xvc3VyZTI~"); @@ -316,12 +320,12 @@ TEST_F(SdJwtTest, SelectiveDisclosure) { Disclosure name; - name.salt = "fake-salt1"; + name.salt = Base64String("fake-salt1"); name.name = "name"; name.value = "Sam"; Disclosure email; - email.salt = "fake-salt2"; + email.salt = Base64String("fake-salt2"); email.name = "email"; email.value = "goto@email.com"; @@ -339,7 +343,8 @@ EXPECT_EQ(presentation->size(), 1ul); // ... and that it was selected correctly: - EXPECT_EQ((*presentation)[0], "[\"fake-salt1\",\"name\",\"Sam\"]"); + EXPECT_EQ((*presentation)[0], + JSONString("[\"fake-salt1\",\"name\",\"Sam\"]")); } TEST_F(SdJwtTest, SdJwtKbParsingAndSerializing) { @@ -356,18 +361,18 @@ auto token = SdJwtKb::Parse(bin); EXPECT_TRUE(token); - EXPECT_EQ(token->sd_jwt.jwt.header, "header"); - EXPECT_EQ(token->sd_jwt.jwt.payload, "payload"); - EXPECT_EQ(token->sd_jwt.jwt.signature, "iss_signature"); + EXPECT_EQ(token->sd_jwt.jwt.header, JSONString("header")); + EXPECT_EQ(token->sd_jwt.jwt.payload, JSONString("payload")); + EXPECT_EQ(token->sd_jwt.jwt.signature, Base64String("iss_signature")); EXPECT_EQ(token->sd_jwt.disclosures.size(), 2ul); - EXPECT_EQ(token->sd_jwt.disclosures[0], "disclosure1"); - EXPECT_EQ(token->sd_jwt.disclosures[1], "disclosure2"); - EXPECT_EQ(token->kb_jwt.header, "header"); - EXPECT_EQ(token->kb_jwt.payload, "payload"); - EXPECT_EQ(token->kb_jwt.signature, "kb_signature"); + EXPECT_EQ(token->sd_jwt.disclosures[0], JSONString("disclosure1")); + EXPECT_EQ(token->sd_jwt.disclosures[1], JSONString("disclosure2")); + EXPECT_EQ(token->kb_jwt.header, JSONString("header")); + EXPECT_EQ(token->kb_jwt.payload, JSONString("payload")); + EXPECT_EQ(token->kb_jwt.signature, Base64String("kb_signature")); // Asserts that we can serialize the token again. - token->sd_jwt.jwt.header = "new-header"; + token->sd_jwt.jwt.header = JSONString("new-header"); EXPECT_EQ( token->Serialize(), "bmV3LWhlYWRlcg.cGF5bG9hZA.iss_signature~ZGlzY2xvc3VyZTE~ZGlzY2xvc3VyZTI~" @@ -419,12 +424,12 @@ TEST_F(SdJwtTest, SdJwtKb_Bind) { Disclosure name; - name.salt = "fake-salt1"; + name.salt = Base64String("fake-salt1"); name.name = "name"; name.value = "Sam"; Disclosure email; - email.salt = "fake-salt2"; + email.salt = Base64String("fake-salt2"); email.name = "email"; email.value = "goto@email.com"; @@ -440,9 +445,9 @@ EXPECT_TRUE(disclosures); Jwt issued; - issued.header = "header"; - issued.payload = "payload"; - issued.signature = "signature"; + issued.header = JSONString("header"); + issued.payload = JSONString("payload"); + issued.signature = Base64String("signature"); SdJwt presentation; presentation.jwt = issued; @@ -459,13 +464,13 @@ // Checks KB headers: // https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-13.html#section-4.3 - auto header = Header::From(*base::JSONReader::ReadDict(kb.header)); + auto header = Header::From(*base::JSONReader::ReadDict(kb.header.value())); EXPECT_TRUE(header); // typ MUST be "kb+jwt". EXPECT_EQ(header->typ, "kb+jwt"); EXPECT_EQ(header->alg, "ES256"); - auto payload = Payload::From(*base::JSONReader::ReadDict(kb.payload)); + auto payload = Payload::From(*base::JSONReader::ReadDict(kb.payload.value())); EXPECT_TRUE(payload); // aud is required. EXPECT_EQ(payload->aud, "https://verifier.example"); @@ -478,9 +483,11 @@ // Checks for how the hash was constructed: // https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-13.html#section-4.3.1 - EXPECT_EQ(payload->sd_hash, - "U2hhMjU2KGFHVmhaR1Z5LmNHRjViRzloWkEuc2lnbmF0dXJlfld5Sm1ZV3RsTFh" - "OaGJIUXhJaXdpYm1GdFpTSXNJbE5oYlNKZH4p"); + EXPECT_EQ( + payload->sd_hash, + Base64String( + "U2hhMjU2KGFHVmhaR1Z5LmNHRjViRzloWkEuc2lnbmF0dXJlfld5Sm1ZV3RsTFh" + "OaGJIUXhJaXdpYm1GdFpTSXNJbE5oYlNKZH4p")); // Checks that the signature was constructed correctly too: // https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-13.html#section-4.3.1 @@ -503,7 +510,7 @@ // Base64(["fake-salt1","name","Sam"])~)" // } // - base64_t base64; + std::string base64; base::Base64UrlEncode( "Signed(eyJhbGciOiJFUzI1NiIsInR5cCI6ImtiK2p3dCJ9." "eyJhdWQiOiJodHRwczovL3ZlcmlmaWVyLmV4YW1wbGUiLCJpYXQiOjEyMzQsIm5" @@ -512,7 +519,7 @@ "EZoT2FHSklVWGhKYVhkcFltMUdkRnBUU1hOSmJFNW9ZbE5LWkg0cCJ9)", base::Base64UrlEncodePolicy::OMIT_PADDING, &base64); - EXPECT_STREQ(kb.signature.c_str(), base64.c_str()); + EXPECT_STREQ(kb.signature->c_str(), base64.c_str()); } } // namespace content::sdjwt
diff --git a/content/browser/xr/service/xr_runtime_manager_impl.cc b/content/browser/xr/service/xr_runtime_manager_impl.cc index 8a185c9..e8679f1 100644 --- a/content/browser/xr/service/xr_runtime_manager_impl.cc +++ b/content/browser/xr/service/xr_runtime_manager_impl.cc
@@ -59,19 +59,6 @@ return *xr_runtime_manager_observers; } -#if !BUILDFLAG(IS_ANDROID) -bool IsEnabled(const base::CommandLine* command_line, - const base::Feature& feature, - const std::string& name) { - if (!command_line->HasSwitch(switches::kWebXrForceRuntime)) - return base::FeatureList::IsEnabled(feature); - - return (base::CompareCaseInsensitiveASCII( - command_line->GetSwitchValueASCII(switches::kWebXrForceRuntime), - name) == 0); -} -#endif - bool IsForcedRuntime(const base::CommandLine* command_line, const std::string& name) { return (base::CompareCaseInsensitiveASCII( @@ -188,14 +175,20 @@ providers.push_back(std::make_unique<IsolatedVRDeviceProvider>()); #endif // !BUILDFLAG(IS_ANDROID) - bool orientation_provider_enabled = true; + const bool is_orientation_provider_forced = + IsForcedRuntime(base::CommandLine::ForCurrentProcess(), + switches::kWebXrRuntimeOrientationSensors); -#if !BUILDFLAG(IS_ANDROID) - const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); - orientation_provider_enabled = - IsEnabled(cmd_line, device::features::kWebXrOrientationSensorDevice, - ::switches::kWebXrRuntimeOrientationSensors); -#endif + // We can use the orientation provider if it's forced, or if the feature is + // enabled and 2D chrome is not being rendered in a head-mounted display. + // On such displays inline sessions can cause "swimmy" behavior, because the + // content would move in response to the user's head motion, but in unexpected + // ways. + bool orientation_provider_enabled = + is_orientation_provider_forced || + (base::FeatureList::IsEnabled( + device::features::kWebXrOrientationSensorDevice) && + !device::features::IsXrDevice()); if (orientation_provider_enabled) { mojo::PendingRemote<device::mojom::SensorProvider> sensor_provider;
diff --git a/content/child/child_performance_coordinator_unittest.cc b/content/child/child_performance_coordinator_unittest.cc index 36e1bea..ba1e3da 100644 --- a/content/child/child_performance_coordinator_unittest.cc +++ b/content/child/child_performance_coordinator_unittest.cc
@@ -4,17 +4,15 @@ #include "content/child/child_performance_coordinator.h" -#include <optional> +#include <memory> #include <utility> #include "base/functional/callback.h" #include "base/memory/read_only_shared_memory_region.h" -#include "base/memory/scoped_refptr.h" -#include "base/memory/structured_shared_memory.h" #include "base/task/sequenced_task_runner.h" #include "base/test/task_environment.h" #include "components/performance_manager/public/mojom/coordination_unit.mojom.h" -#include "components/performance_manager/scenario_api/performance_scenario_memory.h" +#include "components/performance_manager/scenario_api/performance_scenario_test_support.h" #include "components/performance_manager/scenario_api/performance_scenarios.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" @@ -25,8 +23,8 @@ namespace { using performance_manager::mojom::ChildProcessCoordinationUnit; +using performance_scenarios::PerformanceScenarioTestHelper; using performance_scenarios::ScenarioScope; -using performance_scenarios::ScenarioState; using ::testing::_; using ::testing::Invoke; @@ -53,52 +51,47 @@ class ChildPerformanceCoordinatorTest : public ::testing::Test { public: - // Initializes `coordinator` and waits for a mock ChildProcessCoordinationUnit - // to send it `global_region` and `process_region`. + void SetUp() override { + scenario_test_helper_ = + PerformanceScenarioTestHelper::CreateWithoutMapping(); + ASSERT_TRUE(scenario_test_helper_); + } + + // Initializes the ChildPerformanceCoordinator and waits for a mock + // ChildProcessCoordinationUnit to send it `global_region` and + // `process_region`. void InitializeAndWaitForScenarioRegions( - ChildPerformanceCoordinator& coordinator, base::ReadOnlySharedMemoryRegion global_region, base::ReadOnlySharedMemoryRegion process_region) { - global_region_ = std::move(global_region); - process_region_ = std::move(process_region); - quit_closure_ = task_env_.QuitClosure(); - + base::OnceClosure quit_closure = task_env_.QuitClosure(); StrictMockChildProcessCoordinationUnit mock_coordination_unit; EXPECT_CALL(mock_coordination_unit, InitializeChildProcessCoordination(_, _)) .WillOnce(Invoke( - this, - &ChildPerformanceCoordinatorTest::SendScenarioRegionsAndQuit)); - mock_coordination_unit.Bind(coordinator.InitializeAndPassReceiver()); + [&](uint64_t, InitializeChildProcessCoordinationCallback callback) { + std::move(callback).Run(std::move(global_region), + std::move(process_region)); + // `callback` will post to ChildPerformanceCoordinator. Quit the + // runloop after the posted task. + task_env_.GetMainThreadTaskRunner()->PostTask( + FROM_HERE, std::move(quit_closure)); + })); + mock_coordination_unit.Bind(coordinator_.InitializeAndPassReceiver()); task_env_.RunUntilQuit(); } - // Invokes `callback` with the `global_region_` and `process_region_` and - // quits the run loop. - void SendScenarioRegionsAndQuit( - uint64_t, - InitializeChildProcessCoordinationCallback callback) { - std::move(callback).Run(std::move(global_region_), - std::move(process_region_)); - // `callback` will post to ChildPerformanceCoordinator. Quit the runloop - // after the posted task. - task_env_.GetMainThreadTaskRunner()->PostTask(FROM_HERE, - std::move(quit_closure_)); + PerformanceScenarioTestHelper& scenario_test_helper() { + return *scenario_test_helper_; } private: base::test::TaskEnvironment task_env_; - - // State used by SendScenarioRegionsAndQuit. - base::ReadOnlySharedMemoryRegion global_region_; - base::ReadOnlySharedMemoryRegion process_region_; - base::OnceClosure quit_closure_; + std::unique_ptr<PerformanceScenarioTestHelper> scenario_test_helper_; + ChildPerformanceCoordinator coordinator_; }; TEST_F(ChildPerformanceCoordinatorTest, NoScenarioRegion) { - ChildPerformanceCoordinator coordinator; - InitializeAndWaitForScenarioRegions(coordinator, - base::ReadOnlySharedMemoryRegion(), + InitializeAndWaitForScenarioRegions(base::ReadOnlySharedMemoryRegion(), base::ReadOnlySharedMemoryRegion()); EXPECT_FALSE(performance_scenarios::GetScenarioMappingForScope( @@ -108,13 +101,9 @@ } TEST_F(ChildPerformanceCoordinatorTest, GlobalScenarioRegion) { - auto shared_memory = base::StructuredSharedMemory<ScenarioState>::Create(); - ASSERT_TRUE(shared_memory.has_value()); - - ChildPerformanceCoordinator coordinator; - InitializeAndWaitForScenarioRegions(coordinator, - shared_memory->TakeReadOnlyRegion(), - base::ReadOnlySharedMemoryRegion()); + InitializeAndWaitForScenarioRegions( + scenario_test_helper().GetReadOnlyScenarioRegion(ScenarioScope::kGlobal), + base::ReadOnlySharedMemoryRegion()); EXPECT_TRUE(performance_scenarios::GetScenarioMappingForScope( ScenarioScope::kGlobal)); @@ -123,13 +112,10 @@ } TEST_F(ChildPerformanceCoordinatorTest, ProcessScenarioRegion) { - auto shared_memory = base::StructuredSharedMemory<ScenarioState>::Create(); - ASSERT_TRUE(shared_memory.has_value()); - - ChildPerformanceCoordinator coordinator; - InitializeAndWaitForScenarioRegions(coordinator, - base::ReadOnlySharedMemoryRegion(), - shared_memory->TakeReadOnlyRegion()); + InitializeAndWaitForScenarioRegions( + base::ReadOnlySharedMemoryRegion(), + scenario_test_helper().GetReadOnlyScenarioRegion( + ScenarioScope::kCurrentProcess)); EXPECT_FALSE(performance_scenarios::GetScenarioMappingForScope( ScenarioScope::kGlobal));
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 55e7a18f..6874fe39 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -367,8 +367,6 @@ kSetOnlyIfOverridden}, {"FledgeBiddingAndAuctionServerAPI", raw_ref(blink::features::kFledgeBiddingAndAuctionServer), kDefault}, - {"FontationsFontBackend", - raw_ref(blink::features::kFontationsFontBackend)}, {"FontSrcLocalMatching", raw_ref(features::kFontSrcLocalMatching)}, {"MachineLearningNeuralNetwork", raw_ref(webnn::mojom::features::kWebMachineLearningNeuralNetwork),
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index 11c916e4..f7a261f 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -177,6 +177,7 @@ "//content/public/common:common_java", "//device/bluetooth:java", "//device/gamepad:java", + "//device/vr/public:java", "//media/base/android:media_java", "//media/capture/video/android:capture_java", "//media/midi:midi_java",
diff --git a/content/public/browser/navigation_throttle.cc b/content/public/browser/navigation_throttle.cc index 75cd13f..f93753a 100644 --- a/content/public/browser/navigation_throttle.cc +++ b/content/public/browser/navigation_throttle.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/check_deref.h" #include "content/browser/renderer_host/navigation_request.h" namespace content { @@ -59,7 +60,12 @@ NavigationThrottle::ThrottleCheckResult::~ThrottleCheckResult() {} NavigationThrottle::NavigationThrottle(NavigationHandle* navigation_handle) - : navigation_handle_(navigation_handle) {} + : navigation_handle_(navigation_handle) { + CHECK(navigation_handle_); +} + +NavigationThrottle::NavigationThrottle(NavigationThrottleRegistry& registry) + : navigation_handle_(®istry.GetNavigationHandle()) {} NavigationThrottle::~NavigationThrottle() {}
diff --git a/content/public/browser/navigation_throttle.h b/content/public/browser/navigation_throttle.h index 8d32662..79becb63 100644 --- a/content/public/browser/navigation_throttle.h +++ b/content/public/browser/navigation_throttle.h
@@ -9,8 +9,10 @@ #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" +#include "base/memory/raw_ref.h" #include "base/memory/safety_checks.h" #include "content/common/content_export.h" +#include "content/public/browser/navigation_throttle_registry.h" #include "net/base/net_errors.h" namespace content { @@ -140,7 +142,12 @@ std::optional<std::string> error_page_content_; }; - NavigationThrottle(NavigationHandle* navigation_handle); + // Note: This legacy constructor will be removed soon. New code should use the + // other constructor that takes a NavigationThrottleRegistry&. + // TODO(https://crbug.com/412524375): Remove this constructor. + explicit NavigationThrottle(NavigationHandle* navigation_handle); + + explicit NavigationThrottle(NavigationThrottleRegistry& registry); virtual ~NavigationThrottle(); // Called when a network request is about to be made for this navigation. @@ -237,6 +244,10 @@ virtual void CancelDeferredNavigation(ThrottleCheckResult result); private: + // TODO(https://crbug.com/412524375): Once all subclasses are migrated to + // construct this instance with a NavigationThrottleRegistry*, remove + // `navigation_handle_` and replace it with + // `const raw_ref<NavigationThrottleRegistry> registry_`. const raw_ptr<NavigationHandle> navigation_handle_; // Used in tests.
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index a7383e4..3949fd5d 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -1344,11 +1344,6 @@ mojo::Remote<blink::mojom::RendererAudioInputStreamFactory> audio_input_stream_factory_; - // This interface handles generated code cache requests both to fetch code - // cache when loading resources and to store code caches when code caches are - // generated during the JS / Wasm script execution. - mojo::Remote<blink::mojom::CodeCacheHost> code_cache_host_; - // The media permission dispatcher attached to this frame. std::unique_ptr<MediaPermissionDispatcher> media_permission_dispatcher_;
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index 205af82..9d41c83a 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -248,6 +248,18 @@ if (is_ios) { sources += [ + "browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.h", + "browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.mm", + "browser/bluetooth/ios/shell_bluetooth_chooser_ios.h", + "browser/bluetooth/ios/shell_bluetooth_chooser_ios.mm", + "browser/bluetooth/ios/shell_bluetooth_chooser_mediator.h", + "browser/bluetooth/ios/shell_bluetooth_chooser_mediator.mm", + "browser/bluetooth/ios/shell_bluetooth_device_list_consumer.h", + "browser/bluetooth/ios/shell_bluetooth_device_list_delegate.h", + "browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h", + "browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.mm", + "browser/bluetooth/shell_bluetooth_delegate_impl_client.cc", + "browser/bluetooth/shell_bluetooth_delegate_impl_client.h", "browser/color_chooser/shell_color_chooser_ios.h", "browser/color_chooser/shell_color_chooser_ios.mm", "browser/shell_browser_main_parts_ios.mm", @@ -256,23 +268,6 @@ "browser/shell_platform_delegate_ios.mm", "browser/shell_web_contents_view_delegate_ios.mm", ] - - if (target_platform == "iphoneos") { - sources += [ - "browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.h", - "browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.mm", - "browser/bluetooth/ios/shell_bluetooth_chooser_ios.h", - "browser/bluetooth/ios/shell_bluetooth_chooser_ios.mm", - "browser/bluetooth/ios/shell_bluetooth_chooser_mediator.h", - "browser/bluetooth/ios/shell_bluetooth_chooser_mediator.mm", - "browser/bluetooth/ios/shell_bluetooth_device_list_consumer.h", - "browser/bluetooth/ios/shell_bluetooth_device_list_delegate.h", - "browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h", - "browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.mm", - "browser/bluetooth/shell_bluetooth_delegate_impl_client.cc", - "browser/bluetooth/shell_bluetooth_delegate_impl_client.h", - ] - } } if (is_win) {
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.mm b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.mm index 2858c82..855c2fd 100644 --- a/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.mm +++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_chooser_coordinator.mm
@@ -20,13 +20,13 @@ _deviceListViewController = [[ShellDeviceListViewController alloc] initWithTitle:title]; - _deviceListViewController.modalPresentationStyle = UIModalPresentationPopover; - _deviceListViewController.popoverPresentationController.delegate = + + // Set `modalPresentationStyle` to UIModalPresentationOverFullScreen available + // on iOS and tvOS. + _deviceListViewController.modalPresentationStyle = + UIModalPresentationOverFullScreen; + _deviceListViewController.presentationController.delegate = _deviceListViewController; - _deviceListViewController.popoverPresentationController.sourceView = - baseViewController.view; - _deviceListViewController.popoverPresentationController.sourceRect = - baseViewController.view.bounds; _bluetoothChooserMediator = [[ShellBluetoothChooserMediator alloc] initWithBluetoothChooser:bluetoothChooser];
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h index 0be9cb8d..faf279fe 100644 --- a/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h +++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h
@@ -17,7 +17,7 @@ // The ViewController that has UITableView to show the bluetooth device list. @interface ShellDeviceListViewController : UITableViewController <ShellBluetoothDeviceListConsumer, - UIPopoverPresentationControllerDelegate> + UIAdaptivePresentationControllerDelegate> // The view controller this coordinator was initialized with. @property(weak, nonatomic, readonly) UIViewController* baseViewController;
diff --git a/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.mm b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.mm index 006da4e..f8d9032 100644 --- a/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.mm +++ b/content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.mm
@@ -4,6 +4,7 @@ #import "content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_view_controller.h" +#include "build/build_config.h" #import "content/shell/browser/bluetooth/ios/shell_bluetooth_device_list_delegate.h" // Has device information to display it on a cell of UITableView. @@ -62,10 +63,36 @@ } _selectedRowIndex = -1; _listTitle = [title copy]; +#if BUILDFLAG(IS_IOS_TVOS) + // On tvOS, the modal view has transparent background by default. + // Set the background color so that the texts from the dialog don't overlap + // the web page. + self.view.backgroundColor = [UIColor systemGrayColor]; +#endif + self.tableView.bounces = NO; + +#if !BUILDFLAG(IS_IOS_TVOS) + // Add Up/Down swipe actions to close this modal dialog. + // On tvOS, do not add any specific actions to close the dialog since + // the dialog is closed with a back button from a remote controller and + // swipe actions are used for focus navigation. + UISwipeGestureRecognizer* swipeUpDown = [[UISwipeGestureRecognizer alloc] + initWithTarget:self + action:@selector(recognizeSwipe:)]; + [swipeUpDown setDirection:(UISwipeGestureRecognizerDirectionUp | + UISwipeGestureRecognizerDirectionDown)]; + [self.view addGestureRecognizer:swipeUpDown]; +#endif return self; } +#if !BUILDFLAG(IS_IOS_TVOS) +- (void)recognizeSwipe:(UITapGestureRecognizer*)gesture { + [self dismissViewControllerAnimated:YES completion:nil]; +} +#endif + - (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section { return self.listTitle;
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc index cdf869046..ab42138 100644 --- a/content/shell/browser/shell_content_browser_client.cc +++ b/content/shell/browser/shell_content_browser_client.cc
@@ -23,7 +23,6 @@ #include "base/functional/callback_helpers.h" #include "base/logging.h" #include "base/no_destructor.h" -#include "base/notimplemented.h" #include "base/path_service.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -134,10 +133,8 @@ #if BUILDFLAG(IS_IOS) #include "components/permissions/bluetooth_delegate_impl.h" -#if !BUILDFLAG(IS_IOS_TVOS) #include "content/shell/browser/bluetooth/shell_bluetooth_delegate_impl_client.h" #endif -#endif #if BUILDFLAG(IS_WIN) #include "media/mojo/mojom/media_foundation_preferences.mojom.h" @@ -840,16 +837,11 @@ #if BUILDFLAG(IS_IOS) BluetoothDelegate* ShellContentBrowserClient::GetBluetoothDelegate() { -#if !BUILDFLAG(IS_IOS_TVOS) if (!bluetooth_delegate_) { bluetooth_delegate_ = std::make_unique<permissions::BluetoothDelegateImpl>( std::make_unique<ShellBluetoothDelegateImplClient>()); } return bluetooth_delegate_.get(); -#else - TVOS_NOT_YET_IMPLEMENTED(); - return nullptr; -#endif } #endif
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 30ab9e2..6e99811f 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1428,6 +1428,7 @@ "../browser/back_forward_cache_browsertest.h", "../browser/back_forward_cache_features_browsertest.cc", "../browser/back_forward_cache_internal_browsertest.cc", + "../browser/back_forward_cache_limit_browsertest.cc", "../browser/back_forward_cache_network_request_browsertest.cc", "../browser/back_forward_cache_no_store_browsertest.cc", "../browser/back_forward_cache_not_restored_reasons_browsertest.cc", @@ -3144,6 +3145,7 @@ "//components/payments/mojom", "//components/performance_manager/public/mojom", "//components/performance_manager/scenario_api", + "//components/performance_manager/scenario_api:test_support", "//components/permissions:permissions_common", "//components/permissions:test_support", "//components/services/quarantine/public/mojom",
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist index f4530f5..5405bc8 100644 --- a/content/test/content_test_bundle_data.filelist +++ b/content/test/content_test_bundle_data.filelist
@@ -5234,6 +5234,9 @@ data/accessibility/html/select-slowly-build-expected-auralinux.txt data/accessibility/html/select-slowly-build-expected-blink.txt data/accessibility/html/select-slowly-build.html +data/accessibility/html/select-with-input-2-expected-auralinux.txt +data/accessibility/html/select-with-input-2-expected-blink.txt +data/accessibility/html/select-with-input-2.html data/accessibility/html/select-with-input-expected-auralinux.txt data/accessibility/html/select-with-input-expected-blink.txt data/accessibility/html/select-with-input.html
diff --git a/content/test/data/accessibility/html/select-with-input-2-expected-auralinux.txt b/content/test/data/accessibility/html/select-with-input-2-expected-auralinux.txt new file mode 100644 index 0000000..4eb6b45 --- /dev/null +++ b/content/test/data/accessibility/html/select-with-input-2-expected-auralinux.txt
@@ -0,0 +1,32 @@ +[document web] +++[section] +++++[combo box] +++++++[menu] controlled-by=[entry] +++++++++[section] +++++++++++[section] +++++++++++++[entry] selectable-text controller-for=[menu] +++++++++++[menu item] name='one' selectable selected +++++++++++[menu item] name='two' selectable +++++[combo box] +++++++[menu] controlled-by=[entry] +++++++++[section] +++++++++++[menu item] name='one' selectable selected +++++++++++[section] +++++++++++++[entry] selectable-text controller-for=[menu] +++++++++++[menu item] name='two' selectable +++++[combo box] +++++++[dialog] +++++++++[section] +++++++++++[section] +++++++++++++[radio button] checkable checkable:true +++++++++++[menu item] name='one' selectable selected +++++++++++[menu item] name='two' selectable +++++[combo box] +++++++[dialog] controlled-by=[entry,entry] +++++++++[section] +++++++++++[section] +++++++++++++[entry] selectable-text controller-for=[dialog] +++++++++++[section] +++++++++++++[entry] selectable-text controller-for=[dialog] +++++++++++[menu item] name='one' selectable selected +++++++++++[menu item] name='two' selectable
diff --git a/content/test/data/accessibility/html/select-with-input-2-expected-blink.txt b/content/test/data/accessibility/html/select-with-input-2-expected-blink.txt new file mode 100644 index 0000000..a17bea82 --- /dev/null +++ b/content/test/data/accessibility/html/select-with-input-2-expected-blink.txt
@@ -0,0 +1,37 @@ +rootWebArea +++genericContainer ignored +++++genericContainer +++++++comboBoxSelect collapsed value='one' +++++++++menuListPopup invisible ispopup=auto +++++++++++genericContainer invisible +++++++++++++genericContainer invisible +++++++++++++++textField invisible controlsIds=menuListPopup +++++++++++++++++genericContainer invisible +++++++++++++menuListOption name='one' selected=true +++++++++++++menuListOption invisible name='two' selected=false +++++++comboBoxSelect collapsed value='one' +++++++++menuListPopup invisible ispopup=auto +++++++++++genericContainer invisible +++++++++++++menuListOption name='one' selected=true +++++++++++++genericContainer invisible +++++++++++++++textField invisible controlsIds=menuListPopup +++++++++++++++++genericContainer invisible +++++++++++++menuListOption invisible name='two' selected=false +++++++comboBoxSelect collapsed value='one' +++++++++dialog invisible ispopup=auto +++++++++++genericContainer invisible +++++++++++++genericContainer invisible +++++++++++++++radioButton invisible checkedState=false +++++++++++++menuListOption name='one' selected=true +++++++++++++menuListOption invisible name='two' selected=false +++++++comboBoxSelect collapsed value='one' +++++++++dialog invisible ispopup=auto +++++++++++genericContainer invisible +++++++++++++genericContainer invisible +++++++++++++++textField invisible controlsIds=dialog +++++++++++++++++genericContainer invisible +++++++++++++genericContainer invisible +++++++++++++++textField invisible controlsIds=dialog +++++++++++++++++genericContainer invisible +++++++++++++menuListOption name='one' selected=true +++++++++++++menuListOption invisible name='two' selected=false
diff --git a/content/test/data/accessibility/html/select-with-input-2.html b/content/test/data/accessibility/html/select-with-input-2.html new file mode 100644 index 0000000..4f6b8d1 --- /dev/null +++ b/content/test/data/accessibility/html/select-with-input-2.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<style> +select, ::picker(select) { + appearance: base-select; +} +</style> + +<select id=s1> + <span class=input></span> + <option>one</option> + <option>two</option> +</select> + +<select id=s2> + <option>one</option> + <span class=input></span> + <option>two</option> +</select> + +<select id=s3> + <span class=input data-type=radio></span> + <option>one</option> + <option>two</option> +</select> + +<select id=s4> + <span class=input></span> + <span class=input></span> + <option>one</option> + <option>two</option> +</select> + +<script> + document.querySelectorAll('.input').forEach(container => { + const input = document.createElement('input'); + input.type = container.getAttribute('data-type'); + container.appendChild(input); + }); +</script>
diff --git a/content/test/gpu/bad_machine_finder/tasks.py b/content/test/gpu/bad_machine_finder/tasks.py index f1eda8d..fe4cebf7 100644 --- a/content/test/gpu/bad_machine_finder/tasks.py +++ b/content/test/gpu/bad_machine_finder/tasks.py
@@ -5,7 +5,7 @@ import collections import functools -from typing import Generator, List, Tuple +from typing import Generator class BotStats: @@ -78,6 +78,7 @@ self._total_tasks = 0 self._failed_tasks = 0 self._bots = collections.defaultdict(BotStats) + self._cached_overall_failure_rates: list[float] | None = None def Freeze(self) -> None: if self._frozen: @@ -98,18 +99,18 @@ assert self._frozen return self._failed_tasks - def IterBots(self) -> Generator[Tuple[str, 'BotStats'], None, None]: + def IterBots(self) -> Generator[tuple[str, 'BotStats'], None, None]: assert self._frozen for bot_id, stats in self._bots.items(): yield bot_id, stats - @functools.lru_cache(maxsize=None) - def GetOverallFailureRates(self) -> List[float]: + def GetOverallFailureRates(self) -> list[float]: assert self._frozen - failure_rates = [] - for _, stats in self._bots.items(): - failure_rates.append(stats.overall_failure_rate) - return failure_rates + if self._cached_overall_failure_rates is None: + self._cached_overall_failure_rates = [] + for _, stats in self._bots.items(): + self._cached_overall_failure_rates.append(stats.overall_failure_rate) + return self._cached_overall_failure_rates # Mutators
diff --git a/content/test/gpu/gather_power_measurement_results.py b/content/test/gpu/gather_power_measurement_results.py index 163a9a2..65ad692 100755 --- a/content/test/gpu/gather_power_measurement_results.py +++ b/content/test/gpu/gather_power_measurement_results.py
@@ -40,9 +40,8 @@ url = ulib_request.Request( 'https://cr-buildbucket.appspot.com/prpc/buildbucket.v2.Builds/' + method, request, headers) - conn = ulib_request.urlopen(url) - result = conn.read() - conn.close() + with ulib_request.urlopen(url) as conn: + result = conn.read() # Result is a multi-line string the first line of which is # deliberate garbage and the rest of which is a JSON payload. return json.loads(''.join(result.splitlines()[1:])) @@ -127,9 +126,8 @@ ulib_parse.unquote(stdout_url)) # The following fails with Python 2.7.6, but succeeds with Python 2.7.14. - conn = ulib_request.urlopen(stdout_url + '?format=raw') - lines = conn.read().splitlines() - conn.close() + with ulib_request.urlopen(stdout_url + '?format=raw') as conn: + lines = conn.read().splitlines() pattern = re.compile(r'^\[(\d+)/(\d+)\]$') results = None
diff --git a/content/test/gpu/gather_swarming_json_results.py b/content/test/gpu/gather_swarming_json_results.py index 5fa0ed3..841211c 100755 --- a/content/test/gpu/gather_swarming_json_results.py +++ b/content/test/gpu/gather_swarming_json_results.py
@@ -33,9 +33,8 @@ url = ulib.Request( 'https://cr-buildbucket.appspot.com/prpc/buildbucket.v2.Builds/' + method, request, headers) - conn = ulib.urlopen(url) - result = conn.read().decode('utf-8') - conn.close() + with ulib.urlopen(url) as conn: + result = conn.read().decode('utf-8') # Result is a multi-line string the first line of which is # deliberate garbage and the rest of which is a JSON payload. return json.loads(''.join(result.splitlines()[1:])) @@ -81,9 +80,8 @@ def JsonLoadFromUrl(url): - conn = ulib.urlopen(url + '?format=raw') - result = conn.read() - conn.close() + with ulib.urlopen(url + '?format=raw') as conn: + result = conn.read() return json.loads(result)
diff --git a/content/test/gpu/gold_inexact_matching/base_parameter_optimizer.py b/content/test/gpu/gold_inexact_matching/base_parameter_optimizer.py index 1551030..3d30b95 100644 --- a/content/test/gpu/gold_inexact_matching/base_parameter_optimizer.py +++ b/content/test/gpu/gold_inexact_matching/base_parameter_optimizer.py
@@ -14,7 +14,6 @@ import shutil import subprocess import tempfile -from typing import Dict, List, Optional, Set, Tuple from PIL import Image # pylint: disable=import-error @@ -42,10 +41,10 @@ # } # } # } -ExpectationJson = Dict[str, Dict[str, Dict[str, str]]] +ExpectationJson = dict[str, dict[str, dict[str, str]]] -class BaseParameterOptimizer(): +class BaseParameterOptimizer: """Abstract base class for running a parameter optimization for a test.""" MIN_EDGE_THRESHOLD = 0 MAX_EDGE_THRESHOLD = 255 @@ -62,16 +61,16 @@ """ self._args = args self._test_name = test_name - self._goldctl_binary: Optional[str] = None - self._working_dir: Optional[str] = None - self._expectations: Optional[ExpectationJson] = None + self._goldctl_binary: str | None = None + self._working_dir: str | None = None + self._expectations: ExpectationJson | None = None # TODO(skbug.com/10610): Switch away from the public instance once # authentication is fixed for the non-public instance. self._gold_url = f'https://{args.gold_instance}-public-gold.skia.org' self._pool = multiprocessing.Pool() # A map of strings, denoting a resolution or trace, to a set of strings, # denoting images that are that dimension or belong to that trace. - self._images: Dict[str, Set[str]] = collections.defaultdict(set) + self._images: dict[str, set[str]] = collections.defaultdict(set) self._VerifyArgs() parameter_set.ParameterSet.ignored_border_thickness = \ self._args.ignored_border_thickness @@ -367,7 +366,7 @@ return self._goldctl_binary def _RunComparisonForParameters( - self, parameters: parameter_set.ParameterSet) -> Tuple[bool, int, int]: + self, parameters: parameter_set.ParameterSet) -> tuple[bool, int, int]: """Runs a comparison for all image combinations using some parameters. Args: @@ -419,7 +418,7 @@ def _GenerateComparisonCmd( self, left_digest: str, right_digest: str, - parameters: parameter_set.ParameterSet) -> List[str]: + parameters: parameter_set.ParameterSet) -> list[str]: """Generates a comparison command for the given arguments. The returned command can be passed directly to a subprocess call. @@ -445,7 +444,7 @@ return cmd -def RunCommandAndExtractData(cmd: List[str]) -> Tuple[bool, int, int]: +def RunCommandAndExtractData(cmd: list[str]) -> tuple[bool, int, int]: """Runs a comparison command and extracts data from it. This is outside of the parameter optimizers because it is meant to be run via
diff --git a/content/test/gpu/gpu_tests/color_profile_manager.py b/content/test/gpu/gpu_tests/color_profile_manager.py index c31dd4c0..1155c151 100644 --- a/content/test/gpu/gpu_tests/color_profile_manager.py +++ b/content/test/gpu/gpu_tests/color_profile_manager.py
@@ -32,9 +32,8 @@ if skip_restoring_color_profile: print('Skipping restoring the original color profile') return - for display_id in display_profile_url_map: - color_profile_manager_mac.SetDisplayCustomProfile( - display_id, display_profile_url_map[display_id]) + for display_id, profile_url in display_profile_url_map.items(): + color_profile_manager_mac.SetDisplayCustomProfile(display_id, profile_url) atexit.register(Restore)
diff --git a/content/test/gpu/gpu_tests/context_lost_integration_test.py b/content/test/gpu/gpu_tests/context_lost_integration_test.py index 761268b..4a09e59 100644 --- a/content/test/gpu/gpu_tests/context_lost_integration_test.py +++ b/content/test/gpu/gpu_tests/context_lost_integration_test.py
@@ -202,10 +202,11 @@ cls.SetStaticServerDirs([gpu_path_util.GPU_DATA_DIR]) # Can be changed to functools.cache on Python 3.9+. + @classmethod @functools.lru_cache(maxsize=None) - def _GetWaitTimeout(self): + def _GetWaitTimeout(cls): timeout = 60 - if self._is_asan or self.browser.browser_type == 'debug': + if cls._is_asan or cls.browser.browser_type == 'debug': timeout *= 2 return timeout
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py b/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py index 99de5f7..214f71a 100644 --- a/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py +++ b/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py
@@ -158,12 +158,12 @@ # tempfile_ext.NamedTemporaryFile(), put it in the list of generators # starting this with block. Also remove the try finally statement # below. - temp_file = tempfile.NamedTemporaryFile(delete=False) - temp_file.close() + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + temp_file_name = temp_file.name try: test_argv = [ test_name, - f'--write-full-results-to={temp_file.name}', + f'--write-full-results-to={temp_file_name}', # We don't want the underlying typ-based tests to report their # results to ResultDB. '--disable-resultsink', @@ -177,10 +177,10 @@ telemetry_args = browser_test_runner.ProcessConfig( unittest_config, processed_args) run_browser_tests.RunTests(telemetry_args) - with open(temp_file.name, encoding='utf-8') as f: + with open(temp_file_name, encoding='utf-8') as f: self._test_result = json.load(f) finally: - temp_file.close() + os.remove(temp_file_name) def testOverrideDefaultRetryArgumentsinRunGpuIntegrationTests(self) -> None: self._RunGpuIntegrationTests('run_tests_with_expectations_files',
diff --git a/content/test/gpu/gpu_tests/ipg_utils.py b/content/test/gpu/gpu_tests/ipg_utils.py index 8fc08a1..14de5137 100644 --- a/content/test/gpu/gpu_tests/ipg_utils.py +++ b/content/test/gpu/gpu_tests/ipg_utils.py
@@ -25,6 +25,8 @@ import subprocess from typing import Any +import dataclasses # Built-in, but Pylint 2.7 gives an ordering false positive. + from gpu_tests.util import host_information SummaryType = dict[str, dict[str, float]] @@ -32,6 +34,17 @@ MetricType = dict[str, list[str] | list[float]] +@dataclasses.dataclass +class _LogFileColumn: + """Represents the parsed data from a column in an IPG log file.""" + # The index of this column within the file. + index: int + # The name of the column. + label: str + # The sum of all rows within the column. + total: float = 0.0 + + def LocateIPG() -> str: if host_information.IsWindows(): ipg_dir = os.getenv('IPG_Dir') @@ -89,42 +102,41 @@ if not logfile: logfile = GenerateIPGLogFilename() if not os.path.isfile(logfile): - raise Exception("Can't locate logfile at " + logfile) + raise Exception(f"Can't locate logfile at {logfile}") first_line = True samples = 0 - cols = 0 - indices = [] - labels = [] - sums = [] + total_columns = 0 + columns = [] col_time = None - for line in open(logfile, encoding='utf-8'): + with open(logfile, encoding='utf-8') as infile: + contents = infile.read() + for line in contents.splitlines(keepends=True): tokens = [token.strip('" ') for token in line.split(',')] if first_line: first_line = False - cols = len(tokens) - for ii in range(0, cols): + total_columns = len(tokens) + for ii in range(total_columns): token = tokens[ii] if token.startswith('Elapsed Time'): col_time = ii elif token.endswith('(Watt)'): - indices.append(ii) - labels.append(token[:-len('(Watt)')]) - sums.append(0.0) + columns.append(_LogFileColumn(index=ii, label=token[:-len('(Watt)')])) assert col_time - assert cols > 0 - assert len(indices) > 0 + assert total_columns > 0 + assert len(columns) > 0 continue - if len(tokens) != cols: + if len(tokens) != total_columns: continue if skip_in_sec > 0 and float(tokens[col_time]) < skip_in_sec: continue samples += 1 - for ii, index in enumerate(indices): - sums[ii] += float(tokens[index]) + for c in columns: + c.total += float(tokens[c.index]) + results = {'samples': samples} if samples > 0: - for ii in range(0, len(indices)): - results[labels[ii]] = sums[ii] / samples + for c in columns: + results[c.label] = c.total / samples return results @@ -154,10 +166,10 @@ core = core[len(prefix):] per_core_results[core] = results - for key in results: + for key, value in results.items(): if key in ('samples', 'log'): continue - metrics.setdefault(key, []).append(results[key]) + metrics.setdefault(key, []).append(value) return per_core_results, metrics def _CalculateSummaryStatistics(metrics: MetricType) -> SummaryType: @@ -195,8 +207,7 @@ output['summary'] = summary if output_json: - json_file = open(output_json, 'w', encoding='utf-8') - json_file.write(json.dumps(output, indent=4)) - json_file.close() + with open(output_json, 'w', encoding='utf-8') as json_file: + json_file.write(json.dumps(output, indent=4)) return summary
diff --git a/content/test/gpu/gpu_tests/overlay_support.py b/content/test/gpu/gpu_tests/overlay_support.py index dbe318e..0115673 100644 --- a/content/test/gpu/gpu_tests/overlay_support.py +++ b/content/test/gpu/gpu_tests/overlay_support.py
@@ -120,7 +120,7 @@ if set(self_dict.keys()) != set(other_dict.keys()): return False - return all(self_dict[k] == other_dict[k] for k in self_dict) + return all(v == other_dict[k] for k, v in self_dict.items()) def WithDirectComposition(self) -> 'GpuOverlayConfig': """Enables direct composition support via software.""" @@ -461,7 +461,9 @@ .WithHardwareNV12Support(driver_conditionals=[ DriverConditional('ge', '31.0.15.4601')])\ .WithHardwareYUY2Support(driver_conditionals=[ - DriverConditional('ge', '31.0.15.4601')]) + DriverConditional('ge', '31.0.15.4601')])\ + .WithHardwareBGRA8Support(driver_conditionals=[ + DriverConditional('ge', '32.0.15.7602')])\ .WithForceComposedBGRA8(driver_conditionals=[ DriverConditional('lt', '31.0.15.4601')])\ .WithZeroCopyConfig(ZeroCopyConfig(
diff --git a/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py b/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py index b7d7e03..a13f54c4 100644 --- a/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py +++ b/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py
@@ -344,9 +344,16 @@ # PNG to disk, following the pattern in bitmap_unittest.py. The key to # avoiding PermissionErrors seems to be to not actually try to write to # the temporary file object, but to re-open its name for all operations. - temp_file = tempfile.NamedTemporaryFile(suffix='.png').name - image_util.WritePngFile(bitmap, temp_file) - cloud_storage.Insert(bucket, name, temp_file, publicly_readable=public) + with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_file: + temp_file_name = temp_file.name + try: + image_util.WritePngFile(bitmap, temp_file_name) + cloud_storage.Insert(bucket, + name, + temp_file_name, + publicly_readable=public) + finally: + os.remove(temp_file_name) # Not used consistently, but potentially useful for debugging issues on the # bots, so kept around for future use. @@ -454,25 +461,25 @@ test_case: the GPU SkiaGoldTestCase object for the test. """ # Write screenshot to PNG file on local disk. - png_temp_file = tempfile.NamedTemporaryFile( - suffix='.png', dir=self._skia_gold_temp_dir).name - image_util.WritePngFile(screenshot, png_temp_file) + with tempfile.NamedTemporaryFile(suffix='.png', + dir=self._skia_gold_temp_dir, + delete=False) as png_temp_file: + png_temp_file_name = png_temp_file.name + image_util.WritePngFile(screenshot, png_temp_file_name) - gpu_keys = self.GetGoldJsonKeys(test_case) gold_session = self.GetSkiaGoldSessionManager().GetSkiaGoldSession( - gpu_keys, corpus=SKIA_GOLD_CORPUS) + self.GetGoldJsonKeys(test_case), corpus=SKIA_GOLD_CORPUS) gold_properties = self.GetSkiaGoldProperties() use_luci = not (gold_properties.local_pixel_tests or gold_properties.no_luci_auth) - optional_keys = self.GetGoldOptionalKeys() status, error = gold_session.RunComparison( name=image_name, - png_file=png_temp_file, + png_file=png_temp_file_name, inexact_matching_args=test_case.matching_algorithm.GetCmdline(), use_luci=use_luci, service_account=gold_properties.service_account, - optional_keys=optional_keys) + optional_keys=self.GetGoldOptionalKeys()) if not status: return
diff --git a/content/test/gpu/gpu_tests/test_expectations/cast_streaming_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/cast_streaming_expectations.txt index b533c7c..81fd678 100644 --- a/content/test/gpu/gpu_tests/test_expectations/cast_streaming_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/cast_streaming_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt index 3b140a3..0eab87e 100644 --- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt index 10092b4..e63345d 100644 --- a/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt index 0cdc7f6..9b9ada6 100644 --- a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ] @@ -160,6 +162,7 @@ crbug.com/380269801 [ android android-sm-a137f ] GpuProcess_visibility [ Failure ] crbug.com/380269801 [ android android-sm-a236b ] GpuProcess_visibility [ Failure ] crbug.com/380269801 [ android android-pixel-4 ] GpuProcess_visibility [ RetryOnFailure ] +crbug.com/380269801 [ android android-brya ] GpuProcess_visibility [ Failure ] ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt index 1e7e40a3..d83181619 100644 --- a/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/hardware_accelerated_feature_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt index dd9b677..45461066 100644 --- a/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/info_collection_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index d3b85dc..e41b10b1 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ] @@ -479,9 +481,6 @@ crbug.com/370694819 [ angle-opengl asan graphite-disabled mac ] Pixel_WebGPUDestroyed_OffscreenCanvas* [ Failure ] crbug.com/370694819 [ angle-opengl asan graphite-disabled mac ] Pixel_WebGPUDestroyed_OnscreenCanvas* [ Failure ] -# Failure on Mac ARM -crbug.com/412679361 [ mac mac-arm64 ] Pixel_WebGPUCopyExternalImageWebGPUCanvas [ Failure ] - # Flaky on Win10 Intel with bad image crbug.com/413062240 [ win10 intel-0x4680 passthrough ] Pixel_WebGPUDestroyed_OnscreenCanvas_CopyExternalImageToTexture [ RetryOnFailure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt index 1e7e40a3..d83181619 100644 --- a/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/power_measurement_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt index b38dac1..21681883 100644 --- a/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt index 3c4dc39..85c38f5b 100644 --- a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ] @@ -211,18 +213,18 @@ crbug.com/329138770 [ win graphite-enabled ] SwapChainTraceTest_CanvasLowLatencyWebGLAlphaFalse [ Failure ] crbug.com/329138770 [ win graphite-enabled ] SwapChainTraceTest_CanvasLowLatencyWebGLDrawImage [ Failure ] crbug.com/329138770 [ win graphite-enabled ] SwapChainTraceTest_CanvasLowLatencyWebGLRoundedCorners [ Failure ] -crbug.com/329138770 [ graphite-enabled no-clang-coverage nvidia-0x2783 nvidia_lt_535.183.01 release-x64 target-cpu-64 win11 ] WebGPUCachingTraceTest_ComputePipelineCrossOriginsCacheMisses [ Failure ] crbug.com/329138770 [ graphite-enabled win10 ] WebGPUCachingTraceTest_ComputePipelineCrossOriginsCacheMisses [ Failure ] -crbug.com/329138770 [ graphite-enabled no-clang-coverage nvidia-0x2783 nvidia_lt_535.183.01 release-x64 target-cpu-64 win11 ] WebGPUCachingTraceTest_ComputePipelineDifferentOrigins [ Failure ] crbug.com/329138770 [ graphite-enabled win10 ] WebGPUCachingTraceTest_ComputePipelineDifferentOrigins [ Failure ] -crbug.com/329138770 [ graphite-enabled no-clang-coverage nvidia-0x2783 nvidia_lt_535.183.01 release-x64 target-cpu-64 win11 ] WebGPUCachingTraceTest_ComputePipelineIncognito [ Failure ] crbug.com/329138770 [ graphite-enabled win10 ] WebGPUCachingTraceTest_ComputePipelineIncognito [ Failure ] -crbug.com/329138770 [ graphite-enabled no-clang-coverage nvidia-0x2783 nvidia_lt_535.183.01 release-x64 target-cpu-64 win11 ] WebGPUCachingTraceTest_RenderPipelineCrossOriginsCacheMisses [ Failure ] crbug.com/329138770 [ graphite-enabled win10 ] WebGPUCachingTraceTest_RenderPipelineCrossOriginsCacheMisses [ Failure ] -crbug.com/329138770 [ graphite-enabled no-clang-coverage nvidia-0x2783 nvidia_lt_535.183.01 release-x64 target-cpu-64 win11 ] WebGPUCachingTraceTest_RenderPipelineDifferentOrigins [ Failure ] crbug.com/329138770 [ graphite-enabled win10 ] WebGPUCachingTraceTest_RenderPipelineDifferentOrigins [ Failure ] -crbug.com/329138770 [ graphite-enabled no-clang-coverage nvidia-0x2783 nvidia_lt_535.183.01 release-x64 target-cpu-64 win11 ] WebGPUCachingTraceTest_RenderPipelineIncognito [ Failure ] crbug.com/329138770 [ graphite-enabled win10 ] WebGPUCachingTraceTest_RenderPipelineIncognito [ Failure ] +crbug.com/329138770 [ graphite-enabled win11 nvidia ] WebGPUCachingTraceTest_ComputePipelineCrossOriginsCacheMisses [ Failure ] +crbug.com/329138770 [ graphite-enabled win11 nvidia ] WebGPUCachingTraceTest_ComputePipelineDifferentOrigins [ Failure ] +crbug.com/329138770 [ graphite-enabled win11 nvidia ] WebGPUCachingTraceTest_ComputePipelineIncognito [ Failure ] +crbug.com/329138770 [ graphite-enabled win11 nvidia ] WebGPUCachingTraceTest_RenderPipelineCrossOriginsCacheMisses [ Failure ] +crbug.com/329138770 [ graphite-enabled win11 nvidia ] WebGPUCachingTraceTest_RenderPipelineDifferentOrigins [ Failure ] +crbug.com/329138770 [ graphite-enabled win11 nvidia ] WebGPUCachingTraceTest_RenderPipelineIncognito [ Failure ] # Win/AMD RX 7600 failures crbug.com/402989071 [ win11 amd-0x7480 ] TraceTest_MediaFoundationD3D11VideoCapture [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt index 01f1e5a..6ec33ae5 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ] @@ -146,6 +148,20 @@ # Same with prefer-hardware crbug.com/371802469 [ amd-0x7340 angle-opengl asan graphite-disabled mac ] WebCodecs_Encode_camera_hvc1.1.6.L123.00_prefer-hardware [ Failure ] +# Flaky crashes that started when upgrading to Mac 15.4 +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_ContentHint_hvc1.1.6.L123.00_detail [ Failure ] +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_ContentHint_hvc1.1.6.L123.00_motion [ Failure ] +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_EncodeColorSpace_hvc1.1.6.L123.00_prefer-hardware [ Failure ] +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_EncodeDecode_arraybuffer_hvc1.1.6.L123.00_prefer-hardware [ Failure ] +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_EncodeDecode_camera_hvc1.1.6.L123.00_prefer-hardware [ Failure ] +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_EncodeDecode_capture_hvc1.1.6.L123.00_prefer-hardware [ Failure ] +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_EncodeDecode_hw_decoder_hvc1.1.6.L123.00_prefer-hardware [ Failure ] +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_EncodeDecode_offscreen_hvc1.1.6.L123.00_prefer-hardware [ Failure ] +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_EncodeDecode_sw_decoder_hvc1.1.6.L123.00_prefer-hardware [ Failure ] +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_Encode_arraybuffer_hvc1.1.6.L123.00_prefer-hardware [ Failure ] +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_Encode_camera_hvc1.1.6.L123.00_prefer-hardware [ Failure ] +crbug.com/416294710 [ sequoia angle-opengl graphite-disabled intel-0x3e9b ] WebCodecs_Encode_capture_hvc1.1.6.L123.00_prefer-hardware [ Failure ] + crbug.com/389978730 [ win11 nvidia-0x2783 ] WebCodecs_EncodeColorSpace_av01.0.04M.08_prefer-hardware [ Failure ] # Win/AMD RX 7600 Failures
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index 71b92177..6dc4074 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ] @@ -791,9 +793,6 @@ ## Mac ASAN ## -# Flaky failure due to possible synchronization issues -crbug.com/412679364 [ mac mac-arm64 ] conformance/textures/canvas/tex-2d-alpha-alpha-unsigned_byte.html [ RetryOnFailure ] - #################### # Linux failures # ####################
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index 01f66e3..dedf32f 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -1,7 +1,7 @@ # BEGIN TAG HEADER (autogenerated, see validate_tag_consistency.py) # OS # tags: [ android android-oreo android-pie android-r android-s android-t -# android-14 +# android-14 android-15 android-16 # chromeos # fuchsia # linux ubuntu @@ -11,6 +11,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock @@ -37,7 +38,8 @@ # google google-0xffff google-0xc0de # imagination # intel intel-gen-9 intel-gen-12 intel-0xa2e intel-0xd26 intel-0xa011 -# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x5912 intel-0x9bc5 +# intel-0x3e92 intel-0x3e9b intel-0x4680 intel-0x46a8 intel-0x5912 +# intel-0x9bc5 # microsoft microsoft-0xffff # nvidia nvidia-0xfe9 nvidia-0x1cb3 nvidia-0x2184 nvidia-0x2783 # qualcomm qualcomm-0x41333430 qualcomm-0x36333630 qualcomm-0x36334330 ] @@ -499,7 +501,8 @@ ## Vulkan / Win / NVIDIA / Passthrough command decoder ## -crbug.com/40786644 [ win nvidia-0x2783 angle-vulkan passthrough ] conformance/glsl/bugs/pow-with-constant-exponent-should-not-crash.html [ Failure ] +crbug.com/40786644 [ win11 nvidia angle-vulkan passthrough ] conformance/glsl/bugs/pow-with-constant-exponent-should-not-crash.html [ Failure ] +crbug.com/415086850 [ win11 nvidia-0x2184 angle-vulkan passthrough ] conformance/ogles/GL/mod/mod_001_to_008.html [ Failure ] ## Win / Adreno 690 / D3D11 crbug.com/1523062 [ win11 qualcomm-0x41333430 angle-d3d11 ] conformance/rendering/bind-framebuffer-flush-bug.html [ Failure ]
diff --git a/content/test/gpu/gpu_tests/trace_integration_test.py b/content/test/gpu/gpu_tests/trace_integration_test.py index 221bae2f..6f56389 100644 --- a/content/test/gpu/gpu_tests/trace_integration_test.py +++ b/content/test/gpu/gpu_tests/trace_integration_test.py
@@ -589,22 +589,21 @@ self._RunActualGpuTraceTest(test_path, params) elif isinstance(params, _CacheTraceTestArguments): # Create a new temporary directory for each cache test that is run. - cache_profile_dir = tempfile.TemporaryDirectory() + with tempfile.TemporaryDirectory() as cache_profile_dir: + # Run the first load page and get the number of expected cache hits. + load_params = params.GenerateFirstLoadTest() + results =\ + self._RunActualGpuTraceTest(test_path, + load_params, + profile_dir=cache_profile_dir, + profile_type='exact') - # Run the first load page and get the number of expected cache hits. - load_params = params.GenerateFirstLoadTest() - results =\ - self._RunActualGpuTraceTest(test_path, - load_params, - profile_dir=cache_profile_dir.name, - profile_type='exact') - - # Generate and run the cache hit tests using the seeded cache dir. - for (hit_path, trace_params) in params.GenerateCacheHitTests(results): - self._RunActualGpuTraceTest(hit_path, - trace_params, - profile_dir=cache_profile_dir.name, - profile_type='clean') + # Generate and run the cache hit tests using the seeded cache dir. + for (hit_path, trace_params) in params.GenerateCacheHitTests(results): + self._RunActualGpuTraceTest(hit_path, + trace_params, + profile_dir=cache_profile_dir, + profile_type='clean') @classmethod def SetUpProcess(cls) -> None:
diff --git a/content/test/gpu/validate_tag_consistency.py b/content/test/gpu/validate_tag_consistency.py index fc0b4868..d32c7c7 100755 --- a/content/test/gpu/validate_tag_consistency.py +++ b/content/test/gpu/validate_tag_consistency.py
@@ -33,6 +33,8 @@ 'android-s', 'android-t', 'android-14', + 'android-15', + 'android-16', ], 'chromeos': [], 'fuchsia': [], @@ -106,6 +108,7 @@ 'intel-0x3e92', 'intel-0x3e9b', 'intel-0x4680', + 'intel-0x46a8', 'intel-0x5912', 'intel-0x9bc5', ], @@ -188,6 +191,7 @@ # tags: [ android-nexus-5x android-pixel-2 android-pixel-4 # android-pixel-6 android-shield-android-tv android-sm-a137f # android-sm-a236b android-sm-s911u1 +# android-brya # chromeos-board-amd64-generic chromeos-board-eve chromeos-board-jacuzzi # chromeos-board-octopus chromeos-board-volteer # fuchsia-board-astro fuchsia-board-nelson fuchsia-board-sherlock
diff --git a/content/utility/utility_main.cc b/content/utility/utility_main.cc index 19ada6e..7ca43d0e 100644 --- a/content/utility/utility_main.cc +++ b/content/utility/utility_main.cc
@@ -45,8 +45,6 @@ #include "content/common/gpu_pre_sandbox_hook_linux.h" #include "content/public/common/content_descriptor_keys.h" #include "content/utility/speech/speech_recognition_sandbox_hook_linux.h" -#include "media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.h" -#include "media/gpu/sandbox/hardware_video_encoding_sandbox_hook_linux.h" #include "sandbox/policy/linux/sandbox_linux.h" #include "services/audio/audio_sandbox_hook_linux.h" #include "services/network/network_sandbox_hook_linux.h" @@ -54,6 +52,8 @@ #if BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION) #include "gpu/config/gpu_info_collector.h" +#include "media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.h" +#include "media/gpu/sandbox/hardware_video_encoding_sandbox_hook_linux.h" // gn check is not smart enough to realize that this include is guarded behind // some BUILDFLAG()s and the BUILD.gn dependencies correctly account for that. #include "third_party/angle/src/gpu_info_util/SystemInfo.h" //nogncheck
diff --git a/docs/android_emulator.md b/docs/android_emulator.md index 91844dc4..448d980 100644 --- a/docs/android_emulator.md +++ b/docs/android_emulator.md
@@ -229,9 +229,7 @@ ### Using Your Own Emulator Image -By far the easiest way to set up emulator images is to use Android Studio. -If you don't have an [Android Studio project](android_studio.md) already, you -can create a blank one to be able to reach the Virtual Device Manager screen. +You can also set up emulator images in Android Studio. Refer to: https://developer.android.com/studio/run/managing-avds.html @@ -240,52 +238,62 @@ * Emulator configs and data partition images are stored within `~/.android/avd/`. +To get started, launch any Android Studio Project. If you don't have an [Android +Studio project](android_studio.md) already, you can create a blank one. Go to +the menu on the right-hand side of the window and click to launch the Device +Manager. In the Device Manager window, click the "+" icon and **Create Virtual +Device**. + #### Creating an Image -##### Choosing a Skin +You'll see a long list of Pixel phone names. You need to 2 decisions here: -Choose a skin with a small screen for better performance (unless you care about -testing large screens). +1. Which form factor (phone/tablet/etc.)? If you're not sure, a **phone** target + is usually fine for most development. +2. Which device model skin? Any Pixel skin is usually sufficient, but pay + attention to the "API" column if you need a specific OS version. You can + refer to + https://developer.android.com/guide/topics/manifest/uses-sdk-element.html to + convert between API numbers and the OS release number (ex. API 34 refers to + the Android 14 release). -##### Choosing an Image +##### Device settings -Android Studio's image labels roughly translate to the following: +You need to choose 4 things on the "Device" tab: -| AVD "Target" | Virtual Device Configuration tab | GMS? | Build Properties | -| --- | --- | --- | --- | -| Google Play | "Recommended" (the default tab) | This has GMS | `user`/`release-keys` | -| Google APIs | "x86 Images" | This has GMS | `userdebug`/`dev-keys` | -| No label | "x86 Images" | AOSP image, does not have GMS | `eng`/`test-keys` | +1. Name: give this emulator a name to help you remember what this emulator is + for (ex. "Android 15"). +2. API: choose an API version (Android operating system version) for the emulator. +3. Services: you'll probably want to choose **Google APIs** for most + development, since this gives you a `userdebug` emulator with GMS Core APIs + installed. See the table below if you need something different. +4. System image: select "Google APIs Intel x86\_64" (or whichever row has the + ⭐ icon) -*** promo -**Tip:** if you're not sure which to use, choose **Google APIs** under the **x86 -Images** tab in the Virtual Device Configuration wizard. -*** +Choosing different **Services** for the emulator: -##### Configuration +| Services | GMS? | Build Properties | +| --- | --- | --- | +| Google Play | This has GMS and the Play Store | `user`/`release-keys` | +| Google APIs | This has GMS | `userdebug`/`dev-keys` | +| Android Open Source | AOSP image, does not have GMS | `eng`/`test-keys` | -"Show Advanced Settings" > scroll down: -* Set internal storage to 4000MB (component builds are really big). -* Set SD card to 1000MB (our tests push a lot of files to /sdcard). + -##### Known Issues +##### Additional settings - * Our test & installer scripts do not work with pre-MR1 Jelly Bean. - * Component builds do not work on pre-KitKat (due to the OS having a max - number of shared libraries). - * Jelly Bean and KitKat images sometimes forget to mount /sdcard :(. - * This causes tests to fail. - * To ensure it's there: `adb -s emulator-5554 shell mount` (look for /sdcard) - * Can often be fixed by editing `~/.android/avd/YOUR_DEVICE/config.ini`. - * Look for `hw.sdCard=no` and set it to `yes` - * The "Google APIs" Android L and M emulator images are configured to expect - the "AOSP" WebView package (`com.android.webview`). This does not resemble - production devices with GMS, which expect the ["Google WebView" - configuration](/android_webview/docs/webview-providers.md#webview-provider-options) - (`com.google.android.webview` on L and M). See [Removing preinstalled - WebView](/android_webview/docs/build-instructions.md#Removing-preinstalled-WebView) - if you need to install a local build or official build. +1. Internal storage: this needs to be at least 4000 MB (4 GB) + (component builds are really big). +2. Expanded storage: this needs to be at least 1000 MB (1 GB) + (our tests push a lot of files to /sdcard). +After you have configured everything, you can click "Finish" to create the AVD +(emulator). +After it's been created, you can launch the AVD from Device Manager by clicking +the play button or you can launch it from the commandline (see instructions +below). + + #### Starting an Emulator from the Command Line
diff --git a/docs/images/android_device_manager_additional_settings_tab.png b/docs/images/android_device_manager_additional_settings_tab.png new file mode 100644 index 0000000..df2ed166 --- /dev/null +++ b/docs/images/android_device_manager_additional_settings_tab.png Binary files differ
diff --git a/docs/images/android_device_manager_device_tab.png b/docs/images/android_device_manager_device_tab.png new file mode 100644 index 0000000..6536976 --- /dev/null +++ b/docs/images/android_device_manager_device_tab.png Binary files differ
diff --git a/docs/testing/run_web_platform_tests_on_android.md b/docs/testing/run_web_platform_tests_on_android.md index 3f47baa..fe8f134 100644 --- a/docs/testing/run_web_platform_tests_on_android.md +++ b/docs/testing/run_web_platform_tests_on_android.md
@@ -117,11 +117,8 @@ ## Test expectations and Baselines -The -[MobileTestExpectations](../../third_party/blink/web_tests/MobileTestExpectations) -file contains the list of all known Chrome Android and Chrome WebView specific -test failures, and it inherits or overrides test expectations from the default -[TestExpectations](../../third_party/blink/web_tests/TestExpectations) file. +Expected failures on Chrome Android or WebView should be added to the default +[TestExpectations](../../third_party/blink/web_tests/TestExpectations) file with the modifier "Android" or "Webview" respectively. For baselines: * Chrome Android specific baselines reside at
diff --git a/docs/testing/web_test_expectations.md b/docs/testing/web_test_expectations.md index 6ef74c26..3fcdb25 100644 --- a/docs/testing/web_test_expectations.md +++ b/docs/testing/web_test_expectations.md
@@ -217,8 +217,6 @@ Tests that fail under Chrome for Testing * [LeakExpectations](../../third_party/blink/web_tests/LeakExpectations): Tests that have memory leaks under the leak checker. -* [MobileTestExpectations](../../third_party/blink/web_tests/MobileTestExpectations) - Tests that fails under Chrome Android and Chrome WebView platform. * [MSANExpectations](../../third_party/blink/web_tests/MSANExpectations): Tests that fail under MSAN. * [NeverFixTests](../../third_party/blink/web_tests/NeverFixTests): Tests @@ -284,8 +282,9 @@ applicable to that file. * If specified, modifiers can be one of `Fuchsia`, `Mac`, `Mac11`, `Mac11-arm64`, `Mac12`, `Mac12-arm64`, `Mac13`, `Mac13-arm64`, `Mac14`, - `Mac14-arm64`, `Mac15`, `Mac15-arm64`, `Linux`, `Chrome`, `Win`, `Win10.20h2`, - `Win11`, `iOS17-Simulator`, and, optionally, `Release`, or `Debug`. + `Mac14-arm64`, `Mac15`, `Mac15-arm64`, `Linux`, `Win`, `Win10.20h2`, + `Win11`, `Win11-arm64`, `Android`, `Webview`, `iOS17-Simulator`, and, + optionally, `Release`, or `Debug`. Check the `# tags: ...` comments [at the top of each file](/third_party/blink/web_tests/TestExpectations#1) to see which modifiers that file supports.
diff --git a/docs/use_counter_wiki.md b/docs/use_counter_wiki.md index 3b9fbdb..168110f 100644 --- a/docs/use_counter_wiki.md +++ b/docs/use_counter_wiki.md
@@ -156,63 +156,44 @@ ### UseCounter Feature in HTTP Archive -HTTP Archive crawls the top 10K sites on the web and records everything from +HTTP Archive crawls the top sites on the web and records everything from request and response headers. The data is available on Google BigQuery. -You can find pages that trigger a particular UseCounter using the following -script: +You can find usage and sample pages that trigger a particular UseCounter using +the following script: ```sql SELECT - DATE(yyyymmdd) AS date, + date, client AS platform, - num_url AS url_count, - pct_urls AS urls_percentile, + num_urls AS url_count, + pct_urls AS urls_percent, sample_urls AS url -FROM [httparchive:blink_features.usage] -WHERE feature = 'MyFeature' -ORDER BY url_percentile DESC +FROM `httparchive.blink_features.usage` +WHERE + feature = 'MyFeature' AND + date = (SELECT MAX(date) FROM `httparchive.blink_features.usage`) +ORDER BY date DESC ``` -OR + + +Or to see or filter my more data available in the HTTP Archive you can query the main `httparchive.crawl.pages` table like this: ```sql -SELECT - url -FROM [httparchive:pages.yyyy_mm_dd_mobile] +SELECT DISTINCT + client, + page, + rank +FROM + `httparchive.crawl.pages`, + UNNEST (features) As feats WHERE - JSON_EXTRACT(payload, '$._blinkFeatureFirstUsed.Features.MyFeature') IS NOT - NULL -LIMIT 500 + date = '2024-11-01' AND -- update date to latest month + feats.feature = 'MyFeature' -- update feature +ORDER BY + rank ``` -You can also find pages that trigger a particular CSS property (during parsing): - -```sql -SELECT - url -FROM [httparchive:pages.yyyy_mm_dd_mobile] -WHERE - JSON_EXTRACT(payload, '$._blinkFeatureFirstUsed.CSSFeatures.MyCSSProperty') - IS NOT NULL -LIMIT 500 -``` - -To find pages that trigger a UseCounter and sort by page rank: - -```sql -SELECT - IFNULL(runs.rank, 1000000) AS rank, - har.url AS url, -FROM [httparchive:latest.pages_desktop] AS har -LEFT JOIN [httparchive:runs.latest_pages] AS runs - ON har.url = runs.url -WHERE - JSON_EXTRACT(payload, '$._blinkFeatureFirstUsed.Features.MyFeature') IS NOT - NULL -ORDER BY rank; -``` - - ### UMA Usage on Fraction of Users You may also see the fraction of users that trigger your feature at lease once a day on [UMA Usage dashboard](https://goto.google.com/uma-usecounter-peruser).
diff --git a/docs/website b/docs/website index b2558d3..406e2b2 160000 --- a/docs/website +++ b/docs/website
@@ -1 +1 @@ -Subproject commit b2558d301fc88f8e4671024c47960ff1ee82cf34 +Subproject commit 406e2b2832f3d734a2ba4f8fa93fb78deecb16d2
diff --git a/extensions/browser/api/power/BUILD.gn b/extensions/browser/api/power/BUILD.gn index 279c3aae..35ab8d7c 100644 --- a/extensions/browser/api/power/BUILD.gn +++ b/extensions/browser/api/power/BUILD.gn
@@ -16,15 +16,18 @@ configs += [ "//build/config/compiler:wexit_time_destructors" ] - deps = [ - "//content/public/browser", - "//content/public/common", + public_deps = [ + "//base", + "//build:chromeos_buildflags", + "//extensions/browser:browser_sources", "//extensions/common", "//extensions/common/api", "//mojo/public/cpp/bindings", "//services/device/public/mojom", ] + deps = [ "//content/public/browser" ] + if (is_chromeos) { sources += [ "activity_reporter_delegate.cc", @@ -33,8 +36,6 @@ "activity_reporter_delegate_ash.h", ] - deps += [ "//build:chromeos_buildflags" ] + deps += [ "//ui/base" ] } - - public_deps = [ "//extensions/browser:browser_sources" ] }
diff --git a/extensions/browser/api/runtime/BUILD.gn b/extensions/browser/api/runtime/BUILD.gn index ea4fe0bf..8851d80 100644 --- a/extensions/browser/api/runtime/BUILD.gn +++ b/extensions/browser/api/runtime/BUILD.gn
@@ -17,13 +17,20 @@ configs += [ "//build/config/compiler:wexit_time_destructors" ] - deps = [ - "//components/prefs", - "//components/sessions", - "//content/public/browser", + public_deps = [ + "//base", + "//extensions/browser:browser_sources", "//extensions/common", "//extensions/common/api", ] - public_deps = [ "//extensions/browser:browser_sources" ] + deps = [ + "//components/prefs", + "//components/sessions", + "//content/public/browser", + "//extensions/common:common_constants", + "//extensions/common:mojom", + "//storage/browser", + "//url", + ] }
diff --git a/extensions/browser/json_file_sanitizer.cc b/extensions/browser/json_file_sanitizer.cc index 7a17c45..df0dc36 100644 --- a/extensions/browser/json_file_sanitizer.cc +++ b/extensions/browser/json_file_sanitizer.cc
@@ -6,145 +6,107 @@ #include <optional> #include <string> +#include <utility> #include "base/files/file_util.h" #include "base/functional/bind.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/task/sequenced_task_runner.h" +#include "base/types/expected.h" +#include "base/values.h" #include "extensions/browser/extension_file_task_runner.h" -#include "services/data_decoder/public/cpp/data_decoder.h" namespace extensions { -namespace { - -// Reads the file in |path| and then deletes it. -// Returns a tuple containing: the file content, whether the read was -// successful, whether the delete was successful. -std::tuple<std::string, bool, bool> ReadAndDeleteTextFile( - const base::FilePath& path) { - std::string contents; - bool read_success = base::ReadFileToString(path, &contents); - bool delete_success = base::DeleteFile(path); - return std::make_tuple(contents, read_success, delete_success); -} - -bool WriteStringToFile(const std::string& contents, - const base::FilePath& file_path) { - return base::WriteFile(file_path, contents); -} - -} // namespace - // static std::unique_ptr<JsonFileSanitizer> JsonFileSanitizer::CreateAndStart( - data_decoder::DataDecoder* decoder, const std::set<base::FilePath>& file_paths, Callback callback, const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) { // Note we can't use std::make_unique as we want to keep the constructor // private. std::unique_ptr<JsonFileSanitizer> sanitizer( - new JsonFileSanitizer(file_paths, std::move(callback), io_task_runner)); - sanitizer->Start(decoder); + new JsonFileSanitizer(std::move(callback), io_task_runner)); + sanitizer->Start(file_paths); return sanitizer; } JsonFileSanitizer::JsonFileSanitizer( - const std::set<base::FilePath>& file_paths, Callback callback, const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) - : file_paths_(file_paths), - callback_(std::move(callback)), - io_task_runner_(io_task_runner) {} + : callback_(std::move(callback)), io_task_runner_(io_task_runner) {} JsonFileSanitizer::~JsonFileSanitizer() = default; -void JsonFileSanitizer::Start(data_decoder::DataDecoder* decoder) { - if (file_paths_.empty()) { +void JsonFileSanitizer::Start(const std::set<base::FilePath>& file_paths) { + if (file_paths.empty()) { base::SequencedTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce(&JsonFileSanitizer::ReportSuccess, weak_factory_.GetWeakPtr())); return; } - decoder->GetService()->BindJsonParser( - json_parser_.BindNewPipeAndPassReceiver()); - - for (const base::FilePath& path : file_paths_) { + remaining_callbacks_ = file_paths.size(); + for (const base::FilePath& path : file_paths) { io_task_runner_->PostTaskAndReplyWithResult( - FROM_HERE, base::BindOnce(&ReadAndDeleteTextFile, path), - base::BindOnce(&JsonFileSanitizer::JsonFileRead, - weak_factory_.GetWeakPtr(), path)); + FROM_HERE, base::BindOnce(&JsonFileSanitizer::ProcessFile, path), + base::BindOnce(&JsonFileSanitizer::OnProcessedFile, + weak_factory_.GetWeakPtr())); } } -void JsonFileSanitizer::JsonFileRead( - const base::FilePath& file_path, - std::tuple<std::string, bool, bool> read_and_delete_result) { - if (!std::get<1>(read_and_delete_result)) { - ReportError(Status::kFileReadError, std::string()); - return; - } - if (!std::get<2>(read_and_delete_result)) { - ReportError(Status::kFileDeleteError, std::string()); - return; - } - json_parser_->Parse(std::get<0>(read_and_delete_result), - base::JSON_PARSE_CHROMIUM_EXTENSIONS, - base::BindOnce(&JsonFileSanitizer::JsonParsingDone, - weak_factory_.GetWeakPtr(), file_path)); -} +base::expected<void, JsonFileSanitizer::Error> JsonFileSanitizer::ProcessFile( + const base::FilePath& path) { + std::string contents; + bool read_success = base::ReadFileToString(path, &contents); + bool delete_success = base::DeleteFile(path); -void JsonFileSanitizer::JsonParsingDone( - const base::FilePath& file_path, - std::optional<base::Value> json_value, - const std::optional<std::string>& error) { - if (!json_value || !json_value->is_dict()) { - ReportError(Status::kDecodingError, error ? *error : std::string()); - return; + if (!read_success) { + return base::unexpected(Error::kFileReadError); + } + + if (!delete_success) { + return base::unexpected(Error::kFileDeleteError); + } + + std::optional<base::Value> result = base::JSONReader::Read(contents); + if (!result.has_value() || !result->is_dict()) { + return base::unexpected(Error::kDecodingError); } // Reserialize the JSON and write it back to the original file. std::optional<std::string> json_string = base::WriteJsonWithOptions( - *json_value, base::JSONWriter::OPTIONS_PRETTY_PRINT); + *result, base::JSONWriter::OPTIONS_PRETTY_PRINT); if (!json_string) { - ReportError(Status::kSerializingError, std::string()); - return; + return base::unexpected(Error::kSerializingError); } - io_task_runner_->PostTaskAndReplyWithResult( - FROM_HERE, - base::BindOnce(&WriteStringToFile, std::move(*json_string), file_path), - base::BindOnce(&JsonFileSanitizer::JsonFileWritten, - weak_factory_.GetWeakPtr(), file_path)); + if (!base::WriteFile(path, *json_string)) { + return base::unexpected(Error::kFileWriteError); + } + + return base::ok(); } -void JsonFileSanitizer::JsonFileWritten(const base::FilePath& file_path, - bool success) { - if (!success) { - ReportError(Status::kFileWriteError, std::string()); - return; - } - // We have finished with this JSON file. - size_t removed_count = file_paths_.erase(file_path); - DCHECK_EQ(1U, removed_count); - - if (file_paths_.empty()) { - // This was the last path, we are done. - ReportSuccess(); +void JsonFileSanitizer::OnProcessedFile(base::expected<void, Error> result) { + if (result.has_value()) { + if (--remaining_callbacks_ == 0) { + ReportSuccess(); + } + } else { + ReportError(result.error()); } } void JsonFileSanitizer::ReportSuccess() { - std::move(callback_).Run(Status::kSuccess, std::string()); + std::move(callback_).Run(base::ok()); } -void JsonFileSanitizer::ReportError(Status status, const std::string& error) { +void JsonFileSanitizer::ReportError(Error error) { // Prevent any other task from reporting, we want to notify only once. weak_factory_.InvalidateWeakPtrs(); - std::move(callback_).Run(status, error); + std::move(callback_).Run(base::unexpected(error)); } } // namespace extensions
diff --git a/extensions/browser/json_file_sanitizer.h b/extensions/browser/json_file_sanitizer.h index 1d1a59d..f592d49 100644 --- a/extensions/browser/json_file_sanitizer.h +++ b/extensions/browser/json_file_sanitizer.h
@@ -9,18 +9,13 @@ #include <optional> #include <set> #include <string> -#include <tuple> #include "base/files/file_path.h" #include "base/memory/weak_ptr.h" #include "base/task/sequenced_task_runner.h" +#include "base/types/expected.h" #include "base/values.h" #include "mojo/public/cpp/bindings/remote.h" -#include "services/data_decoder/public/mojom/json_parser.mojom.h" - -namespace data_decoder { -class DataDecoder; -} namespace extensions { @@ -32,8 +27,7 @@ // is not the case. class JsonFileSanitizer { public: - enum class Status { - kSuccess = 0, + enum class Error { kFileReadError, kFileDeleteError, kDecodingError, @@ -41,23 +35,17 @@ kFileWriteError, }; - // Callback invoked when the JSON sanitization is is done. If status is an - // error, `error_msg` contains the error message. - using Callback = - base::OnceCallback<void(Status status, const std::string& error_msg)>; + // Callback invoked when the JSON sanitization is is done. + using Callback = base::OnceCallback<void(base::expected<void, Error>)>; // Creates a JsonFileSanitizer and starts the sanitization of the JSON files // in `file_paths`. - // `decoder` should be a DataDecoder which can be used to talk to a Data - // Decoder service instance. It must be live on the calling sequence and - // it is not retained beyond the extent of this call. // `callback` is invoked asynchronously when all JSON files have been // sanitized or if an error occurred. // If the returned JsonFileSanitizer instance is deleted before `callback` was // invoked, then `callback` is never invoked and the sanitization stops // promptly (some background tasks may still run). static std::unique_ptr<JsonFileSanitizer> CreateAndStart( - data_decoder::DataDecoder* decoder, const std::set<base::FilePath>& file_paths, Callback callback, const scoped_refptr<base::SequencedTaskRunner>& io_task_runner); @@ -69,29 +57,22 @@ private: JsonFileSanitizer( - const std::set<base::FilePath>& file_paths, Callback callback, const scoped_refptr<base::SequencedTaskRunner>& io_task_runner); - void Start(data_decoder::DataDecoder* decoder); + void Start(const std::set<base::FilePath>& file_paths); - void JsonFileRead(const base::FilePath& file_path, - std::tuple<std::string, bool, bool> read_and_delete_result); + // Note: unlike all other methods, this executes on `io_task_runner_`. + static base::expected<void, Error> ProcessFile(const base::FilePath& path); - void JsonParsingDone(const base::FilePath& file_path, - std::optional<base::Value> json_value, - const std::optional<std::string>& error); - - void JsonFileWritten(const base::FilePath& file_path, bool success); - + void OnProcessedFile(base::expected<void, Error> result); void ReportSuccess(); + void ReportError(Error error); - void ReportError(Status status, const std::string& path); - - std::set<base::FilePath> file_paths_; + size_t remaining_callbacks_ = 0; Callback callback_; scoped_refptr<base::SequencedTaskRunner> io_task_runner_; - mojo::Remote<data_decoder::mojom::JsonParser> json_parser_; + base::WeakPtrFactory<JsonFileSanitizer> weak_factory_{this}; };
diff --git a/extensions/browser/json_file_sanitizer_unittest.cc b/extensions/browser/json_file_sanitizer_unittest.cc index 7d493b3..becd8186 100644 --- a/extensions/browser/json_file_sanitizer_unittest.cc +++ b/extensions/browser/json_file_sanitizer_unittest.cc
@@ -12,12 +12,15 @@ #include "base/functional/bind.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" +#include "base/test/gmock_expected_support.h" +#include "base/types/expected.h" #include "content/public/test/browser_task_environment.h" #include "extensions/browser/extension_file_task_runner.h" -#include "services/data_decoder/public/cpp/data_decoder.h" -#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" #include "testing/gtest/include/gtest/gtest.h" +using ::base::test::ErrorIs; +using ::base::test::HasValue; + namespace extensions { namespace { @@ -55,35 +58,28 @@ void CreateAndStartSanitizer(const std::set<base::FilePath>& file_paths) { sanitizer_ = JsonFileSanitizer::CreateAndStart( - &data_decoder_, file_paths, + file_paths, base::BindOnce(&JsonFileSanitizerTest::SanitizationDone, base::Unretained(this)), GetExtensionFileTaskRunner()); } - JsonFileSanitizer::Status last_reported_status() const { + base::expected<void, JsonFileSanitizer::Error> last_reported_status() const { return last_status_; } - const std::string& last_reported_error() const { return last_error_; } - private: void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } - void SanitizationDone(JsonFileSanitizer::Status status, - const std::string& error_msg) { + void SanitizationDone(base::expected<void, JsonFileSanitizer::Error> status) { last_status_ = status; - last_error_ = error_msg; if (done_callback_) { std::move(done_callback_).Run(); } } content::BrowserTaskEnvironment task_environment_; - data_decoder::test::InProcessDataDecoder in_process_data_decoder_; - data_decoder::DataDecoder data_decoder_; - JsonFileSanitizer::Status last_status_; - std::string last_error_; + base::expected<void, JsonFileSanitizer::Error> last_status_; base::OnceClosure done_callback_; std::unique_ptr<JsonFileSanitizer> sanitizer_; base::ScopedTempDir temp_dir_; @@ -94,8 +90,7 @@ TEST_F(JsonFileSanitizerTest, NoFilesProvided) { CreateAndStartSanitizer(std::set<base::FilePath>()); WaitForSanitizationDone(); - EXPECT_EQ(last_reported_status(), JsonFileSanitizer::Status::kSuccess); - EXPECT_TRUE(last_reported_error().empty()); + EXPECT_THAT(last_reported_status(), HasValue()); } TEST_F(JsonFileSanitizerTest, ValidCase) { @@ -113,8 +108,7 @@ } CreateAndStartSanitizer(paths); WaitForSanitizationDone(); - EXPECT_EQ(last_reported_status(), JsonFileSanitizer::Status::kSuccess); - EXPECT_TRUE(last_reported_error().empty()); + EXPECT_THAT(last_reported_status(), HasValue()); // Make sure the JSON files are there and non empty. for (const auto& path : paths) { std::optional<int64_t> file_size = base::GetFileSize(path); @@ -133,7 +127,8 @@ base::FilePath invalid_path = CreateFilePath(kNonExistingName); CreateAndStartSanitizer({good_path, invalid_path}); WaitForSanitizationDone(); - EXPECT_EQ(last_reported_status(), JsonFileSanitizer::Status::kFileReadError); + EXPECT_THAT(last_reported_status(), + ErrorIs(JsonFileSanitizer::Error::kFileReadError)); } TEST_F(JsonFileSanitizerTest, InvalidJson) { @@ -147,8 +142,8 @@ CreateInvalidJsonFile(badd_path); CreateAndStartSanitizer({good_path, badd_path}); WaitForSanitizationDone(); - EXPECT_EQ(last_reported_status(), JsonFileSanitizer::Status::kDecodingError); - EXPECT_FALSE(last_reported_error().empty()); + EXPECT_THAT(last_reported_status(), + ErrorIs(JsonFileSanitizer::Error::kDecodingError)); } } // namespace extensions
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc index 895ad5f..dd94c82 100644 --- a/extensions/browser/sandboxed_unpacker.cc +++ b/extensions/browser/sandboxed_unpacker.cc
@@ -43,6 +43,7 @@ #include "extensions/browser/install/crx_install_error.h" #include "extensions/browser/install/sandboxed_unpacker_failure_reason.h" #include "extensions/browser/install_stage.h" +#include "extensions/browser/json_file_sanitizer.h" #include "extensions/browser/ruleset_parse_result.h" #include "extensions/browser/verified_contents.h" #include "extensions/browser/zipfile_installer.h" @@ -179,7 +180,6 @@ void CleanUp() { image_sanitizer_.reset(); json_file_sanitizer_.reset(); - json_parser_.reset(); } data_decoder::DataDecoder* GetDataDecoder() { return &data_decoder_; } @@ -197,48 +197,24 @@ } void CreateJsonFileSanitizer( - const std::set<base::FilePath>& message_catalog_paths, + std::set<base::FilePath> message_catalog_paths, JsonFileSanitizer::Callback callback, const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner) { json_file_sanitizer_ = JsonFileSanitizer::CreateAndStart( - GetDataDecoder(), message_catalog_paths, std::move(callback), + std::move(message_catalog_paths), std::move(callback), unpacker_io_task_runner); } - data_decoder::mojom::JsonParser* GetJsonParserPtr( - SandboxedUnpacker* unpacker) { - if (!json_parser_) { - data_decoder_.GetService()->BindJsonParser( - json_parser_.BindNewPipeAndPassReceiver()); - json_parser_.set_disconnect_handler(base::BindOnce( - &SandboxedUnpacker::ReportFailure, unpacker, - SandboxedUnpackerFailureReason:: - UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, - l10n_util::GetStringFUTF16( - IDS_EXTENSION_PACKAGE_INSTALL_ERROR, - u"UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL") + - u". " + - l10n_util::GetStringUTF16( - IDS_EXTENSION_INSTALL_PROCESS_CRASHED))); - } - - return json_parser_.get(); - } - private: // Controls our own lazily started, isolated instance of the Data Decoder // service so that multiple decode operations related to this - // SandboxedUnpacker can share a single instance. + // SandboxedUnpacker can share a single instance. Only used for image + // sanitization. data_decoder::DataDecoder data_decoder_; - // The JSONParser remote from the data decoder service. - mojo::Remote<data_decoder::mojom::JsonParser> json_parser_; - // The ImageSanitizer used to clean-up images. std::unique_ptr<ImageSanitizer> image_sanitizer_; - // Used during the message catalog rewriting phase to sanitize the extension - // provided message catalogs. std::unique_ptr<JsonFileSanitizer> json_file_sanitizer_; }; @@ -516,27 +492,27 @@ base::FilePath manifest_path = extension_root_.Append(kManifestFilename); - ParseJsonFile(manifest_path, - base::BindOnce(&SandboxedUnpacker::ReadManifestDone, this)); + // This calls `ReadManifestDone()` on completion. + ParseJsonFile(manifest_path); } void SandboxedUnpacker::ReadManifestDone( - std::optional<base::Value> manifest, - const std::optional<std::string>& error) { + base::expected<base::Value, std::string> result) { DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); - if (error) { - ReportUnpackExtensionFailed(*error); + if (!result.has_value()) { + ReportUnpackExtensionFailed(result.error()); return; } - if (!manifest || !manifest->is_dict()) { + const base::Value::Dict* dict = result->GetIfDict(); + if (!dict) { ReportUnpackExtensionFailed(manifest_errors::kInvalidManifest); return; } std::string error_msg; scoped_refptr<Extension> extension( - Extension::Create(extension_root_, location_, manifest->GetDict(), - creation_flags_, extension_id_, &error_msg)); + Extension::Create(extension_root_, location_, *dict, creation_flags_, + extension_id_, &error_msg)); if (!extension) { ReportUnpackExtensionFailed(error_msg); return; @@ -549,7 +525,7 @@ } extension->AddInstallWarnings(std::move(warnings)); - UnpackExtensionSucceeded(std::move(manifest.value()).TakeDict()); + UnpackExtensionSucceeded(std::move(result).value().TakeDict()); } void SandboxedUnpacker::UnpackExtensionSucceeded(base::Value::Dict manifest) { @@ -680,8 +656,7 @@ void SandboxedUnpacker::ReadMessageCatalogs() { DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); if (LocaleInfo::GetDefaultLocale(extension_.get()).empty()) { - MessageCatalogsSanitized(JsonFileSanitizer::Status::kSuccess, - std::string()); + MessageCatalogsSanitized(base::ok()); return; } @@ -698,6 +673,7 @@ void SandboxedUnpacker::SanitizeMessageCatalogs( const std::set<base::FilePath>& message_catalog_paths) { DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); + io_thread_state_->CreateJsonFileSanitizer( message_catalog_paths, base::BindOnce(&SandboxedUnpacker::MessageCatalogsSanitized, this), @@ -705,10 +681,9 @@ } void SandboxedUnpacker::MessageCatalogsSanitized( - JsonFileSanitizer::Status status, - const std::string& error_msg) { + base::expected<void, JsonFileSanitizer::Error> result) { DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); - if (status == JsonFileSanitizer::Status::kSuccess) { + if (result.has_value()) { IndexAndPersistJSONRulesetsIfNeeded(); return; } @@ -716,27 +691,25 @@ SandboxedUnpackerFailureReason failure_reason = SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED; std::u16string error; - switch (status) { - case JsonFileSanitizer::Status::kFileReadError: - case JsonFileSanitizer::Status::kDecodingError: + switch (result.error()) { + case JsonFileSanitizer::Error::kFileReadError: + case JsonFileSanitizer::Error::kDecodingError: failure_reason = SandboxedUnpackerFailureReason::INVALID_CATALOG_DATA; error = l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, u"INVALID_CATALOG_DATA"); break; - case JsonFileSanitizer::Status::kSerializingError: + case JsonFileSanitizer::Error::kSerializingError: failure_reason = SandboxedUnpackerFailureReason::ERROR_SERIALIZING_CATALOG; error = l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, u"ERROR_SERIALIZING_CATALOG"); break; - case JsonFileSanitizer::Status::kFileDeleteError: - case JsonFileSanitizer::Status::kFileWriteError: + case JsonFileSanitizer::Error::kFileDeleteError: + case JsonFileSanitizer::Error::kFileWriteError: failure_reason = SandboxedUnpackerFailureReason::ERROR_SAVING_CATALOG; error = l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, u"ERROR_SAVING_CATALOG"); break; - default: - NOTREACHED(); } ReportFailure(failure_reason, error); @@ -817,11 +790,6 @@ ReportSuccess(); } -data_decoder::mojom::JsonParser* SandboxedUnpacker::GetJsonParserPtr() { - DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); - return io_thread_state_->GetJsonParserPtr(this); -} - void SandboxedUnpacker::ReportUnpackExtensionFailed(std::string_view error) { DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); ReportFailure(SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED, @@ -1082,20 +1050,18 @@ io_thread_state_->CleanUp(); } -void SandboxedUnpacker::ParseJsonFile( - const base::FilePath& path, - data_decoder::mojom::JsonParser::ParseCallback callback) { +void SandboxedUnpacker::ParseJsonFile(const base::FilePath& path) { DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); std::string contents; if (!base::ReadFileToString(path, &contents)) { - std::move(callback).Run( - /*value=*/std::nullopt, - /*error=*/std::optional<std::string>("File doesn't exist.")); + ReadManifestDone(base::unexpected("File doesn't exist.")); return; } - GetJsonParserPtr()->Parse(contents, base::JSON_PARSE_CHROMIUM_EXTENSIONS, - std::move(callback)); + base::JSONReader::Result result = + base::JSONReader::ReadAndReturnValueWithError(contents); + ReadManifestDone(std::move(result).transform_error( + [](const base::JSONReader::Error& error) { return error.ToString(); })); } } // namespace extensions
diff --git a/extensions/browser/sandboxed_unpacker.h b/extensions/browser/sandboxed_unpacker.h index 27776ca..329495b 100644 --- a/extensions/browser/sandboxed_unpacker.h +++ b/extensions/browser/sandboxed_unpacker.h
@@ -15,6 +15,7 @@ #include "base/memory/ref_counted_delete_on_sequence.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" +#include "base/types/expected.h" #include "base/values.h" #include "extensions/browser/api/declarative_net_request/install_index_helper.h" #include "extensions/browser/content_verifier/content_verifier_key.h" @@ -27,7 +28,6 @@ #include "extensions/common/mojom/manifest.mojom-shared.h" #include "mojo/public/cpp/bindings/remote.h" #include "services/data_decoder/public/cpp/data_decoder.h" -#include "services/data_decoder/public/mojom/json_parser.mojom.h" class SkBitmap; @@ -200,8 +200,7 @@ // Unpacks the extension in directory and returns the manifest. void Unpack(const base::FilePath& directory); - void ReadManifestDone(std::optional<base::Value> manifest, - const std::optional<std::string>& error); + void ReadManifestDone(base::expected<base::Value, std::string> result); void UnpackExtensionSucceeded(base::Value::Dict manifest); // Helper which calls ReportFailure. @@ -218,8 +217,8 @@ void SanitizeMessageCatalogs( const std::set<base::FilePath>& message_catalog_paths); - void MessageCatalogsSanitized(JsonFileSanitizer::Status status, - const std::string& error_msg); + void MessageCatalogsSanitized( + base::expected<void, JsonFileSanitizer::Error> result); // Reports unpack success or failure, or unzip failure. void ReportSuccess(); @@ -252,14 +251,10 @@ void MaybeComputeHashes(bool should_compute_hashes); - // Returns a JsonParser that can be used on the `unpacker_io_task_runner`. - data_decoder::mojom::JsonParser* GetJsonParserPtr(); - - // Parses the JSON file at `path` and invokes `callback` when done. `callback` - // is called with a null parameter if parsing failed. + // Parses the JSON file at `path` and invokes `ReadManifestDone()` with the + // result. // This must be called from the `unpacker_io_task_runner_`. - void ParseJsonFile(const base::FilePath& path, - data_decoder::mojom::JsonParser::ParseCallback callback); + void ParseJsonFile(const base::FilePath& path); // If we unpacked a CRX file, we hold on to the path name for use // in various histograms.
diff --git a/extensions/browser/service_worker/service_worker_task_queue.cc b/extensions/browser/service_worker/service_worker_task_queue.cc index d42d069..0c296f5b 100644 --- a/extensions/browser/service_worker/service_worker_task_queue.cc +++ b/extensions/browser/service_worker/service_worker_task_queue.cc
@@ -550,10 +550,6 @@ const ExtensionId& extension_id = worker_info.scope.host(); - // Stop tracking the worker for extension API purposes. - ProcessManager::Get(browser_context_) - ->StopTrackingServiceWorkerRunningInstance(extension_id, version_id); - // Remove worker running state information for event dispatching from the task // queue. std::optional<base::UnguessableToken> activation_token = @@ -567,13 +563,35 @@ WorkerState* worker_state = GetWorkerState(context_id); // If the extension is still activated, worker state should still exist. CHECK(worker_state); - // Untrack all the worker state because once a worker begin stopping or stops, - // a new instance must start before the worker can be considered ready to - // receive tasks/events again and the renderer stop notifications are not 100% - // reliable. - worker_state->SetBrowserState(BrowserState::kInitial); - worker_state->SetRendererState(RendererState::kNotActive); - worker_state->ResetWorkerId(); + + // Check that the version ID of the worker that is stopping refers to an + // extension service worker that is tracked by this class. Service workers + // registered for subscopes via `navigation.serviceWorker.register()` rather + // than being declared in the manifest's background section are not allowed + // to use extensions API, and should be ignored here. See crbug.com/395536907. + // NOTE: We may have already reset worker ID and renderer state, but not + // browser state, if `DidStopServiceWorkerContext()` was called first. + // In that case, we reset browser state here. + bool has_already_reset_renderer_state = + !worker_state->worker_id() && + worker_state->renderer_state() == RendererState::kNotActive; + if (has_already_reset_renderer_state || + worker_state->worker_id()->version_id == version_id) { + // Stop tracking the worker for extension API purposes. + ProcessManager::Get(browser_context_) + ->StopTrackingServiceWorkerRunningInstance(extension_id, version_id); + // Untrack all the worker state because once a worker begin stopping or + // stops, a new instance must start before the worker can be considered + // ready to receive tasks/events again and the renderer stop notifications + // are not 100% reliable. + worker_state->SetBrowserState(BrowserState::kInitial); + worker_state->SetRendererState(RendererState::kNotActive); + worker_state->ResetWorkerId(); + } + + if (g_test_observer) { + g_test_observer->UntrackServiceWorkerState(worker_info.scope); + } } void ServiceWorkerTaskQueue::RegisterServiceWorker(
diff --git a/extensions/browser/service_worker/service_worker_task_queue.h b/extensions/browser/service_worker/service_worker_task_queue.h index 42f2f8cf..a892a08 100644 --- a/extensions/browser/service_worker/service_worker_task_queue.h +++ b/extensions/browser/service_worker/service_worker_task_queue.h
@@ -380,6 +380,13 @@ // is preparing to terminate. virtual void DidStopServiceWorkerContext(const ExtensionId& extension_id) {} + // Called when UntrackServiceWorkerState() is invoked for a worker + // associated with `scope` (because it's stopping or has stopped). + // This notification occurs even if the worker is a sub-scope worker and + // does not result in altering the ServiceWorkerTaskQueue's tracking state + // for the primary extension service worker. + virtual void UntrackServiceWorkerState(const GURL& scope) {} + // Called when a service worker registered for the extension with the // `extension_id` has been unregistered in the //content layer. virtual void WorkerUnregistered(const ExtensionId& extension_id) {}
diff --git a/extensions/browser/service_worker/service_worker_test_utils.cc b/extensions/browser/service_worker/service_worker_test_utils.cc index 4a474342..aae7254c 100644 --- a/extensions/browser/service_worker/service_worker_test_utils.cc +++ b/extensions/browser/service_worker/service_worker_test_utils.cc
@@ -246,6 +246,17 @@ run_loop.Run(); } +void TestServiceWorkerTaskQueueObserver::WaitForUntrackServiceWorkerState( + const GURL& scope) { + if (untracked_set_.count(scope) != 0) { + return; + } + + base::RunLoop run_loop; + untrack_quit_closure_ = run_loop.QuitClosure(); + run_loop.Run(); +} + void TestServiceWorkerTaskQueueObserver::WaitForWorkerContextInitialized( const ExtensionId& extension_id) { if (inited_set_.count(extension_id) != 0) { @@ -374,5 +385,13 @@ } } +void TestServiceWorkerTaskQueueObserver::UntrackServiceWorkerState( + const GURL& scope) { + untracked_set_.insert(scope); + if (untrack_quit_closure_) { + std::move(untrack_quit_closure_).Run(); + } +} + } // namespace service_worker_test_utils } // namespace extensions
diff --git a/extensions/browser/service_worker/service_worker_test_utils.h b/extensions/browser/service_worker/service_worker_test_utils.h index 3c4270c8..fa4e42a9 100644 --- a/extensions/browser/service_worker/service_worker_test_utils.h +++ b/extensions/browser/service_worker/service_worker_test_utils.h
@@ -179,6 +179,7 @@ const ExtensionId& extension_id); void WaitForOnActivateExtension(const ExtensionId& extension_id); bool WaitForRegistrationMismatchMitigation(const ExtensionId& extension_id); + void WaitForUntrackServiceWorkerState(const GURL& scope); std::optional<bool> WillRegisterServiceWorker( const ExtensionId& extension_id) const; @@ -198,6 +199,7 @@ bool success) override; void RequestedWorkerStart(const ExtensionId& extension_id) override; void DidStopServiceWorkerContext(const ExtensionId& extension_id) override; + void UntrackServiceWorkerState(const GURL& scope) override; private: std::map<ExtensionId, bool> activated_map_; @@ -214,7 +216,11 @@ std::set<ExtensionId> stopped_set_; + std::set<GURL> untracked_set_; + base::OnceClosure quit_closure_; + + base::OnceClosure untrack_quit_closure_; }; } // namespace service_worker_test_utils
diff --git a/extensions/browser/zipfile_installer.cc b/extensions/browser/zipfile_installer.cc index db4a5c55..ee8d675 100644 --- a/extensions/browser/zipfile_installer.cc +++ b/extensions/browser/zipfile_installer.cc
@@ -4,6 +4,7 @@ #include "extensions/browser/zipfile_installer.h" +#include <optional> #include <variant> #include "base/containers/contains.h" @@ -15,6 +16,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/task/sequenced_task_runner.h" +#include "base/values.h" #include "components/services/unzip/content/unzip_service.h" #include "components/services/unzip/public/cpp/unzip.h" #include "components/services/unzip/public/mojom/unzipper.mojom.h" @@ -24,8 +26,6 @@ #include "extensions/common/extension_features.h" #include "extensions/common/manifest.h" #include "extensions/strings/grit/extensions_strings.h" -#include "services/data_decoder/public/cpp/data_decoder.h" -#include "services/data_decoder/public/mojom/json_parser.mojom.h" #include "ui/base/l10n/l10n_util.h" namespace extensions { @@ -178,34 +178,7 @@ return; } - // Create a DataDecoder to specify custom parse options to the JSON - // parser. The ownership of the |data_decoder| and |json_parser| - // transfer to the response callback and are deleted after it runs. - auto data_decoder = std::make_unique<data_decoder::DataDecoder>(); - mojo::Remote<data_decoder::mojom::JsonParser> json_parser; - data_decoder->GetService()->BindJsonParser( - json_parser.BindNewPipeAndPassReceiver()); - json_parser.set_disconnect_handler( - base::BindOnce(&ZipFileInstaller::ManifestParsed, this, unzip_dir, - std::nullopt, "Data Decoder terminated unexpectedly")); - auto* json_parser_ptr = json_parser.get(); - json_parser_ptr->Parse( - *manifest_content, base::JSON_PARSE_CHROMIUM_EXTENSIONS, - base::BindOnce( - [](std::unique_ptr<data_decoder::DataDecoder>, - mojo::Remote<data_decoder::mojom::JsonParser>, - scoped_refptr<ZipFileInstaller> installer, - const base::FilePath& unzip_dir, std::optional<base::Value> value, - const std::optional<std::string>& error) { - installer->ManifestParsed(unzip_dir, std::move(value), error); - }, - std::move(data_decoder), std::move(json_parser), - base::WrapRefCounted(this), unzip_dir)); -} - -void ZipFileInstaller::ManifestParsed(const base::FilePath& unzip_dir, - std::optional<base::Value> result, - const std::optional<std::string>& error) { + std::optional<base::Value> result = base::JSONReader::Read(*manifest_content); if (!result || !result->is_dict()) { ReportFailure(std::string(kExtensionHandlerFileUnzipError)); return;
diff --git a/extensions/browser/zipfile_installer.h b/extensions/browser/zipfile_installer.h index 9b4c69ce..3c9d5f9 100644 --- a/extensions/browser/zipfile_installer.h +++ b/extensions/browser/zipfile_installer.h
@@ -17,7 +17,6 @@ #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" #include "base/task/sequenced_task_runner.h" -#include "base/values.h" namespace extensions { @@ -89,9 +88,6 @@ void ManifestUnzipped(const base::FilePath& unzip_dir, bool success); void ManifestRead(const base::FilePath& unzip_dir, std::optional<std::string> manifest_content); - void ManifestParsed(const base::FilePath& unzip_dir, - std::optional<base::Value> result, - const std::optional<std::string>& error); void UnzipDone(const base::FilePath& unzip_dir, bool success); // On failure, report the `error` reason.
diff --git a/extensions/common/switches.cc b/extensions/common/switches.cc index f51ad1e..d6c57c49 100644 --- a/extensions/common/switches.cc +++ b/extensions/common/switches.cc
@@ -43,4 +43,10 @@ const char kAllowFutureManifestVersion[] = "allow-future-manifest-version"; const char kExtensionTestApiOnWebPages[] = "extension-test-api-on-web-pages"; +const char kZeroStatePromoIphVariantParamName[] = + "extension-zero-state-iph-variant"; +const char kZeroStatePromoCustomActionIph[] = "custom-action-iph"; +const char kZeroStatePromoCustomUiChipIph[] = "custom-ui-chip-iph"; +const char kZeroStatePromoCustomUiPlainLinkIph[] = "custom-ui-plain-link-iph"; + } // namespace extensions::switches
diff --git a/extensions/common/switches.h b/extensions/common/switches.h index 61319f9..56816333 100644 --- a/extensions/common/switches.h +++ b/extensions/common/switches.h
@@ -97,6 +97,23 @@ // actually use it in browser tests. extern const char kExtensionTestApiOnWebPages[]; +// The feature parameter name that controls the variant of IPH shown when the +// user has no extensions installed. +extern const char kZeroStatePromoIphVariantParamName[]; + +// When the user has no extensions installed, display a custom action IPH +// that upon triggering, opens a new tab to the Chrome Web Store. +extern const char kZeroStatePromoCustomActionIph[]; + +// When the user has no extensions installed, display a custom UI IPH that +// presents the user with different collections of extensions to explore, +// each in a cr-chip button. +extern const char kZeroStatePromoCustomUiChipIph[]; + +// When the user has no extensions installed, display a custom UI IPH that +// presents the user with different collections of extensions to explore, +// each in a plain text link. +extern const char kZeroStatePromoCustomUiPlainLinkIph[]; } // namespace extensions::switches #endif // EXTENSIONS_COMMON_SWITCHES_H_
diff --git a/extensions/renderer/extension_url_loader_throttle.cc b/extensions/renderer/extension_url_loader_throttle.cc index 1f61f2b..faa7895b 100644 --- a/extensions/renderer/extension_url_loader_throttle.cc +++ b/extensions/renderer/extension_url_loader_throttle.cc
@@ -34,11 +34,11 @@ void ExtensionURLLoaderThrottle::WillRedirectRequest( net::RedirectInfo* redirect_info, - const network::mojom::URLResponseHead& /* response_head */, - bool* /* defer */, - std::vector<std::string>* /* to_be_removed_request_headers */, - net::HttpRequestHeaders* /* modified_request_headers */, - net::HttpRequestHeaders* /* modified_cors_exempt_request_headers */) { + /*response_head=*/const network::mojom::URLResponseHead&, + /*defer=*/bool*, + /*to_be_removed_request_headers=*/std::vector<std::string>*, + /*modified_request_headers=*/net::HttpRequestHeaders*, + /*modified_cors_exempt_request_headers=*/net::HttpRequestHeaders*) { if (manager_->ShouldRejectRedirect(start_request_url_, *redirect_info)) { delegate_->CancelWithError(net::ERR_TEMPORARILY_THROTTLED, kCancelReason); }
diff --git a/extensions/renderer/storage_area.cc b/extensions/renderer/storage_area.cc index 198ea4e..25d693b 100644 --- a/extensions/renderer/storage_area.cc +++ b/extensions/renderer/storage_area.cc
@@ -286,8 +286,12 @@ void StorageArea::HandleFunctionCall(const std::string& method_name, gin::Arguments* arguments) { v8::Isolate* isolate = arguments->isolate(); + // This is only ever called from JavaScript, so we must have entered the + // isolate already in this thread. + CHECK_EQ(v8::Isolate::GetCurrent(), isolate); v8::HandleScope handle_scope(isolate); v8::Local<v8::Context> context = arguments->GetHolderCreationContext(); + CHECK_EQ(isolate, context->GetIsolate()); // The context may have been invalidated, as in the case where this could be // a reference to an object from a removed frame.
diff --git a/fuchsia_web/webengine/browser/frame_impl.cc b/fuchsia_web/webengine/browser/frame_impl.cc index 2c9ef63..c61784e 100644 --- a/fuchsia_web/webengine/browser/frame_impl.cc +++ b/fuchsia_web/webengine/browser/frame_impl.cc
@@ -201,7 +201,7 @@ return frame_impl_map; } -blink::PermissionType FidlPermissionTypeToContentPermissionType( +std::optional<blink::PermissionType> FidlPermissionTypeToContentPermissionType( fuchsia::web::PermissionType fidl_type) { switch (fidl_type) { case fuchsia::web::PermissionType::MICROPHONE: @@ -212,6 +212,8 @@ return blink::PermissionType::PROTECTED_MEDIA_IDENTIFIER; case fuchsia::web::PermissionType::PERSISTENT_STORAGE: return blink::PermissionType::DURABLE_STORAGE; + default: + return std::nullopt; } } @@ -1270,8 +1272,14 @@ return; } - blink::PermissionType type = + std::optional<blink::PermissionType> type = FidlPermissionTypeToContentPermissionType(fidl_permission.type()); + if (!type) { + LOG(ERROR) << "SetPermissionState() called with invalid permission type: " + << static_cast<uint16_t>(fidl_permission.type()) << "."; + CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS); + return; + } blink::mojom::PermissionStatus state = (fidl_state == fuchsia::web::PermissionState::GRANTED) @@ -1281,8 +1289,8 @@ // TODO(crbug.com/40724536): Remove this once the PermissionManager API is // available. if (web_origin_string == "*" && - type == blink::PermissionType::PROTECTED_MEDIA_IDENTIFIER) { - permission_controller_.SetDefaultPermissionState(type, state); + *type == blink::PermissionType::PROTECTED_MEDIA_IDENTIFIER) { + permission_controller_.SetDefaultPermissionState(*type, state); return; } @@ -1295,7 +1303,7 @@ return; } - permission_controller_.SetPermissionState(type, web_origin.value(), state); + permission_controller_.SetPermissionState(*type, web_origin.value(), state); } void FrameImpl::GetPrivateMemorySize(GetPrivateMemorySizeCallback callback) {
diff --git a/fuchsia_web/webengine/browser/web_engine_content_browser_client.cc b/fuchsia_web/webengine/browser/web_engine_content_browser_client.cc index c0bfdc62..6f1812c 100644 --- a/fuchsia_web/webengine/browser/web_engine_content_browser_client.cc +++ b/fuchsia_web/webengine/browser/web_engine_content_browser_client.cc
@@ -195,9 +195,6 @@ content::WebContents* web_contents, content::SiteInstance& main_frame_site, blink::web_pref::WebPreferences* web_prefs) { - // Disable WebSQL support since it is being removed from the web platform - // and does not work. See crbug.com/1317431. - web_prefs->databases_enabled = false; // TODO(crbug.com/40245916): Remove once supported in WebEngine. web_prefs->disable_webauthn = true;
diff --git a/gpu/command_buffer/client/shared_image_pool.h b/gpu/command_buffer/client/shared_image_pool.h index 8180021..25fc628 100644 --- a/gpu/command_buffer/client/shared_image_pool.h +++ b/gpu/command_buffer/client/shared_image_pool.h
@@ -76,7 +76,7 @@ // addition to the shared image it wraps. This allow clients to create its own // custom pool of images of ClientImage type and are not limited to creating // pool of only ClientSharedImage. See unittests for example. -class GPU_EXPORT ClientImage : public base::RefCounted<ClientImage> { +class GPU_EXPORT ClientImage : public base::RefCountedThreadSafe<ClientImage> { public: explicit ClientImage(scoped_refptr<ClientSharedImage> shared_image); @@ -96,7 +96,7 @@ const SharedImagePoolId& GetPoolIdForTesting() const; protected: - friend class base::RefCounted<ClientImage>; + friend class base::RefCountedThreadSafe<ClientImage>; friend class SharedImagePoolBase; // Allow each instantiation of SharedImagePool to access `pool_id_`.
diff --git a/infra/config/generated/builders/ci/Dawn Win10 x64 Builder/targets/chromium.dawn.json b/infra/config/generated/builders/ci/Dawn Win10 x64 Builder/targets/chromium.dawn.json index 0402278..caf3d10 100644 --- a/infra/config/generated/builders/ci/Dawn Win10 x64 Builder/targets/chromium.dawn.json +++ b/infra/config/generated/builders/ci/Dawn Win10 x64 Builder/targets/chromium.dawn.json
@@ -57,8 +57,8 @@ "swarming": { "dimensions": { "display_attached": "1", - "gpu": "10de:2184-31.0.15.4601", - "os": "Windows-10-19045", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", "pool": "chromium.tests.gpu" }, "expiration": 21600,
diff --git "a/infra/config/generated/builders/ci/Dawn Win10 x64 Experimental Release \050NVIDIA\051/targets/chromium.dawn.json" "b/infra/config/generated/builders/ci/Dawn Win10 x64 Experimental Release \050NVIDIA\051/targets/chromium.dawn.json" index 15425165..9666298 100644 --- "a/infra/config/generated/builders/ci/Dawn Win10 x64 Experimental Release \050NVIDIA\051/targets/chromium.dawn.json" +++ "b/infra/config/generated/builders/ci/Dawn Win10 x64 Experimental Release \050NVIDIA\051/targets/chromium.dawn.json"
@@ -20,8 +20,8 @@ "swarming": { "dimensions": { "display_attached": "1", - "gpu": "10de:2184-31.0.15.4601", - "os": "Windows-10-19045", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", "pool": "chromium.tests.gpu" }, "expiration": 21600,
diff --git a/infra/config/generated/builders/ci/Dawn Win10 x86 Builder/targets/chromium.dawn.json b/infra/config/generated/builders/ci/Dawn Win10 x86 Builder/targets/chromium.dawn.json index 622f57e7..7d51189 100644 --- a/infra/config/generated/builders/ci/Dawn Win10 x86 Builder/targets/chromium.dawn.json +++ b/infra/config/generated/builders/ci/Dawn Win10 x86 Builder/targets/chromium.dawn.json
@@ -57,8 +57,8 @@ "swarming": { "dimensions": { "display_attached": "1", - "gpu": "10de:2184-31.0.15.4601", - "os": "Windows-10-19045", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", "pool": "chromium.tests.gpu" }, "expiration": 21600,
diff --git "a/infra/config/generated/builders/ci/Dawn Win10 x86 Experimental Release \050NVIDIA\051/targets/chromium.dawn.json" "b/infra/config/generated/builders/ci/Dawn Win10 x86 Experimental Release \050NVIDIA\051/targets/chromium.dawn.json" index 6305478..054a68fd 100644 --- "a/infra/config/generated/builders/ci/Dawn Win10 x86 Experimental Release \050NVIDIA\051/targets/chromium.dawn.json" +++ "b/infra/config/generated/builders/ci/Dawn Win10 x86 Experimental Release \050NVIDIA\051/targets/chromium.dawn.json"
@@ -20,8 +20,8 @@ "swarming": { "dimensions": { "display_attached": "1", - "gpu": "10de:2184-31.0.15.4601", - "os": "Windows-10-19045", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", "pool": "chromium.tests.gpu" }, "expiration": 21600,
diff --git a/infra/config/generated/builders/ci/GPU FYI Win x64 Builder/targets/chromium.gpu.fyi.json b/infra/config/generated/builders/ci/GPU FYI Win x64 Builder/targets/chromium.gpu.fyi.json index 78e7c40..204fcf0 100644 --- a/infra/config/generated/builders/ci/GPU FYI Win x64 Builder/targets/chromium.gpu.fyi.json +++ b/infra/config/generated/builders/ci/GPU FYI Win x64 Builder/targets/chromium.gpu.fyi.json
@@ -1,10 +1,380 @@ { "GPU FYI Win x64 Builder": {}, "Win10 FYI x64 Exp Release (NVIDIA)": { + "gtest_tests": [ + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "angle_unittests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "angle_unittests", + "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/", + "use_isolated_scripts_api": true + }, + { + "args": [ + "--use-cmd-decoder=passthrough", + "--use-gl=angle", + "--use-gpu-in-tests" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "gl_tests_passthrough", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "gl_tests", + "test_id_prefix": "ninja://gpu:gl_tests/" + }, + { + "args": [ + "--use-gpu-in-tests", + "--git-revision=${got_revision}", + "--test-launcher-filter-file=../../testing/buildbot/filters/win.nvidia.gtx.1660.gl_unittests.filter" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "gl_unittests", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gl_unittests", + "test_id_prefix": "ninja://ui/gl:gl_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "gpu_unittests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gpu_unittests", + "test_id_prefix": "ninja://gpu:gpu_unittests/" + }, + { + "args": [ + "--gtest_filter=MediaFoundationEncryptedMediaTest*", + "--use-gpu-in-tests" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "media_foundation_browser_tests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "browser_tests", + "test_id_prefix": "ninja://chrome/test:browser_tests/" + }, + { + "args": [ + "--gtest_filter=WebNN*", + "--use-gpu-in-tests" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "services_webnn_unittests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "services_unittests", + "test_id_prefix": "ninja://services:services_unittests/" + }, + { + "args": [ + "--enable-gpu", + "--test-launcher-bot-mode", + "--test-launcher-jobs=1", + "--gtest_filter=TabCaptureApiPixelTest.EndToEnd*" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "tab_capture_end2end_tests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "browser_tests", + "test_id_prefix": "ninja://chrome/test:browser_tests/" + }, + { + "args": [ + "--ignore-runtime-requirements=*" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "xr_browser_tests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "xr_browser_tests", + "test_id_prefix": "ninja://chrome/test:xr_browser_tests/" + } + ], "isolated_scripts": [ { "args": [ - "noop_sleep", + "context_lost", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "context_lost_passthrough_graphite_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "context_lost", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "context_lost_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "expected_color", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "expected_color_pixel_passthrough_graphite_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "expected_color", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "expected_color_pixel_passthrough_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "gpu_process", "--show-stdout", "--browser=release_x64", "--passthrough", @@ -17,13 +387,17 @@ "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "noop_sleep_tests", + "name": "gpu_process_launch_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, "swarming": { "containment_type": "AUTO", "dimensions": { "display_attached": "1", - "gpu": "10de:2184-31.0.15.4601", - "os": "Windows-10-19045", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -34,6 +408,514 @@ }, "test": "telemetry_gpu_integration_test", "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "hardware_accelerated_feature", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "hardware_accelerated_feature_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "info_collection", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", + "--enforce-browser-version", + "--expected-vendor-id", + "10de", + "--expected-device-id", + "2184", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "info_collection_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "--gtest-benchmark-name=passthrough_command_buffer_perftests", + "-v", + "--use-cmd-decoder=passthrough", + "--use-angle=gl-null", + "--fast-run" + ], + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, + "name": "passthrough_command_buffer_perftests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "command_buffer_perftests", + "test_id_prefix": "ninja://gpu:command_buffer_perftests/" + }, + { + "args": [ + "pixel", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "pixel_skia_gold_passthrough_graphite_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "pixel", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "pixel_skia_gold_passthrough_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "screenshot_sync", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--dont-restore-color-profile-after-test", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "screenshot_sync_passthrough_graphite_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "screenshot_sync", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--dont-restore-color-profile-after-test", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "screenshot_sync_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "trace_test", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--enforce-browser-version", + "--jobs=1" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "trace_test", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webcodecs", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webcodecs_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl2_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=d3d11 --force_high_performance_gpu", + "--enforce-browser-version", + "--webgl-conformance-version=2.0.1", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl2_conformance_d3d11_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 20 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl1_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=d3d11 --force_high_performance_gpu", + "--enforce-browser-version", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl_conformance_d3d11_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl1_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=d3d9 --force_high_performance_gpu", + "--enforce-browser-version", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl_conformance_d3d9_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl1_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=vulkan --force_high_performance_gpu", + "--enforce-browser-version", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl_conformance_vulkan_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" } ] },
diff --git "a/infra/config/generated/builders/ci/Win10 FYI x64 Exp Release \050NVIDIA\051/targets/chromium.gpu.fyi.json" "b/infra/config/generated/builders/ci/Win10 FYI x64 Exp Release \050NVIDIA\051/targets/chromium.gpu.fyi.json" index e7e366a..d812ebe 100644 --- "a/infra/config/generated/builders/ci/Win10 FYI x64 Exp Release \050NVIDIA\051/targets/chromium.gpu.fyi.json" +++ "b/infra/config/generated/builders/ci/Win10 FYI x64 Exp Release \050NVIDIA\051/targets/chromium.gpu.fyi.json"
@@ -1,9 +1,379 @@ { "Win10 FYI x64 Exp Release (NVIDIA)": { + "gtest_tests": [ + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "angle_unittests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "angle_unittests", + "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/", + "use_isolated_scripts_api": true + }, + { + "args": [ + "--use-cmd-decoder=passthrough", + "--use-gl=angle", + "--use-gpu-in-tests" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "gl_tests_passthrough", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "gl_tests", + "test_id_prefix": "ninja://gpu:gl_tests/" + }, + { + "args": [ + "--use-gpu-in-tests", + "--git-revision=${got_revision}", + "--test-launcher-filter-file=../../testing/buildbot/filters/win.nvidia.gtx.1660.gl_unittests.filter" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "gl_unittests", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gl_unittests", + "test_id_prefix": "ninja://ui/gl:gl_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "gpu_unittests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gpu_unittests", + "test_id_prefix": "ninja://gpu:gpu_unittests/" + }, + { + "args": [ + "--gtest_filter=MediaFoundationEncryptedMediaTest*", + "--use-gpu-in-tests" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "media_foundation_browser_tests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "browser_tests", + "test_id_prefix": "ninja://chrome/test:browser_tests/" + }, + { + "args": [ + "--gtest_filter=WebNN*", + "--use-gpu-in-tests" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "services_webnn_unittests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "services_unittests", + "test_id_prefix": "ninja://services:services_unittests/" + }, + { + "args": [ + "--enable-gpu", + "--test-launcher-bot-mode", + "--test-launcher-jobs=1", + "--gtest_filter=TabCaptureApiPixelTest.EndToEnd*" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "tab_capture_end2end_tests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "browser_tests", + "test_id_prefix": "ninja://chrome/test:browser_tests/" + }, + { + "args": [ + "--ignore-runtime-requirements=*" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "xr_browser_tests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "xr_browser_tests", + "test_id_prefix": "ninja://chrome/test:xr_browser_tests/" + } + ], "isolated_scripts": [ { "args": [ - "noop_sleep", + "context_lost", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "context_lost_passthrough_graphite_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "context_lost", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "context_lost_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "expected_color", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "expected_color_pixel_passthrough_graphite_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "expected_color", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "expected_color_pixel_passthrough_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "gpu_process", "--show-stdout", "--browser=release_x64", "--passthrough", @@ -16,13 +386,17 @@ "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "noop_sleep_tests", + "name": "gpu_process_launch_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, "swarming": { "containment_type": "AUTO", "dimensions": { "display_attached": "1", - "gpu": "10de:2184-31.0.15.4601", - "os": "Windows-10-19045", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -33,6 +407,514 @@ }, "test": "telemetry_gpu_integration_test", "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "hardware_accelerated_feature", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "hardware_accelerated_feature_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "info_collection", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", + "--enforce-browser-version", + "--expected-vendor-id", + "10de", + "--expected-device-id", + "2184", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "info_collection_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "--gtest-benchmark-name=passthrough_command_buffer_perftests", + "-v", + "--use-cmd-decoder=passthrough", + "--use-angle=gl-null", + "--fast-run" + ], + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, + "name": "passthrough_command_buffer_perftests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "command_buffer_perftests", + "test_id_prefix": "ninja://gpu:command_buffer_perftests/" + }, + { + "args": [ + "pixel", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "pixel_skia_gold_passthrough_graphite_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "pixel", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "pixel_skia_gold_passthrough_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "screenshot_sync", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--dont-restore-color-profile-after-test", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "screenshot_sync_passthrough_graphite_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "screenshot_sync", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--dont-restore-color-profile-after-test", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "screenshot_sync_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "trace_test", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--enforce-browser-version", + "--jobs=1" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "trace_test", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webcodecs", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webcodecs_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl2_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=d3d11 --force_high_performance_gpu", + "--enforce-browser-version", + "--webgl-conformance-version=2.0.1", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl2_conformance_d3d11_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 20 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl1_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=d3d11 --force_high_performance_gpu", + "--enforce-browser-version", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl_conformance_d3d11_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl1_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=d3d9 --force_high_performance_gpu", + "--enforce-browser-version", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl_conformance_d3d9_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl1_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=vulkan --force_high_performance_gpu", + "--enforce-browser-version", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl_conformance_vulkan_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" } ] }
diff --git a/infra/config/generated/builders/ci/fuchsia-x64-perf-cast-receiver-rel/properties.json b/infra/config/generated/builders/ci/fuchsia-x64-perf-cast-receiver-rel/properties.json index 6121704..91d83d7 100644 --- a/infra/config/generated/builders/ci/fuchsia-x64-perf-cast-receiver-rel/properties.json +++ b/infra/config/generated/builders/ci/fuchsia-x64-perf-cast-receiver-rel/properties.json
@@ -27,6 +27,7 @@ }, "legacy_gclient_config": { "apply_configs": [ + "checkout_pgo_profiles", "fuchsia_x64" ], "config": "chromium"
diff --git a/infra/config/generated/builders/ci/linux-blink-asan-rel/targets/chromium.memory.json b/infra/config/generated/builders/ci/linux-blink-asan-rel/targets/chromium.memory.json index 1140c37..ff85ab7 100644 --- a/infra/config/generated/builders/ci/linux-blink-asan-rel/targets/chromium.memory.json +++ b/infra/config/generated/builders/ci/linux-blink-asan-rel/targets/chromium.memory.json
@@ -61,7 +61,8 @@ }, { "args": [ - "--test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter" + "--test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter", + "-j6" ], "merge": { "args": [
diff --git a/infra/config/generated/builders/try/dawn-try-win-x64-nvidia-exp/targets/chromium.dawn.json b/infra/config/generated/builders/try/dawn-try-win-x64-nvidia-exp/targets/chromium.dawn.json index 81f0273..e8ad0bc9 100644 --- a/infra/config/generated/builders/try/dawn-try-win-x64-nvidia-exp/targets/chromium.dawn.json +++ b/infra/config/generated/builders/try/dawn-try-win-x64-nvidia-exp/targets/chromium.dawn.json
@@ -21,8 +21,8 @@ "swarming": { "dimensions": { "display_attached": "1", - "gpu": "10de:2184-31.0.15.4601", - "os": "Windows-10-19045", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", "pool": "chromium.tests.gpu" }, "expiration": 21600,
diff --git a/infra/config/generated/builders/try/dawn-try-win-x86-nvidia-exp/targets/chromium.dawn.json b/infra/config/generated/builders/try/dawn-try-win-x86-nvidia-exp/targets/chromium.dawn.json index 0279679..e4dbbe9 100644 --- a/infra/config/generated/builders/try/dawn-try-win-x86-nvidia-exp/targets/chromium.dawn.json +++ b/infra/config/generated/builders/try/dawn-try-win-x86-nvidia-exp/targets/chromium.dawn.json
@@ -21,8 +21,8 @@ "swarming": { "dimensions": { "display_attached": "1", - "gpu": "10de:2184-31.0.15.4601", - "os": "Windows-10-19045", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", "pool": "chromium.tests.gpu" }, "expiration": 21600,
diff --git a/infra/config/generated/builders/try/fuchsia-x64-perf-cast-receiver-rel/properties.json b/infra/config/generated/builders/try/fuchsia-x64-perf-cast-receiver-rel/properties.json index e642ae1..bbe0f00c 100644 --- a/infra/config/generated/builders/try/fuchsia-x64-perf-cast-receiver-rel/properties.json +++ b/infra/config/generated/builders/try/fuchsia-x64-perf-cast-receiver-rel/properties.json
@@ -27,6 +27,7 @@ }, "legacy_gclient_config": { "apply_configs": [ + "checkout_pgo_profiles", "fuchsia_x64" ], "config": "chromium"
diff --git a/infra/config/generated/builders/try/gpu-fyi-try-win10-nvidia-exp-64/targets/chromium.gpu.fyi.json b/infra/config/generated/builders/try/gpu-fyi-try-win10-nvidia-exp-64/targets/chromium.gpu.fyi.json index fff5eca..2778b654 100644 --- a/infra/config/generated/builders/try/gpu-fyi-try-win10-nvidia-exp-64/targets/chromium.gpu.fyi.json +++ b/infra/config/generated/builders/try/gpu-fyi-try-win10-nvidia-exp-64/targets/chromium.gpu.fyi.json
@@ -1,10 +1,380 @@ { "GPU FYI Win x64 Builder": {}, "Win10 FYI x64 Exp Release (NVIDIA)": { + "gtest_tests": [ + { + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "angle_unittests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "angle_unittests", + "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/", + "use_isolated_scripts_api": true + }, + { + "args": [ + "--use-cmd-decoder=passthrough", + "--use-gl=angle", + "--use-gpu-in-tests" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "gl_tests_passthrough", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "gl_tests", + "test_id_prefix": "ninja://gpu:gl_tests/" + }, + { + "args": [ + "--use-gpu-in-tests", + "--git-revision=${got_revision}", + "--test-launcher-filter-file=../../testing/buildbot/filters/win.nvidia.gtx.1660.gl_unittests.filter" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "gl_unittests", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gl_unittests", + "test_id_prefix": "ninja://ui/gl:gl_unittests/" + }, + { + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "gpu_unittests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gpu_unittests", + "test_id_prefix": "ninja://gpu:gpu_unittests/" + }, + { + "args": [ + "--gtest_filter=MediaFoundationEncryptedMediaTest*", + "--use-gpu-in-tests" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "media_foundation_browser_tests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "browser_tests", + "test_id_prefix": "ninja://chrome/test:browser_tests/" + }, + { + "args": [ + "--gtest_filter=WebNN*", + "--use-gpu-in-tests" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "services_webnn_unittests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "services_unittests", + "test_id_prefix": "ninja://services:services_unittests/" + }, + { + "args": [ + "--enable-gpu", + "--test-launcher-bot-mode", + "--test-launcher-jobs=1", + "--gtest_filter=TabCaptureApiPixelTest.EndToEnd*" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "tab_capture_end2end_tests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "browser_tests", + "test_id_prefix": "ninja://chrome/test:browser_tests/" + }, + { + "args": [ + "--ignore-runtime-requirements=*" + ], + "merge": { + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "xr_browser_tests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "xr_browser_tests", + "test_id_prefix": "ninja://chrome/test:xr_browser_tests/" + } + ], "isolated_scripts": [ { "args": [ - "noop_sleep", + "context_lost", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "context_lost_passthrough_graphite_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "context_lost", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "context_lost_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "expected_color", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "expected_color_pixel_passthrough_graphite_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "expected_color", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "expected_color_pixel_passthrough_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "gpu_process", "--show-stdout", "--browser=release_x64", "--passthrough", @@ -17,13 +387,17 @@ "merge": { "script": "//testing/merge_scripts/standard_isolated_script_merge.py" }, - "name": "noop_sleep_tests", + "name": "gpu_process_launch_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, "swarming": { "containment_type": "AUTO", "dimensions": { "display_attached": "1", - "gpu": "10de:2184-31.0.15.4601", - "os": "Windows-10-19045", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -34,6 +408,514 @@ }, "test": "telemetry_gpu_integration_test", "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "hardware_accelerated_feature", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "hardware_accelerated_feature_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "info_collection", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", + "--enforce-browser-version", + "--expected-vendor-id", + "10de", + "--expected-device-id", + "2184", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "info_collection_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "--gtest-benchmark-name=passthrough_command_buffer_perftests", + "-v", + "--use-cmd-decoder=passthrough", + "--use-angle=gl-null", + "--fast-run" + ], + "merge": { + "args": [ + "--smoke-test-mode" + ], + "script": "//tools/perf/process_perf_results.py" + }, + "name": "passthrough_command_buffer_perftests", + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "command_buffer_perftests", + "test_id_prefix": "ninja://gpu:command_buffer_perftests/" + }, + { + "args": [ + "pixel", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "pixel_skia_gold_passthrough_graphite_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "pixel", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--git-revision=${got_revision}", + "--dont-restore-color-profile-after-test", + "--test-machine-name", + "${buildername}", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "pixel_skia_gold_passthrough_test", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "screenshot_sync", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --enable-features=SkiaGraphite", + "--enforce-browser-version", + "--dont-restore-color-profile-after-test", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "screenshot_sync_passthrough_graphite_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "screenshot_sync", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle", + "--enforce-browser-version", + "--dont-restore-color-profile-after-test", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "screenshot_sync_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "trace_test", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--enforce-browser-version", + "--jobs=1" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "trace_test", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webcodecs", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--enforce-browser-version", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webcodecs_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl2_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=d3d11 --force_high_performance_gpu", + "--enforce-browser-version", + "--webgl-conformance-version=2.0.1", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl2_conformance_d3d11_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 20 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl1_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=d3d11 --force_high_performance_gpu", + "--enforce-browser-version", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl_conformance_d3d11_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl1_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=d3d9 --force_high_performance_gpu", + "--enforce-browser-version", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl_conformance_d3d9_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgl1_conformance", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=vulkan --force_high_performance_gpu", + "--enforce-browser-version", + "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_win_runtimes.json", + "--jobs=4" + ], + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "webgl_conformance_vulkan_passthrough_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "containment_type": "AUTO", + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", + "pool": "chromium.tests.gpu" + }, + "expiration": 21600, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" } ] }
diff --git a/infra/config/generated/builders/try/linux-blink-asan-rel/targets/chromium.memory.json b/infra/config/generated/builders/try/linux-blink-asan-rel/targets/chromium.memory.json index 1140c37..ff85ab7 100644 --- a/infra/config/generated/builders/try/linux-blink-asan-rel/targets/chromium.memory.json +++ b/infra/config/generated/builders/try/linux-blink-asan-rel/targets/chromium.memory.json
@@ -61,7 +61,8 @@ }, { "args": [ - "--test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter" + "--test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter", + "-j6" ], "merge": { "args": [
diff --git a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/gn-args.json b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/gn-args.json index 9b1f1e5..b315f28 100644 --- a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/gn-args.json +++ b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/gn-args.json
@@ -6,7 +6,7 @@ "is_component_build": false, "is_debug": false, "is_lsan": true, - "symbol_level": 1, + "symbol_level": 0, "target_cpu": "x64", "target_os": "linux", "use_reclient": false,
diff --git a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/gn-args.json b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/gn-args.json index b4e11861..b9c48870 100644 --- a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/gn-args.json +++ b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/gn-args.json
@@ -5,7 +5,7 @@ "is_component_build": false, "is_debug": false, "is_tsan": true, - "symbol_level": 1, + "symbol_level": 0, "target_cpu": "x64", "target_os": "linux", "use_reclient": false,
diff --git a/infra/config/generated/builders/try/mac15-arm64-rel/gn-args.json b/infra/config/generated/builders/try/mac15-arm64-rel/gn-args.json index cff2012d..4f54d2b 100644 --- a/infra/config/generated/builders/try/mac15-arm64-rel/gn-args.json +++ b/infra/config/generated/builders/try/mac15-arm64-rel/gn-args.json
@@ -8,7 +8,7 @@ "symbol_level": 0, "target_cpu": "arm64", "target_os": "mac", - "use_reclient": true, + "use_reclient": false, "use_remoteexec": true, "use_siso": true }
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index 0b1bb08..b0893d88 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -16459,6 +16459,11 @@ short_name: "dbg" } builders { + name: "buildbucket/luci.chromium.ci/Win10 FYI x64 Exp Release (NVIDIA)" + category: "chromium.gpu.fyi|Windows|10|x64|Nvidia" + short_name: "exp" + } + builders { name: "buildbucket/luci.chromium.ci/Win10 FYI x64 Release (NVIDIA)" category: "chromium.gpu.fyi|Windows|10|x64|Nvidia" short_name: "rel" @@ -17472,6 +17477,11 @@ short_name: "dbg" } builders { + name: "buildbucket/luci.chromium.ci/Win10 FYI x64 Exp Release (NVIDIA)" + category: "Windows|10|x64|Nvidia" + short_name: "exp" + } + builders { name: "buildbucket/luci.chromium.ci/Win10 FYI x64 Release XR Perf (NVIDIA)" category: "Windows|10|x64|Nvidia" short_name: "xr"
diff --git a/infra/config/generated/testing/mixins.pyl b/infra/config/generated/testing/mixins.pyl index dd9fc79..159ef3a 100644 --- a/infra/config/generated/testing/mixins.pyl +++ b/infra/config/generated/testing/mixins.pyl
@@ -261,6 +261,7 @@ ], 'android_args': [ '$$MAGIC_SUBSTITUTION_GPUTelemetryNoRootForUnrootedDevices', + '$$MAGIC_SUBSTITUTION_AndroidDesktopTelemetryRemote', '--initial-find-device-attempts=3', ], 'chromeos_args': [ @@ -866,8 +867,8 @@ 'swarming': { 'dimensions': { 'display_attached': '1', - 'gpu': '10de:2184-31.0.15.4601', - 'os': 'Windows-10-19045', + 'gpu': '10de:2184-32.0.15.7602', + 'os': 'Windows-11-26100', 'pool': 'chromium.tests.gpu', }, },
diff --git a/infra/config/lib/targets-internal/magic_args.star b/infra/config/lib/targets-internal/magic_args.star index cdfaedc..ed99878 100644 --- a/infra/config/lib/targets-internal/magic_args.star +++ b/infra/config/lib/targets-internal/magic_args.star
@@ -33,6 +33,10 @@ # LINT.IfChange +_ANDROID_DESKTOP_BOARD_GPUS = { + "brya": _gpu_device(vendor = "8086", device = "46a8"), +} + _CROS_BOARD_GPUS = { "volteer": _gpu_device(vendor = "8086", device = "9a49"), } @@ -68,11 +72,21 @@ fail("dimensions is not set") return dimensions +def _is_android_desktop(spec_value, settings): + """Helper function to determine if the test will be running on Android Desktop.""" + is_android = settings.os_type == common.os_type.ANDROID + return is_android and _get_android_desktop_board_name(spec_value) + def _is_skylab(settings): """Helper function to determine if the test will be running on skylab.""" return (settings.browser_config == common.browser_config.CROS_CHROME and not settings.use_swarming) +def _get_android_desktop_board_name(spec_value): + """Helper function to determine what Android Desktop board is being used.""" + dimensions = _get_dimensions(spec_value) + return dimensions.get("label-board") + def _get_cros_board_name(spec_value): """Helper function to determine what ChromeOS board is being used.""" dimensions = _get_dimensions(spec_value) @@ -85,6 +99,17 @@ return dimensions.get("device_type", "amd64-generic") +def _android_desktop_telemetry_remote(_, settings, spec_value): + """Substitutes the correct Android Desktop remote Telemetry arguments.""" + if settings.os_type != common.os_type.ANDROID: + fail("Ran an Android Desktop-specific substitution on a non-Android builder") + if not _get_android_desktop_board_name(spec_value): + return [] + return [ + "--device=variable_lab_dut_hostname", + "--connect-to-device-over-network", + ] + def _cros_telemetry_remote(_, settings, spec_value): """Substitutes the correct CrOS remote Telemetry arguments. @@ -149,6 +174,8 @@ We only ever trigger tests on a single vendor type per builder definition, so multiple found vendors is an error. """ + if _is_android_desktop(spec_value, settings): + return _gpu_expected_vendor_id_android_desktop(spec_value) if _is_skylab(settings): return _gpu_expected_vendor_id_skylab(spec_value) gpus = _get_gpus(spec_value) @@ -174,6 +201,14 @@ return ["--expected-vendor-id", vendor_ids.pop()] +def _gpu_expected_vendor_id_android_desktop(spec_value): + board = _get_android_desktop_board_name(spec_value) + if not board: + fail("Failed to get board for Android Desktop test") + gpu_device = _ANDROID_DESKTOP_BOARD_GPUS.get(board) + vendor_id = gpu_device.vendor if gpu_device else "0" + return ["--expected-vendor-id", vendor_id] + def _gpu_expected_vendor_id_skylab(spec_value): cros_board = spec_value.get("cros_board") if cros_board == None: @@ -188,6 +223,8 @@ Most configurations only need one expected GPU, but heterogeneous pools (e.g. HD 630 and UHD 630 machines) require multiple. """ + if _is_android_desktop(spec_value, settings): + return _gpu_expected_device_id_android_desktop(spec_value) if _is_skylab(settings): return _gpu_expected_device_id_skylab(spec_value) gpus = _get_gpus(spec_value) @@ -217,6 +254,14 @@ retval.extend(["--expected-device-id", device_id]) return retval +def _gpu_expected_device_id_android_desktop(spec_value): + board = _get_android_desktop_board_name(spec_value) + if not board: + fail("Failed to get board for Android Desktop test") + gpu_device = _ANDROID_DESKTOP_BOARD_GPUS.get(board) + device_id = gpu_device.device if gpu_device else "0" + return ["--expected-device-id", device_id] + def _gpu_expected_device_id_skylab(spec_value): cros_board = spec_value.get("cros_board") if cros_board == None: @@ -372,6 +417,10 @@ ) magic_args = struct( + ANDROID_DESKTOP_TELEMETRY_REMOTE = _placeholder( + pyl_arg_value = "$$MAGIC_SUBSTITUTION_AndroidDesktopTelemetryRemote", + function = _android_desktop_telemetry_remote, + ), CROS_TELEMETRY_REMOTE = _placeholder( pyl_arg_value = "$$MAGIC_SUBSTITUTION_ChromeOSTelemetryRemote", function = _cros_telemetry_remote,
diff --git a/infra/config/migration/values.py b/infra/config/migration/values.py index 86baaf0..db37367 100644 --- a/infra/config/migration/values.py +++ b/infra/config/migration/values.py
@@ -77,6 +77,8 @@ _MAGIC_ARG_MAPPING = { + '$$MAGIC_SUBSTITUTION_AndroidDesktopTelemetryRemote': + 'ANDROID_DESKTOP_TELEMETRY_REMOTE', '$$MAGIC_SUBSTITUTION_ChromeOSTelemetryRemote': 'CROS_TELEMETRY_REMOTE', '$$MAGIC_SUBSTITUTION_ChromeOSGtestFilterFile': 'CROS_GTEST_FILTER_FILE', '$$MAGIC_SUBSTITUTION_GPUExpectedVendorId': 'GPU_EXPECTED_VENDOR_ID',
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star index f8b5b39..3b3127f5 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star
@@ -414,6 +414,7 @@ gclient_config = builder_config.gclient_config( config = "chromium", apply_configs = [ + "checkout_pgo_profiles", "fuchsia_x64", ], ),
diff --git a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star index f4df5b1..ba738b8 100644 --- a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star
@@ -2769,22 +2769,31 @@ # should be running the same test_suites as # 'Win10 FYI x64 Release (NVIDIA)' targets = [ - "gpu_noop_sleep_telemetry_test", + "gpu_fyi_win_gtests", + "gpu_fyi_win_release_telemetry_tests", + "gpu_fyi_win_optional_isolated_scripts", ], mixins = [ "limited_capacity_bot", "win10_nvidia_gtx_1660_experimental", ], + per_test_modifications = { + "gl_unittests": targets.mixin( + args = [ + "--test-launcher-filter-file=../../testing/buildbot/filters/win.nvidia.gtx.1660.gl_unittests.filter", + ], + ), + }, ), targets_settings = targets.settings( browser_config = targets.browser_config.RELEASE_X64, os_type = targets.os_type.WINDOWS, ), # Uncomment this entry when this experimental tester is actually in use. - # console_view_entry = consoles.console_view_entry( - # category = "Windows|10|x64|Nvidia", - # short_name = "exp", - # ), + console_view_entry = consoles.console_view_entry( + category = "Windows|10|x64|Nvidia", + short_name = "exp", + ), list_view = "chromium.gpu.experimental", )
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.star b/infra/config/subprojects/chromium/ci/chromium.memory.star index 1a5337f..45e8dc4 100644 --- a/infra/config/subprojects/chromium/ci/chromium.memory.star +++ b/infra/config/subprojects/chromium/ci/chromium.memory.star
@@ -1102,6 +1102,11 @@ "linux-jammy", ], per_test_modifications = { + "chrome_wpt_tests": targets.mixin( + args = [ + "-j6", + ], + ), "blink_web_tests": targets.mixin( args = [ "--timeout-ms",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star index f3e77aa0..f70002d 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -698,7 +698,14 @@ "ci/Linux ASan LSan Builder", "ci/Linux ASan LSan Tests (1)", ], - gn_args = "ci/Linux ASan LSan Builder", + gn_args = gn_args.config( + configs = [ + "ci/Linux ASan LSan Builder", + # TODO(crbug.com/416191043): Restore symbol_level=1 if/when CAS + # errors are fixed. + "no_symbols", + ], + ), compilator = "linux_chromium_asan_rel_ng-compilator", experiments = { # go/nplus1shardsproposal @@ -935,7 +942,9 @@ configs = [ "ci/Linux TSan Builder", "release_try_builder", - "minimal_symbols", + # TODO(crbug.com/416191043): Restore symbol_level=1 if/when CAS + # errors are fixed. + "no_symbols", ], ), compilator = "linux_chromium_tsan_rel_ng-compilator",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star index 89f4608e..49e011c8 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
@@ -361,7 +361,6 @@ "arm64", "gpu_tests", "release_try_builder", - "reclient", "remoteexec", "no_symbols", "mac",
diff --git a/infra/config/targets/mixins.star b/infra/config/targets/mixins.star index a2859e8..65c3539 100644 --- a/infra/config/targets/mixins.star +++ b/infra/config/targets/mixins.star
@@ -822,6 +822,7 @@ ], android_args = [ targets.magic_args.GPU_TELEMETRY_NO_ROOT_FOR_UNROOTED_DEVICES, + targets.magic_args.ANDROID_DESKTOP_TELEMETRY_REMOTE, # See crbug.com/333414298 for context on why this is necessary. "--initial-find-device-attempts=3", ], @@ -2389,8 +2390,8 @@ swarming = targets.swarming( dimensions = { "display_attached": "1", - "gpu": "10de:2184-31.0.15.4601", - "os": "Windows-10-19045", + "gpu": "10de:2184-32.0.15.7602", + "os": "Windows-11-26100", "pool": "chromium.tests.gpu", }, ),
diff --git a/internal b/internal index 20b9f62..ce971f9 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit 20b9f62811d76f8f5de0eba491b161f8bb948c6e +Subproject commit ce971f9a7bc61262bdef47fe1bee00420f0bbfc0
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 677e1246..320250e 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -2437,6 +2437,12 @@ <message name="IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_SECOND_STEP" desc="Text of the row indicating the second step of setting the default browser [iOS only]"> Tap <ph name="BEGIN_BOLD">BEGIN_BOLD</ph>Default Browser App<ph name="END_BOLD">END_BOLD</ph> </message> + <message name="IDS_IOS_FIRST_RUN_GUIDED_TOUR_NTP_IPH_TEXT" desc="Text of the Guided Tour IPH for the NTP step focusing on the tab grid." meaning="Title-cased"> + Your open tabs and groups + </message> + <message name="IDS_IOS_FIRST_RUN_GUIDED_TOUR_NTP_IPH_TITLE" desc="Title of the Guided Tour IPH for the NTP step focusing on the tab grid." meaning="Title-cased"> + See and manage everything you have open + </message> <message name="IDS_IOS_FIRST_RUN_GUIDED_TOUR_PROMPT_BUTTON_TITLE" desc="Title of the button for the user to start the First Run Guided Tour." meaning="Title-cased"> Show me around </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_FIRST_RUN_GUIDED_TOUR_NTP_IPH_TEXT.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_FIRST_RUN_GUIDED_TOUR_NTP_IPH_TEXT.png.sha1 new file mode 100644 index 0000000..874b81b --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_FIRST_RUN_GUIDED_TOUR_NTP_IPH_TEXT.png.sha1
@@ -0,0 +1 @@ +8772d463239cc54530d8fa3c7109cd39991ee5b8 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_FIRST_RUN_GUIDED_TOUR_NTP_IPH_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_FIRST_RUN_GUIDED_TOUR_NTP_IPH_TITLE.png.sha1 new file mode 100644 index 0000000..874b81b --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_FIRST_RUN_GUIDED_TOUR_NTP_IPH_TITLE.png.sha1
@@ -0,0 +1 @@ +8772d463239cc54530d8fa3c7109cd39991ee5b8 \ No newline at end of file
diff --git a/ios/chrome/browser/authentication/ui_bundled/change_profile/BUILD.gn b/ios/chrome/browser/authentication/ui_bundled/change_profile/BUILD.gn index 7d299c3b..dc06cc1 100644 --- a/ios/chrome/browser/authentication/ui_bundled/change_profile/BUILD.gn +++ b/ios/chrome/browser/authentication/ui_bundled/change_profile/BUILD.gn
@@ -34,8 +34,6 @@ "change_profile_signout_continuation.mm", "change_profile_voice_search_continuation.h", "change_profile_voice_search_continuation.mm", - "sync_history_continuation.h", - "sync_history_continuation.mm", ] deps = [
diff --git a/ios/chrome/browser/authentication/ui_bundled/change_profile/sync_history_continuation.h b/ios/chrome/browser/authentication/ui_bundled/change_profile/sync_history_continuation.h deleted file mode 100644 index 40b2711..0000000 --- a/ios/chrome/browser/authentication/ui_bundled/change_profile/sync_history_continuation.h +++ /dev/null
@@ -1,19 +0,0 @@ -// 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 IOS_CHROME_BROWSER_AUTHENTICATION_UI_BUNDLED_CHANGE_PROFILE_SYNC_HISTORY_CONTINUATION_H_ -#define IOS_CHROME_BROWSER_AUTHENTICATION_UI_BUNDLED_CHANGE_PROFILE_SYNC_HISTORY_CONTINUATION_H_ - -#import "components/signin/public/base/signin_metrics.h" -#import "ios/chrome/app/change_profile_continuation.h" - -// Returns a ChangeProfileSyncHistoryContinuation that opens the history sync -// opt-in view. Accepts the 'accessPoint' and `optionalHistorySync` (even if it -// is NO, history sync ui might still be skipped if the user previously approved -// it). -ChangeProfileContinuation CreateChangeProfileSyncHistoryContinuation( - signin_metrics::AccessPoint accessPoint, - BOOL optionalHistorySync); - -#endif // IOS_CHROME_BROWSER_AUTHENTICATION_UI_BUNDLED_CHANGE_PROFILE_SYNC_HISTORY_CONTINUATION_H_
diff --git a/ios/chrome/browser/authentication/ui_bundled/change_profile/sync_history_continuation.mm b/ios/chrome/browser/authentication/ui_bundled/change_profile/sync_history_continuation.mm deleted file mode 100644 index df0aa4f..0000000 --- a/ios/chrome/browser/authentication/ui_bundled/change_profile/sync_history_continuation.mm +++ /dev/null
@@ -1,63 +0,0 @@ -// 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. - -#import "ios/chrome/browser/authentication/ui_bundled/change_profile/sync_history_continuation.h" - -#import "base/functional/callback_helpers.h" -#import "components/signin/public/base/consent_level.h" -#import "components/signin/public/identity_manager/identity_manager.h" -#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h" -#import "ios/chrome/browser/shared/model/browser/browser.h" -#import "ios/chrome/browser/shared/model/browser/browser_provider.h" -#import "ios/chrome/browser/shared/model/browser/browser_provider_interface.h" -#import "ios/chrome/browser/shared/public/commands/application_commands.h" -#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" -#import "ios/chrome/browser/shared/public/commands/show_signin_command.h" -#import "ios/chrome/browser/signin/model/identity_manager_factory.h" - -namespace { - -// Implementation of the continuation opening the history opt-in view. -void ChangeProfileSyncHistoryContinuation( - signin_metrics::AccessPoint accessPoint, - BOOL optionalHistorySync, - SceneState* scene_state, - base::OnceClosure closure) { - Browser* browser = - scene_state.browserProviderInterface.currentBrowserProvider.browser; - CHECK(browser); - - // Check that there is a signed in account. - signin::IdentityManager* identity_manager = - IdentityManagerFactory::GetForProfile(browser->GetProfile()); - CHECK(identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin)); - - CommandDispatcher* dispatcher = browser->GetCommandDispatcher(); - id<ApplicationCommands> applicationHandler = - HandlerForProtocol(dispatcher, ApplicationCommands); - - // kHistorySync triggers the history sync opt-in. The user must be already - // signed in. - ShowSigninCommand* command = [[ShowSigninCommand alloc] - initWithOperation:AuthenticationOperation::kHistorySync - identity:nil - accessPoint:accessPoint - promoAction:signin_metrics::PromoAction:: - PROMO_ACTION_NO_SIGNIN_PROMO - completion:nil]; - command.optionalHistorySync = optionalHistorySync; - - [applicationHandler showSignin:command baseViewController:nil]; - - std::move(closure).Run(); -} - -} // namespace - -ChangeProfileContinuation CreateChangeProfileSyncHistoryContinuation( - signin_metrics::AccessPoint accessPoint, - BOOL optionalHistorySync) { - return base::BindOnce(&ChangeProfileSyncHistoryContinuation, accessPoint, - optionalHistorySync); -}
diff --git a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_egtest.mm b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_egtest.mm index 30b27c03..9bce380 100644 --- a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_egtest.mm +++ b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_input_accessory_egtest.mm
@@ -120,6 +120,23 @@ } } +// Matcher for the name suggestion chip. +id<GREYMatcher> KeyboardAccessoryNameSuggestion() { + autofill::AutofillProfile profile = autofill::test::GetFullProfile(); + NSString* name = + base::SysUTF16ToNSString(profile.GetRawInfo(autofill::NAME_FULL)); + if ([AutofillAppInterface isKeyboardAccessoryUpgradeEnabled] && + [ChromeEarlGrey isIPadIdiom]) { + // On iPad, the suggestion text is an attributed string containing the state + // on the 2nd line. + NSString* state = base::SysUTF16ToNSString( + profile.GetRawInfo(autofill::ADDRESS_HOME_STATE)); + return grey_text([NSString stringWithFormat:@"%@\n%@", name, state]); + } else { + return grey_text(name); + } +} + // Verifies that the number of accepted address suggestions recorded for the // given `suggestion_index` is as expected. void CheckAddressAutofillSuggestionAcceptedIndexMetricsCount( @@ -262,6 +279,12 @@ config.iph_feature_enabled = feature_engagement::kIPHAutofillHomeWorkProfileSuggestionFeature.name; } + + if ([self isRunningTest:@selector(testReFillAddressFieldsOnForm)]) { + config.features_enabled.push_back(kAutofillRefillForFormsIos); + config.features_enabled.push_back( + autofill::features::kAutofillAcrossIframesIos); + } return config; } @@ -323,6 +346,13 @@ [ChromeEarlGrey waitForWebStateContainingText:"Profile Autofill"]; } +// Loads simple address page with refill on localhost. +- (void)loadRefillAddressPage { + [ChromeEarlGrey + loadURL:self.testServer->GetURL("/autofill_refill_test.html")]; + [ChromeEarlGrey waitForWebStateContainingText:"Refill Profile Autofill"]; +} + // Verifies that html field with the `id_attr` attribute has been filled with // `value`. - (void)verifyFieldWithIdHasBeenFilled:(std::string)id_attr @@ -776,6 +806,26 @@ /*suggestion_index=*/0); } +// Tests that tapping on a name field of a dinamically expanding address form +// and accepting the keyboard accessory suggestion automatically autofills the +// whole address. +- (void)testReFillAddressFieldsOnForm { + [self loadRefillAddressPage]; + + [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + performAction:chrome_test_util::TapWebElementWithId(kFormName)]; + + id<GREYMatcher> name_chip = KeyboardAccessoryNameSuggestion(); + + [ChromeEarlGrey waitForUIElementToAppearWithMatcher:name_chip]; + + // Autofill the name field to uncover the rest of the address form. + [[EarlGrey selectElementWithMatcher:name_chip] performAction:grey_tap()]; + + // Verify that the whole address was filled properly. + [self verifyAddressInfosHaveBeenFilled:autofill::test::GetFullProfile()]; +} + // Tests the IPH feature for a Home and Work account profile. - (void)testAddressHomeAndWorkIPH { // Delete the profile that is added on `-setUp`.
diff --git a/ios/chrome/browser/bubble/ui_bundled/BUILD.gn b/ios/chrome/browser/bubble/ui_bundled/BUILD.gn index 3505ec1..db60a73 100644 --- a/ios/chrome/browser/bubble/ui_bundled/BUILD.gn +++ b/ios/chrome/browser/bubble/ui_bundled/BUILD.gn
@@ -9,6 +9,7 @@ "bubble_presenter_coordinator.h", "bubble_presenter_coordinator.mm", "bubble_presenter_delegate.h", + "bubble_view_controller_presenter+Subclassing.h", "bubble_view_controller_presenter+Testing.h", "bubble_view_controller_presenter.h", "bubble_view_controller_presenter.mm", @@ -85,6 +86,7 @@ "//ios/chrome/browser/shared/ui/util", "//ios/chrome/common:timing", "//ios/chrome/common/ui/colors", + "//ios/chrome/common/ui/util", "//ios/third_party/material_components_ios", "//ui/base", ]
diff --git a/ios/chrome/browser/bubble/ui_bundled/bubble_view_controller_presenter+Subclassing.h b/ios/chrome/browser/bubble/ui_bundled/bubble_view_controller_presenter+Subclassing.h new file mode 100644 index 0000000..b673619 --- /dev/null +++ b/ios/chrome/browser/bubble/ui_bundled/bubble_view_controller_presenter+Subclassing.h
@@ -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. + +#ifndef IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_BUBBLE_VIEW_CONTROLLER_PRESENTER_SUBCLASSING_H_ +#define IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_BUBBLE_VIEW_CONTROLLER_PRESENTER_SUBCLASSING_H_ + +#import "ios/chrome/browser/bubble/ui_bundled/bubble_view_controller_presenter.h" + +// Exposes shared functionality for BubbleViewControllerPresenter subclasses. +@interface BubbleViewControllerPresenter (Subclassing) + +// ViewController this presenter manages. +@property(nonatomic, strong, readonly) + BubbleViewController* bubbleViewController; + +// Parent View of `bubbleViewController`. +@property(nonatomic, strong, readonly) UIView* parentView; + +// The frame to which the BubbleView is anchored. +@property(nonatomic, assign, readonly) CGRect anchorViewFrame; + +// Whether the BubbleView is being presented. +@property(nonatomic, assign) BOOL presenting; + +// The block invoked when the bubble is dismissed. +@property(nonatomic, strong) + CallbackWithIPHDismissalReasonType dismissalCallback; + +// Calculates the frame of the BubbleView. `rect` is the frame of the bubble's +// superview. `anchorPoint` is the anchor point of the bubble. `anchorPoint` +// and `rect` must be in the same coordinates. +- (CGRect)frameForBubbleInRect:(CGRect)rect atAnchorPoint:(CGPoint)anchorPoint; + +// Configures the BubbleViewController in the context of an `anchorPoint` and +// (optional)`anchorViewFrame` position in the context of the +// `parentViewController`. +- (void)configureInParentViewController:(UIViewController*)parentViewController + anchorPoint:(CGPoint)anchorPoint + anchorViewFrame:(CGRect)anchorViewFrame; + +// Registers VoiceOver announcement for the BubbleView. +- (void)registerVoiceOverAnnouncement; + +@end + +#endif // IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_BUBBLE_VIEW_CONTROLLER_PRESENTER_SUBCLASSING_H_
diff --git a/ios/chrome/browser/bubble/ui_bundled/bubble_view_controller_presenter.mm b/ios/chrome/browser/bubble/ui_bundled/bubble_view_controller_presenter.mm index bc65ca1..246fba4 100644 --- a/ios/chrome/browser/bubble/ui_bundled/bubble_view_controller_presenter.mm +++ b/ios/chrome/browser/bubble/ui_bundled/bubble_view_controller_presenter.mm
@@ -76,7 +76,7 @@ // The type of the bubble view's content. @property(nonatomic, assign, readonly) BubbleViewType bubbleType; // Whether the bubble view controller is presented or dismissed. -@property(nonatomic, assign, getter=isPresenting) BOOL presenting; +@property(nonatomic, assign) BOOL presenting; // The block invoked when the bubble is dismissed (both via timer and via tap). // Is optional. @property(nonatomic, strong) @@ -163,6 +163,24 @@ - (void)presentInViewController:(UIViewController*)parentViewController anchorPoint:(CGPoint)anchorPoint anchorViewFrame:(CGRect)anchorViewFrame { + [self configureInParentViewController:parentViewController + anchorPoint:anchorPoint + anchorViewFrame:anchorViewFrame]; + [self addGestureRecognizersToParentView:self.parentView]; + + [parentViewController addChildViewController:self.bubbleViewController]; + [self.parentView addSubview:self.bubbleViewController.view]; + [self.bubbleViewController + didMoveToParentViewController:parentViewController]; + [self.bubbleViewController animateContentIn]; + + [self setUpDismissalTimer]; + [self registerVoiceOverAnnouncement]; +} + +- (void)configureInParentViewController:(UIViewController*)parentViewController + anchorPoint:(CGPoint)anchorPoint + anchorViewFrame:(CGRect)anchorViewFrame { self.parentView = parentViewController.view; _anchorViewFrame = anchorViewFrame; CGPoint anchorPointInParent = @@ -173,38 +191,10 @@ // The bubble's frame must be set. Call `canPresentInView` to make sure that // the frame can be set before calling `presentInViewController`. DCHECK(!CGRectIsEmpty(self.bubbleViewController.view.frame)); - - [self addGestureRecognizersToParentView:self.parentView]; - self.presenting = YES; - [parentViewController addChildViewController:self.bubbleViewController]; - [self.parentView addSubview:self.bubbleViewController.view]; - [self.bubbleViewController - didMoveToParentViewController:parentViewController]; - [self.bubbleViewController animateContentIn]; +} - self.bubbleDismissalTimer = [NSTimer - scheduledTimerWithTimeInterval:[self bubbleVisibilityDuration] - target:self - selector:@selector(bubbleDismissalTimerFired:) - userInfo:nil - repeats:NO]; - - self.userEngaged = YES; - self.triggerFollowUpAction = YES; - self.engagementTimer = - [NSTimer scheduledTimerWithTimeInterval:kBubbleEngagementDuration - target:self - selector:@selector(engagementTimerFired:) - userInfo:nil - repeats:NO]; - - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(onKeyboardHide:) - name:UIKeyboardWillHideNotification - object:nil]; - +- (void)registerVoiceOverAnnouncement { if (self.voiceOverAnnouncement) { if (self.bubbleShouldAutoDismissUnderAccessibility) { // The VoiceOverAnnouncement should be dispatched after a delay to account @@ -343,6 +333,33 @@ #pragma mark - Private +// Set up a timer that dismisses the bubble view. +- (void)setUpDismissalTimer { + self.bubbleDismissalTimer = [NSTimer + scheduledTimerWithTimeInterval:[self bubbleVisibilityDuration] + target:self + selector:@selector(bubbleDismissalTimerFired:) + userInfo:nil + repeats:NO]; + + self.userEngaged = YES; + self.triggerFollowUpAction = YES; + self.engagementTimer = + [NSTimer scheduledTimerWithTimeInterval:kBubbleEngagementDuration + target:self + selector:@selector(engagementTimerFired:) + userInfo:nil + repeats:NO]; + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(onKeyboardHide:) + name:UIKeyboardWillHideNotification + object:nil]; +} + +// Returns the time the bubble view should be shown before being automatically +// dismissed. - (NSTimeInterval)bubbleVisibilityDuration { return _customBubbleVisibilityDuration > 0 ? _customBubbleVisibilityDuration : kBubbleVisibilityDuration;
diff --git a/ios/chrome/browser/bubble/ui_bundled/guided_tour/BUILD.gn b/ios/chrome/browser/bubble/ui_bundled/guided_tour/BUILD.gn new file mode 100644 index 0000000..840eb0e --- /dev/null +++ b/ios/chrome/browser/bubble/ui_bundled/guided_tour/BUILD.gn
@@ -0,0 +1,19 @@ +# Copyright 2017 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("guided_tour") { + sources = [ + "guided_tour_bubble_view_controller_animator.h", + "guided_tour_bubble_view_controller_animator.mm", + "guided_tour_bubble_view_controller_presentation_controller.h", + "guided_tour_bubble_view_controller_presentation_controller.mm", + "guided_tour_bubble_view_controller_presenter.h", + "guided_tour_bubble_view_controller_presenter.mm", + ] + deps = [ + "//base", + "//ios/chrome/browser/bubble/ui_bundled", + "//ios/chrome/browser/bubble/ui_bundled:bubble_view", + ] +}
diff --git a/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_animator.h b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_animator.h new file mode 100644 index 0000000..ff7b04e4 --- /dev/null +++ b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_animator.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 IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_BUBBLE_VIEW_CONTROLLER_ANIMATOR_H_ +#define IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_BUBBLE_VIEW_CONTROLLER_ANIMATOR_H_ + +#import <UIKit/UIKit.h> + +// Presentation and dismissal animation for the +// GuidedTourBubbleViewControllerPresentationController. +@interface GuidedTourBubbleViewControllerAnimator + : NSObject <UIViewControllerAnimatedTransitioning> + +// Whether the animated view is `appearing`. +@property(nonatomic, assign) BOOL appearing; + +@end + +#endif // IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_BUBBLE_VIEW_CONTROLLER_ANIMATOR_H_
diff --git a/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_animator.mm b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_animator.mm new file mode 100644 index 0000000..0e3a968 --- /dev/null +++ b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_animator.mm
@@ -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. + +#import "ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_animator.h" + +@implementation GuidedTourBubbleViewControllerAnimator + +#pragma mark - UIViewControllerAnimatedTransitioning + +- (void)animateTransition: + (id<UIViewControllerContextTransitioning>)transitionContext { + UIViewController* presentedViewController = [transitionContext + viewControllerForKey:self.appearing + ? UITransitionContextToViewControllerKey + : UITransitionContextFromViewControllerKey]; + UIView* presentedView = [transitionContext + viewForKey:self.appearing ? UITransitionContextToViewKey + : UITransitionContextFromViewKey]; + + UIView* containerView = [transitionContext containerView]; + if (self.appearing) { + [containerView addSubview:presentedView]; + presentedView.frame = + [transitionContext finalFrameForViewController:presentedViewController]; + } + + if (self.appearing) { + presentedView.alpha = 0; + } + + [UIView animateWithDuration:.5 + delay:0 + usingSpringWithDamping:.85 + initialSpringVelocity:0 + options:0 + animations:^{ + presentedView.alpha = self.appearing ? 1 : 0; + } + completion:^(BOOL finished) { + [transitionContext completeTransition:YES]; + }]; +} + +- (NSTimeInterval)transitionDuration: + (id<UIViewControllerContextTransitioning>)transitionContext { + return 0.5; +} + +@end
diff --git a/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presentation_controller.h b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presentation_controller.h new file mode 100644 index 0000000..78d4fb35b --- /dev/null +++ b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presentation_controller.h
@@ -0,0 +1,35 @@ +// 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 IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_BUBBLE_VIEW_CONTROLLER_PRESENTATION_CONTROLLER_H_ +#define IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_BUBBLE_VIEW_CONTROLLER_PRESENTATION_CONTROLLER_H_ + +#import <UIKit/UIKit.h> + +// Custom UIPresentationController for a BubbleView with a dimmed background +// view that has a cutout for the view the BubbleView is anchored to. +@interface GuidedTourBubbleViewControllerPresentationController + : UIPresentationController + +// Initializer adding on mandatory initializers to the superclass +// `presentedViewController` and `presentingViewController`: The +// `presentedBubbleViewFrame` of the BubbleView that is being presented. The +// `anchorViewFrame` of the view that the BubbleView is anchored to. The +// `cornerRadius` of the cutout in the background view. +- (instancetype) + initWithPresentedViewController:(UIViewController*)presentedViewController + presentingViewController:(UIViewController*)presentingViewController + presentedBubbleViewFrame:(CGRect)presentedBubbleViewFrame + anchorViewFrame:(CGRect)anchorViewFrame + cornerRadius:(CGFloat)cornerRadius + NS_DESIGNATED_INITIALIZER; + +- (instancetype) + initWithPresentedViewController:(UIViewController*)presentedViewController + presentingViewController:(UIViewController*)presentingViewController + NS_UNAVAILABLE; + +@end + +#endif // IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_BUBBLE_VIEW_CONTROLLER_PRESENTATION_CONTROLLER_H_
diff --git a/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presentation_controller.mm b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presentation_controller.mm new file mode 100644 index 0000000..6e3d573 --- /dev/null +++ b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presentation_controller.mm
@@ -0,0 +1,136 @@ +// 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. + +#import "ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presentation_controller.h" + +@interface GuidedTourBubbleViewControllerPresentationController () + +// The background dimmed view behind the BubbleView. +@property(nonatomic, strong) UIView* dimmingView; + +@end + +@implementation GuidedTourBubbleViewControllerPresentationController { + CGRect _presentedBubbleViewFrame; + CGRect _anchorViewFrame; + CGFloat _cornerRadius; +} + +- (instancetype) + initWithPresentedViewController:(UIViewController*)presentedViewController + presentingViewController:(UIViewController*)presentingViewController + presentedBubbleViewFrame:(CGRect)presentedBubbleViewFrame + anchorViewFrame:(CGRect)anchorViewFrame + cornerRadius:(CGFloat)cornerRadius { + self = [super initWithPresentedViewController:presentedViewController + presentingViewController:presentingViewController]; + if (self) { + _presentedBubbleViewFrame = presentedBubbleViewFrame; + _anchorViewFrame = anchorViewFrame; + _cornerRadius = cornerRadius; + } + return self; +} + +#pragma mark - Lifecycle + +- (CGRect)frameOfPresentedViewInContainerView { + UIView* containerView = self.containerView; + if (!containerView) { + return CGRectZero; + } + + return _presentedBubbleViewFrame; +} + +- (void)presentationTransitionWillBegin { + UIView* containerView = self.containerView; + UIViewController* presentedVC = self.presentedViewController; + if (!containerView) { + return; + } + + _dimmingView = [[UIView alloc] initWithFrame:CGRectZero]; + _dimmingView.backgroundColor = + [[UIColor blackColor] colorWithAlphaComponent:0.5]; + _dimmingView.alpha = 0.0; + self.dimmingView.frame = containerView.bounds; + [containerView insertSubview:self.dimmingView atIndex:0]; + [self addSpotlightViewCutOutWithCornerRadius:_cornerRadius]; + + id<UIViewControllerTransitionCoordinator> coordinator = + presentedVC.transitionCoordinator; + if (coordinator) { + __weak GuidedTourBubbleViewControllerPresentationController* weakSelf = + self; + [coordinator + animateAlongsideTransition:^( + id<UIViewControllerTransitionCoordinatorContext> context) { + weakSelf.dimmingView.alpha = 1.0; + } + completion:nil]; + } else { + self.dimmingView.alpha = 1.0; + } +} + +- (void)dismissalTransitionWillBegin { + UIViewController* presentedVC = self.presentedViewController; + id<UIViewControllerTransitionCoordinator> coordinator = + presentedVC.transitionCoordinator; + + if (coordinator) { + __weak GuidedTourBubbleViewControllerPresentationController* weakSelf = + self; + [coordinator + animateAlongsideTransition:^( + id<UIViewControllerTransitionCoordinatorContext> context) { + weakSelf.dimmingView.alpha = 0.0; + } + completion:nil]; + } else { + self.dimmingView.alpha = 0.0; + } +} + +- (void)dismissalTransitionDidEnd:(BOOL)completed { + if (completed) { + [self.dimmingView removeFromSuperview]; + self.dimmingView = nil; + } +} + +- (void)containerViewWillLayoutSubviews { + [super containerViewWillLayoutSubviews]; + + if (self.containerView) { + self.dimmingView.frame = self.containerView.bounds; + } + self.presentedView.frame = [self frameOfPresentedViewInContainerView]; +} + +#pragma mark - Private + +// Carves a hole in the background view to spotlight the view anchoring the +// bubble view. +- (void)addSpotlightViewCutOutWithCornerRadius:(CGFloat)radius { + CAShapeLayer* maskLayer = [CAShapeLayer layer]; + CGRect backgroundBounds = self.dimmingView.bounds; + maskLayer.frame = backgroundBounds; + + // Create the path for the mask + // Start with a rectangle covering the whole mask area + UIBezierPath* maskPath = [UIBezierPath bezierPathWithRect:backgroundBounds]; + // Create a path for the spotlight hole. + UIBezierPath* spotlightPath = + [UIBezierPath bezierPathWithRoundedRect:_anchorViewFrame + cornerRadius:radius]; + [maskPath appendPath:spotlightPath]; + + maskLayer.path = maskPath.CGPath; + maskLayer.fillRule = kCAFillRuleEvenOdd; + self.dimmingView.layer.mask = maskLayer; +} + +@end
diff --git a/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presenter.h b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presenter.h new file mode 100644 index 0000000..47cec7c --- /dev/null +++ b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presenter.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 IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_BUBBLE_VIEW_CONTROLLER_PRESENTER_H_ +#define IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_BUBBLE_VIEW_CONTROLLER_PRESENTER_H_ + +#import <UIKit/UIKit.h> + +#import "base/ios/block_types.h" +#import "ios/chrome/browser/bubble/ui_bundled/bubble_view_controller_presenter.h" + +// A subclass implementation that presents the BubbleView in front of a +// background dimmed view with a cutout of the view that the IPH is pointed and +// anchored to. +@interface GuidedTourBubbleViewControllerPresenter + : BubbleViewControllerPresenter + +// Initializes the presenter. `text` is the text displayed by the bubble. +// `titleString` is the title displayed by the bubble. `arrowDirection` is the +// direction the bubble's arrow is pointing. `alignment` is the position of the +// arrow on the bubble. `type` is the type of bubble content. `cornerRadius` is +// the corner radius of the cutout of the anchor view. `dismissalCallback` is a +// block invoked when the bubble is dismissed. `completionCallback` is a block +// invoked when the dismissal finishes. +- (instancetype)initWithText:(NSString*)text + title:(NSString*)titleString + arrowDirection:(BubbleArrowDirection)arrowDirection + alignment:(BubbleAlignment)alignment + bubbleType:(BubbleViewType)type + backgroundCutoutCornerRadius:(CGFloat)cornerRadius + dismissalCallback: + (CallbackWithIPHDismissalReasonType)dismissalCallback + completionCallback:(ProceduralBlock)completionCallback + NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithText:(NSString*)text + title:(NSString*)titleString + arrowDirection:(BubbleArrowDirection)arrowDirection + alignment:(BubbleAlignment)alignment + bubbleType:(BubbleViewType)type + dismissalCallback: + (CallbackWithIPHDismissalReasonType)dismissalCallback + NS_UNAVAILABLE; + +- (void)dismiss; + +@end + +#endif // IOS_CHROME_BROWSER_BUBBLE_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_BUBBLE_VIEW_CONTROLLER_PRESENTER_H_
diff --git a/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presenter.mm b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presenter.mm new file mode 100644 index 0000000..4ee04d7 --- /dev/null +++ b/ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presenter.mm
@@ -0,0 +1,128 @@ +// 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. + +#import "ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presenter.h" + +#import "base/metrics/histogram_functions.h" +#import "ios/chrome/browser/bubble/ui_bundled/bubble_view_controller.h" +#import "ios/chrome/browser/bubble/ui_bundled/bubble_view_controller_presenter+Subclassing.h" +#import "ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_animator.h" +#import "ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presentation_controller.h" + +@interface GuidedTourBubbleViewControllerPresenter () < + UIViewControllerTransitioningDelegate> +@end + +@implementation GuidedTourBubbleViewControllerPresenter { + UIViewController* _parentViewController; + CGPoint _anchorPointInParent; + ProceduralBlock _completionCallback; + CGFloat _cornerRadius; +} + +- (instancetype)initWithText:(NSString*)text + title:(NSString*)titleString + arrowDirection:(BubbleArrowDirection)arrowDirection + alignment:(BubbleAlignment)alignment + bubbleType:(BubbleViewType)type + backgroundCutoutCornerRadius:(CGFloat)cornerRadius + dismissalCallback: + (CallbackWithIPHDismissalReasonType)dismissalCallback + completionCallback:(ProceduralBlock)completionCallback { + self = [super initWithText:text + title:titleString + arrowDirection:arrowDirection + alignment:alignment + bubbleType:type + dismissalCallback:dismissalCallback]; + if (self) { + _completionCallback = completionCallback; + _cornerRadius = cornerRadius; + } + return self; +} + +- (void)presentInViewController:(UIViewController*)parentViewController + anchorPoint:(CGPoint)anchorPoint + anchorViewFrame:(CGRect)anchorViewFrame { + [self configureInParentViewController:parentViewController + anchorPoint:anchorPoint + anchorViewFrame:anchorViewFrame]; + _parentViewController = parentViewController; + _anchorPointInParent = [self.parentView.window convertPoint:anchorPoint + toView:self.parentView]; + + self.bubbleViewController.modalPresentationStyle = UIModalPresentationCustom; + self.bubbleViewController.transitioningDelegate = self; + [parentViewController presentViewController:self.bubbleViewController + animated:YES + completion:nil]; + + [self registerVoiceOverAnnouncement]; +} + +- (void)dismiss { + if (!self.presenting) { + return; + } + __weak GuidedTourBubbleViewControllerPresenter* weakSelf = self; + [_parentViewController + dismissViewControllerAnimated:YES + completion:^{ + GuidedTourBubbleViewControllerPresenter* strongSelf = + weakSelf; + if (strongSelf) { + strongSelf.dismissalCallback( + IPHDismissalReasonType::kTappedIPH); + } + }]; + self.presenting = NO; + _completionCallback(); +} + +#pragma mark - BubbleViewDelegate + +- (void)didTapNextButton { + [self dismiss]; +} + +#pragma mark - UIViewControllerTransitioningDelegate + +- (nullable UIPresentationController*) + presentationControllerForPresentedViewController: + (UIViewController*)presented + presentingViewController: + (nullable UIViewController*)presenting + sourceViewController:(UIViewController*)source { + GuidedTourBubbleViewControllerPresentationController* controller = + [[GuidedTourBubbleViewControllerPresentationController alloc] + initWithPresentedViewController:self.bubbleViewController + presentingViewController:_parentViewController + presentedBubbleViewFrame: + [self frameForBubbleInRect:self.parentView.bounds + atAnchorPoint:_anchorPointInParent] + anchorViewFrame:self.anchorViewFrame + cornerRadius:_cornerRadius]; + return controller; +} + +- (id<UIViewControllerAnimatedTransitioning>) + animationControllerForPresentedController:(UIViewController*)presented + presentingController:(UIViewController*)presenting + sourceController:(UIViewController*)source { + GuidedTourBubbleViewControllerAnimator* animator = + [[GuidedTourBubbleViewControllerAnimator alloc] init]; + animator.appearing = YES; + return animator; +} + +- (id<UIViewControllerAnimatedTransitioning>) + animationControllerForDismissedController:(UIViewController*)dismissed { + GuidedTourBubbleViewControllerAnimator* animator = + [[GuidedTourBubbleViewControllerAnimator alloc] init]; + animator.appearing = NO; + return animator; +} + +@end
diff --git a/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_coordinator.mm b/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_coordinator.mm index dbe6b080..c2d123f 100644 --- a/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_coordinator.mm +++ b/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_coordinator.mm
@@ -125,14 +125,12 @@ if (IOSPasskeysM2Enabled()) { // Show the prompt to allow the app to be turned on as a credential // provider. + __weak __typeof(self) weakSelf = self; [ASSettingsHelper requestToTurnOnCredentialProviderExtensionWithCompletionHandler:^( BOOL appWasEnabledForAutoFill) { - // Record the user's decision. - RecordTurnOnCredentialProviderExtensionPromptOutcome( - TurnOnCredentialProviderExtensionPromptSource:: - kCredentialProviderExtensionPromo, - appWasEnabledForAutoFill); + [weakSelf recordTurnOnCredentialProviderExtensionPromptOutcome: + appWasEnabledForAutoFill]; }]; [self recordAction:IOSCredentialProviderPromoAction::kTurnOnAutofill]; return; @@ -223,4 +221,13 @@ static_cast<int>(action)); } +// Records whether the user has accepted the in-app prompt to set the app as a +// credential provider. +- (void)recordTurnOnCredentialProviderExtensionPromptOutcome:(BOOL)outcome { + RecordTurnOnCredentialProviderExtensionPromptOutcome( + TurnOnCredentialProviderExtensionPromptSource:: + kCredentialProviderExtensionPromo, + outcome); +} + @end
diff --git a/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_coordinator_unittest.mm b/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_coordinator_unittest.mm index 8cf32c6..618f06a 100644 --- a/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_coordinator_unittest.mm +++ b/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_coordinator_unittest.mm
@@ -238,9 +238,8 @@ // Tests that tapping the "Turn on AutoFill…" primary action results in // recording the right histogram. -// TODO(crbug.com/404244113): Test is flaky. TEST_F(CredentialProviderPromoCoordinatorTest, - FLAKY_CredentialProviderPromoTurnOnAutoFillPromptOutcomeRecorded) { + CredentialProviderPromoTurnOnAutoFillPromptOutcomeRecorded) { // The "Turn on AutoFill…" action is only available on iOS 18+. if (@available(iOS 18.0, *)) { // Enable the Passkeys M2 feature.
diff --git a/ios/chrome/browser/enterprise/connectors/connectors_service.h b/ios/chrome/browser/enterprise/connectors/connectors_service.h index 7c8d5921..f64bef2 100644 --- a/ios/chrome/browser/enterprise/connectors/connectors_service.h +++ b/ios/chrome/browser/enterprise/connectors/connectors_service.h
@@ -10,6 +10,8 @@ #import "components/keyed_service/core/keyed_service.h" #import "ios/chrome/browser/enterprise/connectors/connectors_manager.h" +class ProfileIOS; + namespace policy { class UserCloudPolicyManager; } // namespace policy @@ -26,10 +28,7 @@ // - OnSecurityEventEnterpriseConnectors class ConnectorsService : public ConnectorsServiceBase, public KeyedService { public: - ConnectorsService(bool off_the_record, - PrefService* pref_service, - policy::UserCloudPolicyManager* user_cloud_policy_manager, - signin::IdentityManager* identity_manager); + ConnectorsService(ProfileIOS* profile); ~ConnectorsService() override; // Returns the CBCM domain or profile domain that enables connector policies. @@ -60,9 +59,7 @@ FRIEND_TEST_ALL_PREFIXES(ConnectorsServiceTest, GetBrowserDmToken); FRIEND_TEST_ALL_PREFIXES(ConnectorsServiceTest, ConnectorsEnabled); - bool off_the_record_; - raw_ptr<PrefService> prefs_; - raw_ptr<policy::UserCloudPolicyManager> user_cloud_policy_manager_; + raw_ptr<ProfileIOS> profile_; std::unique_ptr<ConnectorsManager> connectors_manager_; // Unowned pointer used for retrieving the management domain for connectors // policies. Can be null for incognito profiles.
diff --git a/ios/chrome/browser/enterprise/connectors/connectors_service.mm b/ios/chrome/browser/enterprise/connectors/connectors_service.mm index 8fbe013..38b50919 100644 --- a/ios/chrome/browser/enterprise/connectors/connectors_service.mm +++ b/ios/chrome/browser/enterprise/connectors/connectors_service.mm
@@ -19,6 +19,8 @@ #import "ios/chrome/browser/enterprise/connectors/features.h" #import "ios/chrome/browser/policy/model/browser_policy_connector_ios.h" #import "ios/chrome/browser/shared/model/application_context/application_context.h" +#import "ios/chrome/browser/shared/model/profile/profile_ios.h" +#import "ios/chrome/browser/signin/model/identity_manager_factory.h" namespace { std::string GetDomainFromEmail(const std::string& email) { @@ -33,20 +35,13 @@ namespace enterprise_connectors { -ConnectorsService::ConnectorsService( - bool off_the_record, - PrefService* pref_service, - policy::UserCloudPolicyManager* user_cloud_policy_manager, - signin::IdentityManager* identity_manager) - : off_the_record_(off_the_record), - prefs_(pref_service), - user_cloud_policy_manager_(user_cloud_policy_manager), - connectors_manager_( - std::make_unique<ConnectorsManager>(pref_service, - GetServiceProviderConfig())), - identity_manager_(identity_manager) { - DCHECK(prefs_); - CHECK(off_the_record_ || identity_manager_ != nullptr); +ConnectorsService::ConnectorsService(ProfileIOS* profile) : profile_(profile) { + CHECK(profile_); + identity_manager_ = IdentityManagerFactory::GetForProfile(profile); + + CHECK(profile_->IsOffTheRecord() || identity_manager_ != nullptr); + connectors_manager_ = std::make_unique<ConnectorsManager>( + profile_->GetPrefs(), GetServiceProviderConfig()); } ConnectorsService::~ConnectorsService() = default; @@ -116,8 +111,8 @@ std::optional<ConnectorsServiceBase::DmToken> ConnectorsService::GetDmToken( const char* scope_pref) const { - policy::PolicyScope scope = - static_cast<policy::PolicyScope>(prefs_->GetInteger(scope_pref)); + policy::PolicyScope scope = static_cast<policy::PolicyScope>( + profile_->GetPrefs()->GetInteger(scope_pref)); if (scope == policy::PolicyScope::POLICY_SCOPE_USER) { auto profile_dm_token = GetProfileDmToken(); if (profile_dm_token) { @@ -137,15 +132,15 @@ } bool ConnectorsService::ConnectorsEnabled() const { - return !off_the_record_; + return !profile_->IsOffTheRecord(); } PrefService* ConnectorsService::GetPrefs() { - return prefs_; + return profile_->GetPrefs(); } const PrefService* ConnectorsService::GetPrefs() const { - return prefs_; + return profile_->GetPrefs(); } ConnectorsManagerBase* ConnectorsService::GetConnectorsManagerBase() { @@ -159,7 +154,7 @@ policy::CloudPolicyManager* ConnectorsService::GetManagedUserCloudPolicyManager() const { - return user_cloud_policy_manager_.get(); + return profile_->GetUserCloudPolicyManager(); } std::unique_ptr<ClientMetadata> ConnectorsService::BuildClientMetadata(
diff --git a/ios/chrome/browser/enterprise/connectors/connectors_service_factory.mm b/ios/chrome/browser/enterprise/connectors/connectors_service_factory.mm index 72e37b8..baa8c72daf 100644 --- a/ios/chrome/browser/enterprise/connectors/connectors_service_factory.mm +++ b/ios/chrome/browser/enterprise/connectors/connectors_service_factory.mm
@@ -6,7 +6,6 @@ #import "ios/chrome/browser/shared/model/profile/profile_ios.h" #import "ios/chrome/browser/shared/model/profile/profile_keyed_service_factory_ios.h" -#import "ios/chrome/browser/signin/model/identity_manager_factory.h" namespace enterprise_connectors { @@ -26,7 +25,6 @@ ConnectorsServiceFactory::ConnectorsServiceFactory() : ProfileKeyedServiceFactoryIOS("ConnectorsService", ProfileSelection::kOwnInstanceInIncognito) { - DependsOn(IdentityManagerFactory::GetInstance()); } ConnectorsServiceFactory::~ConnectorsServiceFactory() = default; @@ -34,10 +32,7 @@ std::unique_ptr<KeyedService> ConnectorsServiceFactory::BuildServiceInstanceFor( web::BrowserState* browser_state) const { auto* profile = ProfileIOS::FromBrowserState(browser_state); - return std::make_unique<ConnectorsService>( - profile->IsOffTheRecord(), profile->GetPrefs(), - profile->GetUserCloudPolicyManager(), - IdentityManagerFactory::GetForProfile(profile)); + return std::make_unique<ConnectorsService>(profile); } } // namespace enterprise_connectors
diff --git a/ios/chrome/browser/enterprise/connectors/connectors_service_unittest.mm b/ios/chrome/browser/enterprise/connectors/connectors_service_unittest.mm index 6cd65561..3e0f1c93 100644 --- a/ios/chrome/browser/enterprise/connectors/connectors_service_unittest.mm +++ b/ios/chrome/browser/enterprise/connectors/connectors_service_unittest.mm
@@ -75,9 +75,6 @@ fake_browser_dm_token_storage_.SetDMToken(kTestBrowserDmToken); fake_browser_dm_token_storage_.SetClientId(kTestClientId); - // Setup required to register connectors prefs with `pref_service_`. - RegisterProfilePrefs(prefs()->registry()); - auto policy_data = std::make_unique<enterprise_management::PolicyData>(); policy_data->set_managed_by(kTestMachineDomain); @@ -99,8 +96,6 @@ ->SetMachineLevelUserCloudPolicyManagerForTesting(manager_.get()); } - TestingPrefServiceSimple* prefs() { return &pref_service_; } - TestProfileIOS* profile() { return profile_.get(); } signin::IdentityManager* identity_manager() { @@ -114,7 +109,6 @@ private: web::WebTaskEnvironment task_environment_; - TestingPrefServiceSimple pref_service_; std::unique_ptr<TestProfileIOS> profile_; policy::FakeBrowserDMTokenStorage fake_browser_dm_token_storage_; std::unique_ptr<policy::MachineLevelUserCloudPolicyManager> manager_; @@ -123,12 +117,8 @@ } // namespace TEST_F(ConnectorsServiceTest, GetPrefs) { - ConnectorsService connectors_service{/*off_the_record=*/false, prefs(), - /*user_cloud_policy_client=*/nullptr, - identity_manager()}; - const ConnectorsService const_connectors_service{ - /*off_the_record=*/false, prefs(), - /*user_cloud_policy_client=*/nullptr, identity_manager()}; + ConnectorsService connectors_service{profile()}; + const ConnectorsService const_connectors_service{profile()}; PrefService* prefs = connectors_service.GetPrefs(); const PrefService* const_prefs = const_connectors_service.GetPrefs(); @@ -139,12 +129,9 @@ } TEST_F(ConnectorsServiceTest, GetProfileDmToken) { - prefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, - policy::POLICY_SCOPE_USER); - ConnectorsService connectors_service{ - /*off_the_record=*/false, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - identity_manager()}; + profile()->GetPrefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, + policy::POLICY_SCOPE_USER); + ConnectorsService connectors_service{profile()}; auto profile_dm_token = connectors_service.GetDmToken(kEnterpriseRealTimeUrlCheckScope); @@ -154,12 +141,9 @@ } TEST_F(ConnectorsServiceTest, GetBrowserDmToken) { - prefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, - policy::POLICY_SCOPE_MACHINE); - ConnectorsService connectors_service{ - /*off_the_record=*/false, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - identity_manager()}; + profile()->GetPrefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, + policy::POLICY_SCOPE_MACHINE); + ConnectorsService connectors_service{profile()}; auto browser_dm_token = connectors_service.GetDmToken(kEnterpriseRealTimeUrlCheckScope); @@ -177,25 +161,13 @@ ASSERT_FALSE(ConnectorsServiceFactory::GetForProfile( profile()->GetOffTheRecordProfile()) ->ConnectorsEnabled()); - ASSERT_TRUE( - ConnectorsService( - /*off_the_record=*/false, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - identity_manager()) - .ConnectorsEnabled()); - ASSERT_FALSE( - ConnectorsService( - /*off_the_record=*/true, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - /*identity_manager=*/nullptr) - .ConnectorsEnabled()); + ASSERT_TRUE(ConnectorsService(profile()).ConnectorsEnabled()); + ASSERT_FALSE(ConnectorsService(profile()->GetOffTheRecordProfile()) + .ConnectorsEnabled()); } TEST_F(ConnectorsServiceTest, RealTimeUrlCheck) { - auto service = ConnectorsService( - /*off_the_record=*/false, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - identity_manager()); + auto service = ConnectorsService(profile()); ASSERT_FALSE(service.GetDMTokenForRealTimeUrlCheck().has_value()); ASSERT_EQ(service.GetDMTokenForRealTimeUrlCheck().error(), @@ -204,19 +176,19 @@ ASSERT_EQ(service.GetAppliedRealTimeUrlCheck(), EnterpriseRealTimeUrlCheckMode::REAL_TIME_CHECK_DISABLED); - prefs()->SetInteger( + profile()->GetPrefs()->SetInteger( kEnterpriseRealTimeUrlCheckMode, EnterpriseRealTimeUrlCheckMode::REAL_TIME_CHECK_FOR_MAINFRAME_ENABLED); - prefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, - policy::POLICY_SCOPE_MACHINE); + profile()->GetPrefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, + policy::POLICY_SCOPE_MACHINE); ASSERT_TRUE(service.GetDMTokenForRealTimeUrlCheck().has_value()); ASSERT_EQ(*service.GetDMTokenForRealTimeUrlCheck(), kTestBrowserDmToken); ASSERT_EQ( service.GetAppliedRealTimeUrlCheck(), EnterpriseRealTimeUrlCheckMode::REAL_TIME_CHECK_FOR_MAINFRAME_ENABLED); - prefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, - policy::POLICY_SCOPE_USER); + profile()->GetPrefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, + policy::POLICY_SCOPE_USER); ASSERT_TRUE(service.GetDMTokenForRealTimeUrlCheck().has_value()); ASSERT_EQ(*service.GetDMTokenForRealTimeUrlCheck(), kTestProfileDmToken); ASSERT_EQ( @@ -225,10 +197,7 @@ } TEST_F(ConnectorsServiceTest, RealTimeUrlCheck_OffTheRecord) { - auto service = ConnectorsService( - /*off_the_record=*/true, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - /*identity_manager=*/nullptr); + auto service = ConnectorsService(profile()->GetOffTheRecordProfile()); ASSERT_FALSE(service.GetDMTokenForRealTimeUrlCheck().has_value()); ASSERT_EQ(service.GetDMTokenForRealTimeUrlCheck().error(), @@ -237,11 +206,11 @@ ASSERT_EQ(service.GetAppliedRealTimeUrlCheck(), EnterpriseRealTimeUrlCheckMode::REAL_TIME_CHECK_DISABLED); - prefs()->SetInteger( + profile()->GetPrefs()->SetInteger( kEnterpriseRealTimeUrlCheckMode, EnterpriseRealTimeUrlCheckMode::REAL_TIME_CHECK_FOR_MAINFRAME_ENABLED); - prefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, - policy::POLICY_SCOPE_MACHINE); + profile()->GetPrefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, + policy::POLICY_SCOPE_MACHINE); ASSERT_FALSE(service.GetDMTokenForRealTimeUrlCheck().has_value()); ASSERT_EQ(service.GetDMTokenForRealTimeUrlCheck().error(), ConnectorsServiceBase::NoDMTokenForRealTimeUrlCheckReason:: @@ -249,8 +218,8 @@ ASSERT_EQ(service.GetAppliedRealTimeUrlCheck(), EnterpriseRealTimeUrlCheckMode::REAL_TIME_CHECK_DISABLED); - prefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, - policy::POLICY_SCOPE_USER); + profile()->GetPrefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, + policy::POLICY_SCOPE_USER); ASSERT_FALSE(service.GetDMTokenForRealTimeUrlCheck().has_value()); ASSERT_EQ(service.GetDMTokenForRealTimeUrlCheck().error(), ConnectorsServiceBase::NoDMTokenForRealTimeUrlCheckReason:: @@ -260,15 +229,12 @@ } TEST_F(ConnectorsServiceTest, ReportingSettings) { - auto service = ConnectorsService( - /*off_the_record=*/false, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - identity_manager()); + auto service = ConnectorsService(profile()); EXPECT_FALSE(service.GetReportingSettings()); EXPECT_TRUE(service.GetReportingServiceProviderNames().empty()); - test::SetOnSecurityEventReporting(prefs(), /*enabled=*/true); + test::SetOnSecurityEventReporting(profile()->GetPrefs(), /*enabled=*/true); auto settings = service.GetReportingSettings(); EXPECT_TRUE(settings.has_value()); @@ -282,7 +248,7 @@ EXPECT_EQ(provider_names, std::vector<std::string>({"google"})); test::SetOnSecurityEventReporting( - prefs(), /*enabled=*/true, /*enabled_event_names=*/{}, + profile()->GetPrefs(), /*enabled=*/true, /*enabled_event_names=*/{}, /*enabled_opt_in_events=*/{}, /*machine_scope=*/false); settings = service.GetReportingSettings(); @@ -298,21 +264,18 @@ } TEST_F(ConnectorsServiceTest, ReportingSettings_OffTheRecord) { - auto service = ConnectorsService( - /*off_the_record=*/true, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - /*identity_manager=*/nullptr); + auto service = ConnectorsService(profile()->GetOffTheRecordProfile()); EXPECT_FALSE(service.GetReportingSettings()); EXPECT_TRUE(service.GetReportingServiceProviderNames().empty()); - test::SetOnSecurityEventReporting(prefs(), /*enabled=*/true); + test::SetOnSecurityEventReporting(profile()->GetPrefs(), /*enabled=*/true); EXPECT_FALSE(service.GetReportingSettings()); EXPECT_TRUE(service.GetReportingServiceProviderNames().empty()); test::SetOnSecurityEventReporting( - prefs(), /*enabled=*/true, /*enabled_event_names=*/{}, + profile()->GetPrefs(), /*enabled=*/true, /*enabled_event_names=*/{}, /*enabled_opt_in_events=*/{}, /*machine_scope=*/false); EXPECT_FALSE(service.GetReportingSettings()); @@ -320,52 +283,45 @@ } TEST_F(ConnectorsServiceTest, GetManagementDomain_UrlFilteringEnabled) { - auto service = ConnectorsService( - /*off_the_record=*/false, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - identity_manager()); + auto service = ConnectorsService(profile()); ASSERT_EQ(service.GetManagementDomain(), std::string()); base::test::ScopedFeatureList feature(kIOSEnterpriseRealtimeUrlFiltering); - prefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, - policy::POLICY_SCOPE_USER); + profile()->GetPrefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, + policy::POLICY_SCOPE_USER); MakePrimaryAccountAvailable(kTestProfileEmail); ASSERT_EQ(service.GetManagementDomain(), kTestProfileDomain); - prefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, - policy::POLICY_SCOPE_MACHINE); + profile()->GetPrefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, + policy::POLICY_SCOPE_MACHINE); ASSERT_EQ(service.GetManagementDomain(), kTestMachineDomain); } TEST_F(ConnectorsServiceTest, GetManagementDomain_EventReportingEnabled) { - auto service = ConnectorsService( - /*off_the_record=*/false, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - identity_manager()); + auto service = ConnectorsService(profile()); ASSERT_EQ(service.GetManagementDomain(), std::string()); base::test::ScopedFeatureList feature(kEnterpriseRealtimeEventReportingOnIOS); - prefs()->SetInteger(kOnSecurityEventScopePref, policy::POLICY_SCOPE_USER); + profile()->GetPrefs()->SetInteger(kOnSecurityEventScopePref, + policy::POLICY_SCOPE_USER); MakePrimaryAccountAvailable(kTestProfileEmail); ASSERT_EQ(service.GetManagementDomain(), kTestProfileDomain); - prefs()->SetInteger(kOnSecurityEventScopePref, policy::POLICY_SCOPE_MACHINE); + profile()->GetPrefs()->SetInteger(kOnSecurityEventScopePref, + policy::POLICY_SCOPE_MACHINE); ASSERT_EQ(service.GetManagementDomain(), kTestMachineDomain); } TEST_F(ConnectorsServiceTest, GetManagementDomain_MachinePolicyHasPrecedence) { - auto service = ConnectorsService( - /*off_the_record=*/false, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - identity_manager()); + auto service = ConnectorsService(profile()); ASSERT_EQ(service.GetManagementDomain(), std::string()); @@ -374,9 +330,10 @@ /*enabled_features=*/{kEnterpriseRealtimeEventReportingOnIOS, kIOSEnterpriseRealtimeUrlFiltering}, /*disabled_features=*/{}); - prefs()->SetInteger(kOnSecurityEventScopePref, policy::POLICY_SCOPE_USER); - prefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, - policy::POLICY_SCOPE_MACHINE); + profile()->GetPrefs()->SetInteger(kOnSecurityEventScopePref, + policy::POLICY_SCOPE_USER); + profile()->GetPrefs()->SetInteger(kEnterpriseRealTimeUrlCheckScope, + policy::POLICY_SCOPE_MACHINE); MakePrimaryAccountAvailable(kTestProfileEmail); @@ -384,10 +341,7 @@ } TEST_F(ConnectorsServiceTest, GetManagementDomain_OffTheRecord) { - auto service = ConnectorsService( - /*off_the_record=*/true, prefs(), - /*user_cloud_policy_client=*/profile()->GetUserCloudPolicyManager(), - /*identity_manager=*/nullptr); + auto service = ConnectorsService(profile()->GetOffTheRecordProfile()); ASSERT_EQ(service.GetManagementDomain(), std::string()); }
diff --git a/ios/chrome/browser/first_run/ui_bundled/guided_tour/BUILD.gn b/ios/chrome/browser/first_run/ui_bundled/guided_tour/BUILD.gn index e71300e..e1c5b28 100644 --- a/ios/chrome/browser/first_run/ui_bundled/guided_tour/BUILD.gn +++ b/ios/chrome/browser/first_run/ui_bundled/guided_tour/BUILD.gn
@@ -4,6 +4,8 @@ source_set("guided_tour") { sources = [ + "guided_tour_coordinator.h", + "guided_tour_coordinator.mm", "guided_tour_promo_coordinator.h", "guided_tour_promo_coordinator.mm", "guided_tour_promo_view_controller.h", @@ -12,8 +14,14 @@ deps = [ "//base", "//ios/chrome/app/strings", + "//ios/chrome/browser/bubble/ui_bundled/guided_tour", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", + "//ios/chrome/browser/shared/coordinator/layout_guide", + "//ios/chrome/browser/shared/public/commands", "//ios/chrome/browser/shared/ui/symbols", + "//ios/chrome/browser/shared/ui/util", + "//ios/chrome/browser/shared/ui/util:util_swift", + "//ios/chrome/browser/toolbar/ui_bundled/buttons", "//ios/chrome/common/ui/promo_style", "//ui/base", ]
diff --git a/ios/chrome/browser/first_run/ui_bundled/guided_tour/DEPS b/ios/chrome/browser/first_run/ui_bundled/guided_tour/DEPS new file mode 100644 index 0000000..9ddff46 --- /dev/null +++ b/ios/chrome/browser/first_run/ui_bundled/guided_tour/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presenter.h", + "+ios/chrome/browser/toolbar/ui_bundled/buttons/toolbar_button.h", +]
diff --git a/ios/chrome/browser/first_run/ui_bundled/guided_tour/guided_tour_coordinator.h b/ios/chrome/browser/first_run/ui_bundled/guided_tour/guided_tour_coordinator.h new file mode 100644 index 0000000..0c962e4 --- /dev/null +++ b/ios/chrome/browser/first_run/ui_bundled/guided_tour/guided_tour_coordinator.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 IOS_CHROME_BROWSER_FIRST_RUN_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_COORDINATOR_H_ +#define IOS_CHROME_BROWSER_FIRST_RUN_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_COORDINATOR_H_ + +#import "base/ios/block_types.h" +#import "ios/chrome/browser/shared/coordinator/chrome_coordinator/chrome_coordinator.h" +#import "ios/chrome/browser/shared/public/commands/guided_tour_commands.h" + +// Delegate for GuidedTourCoordinator to handle user actions. +@protocol GuidedTourCoordinatorDelegate + +// Indicates to the delegate that the user tapped on the next button for `step`. +- (void)nextTappedForStep:(GuidedTourStep)step; + +// Indicates to the delegate that the `step` was dismissed. +- (void)stepCompleted:(GuidedTourStep)step; + +@end + +// Coordinator to present a Guided Tour step. +@interface GuidedTourCoordinator : ChromeCoordinator + +// Initializes a GuidedTourCoordinator with `baseViewController`, +// `browser`, and `delegate`. +- (instancetype)initWithStep:(GuidedTourStep)step + baseViewController:(UIViewController*)baseViewController + browser:(Browser*)browser + delegate:(id<GuidedTourCoordinatorDelegate>)delegate + NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browser:(Browser*)browser NS_UNAVAILABLE; + +@end + +#endif // IOS_CHROME_BROWSER_FIRST_RUN_UI_BUNDLED_GUIDED_TOUR_GUIDED_TOUR_COORDINATOR_H_
diff --git a/ios/chrome/browser/first_run/ui_bundled/guided_tour/guided_tour_coordinator.mm b/ios/chrome/browser/first_run/ui_bundled/guided_tour/guided_tour_coordinator.mm new file mode 100644 index 0000000..373ed4e4 --- /dev/null +++ b/ios/chrome/browser/first_run/ui_bundled/guided_tour/guided_tour_coordinator.mm
@@ -0,0 +1,138 @@ +// 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. + +#import "ios/chrome/browser/first_run/ui_bundled/guided_tour/guided_tour_coordinator.h" + +#import "base/notreached.h" +#import "ios/chrome/browser/bubble/ui_bundled/guided_tour/guided_tour_bubble_view_controller_presenter.h" +#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h" +#import "ios/chrome/browser/shared/ui/util/layout_guide_names.h" +#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h" +#import "ios/chrome/browser/shared/ui/util/util_swift.h" +#import "ios/chrome/browser/toolbar/ui_bundled/buttons/toolbar_button.h" +#import "ios/chrome/grit/ios_strings.h" +#import "ui/base/l10n/l10n_util_mac.h" + +namespace { +// Corner radius of the Tab Grid button spotlight cutout for the NTP step. +const CGFloat kNTPTabGridButtonSpotlightCornerRadius = 7.0f; +} // namespace + +@implementation GuidedTourCoordinator { + GuidedTourStep _step; + __weak id<GuidedTourCoordinatorDelegate> _delegate; + GuidedTourBubbleViewControllerPresenter* _presenter; +} + +- (instancetype)initWithStep:(GuidedTourStep)step + baseViewController:(UIViewController*)baseViewController + browser:(Browser*)browser + delegate:(id<GuidedTourCoordinatorDelegate>)delegate { + if ((self = [super initWithBaseViewController:baseViewController + browser:browser])) { + _step = step; + _delegate = delegate; + } + return self; +} + +#pragma mark - ChromeCoordinator + +- (void)start { + __weak GuidedTourCoordinator* weakSelf = self; + BubbleArrowDirection direction = IsSplitToolbarMode(self.baseViewController) + ? BubbleArrowDirectionDown + : BubbleArrowDirectionUp; + _presenter = [[GuidedTourBubbleViewControllerPresenter alloc] + initWithText:[self bodyString] + title:[self titleString] + arrowDirection:direction + alignment:BubbleAlignmentBottomOrTrailing + bubbleType:BubbleViewTypeRich + backgroundCutoutCornerRadius:[self backgroundCutoutCornerRadius] + dismissalCallback:^(IPHDismissalReasonType reason) { + [weakSelf dismissFinished]; + } + completionCallback:^{ + [weakSelf nextTapped]; + }]; + + UIView* anchorView = [self anchorView]; + CGPoint anchorPoint = [self anchorPointForAnchorView:anchorView]; + CGPoint anchorViewOrigin = + [anchorView.superview convertPoint:anchorView.frame.origin toView:nil]; + CGRect anchorViewFrame = + CGRectMake(anchorViewOrigin.x, anchorViewOrigin.y, + anchorView.frame.size.width, anchorView.frame.size.height); + + [_presenter presentInViewController:self.baseViewController + anchorPoint:anchorPoint + anchorViewFrame:anchorViewFrame]; +} + +- (void)stop { + [_presenter dismiss]; + _presenter = nil; +} + +#pragma mark - Private + +// Returns the view to which the bubble view will be anchored. +- (UIView*)anchorView { + if (_step == GuidedTourStepNTP) { + ToolbarButton* tabSwitcherButton = + static_cast<ToolbarButton*>([LayoutGuideCenterForBrowser(self.browser) + referencedViewUnderName:kTabSwitcherGuide]); + return tabSwitcherButton.spotlightView; + } + NOTREACHED() << "A layout guide view needs to be fetched for each step"; +} + +// Returns the anchor point in `anchorView` to which the bubble view will be +// anchored. +- (CGPoint)anchorPointForAnchorView:(UIView*)anchorView { + CGPoint anchorPoint; + if (IsSplitToolbarMode(self.baseViewController)) { + anchorPoint = CGPointMake(CGRectGetMidX(anchorView.frame), + CGRectGetMinY(anchorView.frame)); + } else { + anchorPoint = CGPointMake(CGRectGetMidX(anchorView.frame), + CGRectGetMaxY(anchorView.frame)); + } + return [anchorView.superview convertPoint:anchorPoint toView:nil]; +} + +// Handle the user tapping on the next button. +- (void)nextTapped { + [_delegate nextTappedForStep:_step]; +} + +// Handle the dismissal completion of this step. +- (void)dismissFinished { + [_delegate stepCompleted:_step]; +} + +// Returns the title string used for this step's Bubble View. +- (NSString*)titleString { + if (_step == GuidedTourStepNTP) { + return l10n_util::GetNSString(IDS_IOS_FIRST_RUN_GUIDED_TOUR_NTP_IPH_TITLE); + } + return @""; +} + +// Returns the main text string for this step's Bubble View. +- (NSString*)bodyString { + if (_step == GuidedTourStepNTP) { + return l10n_util::GetNSString(IDS_IOS_FIRST_RUN_GUIDED_TOUR_NTP_IPH_TEXT); + } + return @""; +} + +// The corner radius of the spotlight cutout for this Bubble View. +- (CGFloat)backgroundCutoutCornerRadius { + return _step == GuidedTourStepNTP ? kNTPTabGridButtonSpotlightCornerRadius + : 0; +} + +@end
diff --git a/ios/chrome/browser/home_customization/coordinator/BUILD.gn b/ios/chrome/browser/home_customization/coordinator/BUILD.gn index eacf8f9a..6c69e630 100644 --- a/ios/chrome/browser/home_customization/coordinator/BUILD.gn +++ b/ios/chrome/browser/home_customization/coordinator/BUILD.gn
@@ -42,15 +42,21 @@ source_set("unit_tests") { testonly = true - sources = [ "home_customization_coordinator_unittest.mm" ] + sources = [ + "home_customization_coordinator_unittest.mm", + "home_customization_mediator_unittest.mm", + ] frameworks = [ "Foundation.framework" ] deps = [ ":coordinator", "//base", "//base/test:test_support", + "//components/prefs", "//ios/chrome/browser/home_customization/ui", "//ios/chrome/browser/home_customization/utils", "//ios/chrome/browser/shared/model/browser/test:test_support", + "//ios/chrome/browser/shared/model/prefs:browser_prefs", + "//ios/chrome/browser/shared/model/prefs:pref_names", "//ios/chrome/browser/shared/model/profile/test", "//ios/chrome/browser/shared/public/features", "//ios/chrome/test:test_support",
diff --git a/ios/chrome/browser/home_customization/coordinator/home_customization_mediator_unittest.mm b/ios/chrome/browser/home_customization/coordinator/home_customization_mediator_unittest.mm new file mode 100644 index 0000000..965d72e --- /dev/null +++ b/ios/chrome/browser/home_customization/coordinator/home_customization_mediator_unittest.mm
@@ -0,0 +1,89 @@ +// 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. + +#import "ios/chrome/browser/home_customization/coordinator/home_customization_mediator.h" + +#import "base/memory/raw_ptr.h" +#import "base/strings/sys_string_conversions.h" +#import "base/test/scoped_feature_list.h" +#import "components/prefs/pref_service.h" +#import "ios/chrome/browser/home_customization/ui/home_customization_main_consumer.h" +#import "ios/chrome/browser/home_customization/utils/home_customization_constants.h" +#import "ios/chrome/browser/shared/model/prefs/browser_prefs.h" +#import "ios/chrome/browser/shared/model/prefs/pref_names.h" +#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h" +#import "ios/chrome/browser/shared/public/features/features.h" +#import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h" +#import "ios/chrome/test/ios_chrome_scoped_testing_variations_service.h" +#import "ios/web/public/test/web_task_environment.h" +#import "testing/gtest/include/gtest/gtest.h" +#import "testing/gtest_mac.h" +#import "testing/platform_test.h" +#import "ui/base/l10n/l10n_util_mac.h" + +// Fake consumer for the main page of the Customization menu. +@interface FakeHomeCustomizationMainConsumer + : NSObject <HomeCustomizationMainConsumer> + +// The toggles, populated by `populateToggles:` to faciliate testing. +@property(nonatomic, assign) std::map<CustomizationToggleType, BOOL> toggleMap; + +@end + +@implementation FakeHomeCustomizationMainConsumer + +#pragma mark - HomeCustomizationMainConsumer + +- (void)populateToggles:(std::map<CustomizationToggleType, BOOL>)toggleMap { + _toggleMap = toggleMap; +} + +- (void) + populateBackgroundCustomizationConfigurations: + (NSMutableDictionary<NSString*, BackgroundCustomizationConfiguration*>*) + BackgroundCustomizationConfigurationMap + selectedBackgroundId: + (NSString*)selectedBackgroundId { + // No-op for fake implementation. +} + +@end + +// Tests for the Home Customization mediator. +class HomeCustomizationMediatorUnitTest : public PlatformTest { + public: + void SetUp() override { + profile_ = TestProfileIOS::Builder().Build(); + pref_service_ = profile_->GetPrefs(); + mediator_ = + [[HomeCustomizationMediator alloc] initWithPrefService:pref_service_]; + } + + protected: + web::WebTaskEnvironment task_environment_; + HomeCustomizationMediator* mediator_; + raw_ptr<PrefService> pref_service_; + std::unique_ptr<TestProfileIOS> profile_; +}; + +// Tests that the mediator populates the main page data for its consumer based +// on the profile's prefs. +TEST_F(HomeCustomizationMediatorUnitTest, TestMainPageData) { + FakeHomeCustomizationMainConsumer* fake_consumer = + [[FakeHomeCustomizationMainConsumer alloc] init]; + mediator_.mainPageConsumer = fake_consumer; + + // Set the prefs. + pref_service_->SetBoolean(prefs::kHomeCustomizationMostVisitedEnabled, NO); + pref_service_->SetBoolean(prefs::kHomeCustomizationMagicStackEnabled, YES); + pref_service_->SetBoolean(prefs::kArticlesForYouEnabled, NO); + + [mediator_ configureMainPageData]; + + // Check that the toggles properly reflect the prefs. + std::map<CustomizationToggleType, BOOL> toggle_map = fake_consumer.toggleMap; + EXPECT_EQ(toggle_map.at(CustomizationToggleType::kMostVisited), NO); + EXPECT_EQ(toggle_map.at(CustomizationToggleType::kMagicStack), YES); + EXPECT_EQ(toggle_map.at(CustomizationToggleType::kDiscover), NO); +}
diff --git a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/BUILD.gn b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/BUILD.gn index 52cf1cd..8a60942 100644 --- a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/BUILD.gn +++ b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/BUILD.gn
@@ -22,6 +22,7 @@ "//components/password_manager/core/browser", "//components/password_manager/core/browser/features:password_features", "//components/password_manager/ios", + "//components/password_manager/ios:features", "//components/prefs", "//components/segmentation_platform/embedder/home_modules/tips_manager:signal_constants", "//ios/chrome/app/strings", @@ -105,6 +106,7 @@ ":eg_test_support+eg2", "//components/password_manager/core/browser/features:password_features", "//components/password_manager/core/common:features", + "//components/password_manager/ios:features", "//components/url_formatter", "//ios/chrome/app/strings", "//ios/chrome/browser/authentication/ui_bundled:eg_test_support+eg2",
diff --git a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_egtest.mm b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_egtest.mm index 4848b39e..bf4ac16e 100644 --- a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_egtest.mm +++ b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_egtest.mm
@@ -10,6 +10,7 @@ #import "base/time/time.h" #import "components/password_manager/core/browser/features/password_features.h" #import "components/password_manager/core/common/password_manager_features.h" +#import "components/password_manager/ios/features.h" #import "components/url_formatter/elide_url.h" #import "ios/chrome/browser/authentication/ui_bundled/signin_earl_grey.h" #import "ios/chrome/browser/authentication/ui_bundled/signin_earl_grey_ui_test_util.h" @@ -162,7 +163,10 @@ } if ([self isRunningTest:@selector - (testOpenPasswordBottomSheetTapUseKeyboardShowKeyboard_V2)]) { + (testOpenPasswordBottomSheetTapUseKeyboardShowKeyboard_V2)] || + [self + isRunningTest:@selector + (testOpenPasswordBottomSheetUsePassword_V2_StatelessFillDataFlow)]) { config.features_enabled.push_back( password_manager::features::kIOSPasswordBottomSheetV2); } else { @@ -170,6 +174,13 @@ password_manager::features::kIOSPasswordBottomSheetV2); } + if ([self + isRunningTest:@selector + (testOpenPasswordBottomSheetUsePassword_V2_StatelessFillDataFlow)]) { + config.features_enabled.push_back( + password_manager::features::kIOSStatelessFillDataFlow); + } + return config; } @@ -273,6 +284,54 @@ [self verifyPasswordFieldsHaveBeenFilled:@"user"]; } +// Tests that accepting suggestions from the sheet V2 works when the stateless +// fill data flow feature is enabled. This tests the combination of the 2 +// features. +- (void)testOpenPasswordBottomSheetUsePassword_V2_StatelessFillDataFlow { + [PasswordSuggestionBottomSheetAppInterface setUpMockReauthenticationModule]; + [PasswordSuggestionBottomSheetAppInterface + mockReauthenticationModuleExpectedResult:ReauthenticationResult:: + kSuccess]; + + GURL URL = self.testServer->GetURL("/simple_login_form_empty.html"); + [PasswordManagerAppInterface + storeCredentialWithUsername:@"user" + password:@"password" + URL:net::NSURLWithGURL(URL)]; + [SigninEarlGrey signinWithFakeIdentity:[FakeSystemIdentity fakeIdentity1]]; + [self loadLoginPage]; + + // Wait a bit to let things settle. Waiting on content to be loaded on the + // page isn't 100% reliable as trying to interact with that content at that + // moment doesn't always work. + base::test::ios::SpinRunLoopWithMinDelay(base::Seconds(1)); + + [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + performAction:chrome_test_util::TapWebElementWithId(kFormPassword)]; + + [ChromeEarlGrey + waitForUIElementToAppearWithMatcher:grey_accessibilityID(@"user")]; + + // Verify that the subtitle string appears. + [ChromeEarlGrey waitForUIElementToAppearWithMatcher:SubtitleString(URL)]; + + [[EarlGrey selectElementWithMatcher:UsePasswordButton()] + performAction:grey_tap()]; + + // No histogram logged because there is only 1 credential shown to the user. + GREYAssertNil( + [MetricsAppInterface + expectTotalCount:0 + forHistogram:@"PasswordManager.TouchToFill.CredentialIndex"], + @"Unexpected histogram error for touch to fill credential index"); + + // Verify that the acceptance of the password suggestion at index 0 was + // correctly recorded. + CheckAutofillSuggestionAcceptedIndexMetricsCount(/*suggestion_index=*/0); + + [self verifyPasswordFieldsHaveBeenFilled:@"user"]; +} + // This test verifies that the bottom sheet opens on autofocus events, when the // kIOSPasswordBottomSheetAutofocus feature is enabled. - (void)testOpenPasswordBottomOnAutofocus {
diff --git a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm index a1a072d7..ebeffa3 100644 --- a/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm +++ b/ios/chrome/browser/passwords/ui_bundled/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm
@@ -20,6 +20,7 @@ #import "components/password_manager/core/browser/password_store/password_store_interface.h" #import "components/password_manager/core/browser/password_ui_utils.h" #import "components/password_manager/core/browser/ui/credential_ui_entry.h" +#import "components/password_manager/ios/features.h" #import "components/password_manager/ios/ios_password_manager_driver_factory.h" #import "components/password_manager/ios/shared_password_controller.h" #import "components/prefs/pref_service.h" @@ -83,6 +84,21 @@ onlyPassword:YES]; } +// Makes a copy of suggestions with `params` and `provider` set in the copies. +NSArray<FormSuggestion*>* SetParamsAndProviderInSuggestions( + NSArray<FormSuggestion*>* suggestions, + const autofill::FormActivityParams& params, + id<FormSuggestionProvider> provider) { + NSMutableArray<FormSuggestion*>* suggestions_copy = + [NSMutableArray<FormSuggestion*> arrayWithCapacity:[suggestions count]]; + for (FormSuggestion* suggestion in suggestions) { + [suggestions_copy addObject:[FormSuggestion copy:suggestion + andSetParams:params + provider:provider]]; + } + return suggestions_copy; +} + } // namespace // TODO(crbug.com/372426818): Move this is to its own specific file/module. @@ -205,7 +221,13 @@ webState:webState completionHandler:^(NSArray<FormSuggestion*>* suggestions, id<FormSuggestionProvider> delegate) { - completion(suggestions); + bool stateless = base::FeatureList::IsEnabled( + password_manager::features::kIOSStatelessFillDataFlow); + NSArray<FormSuggestion*>* wrappedSuggestions = + stateless ? SetParamsAndProviderInSuggestions( + suggestions, params, delegate) + : suggestions; + completion(wrappedSuggestions); }]; }
diff --git a/ios/chrome/browser/shared/public/features/features.mm b/ios/chrome/browser/shared/public/features/features.mm index e5239cd..b5b8e27d 100644 --- a/ios/chrome/browser/shared/public/features/features.mm +++ b/ios/chrome/browser/shared/public/features/features.mm
@@ -1050,9 +1050,7 @@ return base::FeatureList::IsEnabled(kFRESignInSecondaryActionLabelUpdate); } -BASE_FEATURE(kIOSPasskeysM2, - "IOSPasskeysM2", - base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kIOSPasskeysM2, "IOSPasskeysM2", base::FEATURE_ENABLED_BY_DEFAULT); bool IOSPasskeysM2Enabled() { return base::FeatureList::IsEnabled(kIOSPasskeysM2);
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 index e2c432fc..6b612ac0 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -95e6978b4d65d1d36670da01f67a10f1f48f67e0 \ No newline at end of file +e3edaf782e8f7149c4c2492e3e7a55533b5638ad \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 index 23389b1e..d3b92eb3 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -982ed659e3dd4c25f32f0d86ba9fbfe102c3dea7 \ No newline at end of file +5a24acfa661c59bd8eb53e20d89ba10a23de757e \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 index 2a68a49..0cead64 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -f2a63289d3a9e3b4866ed0902ba1b0bfe33c35ba \ No newline at end of file +4e7143699ba681818cab8c98ec0d39998d43cc87 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 index 1fa9c6e..a626e5df 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -e8956ed1fc5f152f204b51cb58ebbfbc3c55c78f \ No newline at end of file +e13e0ffcbdd1b91cfb251441cf1e3eff6f255322 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 index 03e294e4..e176586 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -aa56f949981c08348e424c79f73d55639ddadce3 \ No newline at end of file +54f71374da89594dfdbc25e1f90e897ed3fbbeaa \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 index 6c034f2d..7f66ac3 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -4cf4f502f20d97ba754441ef01af032c7a7b19c5 \ No newline at end of file +a2caf961234900394a8039c7b2c1e74ed7562b1b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 index 67ddf1e..803649ae 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -4436d4d9bdf8d814ae9cf7c8fbc8d0a1d1428cb8 \ No newline at end of file +4036b5db59d8c153da0c24ad91a780e6061dcaf0 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 index d543414..0660c05 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -4a8bdedb83b8e2f33830a5c8f5b07d5b03e02cf2 \ No newline at end of file +76bc5701495778b9db3f446869591ec9f45734e6 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 index 79fded4c..4ab2859 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -66c5368c4b087ae4496bd5c2d54f1486cf91d7cb \ No newline at end of file +cfe872b9fc93298b235d7d423d68ca900e38ead5 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 084377f..047e6e9c 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -a7df80cf9e95f53cc7412f0cd2b30545ac0bfe15 \ No newline at end of file +9f334152f35499b5f00f36a8906b28dda901da44 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index 858166b1..ad9288ae 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -2765ec0306e371794906484249320b88e45f2606 \ No newline at end of file +b6a85dbe1fd2d7d17ee714acd1e9303c682b1c02 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 index ea44ffe..4ffa20c 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -270e580cbf56f9d7c8eef30a39c5c344641060dd \ No newline at end of file +f625ed4638257c969b975d98f137717dc71a76af \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index 4e0bc07..9152f79f 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -e16730370c818c8cc6fed42b8c0b76cb99d92c72 \ No newline at end of file +94db3fa3a60e48af158c566cba149af100116b88 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 755f0f0..eda7b36 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -e3ef9ff77206196672ba1aaca43052f7a5732043 \ No newline at end of file +0e3aff95dd9f2f827ab1ae47dbd4dcd51cf3086c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index 58a94585..91dc2a6 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -3e06f7e8f6da9a67816cda40a7108a02d0e8cca2 \ No newline at end of file +e0332d07cfc93647eb21f7af0553d8a4449d72ab \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 index c470ff9..5c4ec80c 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -9cd5b03798009c9fb57c8e7ea4b176a0523fbef4 \ No newline at end of file +cd52aeb6ddf2ea57d809fc7a2ebdd46095b4b7b8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 0847b31a..9c7f715 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -a18858a586f02ea18466f98d2c4a44f608d114c1 \ No newline at end of file +52deadc27942090c40f04674ec314aa856569a02 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 index be7ffdc..3ef9efe 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -ed042fbd62fdfe4c8eabbd9fa74818ad0da3f909 \ No newline at end of file +362f24d16d131448bf0f2ec87ee5e9d3d0df694c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 index c43b7c6..d714b0b 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -b6ad5a943a47834d75f2987e641b6decbf04f34e \ No newline at end of file +8e61156591295d7e7216a3bb15d6d3ef31b1858b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 index e7b3b25..6fb827c 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -be77c08b55b4dc65f1b80b2848cafcdf1d4e2755 \ No newline at end of file +5f397699b0b9d48a8dccfafa637991051a737b7b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index feb1647d..3c10a54 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -0f000f849843c189d82a71d3d490629b127b184c \ No newline at end of file +30cfdb6241dfe222a5796a2608824ccd9c238f54 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 index 3ddfbfb..8c916e3 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -81a9ae657c8b476a6c4a58f38c7aa446faf85d74 \ No newline at end of file +8dbc98f17be818d6f35848a9f3d63f7039f2f20f \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index b7b7719..9adb7d4 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -c8751ab6cebf149cf901a07dd461eeb5685bccb8 \ No newline at end of file +9ff82179f542204d5776257bceeaa0d16d42ad3f \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 5b520ac..5977791 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -89c8e1967608d6960879fefd092eec22925d422b \ No newline at end of file +76dc804eaaedb9bd7d6051cf98c2cf9aef1b826b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index 4f27820..d0208d6 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -766d5cbbe8b80bd71b90d3a8fac1e07a25d1eab0 \ No newline at end of file +0accc764651e6aa91a7f91e10b5176cacbc7bba8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 index 5542d7e..2265367 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -602c8a893511f9d23a754a71ad71b915a3d5d578 \ No newline at end of file +fa2a6fc90c741236ee1c3e1d239d3a4a4fb6aa8c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index fd9761a3..751f790d 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -2976328b9622721acd4337b186c38cea392ddbc3 \ No newline at end of file +e7b6e5963970afbf8266e6490ce6e9df4d4e718b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 76e254ac..5809b26 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -4fda076ca60e25c1d474e7d8f18f6dfd4f92d15e \ No newline at end of file +8c2470ab343dd081ee28eb7196da7b85a6b2996e \ No newline at end of file
diff --git a/ios/testing/data/http_server_files/autofill_refill_test.html b/ios/testing/data/http_server_files/autofill_refill_test.html new file mode 100644 index 0000000..3a4fc16 --- /dev/null +++ b/ios/testing/data/http_server_files/autofill_refill_test.html
@@ -0,0 +1,61 @@ + +<!DOCTYPE html> +<!-- +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. +--> +<html> +<head> + <meta name="viewport" content="width=device-width, initial-scale=1.5"> + <title>Autofill Refill Test</title> + <style> + #address-fields { display: none; } + </style> + <script> + var FillFormPresident = function() { + var form = document.forms['profile_form']; + form['name'].value = 'George Washington'; + form['address'].value = '1600 Pennsylvania Ave NW'; + form['city'].value = 'Washington'; + form['state'].value = 'DC'; + form['zip'].value = '20500'; + } + </script> +</head> +<body> + <h3>Refill Profile Autofill</h3> + <form name="profile_form" id="profile_form" action="destination.html" method="post"> + Name: <input type="text" name="name" id="form_name" /><br /> + <div id="address-fields"> + Address: <input type="text" name="address" id="form_address" /><br /> + City: <input type="text" name="city" id="form_city" /><br /> + State: <select name="state" id="form_state"> + <option value="CA">CA</option> + <option value="MA">MA</option> + <option value="NY">NY</option> + <option value="MD">MD</option> + <option value="OR">OR</option> + <option value="OH">OH</option> + <option value="IL">IL</option> + <option value="DC">DC</option> + </select> <br /> + Zip: <input name="zip" id="form_zip" /><br /> + </div> + <input type="reset" value="Reset" /> + <input id="submit_profile" type="submit" value="Submit Profile" /> + </form> + <button type="button" onclick="FillFormPresident()" id="fill_profile_president">Fill Form (President)</button> + <br /> + <script> + document.addEventListener('DOMContentLoaded', function() { + const zipInput = document.getElementById('form_name'); + const addressFields = document.getElementById('address-fields'); + zipInput.addEventListener('input', function() { + addressFields.style.display = this.value.trim() !== '' ? 'block' : 'none'; + }); + }); + </script> +</body> +</html> +
diff --git a/ios/testing/http_server_bundle_data.filelist b/ios/testing/http_server_bundle_data.filelist index f4212d24..7fcee69 100644 --- a/ios/testing/http_server_bundle_data.filelist +++ b/ios/testing/http_server_bundle_data.filelist
@@ -5,6 +5,7 @@ # If it requires updating, you should get a presubmit error with # instructions on how to regenerate. Otherwise, do not edit. data/http_server_files/OWNERS +data/http_server_files/autofill_refill_test.html data/http_server_files/autofill_smoke_test.html data/http_server_files/browsing_prevent_default_test_page.html data/http_server_files/bundle.pkpasses @@ -19,8 +20,8 @@ data/http_server_files/destination.html data/http_server_files/download_test_page.html data/http_server_files/email_signup_form.html -data/http_server_files/fullscreen.html data/http_server_files/full_address_form.html +data/http_server_files/fullscreen.html data/http_server_files/generic.pkpass data/http_server_files/green.pdf data/http_server_files/history.html @@ -47,8 +48,8 @@ data/http_server_files/redchair.usdz data/http_server_files/redirect_refresh.html data/http_server_files/sample.ics -data/http_server_files/sample.order data/http_server_files/sample.mobileconfig +data/http_server_files/sample.order data/http_server_files/semi_bundle.pkpasses data/http_server_files/simple_login_form.html data/http_server_files/simple_login_form_empty.html
diff --git a/ios/third_party/material_components_ios/src b/ios/third_party/material_components_ios/src index f25aad8..b29adef 160000 --- a/ios/third_party/material_components_ios/src +++ b/ios/third_party/material_components_ios/src
@@ -1 +1 @@ -Subproject commit f25aad87ce54240ed58abe7ae84b9316e80a8492 +Subproject commit b29adefbd8be6d39542d679b8f9189fc466283b7
diff --git a/ios_internal b/ios_internal index 6753a19..8fbb4c8 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit 6753a19d2e211ea27988a2603073395d0469a202 +Subproject commit 8fbb4c8734fa75050d85b613666e0d87d27e061e
diff --git a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java index 424788d..ad421bb 100644 --- a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java +++ b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
@@ -1435,9 +1435,14 @@ // SessionException may be thrown when an operation failed in a way that is likely to // succeed on a subsequent attempt. However, checking for transient errors is only // available on S and later. Try only once to repeat it if possible. - if (retryAllowed && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && e.isTransient()) { - return startProvisioningQorLater(false); + // On versions Q and R, since transient error detection is not available, retry no + // matter what. + if (retryAllowed) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || e.isTransient()) { + return startProvisioningQorLater(false); + } } + Log.e(TAG, "Failed to get provisioning request", e); displayMetrics(); return false;
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 2fe23aa..358bd89 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -944,6 +944,8 @@ base::FEATURE_DISABLED_BY_DEFAULT); // Enables hardware secure decryption if supported by hardware and CDM. +// NOTE: This feature is experimental and not officially supported. Users may +// encounter issues; enabling is discouraged. // TODO(xhwang): Currently this is only used for development of new features. // Apply this to Android and ChromeOS as well where hardware secure decryption // is already available.
diff --git a/media/base/win/mf_mocks.cc b/media/base/win/mf_mocks.cc index b03cb59..150d30d 100644 --- a/media/base/win/mf_mocks.cc +++ b/media/base/win/mf_mocks.cc
@@ -18,4 +18,16 @@ MockMFCdmSession::MockMFCdmSession() = default; MockMFCdmSession::~MockMFCdmSession() = default; +MockMFExtendedDRMTypeSupport::MockMFExtendedDRMTypeSupport() = default; +MockMFExtendedDRMTypeSupport::~MockMFExtendedDRMTypeSupport() = default; + +MockMFGetService::MockMFGetService() = default; +MockMFGetService::~MockMFGetService() = default; + +MockMFPMPHost::MockMFPMPHost() = default; +MockMFPMPHost::~MockMFPMPHost() = default; + +MockMFPMPHostApp::MockMFPMPHostApp() = default; +MockMFPMPHostApp::~MockMFPMPHostApp() = default; + } // namespace media
diff --git a/media/base/win/mf_mocks.h b/media/base/win/mf_mocks.h index 8f325e3..75e936c5 100644 --- a/media/base/win/mf_mocks.h +++ b/media/base/win/mf_mocks.h
@@ -6,6 +6,7 @@ #define MEDIA_BASE_WIN_MF_MOCKS_H_ #include <mfcontentdecryptionmodule.h> +#include <mfmediaengine.h> #include <wrl/client.h> #include <wrl/implements.h> @@ -56,6 +57,9 @@ MockMFCdm(); ~MockMFCdm() override; + // IUnknown method + MOCK_STDCALL_METHOD2(QueryInterface, HRESULT(REFIID riid, void** ppv)); + // IMFContentDecryptionModule methods MOCK_STDCALL_METHOD2(SetContentEnabler, HRESULT(IMFContentEnabler* content_enabler, @@ -103,6 +107,68 @@ MOCK_STDCALL_METHOD0(Remove, HRESULT()); }; +class MockMFExtendedDRMTypeSupport + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, + IMFExtendedDRMTypeSupport> { + public: + MockMFExtendedDRMTypeSupport(); + ~MockMFExtendedDRMTypeSupport() override; + + // IMFExtendedDRMTypeSupport methods + MOCK_STDCALL_METHOD3(IsTypeSupportedEx, + HRESULT(BSTR type, + BSTR keySystem, + MF_MEDIA_ENGINE_CANPLAY* pAnswer)); +}; + +class MockMFGetService + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, + IMFGetService> { + public: + MockMFGetService(); + ~MockMFGetService() override; + + // IMFGetService methods + MOCK_STDCALL_METHOD3(GetService, + HRESULT(REFGUID guidService, + REFIID riid, + LPVOID* ppvObject)); +}; + +class MockMFPMPHost + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, + IMFPMPHost> { + public: + MockMFPMPHost(); + ~MockMFPMPHost() override; + + // IMFPMPHost methods + MOCK_STDCALL_METHOD0(LockProcess, HRESULT()); + MOCK_STDCALL_METHOD0(UnlockProcess, HRESULT()); + MOCK_STDCALL_METHOD4( + CreateObjectByCLSID, + HRESULT(REFCLSID clsid, IStream* pStream, REFIID riid, void** ppv)); +}; + +class MockMFPMPHostApp + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, + IMFPMPHostApp> { + public: + MockMFPMPHostApp(); + ~MockMFPMPHostApp() override; + + // IMFPMPHostApp methods + MOCK_STDCALL_METHOD0(LockProcess, HRESULT()); + MOCK_STDCALL_METHOD0(UnlockProcess, HRESULT()); + MOCK_STDCALL_METHOD4( + ActivateClassById, + HRESULT(LPCWSTR id, IStream* pStream, REFIID riid, void** ppv)); +}; + } // namespace media #endif // MEDIA_BASE_WIN_MF_MOCKS_H_
diff --git a/media/cdm/BUILD.gn b/media/cdm/BUILD.gn index 29cb46b..f56907b 100644 --- a/media/cdm/BUILD.gn +++ b/media/cdm/BUILD.gn
@@ -257,6 +257,7 @@ "win/media_foundation_cdm_factory_unittest.cc", "win/media_foundation_cdm_session_unittest.cc", "win/media_foundation_cdm_unittest.cc", + "win/media_foundation_cdm_util_unittest.cc", ] } }
diff --git a/media/cdm/win/media_foundation_cdm_factory.cc b/media/cdm/win/media_foundation_cdm_factory.cc index eead4cd..9bdd8a2 100644 --- a/media/cdm/win/media_foundation_cdm_factory.cc +++ b/media/cdm/win/media_foundation_cdm_factory.cc
@@ -38,6 +38,23 @@ base::UTF8ToWide(content_type).c_str()); } +bool IsTypeSupportedInternalEx(const std::string& key_system, + const std::string& content_type) { + ComPtr<IMFExtendedDRMTypeSupport> mf_type_support; + HRESULT hr = + CoCreateInstance(CLSID_MFMediaEngineClassFactory, nullptr, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&mf_type_support)); + if (FAILED(hr)) { + DLOG(ERROR) << __func__ + << ": Failed to create class factory for IsTypeSupportedEx. hr=" + << hr; + return false; + } + + return IsMediaFoundationContentTypeSupported(mf_type_support, key_system, + content_type); +} + crash_reporter::CrashKeyString<256> g_origin_crash_key("cdm-origin"); } // namespace @@ -169,6 +186,16 @@ const std::string& key_system, const std::string& content_type, IsTypeSupportedResultCB is_type_supported_result_cb) { + // Note that IsTypeSupported may take up to 10s, so run it on a separate + // thread to unblock the main thread. + if (MediaFoundationCdmModule::GetInstance()->IsOsCdm()) { + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce(&IsTypeSupportedInternalEx, key_system, content_type), + std::move(is_type_supported_result_cb)); + return; + } + ComPtr<IMFContentDecryptionModuleFactory> cdm_factory; HRESULT hr = GetCdmFactory(key_system, cdm_factory); if (FAILED(hr)) { @@ -177,8 +204,6 @@ return; } - // Note that IsTypeSupported may take up to 10s, so run it on a separate - // thread to unblock the main thread. base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, base::BindOnce(&IsTypeSupportedInternal, cdm_factory, key_system,
diff --git a/media/cdm/win/media_foundation_cdm_unittest.cc b/media/cdm/win/media_foundation_cdm_unittest.cc index e8dd45c6..7d8c2f53 100644 --- a/media/cdm/win/media_foundation_cdm_unittest.cc +++ b/media/cdm/win/media_foundation_cdm_unittest.cc
@@ -463,6 +463,9 @@ Initialize(); CreateSessionAndGenerateRequest(); + COM_EXPECT_CALL(mf_cdm_, QueryInterface(IID_IMFAttributes, _)) + .WillOnce(Return(E_FAIL)); + std::vector<uint8_t> response = StringToVector("response"); COM_EXPECT_CALL(mf_cdm_session_, Update(NotNull(), response.size())) .WillOnce(DoAll([&] { mf_cdm_session_callbacks_->KeyStatusChanged(); },
diff --git a/media/cdm/win/media_foundation_cdm_util.cc b/media/cdm/win/media_foundation_cdm_util.cc index b69905b7..4f65bfa 100644 --- a/media/cdm/win/media_foundation_cdm_util.cc +++ b/media/cdm/win/media_foundation_cdm_util.cc
@@ -15,6 +15,7 @@ #include "base/not_fatal_until.h" #include "base/strings/utf_string_conversions.h" #include "base/win/propvarutil.h" +#include "base/win/scoped_bstr.h" #include "base/win/scoped_propvariant.h" #include "media/base/win/mf_helpers.h" #include "media/cdm/cdm_paths.h" @@ -251,4 +252,48 @@ return S_OK; } +bool IsMediaFoundationContentTypeSupported( + Microsoft::WRL::ComPtr<IMFExtendedDRMTypeSupport> mf_type_support, + const std::string& key_system, + const std::string& content_type) { + DCHECK(!key_system.empty()); + DCHECK(!content_type.empty()); + + if (key_system.empty() || content_type.empty()) { + DLOG(ERROR) << __func__ << ": key_system or content_type is empty"; + return false; + } + + // `IMFContentDecryptionModuleFactory::IsTypeSupported()` returns + // 'supported' for OS PlayReady backed implementation regardless of the + // value passed in for the `contentType` parameter. Use + // IMFExtendedDRMTypeSupport::IsTypeSupportedEx() instead. + MF_MEDIA_ENGINE_CANPLAY answer = MF_MEDIA_ENGINE_CANPLAY_NOT_SUPPORTED; + base::win::ScopedBstr key_system_bstr(base::UTF8ToWide(key_system).c_str()); + base::win::ScopedBstr query(base::UTF8ToWide(content_type).c_str()); + + const int kMaxRetryCount = 5; + for (int retry = 0; retry < kMaxRetryCount; ++retry) { + // IsTypeSupportedEx returns "MAYBE" for HDCP queries while + // HDCP is being established. If the answer is "Maybe" then + // try again once per second for a total of 5 seconds. + HRESULT hr = mf_type_support->IsTypeSupportedEx( + query.Get(), key_system_bstr.Get(), &answer); + + if (FAILED(hr)) { + DLOG(ERROR) << __func__ << ": type_query support failed. hr=" << hr; + return false; + } else if (answer != MF_MEDIA_ENGINE_CANPLAY_MAYBE) { + break; + } + + DVLOG(2) << "IsTypeSupportedEx() returned MAYBE; wait for negotiation..."; + base::PlatformThread::Sleep(base::Seconds(1)); + } + + DVLOG(2) << __func__ << ": answer=" << answer << ", " << key_system << ", " + << content_type; + return (answer == MF_MEDIA_ENGINE_CANPLAY_PROBABLY); +} + } // namespace media
diff --git a/media/cdm/win/media_foundation_cdm_util.h b/media/cdm/win/media_foundation_cdm_util.h index 779a8b7..cf6a90a3 100644 --- a/media/cdm/win/media_foundation_cdm_util.h +++ b/media/cdm/win/media_foundation_cdm_util.h
@@ -27,6 +27,11 @@ const base::FilePath& cdm_store_path_root, Microsoft::WRL::ComPtr<IMFContentDecryptionModule>& mf_cdm); +MEDIA_EXPORT bool IsMediaFoundationContentTypeSupported( + Microsoft::WRL::ComPtr<IMFExtendedDRMTypeSupport> mf_type_support, + const std::string& key_system, + const std::string& content_type); + } // namespace media #endif // MEDIA_CDM_WIN_MEDIA_FOUNDATION_CDM_UTIL_H_
diff --git a/media/cdm/win/media_foundation_cdm_util_unittest.cc b/media/cdm/win/media_foundation_cdm_util_unittest.cc new file mode 100644 index 0000000..2083667 --- /dev/null +++ b/media/cdm/win/media_foundation_cdm_util_unittest.cc
@@ -0,0 +1,307 @@ +// 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 "media/cdm/win/media_foundation_cdm_util.h" + +#include <Mferror.h> + +#include "base/strings/utf_string_conversions.h" +#include "base/test/task_environment.h" +#include "base/win/scoped_bstr.h" +#include "base/win/scoped_com_initializer.h" +#include "media/base/win/mf_helpers.h" +#include "media/base/win/mf_mocks.h" +#include "media/cdm/win/media_foundation_cdm_module.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using Microsoft::WRL::ComPtr; +using ::testing::_; +using ::testing::DoAll; +using ::testing::InSequence; +using ::testing::NotNull; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::StrictMock; + +namespace media { + +namespace { + +const char kTestKeySystem[] = "com.example.test.key.system"; +const char kTestContentType[] = "video/mp4;codecs=\"avc1.4d401e\""; +const CdmConfig kTestCdmConfig = { + kTestKeySystem, // key_system + true, // allow_distinctive_identifier + true, // allow_persistent_state + true // use_hw_secure_codecs +}; +const base::UnguessableToken kTestOriginId = base::UnguessableToken::Create(); +const base::FilePath kTestStorePath(FILE_PATH_LITERAL("C:\\test\\store\\path")); + +} // namespace + +class IsMediaFoundationContentTypeSupportedTest : public testing::Test { + public: + IsMediaFoundationContentTypeSupportedTest() + : mf_type_support_(MakeComPtr<MockMFExtendedDRMTypeSupport>()) {} + + ~IsMediaFoundationContentTypeSupportedTest() override = default; + + protected: + ComPtr<MockMFExtendedDRMTypeSupport> mf_type_support_; +}; + +TEST_F(IsMediaFoundationContentTypeSupportedTest, Probably) { + COM_EXPECT_CALL(mf_type_support_, IsTypeSupportedEx(_, _, _)) + .WillOnce(DoAll(SetArgPointee<2>(MF_MEDIA_ENGINE_CANPLAY_PROBABLY), + Return(S_OK))); + + bool result = IsMediaFoundationContentTypeSupported( + mf_type_support_, kTestKeySystem, kTestContentType); + + EXPECT_TRUE(result); +} + +TEST_F(IsMediaFoundationContentTypeSupportedTest, NotSupported) { + COM_EXPECT_CALL(mf_type_support_, IsTypeSupportedEx(_, _, _)) + .WillOnce(DoAll(SetArgPointee<2>(MF_MEDIA_ENGINE_CANPLAY_NOT_SUPPORTED), + Return(S_OK))); + + bool result = IsMediaFoundationContentTypeSupported( + mf_type_support_, kTestKeySystem, kTestContentType); + + EXPECT_FALSE(result); +} + +TEST_F(IsMediaFoundationContentTypeSupportedTest, Maybe) { + // Set up the mock to return MAYBE for each call, + // simulating ongoing HDCP negotiation + COM_EXPECT_CALL(mf_type_support_, IsTypeSupportedEx(_, _, _)) + .Times(5) + .WillRepeatedly( + DoAll(SetArgPointee<2>(MF_MEDIA_ENGINE_CANPLAY_MAYBE), Return(S_OK))); + + // The method should retry the maximum number of times and then return false + bool result = IsMediaFoundationContentTypeSupported( + mf_type_support_, kTestKeySystem, kTestContentType); + + // After only receiving MAYBE responses, the method should return false + EXPECT_FALSE(result); +} + +TEST_F(IsMediaFoundationContentTypeSupportedTest, MaybeAndThenProbably) { + // Set up expectations in sequence + { + InSequence seq; + // First call returns MAYBE + COM_EXPECT_CALL(mf_type_support_, IsTypeSupportedEx(_, _, _)) + .WillOnce(DoAll(SetArgPointee<2>(MF_MEDIA_ENGINE_CANPLAY_MAYBE), + Return(S_OK))); + + // Second call returns PROBABLY + COM_EXPECT_CALL(mf_type_support_, IsTypeSupportedEx(_, _, _)) + .WillOnce(DoAll(SetArgPointee<2>(MF_MEDIA_ENGINE_CANPLAY_PROBABLY), + Return(S_OK))); + } + + bool result = IsMediaFoundationContentTypeSupported( + mf_type_support_, kTestKeySystem, kTestContentType); + + EXPECT_TRUE(result); +} + +TEST_F(IsMediaFoundationContentTypeSupportedTest, Failure) { + COM_EXPECT_CALL(mf_type_support_, IsTypeSupportedEx(_, _, _)) + .WillOnce(Return(E_FAIL)); + + bool result = IsMediaFoundationContentTypeSupported( + mf_type_support_, kTestKeySystem, kTestContentType); + + EXPECT_FALSE(result); +} + +class CreateMediaFoundationCdmTest : public testing::Test { + public: + CreateMediaFoundationCdmTest() + : mf_cdm_factory_(MakeComPtr<MockMFCdmFactory>()), + mf_cdm_access_(MakeComPtr<MockMFCdmAccess>()), + mf_cdm_(MakeComPtr<MockMFCdm>()), + mf_get_service_(MakeComPtr<MockMFGetService>()), + mf_pmp_host_(MakeComPtr<MockMFPMPHost>()), + mf_pmp_host_app_(MakeComPtr<MockMFPMPHostApp>()) {} + + ~CreateMediaFoundationCdmTest() override = default; + + void SetUpMockCdmFactoryExpectations(bool support_key_system) { + COM_EXPECT_CALL(mf_cdm_factory_, IsTypeSupported(_, nullptr)) + .WillOnce(Return(support_key_system ? TRUE : FALSE)); + } + + void SetUpMockCdmAccessExpectations(bool success) { + HRESULT hr = success ? S_OK : E_FAIL; + COM_EXPECT_CALL(mf_cdm_factory_, CreateContentDecryptionModuleAccess( + NotNull(), NotNull(), _, _)) + .WillOnce(DoAll(SetComPointee<3>(mf_cdm_access_.Get()), Return(hr))); + + if (success) { + COM_EXPECT_CALL(mf_cdm_access_, CreateContentDecryptionModule(_, _)) + .WillOnce(DoAll(SetComPointee<1>(mf_cdm_.Get()), Return(S_OK))); + } + } + + void SetUpOsCdmExpectations(bool with_pmp_host) { + MediaFoundationCdmModule::GetInstance()->SetIsOsCdmForTesting(true); + { + // Setup expectations to simulate OS CDM + InSequence seq; + + COM_ON_CALL(mf_cdm_, QueryInterface(IID_IMFGetService, _)) + .WillByDefault(SetComPointeeAndReturnOk<1>(mf_get_service_.Get())); + + if (with_pmp_host) { + COM_EXPECT_CALL(mf_get_service_, GetService(_, IID_IMFPMPHost, _)) + .WillOnce( + DoAll(SetComPointee<2>(mf_pmp_host_.Get()), Return(S_OK))); + + COM_EXPECT_CALL(mf_cdm_, SetPMPHostApp(_)).WillOnce(Return(S_OK)); + } else { + COM_EXPECT_CALL(mf_get_service_, GetService(_, IID_IMFPMPHost, _)) + .WillOnce(Return(E_NOINTERFACE)); + + COM_EXPECT_CALL(mf_get_service_, GetService(_, IID_IMFPMPHostApp, _)) + .WillOnce( + DoAll(SetComPointee<2>(mf_pmp_host_app_.Get()), Return(S_OK))); + + COM_EXPECT_CALL(mf_cdm_, SetPMPHostApp(_)).WillOnce(Return(S_OK)); + } + } + } + + protected: + ComPtr<MockMFCdmFactory> mf_cdm_factory_; + ComPtr<MockMFCdmAccess> mf_cdm_access_; + ComPtr<MockMFCdm> mf_cdm_; + ComPtr<MockMFGetService> mf_get_service_; + ComPtr<MockMFPMPHost> mf_pmp_host_; + ComPtr<MockMFPMPHostApp> mf_pmp_host_app_; + + base::win::ScopedCOMInitializer com_initializer_; +}; + +TEST_F(CreateMediaFoundationCdmTest, Success) { + SetUpMockCdmFactoryExpectations(true); + SetUpMockCdmAccessExpectations(true); + MediaFoundationCdmModule::GetInstance()->SetIsOsCdmForTesting(false); + + ComPtr<IMFContentDecryptionModule> result_cdm; + HRESULT hr = + CreateMediaFoundationCdm(mf_cdm_factory_, kTestCdmConfig, kTestOriginId, + std::nullopt, kTestStorePath, result_cdm); + + EXPECT_EQ(hr, S_OK); + EXPECT_EQ(result_cdm.Get(), mf_cdm_.Get()); +} + +TEST_F(CreateMediaFoundationCdmTest, KeySystemNotSupported) { + // Set up mock to indicate key system not supported + SetUpMockCdmFactoryExpectations(false); + + ComPtr<IMFContentDecryptionModule> result_cdm; + HRESULT hr = + CreateMediaFoundationCdm(mf_cdm_factory_, kTestCdmConfig, kTestOriginId, + std::nullopt, kTestStorePath, result_cdm); + + EXPECT_EQ(hr, (HRESULT)MF_NOT_SUPPORTED_ERR); + EXPECT_EQ(result_cdm.Get(), nullptr); +} + +TEST_F(CreateMediaFoundationCdmTest, CreateAccessFailed) { + // Set up mock to indicate key system supported but CDM access creation fails + SetUpMockCdmFactoryExpectations(true); + COM_EXPECT_CALL(mf_cdm_factory_, + CreateContentDecryptionModuleAccess(_, _, _, _)) + .WillOnce(Return(E_FAIL)); + + ComPtr<IMFContentDecryptionModule> result_cdm; + HRESULT hr = + CreateMediaFoundationCdm(mf_cdm_factory_, kTestCdmConfig, kTestOriginId, + std::nullopt, kTestStorePath, result_cdm); + + EXPECT_EQ(hr, E_FAIL); + EXPECT_EQ(result_cdm.Get(), nullptr); +} + +TEST_F(CreateMediaFoundationCdmTest, CreateCdmFailed) { + // Set up mock for successful key system support and CDM access creation + SetUpMockCdmFactoryExpectations(true); + + COM_EXPECT_CALL(mf_cdm_factory_, + CreateContentDecryptionModuleAccess(_, _, _, _)) + .WillOnce(DoAll(SetComPointee<3>(mf_cdm_access_.Get()), Return(S_OK))); + + COM_EXPECT_CALL(mf_cdm_access_, CreateContentDecryptionModule(_, _)) + .WillOnce(Return(E_FAIL)); + + ComPtr<IMFContentDecryptionModule> result_cdm; + HRESULT hr = + CreateMediaFoundationCdm(mf_cdm_factory_, kTestCdmConfig, kTestOriginId, + std::nullopt, kTestStorePath, result_cdm); + + EXPECT_EQ(hr, E_FAIL); + EXPECT_EQ(result_cdm.Get(), nullptr); +} + +TEST_F(CreateMediaFoundationCdmTest, OsCdmWithPmpHost) { + // Set up mock for successful CDM creation + SetUpMockCdmFactoryExpectations(true); + SetUpMockCdmAccessExpectations(true); + + // Set up OS CDM with PMPHost expectations + SetUpOsCdmExpectations(true); + + ComPtr<IMFContentDecryptionModule> result_cdm; + HRESULT hr = + CreateMediaFoundationCdm(mf_cdm_factory_, kTestCdmConfig, kTestOriginId, + std::nullopt, kTestStorePath, result_cdm); + + EXPECT_EQ(hr, S_OK); + EXPECT_EQ(result_cdm.Get(), mf_cdm_.Get()); +} + +TEST_F(CreateMediaFoundationCdmTest, OsCdmWithPmpHostApp) { + // Set up mock for successful CDM creation + SetUpMockCdmFactoryExpectations(true); + SetUpMockCdmAccessExpectations(true); + + // Set up OS CDM with PMPHostApp expectations + SetUpOsCdmExpectations(false); + + ComPtr<IMFContentDecryptionModule> result_cdm; + HRESULT hr = + CreateMediaFoundationCdm(mf_cdm_factory_, kTestCdmConfig, kTestOriginId, + std::nullopt, kTestStorePath, result_cdm); + + EXPECT_EQ(hr, S_OK); + EXPECT_EQ(result_cdm.Get(), mf_cdm_.Get()); +} + +TEST_F(CreateMediaFoundationCdmTest, WithClientToken) { + // Set up mock for successful CDM creation + SetUpMockCdmFactoryExpectations(true); + SetUpMockCdmAccessExpectations(true); + MediaFoundationCdmModule::GetInstance()->SetIsOsCdmForTesting(false); + + std::vector<uint8_t> client_token = {1, 2, 3, 4, 5}; + + ComPtr<IMFContentDecryptionModule> result_cdm; + HRESULT hr = + CreateMediaFoundationCdm(mf_cdm_factory_, kTestCdmConfig, kTestOriginId, + client_token, kTestStorePath, result_cdm); + + EXPECT_EQ(hr, S_OK); + EXPECT_EQ(result_cdm.Get(), mf_cdm_.Get()); +} + +} // namespace media
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 2c6c0e3..ff199ef 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc
@@ -673,9 +673,9 @@ // below. Only the first buffer should have discard padding. // Note: Some packets marked for total discard have their `start_padding` set // to kInfiniteDuration. Ignore these packets. - if (first_valid_frame_timestamp_ == kNoTimestamp && + if (!initial_start_padding_.has_value() && start_padding != kInfiniteDuration) { - first_valid_frame_timestamp_ = buffer->timestamp() + start_padding; + initial_start_padding_ = start_padding; } last_packet_timestamp_ = buffer->timestamp(); @@ -684,14 +684,10 @@ // Check if `buffer` contains only padding. const bool is_padding = buffer->duration() == start_padding + end_padding; - // Don't adjust for `first_valid_frame_timestamp_` if we don't have a valid - // timestamp yet. Otherwise, we end up with an infinite `new_duration`. - const base::TimeDelta base_timestamp = - first_valid_frame_timestamp_ == kNoTimestamp - ? base::TimeDelta() - : first_valid_frame_timestamp_; + const base::TimeDelta new_duration = + last_packet_timestamp_ - + initial_start_padding_.value_or(base::TimeDelta()); - const base::TimeDelta new_duration = last_packet_timestamp_ - base_timestamp; if ((!is_padding && new_duration > duration_) || duration_ == kNoTimestamp) { duration_ = new_duration; }
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h index 64dc64c1..a7aa7028 100644 --- a/media/filters/ffmpeg_demuxer.h +++ b/media/filters/ffmpeg_demuxer.h
@@ -26,6 +26,7 @@ #include <stdint.h> #include <memory> +#include <optional> #include <string> #include <vector> @@ -171,12 +172,12 @@ scoped_refptr<base::SequencedTaskRunner> task_runner_; raw_ptr<AVStream> stream_; base::TimeDelta start_time_; + std::optional<base::TimeDelta> initial_start_padding_; std::unique_ptr<AudioDecoderConfig> audio_config_; std::unique_ptr<VideoDecoderConfig> video_config_; raw_ptr<MediaLog> media_log_; Type type_ = UNKNOWN; StreamLiveness liveness_ = StreamLiveness::kUnknown; - base::TimeDelta first_valid_frame_timestamp_ = kNoTimestamp; base::TimeDelta duration_; bool end_of_stream_; base::TimeDelta last_packet_timestamp_;
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc index f2b41158..fba6aead 100644 --- a/media/filters/ffmpeg_demuxer_unittest.cc +++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -900,6 +900,38 @@ verify_finite_duration(GetStream(DemuxerStream::AUDIO)); verify_finite_duration(GetStream(DemuxerStream::VIDEO)); } + +TEST_F(FFmpegDemuxerTest, Read_LargeStartTime_DurationUpdates) { + // This file is poorly muxed, but useful as a regression test. It has an + // initial duration of 10s, contains 20s of video data, starts at a timestamp + // of 10s, and (surprisingly) ends at ~20s. + // Reading from this stream should update the duration. + CreateDemuxer("mid-file-start-time.mp4"); + InitializeDemuxer(); + + auto* stream = + reinterpret_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::VIDEO)); + + auto inital_duration = stream->duration(); + ASSERT_GT(inital_duration, base::Seconds(9)); + ASSERT_LT(inital_duration, base::Seconds(11)); + + // The final duration of the file after reading all packets is just below 20s. + const base::TimeDelta target_duration = base::Seconds(19); + + int remaining_reads = 300; + while (remaining_reads-- > 0 && stream->duration() < target_duration) { + base::RunLoop loop; + stream->Read(1, base::BindLambdaForTesting( + [&](DemuxerStream::Status status, + DemuxerStream::DecoderBufferVector buffers) { + loop.QuitWhenIdle(); + })); + loop.Run(); + } + + EXPECT_GT(stream->duration(), target_duration); +} #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) // Similar to the test above, but using sfx-opus.ogg, which has a much smaller
diff --git a/media/mojo/mojom/BUILD.gn b/media/mojo/mojom/BUILD.gn index bbc8b7d..d9ef913 100644 --- a/media/mojo/mojom/BUILD.gn +++ b/media/mojo/mojom/BUILD.gn
@@ -1004,6 +1004,7 @@ ":speech_recognition_recognition_context", "//base", "//base/test:test_support", + "//gpu:test_support", "//media:test_support", "//media/mojo:test_support", "//mojo/public/cpp/test_support:test_utils",
diff --git a/media/mojo/mojom/speech_recognition_error_code.mojom b/media/mojo/mojom/speech_recognition_error_code.mojom index f84f531..d9d189a0 100644 --- a/media/mojo/mojom/speech_recognition_error_code.mojom +++ b/media/mojo/mojom/speech_recognition_error_code.mojom
@@ -20,5 +20,5 @@ kBadGrammar, kLanguageNotSupported, kNoMatch, - [MinVersion=1] kRecognitionContextNotSupported, + [MinVersion=1] kPhrasesNotSupported, };
diff --git a/media/mojo/mojom/video_frame_mojom_traits_unittest.cc b/media/mojo/mojom/video_frame_mojom_traits_unittest.cc index 4c1709c..e3270a77 100644 --- a/media/mojo/mojom/video_frame_mojom_traits_unittest.cc +++ b/media/mojo/mojom/video_frame_mojom_traits_unittest.cc
@@ -18,6 +18,7 @@ #include "base/numerics/safe_conversions.h" #include "base/test/task_environment.h" #include "build/build_config.h" +#include "gpu/command_buffer/client/test_shared_image_interface.h" #include "gpu/command_buffer/common/mailbox.h" #include "gpu/command_buffer/common/mailbox_holder.h" #include "gpu/command_buffer/common/sync_token.h" @@ -25,7 +26,6 @@ #include "media/base/video_frame.h" #include "media/base/video_frame_layout.h" #include "media/mojo/mojom/traits_test_service.test-mojom.h" -#include "media/video/fake_gpu_memory_buffer.h" #include "mojo/public/cpp/bindings/message.h" #include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/remote.h" @@ -636,44 +636,36 @@ } #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) -// BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) because -// media::FakeGpuMemoryBuffer supports NativePixmapHandle backed -// GpuMemoryBufferHandle only. !BUILDFLAG(IS_OZONE) so as to force -// GpuMemoryBufferSupport to select gfx::ClientNativePixmapFactoryDmabuf for -// gfx::ClientNativePixmapFactory. -// TODO(crbug.com/40286368): Allow this test without !BUILDFLAG(IS_OZONE) -#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && !BUILDFLAG(IS_OZONE) -TEST_F(VideoFrameStructTraitsTest, GpuMemoryBufferSharedImageVideoFrame) { +TEST_F(VideoFrameStructTraitsTest, MappableSharedImageVideoFrame) { + auto test_sii = base::MakeRefCounted<gpu::TestSharedImageInterface>(); + test_sii->UseTestGMBInSharedImageCreationWithBufferUsage(); gfx::Size coded_size = gfx::Size(256, 256); gfx::Rect visible_rect(coded_size); auto timestamp = base::Milliseconds(1); - std::unique_ptr<gfx::GpuMemoryBuffer> gmb = - std::make_unique<FakeGpuMemoryBuffer>( - coded_size, gfx::BufferFormat::YUV_420_BIPLANAR); - gfx::BufferFormat expected_gmb_format = gmb->GetFormat(); - gfx::Size expected_gmb_size = gmb->GetSize(); - scoped_refptr<gpu::ClientSharedImage> shared_image = - gpu::ClientSharedImage::CreateForTesting(); - auto frame = VideoFrame::WrapExternalGpuMemoryBuffer( - visible_rect, visible_rect.size(), std::move(gmb), shared_image, - gpu::SyncToken(), base::NullCallback(), timestamp); + auto si_format = viz::SinglePlaneFormat::kRGBA_8888; + const auto si_usage = gpu::SHARED_IMAGE_USAGE_CPU_WRITE_ONLY | + gpu::SHARED_IMAGE_USAGE_DISPLAY_READ; + auto shared_image = test_sii->CreateSharedImage( + {si_format, coded_size, gfx::ColorSpace(), + gpu::SharedImageUsageSet(si_usage), "VideoFrameStructTraitsTest"}, + gpu::kNullSurfaceHandle, gfx::BufferUsage::GPU_READ); + ASSERT_TRUE(shared_image); + auto frame = VideoFrame::WrapMappableSharedImage( + shared_image, test_sii->GenVerifiedSyncToken(), base::NullCallback(), + visible_rect, visible_rect.size(), timestamp); + ASSERT_TRUE(frame); ASSERT_TRUE(RoundTrip(&frame)); ASSERT_TRUE(frame); ASSERT_EQ(frame->storage_type(), VideoFrame::STORAGE_GPU_MEMORY_BUFFER); EXPECT_TRUE(frame->HasMappableGpuBuffer()); EXPECT_FALSE(frame->metadata().end_of_stream); - EXPECT_EQ(frame->format(), PIXEL_FORMAT_NV12); + EXPECT_EQ(frame->format(), PIXEL_FORMAT_ABGR); EXPECT_EQ(frame->coded_size(), coded_size); EXPECT_EQ(frame->visible_rect(), visible_rect); EXPECT_EQ(frame->natural_size(), visible_rect.size()); EXPECT_EQ(frame->timestamp(), timestamp); ASSERT_TRUE(frame->HasSharedImage()); - EXPECT_EQ(frame->mailbox_holder(0).mailbox, shared_image->mailbox()); - EXPECT_EQ(frame->GetGpuMemoryBufferForTesting()->GetFormat(), - expected_gmb_format); - EXPECT_EQ(frame->GetGpuMemoryBufferForTesting()->GetSize(), - expected_gmb_size); + ASSERT_EQ(frame->shared_image()->mailbox(), shared_image->mailbox()); } -#endif // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && - // !BUILDFLAG(IS_OZONE) + } // namespace media
diff --git a/media/mojo/services/media_foundation_service.cc b/media/mojo/services/media_foundation_service.cc index 43e289e..bff4dbb5 100644 --- a/media/mojo/services/media_foundation_service.cc +++ b/media/mojo/services/media_foundation_service.cc
@@ -64,6 +64,9 @@ const char kSwSecureRobustness[] = "SW_SECURE_DECODE"; const char kHwSecureRobustness[] = "HW_SECURE_ALL"; +const char kPlayReadyKeySystemRecommendationHwSecure[] = + "com.microsoft.playready.recommendation.3000"; + // The followings define the supported codecs and encryption schemes that we try // to query. constexpr VideoCodec kAllVideoCodecs[] = { @@ -124,6 +127,15 @@ return supported; } +bool IsTypeSupportedInternalEx( + ComPtr<IMFExtendedDRMTypeSupport> mf_type_support, + const std::string& key_system, + bool is_hw_secure, + const std::string& content_type) { + return IsMediaFoundationContentTypeSupported(mf_type_support, key_system, + content_type); +} + std::string GetFourCCString(VideoCodec codec) { switch (codec) { case VideoCodec::kH264: @@ -234,10 +246,13 @@ IsTypeSupportedCallback is_type_supported_cb) { base::flat_set<EncryptionScheme> supported_schemes; for (const auto scheme : kAllEncryptionSchemes) { - const FeatureMap extra_features = { + FeatureMap extra_features = { {kEncryptionSchemeQueryName, GetName(scheme)}, - {kEncryptionIvQueryName, base::NumberToString(GetIvSize(scheme))}, - {kRobustnessQueryName, robustness.c_str()}}; + {kEncryptionIvQueryName, base::NumberToString(GetIvSize(scheme))}}; + + if (!robustness.empty()) { + extra_features.insert({kRobustnessQueryName, robustness}); + } if (is_type_supported_cb.Run( is_hw_secure, @@ -266,9 +281,12 @@ // C:\Users\<user>\AppData\Local\Packages\cr.sb.cdm<...>\AC\Temp // This folder is specifically for the CDM app container, so there's no need // to set ACL explicitly. + // Use a short name for the store path to help avoid hitting the MAX_PATH + // limitation. Note, this won't fix all scenarios since the path is still + // dependent on the username length. base::FilePath temp_dir; base::PathService::Get(base::DIR_TEMP, &temp_dir); - const char kDummyCdmStore[] = "DummyMediaFoundationCdmStore"; + const char kDummyCdmStore[] = "DummyCdm"; auto dummy_cdm_store_path_root = temp_dir.AppendASCII(kDummyCdmStore); // Create the dummy CDM. @@ -305,6 +323,7 @@ ComPtr<IMFContentDecryptionModuleFactory> cdm_factory, const std::string& key_system, bool is_hw_secure, + bool is_os_cdm, IsTypeSupportedCallback is_type_supported_cb) { DVLOG(2) << __func__ << ": key_system=" << key_system << ", is_hw_secure=" << is_hw_secure; @@ -324,9 +343,16 @@ CdmCapabilityQueryStatus::kCreateDummyMediaFoundationCdmFailed); } - // TODO(hmchen): make this generic for more key systems. - const std::string robustness = - is_hw_secure ? kHwSecureRobustness : kSwSecureRobustness; + std::string robustness; + FeatureMap extra_features = {}; + + if (!is_os_cdm) { + // TODO(hmchen): make this generic for more key systems. + robustness = is_hw_secure ? kHwSecureRobustness : kSwSecureRobustness; + + // encryption-robustness is not a supported for PlayReady key systems. + extra_features.insert({{kRobustnessQueryName, robustness}}); + } CdmCapability capability; @@ -348,8 +374,6 @@ } #endif - const FeatureMap extra_features = {{kRobustnessQueryName, robustness}}; - if (is_type_supported_cb.Run( is_hw_secure, GetTypeString(video_codec, /*audio_codec=*/std::nullopt, @@ -397,7 +421,6 @@ // supported video codecs> + <audio codec> to query the audio capability. for (const auto audio_codec : kAllAudioCodecs) { const auto& video_codec = capability.video_codecs.begin()->first; - const FeatureMap extra_features = {{kRobustnessQueryName, robustness}}; if (is_type_supported_cb.Run( is_hw_secure, @@ -440,8 +463,9 @@ } // namespace MediaFoundationService::MediaFoundationService( + bool is_os_cdm, mojo::PendingReceiver<mojom::MediaFoundationService> receiver) - : receiver_(this, std::move(receiver)) { + : receiver_(this, std::move(receiver)), is_os_cdm_(is_os_cdm) { DVLOG(1) << __func__; mojo_media_client_.Initialize(); } @@ -477,12 +501,45 @@ return; } + IsTypeSupportedCallback is_type_supported_cb; + + if (is_os_cdm_) { + // `IMFContentDecryptionModuleFactory::IsTypeSupported()` returns + // 'supported' for OS PlayReady backed implementation regardless of the + // value passed in for the `contentType` parameter. Use + // IMFExtendedDRMTypeSupport::IsTypeSupportedEx() instead. + ComPtr<IMFExtendedDRMTypeSupport> mf_type_support; + HRESULT hr = + CoCreateInstance(CLSID_MFMediaEngineClassFactory, nullptr, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&mf_type_support)); + if (FAILED(hr)) { + DLOG(ERROR) << __func__ + << ": Failed to create class factory for " + "IMFExtendedDRMTypeSupport::IsTypeSupportedEx. hr=" + << hr; + std::move(callback).Run( + false, KeySystemCapability( + // TODO(crbug.com/384962301): need better error codes here. + base::unexpected(CdmCapabilityQueryStatus::kUnknown), + base::unexpected(CdmCapabilityQueryStatus::kUnknown))); + return; + } + + // Force the use of the hardware based PlayReady key system. + is_type_supported_cb = + base::BindRepeating(&IsTypeSupportedInternalEx, mf_type_support, + kPlayReadyKeySystemRecommendationHwSecure); + } else { + is_type_supported_cb = + base::BindRepeating(&IsTypeSupportedInternal, cdm_factory, key_system); + } + // Use empty software secure capability as it is not used. auto sw_cdm_capability_or_status = base::unexpected(CdmCapabilityQueryStatus::kNoSupportedVideoCodec); - auto hw_cdm_capability_or_status = GetCdmCapability( - cdm_factory, key_system, /*is_hw_secure=*/true, - base::BindRepeating(&IsTypeSupportedInternal, cdm_factory, key_system)); + auto hw_cdm_capability_or_status = + GetCdmCapability(cdm_factory, key_system, /*is_hw_secure=*/true, + is_os_cdm_, is_type_supported_cb); auto key_system_capability = KeySystemCapability(sw_cdm_capability_or_status, hw_cdm_capability_or_status); if (!key_system_capability.sw_cdm_capability_or_status.has_value() &&
diff --git a/media/mojo/services/media_foundation_service.h b/media/mojo/services/media_foundation_service.h index 6ee6eeb..1d8864ec 100644 --- a/media/mojo/services/media_foundation_service.h +++ b/media/mojo/services/media_foundation_service.h
@@ -30,6 +30,7 @@ // `ensure_sandboxed_cb` must be called after necessary initialization to // ensure the process is sandboxed. explicit MediaFoundationService( + bool is_os_cdm, mojo::PendingReceiver<mojom::MediaFoundationService> receiver); MediaFoundationService(const MediaFoundationService&) = delete; MediaFoundationService operator=(const MediaFoundationService&) = delete; @@ -51,6 +52,11 @@ // IMFContentDecryptionModule implementations typically require MTA to run. base::win::ScopedCOMInitializer com_initializer_{ base::win::ScopedCOMInitializer::kMTA}; + + // An OS CDM is a CDM that is implemented by the OS, such as PlayReady. + // This type of CDM does not usually have a CDM path since the implementation + // is usually provided by the OS through a particular framework. + bool is_os_cdm_; }; } // namespace media
diff --git a/media/mojo/services/media_foundation_service_broker.cc b/media/mojo/services/media_foundation_service_broker.cc index 98fa45f..74d6486 100644 --- a/media/mojo/services/media_foundation_service_broker.cc +++ b/media/mojo/services/media_foundation_service_broker.cc
@@ -40,8 +40,8 @@ bool success = MediaFoundationCdmModule::GetInstance()->Initialize(cdm_path); std::move(ensure_sandboxed_cb_).Run(); - media_foundation_service_ = - std::make_unique<MediaFoundationService>(std::move(service_receiver)); + media_foundation_service_ = std::make_unique<MediaFoundationService>( + /*is_os_cdm=*/cdm_path.empty(), std::move(service_receiver)); DVLOG(1) << __func__ << ": success=" << success; if (!success) {
diff --git a/media/test/data/README.md b/media/test/data/README.md index aba6795..8298cf8 100644 --- a/media/test/data/README.md +++ b/media/test/data/README.md
@@ -76,6 +76,14 @@ #### front-discard.mp4 File recorded by a ChromeOS device, whose first packet is marked for complete discard. +#### mid-file-start-time.mp4 +File generated by copying the last 20s of a 30s file, without adjusting timestamps. +At the time when this file was generated, FFmpeg seems introduce some muxing issues. +``` +ffmpeg -filter_complex "smptehdbars=size=1280x720" -t 30 -c:v libx264 -y bars.mp4 +ffmpeg -i bars.mp4 -ss 10 -copyts -c copy -movflags +faststart -y bars2.mp4 +``` + ### FLAC #### bear-flac.mp4
diff --git a/media/test/data/mid-file-start-time.mp4 b/media/test/data/mid-file-start-time.mp4 new file mode 100644 index 0000000..dfcf545 --- /dev/null +++ b/media/test/data/mid-file-start-time.mp4 Binary files differ
diff --git a/media/test/media_bundle_data.filelist b/media/test/media_bundle_data.filelist index 75f2ecd..7f76509e 100644 --- a/media/test/media_bundle_data.filelist +++ b/media/test/media_bundle_data.filelist
@@ -393,6 +393,7 @@ data/media_foundation_fallback.html data/media_source_player.html data/media_suspend_test.html +data/mid-file-start-time.mp4 data/midstream_config_change.mp3 data/mono_cpe.adts data/mse_config_change.html
diff --git a/media/unit_tests_bundle_data.filelist b/media/unit_tests_bundle_data.filelist index 20d5130..a4d5ba5 100644 --- a/media/unit_tests_bundle_data.filelist +++ b/media/unit_tests_bundle_data.filelist
@@ -405,6 +405,7 @@ //media/test/data/media_foundation_fallback.html //media/test/data/media_source_player.html //media/test/data/media_suspend_test.html +//media/test/data/mid-file-start-time.mp4 //media/test/data/midstream_config_change.mp3 //media/test/data/mono_cpe.adts //media/test/data/mse_config_change.html
diff --git a/media/video/fake_gpu_memory_buffer.cc b/media/video/fake_gpu_memory_buffer.cc index 0066457..d6bee7c 100644 --- a/media/video/fake_gpu_memory_buffer.cc +++ b/media/video/fake_gpu_memory_buffer.cc
@@ -11,7 +11,6 @@ #include "base/atomic_sequence_num.h" #include "build/build_config.h" -#include "gpu/ipc/common/gpu_memory_buffer_impl.h" #include "media/base/format_utils.h" #include "media/base/video_frame.h" @@ -38,38 +37,6 @@ } #endif -class FakeGpuMemoryBufferImpl : public gpu::GpuMemoryBufferImpl { - public: - FakeGpuMemoryBufferImpl(const gfx::Size& size, gfx::BufferFormat format) - : gpu::GpuMemoryBufferImpl( - gfx::GpuMemoryBufferId(), - size, - format, - gpu::GpuMemoryBufferImpl::DestructionCallback()), - fake_gmb_(std::make_unique<media::FakeGpuMemoryBuffer>(size, format)) {} - - // gfx::GpuMemoryBuffer implementation - bool Map() override { return fake_gmb_->Map(); } - void MapAsync(base::OnceCallback<void(bool)> result_cb) override { - fake_gmb_->MapAsync(std::move(result_cb)); - } - bool AsyncMappingIsNonBlocking() const override { - return fake_gmb_->AsyncMappingIsNonBlocking(); - } - void* memory(size_t plane) override { return fake_gmb_->memory(plane); } - void Unmap() override { fake_gmb_->Unmap(); } - int stride(size_t plane) const override { return fake_gmb_->stride(plane); } - gfx::GpuMemoryBufferType GetType() const override { - return fake_gmb_->GetType(); - } - gfx::GpuMemoryBufferHandle CloneHandle() const override { - return fake_gmb_->CloneHandle(); - } - - private: - std::unique_ptr<media::FakeGpuMemoryBuffer> fake_gmb_; -}; - static base::AtomicSequenceNumber buffer_id_generator; } // namespace
diff --git a/net/BUILD.gn b/net/BUILD.gn index 04e1ad5f..07a7c20 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -2069,6 +2069,8 @@ "http/http_transaction_test_util.h", "http/mock_http_cache.cc", "http/mock_http_cache.h", + "http/no_vary_search_cache_storage_mock_file_operations.cc", + "http/no_vary_search_cache_storage_mock_file_operations.h", "http/no_vary_search_cache_test_utils.cc", "http/no_vary_search_cache_test_utils.h", "http/transport_security_state_test_util.cc",
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc index 37f1707..924bd083 100644 --- a/net/cookies/cookie_monster_unittest.cc +++ b/net/cookies/cookie_monster_unittest.cc
@@ -7512,14 +7512,12 @@ net::SchemefulSite member4(GURL("https://member4.test")); access_delegate_->SetFirstPartySets({ - {owner1, - net::FirstPartySetEntry(owner1, net::SiteType::kPrimary, std::nullopt)}, - {member1, net::FirstPartySetEntry(owner1, net::SiteType::kAssociated, 0)}, - {member2, net::FirstPartySetEntry(owner1, net::SiteType::kAssociated, 1)}, - {owner2, - net::FirstPartySetEntry(owner2, net::SiteType::kPrimary, std::nullopt)}, - {member3, net::FirstPartySetEntry(owner2, net::SiteType::kAssociated, 0)}, - {member4, net::FirstPartySetEntry(owner2, net::SiteType::kAssociated, 1)}, + {owner1, net::FirstPartySetEntry(owner1, net::SiteType::kPrimary)}, + {member1, net::FirstPartySetEntry(owner1, net::SiteType::kAssociated)}, + {member2, net::FirstPartySetEntry(owner1, net::SiteType::kAssociated)}, + {owner2, net::FirstPartySetEntry(owner2, net::SiteType::kPrimary)}, + {member3, net::FirstPartySetEntry(owner2, net::SiteType::kAssociated)}, + {member4, net::FirstPartySetEntry(owner2, net::SiteType::kAssociated)}, }); ASSERT_TRUE(SetCookie(cm(), GURL("https://owner1.test"), kValidCookieLine));
diff --git a/net/first_party_sets/first_party_set_entry.cc b/net/first_party_sets/first_party_set_entry.cc index 213b369..e35a56d 100644 --- a/net/first_party_sets/first_party_set_entry.cc +++ b/net/first_party_sets/first_party_set_entry.cc
@@ -28,37 +28,11 @@ } // namespace -FirstPartySetEntry::SiteIndex::SiteIndex() = default; - -FirstPartySetEntry::SiteIndex::SiteIndex(uint32_t value) : value_(value) {} - -bool FirstPartySetEntry::SiteIndex::operator==(const SiteIndex& other) const = - default; - FirstPartySetEntry::FirstPartySetEntry() = default; -FirstPartySetEntry::FirstPartySetEntry( - SchemefulSite primary, - SiteType site_type, - std::optional<FirstPartySetEntry::SiteIndex> site_index) - : primary_(std::move(primary)), site_type_(site_type) { - switch (site_type_) { - case SiteType::kPrimary: - case SiteType::kService: - CHECK(!site_index.has_value()); - break; - case SiteType::kAssociated: - break; - } -} - FirstPartySetEntry::FirstPartySetEntry(SchemefulSite primary, - SiteType site_type, - uint32_t site_index) - : FirstPartySetEntry( - std::move(primary), - site_type, - std::make_optional(FirstPartySetEntry::SiteIndex(site_index))) {} + SiteType site_type) + : primary_(std::move(primary)), site_type_(site_type) {} FirstPartySetEntry::FirstPartySetEntry(const FirstPartySetEntry&) = default; FirstPartySetEntry& FirstPartySetEntry::operator=(const FirstPartySetEntry&) = @@ -95,12 +69,6 @@ ", site_type: ", SiteTypeToString(site_type_), "}"}); } -std::ostream& operator<<(std::ostream& os, - const FirstPartySetEntry::SiteIndex& index) { - os << index.value(); - return os; -} - std::ostream& operator<<(std::ostream& os, const FirstPartySetEntry& entry) { os << "{" << entry.primary() << ", " << static_cast<int>(entry.site_type()) << "}";
diff --git a/net/first_party_sets/first_party_set_entry.h b/net/first_party_sets/first_party_set_entry.h index 17eee21..222c045 100644 --- a/net/first_party_sets/first_party_set_entry.h +++ b/net/first_party_sets/first_party_set_entry.h
@@ -30,28 +30,10 @@ // First-Party Set. class NET_EXPORT FirstPartySetEntry { public: - class NET_EXPORT SiteIndex { - public: - SiteIndex(); - explicit SiteIndex(uint32_t value); - - bool operator==(const SiteIndex& other) const; - - uint32_t value() const { return value_; } - - private: - uint32_t value_; - }; - FirstPartySetEntry(); // `primary` is the primary site in the First-Party Set associated with this // entry. - FirstPartySetEntry(SchemefulSite primary, - SiteType site_type, - std::optional<SiteIndex> site_index); - FirstPartySetEntry(SchemefulSite primary, - SiteType site_type, - uint32_t site_index); + FirstPartySetEntry(SchemefulSite primary, SiteType site_type); FirstPartySetEntry(const FirstPartySetEntry&); FirstPartySetEntry& operator=(const FirstPartySetEntry&); @@ -78,9 +60,6 @@ SiteType site_type_; }; -NET_EXPORT std::ostream& operator<<( - std::ostream& os, - const FirstPartySetEntry::SiteIndex& site_index); NET_EXPORT std::ostream& operator<<(std::ostream& os, const FirstPartySetEntry& fpse);
diff --git a/net/first_party_sets/first_party_set_entry_override_unittest.cc b/net/first_party_sets/first_party_set_entry_override_unittest.cc index 0b5b1cd..9b19d211 100644 --- a/net/first_party_sets/first_party_set_entry_override_unittest.cc +++ b/net/first_party_sets/first_party_set_entry_override_unittest.cc
@@ -19,13 +19,13 @@ EXPECT_FALSE( FirstPartySetEntryOverride( FirstPartySetEntry(SchemefulSite(GURL("https://example.test")), - SiteType::kPrimary, std::nullopt)) + SiteType::kPrimary)) .IsDeletion()); } TEST(FirstPartySetEntryOverrideTest, GetEntry) { FirstPartySetEntry entry(SchemefulSite(GURL("https://example.test")), - SiteType::kPrimary, std::nullopt); + SiteType::kPrimary); EXPECT_EQ(FirstPartySetEntryOverride(entry).GetEntry(), entry); }
diff --git a/net/first_party_sets/first_party_sets_context_config_unittest.cc b/net/first_party_sets/first_party_sets_context_config_unittest.cc index fdf9a8bf..96f2e7b 100644 --- a/net/first_party_sets/first_party_sets_context_config_unittest.cc +++ b/net/first_party_sets/first_party_sets_context_config_unittest.cc
@@ -34,7 +34,7 @@ TEST(FirstPartySetsContextConfigTest, FindOverride_irrelevant) { SchemefulSite example(GURL("https://example.test")); - FirstPartySetEntry entry(example, SiteType::kPrimary, std::nullopt); + FirstPartySetEntry entry(example, SiteType::kPrimary); SchemefulSite foo(GURL("https://foo.test")); EXPECT_EQ(FirstPartySetsContextConfig::Create( @@ -56,7 +56,7 @@ TEST(FirstPartySetsContextConfigTest, FindOverride_modification) { SchemefulSite example(GURL("https://example.test")); - FirstPartySetEntry entry(example, SiteType::kPrimary, std::nullopt); + FirstPartySetEntry entry(example, SiteType::kPrimary); EXPECT_THAT(FirstPartySetsContextConfig::Create( {{example, FirstPartySetEntryOverride(entry)}}) @@ -126,9 +126,8 @@ const SchemefulSite foo(GURL("https://foo.test")); const SchemefulSite foo_alias(GURL("https://foo.test2")); - const FirstPartySetEntry primary_entry(example, SiteType::kPrimary, - std::nullopt); - const FirstPartySetEntry associated_entry(example, SiteType::kAssociated, 0); + const FirstPartySetEntry primary_entry(example, SiteType::kPrimary); + const FirstPartySetEntry associated_entry(example, SiteType::kAssociated); const FirstPartySetsContextConfig config = FirstPartySetsContextConfig::Create( @@ -153,11 +152,9 @@ const SchemefulSite bar(GURL("https://bar.test")); const SchemefulSite bar_alias(GURL("https://bar.test2")); - const FirstPartySetEntry primary_entry(example, SiteType::kPrimary, - std::nullopt); - const FirstPartySetEntry associated_entry(example, SiteType::kAssociated, 0); - const FirstPartySetEntry service_entry(example, SiteType::kService, - std::nullopt); + const FirstPartySetEntry primary_entry(example, SiteType::kPrimary); + const FirstPartySetEntry associated_entry(example, SiteType::kAssociated); + const FirstPartySetEntry service_entry(example, SiteType::kService); const FirstPartySetsContextConfig config = FirstPartySetsContextConfig::Create(
diff --git a/net/first_party_sets/global_first_party_sets.cc b/net/first_party_sets/global_first_party_sets.cc index 617d10e..658dffa 100644 --- a/net/first_party_sets/global_first_party_sets.cc +++ b/net/first_party_sets/global_first_party_sets.cc
@@ -328,8 +328,7 @@ member, FirstPartySetEntry(entry->second.primary(), member == entry->second.primary() ? SiteType::kPrimary - : SiteType::kAssociated, - std::nullopt)); + : SiteType::kAssociated)); } if (member == set_entry.primary()) return true; @@ -436,8 +435,7 @@ bool inserted = normalized .emplace(child_site_and_entry.first, - FirstPartySetEntry(rep_primary, SiteType::kAssociated, - std::nullopt)) + FirstPartySetEntry(rep_primary, SiteType::kAssociated)) .second; CHECK(inserted); }
diff --git a/net/first_party_sets/global_first_party_sets_unittest.cc b/net/first_party_sets/global_first_party_sets_unittest.cc index 3537bb3..50788d4 100644 --- a/net/first_party_sets/global_first_party_sets_unittest.cc +++ b/net/first_party_sets/global_first_party_sets_unittest.cc
@@ -73,10 +73,8 @@ GlobalFirstPartySets sets( base::Version(), /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}); @@ -90,13 +88,13 @@ const SchemefulSite example(GURL("https://example.test")); const SchemefulSite example_cctld(GURL("https://example.cctld")); const SchemefulSite member1(GURL("https://member1.test")); - const FirstPartySetEntry entry(example, SiteType::kPrimary, std::nullopt); - const FirstPartySetEntry member1_entry(example, SiteType::kAssociated, 1); + const FirstPartySetEntry entry(example, SiteType::kPrimary); + const FirstPartySetEntry member1_entry(example, SiteType::kAssociated); const SchemefulSite foo(GURL("https://foo.test")); const SchemefulSite member2(GURL("https://member2.test")); - const FirstPartySetEntry foo_entry(foo, SiteType::kPrimary, std::nullopt); - const FirstPartySetEntry member2_entry(foo, SiteType::kAssociated, 1); + const FirstPartySetEntry foo_entry(foo, SiteType::kPrimary); + const FirstPartySetEntry member2_entry(foo, SiteType::kAssociated); GlobalFirstPartySets sets(version, /*entries=*/ @@ -115,8 +113,7 @@ GlobalFirstPartySets global_sets( kVersion, /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, }, /*aliases=*/ { @@ -126,10 +123,8 @@ EXPECT_THAT( CollectEffectiveSetEntries(global_sets, FirstPartySetsContextConfig()), UnorderedElementsAre( - Pair(kPrimaryCctld, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)), - Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary, - std::nullopt)))); + Pair(kPrimaryCctld, FirstPartySetEntry(kPrimary, SiteType::kPrimary)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)))); } TEST_F(GlobalFirstPartySetsTest, FindEntry_Nonexistent) { @@ -143,8 +138,8 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_Exists) { SchemefulSite example(GURL("https://example.test")); SchemefulSite decoy_site(GURL("https://decoy.test")); - FirstPartySetEntry entry(example, SiteType::kPrimary, std::nullopt); - FirstPartySetEntry decoy_entry(example, SiteType::kAssociated, 1); + FirstPartySetEntry entry(example, SiteType::kPrimary); + FirstPartySetEntry decoy_entry(example, SiteType::kAssociated); EXPECT_THAT(GlobalFirstPartySets(kVersion, { @@ -160,8 +155,8 @@ SchemefulSite https_example(GURL("https://example.test")); SchemefulSite associated(GURL("https://associated.test")); SchemefulSite wss_example(GURL("wss://example.test")); - FirstPartySetEntry entry(https_example, SiteType::kPrimary, std::nullopt); - FirstPartySetEntry assoc_entry(https_example, SiteType::kAssociated, 0); + FirstPartySetEntry entry(https_example, SiteType::kPrimary); + FirstPartySetEntry assoc_entry(https_example, SiteType::kAssociated); EXPECT_THAT(GlobalFirstPartySets(kVersion, { @@ -176,9 +171,9 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_ExistsViaOverride) { SchemefulSite example(GURL("https://example.test")); SchemefulSite associated(GURL("https://associated.test")); - FirstPartySetEntry public_entry(example, SiteType::kPrimary, std::nullopt); - FirstPartySetEntry assoc_entry(example, SiteType::kAssociated, 0); - FirstPartySetEntry override_entry(example, SiteType::kAssociated, 1); + FirstPartySetEntry public_entry(example, SiteType::kPrimary); + FirstPartySetEntry assoc_entry(example, SiteType::kAssociated); + FirstPartySetEntry override_entry(example, SiteType::kAssociated); FirstPartySetsContextConfig config = FirstPartySetsContextConfig::Create( @@ -198,8 +193,8 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_RemovedViaOverride) { SchemefulSite example(GURL("https://example.test")); SchemefulSite associated(GURL("https://associated.test")); - FirstPartySetEntry public_entry(example, SiteType::kPrimary, std::nullopt); - FirstPartySetEntry assoc_entry(example, SiteType::kAssociated, 0); + FirstPartySetEntry public_entry(example, SiteType::kPrimary); + FirstPartySetEntry assoc_entry(example, SiteType::kAssociated); FirstPartySetsContextConfig config = FirstPartySetsContextConfig::Create( @@ -219,7 +214,7 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_ExistsViaAlias) { SchemefulSite example(GURL("https://example.test")); SchemefulSite example_cctld(GURL("https://example.cctld")); - FirstPartySetEntry entry(example, SiteType::kPrimary, std::nullopt); + FirstPartySetEntry entry(example, SiteType::kPrimary); EXPECT_THAT(GlobalFirstPartySets(kVersion, { @@ -233,8 +228,8 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_ExistsViaOverrideWithDecoyAlias) { SchemefulSite example(GURL("https://example.test")); SchemefulSite example_cctld(GURL("https://example.cctld")); - FirstPartySetEntry public_entry(example, SiteType::kPrimary, std::nullopt); - FirstPartySetEntry override_entry(example, SiteType::kAssociated, 1); + FirstPartySetEntry public_entry(example, SiteType::kPrimary); + FirstPartySetEntry override_entry(example, SiteType::kAssociated); FirstPartySetsContextConfig config = FirstPartySetsContextConfig::Create( @@ -253,7 +248,7 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_RemovedViaOverrideWithDecoyAlias) { SchemefulSite example(GURL("https://example.test")); SchemefulSite example_cctld(GURL("https://example.cctld")); - FirstPartySetEntry public_entry(example, SiteType::kPrimary, std::nullopt); + FirstPartySetEntry public_entry(example, SiteType::kPrimary); FirstPartySetsContextConfig config = FirstPartySetsContextConfig::Create( @@ -272,8 +267,8 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_AliasesIgnoredForConfig) { SchemefulSite example(GURL("https://example.test")); SchemefulSite example_cctld(GURL("https://example.cctld")); - FirstPartySetEntry public_entry(example, SiteType::kPrimary, std::nullopt); - FirstPartySetEntry override_entry(example, SiteType::kAssociated, 1); + FirstPartySetEntry public_entry(example, SiteType::kPrimary); + FirstPartySetEntry override_entry(example, SiteType::kAssociated); FirstPartySetsContextConfig config = FirstPartySetsContextConfig::Create( @@ -300,10 +295,9 @@ GlobalFirstPartySets( kVersion, { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, {kAssociated4, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, {}) .empty()); @@ -315,10 +309,9 @@ LocalSetDeclaration::Create( /*set_entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, {kAssociated4, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}) .value()); @@ -329,10 +322,8 @@ GlobalFirstPartySets sets( base::Version(), /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}); ASSERT_TRUE(sets.empty()); @@ -340,10 +331,9 @@ LocalSetDeclaration::Create( /*set_entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, {kAssociated4, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}) .value()); @@ -355,10 +345,9 @@ sets.FindEntries({kPrimary, kAssociated1, kAssociated4}, FirstPartySetsContextConfig()), UnorderedElementsAre( - Pair(kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)), Pair(kAssociated4, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)))); + FirstPartySetEntry(kPrimary, SiteType::kAssociated)))); } TEST_F(GlobalFirstPartySetsTest, @@ -368,12 +357,11 @@ LocalSetDeclaration::Create( /*set_entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, {kAssociated4, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, {kAssociated5, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}) .value()); @@ -384,17 +372,14 @@ /*replacement_sets=*/ { { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, {kAssociated1Cctld, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)}, - {kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)}, - {kService, - FirstPartySetEntry(kPrimary, SiteType::kService, std::nullopt)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + {kAssociated4, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + {kService, FirstPartySetEntry(kPrimary, SiteType::kService)}, }, }, /*addition_sets=*/{}, /*aliases=*/ @@ -408,16 +393,13 @@ CollectEffectiveSetEntries(global_sets, config), UnorderedElementsAre( Pair(kAssociated1Cctld, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)), - Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService, - std::nullopt)))); + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kAssociated1, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kAssociated4, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)), + Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService)))); } class PopulatedGlobalFirstPartySetsTest : public GlobalFirstPartySetsTest { @@ -426,21 +408,15 @@ : global_sets_( kVersion, { - {kPrimary, FirstPartySetEntry(kPrimary, - SiteType::kPrimary, - std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, {kAssociated2, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)}, - {kService, FirstPartySetEntry(kPrimary, - SiteType::kService, - std::nullopt)}, - {kPrimary2, FirstPartySetEntry(kPrimary2, - SiteType::kPrimary, - std::nullopt)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + {kService, FirstPartySetEntry(kPrimary, SiteType::kService)}, + {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)}, {kAssociated3, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)}, }, { {kAssociated1Cctld, kAssociated1}, @@ -460,10 +436,9 @@ LocalSetDeclaration::Create( /*set_entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, {kAssociated4, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}) .value()); @@ -480,10 +455,9 @@ }, FirstPartySetsContextConfig()), UnorderedElementsAre( - Pair(kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)), Pair(kAssociated4, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)))); + FirstPartySetEntry(kPrimary, SiteType::kAssociated)))); } TEST_F(PopulatedGlobalFirstPartySetsTest, @@ -494,10 +468,8 @@ LocalSetDeclaration::Create( /*set_entries=*/ { - {kPrimary3, - FirstPartySetEntry(kPrimary3, SiteType::kPrimary, std::nullopt)}, - {kPrimary, - FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)}, + {kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary)}, + {kPrimary, FirstPartySetEntry(kPrimary3, SiteType::kAssociated)}, }, /*aliases=*/{}) .value()); @@ -515,10 +487,9 @@ }, FirstPartySetsContextConfig()), UnorderedElementsAre( - Pair(kPrimary3, - FirstPartySetEntry(kPrimary3, SiteType::kPrimary, std::nullopt)), + Pair(kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary)), Pair(kPrimary, - FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)))); + FirstPartySetEntry(kPrimary3, SiteType::kAssociated)))); } TEST_F(PopulatedGlobalFirstPartySetsTest, @@ -531,10 +502,9 @@ /*set_entries=*/ { {kAssociated1, - FirstPartySetEntry(kAssociated1, SiteType::kPrimary, - std::nullopt)}, + FirstPartySetEntry(kAssociated1, SiteType::kPrimary)}, {kAssociated4, - FirstPartySetEntry(kAssociated1, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kAssociated1, SiteType::kAssociated)}, }, /*aliases=*/{}) .value()); @@ -552,17 +522,14 @@ }, FirstPartySetsContextConfig()), UnorderedElementsAre( - Pair(kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)), Pair(kAssociated2, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)), - Pair(kService, - FirstPartySetEntry(kPrimary, SiteType::kService, std::nullopt)), + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService)), Pair(kAssociated1, - FirstPartySetEntry(kAssociated1, SiteType::kPrimary, - std::nullopt)), + FirstPartySetEntry(kAssociated1, SiteType::kPrimary)), Pair(kAssociated4, - FirstPartySetEntry(kAssociated1, SiteType::kAssociated, 0)))); + FirstPartySetEntry(kAssociated1, SiteType::kAssociated)))); } TEST_F(PopulatedGlobalFirstPartySetsTest, @@ -573,10 +540,9 @@ LocalSetDeclaration::Create( /*set_entries=*/ { - {kPrimary3, - FirstPartySetEntry(kPrimary3, SiteType::kPrimary, std::nullopt)}, + {kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary)}, {kAssociated1, - FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated)}, }, /*aliases=*/{}) .value()); @@ -594,16 +560,13 @@ }, FirstPartySetsContextConfig()), UnorderedElementsAre( - Pair(kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)), Pair(kAssociated2, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)), - Pair(kService, - FirstPartySetEntry(kPrimary, SiteType::kService, std::nullopt)), - Pair(kPrimary3, - FirstPartySetEntry(kPrimary3, SiteType::kPrimary, std::nullopt)), + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService)), + Pair(kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary)), Pair(kAssociated1, - FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)))); + FirstPartySetEntry(kPrimary3, SiteType::kAssociated)))); } TEST_F(PopulatedGlobalFirstPartySetsTest, @@ -614,10 +577,9 @@ LocalSetDeclaration::Create( /*set_entries=*/ { - {kPrimary3, - FirstPartySetEntry(kPrimary3, SiteType::kPrimary, std::nullopt)}, + {kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary)}, {kAssociated3, - FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated)}, }, /*aliases=*/{}) .value()); @@ -636,10 +598,9 @@ LocalSetDeclaration::Create( /*set_entries=*/ { - {kPrimary3, - FirstPartySetEntry(kPrimary3, SiteType::kPrimary, std::nullopt)}, + {kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary)}, {kAssociated1, - FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated)}, }, /*aliases=*/ { @@ -647,19 +608,18 @@ }) .value()); - EXPECT_THAT( - global_sets().FindEntries( - { - kAssociated1, - kAssociated1Cctld, - kAssociated1Cctld2, - }, - FirstPartySetsContextConfig()), - UnorderedElementsAre( - Pair(kAssociated1, - FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)), - Pair(kAssociated1Cctld2, - FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0)))); + EXPECT_THAT(global_sets().FindEntries( + { + kAssociated1, + kAssociated1Cctld, + kAssociated1Cctld2, + }, + FirstPartySetsContextConfig()), + UnorderedElementsAre( + Pair(kAssociated1, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated)), + Pair(kAssociated1Cctld2, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated)))); } TEST_F(PopulatedGlobalFirstPartySetsTest, ForEachPublicSetEntry_FullIteration) { @@ -688,19 +648,16 @@ CollectEffectiveSetEntries(global_sets(), FirstPartySetsContextConfig()), UnorderedElementsAre( Pair(kAssociated1Cctld, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)), + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), Pair(kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)), + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), Pair(kAssociated2, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)), + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), Pair(kAssociated3, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, 0)), - Pair(kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)), - Pair(kPrimary2, - FirstPartySetEntry(kPrimary2, SiteType::kPrimary, std::nullopt)), - Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService, - std::nullopt)))); + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)), + Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)), + Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService)))); } TEST_F(PopulatedGlobalFirstPartySetsTest, @@ -711,10 +668,9 @@ LocalSetDeclaration::Create( /*set_entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, {kAssociated4, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}) .value()); @@ -723,13 +679,11 @@ CollectEffectiveSetEntries(global_sets(), FirstPartySetsContextConfig()), UnorderedElementsAre( Pair(kAssociated3, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, 0)), + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)), Pair(kAssociated4, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)), - Pair(kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)), - Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary, - std::nullopt)))); + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)), + Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)))); } TEST_F(PopulatedGlobalFirstPartySetsTest, @@ -740,17 +694,14 @@ /*replacement_sets=*/ { { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, {kAssociated1Cctld, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)}, - {kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)}, - {kService, - FirstPartySetEntry(kPrimary, SiteType::kService, std::nullopt)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + {kAssociated4, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + {kService, FirstPartySetEntry(kPrimary, SiteType::kService)}, }, }, /*addition_sets=*/{}, @@ -763,20 +714,16 @@ CollectEffectiveSetEntries(global_sets(), config), UnorderedElementsAre( Pair(kAssociated1Cctld, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kAssociated1, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), Pair(kAssociated3, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, 0)), - Pair(kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)), - Pair(kPrimary2, - FirstPartySetEntry(kPrimary2, SiteType::kPrimary, std::nullopt)), - Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService, - std::nullopt)))); + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)), + Pair(kAssociated4, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)), + Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)), + Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService)))); } TEST_F( @@ -788,12 +735,11 @@ LocalSetDeclaration::Create( /*set_entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, {kAssociated4, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, {kAssociated5, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}) .value()); @@ -804,17 +750,14 @@ /*replacement_sets=*/ { { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, {kAssociated1Cctld, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)}, - {kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)}, - {kService, - FirstPartySetEntry(kPrimary, SiteType::kService, std::nullopt)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + {kAssociated4, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + {kService, FirstPartySetEntry(kPrimary, SiteType::kService)}, }, }, /*addition_sets=*/{}, /*aliases=*/ @@ -828,20 +771,16 @@ CollectEffectiveSetEntries(global_sets(), config), UnorderedElementsAre( Pair(kAssociated1Cctld, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kAssociated1, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), Pair(kAssociated3, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, 0)), - Pair(kAssociated4, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)), - Pair(kPrimary2, - FirstPartySetEntry(kPrimary2, SiteType::kPrimary, std::nullopt)), - Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService, - std::nullopt)))); + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)), + Pair(kAssociated4, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)), + Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)), + Pair(kService, FirstPartySetEntry(kPrimary, SiteType::kService)))); } TEST_F( @@ -851,10 +790,9 @@ LocalSetDeclaration::Create( /*set_entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/ { @@ -866,11 +804,9 @@ /*replacement_sets=*/ { { - {kPrimary2, - FirstPartySetEntry(kPrimary2, SiteType::kPrimary, std::nullopt)}, + {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)}, {kAssociated1, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)}, + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)}, }, }, /*addition_sets=*/{}, /*aliases=*/{})); @@ -879,16 +815,14 @@ CollectEffectiveSetEntries(global_sets(), config), UnorderedElementsAre( Pair(kAssociated1, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary, - std::nullopt)))); + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)), + Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)))); } TEST_F(PopulatedGlobalFirstPartySetsTest, ComputeMetadata) { SchemefulSite nonmember(GURL("https://nonmember.test")); - FirstPartySetEntry primary_entry(kPrimary, SiteType::kPrimary, std::nullopt); - FirstPartySetEntry associated_entry(kPrimary, SiteType::kAssociated, 0); + FirstPartySetEntry primary_entry(kPrimary, SiteType::kPrimary); + FirstPartySetEntry associated_entry(kPrimary, SiteType::kAssociated); // Works as usual for sites that are in First-Party sets. EXPECT_EQ(global_sets().ComputeMetadata(kAssociated1, &kAssociated1, @@ -914,18 +848,18 @@ } TEST_F(GlobalFirstPartySetsTest, ComputeConfig_Empty) { - EXPECT_EQ(GlobalFirstPartySets( - kVersion, - /*entries=*/ - { - {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary, - std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, - }, - /*aliases=*/{}) - .ComputeConfig(SetsMutation({}, {}, {})), - FirstPartySetsContextConfig()); + EXPECT_EQ( + GlobalFirstPartySets( + kVersion, + /*entries=*/ + { + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + }, + /*aliases=*/{}) + .ComputeConfig(SetsMutation({}, {}, {})), + FirstPartySetsContextConfig()); } TEST_F(GlobalFirstPartySetsTest, @@ -934,21 +868,17 @@ kVersion, /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}); FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation( /*replacement_sets=*/ { { - {kPrimary2, - FirstPartySetEntry(kPrimary2, SiteType::kPrimary, std::nullopt)}, + {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)}, {kAssociated2, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)}, + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)}, }, }, /*addition_sets=*/{}, /*aliases=*/{})); @@ -956,10 +886,8 @@ sets.FindEntries({kAssociated2, kPrimary2}, config), UnorderedElementsAre( Pair(kAssociated2, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary, - std::nullopt)))); + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)), + Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)))); } // The common associated site between the policy and existing set is removed @@ -971,23 +899,18 @@ kVersion, /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, - {kAssociated2, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + {kAssociated2, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}); FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation( /*replacement_sets=*/ { { - {kPrimary2, - FirstPartySetEntry(kPrimary2, SiteType::kPrimary, std::nullopt)}, + {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)}, {kAssociated2, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)}, + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)}, }, }, /*addition_sets=*/{}, /*aliases=*/{})); @@ -995,10 +918,8 @@ sets.FindEntries({kPrimary2, kAssociated2}, config), UnorderedElementsAre( Pair(kAssociated2, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary, - std::nullopt)))); + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)), + Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)))); } // The common primary between the policy and existing set is removed and its @@ -1010,22 +931,18 @@ kVersion, /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, - {kAssociated2, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + {kAssociated2, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}); FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation( /*replacement_sets=*/ { { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated3, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated3, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, }, /*addition_sets=*/{}, /*aliases=*/{})); @@ -1033,10 +950,9 @@ sets.FindEntries({kAssociated3, kPrimary, kAssociated1, kAssociated2}, config), UnorderedElementsAre( - Pair(kAssociated3, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary, - std::nullopt)))); + Pair(kAssociated3, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)))); } // The common associated site between the policy and existing set is removed and @@ -1048,21 +964,17 @@ kVersion, /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}); FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation( /*replacement_sets=*/ { { - {kPrimary3, - FirstPartySetEntry(kPrimary3, SiteType::kPrimary, std::nullopt)}, + {kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary)}, {kAssociated1, - FirstPartySetEntry(kPrimary3, SiteType::kAssociated, - std::nullopt)}, + FirstPartySetEntry(kPrimary3, SiteType::kAssociated)}, }, }, /*addition_sets=*/{}, /*aliases=*/{})); @@ -1070,10 +982,8 @@ sets.FindEntries({kAssociated1, kPrimary3, kPrimary}, config), UnorderedElementsAre( Pair(kAssociated1, - FirstPartySetEntry(kPrimary3, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary, - std::nullopt)))); + FirstPartySetEntry(kPrimary3, SiteType::kAssociated)), + Pair(kPrimary3, FirstPartySetEntry(kPrimary3, SiteType::kPrimary)))); } // The policy set and the existing set have nothing in common so the policy set @@ -1084,10 +994,8 @@ kVersion, /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}); FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation( @@ -1095,11 +1003,9 @@ /*addition_sets=*/ { { - {kPrimary2, - FirstPartySetEntry(kPrimary2, SiteType::kPrimary, std::nullopt)}, + {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)}, {kAssociated2, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)}, + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)}, }, }, /*aliases=*/{})); @@ -1107,10 +1013,8 @@ sets.FindEntries({kAssociated2, kPrimary2}, config), UnorderedElementsAre( Pair(kAssociated2, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary, - std::nullopt)))); + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)), + Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)))); } // The primary of a policy set is also an associated site in an existing set. @@ -1123,10 +1027,8 @@ kVersion, /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}); FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation( @@ -1135,32 +1037,25 @@ { { {kAssociated1, - FirstPartySetEntry(kAssociated1, SiteType::kPrimary, - std::nullopt)}, + FirstPartySetEntry(kAssociated1, SiteType::kPrimary)}, {kAssociated2, - FirstPartySetEntry(kAssociated1, SiteType::kAssociated, - std::nullopt)}, + FirstPartySetEntry(kAssociated1, SiteType::kAssociated)}, {kAssociated3, - FirstPartySetEntry(kAssociated1, SiteType::kAssociated, - std::nullopt)}, + FirstPartySetEntry(kAssociated1, SiteType::kAssociated)}, }, }, /*aliases=*/{})); - EXPECT_THAT( - sets.FindEntries({kPrimary, kAssociated2, kAssociated3, kAssociated1}, - config), - UnorderedElementsAre( - Pair(kPrimary, FirstPartySetEntry(kAssociated1, SiteType::kAssociated, - std::nullopt)), - Pair(kAssociated2, - FirstPartySetEntry(kAssociated1, SiteType::kAssociated, - std::nullopt)), - Pair(kAssociated3, - FirstPartySetEntry(kAssociated1, SiteType::kAssociated, - std::nullopt)), - Pair(kAssociated1, - FirstPartySetEntry(kAssociated1, SiteType::kPrimary, - std::nullopt)))); + EXPECT_THAT(sets.FindEntries( + {kPrimary, kAssociated2, kAssociated3, kAssociated1}, config), + UnorderedElementsAre( + Pair(kPrimary, + FirstPartySetEntry(kAssociated1, SiteType::kAssociated)), + Pair(kAssociated2, + FirstPartySetEntry(kAssociated1, SiteType::kAssociated)), + Pair(kAssociated3, + FirstPartySetEntry(kAssociated1, SiteType::kAssociated)), + Pair(kAssociated1, + FirstPartySetEntry(kAssociated1, SiteType::kPrimary)))); } // The primary of a policy set is also a primary of an existing set. @@ -1173,36 +1068,30 @@ kVersion, /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, - {kAssociated3, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + {kAssociated3, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}); FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation( /*replacement_sets=*/{}, /*addition_sets=*/ {{ - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated2, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated2, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }}, /*aliases=*/{})); EXPECT_THAT( sets.FindEntries({kAssociated1, kAssociated2, kAssociated3, kPrimary}, config), UnorderedElementsAre( - Pair(kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kAssociated2, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kAssociated3, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary, - std::nullopt)))); + Pair(kAssociated1, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kAssociated2, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kAssociated3, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)))); } // Existing set overlaps with both replacement and addition set. @@ -1213,32 +1102,26 @@ kVersion, /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, - {kAssociated2, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 1)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, + {kAssociated2, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}); FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation( /*replacement_sets=*/ { { - {kPrimary2, - FirstPartySetEntry(kPrimary2, SiteType::kPrimary, std::nullopt)}, + {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)}, {kAssociated1, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)}, + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)}, }, }, /*addition_sets=*/ { { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated3, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated3, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, }, /*aliases=*/{})); @@ -1248,16 +1131,13 @@ config), UnorderedElementsAre( Pair(kAssociated1, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)), - Pair(kAssociated2, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kAssociated3, FirstPartySetEntry(kPrimary, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)), - Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary, - std::nullopt)))); + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)), + Pair(kAssociated2, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kAssociated3, + FirstPartySetEntry(kPrimary, SiteType::kAssociated)), + Pair(kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)), + Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)))); } TEST_F(GlobalFirstPartySetsTest, TransitiveOverlap_TwoCommonPrimaries) { @@ -1277,32 +1157,26 @@ kVersion, /*entries=*/ { - {primary1, - FirstPartySetEntry(primary1, SiteType::kPrimary, std::nullopt)}, - {primary2, FirstPartySetEntry(primary1, SiteType::kAssociated, 0)}, + {primary1, FirstPartySetEntry(primary1, SiteType::kPrimary)}, + {primary2, FirstPartySetEntry(primary1, SiteType::kAssociated)}, }, /*aliases=*/{}); FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation( /*replacement_sets=*/{}, /*addition_sets=*/ { - {{primary0, - FirstPartySetEntry(primary0, SiteType::kPrimary, std::nullopt)}, + {{primary0, FirstPartySetEntry(primary0, SiteType::kPrimary)}, {associated_site0, - FirstPartySetEntry(primary0, SiteType::kAssociated, std::nullopt)}}, - {{primary1, - FirstPartySetEntry(primary1, SiteType::kPrimary, std::nullopt)}, + FirstPartySetEntry(primary0, SiteType::kAssociated)}}, + {{primary1, FirstPartySetEntry(primary1, SiteType::kPrimary)}, {associated_site1, - FirstPartySetEntry(primary1, SiteType::kAssociated, std::nullopt)}}, - {{primary2, - FirstPartySetEntry(primary2, SiteType::kPrimary, std::nullopt)}, + FirstPartySetEntry(primary1, SiteType::kAssociated)}}, + {{primary2, FirstPartySetEntry(primary2, SiteType::kPrimary)}, {associated_site2, - FirstPartySetEntry(primary2, SiteType::kAssociated, std::nullopt)}}, - {{primary42, - FirstPartySetEntry(primary42, SiteType::kPrimary, std::nullopt)}, + FirstPartySetEntry(primary2, SiteType::kAssociated)}}, + {{primary42, FirstPartySetEntry(primary42, SiteType::kPrimary)}, {associated_site42, - FirstPartySetEntry(primary42, SiteType::kAssociated, - std::nullopt)}}, + FirstPartySetEntry(primary42, SiteType::kAssociated)}}, }, /*aliases=*/{})); EXPECT_THAT( @@ -1320,25 +1194,17 @@ config), UnorderedElementsAre( Pair(associated_site0, - FirstPartySetEntry(primary0, SiteType::kAssociated, - std::nullopt)), + FirstPartySetEntry(primary0, SiteType::kAssociated)), Pair(associated_site1, - FirstPartySetEntry(primary1, SiteType::kAssociated, - std::nullopt)), + FirstPartySetEntry(primary1, SiteType::kAssociated)), Pair(associated_site2, - FirstPartySetEntry(primary1, SiteType::kAssociated, - std::nullopt)), + FirstPartySetEntry(primary1, SiteType::kAssociated)), Pair(associated_site42, - FirstPartySetEntry(primary42, SiteType::kAssociated, - std::nullopt)), - Pair(primary0, - FirstPartySetEntry(primary0, SiteType::kPrimary, std::nullopt)), - Pair(primary1, - FirstPartySetEntry(primary1, SiteType::kPrimary, std::nullopt)), - Pair(primary2, FirstPartySetEntry(primary1, SiteType::kAssociated, - std::nullopt)), - Pair(primary42, FirstPartySetEntry(primary42, SiteType::kPrimary, - std::nullopt)))); + FirstPartySetEntry(primary42, SiteType::kAssociated)), + Pair(primary0, FirstPartySetEntry(primary0, SiteType::kPrimary)), + Pair(primary1, FirstPartySetEntry(primary1, SiteType::kPrimary)), + Pair(primary2, FirstPartySetEntry(primary1, SiteType::kAssociated)), + Pair(primary42, FirstPartySetEntry(primary42, SiteType::kPrimary)))); } TEST_F(GlobalFirstPartySetsTest, TransitiveOverlap_TwoCommonAssociatedSites) { @@ -1358,32 +1224,26 @@ kVersion, /*entries=*/ { - {primary2, - FirstPartySetEntry(primary2, SiteType::kPrimary, std::nullopt)}, - {primary1, FirstPartySetEntry(primary2, SiteType::kAssociated, 0)}, + {primary2, FirstPartySetEntry(primary2, SiteType::kPrimary)}, + {primary1, FirstPartySetEntry(primary2, SiteType::kAssociated)}, }, /*aliases=*/{}); FirstPartySetsContextConfig config = sets.ComputeConfig(SetsMutation( /*replacement_sets=*/{}, /*addition_sets=*/ { - {{primary0, - FirstPartySetEntry(primary0, SiteType::kPrimary, std::nullopt)}, + {{primary0, FirstPartySetEntry(primary0, SiteType::kPrimary)}, {associated_site0, - FirstPartySetEntry(primary0, SiteType::kAssociated, std::nullopt)}}, - {{primary2, - FirstPartySetEntry(primary2, SiteType::kPrimary, std::nullopt)}, + FirstPartySetEntry(primary0, SiteType::kAssociated)}}, + {{primary2, FirstPartySetEntry(primary2, SiteType::kPrimary)}, {associated_site2, - FirstPartySetEntry(primary2, SiteType::kAssociated, std::nullopt)}}, - {{primary1, - FirstPartySetEntry(primary1, SiteType::kPrimary, std::nullopt)}, + FirstPartySetEntry(primary2, SiteType::kAssociated)}}, + {{primary1, FirstPartySetEntry(primary1, SiteType::kPrimary)}, {associated_site1, - FirstPartySetEntry(primary1, SiteType::kAssociated, std::nullopt)}}, - {{primary42, - FirstPartySetEntry(primary42, SiteType::kPrimary, std::nullopt)}, + FirstPartySetEntry(primary1, SiteType::kAssociated)}}, + {{primary42, FirstPartySetEntry(primary42, SiteType::kPrimary)}, {associated_site42, - FirstPartySetEntry(primary42, SiteType::kAssociated, - std::nullopt)}}, + FirstPartySetEntry(primary42, SiteType::kAssociated)}}, }, /*aliases=*/{})); EXPECT_THAT( @@ -1401,35 +1261,25 @@ config), UnorderedElementsAre( Pair(associated_site0, - FirstPartySetEntry(primary0, SiteType::kAssociated, - std::nullopt)), + FirstPartySetEntry(primary0, SiteType::kAssociated)), Pair(associated_site1, - FirstPartySetEntry(primary2, SiteType::kAssociated, - std::nullopt)), + FirstPartySetEntry(primary2, SiteType::kAssociated)), Pair(associated_site2, - FirstPartySetEntry(primary2, SiteType::kAssociated, - std::nullopt)), + FirstPartySetEntry(primary2, SiteType::kAssociated)), Pair(associated_site42, - FirstPartySetEntry(primary42, SiteType::kAssociated, - std::nullopt)), - Pair(primary0, - FirstPartySetEntry(primary0, SiteType::kPrimary, std::nullopt)), - Pair(primary1, FirstPartySetEntry(primary2, SiteType::kAssociated, - std::nullopt)), - Pair(primary2, - FirstPartySetEntry(primary2, SiteType::kPrimary, std::nullopt)), - Pair(primary42, FirstPartySetEntry(primary42, SiteType::kPrimary, - std::nullopt)))); + FirstPartySetEntry(primary42, SiteType::kAssociated)), + Pair(primary0, FirstPartySetEntry(primary0, SiteType::kPrimary)), + Pair(primary1, FirstPartySetEntry(primary2, SiteType::kAssociated)), + Pair(primary2, FirstPartySetEntry(primary2, SiteType::kPrimary)), + Pair(primary42, FirstPartySetEntry(primary42, SiteType::kPrimary)))); } TEST_F(GlobalFirstPartySetsTest, InvalidPublicSetsVersion_ComputeConfig) { const GlobalFirstPartySets sets( base::Version(), /*entries=*/ { - {kPrimary, - FirstPartySetEntry(kPrimary, SiteType::kPrimary, std::nullopt)}, - {kAssociated1, - FirstPartySetEntry(kPrimary, SiteType::kAssociated, 0)}, + {kPrimary, FirstPartySetEntry(kPrimary, SiteType::kPrimary)}, + {kAssociated1, FirstPartySetEntry(kPrimary, SiteType::kAssociated)}, }, /*aliases=*/{}); ASSERT_TRUE(sets.empty()); @@ -1438,11 +1288,9 @@ /*replacement_sets=*/ { { - {kPrimary2, - FirstPartySetEntry(kPrimary2, SiteType::kPrimary, std::nullopt)}, + {kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)}, {kAssociated2, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)}, + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)}, }, }, /*addition_sets=*/{}, /*aliases=*/{})); @@ -1461,10 +1309,8 @@ config), UnorderedElementsAre( Pair(kAssociated2, - FirstPartySetEntry(kPrimary2, SiteType::kAssociated, - std::nullopt)), - Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary, - std::nullopt)))); + FirstPartySetEntry(kPrimary2, SiteType::kAssociated)), + Pair(kPrimary2, FirstPartySetEntry(kPrimary2, SiteType::kPrimary)))); } class GlobalFirstPartySetsWithConfigTest @@ -1475,17 +1321,15 @@ FirstPartySetsContextConfig::Create( { // New entry: - {kPrimary3, net::FirstPartySetEntryOverride( - FirstPartySetEntry(kPrimary3, - SiteType::kPrimary, - std::nullopt))}, + {kPrimary3, + net::FirstPartySetEntryOverride( + FirstPartySetEntry(kPrimary3, SiteType::kPrimary))}, // Removed entry: {kAssociated1, net::FirstPartySetEntryOverride()}, // Remapped entry: - {kAssociated3, net::FirstPartySetEntryOverride( - FirstPartySetEntry(kPrimary3, - SiteType::kAssociated, - 0))}, + {kAssociated3, + net::FirstPartySetEntryOverride( + FirstPartySetEntry(kPrimary3, SiteType::kAssociated))}, // Removed alias: {kAssociated1Cctld, net::FirstPartySetEntryOverride()}, }) @@ -1499,17 +1343,16 @@ TEST_F(GlobalFirstPartySetsWithConfigTest, ComputeMetadata) { // kAssociated1 has been removed from its set. - EXPECT_EQ(global_sets().ComputeMetadata(kAssociated1, &kPrimary, config()), - FirstPartySetMetadata( - std::nullopt, FirstPartySetEntry(kPrimary, SiteType::kPrimary, - std::nullopt))); + EXPECT_EQ( + global_sets().ComputeMetadata(kAssociated1, &kPrimary, config()), + FirstPartySetMetadata(std::nullopt, + FirstPartySetEntry(kPrimary, SiteType::kPrimary))); // kAssociated3 and kPrimary3 are sites in a new set. - EXPECT_EQ( - global_sets().ComputeMetadata(kAssociated3, &kPrimary3, config()), - FirstPartySetMetadata( - FirstPartySetEntry(kPrimary3, SiteType::kAssociated, 0), - FirstPartySetEntry(kPrimary3, SiteType::kPrimary, std::nullopt))); + EXPECT_EQ(global_sets().ComputeMetadata(kAssociated3, &kPrimary3, config()), + FirstPartySetMetadata( + FirstPartySetEntry(kPrimary3, SiteType::kAssociated), + FirstPartySetEntry(kPrimary3, SiteType::kPrimary))); } } // namespace net
diff --git a/net/first_party_sets/local_set_declaration_unittest.cc b/net/first_party_sets/local_set_declaration_unittest.cc index 1ba5292..3e51ae9 100644 --- a/net/first_party_sets/local_set_declaration_unittest.cc +++ b/net/first_party_sets/local_set_declaration_unittest.cc
@@ -32,8 +32,8 @@ SchemefulSite associated(GURL("https://associated.test")); base::flat_map<SchemefulSite, FirstPartySetEntry> entries({ - {primary, FirstPartySetEntry(primary, SiteType::kPrimary, std::nullopt)}, - {associated, FirstPartySetEntry(primary, SiteType::kAssociated, 0)}, + {primary, FirstPartySetEntry(primary, SiteType::kPrimary)}, + {associated, FirstPartySetEntry(primary, SiteType::kAssociated)}, }); LocalSetDeclaration local_set_declaration = @@ -45,10 +45,9 @@ /*replacement_sets=*/ { { - {primary, FirstPartySetEntry(primary, SiteType::kPrimary, - std::nullopt)}, + {primary, FirstPartySetEntry(primary, SiteType::kPrimary)}, {associated, - FirstPartySetEntry(primary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary, SiteType::kAssociated)}, }, }, /*addition_sets=*/{}, /*aliases=*/{})); @@ -62,8 +61,8 @@ SchemefulSite associated_cctld(GURL("https://associated.cctld")); base::flat_map<SchemefulSite, FirstPartySetEntry> entries({ - {primary, FirstPartySetEntry(primary, SiteType::kPrimary, std::nullopt)}, - {associated, FirstPartySetEntry(primary, SiteType::kAssociated, 0)}, + {primary, FirstPartySetEntry(primary, SiteType::kPrimary)}, + {associated, FirstPartySetEntry(primary, SiteType::kAssociated)}, }); base::flat_map<SchemefulSite, SchemefulSite> aliases( @@ -80,15 +79,13 @@ /*replacement_sets=*/ { { - {primary, FirstPartySetEntry(primary, SiteType::kPrimary, - std::nullopt)}, + {primary, FirstPartySetEntry(primary, SiteType::kPrimary)}, {primary_cctld, - FirstPartySetEntry(primary, SiteType::kPrimary, - std::nullopt)}, + FirstPartySetEntry(primary, SiteType::kPrimary)}, {associated, - FirstPartySetEntry(primary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary, SiteType::kAssociated)}, {associated_cctld, - FirstPartySetEntry(primary, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary, SiteType::kAssociated)}, }, }, /*addition_sets=*/{}, /*aliases=*/ @@ -112,19 +109,17 @@ // All aliases must refer to a canonical site that has an entry in the set. EXPECT_FALSE(LocalSetDeclaration::Create( { - {primary, - FirstPartySetEntry(primary, SiteType::kPrimary, std::nullopt)}, - {associated, FirstPartySetEntry(primary, SiteType::kAssociated, 0)}, + {primary, FirstPartySetEntry(primary, SiteType::kPrimary)}, + {associated, FirstPartySetEntry(primary, SiteType::kAssociated)}, }, {{associated2_cctld, associated2}})); // An alias must not have an explicit entry, even one that matches the // canonical's entry. - FirstPartySetEntry associated_entry(primary, SiteType::kAssociated, 0); + FirstPartySetEntry associated_entry(primary, SiteType::kAssociated); EXPECT_FALSE(LocalSetDeclaration::Create( { - {primary, - FirstPartySetEntry(primary, SiteType::kPrimary, std::nullopt)}, + {primary, FirstPartySetEntry(primary, SiteType::kPrimary)}, {associated, associated_entry}, {associated_cctld, associated_entry}, }, @@ -133,20 +128,17 @@ // No singleton sets. EXPECT_FALSE(LocalSetDeclaration::Create( { - {primary, - FirstPartySetEntry(primary, SiteType::kPrimary, std::nullopt)}, + {primary, FirstPartySetEntry(primary, SiteType::kPrimary)}, }, {})); // Multiple sets aren't supported. EXPECT_FALSE(LocalSetDeclaration::Create( { - {primary, - FirstPartySetEntry(primary, SiteType::kPrimary, std::nullopt)}, - {primary2, - FirstPartySetEntry(primary2, SiteType::kPrimary, std::nullopt)}, - {associated, FirstPartySetEntry(primary, SiteType::kAssociated, 0)}, - {associated2, FirstPartySetEntry(primary2, SiteType::kAssociated, 0)}, + {primary, FirstPartySetEntry(primary, SiteType::kPrimary)}, + {primary2, FirstPartySetEntry(primary2, SiteType::kPrimary)}, + {associated, FirstPartySetEntry(primary, SiteType::kAssociated)}, + {associated2, FirstPartySetEntry(primary2, SiteType::kAssociated)}, }, {})); }
diff --git a/net/first_party_sets/sets_mutation_unittest.cc b/net/first_party_sets/sets_mutation_unittest.cc index abcac89e..b84bd0d 100644 --- a/net/first_party_sets/sets_mutation_unittest.cc +++ b/net/first_party_sets/sets_mutation_unittest.cc
@@ -31,22 +31,20 @@ /*replacement_sets=*/ { { - {primary1, - FirstPartySetEntry(primary1, SiteType::kPrimary, std::nullopt)}, + {primary1, FirstPartySetEntry(primary1, SiteType::kPrimary)}, {associated1, - FirstPartySetEntry(primary1, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary1, SiteType::kAssociated)}, {primary1_cctld, - FirstPartySetEntry(primary1, SiteType::kPrimary, std::nullopt)}, + FirstPartySetEntry(primary1, SiteType::kPrimary)}, {associated1_cctld, - FirstPartySetEntry(primary1, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary1, SiteType::kAssociated)}, }, { - {primary2, - FirstPartySetEntry(primary2, SiteType::kPrimary, std::nullopt)}, + {primary2, FirstPartySetEntry(primary2, SiteType::kPrimary)}, {associated2, - FirstPartySetEntry(primary2, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary2, SiteType::kAssociated)}, {associated2_cctld, - FirstPartySetEntry(primary2, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary2, SiteType::kAssociated)}, }, }, /*addition_sets=*/{}, /*aliases=*/ @@ -61,22 +59,20 @@ /*addition_sets=*/ { { - {primary1, - FirstPartySetEntry(primary1, SiteType::kPrimary, std::nullopt)}, + {primary1, FirstPartySetEntry(primary1, SiteType::kPrimary)}, {associated1, - FirstPartySetEntry(primary1, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary1, SiteType::kAssociated)}, {primary1_cctld, - FirstPartySetEntry(primary1, SiteType::kPrimary, std::nullopt)}, + FirstPartySetEntry(primary1, SiteType::kPrimary)}, {associated1_cctld, - FirstPartySetEntry(primary1, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary1, SiteType::kAssociated)}, }, { - {primary2, - FirstPartySetEntry(primary2, SiteType::kPrimary, std::nullopt)}, + {primary2, FirstPartySetEntry(primary2, SiteType::kPrimary)}, {associated2, - FirstPartySetEntry(primary2, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary2, SiteType::kAssociated)}, {associated2_cctld, - FirstPartySetEntry(primary2, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary2, SiteType::kAssociated)}, }, }, /*aliases=*/ @@ -90,25 +86,23 @@ /*replacement_sets=*/ { { - {primary1, - FirstPartySetEntry(primary1, SiteType::kPrimary, std::nullopt)}, + {primary1, FirstPartySetEntry(primary1, SiteType::kPrimary)}, {associated1, - FirstPartySetEntry(primary1, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary1, SiteType::kAssociated)}, {primary1_cctld, - FirstPartySetEntry(primary1, SiteType::kPrimary, std::nullopt)}, + FirstPartySetEntry(primary1, SiteType::kPrimary)}, {associated1_cctld, - FirstPartySetEntry(primary1, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary1, SiteType::kAssociated)}, }, }, /*addition_sets=*/ { { - {primary2, - FirstPartySetEntry(primary2, SiteType::kPrimary, std::nullopt)}, + {primary2, FirstPartySetEntry(primary2, SiteType::kPrimary)}, {associated2, - FirstPartySetEntry(primary2, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary2, SiteType::kAssociated)}, {associated2_cctld, - FirstPartySetEntry(primary2, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary2, SiteType::kAssociated)}, }, }, /*aliases=*/ @@ -132,18 +126,18 @@ /*replacement_sets=*/ { { - {primary1, FirstPartySetEntry(primary1, SiteType::kPrimary, - std::nullopt)}, + {primary1, + FirstPartySetEntry(primary1, SiteType::kPrimary)}, {associated1, - FirstPartySetEntry(primary1, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary1, SiteType::kAssociated)}, }, { - {primary2, FirstPartySetEntry(primary2, SiteType::kPrimary, - std::nullopt)}, + {primary2, + FirstPartySetEntry(primary2, SiteType::kPrimary)}, {associated1, - FirstPartySetEntry(primary2, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary2, SiteType::kAssociated)}, {associated2, - FirstPartySetEntry(primary2, SiteType::kAssociated, 0)}, + FirstPartySetEntry(primary2, SiteType::kAssociated)}, }, }, /*addition_sets=*/{}, /*aliases=*/{});
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index 7027689a..fda98b13 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc
@@ -54,6 +54,7 @@ #include "net/http/http_response_headers.h" #include "net/http/http_response_info.h" #include "net/http/http_util.h" +#include "net/http/no_vary_search_cache_storage_file_operations.h" #include "net/log/net_log_with_source.h" #include "net/quic/quic_server_info.h" #include "url/origin.h" @@ -396,20 +397,26 @@ //----------------------------------------------------------------------------- -HttpCache::HttpCache(std::unique_ptr<HttpTransactionFactory> network_layer, - std::unique_ptr<BackendFactory> backend_factory) +HttpCache::HttpCache( + std::unique_ptr<HttpTransactionFactory> network_layer, + std::unique_ptr<BackendFactory> backend_factory, + std::unique_ptr<NoVarySearchCacheStorageFileOperations> file_operations) : net_log_(nullptr), backend_factory_(std::move(backend_factory)), network_layer_(std::move(network_layer)), clock_(base::DefaultClock::GetInstance()), keys_marked_no_store_( - features::kAvoidEntryCreationForNoStoreCacheSize.Get()) { + features::kAvoidEntryCreationForNoStoreCacheSize.Get()), + file_operations_(std::move(file_operations)) { g_init_cache = true; if (base::FeatureList::IsEnabled(features::kHttpCacheNoVarySearch)) { size_t max_entries = features::kHttpCacheNoVarySearchCacheMaxEntries.Get(); if (max_entries) { - no_vary_search_cache_.emplace(static_cast<size_t>(max_entries)); + // TODO(https://crbug.com/382394774): Make + // kHttpCacheNoVarySearchCacheMaxEntries be a size_t param. + no_vary_search_cache_ = + std::make_unique<NoVarySearchCache>(static_cast<size_t>(max_entries)); } } HttpNetworkSession* session = network_layer_->GetSession(); @@ -552,8 +559,8 @@ filter_type, origins, domains, delete_begin, delete_end); if (cleared) { - // TODO(https://crbug.com/399562754): Re-write the on-disk store to erase - // the removed entries. + // This will safely do nothing if we are not using on-disk storage. + no_vary_search_cache_storage_.TakeSnapshot(); } } @@ -1438,6 +1445,18 @@ keys_marked_no_store_.end(); } +void HttpCache::MaybeLoadNoVarySearchCacheFromDisk() { + if (file_operations_ && no_vary_search_cache_) { + // This use of base::Unretained() is safe because destroying this object + // destroys the `no_vary_search_cache_storage_` object after which the + // callback will not be called. + no_vary_search_cache_storage_.Load( + std::move(file_operations_), no_vary_search_cache_->max_size(), + base::BindOnce(&HttpCache::OnNoVarySearchCacheLoadComplete, + base::Unretained(this))); + } +} + void HttpCache::OnProcessQueuedTransactions(scoped_refptr<ActiveEntry> entry) { entry->set_will_process_queued_transactions(false); @@ -1639,6 +1658,7 @@ disk_cache_ = std::move(pending_op->backend); UMA_HISTOGRAM_MEMORY_KB("HttpCache.MaxFileSizeOnInit", disk_cache_->MaxFileSize() / 1024); + MaybeLoadNoVarySearchCacheFromDisk(); } } @@ -1666,4 +1686,18 @@ } } +void HttpCache::OnNoVarySearchCacheLoadComplete( + NoVarySearchCacheStorage::LoadResult result) { + if (!result.has_value()) { + // Failure. Nothing to do here. + return; + } + base::UmaHistogramCounts100( + "HttpCache.NoVarySearch.EntriesAddedDuringLoading", + no_vary_search_cache_->size()); + auto provisional_no_vary_search_cache = std::move(no_vary_search_cache_); + no_vary_search_cache_ = std::move(result.value()); + no_vary_search_cache_->MergeFrom(*provisional_no_vary_search_cache); +} + } // namespace net
diff --git a/net/http/http_cache.h b/net/http/http_cache.h index b94b3de8..465513a 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h
@@ -46,6 +46,7 @@ #include "net/disk_cache/disk_cache.h" #include "net/http/http_transaction_factory.h" #include "net/http/no_vary_search_cache.h" +#include "net/http/no_vary_search_cache_storage.h" class GURL; @@ -63,6 +64,7 @@ class HttpResponseInfo; class NetLog; class NetworkIsolationKey; +class NoVarySearchCacheStorageFileOperations; struct HttpRequestInfo; class NET_EXPORT HttpCache : public HttpTransactionFactory { @@ -177,8 +179,10 @@ // Initialize the cache from its component parts. |network_layer| and // |backend_factory| will be destroyed when the HttpCache is. - HttpCache(std::unique_ptr<HttpTransactionFactory> network_layer, - std::unique_ptr<BackendFactory> backend_factory); + HttpCache( + std::unique_ptr<HttpTransactionFactory> network_layer, + std::unique_ptr<BackendFactory> backend_factory, + std::unique_ptr<NoVarySearchCacheStorageFileOperations> file_operations); HttpCache(const HttpCache&) = delete; HttpCache& operator=(const HttpCache&) = delete; @@ -231,8 +235,8 @@ // Delete entries matching the criteria `filter_type`, `origins`, `domains`, // `delete_begin` and `delete_end` from the NoVarySearchCache and refresh the - // on-disk cache to reflect the removals if necessary. See - // no_vary_search_cache.h for the definition of the parameter. + // on-disk cache snapshot to reflect the removals if necessary. See + // no_vary_search_cache.h for the definition of the parameters. void ClearNoVarySearchCache(UrlFilterType filter_type, const base::flat_set<url::Origin>& origins, const base::flat_set<std::string>& domains, @@ -722,6 +726,10 @@ // to avoid attempting creating cache entries uselessly. bool DidKeyLeadToNoStoreResponse(const std::string& key); + // Calls NoVarySearchCacheStorage::Load() if `file_operations_` is set. Since + // this gives away `file_operations_`, it will only call it once. + void MaybeLoadNoVarySearchCacheFromDisk(); + // Events (called via PostTask) --------------------------------------------- void OnProcessQueuedTransactions(scoped_refptr<ActiveEntry> entry); @@ -753,6 +761,10 @@ // Processes the backend creation notification. void OnBackendCreated(int result, PendingOp* pending_op); + // Starts using the loaded cache if loading was successful. + void OnNoVarySearchCacheLoadComplete( + NoVarySearchCacheStorage::LoadResult result); + // Constants ---------------------------------------------------------------- // Used when generating and accessing keys if cache is split. @@ -801,7 +813,18 @@ // Set if the kHttpCacheNoVarySearch feature is enabled. Translates the URL in // the request into the URL of a previous response that is equivalent // according to the rules of the No-Vary-Search header in the response. - std::optional<NoVarySearchCache> no_vary_search_cache_; + std::unique_ptr<NoVarySearchCache> no_vary_search_cache_; + + // Implements persistence for `no_vary_search_cache_`. Only used when the + // cache is stored on disk. Holds a raw_ptr to `no_vary_search_cache_` so must + // be destroyed before it. + NoVarySearchCacheStorage no_vary_search_cache_storage_; + + // Implementation of file operations for No-Vary-Search cache persistence. + // Only non-null if the backend is on-disk, and only until a backend has been + // created. After that ownership is transferred to + // `no_vary_search_cache_storage_`. + std::unique_ptr<NoVarySearchCacheStorageFileOperations> file_operations_; THREAD_CHECKER(thread_checker_);
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 594c8772..74cb85e 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc
@@ -32,10 +32,12 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/test/bind.h" +#include "base/test/gmock_callback_support.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "base/test/test_future.h" +#include "base/test/test_waitable_event.h" #include "base/time/time.h" #include "base/trace_event/memory_allocator_dump.h" #include "base/trace_event/memory_dump_request_args.h" @@ -72,6 +74,7 @@ #include "net/http/http_transaction_test_util.h" #include "net/http/http_util.h" #include "net/http/mock_http_cache.h" +#include "net/http/no_vary_search_cache_storage_mock_file_operations.h" #include "net/log/net_log_event_type.h" #include "net/log/net_log_source.h" #include "net/log/net_log_with_source.h" @@ -90,17 +93,26 @@ #include "testing/gtest/include/gtest/gtest.h" #include "url/origin.h" +using base::test::RunClosure; using net::test::IsError; using net::test::IsOk; +using testing::_; using testing::AllOf; using testing::ByRef; using testing::Contains; +using testing::DoAll; using testing::ElementsAre; using testing::Eq; using testing::Field; using testing::Gt; +using testing::InSequence; +using testing::Invoke; using testing::IsEmpty; +using testing::MockFunction; using testing::NotNull; +using testing::Return; +using testing::StrictMock; +using testing::Truly; using base::Time; @@ -14112,13 +14124,14 @@ HINT_HIGH_PRIORITY); } -class HttpCacheNoVarySearchTest : public HttpCacheTest, - public ::testing::WithParamInterface<bool> { +class HttpCacheNoVarySearchTestBase + : public HttpCacheTest, + public ::testing::WithParamInterface<bool> { protected: static constexpr int kMaxAgeOneDay = 24 * 60 * 60; // seconds static constexpr std::string_view kBaseURL = "https://example.com/search?"; - HttpCacheNoVarySearchTest() { + HttpCacheNoVarySearchTestBase() { using base::test::FeatureRef; std::vector<FeatureRef> enabled_features = { features::kHttpCacheNoVarySearch}; @@ -14130,11 +14143,30 @@ disabled_features.push_back(split_cache_feature); } scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); - http_cache_.emplace(); + } + + ~HttpCacheNoVarySearchTestBase() { + // Destroy the NoVarySearchCacheStorage object. + http_cache_.reset(); + + // Make sure the NoVarySearchCacheStorage::Journaller object that lives on + // the thread pool has been destroyed along with any mock objects it owns. + // Despite what the presubmit claims, this use of RunUntilIdle() is correct. + RunUntilIdle(); + } + + void SetUp() override { ConstructCache(http_cache_); } + + // This can be overloaded by subclasses to construct the cache with different + // arguments. + virtual void ConstructCache(std::optional<MockHttpCache>& http_cache) { + http_cache.emplace(); } HttpCache* cache() { return http_cache_->http_cache(); } + MockDiskCache* mock_disk_cache() { return http_cache_->disk_cache(); } + // Callers can safely modify the return value, except for the `url` field. MockTransaction& CreateMockTransaction(std::string_view query, std::string_view no_vary_search, @@ -14199,6 +14231,8 @@ std::optional<MockHttpCache> http_cache_; }; +using HttpCacheNoVarySearchTest = HttpCacheNoVarySearchTestBase; + TEST_P(HttpCacheNoVarySearchTest, SimpleSuccess) { FetchIntoCache("q=fred&a=1", "params=(\"a\")"); @@ -14350,4 +14384,273 @@ return info.param ? "NotSplitCache" : "SplitCache"; }); +// A GoogleMock action to quit a base::RunLoop. This is not defined using the +// ACTION_P macro because to be thread-safe QuitClosure() needs to be called +// when the action is created, not when it is executed. +auto QuitRunLoop(base::RunLoop& run_loop) { + return RunClosure(run_loop.QuitClosure()); +} + +// Tests for NoVarySearchCacheStorage integration. These necessarily depend on +// the implementation of NoVarySearchCacheStorage, and would need to be updated +// if a different storage backend was used. +class HttpCacheNoVarySearchMockFileOperationsTest + : public HttpCacheNoVarySearchTestBase { + public: + using StrictMockFileOperations = StrictMock<MockFileOperations>; + using StrictMockWriter = StrictMock<MockWriter>; + using Checkpoint = StrictMock<MockFunction<void()>>; + + void ConstructCache(std::optional<MockHttpCache>& http_cache) override { + auto file_operations = std::make_unique<StrictMockFileOperations>(); + file_operations_ = file_operations.get(); + auto writer = std::make_unique<StrictMockWriter>(); + writer_ = writer.get(); + + auto maybe_block = [&] { + if (delay_load_.load()) { + // This thread synchronously goes to sleep until signalled. + load_can_proceed_.Wait(); + } + }; + + { + InSequence s; + + load_expectations_ += + EXPECT_CALL(*file_operations, Load) + .WillOnce(DoAll( + Invoke(maybe_block), + Return(base::unexpected(base::File::FILE_ERROR_NOT_FOUND)))); + load_expectations_ += EXPECT_CALL(*file_operations, AtomicSave) + .WillOnce(Return(base::ok())); + load_expectations_ += EXPECT_CALL(*file_operations, CreateWriter) + .WillOnce(Return(std::move(writer))); + load_expectations_ += + EXPECT_CALL(*writer_, Write) + .WillOnce(DoAll(QuitRunLoop(load_run_loop_), Return(true))); + } + http_cache.emplace(std::make_unique<MockBackendFactory>(), + std::move(file_operations)); + } + + void InitializeBackend() { + initialized_backend_ = true; + // It's not safe to set new expectations after this point. + file_operations_ = nullptr; + writer_ = nullptr; + + TestGetBackendCompletionCallback cb; + HttpCache::GetBackendResult result = cache()->GetBackend(cb.callback()); + EXPECT_THAT(cb.GetResult(result).first, IsOk()); + } + + void WaitForLoad() { load_run_loop_.Run(); } + + // Returns a GoogleMock matcher which tests if `substring` appears within a + // uint8_t span. For example SpanHasSubstring("foo") will match against a span + // that contains the bytes 'f' 'o' 'o' contiguously in that order. + static auto SpanHasSubstring(const std::string& substring) { + return Truly([substring](base::span<const uint8_t> span) { + return !std::ranges::search(span, substring).empty(); + }); + } + + void ResumeLoad() { + CHECK(delay_load_.load()); + load_can_proceed_.Signal(); + } + + // Set whether loading the snapshot should block the background thread. + void set_delay_load(bool delay_load) { delay_load_.store(delay_load); } + + StrictMockFileOperations& operations() { + CHECK(!initialized_backend_) + << "Set expectations before initializing backend"; + return *file_operations_; + } + + StrictMockWriter& writer() { + CHECK(!initialized_backend_) + << "Set expectations before initializing backend"; + return *writer_; + } + + const testing::ExpectationSet& load_expectations() const { + CHECK(!initialized_backend_) + << "Set expectations before initializing backend"; + return load_expectations_; + } + + private: + base::RunLoop load_run_loop_; + raw_ptr<StrictMockFileOperations> file_operations_ = nullptr; + + // This pointer will dangle if a new snapshot is created + raw_ptr<StrictMockWriter> writer_ = nullptr; + + // ExpectationSet represents a set of expectation. See + // https://google.github.io/googletest/reference/mocking.html#ExpectationSet + // for documentation. + testing::ExpectationSet load_expectations_; + + // This is used for blocking load when `delay_load_` is true. + base::TestWaitableEvent load_can_proceed_; + + bool initialized_backend_ = false; + std::atomic<bool> delay_load_ = false; +}; + +INSTANTIATE_TEST_SUITE_P(All, + HttpCacheNoVarySearchMockFileOperationsTest, + ::testing::Bool(), + [](const auto& info) { + return info.param ? "NotSplitCache" : "SplitCache"; + }); + +TEST_P(HttpCacheNoVarySearchMockFileOperationsTest, CacheStorageIsCreated) { + InitializeBackend(); + + WaitForLoad(); +} + +TEST_P(HttpCacheNoVarySearchMockFileOperationsTest, InsertsAreJournalled) { + base::RunLoop run_loop; + EXPECT_CALL(writer(), Write(SpanHasSubstring("q=fred&a=1"))) + .After(load_expectations()) + .WillOnce(DoAll(QuitRunLoop(run_loop), Return(true))); + + InitializeBackend(); + + WaitForLoad(); + + FetchIntoCache("q=fred&a=1", "params=(\"a\")"); + run_loop.Run(); +} + +TEST_P(HttpCacheNoVarySearchMockFileOperationsTest, EraseIsJournalled) { + base::RunLoop insert_run_loop; + base::RunLoop erase_run_loop; + // The same matcher works for the insert and erase operations, because they + // both have to contain the original query. This line verifies that two + // matching writes have been performed, but to avoid making the test too + // sensitive to the format of the journal, it does not verify that the journal + // entry types match. + EXPECT_CALL(writer(), Write(SpanHasSubstring("q=fred&a=1"))) + .After(load_expectations()) + .WillOnce(DoAll(QuitRunLoop(insert_run_loop), Return(true))) + .WillOnce(DoAll(QuitRunLoop(erase_run_loop), Return(true))); + + InitializeBackend(); + + WaitForLoad(); + + FetchIntoCache("q=fred&a=1", "params=(\"a\")"); + + // Ensure the insert is really complete. Without this, the call to + // set_fail_requests() sometimes causes the previous transaction to fail. + insert_run_loop.Run(); + + // Cause the next request to fail. This will then cause the entry to be + // erased from the NoVarySearchCache. + mock_disk_cache()->set_fail_requests(true); + + MockTransaction& from_cache = + CreateMockTransaction("q=fred&a=2", "params=(\"a\")"); + RunTransactionTest(cache(), from_cache); + erase_run_loop.Run(); +} + +TEST_P(HttpCacheNoVarySearchMockFileOperationsTest, + ClearNoVarySearchCacheRewritesSnapshot) { + base::RunLoop journal_run_loop; + base::RunLoop snapshot_run_loop; + { + InSequence s; + + // Verifies that the initial FetchIntoCache() transaction is journalled and + // permits the main thread to continue. + EXPECT_CALL(writer(), Write(SpanHasSubstring("q=fred&a=1"))) + .After(load_expectations()) + .WillOnce(DoAll(QuitRunLoop(journal_run_loop), Return(true))); + + // Verifies that the snapshot is written and that it does not contain the + // entry that the call to ClearNoVarySearchCache() should have removed. + EXPECT_CALL(operations(), + AtomicSave(_, Not(Contains(SpanHasSubstring("q=fred&a=1"))))) + .WillOnce(Return(base::ok())); + + auto writer = std::make_unique<StrictMockWriter>(); + auto& writer_ref = *writer; + + // Verifies that a new journal file is created. + EXPECT_CALL(operations(), CreateWriter).WillOnce(Return(std::move(writer))); + + // Verifies that the magic number (and nothing else) is written to the + // journal file, and permits the test to complete. + EXPECT_CALL(writer_ref, Write) + .WillOnce(DoAll(QuitRunLoop(snapshot_run_loop), Return(true))); + } + + InitializeBackend(); + + WaitForLoad(); + + FetchIntoCache("q=fred&a=1", "params=(\"a\")"); + journal_run_loop.Run(); + + cache()->ClearNoVarySearchCache(UrlFilterType::kFalseIfMatches, {}, {}, + base::Time(), base::Time::Max()); + + snapshot_run_loop.Run(); +} + +TEST_P(HttpCacheNoVarySearchMockFileOperationsTest, + InsertDuringLoadIsJournalled) { + // To make the test robust, ensure that background file operations don't + // complete until we have finished our first request. + set_delay_load(true); + + base::RunLoop run_loop; + Checkpoint checkpoint; + { + InSequence s; + + // Verifies that the journal write does not happen before the call to + // ResumeLoad(). + EXPECT_CALL(checkpoint, Call()); + + // Verifies that the transaction that happened before the load completed is + // journalled, and permits the test to continue. + EXPECT_CALL(writer(), Write(SpanHasSubstring("q=fred&a=1"))) + .After(load_expectations()) + .WillOnce(DoAll(QuitRunLoop(run_loop), Return(true))); + } + + InitializeBackend(); + + FetchIntoCache("q=fred&a=1", "params=(\"a\")"); + + checkpoint.Call(); + + // Let background file operations resume. + ResumeLoad(); + + // Wait for the journal to be written. + run_loop.Run(); + + // The entry should still be there. + MockTransaction& from_cache = + CreateMockTransaction("q=fred&a=2", "params=(\"a\")"); + MockHttpRequest cache_request(from_cache); + + HttpResponseInfo info; + + RunTransactionTestWithRequest(cache(), from_cache, cache_request, &info); + EXPECT_TRUE(info.was_cached); + EXPECT_FALSE(info.network_accessed); + EXPECT_EQ(info.cache_entry_status, HttpResponseInfo::ENTRY_USED); + EXPECT_EQ(info.headers->response_code(), 200); +} + } // namespace net
diff --git a/net/http/http_cache_writers_unittest.cc b/net/http/http_cache_writers_unittest.cc index 9ba736e5..a7c4cad 100644 --- a/net/http/http_cache_writers_unittest.cc +++ b/net/http/http_cache_writers_unittest.cc
@@ -20,6 +20,7 @@ #include "net/http/http_transaction.h" #include "net/http/http_transaction_test_util.h" #include "net/http/mock_http_cache.h" +#include "net/http/no_vary_search_cache_storage_file_operations.h" #include "net/http/partial_data.h" #include "net/test/gtest_util.h" #include "net/test/test_with_task_environment.h" @@ -56,7 +57,9 @@ public: TestHttpCache(std::unique_ptr<HttpTransactionFactory> network_layer, std::unique_ptr<BackendFactory> backend_factory) - : HttpCache(std::move(network_layer), std::move(backend_factory)) {} + : HttpCache(std::move(network_layer), + std::move(backend_factory), + /*file_operations=*/nullptr) {} void WritersDoneWritingToEntry(scoped_refptr<ActiveEntry> entry, bool success,
diff --git a/net/http/http_stream_factory_job_controller_unittest.cc b/net/http/http_stream_factory_job_controller_unittest.cc index 9e47159a..53db343 100644 --- a/net/http/http_stream_factory_job_controller_unittest.cc +++ b/net/http/http_stream_factory_job_controller_unittest.cc
@@ -6955,7 +6955,8 @@ }; TEST_F(HttpStreamFactoryJobControllerPoolTest, Preconnect) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("127.0.0.1").endpoint()) .CompleteStartSynchronously(OK);
diff --git a/net/http/http_stream_pool_attempt_manager.cc b/net/http/http_stream_pool_attempt_manager.cc index aa05b77..c7fdd5d 100644 --- a/net/http/http_stream_pool_attempt_manager.cc +++ b/net/http/http_stream_pool_attempt_manager.cc
@@ -848,6 +848,12 @@ return MultiplexedSessionCreationInitiator::kUnknown; } +void HttpStreamPool::AttemptManager::SetOnCompleteCallbackForTesting( + base::OnceClosure callback) { + CHECK(on_complete_callback_for_testing_.is_null()); + on_complete_callback_for_testing_ = std::move(callback); +} + void HttpStreamPool::AttemptManager::StartInternal(Job* job) { RestrictAllowedProtocols(job->allowed_alpns()); UpdateTcpBasedAttemptState(); @@ -904,6 +910,9 @@ } void HttpStreamPool::AttemptManager::ProcessServiceEndpointChanges() { + CHECK(!is_failing_); + CHECK(service_endpoint_request_); + // The order of the following checks is important, see the following comments. // TODO(crbug.com/383606724): Figure out a better design and algorithms to // handle attempts and existing sessions. @@ -1414,6 +1423,8 @@ CHECK(!final_error_to_notify_jobs_.has_value()); final_error_to_notify_jobs_ = error; is_failing_ = true; + service_endpoint_request_.reset(); + net_log_.AddEvent( NetLogEventType::HTTP_STREAM_POOL_ATTEMPT_MANAGER_NOTIFY_FAILURE, [&] { base::Value::Dict dict = GetStatesAsNetLogParams(); @@ -2060,6 +2071,11 @@ CHECK(ip_based_pooling_disabling_jobs_.empty()); CHECK(alternative_service_disabling_jobs_.empty()); + if (on_complete_callback_for_testing_) { + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, std::move(on_complete_callback_for_testing_)); + } + group_->OnAttemptManagerComplete(); // `this` is deleted. }
diff --git a/net/http/http_stream_pool_attempt_manager.h b/net/http/http_stream_pool_attempt_manager.h index 4347bf18..30b19941 100644 --- a/net/http/http_stream_pool_attempt_manager.h +++ b/net/http/http_stream_pool_attempt_manager.h
@@ -200,6 +200,8 @@ return ip_endpoint_states_; } + void SetOnCompleteCallbackForTesting(base::OnceClosure callback); + private: FRIEND_TEST_ALL_PREFIXES(HttpStreamPoolAttemptManagerTest, GetIPEndPointToAttempt); @@ -613,6 +615,8 @@ bool should_block_tcp_based_attempt_ = false; base::OneShotTimer tcp_based_attempt_delay_timer_; + base::OnceClosure on_complete_callback_for_testing_; + base::WeakPtrFactory<AttemptManager> weak_ptr_factory_{this}; };
diff --git a/net/http/http_stream_pool_attempt_manager_unittest.cc b/net/http/http_stream_pool_attempt_manager_unittest.cc index f276dc2..4ac4add 100644 --- a/net/http/http_stream_pool_attempt_manager_unittest.cc +++ b/net/http/http_stream_pool_attempt_manager_unittest.cc
@@ -619,7 +619,8 @@ }; TEST_F(HttpStreamPoolAttemptManagerTest, ResolveEndpointFailedSync) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request->CompleteStartSynchronously(ERR_FAILED); StreamRequester requester; requester.RequestStream(pool()); @@ -633,7 +634,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, ResolveEndpointFailedMultipleRequests) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester1; requester1.RequestStream(pool()); @@ -649,7 +651,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, LoadState) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; HttpStreamRequest* request = requester.RequestStream(pool()); @@ -665,7 +668,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, ResolveErrorInfo) { ResolveErrorInfo resolve_error_info(ERR_NAME_NOT_RESOLVED); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request->set_resolve_error_info(resolve_error_info); StreamRequester requester; @@ -681,7 +685,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, DnsAliases) { const std::set<std::string> kAliases = {"alias1", "alias2"}; - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .set_aliases(kAliases) @@ -704,7 +709,8 @@ constexpr base::TimeDelta kTcpDelay = base::Milliseconds(20); constexpr base::TimeDelta kTlsDelay = base::Milliseconds(90); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.set_destination("https://a.test").RequestStream(pool()); @@ -770,7 +776,8 @@ ConnectTimingDnsResolutionNotFinished) { constexpr base::TimeDelta kDnsUpdateDelay = base::Milliseconds(30); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.set_destination("http://a.test").RequestStream(pool()); @@ -804,7 +811,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, PlainHttpWaitForHttpsRecord) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.set_destination("http://a.test").RequestStream(pool()); @@ -825,7 +833,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, SetPriority) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester1; HttpStreamRequest* request1 = @@ -833,7 +842,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester1.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); ASSERT_EQ(endpoint_request->priority(), RequestPriority::LOW); ASSERT_EQ(manager->GetPriority(), RequestPriority::LOW); @@ -843,7 +852,7 @@ requester2.set_priority(RequestPriority::IDLE).RequestStream(pool()); ASSERT_EQ(manager, pool() .GetOrCreateGroupForTesting(requester2.GetStreamKey()) - .GetAttemptManagerForTesting()); + .attempt_manager()); ASSERT_EQ(endpoint_request->priority(), RequestPriority::LOW); ASSERT_EQ(manager->GetPriority(), RequestPriority::LOW); @@ -903,7 +912,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); ASSERT_EQ(manager->GetPriority(), RequestPriority::HIGHEST); // Complete the stream attempt and wait for request completion. The @@ -915,7 +924,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, TcpFailSync) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.RequestStream(pool()); @@ -934,7 +944,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, TcpFailAsync) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.RequestStream(pool()); @@ -953,7 +964,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, TlsOkAsync) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); auto data = std::make_unique<SequencedSocketData>(); socket_factory()->AddSocketDataProvider(data.get()); @@ -990,7 +1002,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, TlsCryptoReadyDelayed) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); auto data = std::make_unique<SequencedSocketData>(); socket_factory()->AddSocketDataProvider(data.get()); @@ -1018,7 +1031,8 @@ constexpr size_t kMaxPerGroup = 1; pool().set_max_stream_sockets_per_group_for_testing(kMaxPerGroup); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); const scoped_refptr<X509Certificate> kCert = ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"); @@ -1063,7 +1077,8 @@ constexpr size_t kMaxPerGroup = 1; pool().set_max_stream_sockets_per_group_for_testing(kMaxPerGroup); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); const url::SchemeHostPort kDestination(GURL("https://a.test")); @@ -1099,7 +1114,8 @@ // following attempt failures are ignored and the existing requests get the // same fatal error. TEST_F(HttpStreamPoolAttemptManagerTest, TcpFailAfterNeedsClientAuth) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); const url::SchemeHostPort kDestination(GURL("https://a.test")); @@ -1132,7 +1148,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, RequestCanceledBeforeAttemptSuccess) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.RequestStream(pool()); @@ -1155,7 +1172,8 @@ // Tests that canceling a limit ignoring request doesn't result in hitting a // CHECK. Ensures that a group is destroyed after the attempt failed. TEST_F(HttpStreamPoolAttemptManagerTest, LimitIgnoringRequestCanceled) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.set_load_flags(LOAD_IGNORE_LIMITS).RequestStream(pool()); @@ -1249,7 +1267,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, OneIPEndPointFailed) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.RequestStream(pool()); @@ -1271,7 +1290,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, IPEndPointTimedout) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.RequestStream(pool()); @@ -1379,9 +1399,8 @@ requester.RequestStream(pool()); ASSERT_FALSE(requester.result().has_value()); - AttemptManager* manager = pool() - .GetOrCreateGroupForTesting(stream_key) - .GetAttemptManagerForTesting(); + AttemptManager* manager = + pool().GetOrCreateGroupForTesting(stream_key).attempt_manager(); // TODO(crbug.com/383606724): Don't modify internal representations. This // makes the test fragile and overly depend on internal representation. Best // practice is to test the public-facing API, when possible. @@ -1401,7 +1420,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, IPEndPointsSlow) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; HttpStreamRequest* request = requester.RequestStream(pool()); @@ -1428,7 +1448,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); ASSERT_EQ(manager->TcpBasedAttemptCount(), 1u); ASSERT_FALSE(request->completed()); @@ -1467,7 +1487,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester1.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); auto get_ip_endpoint_state = [&]() -> std::optional<IPEndPointState> { auto it = manager->ip_endpoint_states_for_testing().find(ip_endpoint); if (it == manager->ip_endpoint_states_for_testing().end()) { @@ -1628,7 +1648,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester1.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); auto get_ip_endpoint_state = [&](const IPEndPoint& ip_endpoint) -> std::optional<IPEndPointState> { auto it = manager->ip_endpoint_states_for_testing().find(ip_endpoint); @@ -1727,7 +1747,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester1.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); auto get_ip_endpoint_state = [&](const IPEndPoint& ip_endpoint) -> std::optional<IPEndPointState> { auto it = manager->ip_endpoint_states_for_testing().find(ip_endpoint); @@ -1779,7 +1799,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, PauseSlowTimerAfterTcpHandshakeForTls) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.set_destination("https://a.test").RequestStream(pool()); @@ -1810,7 +1831,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); ASSERT_EQ(manager->TcpBasedAttemptCount(), 1u); ASSERT_FALSE(requester.result().has_value()); @@ -1949,7 +1970,8 @@ constexpr size_t kMaxPerGroup = 4; pool().set_max_stream_sockets_per_group_for_testing(kMaxPerGroup); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); // Create streams up to the per-group limit for a destination. std::vector<std::unique_ptr<StreamRequester>> requesters; @@ -1972,7 +1994,7 @@ Group& group = pool().GetOrCreateGroupForTesting(requesters[0]->GetStreamKey()); - AttemptManager* manager = group.GetAttemptManagerForTesting(); + AttemptManager* manager = group.attempt_manager(); ASSERT_EQ(pool().TotalActiveStreamCount(), kMaxPerGroup); ASSERT_EQ(group.ActiveStreamSocketCount(), kMaxPerGroup); ASSERT_EQ(manager->TcpBasedAttemptCount(), kMaxPerGroup); @@ -2068,7 +2090,8 @@ ASSERT_EQ(pool().TotalActiveStreamCount(), kMaxPerGroup); ASSERT_EQ(group_a.ActiveStreamSocketCount(), kMaxPerGroup); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); // Create a HttpStream in group B. It should not be blocked because both // per-group and per-pool limits are not reached yet. @@ -2104,7 +2127,7 @@ LOAD_STATE_WAITING_FOR_STALLED_SOCKET_POOL); RunUntilIdle(); - AttemptManager* manager_b = group_b.GetAttemptManagerForTesting(); + AttemptManager* manager_b = group_b.attempt_manager(); ASSERT_FALSE(request2->completed()); ASSERT_TRUE(pool().ReachedMaxStreamLimit()); ASSERT_TRUE(pool().IsPoolStalled()); @@ -2143,11 +2166,12 @@ {"d.test", "192.0.2.4", RequestPriority::HIGHEST}, }; - std::vector<FakeServiceEndpointRequest*> endpoint_requests; + std::vector<base::WeakPtr<FakeServiceEndpointRequest>> endpoint_requests; std::vector<std::unique_ptr<StreamRequester>> requesters; std::vector<std::unique_ptr<SequencedSocketData>> socket_datas; for (const auto& [host, ip_address, priority] : items) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request->add_endpoint( ServiceEndpointBuilder().add_v4(ip_address).endpoint()); endpoint_requests.emplace_back(endpoint_request); @@ -2401,8 +2425,7 @@ } Group& group = pool().GetOrCreateGroupForTesting(stream_key); - ASSERT_GT(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), - kMaxPerGroup); + ASSERT_GT(group.attempt_manager()->TcpBasedAttemptCount(), kMaxPerGroup); // Complete requests that ignore limits. while (!limit_ignoring_requesters.empty()) { @@ -2523,7 +2546,7 @@ resolver()->AddFakeRequest(); HttpStreamRequest* request = requester.RequestStream(pool()); RunUntilIdle(); - AttemptManager* manager = group.GetAttemptManagerForTesting(); + AttemptManager* manager = group.attempt_manager(); ASSERT_FALSE(request->completed()); ASSERT_EQ(manager->PendingJobCount(), 1u); @@ -2573,7 +2596,8 @@ // Request a stream in group B. The request should close an idle stream in // group A. - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; HttpStreamRequest* request = requester.RequestStream(pool()); auto data = std::make_unique<SequencedSocketData>(); @@ -2591,7 +2615,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, ProcessPendingRequestDnsResolutionOngoing) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); auto data = std::make_unique<SequencedSocketData>(); socket_factory()->AddSocketDataProvider(data.get()); @@ -2614,8 +2639,10 @@ // when an IP address change event happens. TEST_F(HttpStreamPoolAttemptManagerTest, CancelAttemptAndRequestsOnIPAddressChange) { - FakeServiceEndpointRequest* endpoint_request1 = resolver()->AddFakeRequest(); - FakeServiceEndpointRequest* endpoint_request2 = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request1 = + resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request2 = + resolver()->AddFakeRequest(); auto data1 = std::make_unique<SequencedSocketData>(); data1->set_connect_data(MockConnect(ASYNC, ERR_IO_PENDING)); @@ -2641,11 +2668,11 @@ AttemptManager* manager1 = pool() .GetOrCreateGroupForTesting(requester1.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); AttemptManager* manager2 = pool() .GetOrCreateGroupForTesting(requester2.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); ASSERT_EQ(manager1->JobCount(), 1u); ASSERT_EQ(manager1->TcpBasedAttemptCount(), 1u); ASSERT_EQ(manager2->JobCount(), 1u); @@ -2668,7 +2695,8 @@ constexpr size_t kMaxPerGroup = 1; pool().set_max_stream_sockets_per_group_for_testing(kMaxPerGroup); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); const url::SchemeHostPort kDestination(GURL("https://a.test")); @@ -2762,7 +2790,7 @@ ASSERT_FALSE(raw_requester->result().has_value()); } AttemptManager* manager = - pool().GetGroupForTesting(stream_key)->GetAttemptManagerForTesting(); + pool().GetGroupForTesting(stream_key)->attempt_manager(); ASSERT_EQ(manager->JobCount(), 2u); ASSERT_EQ(manager->NotifiedJobCount(), 0u); ASSERT_EQ(manager->TcpBasedAttemptCount(), 2u); @@ -2785,8 +2813,7 @@ // Ensure that the job and attempt manager are still alive since there are // in-flight attempts. requesters.clear(); - manager = - pool().GetGroupForTesting(stream_key)->GetAttemptManagerForTesting(); + manager = pool().GetGroupForTesting(stream_key)->attempt_manager(); ASSERT_TRUE(manager); ASSERT_EQ(manager->JobCount(), 0u); ASSERT_EQ(manager->NotifiedJobCount(), 0u); @@ -2863,7 +2890,8 @@ const HttpStreamKey stream_key = StreamKeyBuilder().set_destination("https://a.test").Build(); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); std::vector<std::unique_ptr<SequencedSocketData>> socket_datas; std::vector<std::unique_ptr<SSLSocketDataProvider>> ssls; @@ -2896,7 +2924,7 @@ } Group& group = pool().GetOrCreateGroupForTesting(requesters[0]->GetStreamKey()); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), 0u); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), 0u); ASSERT_EQ(group.IdleStreamSocketCount(), 0u); ASSERT_EQ(group.ActiveStreamSocketCount(), 1u); ASSERT_EQ(pool().TotalConnectingStreamCount(), 0u); @@ -2905,7 +2933,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, SpdyCreateSessionFail) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); const MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 0)}; const MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1)}; @@ -3161,7 +3190,8 @@ ASSERT_FALSE(pool().IsPoolStalled()); // Request a stream in group C. It should be blocked. - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); const MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 1)}; const MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; @@ -3180,7 +3210,7 @@ RunUntilIdle(); Group& group_c = pool().GetOrCreateGroupForTesting(requester_c.GetStreamKey()); - ASSERT_EQ(group_c.GetAttemptManagerForTesting()->PendingJobCount(), 1u); + ASSERT_EQ(group_c.attempt_manager()->PendingJobCount(), 1u); ASSERT_TRUE(pool().ReachedMaxStreamLimit()); ASSERT_TRUE(pool().IsPoolStalled()); @@ -3214,7 +3244,8 @@ RunUntilIdle(); EXPECT_THAT(requester_a.result(), Optional(IsOk())); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester_b; requester_b.set_destination("https://example.test").RequestStream(pool()); @@ -3250,7 +3281,8 @@ ssl->next_proto = NextProto::kProtoHTTP2; socket_factory()->AddSSLSocketDataProvider(ssl.get()); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); // Create the second request to example.test. It will finds the matching // SPDY session, but the task to use the session runs asynchronously, so it @@ -3290,7 +3322,8 @@ RunUntilIdle(); EXPECT_THAT(requester_a.result(), Optional(IsOk())); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); Preconnector preconnector_b("https://example.test"); preconnector_b.Preconnect(pool()); @@ -3316,7 +3349,8 @@ requester_a.WaitForResult(); EXPECT_THAT(requester_a.result(), Optional(IsOk())); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester_b; requester_b.set_destination("https://example.test").RequestStream(pool()); @@ -3347,7 +3381,8 @@ RunUntilIdle(); EXPECT_THAT(requester_a.result(), Optional(IsOk())); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint( ServiceEndpointBuilder().add_ip_endpoint(kCommonEndPoint).endpoint()) @@ -3373,7 +3408,8 @@ RunUntilIdle(); EXPECT_THAT(requester_a.result(), Optional(IsOk())); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); const MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 1)}; const MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; @@ -3460,7 +3496,8 @@ RunUntilIdle(); EXPECT_THAT(requester_a.result(), Optional(IsOk())); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); const MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 1)}; const MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; @@ -3494,7 +3531,8 @@ RunUntilIdle(); EXPECT_THAT(requester_a.result(), Optional(IsOk())); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); const MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 1)}; const MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; @@ -3531,7 +3569,8 @@ const IPEndPoint kCommonEndPoint = MakeIPEndPoint("2001:db8::1", 443); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint( ServiceEndpointBuilder().add_ip_endpoint(kCommonEndPoint).endpoint()) @@ -3581,7 +3620,8 @@ stream_key.destination(), stream_key.network_anonymization_key(), /*supports_spdy=*/true); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester1; requester1.set_destination(kDestination).RequestStream(pool()); @@ -3602,7 +3642,7 @@ .CallOnServiceEndpointRequestFinished(OK); // There should be only one in-flight attempt because attempts are throttled. Group& group = pool().GetOrCreateGroupForTesting(requester1.GetStreamKey()); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), 1u); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), 1u); // This should not enter an infinite loop. pool().ProcessPendingRequestsInGroups(); @@ -3623,7 +3663,8 @@ stream_key.destination(), stream_key.network_anonymization_key(), /*supports_spdy=*/true); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester1; requester1.set_destination(kDestination).RequestStream(pool()); @@ -3654,14 +3695,14 @@ .CallOnServiceEndpointRequestFinished(OK); // There should be only one in-flight attempt because attempts are throttled. Group& group = pool().GetOrCreateGroupForTesting(requester1.GetStreamKey()); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), 1u); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), 1u); FastForwardBy(AttemptManager::kSpdyThrottleDelay); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), 2u); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), 2u); connect_completer1.Complete(OK); RunUntilIdle(); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), 0u); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), 0u); EXPECT_THAT(requester1.result(), Optional(IsOk())); EXPECT_THAT(requester2.result(), Optional(IsOk())); @@ -3678,7 +3719,8 @@ stream_key.destination(), stream_key.network_anonymization_key(), /*supports_spdy=*/true); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester1; requester1.set_destination(kDestination).RequestStream(pool()); @@ -3707,14 +3749,14 @@ .CallOnServiceEndpointRequestFinished(OK); // There should be only one in-flight attempt because attempts are throttled. Group& group = pool().GetOrCreateGroupForTesting(requester1.GetStreamKey()); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), 1u); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), 1u); FastForwardBy(AttemptManager::kSpdyThrottleDelay); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), 2u); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), 2u); connect_completer1.Complete(OK); RunUntilIdle(); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), 1u); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), 1u); connect_completer2.Complete(OK); RunUntilIdle(); @@ -3738,11 +3780,12 @@ int rv = preconnector.Preconnect(pool()); EXPECT_THAT(rv, IsOk()); - ASSERT_EQ(group.GetAttemptManagerForTesting(), nullptr); + ASSERT_EQ(group.attempt_manager(), nullptr); } TEST_F(HttpStreamPoolAttemptManagerTest, PreconnectFail) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); Preconnector preconnector("http://a.test"); @@ -3757,7 +3800,7 @@ ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CallOnServiceEndpointRequestFinished(OK); Group& group = pool().GetOrCreateGroupForTesting(preconnector.GetStreamKey()); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), 1u); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), 1u); ASSERT_FALSE(preconnector.result().has_value()); RunUntilIdle(); @@ -3767,7 +3810,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, PreconnectMultipleStreamsHttp1) { constexpr size_t kNumStreams = 2; - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); Preconnector preconnector("http://a.test"); @@ -3786,8 +3830,7 @@ ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CallOnServiceEndpointRequestFinished(OK); Group& group = pool().GetOrCreateGroupForTesting(preconnector.GetStreamKey()); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), - kNumStreams); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), kNumStreams); ASSERT_FALSE(preconnector.result().has_value()); RunUntilIdle(); @@ -3833,7 +3876,7 @@ int rv = preconnector.set_num_streams(kNumPreconnectStreams).Preconnect(pool()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), kNumPreconnectStreams - 1u); ASSERT_FALSE(preconnector.result().has_value()); @@ -3845,7 +3888,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, PreconnectMultipleStreamsHttp2) { constexpr size_t kNumStreams = 2; - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); Preconnector preconnector("https://a.test"); @@ -3869,7 +3913,7 @@ ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CallOnServiceEndpointRequestFinished(OK); Group& group = pool().GetOrCreateGroupForTesting(preconnector.GetStreamKey()); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), 1u); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), 1u); ASSERT_FALSE(preconnector.result().has_value()); RunUntilIdle(); @@ -3883,7 +3927,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, PreconnectRequireHttp1) { constexpr size_t kNumStreams = 2; - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); Preconnector preconnector("https://a.test"); @@ -3911,7 +3956,7 @@ ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CallOnServiceEndpointRequestFinished(OK); Group& group = pool().GetOrCreateGroupForTesting(preconnector.GetStreamKey()); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), 2u); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), 2u); ASSERT_FALSE(preconnector.result().has_value()); RunUntilIdle(); @@ -3925,7 +3970,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, PreconnectMultipleStreamsOkAndFail) { constexpr size_t kNumStreams = 2; - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); Preconnector preconnector("http://a.test"); @@ -3946,8 +3992,7 @@ ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CallOnServiceEndpointRequestFinished(OK); Group& group = pool().GetOrCreateGroupForTesting(preconnector.GetStreamKey()); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), - kNumStreams); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), kNumStreams); ASSERT_FALSE(preconnector.result().has_value()); preconnector.WaitForResult(); @@ -3963,7 +4008,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, PreconnectMultipleStreamsFailAndOk) { constexpr size_t kNumStreams = 2; - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); Preconnector preconnector("http://a.test"); @@ -3984,8 +4030,7 @@ ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CallOnServiceEndpointRequestFinished(OK); Group& group = pool().GetOrCreateGroupForTesting(preconnector.GetStreamKey()); - ASSERT_EQ(group.GetAttemptManagerForTesting()->TcpBasedAttemptCount(), - kNumStreams); + ASSERT_EQ(group.attempt_manager()->TcpBasedAttemptCount(), kNumStreams); ASSERT_FALSE(preconnector.result().has_value()); RunUntilIdle(); @@ -3996,7 +4041,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, PreconnectMultipleRequests) { constexpr std::string_view kDestination("http://a.test"); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); Preconnector preconnector1(kDestination); @@ -4043,7 +4089,8 @@ constexpr size_t kNumStreams = 2; - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); Preconnector preconnector("http://a.test"); @@ -4078,7 +4125,8 @@ StreamSocketHandle::SocketReuseType::kUnused, LoadTimingInfo::ConnectTiming()); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); Preconnector preconnector_b("http://b.test"); @@ -4107,7 +4155,8 @@ // Add two fake DNS resolutions (one for failing case, another is for success // case). for (size_t i = 0; i < 2; ++i) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CompleteStartSynchronously(OK); @@ -4145,11 +4194,10 @@ // Destroy the failed request. This should destroy the failing attempt manager // and should create a new one. requester1.ResetRequest(); - WaitForAttemptManagerComplete(*pool().GetGroupForTesting(stream_key)); - ASSERT_FALSE(pool() - .GetGroupForTesting(stream_key) - ->GetAttemptManagerForTesting() - ->is_failing()); + WaitForAttemptManagerComplete( + pool().GetGroupForTesting(stream_key)->attempt_manager()); + ASSERT_FALSE( + pool().GetGroupForTesting(stream_key)->attempt_manager()->is_failing()); // The paused request should succeed now. requester2.WaitForResult(); @@ -4168,7 +4216,8 @@ // Add two fake DNS resolutions (one for failing case, another is for success // case). for (size_t i = 0; i < 2; ++i) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CompleteStartSynchronously(OK); @@ -4220,7 +4269,8 @@ // 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) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CompleteStartSynchronously(OK); @@ -4273,21 +4323,18 @@ // Destroy the first request. This should resume paused requests. failing_requester1.ResetRequest(); - WaitForAttemptManagerComplete(*pool().GetGroupForTesting(stream_key)); - ASSERT_FALSE(pool() - .GetGroupForTesting(stream_key) - ->GetAttemptManagerForTesting() - ->is_failing()); + WaitForAttemptManagerComplete( + pool().GetGroupForTesting(stream_key)->attempt_manager()); + ASSERT_FALSE( + pool().GetGroupForTesting(stream_key)->attempt_manager()->is_failing()); // 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) - ->GetAttemptManagerForTesting() - ->is_failing()); + ASSERT_TRUE( + pool().GetGroupForTesting(stream_key)->attempt_manager()->is_failing()); failing_requester2.ResetRequest(); // Complete subsequent requests. These requests could be associated with @@ -4390,8 +4437,7 @@ 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)->GetAttemptManagerForTesting()); + 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. @@ -4535,10 +4581,9 @@ HttpStreamKey stream_key = requester1.GetStreamKey(); requester1.ResetRequest(); requester2.ResetRequest(); - WaitForAttemptManagerComplete(*pool().GetGroupForTesting(stream_key)); - ASSERT_FALSE(pool() - .GetOrCreateGroupForTesting(stream_key) - .GetAttemptManagerForTesting()); + WaitForAttemptManagerComplete( + pool().GetGroupForTesting(stream_key)->attempt_manager()); + ASSERT_FALSE(pool().GetOrCreateGroupForTesting(stream_key).attempt_manager()); } TEST_F(HttpStreamPoolAttemptManagerTest, PreconnectPriority) { @@ -4555,7 +4600,7 @@ EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); EXPECT_EQ(pool() .GetOrCreateGroupForTesting(preconnector.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->GetPriority(), RequestPriority::IDLE); } @@ -4600,7 +4645,7 @@ requester_b.ReleaseStream().reset(); EXPECT_FALSE(pool() .GetOrCreateGroupForTesting(requester_a.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->IsStalledByPoolLimit()); } @@ -4627,7 +4672,7 @@ EXPECT_FALSE(pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->IsStalledByPoolLimit()); } @@ -4655,7 +4700,7 @@ EXPECT_FALSE(pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->IsStalledByPoolLimit()); } @@ -4741,7 +4786,8 @@ // is updated to true after the QUIC attempt succeeds. quic_session_pool()->set_has_quic_ever_worked_on_current_network(false); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); AddQuicData(); @@ -4769,7 +4815,7 @@ EXPECT_THAT(requester.result(), Optional(IsOk())); EXPECT_THAT(pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->GetQuicAttemptResultForTesting(), Optional(IsOk())); EXPECT_TRUE(quic_session_pool()->has_quic_ever_worked_on_current_network()); @@ -4800,7 +4846,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); ASSERT_EQ(manager->TcpBasedAttemptCount(), 0u); requester.WaitForResult(); @@ -4808,7 +4854,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, QuicOkDnsAlpn) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); AddQuicData(); @@ -4839,7 +4886,7 @@ EXPECT_THAT(requester2.result(), Optional(IsOk())); EXPECT_THAT(pool() .GetOrCreateGroupForTesting(requester1.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->GetQuicAttemptResultForTesting(), Optional(IsOk())); } @@ -4849,7 +4896,8 @@ TEST_F(HttpStreamPoolAttemptManagerTest, DontStartQuicAfterFailure) { AddQuicData(); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); // Request a stream to create an AttemptManager. StreamRequester requester; @@ -4858,29 +4906,27 @@ .RequestStream(pool()); ASSERT_FALSE(requester.result().has_value()); - // Simulate a network change event to fail the AttemptManager. + // Simulate a network change event to fail the AttemptManager. The + // AttemptManager will reset ServiceEndpointRequest. NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); FastForwardUntilNoTasksRemain(); + ASSERT_FALSE(endpoint_request); - // Complete the service endpoint resolution. QuicAttempt should not start. - endpoint_request - ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) - .CallOnServiceEndpointRequestFinished(OK); requester.WaitForResult(); EXPECT_THAT(requester.result(), Optional(IsError(ERR_NETWORK_CHANGED))); ASSERT_TRUE(pool() .GetGroupForTesting(requester.GetStreamKey()) - ->GetAttemptManagerForTesting() + ->attempt_manager() ->is_failing()); ASSERT_FALSE(pool() .GetGroupForTesting(requester.GetStreamKey()) - ->GetAttemptManagerForTesting() + ->attempt_manager() ->GetQuicAttemptResultForTesting()); // Ensure that the attempt manager completes after the request is destroyed. requester.ResetRequest(); WaitForAttemptManagerComplete( - *pool().GetGroupForTesting(requester.GetStreamKey())); + pool().GetGroupForTesting(requester.GetStreamKey())->attempt_manager()); } // Tests that QUIC is not attempted when marked broken. @@ -4941,7 +4987,7 @@ FastForwardBy(base::Milliseconds(1)); EXPECT_THAT(pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_CONNECTION_REFUSED))); ASSERT_FALSE(requester.result().has_value()); @@ -4995,7 +5041,7 @@ requester.WaitForResult(); EXPECT_THAT(pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_CONNECTION_REFUSED))); EXPECT_THAT(requester.result(), Optional(IsError(ERR_CONNECTION_REFUSED))); @@ -5135,7 +5181,8 @@ base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(net::features::kAsyncQuicSession); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); AddQuicData(); @@ -5171,13 +5218,14 @@ EXPECT_THAT(pool() .GetOrCreateGroupForTesting(requester1.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->GetQuicAttemptResultForTesting(), Optional(IsOk())); } TEST_F(HttpStreamPoolAttemptManagerTest, AlternativeSerivcesDisabled) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CompleteStartSynchronously(OK); @@ -5196,7 +5244,7 @@ EXPECT_THAT(requester.result(), Optional(IsOk())); ASSERT_FALSE(pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->GetQuicAttemptResultForTesting() .has_value()); } @@ -5234,7 +5282,7 @@ EXPECT_THAT(requester2.result(), Optional(IsOk())); EXPECT_THAT(pool() .GetOrCreateGroupForTesting(requester1.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->GetQuicAttemptResultForTesting(), Optional(IsOk())); } @@ -5279,7 +5327,8 @@ // Set that QUIC is working on the current network. quic_session_pool()->set_has_quic_ever_worked_on_current_network(true); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CompleteStartSynchronously(OK); @@ -5298,7 +5347,7 @@ EXPECT_THAT(requester.result(), Optional(IsOk())); EXPECT_THAT(pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_DNS_NO_MATCHING_SUPPORTED_ALPN))); // No matching ALPN should not update @@ -5323,7 +5372,8 @@ const HttpStreamKey stream_key = StreamKeyBuilder("https://www.example.org").Build(); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request->set_crypto_ready(true); // The first request triggers DNS resolution. @@ -5332,7 +5382,7 @@ ASSERT_FALSE(requester1.result().has_value()); AttemptManager* manager = - pool().GetGroupForTesting(stream_key)->GetAttemptManagerForTesting(); + pool().GetGroupForTesting(stream_key)->attempt_manager(); // The second request should not trigger a QUIC attempt in AttemptManager. StreamRequester requester2(stream_key); @@ -5359,7 +5409,8 @@ } TEST_F(HttpStreamPoolAttemptManagerTest, QuicPreconnect) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CompleteStartSynchronously(OK); @@ -5403,7 +5454,8 @@ tcp_data.set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); socket_factory()->AddSocketDataProvider(&tcp_data); - FakeServiceEndpointRequest* endpoint_request1 = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request1 = + resolver()->AddFakeRequest(); endpoint_request1 ->add_endpoint( ServiceEndpointBuilder().add_ip_endpoint(kCommonEndPoint).endpoint()) @@ -5416,7 +5468,8 @@ RunUntilIdle(); EXPECT_THAT(requester1.result(), Optional(IsOk())); - FakeServiceEndpointRequest* endpoint_request2 = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request2 = + resolver()->AddFakeRequest(); endpoint_request2 ->add_endpoint( ServiceEndpointBuilder().add_ip_endpoint(kCommonEndPoint).endpoint()) @@ -5455,7 +5508,8 @@ tcp_data1.set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); socket_factory()->AddSocketDataProvider(&tcp_data1); - FakeServiceEndpointRequest* endpoint_request1 = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request1 = + resolver()->AddFakeRequest(); endpoint_request1 ->add_endpoint(ServiceEndpointBuilder().add_v6("2001:db8::1").endpoint()) .CompleteStartSynchronously(OK); @@ -5482,7 +5536,8 @@ tcp_data2.set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); socket_factory()->AddSocketDataProvider(&tcp_data2); - FakeServiceEndpointRequest* endpoint_request2 = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request2 = + resolver()->AddFakeRequest(); endpoint_request2 ->add_endpoint(ServiceEndpointBuilder().add_v6("2001:db8::2").endpoint()) .CompleteStartSynchronously(OK); @@ -5547,7 +5602,8 @@ quic_data2.set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); socket_factory()->AddSocketDataProvider(&quic_data2); - FakeServiceEndpointRequest* endpoint_request1 = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request1 = + resolver()->AddFakeRequest(); endpoint_request1 ->add_endpoint( ServiceEndpointBuilder().add_ip_endpoint(kCommonEndPoint).endpoint()) @@ -5560,7 +5616,8 @@ RunUntilIdle(); EXPECT_THAT(requester1.result(), Optional(IsOk())); - FakeServiceEndpointRequest* endpoint_request2 = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request2 = + resolver()->AddFakeRequest(); StreamRequester requester2; requester2.set_destination(kAltDestination) @@ -5601,7 +5658,8 @@ tcp_data.set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); socket_factory()->AddSocketDataProvider(&tcp_data); - FakeServiceEndpointRequest* endpoint_request1 = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request1 = + resolver()->AddFakeRequest(); endpoint_request1 ->add_endpoint( ServiceEndpointBuilder().add_ip_endpoint(kCommonEndPoint).endpoint()) @@ -5614,7 +5672,8 @@ RunUntilIdle(); EXPECT_THAT(requester1.result(), Optional(IsOk())); - FakeServiceEndpointRequest* endpoint_request2 = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request2 = + resolver()->AddFakeRequest(); endpoint_request2 ->add_endpoint( ServiceEndpointBuilder().add_ip_endpoint(kCommonEndPoint).endpoint()) @@ -5639,7 +5698,8 @@ // In production code, we currently disable both IP-based pooling and QUIC at // the same time. TEST_F(HttpStreamPoolAttemptManagerTest, QuicMatchingIpSessionDisabled) { - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CompleteStartSynchronously(OK); @@ -5658,7 +5718,7 @@ EXPECT_THAT(requester.result(), Optional(IsOk())); ASSERT_FALSE(pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting() + .attempt_manager() ->GetQuicAttemptResultForTesting() .has_value()); } @@ -5667,7 +5727,8 @@ constexpr base::TimeDelta kDelay = base::Milliseconds(10); quic_session_pool()->SetTimeDelayForWaitingJobForTesting(kDelay); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CompleteStartSynchronously(OK); @@ -5689,7 +5750,8 @@ constexpr base::TimeDelta kDelay = base::Milliseconds(10); quic_session_pool()->SetTimeDelayForWaitingJobForTesting(kDelay); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) .CompleteStartSynchronously(OK); @@ -5735,7 +5797,8 @@ quic_session_pool()->SetTimeDelayForWaitingJobForTesting(kDelay); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); SequencedSocketData tcp_data; socket_factory()->AddSocketDataProvider(&tcp_data); @@ -5756,7 +5819,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); // Provide an IP address. QUIC attempt isn't triggered yet since it's not // ready for cryptographic handshakes, but the stream attempt delay timer @@ -5798,7 +5861,8 @@ quic_session_pool()->SetTimeDelayForWaitingJobForTesting(kQuicDelay); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); // QUIC attempt stalls forever. auto quic_data = std::make_unique<MockQuicData>(quic_version()); @@ -5819,7 +5883,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); // Provide an IP address. QUIC attempt isn't triggered yet since it's not // ready for cryptographic handshakes. @@ -5863,7 +5927,8 @@ quic_session_pool()->SetTimeDelayForWaitingJobForTesting(kDelay); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); MockConnectCompleter connect_completer; SequencedSocketData tcp_data; @@ -5879,7 +5944,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(preconnector.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); // Provide an IP address. QUIC attempt isn't triggered yet since it's not // ready for cryptographic handshakes. @@ -5917,7 +5982,8 @@ constexpr base::TimeDelta kDelay = base::Milliseconds(10); quic_session_pool()->SetTimeDelayForWaitingJobForTesting(kDelay); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); auto quic_data = std::make_unique<MockQuicData>(quic_version()); quic_data->AddConnect(SYNCHRONOUS, ERR_IO_PENDING); @@ -6359,7 +6425,7 @@ AttemptManager* origin_manager = pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); ASSERT_TRUE(origin_manager); EXPECT_EQ(origin_manager->GetPriority(), RequestPriority::LOW); @@ -6368,9 +6434,8 @@ .set_destination(url::SchemeHostPort( url::kHttpsScheme, kAlternative.host(), kAlternative.port())) .Build(); - AttemptManager* alt_manager = pool() - .GetOrCreateGroupForTesting(alt_stream_key) - .GetAttemptManagerForTesting(); + AttemptManager* alt_manager = + pool().GetOrCreateGroupForTesting(alt_stream_key).attempt_manager(); ASSERT_TRUE(alt_manager); EXPECT_EQ(alt_manager->GetPriority(), RequestPriority::LOW); @@ -6591,10 +6656,8 @@ failing_requester.WaitForResult(); EXPECT_THAT(failing_requester.result(), Optional(IsError(ERR_CONNECTION_REFUSED))); - EXPECT_TRUE(pool() - .GetGroupForTesting(stream_key) - ->GetAttemptManagerForTesting() - ->is_failing()); + EXPECT_TRUE( + pool().GetGroupForTesting(stream_key)->attempt_manager()->is_failing()); // Subsequent requests (jobs) are paused until the first request is destroyed. std::vector<std::unique_ptr<StreamRequester>> requesters; @@ -6625,7 +6688,8 @@ for (auto& requester : requesters) { requester->ResetRequest(); } - WaitForAttemptManagerComplete(*pool().GetGroupForTesting(stream_key)); + WaitForAttemptManagerComplete( + pool().GetGroupForTesting(stream_key)->attempt_manager()); EXPECT_FALSE(pool().GetGroupForTesting(stream_key)); EXPECT_EQ(pool().TotalActiveStreamCount(), 0u); } @@ -6791,7 +6855,8 @@ // Actual test: Create a request that starts a QuicSessionAttempt, which // is later destroyed since there is a matching IP session. - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); MockConnectCompleter quic_completer; MockQuicData quic_data(quic_version()); @@ -6967,7 +7032,8 @@ ASSERT_TRUE(MakeTestEchKeys("www.example.org", /*max_name_len=*/128, &ech_config_list)); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); SequencedSocketData tcp_data; tcp_data.set_connect_data(MockConnect(SYNCHRONOUS, OK)); @@ -7079,7 +7145,7 @@ EXPECT_THAT(pool() .GetOrCreateGroupForTesting(stream_key) - .GetAttemptManagerForTesting() + .attempt_manager() ->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_ABORTED))); } @@ -7272,7 +7338,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); EXPECT_THAT(manager->TcpBasedAttemptCount(), 0u); EXPECT_THAT(manager->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_NETWORK_CHANGED))); @@ -7286,7 +7352,8 @@ base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(net::features::kAsyncQuicSession); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); endpoint_request ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint()) @@ -7321,7 +7388,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); EXPECT_THAT(manager->TcpBasedAttemptCount(), 0u); EXPECT_THAT(manager->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_NAME_NOT_RESOLVED))); @@ -7365,7 +7432,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); EXPECT_THAT(manager->TcpBasedAttemptCount(), 0u); EXPECT_THAT(manager->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED))); @@ -7404,7 +7471,7 @@ AttemptManager* manager = pool() .GetOrCreateGroupForTesting(requester.GetStreamKey()) - .GetAttemptManagerForTesting(); + .attempt_manager(); EXPECT_THAT(manager->TcpBasedAttemptCount(), 0u); EXPECT_THAT(manager->GetQuicAttemptResultForTesting(), Optional(IsError(ERR_CERT_DATE_INVALID))); @@ -7418,7 +7485,8 @@ data.set_connect_data(MockConnect(&completer)); socket_factory()->AddSocketDataProvider(&data); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.set_destination(kDefaultDestination) @@ -7455,7 +7523,8 @@ SSLSocketDataProvider ssl(ASYNC, OK); socket_factory()->AddSSLSocketDataProvider(&ssl); - FakeServiceEndpointRequest* endpoint_request = resolver()->AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> endpoint_request = + resolver()->AddFakeRequest(); StreamRequester requester; requester.set_destination(kDefaultDestination)
diff --git a/net/http/http_stream_pool_group.cc b/net/http/http_stream_pool_group.cc index 3fe2e7f..7161ac7 100644 --- a/net/http/http_stream_pool_group.cc +++ b/net/http/http_stream_pool_group.cc
@@ -358,10 +358,6 @@ attempt_manager_.reset(); - if (on_attempt_manager_complete_callback_for_testing_) { - std::move(on_attempt_manager_complete_callback_for_testing_).Run(); - } - if (should_resume_paused_job) { ResumePausedJob(); } else { @@ -401,12 +397,6 @@ CleanupIdleStreamSockets(CleanupMode::kTimeoutOnly, "For testing"); } -void HttpStreamPool::Group::SetOnAttemptManagerCompleteCallbackForTesting( - base::OnceClosure callback) { - CHECK(on_attempt_manager_complete_callback_for_testing_.is_null()); - on_attempt_manager_complete_callback_for_testing_ = std::move(callback); -} - bool HttpStreamPool::Group::IsFailing() const { // If we don't have an AttemptManager the group is not considered as failing // because we destroy an AttemptManager after all in-flight attempts are
diff --git a/net/http/http_stream_pool_group.h b/net/http/http_stream_pool_group.h index 4293e92..6339a188 100644 --- a/net/http/http_stream_pool_group.h +++ b/net/http/http_stream_pool_group.h
@@ -193,13 +193,6 @@ void CleanupTimedoutIdleStreamSocketsForTesting(); - AttemptManager* GetAttemptManagerForTesting() const { - return attempt_manager_.get(); - } - - void SetOnAttemptManagerCompleteCallbackForTesting( - base::OnceClosure callback); - private: FRIEND_TEST_ALL_PREFIXES(HttpStreamPoolGroupTest, ComparePausedJobSet); @@ -276,8 +269,6 @@ // them to avoid dangling pointers. PausedJobSet resumed_jobs_; - base::OnceClosure on_attempt_manager_complete_callback_for_testing_; - 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 1155cec..ea4a2fe 100644 --- a/net/http/http_stream_pool_group_unittest.cc +++ b/net/http/http_stream_pool_group_unittest.cc
@@ -514,7 +514,7 @@ delegate1.reset(); delegate2.reset(); delegate3.reset(); - WaitForAttemptManagerComplete(*GetTestGroup()); + WaitForAttemptManagerComplete(GetTestGroup()->attempt_manager()); ASSERT_FALSE(GetTestGroup()); }
diff --git a/net/http/http_stream_pool_test_util.cc b/net/http/http_stream_pool_test_util.cc index 245eaa2..c23ce72 100644 --- a/net/http/http_stream_pool_test_util.cc +++ b/net/http/http_stream_pool_test_util.cc
@@ -9,6 +9,7 @@ #include "net/base/features.h" #include "net/base/net_errors.h" #include "net/http/http_stream_pool.h" +#include "net/http/http_stream_pool_attempt_manager.h" #include "net/http/http_stream_pool_group.h" #include "net/http/http_stream_pool_job.h" #include "net/log/net_log_with_source.h" @@ -97,12 +98,14 @@ FakeServiceEndpointResolver::~FakeServiceEndpointResolver() = default; -FakeServiceEndpointRequest* FakeServiceEndpointResolver::AddFakeRequest() { +base::WeakPtr<FakeServiceEndpointRequest> +FakeServiceEndpointResolver::AddFakeRequest() { std::unique_ptr<FakeServiceEndpointRequest> request = std::make_unique<FakeServiceEndpointRequest>(); - FakeServiceEndpointRequest* raw_request = request.get(); + base::WeakPtr<FakeServiceEndpointRequest> weak_request = + request->weak_ptr_factory_.GetWeakPtr(); requests_.emplace_back(std::move(request)); - return raw_request; + return weak_request; } void FakeServiceEndpointResolver::OnShutdown() {} @@ -278,9 +281,10 @@ group_id.disable_cert_network_fetches()); } -void WaitForAttemptManagerComplete(HttpStreamPool::Group& group) { +void WaitForAttemptManagerComplete( + HttpStreamPool::AttemptManager* attempt_manager) { base::RunLoop run_loop; - group.SetOnAttemptManagerCompleteCallbackForTesting(run_loop.QuitClosure()); + attempt_manager->SetOnCompleteCallbackForTesting(run_loop.QuitClosure()); run_loop.Run(); }
diff --git a/net/http/http_stream_pool_test_util.h b/net/http/http_stream_pool_test_util.h index 280cd8af..e547ceb 100644 --- a/net/http/http_stream_pool_test_util.h +++ b/net/http/http_stream_pool_test_util.h
@@ -12,6 +12,7 @@ #include <string> #include <vector> +#include "base/memory/weak_ptr.h" #include "base/test/test_future.h" #include "net/base/completion_once_callback.h" #include "net/base/net_errors.h" @@ -100,6 +101,8 @@ void ChangeRequestPriority(RequestPriority priority) override; private: + friend class FakeServiceEndpointResolver; + raw_ptr<Delegate> delegate_; int start_result_ = ERR_IO_PENDING; @@ -108,6 +111,8 @@ bool endpoints_crypto_ready_ = false; ResolveErrorInfo resolve_error_info_; RequestPriority priority_ = RequestPriority::IDLE; + + base::WeakPtrFactory<FakeServiceEndpointRequest> weak_ptr_factory_{this}; }; // A fake HostResolver that implements the ServiceEndpointRequest API using @@ -127,7 +132,7 @@ // CreateServiceEndpointRequest() consumes the request. You will need to call // this method multiple times when you expect multiple // CreateServiceEndpointRequest() calls. - FakeServiceEndpointRequest* AddFakeRequest(); + base::WeakPtr<FakeServiceEndpointRequest> AddFakeRequest(); // HostResolver methods: void OnShutdown() override; @@ -344,8 +349,9 @@ // Convert a ClientSocketPool::GroupId to an HttpStreamKey. HttpStreamKey GroupIdToHttpStreamKey(const ClientSocketPool::GroupId& group_id); -// Wait for the `group`'s current AttemptManager completion. -void WaitForAttemptManagerComplete(HttpStreamPool::Group& group); +// Wait for the `attempt_manager`'s completion. +void WaitForAttemptManagerComplete( + HttpStreamPool::AttemptManager* attempt_manager); } // namespace net
diff --git a/net/http/mock_http_cache.cc b/net/http/mock_http_cache.cc index a28ee40..69b386e 100644 --- a/net/http/mock_http_cache.cc +++ b/net/http/mock_http_cache.cc
@@ -26,6 +26,7 @@ #include "net/base/net_errors.h" #include "net/disk_cache/disk_cache_test_util.h" #include "net/http/http_cache_writers.h" +#include "net/http/no_vary_search_cache_storage_file_operations.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -712,9 +713,11 @@ : MockHttpCache(std::make_unique<MockBackendFactory>()) {} MockHttpCache::MockHttpCache( - std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory) + std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory, + std::unique_ptr<NoVarySearchCacheStorageFileOperations> file_operations) : http_cache_(std::make_unique<MockNetworkLayer>(), - std::move(disk_cache_factory)) {} + std::move(disk_cache_factory), + std::move(file_operations)) {} disk_cache::Backend* MockHttpCache::backend() { TestGetBackendCompletionCallback cb;
diff --git a/net/http/mock_http_cache.h b/net/http/mock_http_cache.h index 619f21f..dc406eb 100644 --- a/net/http/mock_http_cache.h +++ b/net/http/mock_http_cache.h
@@ -26,6 +26,7 @@ #include "net/disk_cache/disk_cache.h" #include "net/http/http_cache.h" #include "net/http/http_transaction_test_util.h" +#include "net/http/no_vary_search_cache_storage_file_operations.h" namespace net { @@ -289,7 +290,9 @@ public: MockHttpCache(); explicit MockHttpCache( - std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory); + std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory, + std::unique_ptr<NoVarySearchCacheStorageFileOperations> file_operations = + nullptr); HttpCache* http_cache() { return &http_cache_; }
diff --git a/net/http/no_vary_search_cache.cc b/net/http/no_vary_search_cache.cc index 1564d1cd..e320a56b 100644 --- a/net/http/no_vary_search_cache.cc +++ b/net/http/no_vary_search_cache.cc
@@ -8,6 +8,7 @@ #include <compare> #include <iostream> #include <limits> +#include <map> #include <tuple> #include <type_traits> #include <utility> @@ -544,11 +545,10 @@ std::optional<std::string> query = query_string->query(); CHECK(!query || query->find('#') == std::string::npos); - // Set `journal` to nullptr so no notification is fired for this - // insertion. + // Pass `journal_` so the merged entries are journalled as insertions. ReconstructURLAndDoInsert(base_url, std::move(base_url_cache_key), nvs_data, std::move(query), query_string->update_time(), - /*journal=*/nullptr); + journal_); } } @@ -859,16 +859,17 @@ using QueryString = NoVarySearchCache::QueryString; // Get a list of every QueryString object in the map so that we can sort - // them to reconstruct the `lru_` list. - std::vector<QueryString*> all_query_strings; - all_query_strings.reserve(size); + // them to reconstruct the `lru_` list. std::multimap is used here as a + // workaround for the excessive binary size cost of std::sort. + std::multimap<base::Time, QueryString*> all_query_strings; for (auto& [base_url_cache_key, data_map] : cache.map_) { for (auto& [nvs_data, query_string_list] : data_map) { query_string_list.nvs_data_ref = &nvs_data; query_string_list.key_ref = &base_url_cache_key; NoVarySearchCache::ForEachQueryString( query_string_list.list, [&](QueryString* query_string) { - all_query_strings.push_back(query_string); + all_query_strings.emplace(query_string->update_time(), + query_string); }); } } @@ -876,15 +877,9 @@ return std::nullopt; } - // Sort by `update_time`, which we use as an approximation of `use_time` - // during deserialization on the assumption that it won't make much - // difference. - std::ranges::sort(all_query_strings, std::less<base::Time>(), - [](QueryString* qs) { return qs->update_time(); }); - // Insert each entry at the head of the list, so that the oldest entry ends // up at the tail. - for (QueryString* qs : all_query_strings) { + for (auto [_, qs] : all_query_strings) { qs->LruNode::InsertBefore(cache.lru_.head()); }
diff --git a/net/http/no_vary_search_cache.h b/net/http/no_vary_search_cache.h index 89aba4be..1f0c7f2b 100644 --- a/net/http/no_vary_search_cache.h +++ b/net/http/no_vary_search_cache.h
@@ -95,7 +95,7 @@ // Called when an entry is inserted or refreshed by the MaybeInsert() // method. Not called when MaybeInsert() results in no changes to the - // database. + // database. Also called by MergeFrom() for each merged entry. virtual void OnInsert(const std::string& base_url_cache_key, const HttpNoVarySearchData& nvs_data, const std::optional<std::string>& query, @@ -198,8 +198,9 @@ // Merge entries from `newer` in order from the least-recently-used to the // most-recently-used, treating them as newly used. Less recently-used entries - // will be evicted if necessary to avoid exceeding the maximum size. Journal - // methods are not called. + // will be evicted if necessary to avoid exceeding the maximum size. + // Journal::OnInsert() is called as if the entries were newly inserted (but + // with the original update_time). void MergeFrom(const NoVarySearchCache& newer); // Returns the size (number of stored original query strings) of the cache. @@ -210,7 +211,7 @@ size_t max_size() const { return max_size_; } // Returns true if the top-level map is empty. This should be equivalent to - // GetSizeForTesting() == 0 in the absence of bugs. + // size() == 0 in the absence of bugs. bool IsTopLevelMapEmptyForTesting() const; private:
diff --git a/net/http/no_vary_search_cache_storage_mock_file_operations.cc b/net/http/no_vary_search_cache_storage_mock_file_operations.cc new file mode 100644 index 0000000..a4b1bae --- /dev/null +++ b/net/http/no_vary_search_cache_storage_mock_file_operations.cc
@@ -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. + +#include "net/http/no_vary_search_cache_storage_mock_file_operations.h" + +namespace net { + +MockFileOperations::MockFileOperations() = default; +MockFileOperations::~MockFileOperations() = default; + +MockWriter::MockWriter() = default; +MockWriter::~MockWriter() = default; + +} // namespace net
diff --git a/net/http/no_vary_search_cache_storage_mock_file_operations.h b/net/http/no_vary_search_cache_storage_mock_file_operations.h new file mode 100644 index 0000000..80325b7 --- /dev/null +++ b/net/http/no_vary_search_cache_storage_mock_file_operations.h
@@ -0,0 +1,52 @@ +// 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 NET_HTTP_NO_VARY_SEARCH_CACHE_STORAGE_MOCK_FILE_OPERATIONS_H_ +#define NET_HTTP_NO_VARY_SEARCH_CACHE_STORAGE_MOCK_FILE_OPERATIONS_H_ + +#include "net/http/no_vary_search_cache_storage_file_operations.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace net { + +// Mock implementation of NoVarySearchCacheStorageFileOperations. +class MockFileOperations : public NoVarySearchCacheStorageFileOperations { + public: + MockFileOperations(); + ~MockFileOperations() override; + + MOCK_METHOD((base::expected<LoadResult, base::File::Error>), + Load, + (std::string_view filename, size_t max_size), + (override)); + MOCK_METHOD((base::expected<void, base::File::Error>), + AtomicSave, + (std::string_view filename, + base::span<const base::span<const uint8_t>> segments), + (override)); + MOCK_METHOD((base::expected<std::unique_ptr<Writer>, base::File::Error>), + CreateWriter, + (std::string_view filename), + (override)); +}; + +// Mock implementation of NoVarySearchCacheStorageFileOperations::Writer. This +// can be returned from CreateWriter() after setting expectations, like this: +// +// auto mock_writer = std::make_unique<StrictMock<MockWriter>>(); +// EXPECT_CALL(*mock_writer, Write).WillOnce(Return(true)); +// EXPECT_CALL(file_operations, CreateWriter) +// .WillOnce(Return(std::move(mock_writer))); +// +class MockWriter : public NoVarySearchCacheStorageFileOperations::Writer { + public: + MockWriter(); + ~MockWriter() override; + + MOCK_METHOD(bool, Write, (base::span<const uint8_t> data), (override)); +}; + +} // namespace net + +#endif // NET_HTTP_NO_VARY_SEARCH_CACHE_STORAGE_MOCK_FILE_OPERATIONS_H_
diff --git a/net/http/no_vary_search_cache_storage_unittest.cc b/net/http/no_vary_search_cache_storage_unittest.cc index 1dec151..baa390cd 100644 --- a/net/http/no_vary_search_cache_storage_unittest.cc +++ b/net/http/no_vary_search_cache_storage_unittest.cc
@@ -36,6 +36,7 @@ #include "net/base/features.h" #include "net/http/no_vary_search_cache.h" #include "net/http/no_vary_search_cache_storage_file_operations.h" +#include "net/http/no_vary_search_cache_storage_mock_file_operations.h" #include "net/http/no_vary_search_cache_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -821,29 +822,6 @@ EXPECT_GT(journal_entry_size, 0u); } -// Mock implementation of FileOperations for error injection. -class MockFileOperations : public NoVarySearchCacheStorageFileOperations { - public: - MOCK_METHOD((base::expected<LoadResult, base::File::Error>), - Load, - (std::string_view filename, size_t max_size), - (override)); - MOCK_METHOD((base::expected<void, base::File::Error>), - AtomicSave, - (std::string_view filename, - base::span<const base::span<const uint8_t>> segments), - (override)); - MOCK_METHOD((base::expected<std::unique_ptr<Writer>, base::File::Error>), - CreateWriter, - (std::string_view filename), - (override)); -}; - -class MockWriter : public NoVarySearchCacheStorageFileOperations::Writer { - public: - MOCK_METHOD(bool, Write, (base::span<const uint8_t> data), (override)); -}; - class NoVarySearchCacheStorageMockFilesystemTest : public NoVarySearchCacheStorageTestBase { public:
diff --git a/net/http/no_vary_search_cache_unittest.cc b/net/http/no_vary_search_cache_unittest.cc index 552ba0c..8e14f3ff 100644 --- a/net/http/no_vary_search_cache_unittest.cc +++ b/net/http/no_vary_search_cache_unittest.cc
@@ -39,9 +39,12 @@ namespace nvs_test = no_vary_search_cache_test_utils; using ::testing::_; +using ::testing::AllOf; using ::testing::EndsWith; using ::testing::Eq; using ::testing::Ge; +using ::testing::InSequence; +using ::testing::Le; using ::testing::Optional; constexpr size_t kMaxSize = 5; @@ -1244,12 +1247,41 @@ TEST_P(NoVarySearchCacheReplayTest, MergeFrom) { const auto test_cases = ReplayTestCases(); + const base::Time before_inserts = base::Time::Now(); + for (const auto& [description, to_insert, no_vary_search_value, to_lookup] : test_cases) { cache().MaybeInsert(to_insert, TestHeaders(no_vary_search_value)); } + const base::Time after_inserts = base::Time::Now(); + NoVarySearchCache target(kMaxSize); + ScopedMockJournal journal(target); + + EXPECT_CALL(journal, OnErase).Times(0); + + { + InSequence s; + for (const auto& [description, to_insert, no_vary_search_value, to_lookup] : + test_cases) { + auto expected_nvs_data = HttpNoVarySearchData::ParseFromHeaders( + TestHeaders(no_vary_search_value)); + const GURL& url = to_insert.url; + std::optional<std::string_view> query; + if (url.has_query()) { + query = url.query_piece(); + } + std::string base_url = url.spec(); + if (size_t pos = base_url.find('?'); pos != std::string::npos) { + base_url = base_url.substr(0, pos); + } + EXPECT_CALL(journal, + OnInsert(EndsWith(base_url), Eq(expected_nvs_data), Eq(query), + AllOf(Ge(before_inserts), Le(after_inserts)))); + } + } + target.MergeFrom(cache()); EXPECT_EQ(cache().size(), target.size());
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc index ef16c0f..4ac56ba 100644 --- a/net/url_request/url_request_context_builder.cc +++ b/net/url_request/url_request_context_builder.cc
@@ -21,6 +21,7 @@ #include "base/types/pass_key.h" #include "build/build_config.h" #include "net/base/cache_type.h" +#include "net/base/features.h" #include "net/base/net_errors.h" #include "net/base/network_delegate_impl.h" #include "net/cert/cert_verifier.h" @@ -39,6 +40,7 @@ #include "net/http/http_network_session.h" #include "net/http/http_server_properties.h" #include "net/http/http_server_properties_manager.h" +#include "net/http/no_vary_search_cache_storage_file_operations.h" #include "net/http/transport_security_persister.h" #include "net/http/transport_security_state.h" #include "net/log/net_log.h" @@ -558,6 +560,8 @@ std::move(http_transaction_factory), enable_shared_zstd_); } + std::unique_ptr<NoVarySearchCacheStorageFileOperations> file_operations; + if (http_cache_enabled_) { std::unique_ptr<HttpCache::BackendFactory> http_cache_backend; if (http_cache_params_.type != HttpCacheParams::IN_MEMORY) { @@ -581,6 +585,10 @@ DISK_CACHE, backend_type, http_cache_params_.file_operations_factory, http_cache_params_.path, http_cache_params_.max_size, http_cache_params_.reset_cache); + if (base::FeatureList::IsEnabled(features::kHttpCacheNoVarySearch)) { + file_operations = NoVarySearchCacheStorageFileOperations::Create( + http_cache_params_.path); + } } else { http_cache_backend = HttpCache::DefaultBackend::InMemory(http_cache_params_.max_size); @@ -591,7 +599,8 @@ #endif http_transaction_factory = std::make_unique<HttpCache>( - std::move(http_transaction_factory), std::move(http_cache_backend)); + std::move(http_transaction_factory), std::move(http_cache_backend), + std::move(file_operations)); } context->set_http_transaction_factory(std::move(http_transaction_factory));
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 2c75034..b1a654a 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/android/android_info.h" +#include "net/url_request/url_request.h" #include <stdint.h> @@ -14,6 +14,7 @@ #include <string_view> #include <utility> +#include "base/android/android_info.h" #include "base/base64.h" #include "base/base64url.h" #include "base/compiler_specific.h" @@ -109,6 +110,7 @@ #include "net/http/http_status_code.h" #include "net/http/http_transaction_test_util.h" #include "net/http/http_util.h" +#include "net/http/no_vary_search_cache_storage_file_operations.h" #include "net/http/transport_security_state.h" #include "net/http/transport_security_state_source.h" #include "net/log/file_net_log_observer.h" @@ -144,7 +146,6 @@ #include "net/url_request/referrer_policy.h" #include "net/url_request/static_http_user_agent_settings.h" #include "net/url_request/storage_access_status_cache.h" -#include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h" #include "net/url_request/url_request_filter.h" @@ -8798,7 +8799,8 @@ network_layer->OnSuspend(); std::unique_ptr<HttpTransactionFactory> factory = std::make_unique<HttpCache>(std::move(network_layer), - HttpCache::DefaultBackend::InMemory(0)); + HttpCache::DefaultBackend::InMemory(0), + /*file_operations=*/nullptr); return factory; })); auto context = context_builder->Build();
diff --git a/pdf/pdf_ink_module.cc b/pdf/pdf_ink_module.cc index 2af8a969..727ce88 100644 --- a/pdf/pdf_ink_module.cc +++ b/pdf/pdf_ink_module.cc
@@ -351,8 +351,6 @@ &PdfInkModule::HandleFinishTextAnnotationMessage}, {"getAnnotationBrush", &PdfInkModule::HandleGetAnnotationBrushMessage}, - {"getTextAnnotFontNames", - &PdfInkModule::HandleGetTextAnnotFontNamesMessage}, {"setAnnotationBrush", &PdfInkModule::HandleSetAnnotationBrushMessage}, {"setAnnotationMode", &PdfInkModule::HandleSetAnnotationModeMessage}, @@ -1308,12 +1306,6 @@ MaybeSetCursor(); } -void PdfInkModule::HandleGetTextAnnotFontNamesMessage( - const base::Value::Dict& message) { - // TODO(crbug.com/409439509): Fill in this method. For now, just create it - // so the backend doesn't CHECK when it's sent from the frontend. -} - void PdfInkModule::HandleStartTextAnnotationMessage( const base::Value::Dict& message) { // TODO(crbug.com/409439509): Fill in this method. For now, just create it
diff --git a/pdf/pdf_ink_module.h b/pdf/pdf_ink_module.h index 45adf9d..cf02d0f 100644 --- a/pdf/pdf_ink_module.h +++ b/pdf/pdf_ink_module.h
@@ -388,7 +388,6 @@ void HandleAnnotationUndoMessage(const base::Value::Dict& message); void HandleFinishTextAnnotationMessage(const base::Value::Dict& message); void HandleGetAnnotationBrushMessage(const base::Value::Dict& message); - void HandleGetTextAnnotFontNamesMessage(const base::Value::Dict& message); void HandleSetAnnotationBrushMessage(const base::Value::Dict& message); void HandleSetAnnotationModeMessage(const base::Value::Dict& message); void HandleStartTextAnnotationMessage(const base::Value::Dict& message);
diff --git a/pdf/pdfium/pdfium_text_fragment_finder.cc b/pdf/pdfium/pdfium_text_fragment_finder.cc index c9397315..ac0ab4a 100644 --- a/pdf/pdfium/pdfium_text_fragment_finder.cc +++ b/pdf/pdfium/pdfium_text_fragment_finder.cc
@@ -296,6 +296,10 @@ std::ref(text_fragment_suffix_), fragment)); if (text_fragment_end_) { + // If a text fragment end was found, then the text fragment start list + // should be cleared except for the start range that was used in the + // search. + text_fragment_starts_ = {start_range}; FinishTextFragmentSearch(); return; }
diff --git a/pdf/pdfium/pdfium_text_fragment_finder_unittest.cc b/pdf/pdfium/pdfium_text_fragment_finder_unittest.cc index 011e2df..d452aee 100644 --- a/pdf/pdfium/pdfium_text_fragment_finder_unittest.cc +++ b/pdf/pdfium/pdfium_text_fragment_finder_unittest.cc
@@ -44,11 +44,10 @@ const auto highlights = finder.FindTextFragments({"Google"}); ASSERT_EQ(highlights.size(), 1u); - static constexpr char16_t kExpectedString[] = u"Google"; + static constexpr std::u16string_view kExpectedString = u"Google"; const auto& range = highlights[0]; EXPECT_EQ(range.GetText(), kExpectedString); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString.size())); EXPECT_EQ(range.char_index(), 9); EXPECT_EQ(range.page_index(), 0); } @@ -63,12 +62,11 @@ const auto highlights = finder.FindTextFragments({"spanner,database"}); ASSERT_EQ(highlights.size(), 1u); - static constexpr char16_t kExpectedString[] = + static constexpr std::u16string_view kExpectedString = u"Spanner: Google\x2019s Globally-Distributed Database\r"; const auto& range = highlights[0]; EXPECT_EQ(range.GetText(), kExpectedString); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString.size())); EXPECT_EQ(range.char_index(), 0); EXPECT_EQ(range.page_index(), 0); } @@ -83,11 +81,10 @@ const auto highlights = finder.FindTextFragments({"how,-many"}); ASSERT_EQ(highlights.size(), 1u); - static constexpr char16_t kExpectedString[] = u"how"; + static constexpr std::u16string_view kExpectedString = u"how"; const auto& range = highlights[0]; EXPECT_EQ(range.GetText(), kExpectedString); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString.size())); EXPECT_EQ(range.char_index(), 4141); EXPECT_EQ(range.page_index(), 0); } @@ -103,13 +100,12 @@ ASSERT_EQ(highlights.size(), 1u); const auto& range = highlights[0]; - static constexpr char16_t kExpectedString[] = + static constexpr std::u16string_view kExpectedString = u"This\r\npaper describes how Spanner is structured, its feature " u"set,\r\nthe rationale underlying various design decisions, and " u"a\r\nnovel time API that exposes clock uncertainty. This API\r"; EXPECT_EQ(range.GetText(), kExpectedString); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString.size())); EXPECT_EQ(range.char_index(), 704); EXPECT_EQ(range.page_index(), 0); } @@ -124,11 +120,10 @@ const auto highlights = finder.FindTextFragments({"is-,Google"}); ASSERT_EQ(highlights.size(), 1u); - static constexpr char16_t kExpectedString[] = u"Google"; + static constexpr std::u16string_view kExpectedString = u"Google"; const auto& range = highlights[0]; EXPECT_EQ(range.GetText(), kExpectedString); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString.size())); EXPECT_EQ(range.char_index(), 489); EXPECT_EQ(range.page_index(), 0); } @@ -143,11 +138,10 @@ const auto highlights = finder.FindTextFragments({"of-,Google,-'s"}); ASSERT_EQ(highlights.size(), 1u); - static constexpr char16_t kExpectedString[] = u"Google"; + static constexpr std::u16string_view kExpectedString = u"Google"; const auto& range = highlights[0]; EXPECT_EQ(range.GetText(), kExpectedString); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString.size())); EXPECT_EQ(range.char_index(), 2072); EXPECT_EQ(range.page_index(), 0); } @@ -164,12 +158,11 @@ ASSERT_EQ(highlights.size(), 1u); const auto& range = highlights[0]; - static constexpr char16_t kExpectedString[] = + static constexpr std::u16string_view kExpectedString = u"API that exposes clock uncertainty. This API\r\nand its " u"implementation"; EXPECT_EQ(range.GetText(), kExpectedString); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString.size())); EXPECT_EQ(range.char_index(), 840); EXPECT_EQ(range.page_index(), 0); } @@ -185,12 +178,11 @@ finder.FindTextFragments({"and-,applications,old,-timestamps"}); ASSERT_EQ(highlights.size(), 1u); - static constexpr char16_t kExpectedString[] = + static constexpr std::u16string_view kExpectedString = u"applications can read data at old"; const auto& range = highlights[0]; EXPECT_EQ(range.GetText(), kExpectedString); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString.size())); EXPECT_EQ(range.char_index(), 3591); EXPECT_EQ(range.page_index(), 0); } @@ -207,33 +199,30 @@ "and-,applications,old,-timestamps"}); ASSERT_EQ(highlights.size(), 4u); - static constexpr char16_t kExpectedString1[] = u"Google"; - static constexpr int kExpectedString1Length = - static_cast<int>(base::span_from_cstring(kExpectedString1).size()); - static constexpr char16_t kExpectedString2[] = + static constexpr std::u16string_view kExpectedString1 = u"Google"; + static constexpr std::u16string_view kExpectedString2 = u"applications can read data at old"; auto range = highlights[0]; EXPECT_EQ(range.GetText(), kExpectedString1); - EXPECT_EQ(range.char_count(), kExpectedString1Length); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString1.size())); EXPECT_EQ(range.char_index(), 9); EXPECT_EQ(range.page_index(), 0); range = highlights[1]; EXPECT_EQ(range.GetText(), kExpectedString1); - EXPECT_EQ(range.char_count(), kExpectedString1Length); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString1.size())); EXPECT_EQ(range.char_index(), 489); EXPECT_EQ(range.page_index(), 0); range = highlights[2]; EXPECT_EQ(range.GetText(), kExpectedString1); - EXPECT_EQ(range.char_count(), kExpectedString1Length); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString1.size())); EXPECT_EQ(range.char_index(), 2072); EXPECT_EQ(range.page_index(), 0); range = highlights[3]; EXPECT_EQ(range.GetText(), kExpectedString2); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString2).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString2.size())); EXPECT_EQ(range.char_index(), 3591); EXPECT_EQ(range.page_index(), 0); } @@ -250,42 +239,37 @@ "second-,page", "second-,page,in,-document"}); ASSERT_EQ(highlights.size(), 5u); - static constexpr char16_t kExpectedString1[] = u"Link"; - static constexpr int kExpectedString1Length = - static_cast<int>(base::span_from_cstring(kExpectedString1).size()); - static constexpr char16_t kExpectedString2[] = u"Page"; - static constexpr char16_t kExpectedString3[] = u"page\r"; - static constexpr char16_t kExpectedString4[] = u"Page in"; + static constexpr std::u16string_view kExpectedString1 = u"Link"; + static constexpr std::u16string_view kExpectedString2 = u"Page"; + static constexpr std::u16string_view kExpectedString3 = u"page\r"; + static constexpr std::u16string_view kExpectedString4 = u"Page in"; auto range = highlights[0]; EXPECT_EQ(range.GetText(), kExpectedString1); - EXPECT_EQ(range.char_count(), kExpectedString1Length); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString1.size())); EXPECT_EQ(range.char_index(), 0); EXPECT_EQ(range.page_index(), 0); range = highlights[1]; EXPECT_EQ(range.GetText(), kExpectedString1); - EXPECT_EQ(range.char_count(), kExpectedString1Length); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString1.size())); EXPECT_EQ(range.char_index(), 27); EXPECT_EQ(range.page_index(), 0); range = highlights[2]; EXPECT_EQ(range.GetText(), kExpectedString2); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString2).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString2.size())); EXPECT_EQ(range.char_index(), 7); EXPECT_EQ(range.page_index(), 1); range = highlights[3]; EXPECT_EQ(range.GetText(), kExpectedString3); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString3).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString3.size())); EXPECT_EQ(range.char_index(), 59); EXPECT_EQ(range.page_index(), 0); range = highlights[4]; EXPECT_EQ(range.GetText(), kExpectedString4); - EXPECT_EQ(range.char_count(), - static_cast<int>(base::span_from_cstring(kExpectedString4).size())); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString4.size())); EXPECT_EQ(range.char_index(), 7); EXPECT_EQ(range.page_index(), 1); } @@ -341,6 +325,27 @@ EXPECT_TRUE(highlights.empty()); } +TEST_P(PDFiumTextFragmentFinderTest, + TextStartAndEnd_FindsCorrectInstanceOfStart) { + NiceMock<SearchStringTestClient> client; + std::unique_ptr<PDFiumEngine> engine = + InitializeEngine(&client, FILE_PATH_LITERAL("link_annots.pdf")); + ASSERT_TRUE(engine); + + PDFiumTextFragmentFinder finder(engine.get()); + // "second" appears on both pages of the PDF. + const auto highlights = finder.FindTextFragments({"second,document"}); + ASSERT_EQ(highlights.size(), 1u); + + static constexpr std::u16string_view kExpectedString = + u"Second Page in Document"; + const auto& range = highlights[0]; + EXPECT_EQ(range.GetText(), kExpectedString); + EXPECT_EQ(range.char_count(), static_cast<int>(kExpectedString.size())); + EXPECT_EQ(range.char_index(), 0); + EXPECT_EQ(range.page_index(), 1); +} + INSTANTIATE_TEST_SUITE_P(All, PDFiumTextFragmentFinderTest, testing::Bool()); } // namespace chrome_pdf
diff --git a/printing/backend/cups_ipp_constants.cc b/printing/backend/cups_ipp_constants.cc index 80b573c..e20ad20 100644 --- a/printing/backend/cups_ipp_constants.cc +++ b/printing/backend/cups_ipp_constants.cc
@@ -33,6 +33,7 @@ constexpr char kIppMediaCol[] = "media-col"; // PWG 5100.7 constexpr char kIppDuplex[] = CUPS_SIDES; constexpr char kIppResolution[] = "printer-resolution"; // RFC 8011 +constexpr char kIppPrintQuality[] = "print-quality"; // RFC 8011 // collation values constexpr char kCollated[] = "separate-documents-collated-copies";
diff --git a/printing/backend/cups_ipp_constants.h b/printing/backend/cups_ipp_constants.h index cfaa699..726b6be 100644 --- a/printing/backend/cups_ipp_constants.h +++ b/printing/backend/cups_ipp_constants.h
@@ -33,6 +33,7 @@ COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppMediaCol[]; COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppDuplex[]; COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppResolution[]; +COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppPrintQuality[]; // collation values COMPONENT_EXPORT(PRINT_BACKEND) extern const char kCollated[];
diff --git a/printing/mojom/print.mojom b/printing/mojom/print.mojom index ae7143b..662bfe9 100644 --- a/printing/mojom/print.mojom +++ b/printing/mojom/print.mojom
@@ -53,6 +53,15 @@ kHpPjlColorAsGrayYes, // Used in HP printer PPDs. }; +// Print job quality values (from rfc8011). +[EnableIf=is_chromeos] +enum Quality { + kUnknownQuality = -1, + kDraft = 3, + kNormal = 4, + kHigh = 5 +}; + // Print job duplex mode values. enum DuplexMode { kUnknownDuplexMode = -1,
diff --git a/printing/print_settings.h b/printing/print_settings.h index 43574fa6..ead9c4a 100644 --- a/printing/print_settings.h +++ b/printing/print_settings.h
@@ -325,6 +325,9 @@ print_scaling_ = print_scaling; } mojom::PrintScalingType print_scaling() const { return print_scaling_; } + + void set_quality(mojom::Quality quality) { quality_ = quality; } + mojom::Quality quality() const { return quality_; } #endif // BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(ENABLE_OOP_PRINTING_NO_OOP_BASIC_PRINT_DIALOG) @@ -467,6 +470,9 @@ // Print scaling type. mojom::PrintScalingType print_scaling_ = mojom::PrintScalingType::kUnknownPrintScalingType; + + // Print qulity for the printer to use. + mojom::Quality quality_ = mojom::Quality::kUnknownQuality; #endif // BUILDFLAG(IS_CHROMEOS) };
diff --git a/printing/printing_context_chromeos.cc b/printing/printing_context_chromeos.cc index d0c7c6d..0730c29 100644 --- a/printing/printing_context_chromeos.cc +++ b/printing/printing_context_chromeos.cc
@@ -305,6 +305,12 @@ PrintScalingTypeToIPPString(settings.print_scaling()).c_str()); } + // print quality + if (settings.quality() != mojom::Quality::kUnknownQuality) { + ippAddInteger(options, IPP_TAG_JOB, IPP_TAG_ENUM, kIppPrintQuality, + static_cast<int>(settings.quality())); + } + std::map<std::string, std::vector<int>> multival; std::string media_source; for (const auto& setting : settings.advanced_settings()) {
diff --git a/remoting/base/crash/BUILD.gn b/remoting/base/crash/BUILD.gn index 0909b55c..14d886ba 100644 --- a/remoting/base/crash/BUILD.gn +++ b/remoting/base/crash/BUILD.gn
@@ -5,26 +5,19 @@ import("//remoting/build/config/remoting_build.gni") source_set("crash") { - public_deps = [ ":breakpad_utils" ] - if (enable_chromoting_crashpad) { + public_deps = [] + if (is_linux || is_win) { public_deps += [ ":crashpad" ] - } else { - public_deps += [ ":breakpad" ] + } + if (is_win) { + public_deps += [ + ":breakpad", + ":breakpad_utils", + ] } } -source_set("breakpad_utils") { - sources = [ - "breakpad_utils.cc", - "breakpad_utils.h", - ] - deps = [ - "//base", - "//remoting/base:remoting_base_version", - ] -} - -if (enable_chromoting_crashpad) { +if (is_linux || is_win) { source_set("crashpad_db_mgr") { sources = [ "crashpad_database_manager.cc", @@ -38,15 +31,27 @@ "//third_party/crashpad/crashpad/util", ] } + source_set("crashpad") { sources = [ - "crash_reporting.cc", - "crash_reporting.h", - "crashpad.h", - "crashpad_linux.cc", - "crashpad_linux.h", + "crash_reporting_crashpad.cc", + "crash_reporting_crashpad.h", ] + if (is_linux) { + sources += [ + "crashpad_linux.cc", + "crashpad_linux.h", + ] + } + if (is_win) { + sources += [ + "crashpad_win.cc", + "crashpad_win.h", + ] + } + configs += [ "//remoting/build/config:host_implementation" ] + deps = [ ":crashpad_db_mgr", "//base", @@ -57,11 +62,27 @@ "//third_party/crashpad/crashpad/util", ] } -} else { +} + +if (is_win) { + source_set("breakpad_utils") { + sources = [ + "breakpad_utils.cc", + "breakpad_utils.h", + ] + deps = [ + "//base", + "//remoting/base:remoting_base_version", + ] + } + source_set("breakpad") { sources = [ - "crash_reporting.cc", - "crash_reporting.h", + "breakpad_server.cc", + "breakpad_win.cc", + "breakpad_win.h", + "crash_reporting_breakpad.cc", + "crash_reporting_breakpad.h", ] configs += [ @@ -72,19 +93,9 @@ deps = [ ":breakpad_utils", "//base", + "//remoting/base:logging", "//remoting/base:remoting_base_version", + "//third_party/breakpad:breakpad_handler", ] - - if (is_win) { - sources += [ - "breakpad_server.cc", - "breakpad_win.cc", - "breakpad_win.h", - ] - deps += [ - "//remoting/base:logging", - "//third_party/breakpad:breakpad_handler", - ] - } } }
diff --git a/remoting/base/crash/breakpad_server.cc b/remoting/base/crash/breakpad_server.cc index 4a071cd..5eed1655 100644 --- a/remoting/base/crash/breakpad_server.cc +++ b/remoting/base/crash/breakpad_server.cc
@@ -15,7 +15,7 @@ #include "base/win/security_descriptor.h" #include "base/win/sid.h" #include "remoting/base/crash/breakpad_utils.h" -#include "remoting/base/crash/crash_reporting.h" +#include "remoting/base/crash/crash_reporting_breakpad.h" #include "remoting/base/logging.h" #include "remoting/base/version.h" #include "third_party/breakpad/breakpad/src/client/windows/crash_generation/crash_generation_server.h"
diff --git a/remoting/base/crash/crash_reporting.cc b/remoting/base/crash/crash_reporting_breakpad.cc similarity index 62% copy from remoting/base/crash/crash_reporting.cc copy to remoting/base/crash/crash_reporting_breakpad.cc index 73f7e651..07746c5 100644 --- a/remoting/base/crash/crash_reporting.cc +++ b/remoting/base/crash/crash_reporting_breakpad.cc
@@ -2,34 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/base/crash/crash_reporting.h" +#include "remoting/base/crash/crash_reporting_breakpad.h" #if BUILDFLAG(IS_WIN) #include "remoting/base/crash/breakpad_win.h" #endif // BUILDFLAG(IS_WIN) -#if BUILDFLAG(IS_LINUX) -#include "remoting/base/crash/crashpad_linux.h" -#endif // BUILDFLAG(IS_LINUX) - namespace remoting { -void LogAndCleanupCrashDatabase() { -#if BUILDFLAG(IS_LINUX) - CrashpadLinux::GetInstance().LogAndCleanupCrashpadDatabase(); -#endif // BUILDFLAG(IS_LINUX) -} - // Not implemented for Mac, see https://crbug.com/714714 -void InitializeCrashReporting() { +void InitializeBreakpadReporting() { // Touch the object to make sure it is initialized. #if BUILDFLAG(IS_WIN) BreakpadWin::GetInstance().Initialize(); #endif // BUILDFLAG(IS_WIN) - -#if BUILDFLAG(IS_LINUX) - CrashpadLinux::GetInstance().Initialize(); -#endif // BUILDFLAG(IS_LINUX) } #if BUILDFLAG(IS_WIN)
diff --git a/remoting/base/crash/crash_reporting.h b/remoting/base/crash/crash_reporting_breakpad.h similarity index 80% rename from remoting/base/crash/crash_reporting.h rename to remoting/base/crash/crash_reporting_breakpad.h index e26895d..9d66258 100644 --- a/remoting/base/crash/crash_reporting.h +++ b/remoting/base/crash/crash_reporting_breakpad.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 REMOTING_BASE_CRASH_CRASH_REPORTING_H_ -#define REMOTING_BASE_CRASH_CRASH_REPORTING_H_ +#ifndef REMOTING_BASE_CRASH_CRASH_REPORTING_BREAKPAD_H_ +#define REMOTING_BASE_CRASH_CRASH_REPORTING_BREAKPAD_H_ #include <string> @@ -12,11 +12,7 @@ namespace remoting { -// Query and log the entries in the crash database. -// This will also verify that crash entries were uploaded and will clean up -// old entries to help reduce disk space usage. -void LogAndCleanupCrashDatabase(); - +#if BUILDFLAG(IS_WIN) // Initializes collection and upload of crash reports. The caller has to ensure // that the user has agreed to crash dump reporting. // @@ -26,9 +22,8 @@ // be caught and reported. This should not be a problem as static non-POD // objects are not allowed by the style guide and exceptions to this rule are // rare. -void InitializeCrashReporting(); +void InitializeBreakpadReporting(); -#if BUILDFLAG(IS_WIN) // Initializes a client for out-of-process (OOP) crash reporting using the // server process which owns the pipe referenced by |crash_server_pipe_handle|. // This is used for processes which do not have permission to write to the @@ -44,4 +39,4 @@ } // namespace remoting -#endif // REMOTING_BASE_CRASH_CRASH_REPORTING_H_ +#endif // REMOTING_BASE_CRASH_CRASH_REPORTING_BREAKPAD_H_
diff --git a/remoting/base/crash/crash_reporting.cc b/remoting/base/crash/crash_reporting_crashpad.cc similarity index 65% rename from remoting/base/crash/crash_reporting.cc rename to remoting/base/crash/crash_reporting_crashpad.cc index 73f7e651..572c0609 100644 --- a/remoting/base/crash/crash_reporting.cc +++ b/remoting/base/crash/crash_reporting_crashpad.cc
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/base/crash/crash_reporting.h" +#include "remoting/base/crash/crash_reporting_crashpad.h" #if BUILDFLAG(IS_WIN) -#include "remoting/base/crash/breakpad_win.h" +#include "remoting/base/crash/crashpad_win.h" #endif // BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_LINUX) @@ -21,10 +21,10 @@ } // Not implemented for Mac, see https://crbug.com/714714 -void InitializeCrashReporting() { +void InitializeCrashpadReporting() { // Touch the object to make sure it is initialized. #if BUILDFLAG(IS_WIN) - BreakpadWin::GetInstance().Initialize(); + CrashpadWin::GetInstance().Initialize(); #endif // BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_LINUX) @@ -32,11 +32,4 @@ #endif // BUILDFLAG(IS_LINUX) } -#if BUILDFLAG(IS_WIN) -void InitializeOopCrashClient(const std::string& server_pipe_handle) { - // Touch the object to make sure it is initialized. - BreakpadWin::GetInstance().Initialize(server_pipe_handle); -} -#endif // BUILDFLAG(IS_WIN) - } // namespace remoting
diff --git a/remoting/base/crash/crash_reporting_crashpad.h b/remoting/base/crash/crash_reporting_crashpad.h new file mode 100644 index 0000000..b1e8fe8 --- /dev/null +++ b/remoting/base/crash/crash_reporting_crashpad.h
@@ -0,0 +1,31 @@ +// 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 REMOTING_BASE_CRASH_CRASH_REPORTING_CRASHPAD_H_ +#define REMOTING_BASE_CRASH_CRASH_REPORTING_CRASHPAD_H_ + +#include "build/build_config.h" +#include "build/buildflag.h" + +namespace remoting { + +// Query and log the entries in the crash database. +// This will also verify that crash entries were uploaded and will clean up +// old entries to help reduce disk space usage. +void LogAndCleanupCrashDatabase(); + +// Initializes collection and upload of crash reports. The caller has to ensure +// that the user has agreed to crash dump reporting. +// +// Crash reporting has to be initialized as early as possible (e.g. the first +// thing in main()) to catch crashes occurring during process startup. +// Crashes which occur during the global static construction phase will not +// be caught and reported. This should not be a problem as static non-POD +// objects are not allowed by the style guide and exceptions to this rule are +// rare. +void InitializeCrashpadReporting(); + +} // namespace remoting + +#endif // REMOTING_BASE_CRASH_CRASH_REPORTING_CRASHPAD_H_
diff --git a/remoting/base/crash/crashpad.h b/remoting/base/crash/crashpad.h deleted file mode 100644 index 437a8928..0000000 --- a/remoting/base/crash/crashpad.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2024 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef REMOTING_BASE_CRASH_CRASHPAD_H_ -#define REMOTING_BASE_CRASH_CRASHPAD_H_ - -namespace remoting { - -// Initializes collection and upload of crash reports. This will only be -// called if the user has already opted in to having their crash dumps -// uploaded. -// -// Crash reporting has to be initialized as early as possible (e.g. the first -// thing in main()) to catch crashes occurring during process startup. -// Crashes which occur during the global static construction phase will not -// be caught and reported. This should not be a problem as static non-POD -// objects are not allowed by the style guide and exceptions to this rule are -// rare. -void InitializeCrashReporting(); - -} // namespace remoting - -#endif // REMOTING_BASE_CRASH_CRASHPAD_H_
diff --git a/remoting/base/crash/crashpad_database_manager.cc b/remoting/base/crash/crashpad_database_manager.cc index a8dbe0f..2839ffe 100644 --- a/remoting/base/crash/crashpad_database_manager.cc +++ b/remoting/base/crash/crashpad_database_manager.cc
@@ -11,11 +11,17 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/i18n/time_formatting.h" +#include "base/path_service.h" #include "base/strings/string_number_conversions.h" #include "remoting/base/file_path_util_linux.h" #include "third_party/crashpad/crashpad/client/crash_report_database.h" #include "third_party/crashpad/crashpad/client/settings.h" +#if BUILDFLAG(IS_WIN) +#include "base/base_paths.h" +#include "base/strings/utf_string_conversions.h" +#endif // BUILDFLAG(IS_WIN) + namespace { const base::FilePath::CharType kChromotingCrashpadDatabasePath[] = @@ -38,7 +44,12 @@ namespace remoting { base::FilePath GetCrashpadDatabasePath() { - base::FilePath database_path = GetConfigDirectoryPath(); + base::FilePath database_path; +#if BUILDFLAG(IS_WIN) + base::PathService::Get(base::BasePathKey::DIR_ASSETS, &database_path); +#else + database_path = GetConfigDirectoryPath(); +#endif return database_path.Append(kChromotingCrashpadDatabasePath); } @@ -51,8 +62,13 @@ base::FilePath database_path = GetCrashpadDatabasePath(); base::File::Error error; if (!base::CreateDirectoryAndGetError(database_path, &error)) { +#if BUILDFLAG(IS_WIN) + logger_->LogError("Unable to get directory for crash database: " + + base::WideToUTF8(database_path.value())); +#else logger_->LogError("Unable to get directory for crash database: " + database_path.value()); +#endif logger_->LogError("File Error: " + base::File::ErrorToString(error)); return false; } @@ -154,7 +170,11 @@ } else { logger_->Log(" Crash id: " + id + " (http://go/crash/" + id + ")"); } +#if BUILDFLAG(IS_WIN) + logger_->Log(" path: " + base::WideToUTF8(report.file_path.value())); +#else logger_->Log(" path: " + report.file_path.value()); +#endif logger_->Log(" uuid: " + report.uuid.ToString()); logger_->Log(" created: " + TimeFormatHTTP(base::Time::FromTimeT(report.creation_time)));
diff --git a/remoting/base/crash/crashpad_win.cc b/remoting/base/crash/crashpad_win.cc new file mode 100644 index 0000000..29c7eb7 --- /dev/null +++ b/remoting/base/crash/crashpad_win.cc
@@ -0,0 +1,104 @@ +// 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 "remoting/base/crash/crashpad_win.h" + +#include "base/base_paths.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/no_destructor.h" +#include "base/path_service.h" +#include "base/time/time.h" +#include "remoting/base/crash/crashpad_database_manager.h" +#include "remoting/base/logging.h" +#include "remoting/base/version.h" +#include "third_party/crashpad/crashpad/client/crash_report_database.h" +#include "third_party/crashpad/crashpad/client/crashpad_client.h" + +namespace remoting { + +constexpr wchar_t kChromotingCrashpadHandler[] = L"crashpad-handler"; +constexpr char kDefaultCrashpadUploadUrl[] = + "https://clients2.google.com/cr/report"; + +CrashpadWin::CrashpadWin() : database_(*this) {} + +bool CrashpadWin::Initialize() { + if (!database_.InitializeCrashpadDatabase()) { + LOG(ERROR) << "Failed to initialize database for Crashpad"; + return false; + } + + // We only initialize crash handling if the user has consented to record and + // upload reports, so we can simply enable it here. + if (!database_.EnableReportUploads()) { + LOG(WARNING) << "Unable to enable Crashpad uploads."; + } + + // Leave metrics_path empty because this option is not used (or supported) on + // non-Chromium builds. + base::FilePath metrics_path; + + std::map<std::string, std::string> annotations; + annotations["prod"] = "Chromoting_Win"; + annotations["ver"] = REMOTING_VERSION_STRING; + annotations["plat"] = std::string("Windows"); + + std::vector<std::string> arguments; + // Make sure Crashpad's generate_dump tool includes monitor-self annotations. + // This creates a second crashpad instance that monitors the handler so it can + // report crashes in the handler. + arguments.push_back("--monitor-self-annotation=ptype=crashpad-handler"); + + base::FilePath handler_path; + if (!GetCrashpadHandlerPath(&handler_path)) { + return false; + } + + crashpad::CrashpadClient client; + if (!client.StartHandler(handler_path, GetCrashpadDatabasePath(), + metrics_path, kDefaultCrashpadUploadUrl, annotations, + arguments, false, false)) { + LOG(ERROR) << "Failed to start Crashpad handler."; + return false; + } + + HOST_LOG << "Crashpad handler started."; + return true; +} + +void CrashpadWin::LogAndCleanupCrashpadDatabase() { + database_.LogCompletedCrashpadReports(); + database_.LogPendingCrashpadReports(); + database_.CleanupCompletedCrashpadReports(); +} + +// static +CrashpadWin& CrashpadWin::GetInstance() { + static base::NoDestructor<CrashpadWin> instance; + return *instance; +} + +// private + +// CrashpadDatabaseManager::Logger overrides +void CrashpadWin::Log(const std::string message) const { + HOST_LOG << message; +} + +void CrashpadWin::LogError(const std::string message) const { + LOG(ERROR) << message; +} + +bool CrashpadWin::GetCrashpadHandlerPath(base::FilePath* handler_path) { + if (!base::PathService::Get(base::DIR_EXE, handler_path)) { + LOG(ERROR) << "Unable to get exe dir for crashpad handler"; + return false; + } + *handler_path = handler_path->Append(kChromotingCrashpadHandler); + return true; +} + +} // namespace remoting
diff --git a/remoting/base/crash/crashpad_win.h b/remoting/base/crash/crashpad_win.h new file mode 100644 index 0000000..d450853 --- /dev/null +++ b/remoting/base/crash/crashpad_win.h
@@ -0,0 +1,37 @@ +// 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 REMOTING_BASE_CRASH_CRASHPAD_WIN_H_ +#define REMOTING_BASE_CRASH_CRASHPAD_WIN_H_ + +#include "base/files/file_path.h" +#include "remoting/base/crash/crashpad_database_manager.h" + +namespace remoting { + +class CrashpadWin : CrashpadDatabaseManager::Logger { + public: + CrashpadWin(); + + CrashpadWin(const CrashpadWin&) = delete; + CrashpadWin& operator=(const CrashpadWin&) = delete; + + bool Initialize(); + void LogAndCleanupCrashpadDatabase(); + + static CrashpadWin& GetInstance(); + + private: + bool GetCrashpadHandlerPath(base::FilePath* handler_path); + + // CrashpadDatabaseManager::Logger overrides + void Log(std::string message) const override; + void LogError(std::string message) const override; + + remoting::CrashpadDatabaseManager database_; +}; + +} // namespace remoting + +#endif // REMOTING_BASE_CRASH_CRASHPAD_WIN_H_
diff --git a/remoting/build/config/BUILD.gn b/remoting/build/config/BUILD.gn index 1d840d30..8760d21 100644 --- a/remoting/build/config/BUILD.gn +++ b/remoting/build/config/BUILD.gn
@@ -46,9 +46,6 @@ if (!is_mac && is_chrome_branded && is_official_build) { defines += [ "REMOTING_ENABLE_CRASH_REPORTING" ] } - if (enable_chromoting_crashpad) { - defines += [ "REMOTING_ENABLE_CRASHPAD" ] - } } if (is_win) { defines += host_predefines
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn index 6b65802..13fb0cc 100644 --- a/remoting/host/BUILD.gn +++ b/remoting/host/BUILD.gn
@@ -1206,13 +1206,13 @@ "//remoting/host/mac:host_service_main", ] } else { - deps += [ - "//remoting/host/crash:crash_uploader_main", - "//remoting/host/remote_open_url:main", - ] + deps += [ "//remoting/host/remote_open_url:main" ] } if (is_win) { - deps += [ "//remoting/host/security_key:main" ] + deps += [ + "//remoting/host/crash:crash_uploader_main", + "//remoting/host/security_key:main", + ] } }
diff --git a/remoting/host/crash/BUILD.gn b/remoting/host/crash/BUILD.gn index 7114685d..eb9dbd4d 100644 --- a/remoting/host/crash/BUILD.gn +++ b/remoting/host/crash/BUILD.gn
@@ -15,48 +15,6 @@ } } -source_set("crash_uploader") { - sources = [ - "crash_directory_watcher.cc", - "crash_directory_watcher.h", - "crash_file_uploader.cc", - "crash_file_uploader.h", - "minidump_handler.cc", - "minidump_handler.h", - ] - deps = [ - "//base", - "//remoting/base", - "//remoting/base/crash", - "//remoting/base/crash:breakpad_utils", - "//remoting/host:common_headers", - "//remoting/host/base", - "//services/network:network_service", - "//services/network/public/cpp", - ] -} - -source_set("crash_uploader_main_headers") { - sources = [ "crash_uploader_main.h" ] - public_deps = [ "//remoting/host:host_main_headers" ] -} - -source_set("crash_uploader_main") { - configs += [ "//remoting/build/config:host_implementation" ] - - sources = [ "crash_uploader_main.cc" ] - deps = [ - ":crash_uploader", - ":crash_uploader_main_headers", - "//base", - "//mojo/core/embedder:embedder", - "//remoting/base", - "//remoting/base/crash", - "//remoting/host:common_headers", - "//remoting/host/base", - ] -} - if (is_linux || is_win) { executable("remoting_crashpad_handler") { sources = [ "crashpad_handler.cc" ] @@ -91,6 +49,48 @@ } if (is_win) { + source_set("crash_uploader") { + sources = [ + "crash_directory_watcher.cc", + "crash_directory_watcher.h", + "crash_file_uploader.cc", + "crash_file_uploader.h", + "minidump_handler.cc", + "minidump_handler.h", + ] + deps = [ + "//base", + "//remoting/base", + "//remoting/base/crash", + "//remoting/base/crash:breakpad_utils", + "//remoting/host:common_headers", + "//remoting/host/base", + "//services/network:network_service", + "//services/network/public/cpp", + ] + } + + source_set("crash_uploader_main_headers") { + sources = [ "crash_uploader_main.h" ] + public_deps = [ "//remoting/host:host_main_headers" ] + } + + source_set("crash_uploader_main") { + configs += [ "//remoting/build/config:host_implementation" ] + + sources = [ "crash_uploader_main.cc" ] + deps = [ + ":crash_uploader", + ":crash_uploader_main_headers", + "//base", + "//mojo/core/embedder:embedder", + "//remoting/base", + "//remoting/base/crash", + "//remoting/host:common_headers", + "//remoting/host/base", + ] + } + executable("remoting_crash_uploader") { sources = [ "crash_uploader_entry_point.cc" ]
diff --git a/remoting/host/daemon_process_win.cc b/remoting/host/daemon_process_win.cc index a166b7d..bcee097c 100644 --- a/remoting/host/daemon_process_win.cc +++ b/remoting/host/daemon_process_win.cc
@@ -35,7 +35,7 @@ #include "mojo/public/cpp/system/message_pipe.h" #include "remoting/base/auto_thread.h" #include "remoting/base/auto_thread_task_runner.h" -#include "remoting/base/crash/crash_reporting.h" +#include "remoting/base/crash/crash_reporting_breakpad.h" #include "remoting/base/logging.h" #include "remoting/base/scoped_sc_handle_win.h" #include "remoting/host/base/host_exit_codes.h"
diff --git a/remoting/host/host_main.cc b/remoting/host/host_main.cc index a0012bb..9408862e 100644 --- a/remoting/host/host_main.cc +++ b/remoting/host/host_main.cc
@@ -24,7 +24,7 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "mojo/core/embedder/embedder.h" -#include "remoting/base/crash/crash_reporting.h" +#include "remoting/base/crash/crash_reporting_crashpad.h" #include "remoting/base/logging.h" #include "remoting/host/base/host_exit_codes.h" #include "remoting/host/base/switches.h" @@ -42,6 +42,8 @@ #include <commctrl.h> #include <shellapi.h> + +#include "remoting/base/crash/crash_reporting_breakpad.h" #endif // BUILDFLAG(IS_WIN) namespace remoting { @@ -230,12 +232,14 @@ // the crash reports uploaded. if (IsUsageStatsAllowed()) { #if BUILDFLAG(IS_LINUX) - InitializeCrashReporting(); + InitializeCrashpadReporting(); #elif BUILDFLAG(IS_WIN) // TODO: joedow - Enable crash reporting for the RDP process. - if (process_type == kProcessTypeDesktop || - process_type == kProcessTypeDaemon) { - InitializeCrashReporting(); + if (process_type == kProcessTypeDaemon) { + InitializeBreakpadReporting(); + } else if (process_type == kProcessTypeDesktop) { + // TODO(garykac): Switch to use InitializeCrashpadReporting(); + InitializeBreakpadReporting(); } else if (command_line->HasSwitch(kCrashServerPipeHandle)) { InitializeOopCrashClient( command_line->GetSwitchValueASCII(kCrashServerPipeHandle));
diff --git a/remoting/host/it2me/it2me_native_messaging_host_main.cc b/remoting/host/it2me/it2me_native_messaging_host_main.cc index 1a9ddba..209f773 100644 --- a/remoting/host/it2me/it2me_native_messaging_host_main.cc +++ b/remoting/host/it2me/it2me_native_messaging_host_main.cc
@@ -17,7 +17,6 @@ #include "mojo/core/embedder/embedder.h" #include "net/base/network_change_notifier.h" #include "remoting/base/auto_thread_task_runner.h" -#include "remoting/base/crash/crash_reporting.h" #include "remoting/base/host_settings.h" #include "remoting/base/logging.h" #include "remoting/host/base/host_exit_codes.h" @@ -44,10 +43,15 @@ #include "remoting/host/mac/permission_utils.h" #endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_LINUX) +#include "remoting/base/crash/crash_reporting_crashpad.h" +#endif // BUILDFLAG(IS_LINUX) + #if BUILDFLAG(IS_WIN) #include <windows.h> #include <commctrl.h> +#include "remoting/base/crash/crash_reporting_breakpad.h" #endif // BUILDFLAG(IS_WIN) namespace remoting { @@ -100,7 +104,11 @@ // needs to be initialized first, so that the preference for crash-reporting // can be looked up in the config file. if (IsUsageStatsAllowed()) { - InitializeCrashReporting(); +#if BUILDFLAG(IS_LINUX) + InitializeCrashpadReporting(); +#elif BUILDFLAG(IS_WIN) + InitializeBreakpadReporting(); +#endif // BUILDFLAG(IS_LINUX) } #endif // defined(REMOTING_ENABLE_CRASH_REPORTING)
diff --git a/remoting/host/remote_open_url/remote_open_url_main.cc b/remoting/host/remote_open_url/remote_open_url_main.cc index 29ee547d..89a8838f 100644 --- a/remoting/host/remote_open_url/remote_open_url_main.cc +++ b/remoting/host/remote_open_url/remote_open_url_main.cc
@@ -18,7 +18,6 @@ #include "base/task/single_thread_task_runner.h" #include "mojo/core/embedder/embedder.h" #include "mojo/core/embedder/scoped_ipc_support.h" -#include "remoting/base/crash/crash_reporting.h" #include "remoting/base/host_settings.h" #include "remoting/base/logging.h" #include "remoting/host/base/host_exit_codes.h" @@ -28,6 +27,14 @@ #include "remoting/host/usage_stats_consent.h" #include "ui/base/l10n/l10n_util.h" +#if BUILDFLAG(IS_LINUX) +#include "remoting/base/crash/crash_reporting_crashpad.h" +#endif // BUILDFLAG(IS_LINUX) + +#if BUILDFLAG(IS_WIN) +#include "remoting/base/crash/crash_reporting_breakpad.h" +#endif // BUILDFLAG(IS_WIN) + namespace remoting { int RemoteOpenUrlMain(int argc, char** argv) { @@ -44,7 +51,11 @@ #if defined(REMOTING_ENABLE_CRASH_REPORTING) if (IsUsageStatsAllowed()) { - InitializeCrashReporting(); +#if BUILDFLAG(IS_LINUX) + InitializeCrashpadReporting(); +#elif BUILDFLAG(IS_WIN) + InitializeBreakpadReporting(); +#endif // BUILDFLAG(IS_LINUX) } #endif // defined(REMOTING_ENABLE_CRASH_REPORTING)
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc index 1fe53f8..d39e13b7 100644 --- a/remoting/host/remoting_me2me_host.cc +++ b/remoting/host/remoting_me2me_host.cc
@@ -56,7 +56,6 @@ #include "remoting/base/cloud_session_authz_service_client_factory.h" #include "remoting/base/corp_session_authz_service_client_factory.h" #include "remoting/base/cpu_utils.h" -#include "remoting/base/crash/crash_reporting.h" #include "remoting/base/errors.h" #include "remoting/base/host_settings.h" #include "remoting/base/instance_identity_token_getter.h" @@ -166,6 +165,7 @@ #endif // BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_LINUX) +#include "remoting/base/crash/crash_reporting_crashpad.h" #include "remoting/host/host_wtmpdb_logger.h" #endif // BUILDFLAG(IS_LINUX) @@ -2154,10 +2154,12 @@ return kInitializationFailed; } -#if defined(REMOTING_ENABLE_CRASH_REPORTING) +#if BUILDFLAG(IS_LINUX) // Log and cleanup the crash database. We do this after a short delay so that // the crash database has a chance to be updated properly if we just got // relaunched after a crash. + // TODO(garykac): When Crashpad is enabled for the network process on Windows + // we will need to enable this code on Windows as well. if (IsUsageStatsAllowed()) { scoped_refptr<base::SequencedTaskRunner> task_runner_crashdb = base::ThreadPool::CreateSequencedTaskRunner(
diff --git a/remoting/host/security_key/remote_security_key_main.cc b/remoting/host/security_key/remote_security_key_main.cc index f782077..1b39ccc 100644 --- a/remoting/host/security_key/remote_security_key_main.cc +++ b/remoting/host/security_key/remote_security_key_main.cc
@@ -17,7 +17,6 @@ #include "build/build_config.h" #include "mojo/core/embedder/embedder.h" #include "mojo/core/embedder/scoped_ipc_support.h" -#include "remoting/base/crash/crash_reporting.h" #include "remoting/base/logging.h" #include "remoting/host/base/host_exit_codes.h" #include "remoting/host/chromoting_host_services_client.h" @@ -25,9 +24,14 @@ #include "remoting/host/security_key/security_key_message_handler.h" #include "remoting/host/usage_stats_consent.h" +#if BUILDFLAG(IS_LINUX) +#include "remoting/base/crash/crash_reporting_crashpad.h" +#endif // BUILDFLAG(IS_LINUX) + #if BUILDFLAG(IS_WIN) #include <windows.h> +#include "remoting/base/crash/crash_reporting_breakpad.h" #include "remoting/host/win/acl_util.h" #endif // BUILDFLAG(IS_WIN) @@ -92,7 +96,11 @@ #if defined(REMOTING_ENABLE_CRASH_REPORTING) if (IsUsageStatsAllowed()) { - InitializeCrashReporting(); +#if BUILDFLAG(IS_LINUX) + InitializeCrashpadReporting(); +#elif BUILDFLAG(IS_WIN) + InitializeBreakpadReporting(); +#endif // BUILDFLAG(IS_LINUX) } #endif // defined(REMOTING_ENABLE_CRASH_REPORTING)
diff --git a/remoting/host/setup/me2me_native_messaging_host_main.cc b/remoting/host/setup/me2me_native_messaging_host_main.cc index b24d266..4a7e34c 100644 --- a/remoting/host/setup/me2me_native_messaging_host_main.cc +++ b/remoting/host/setup/me2me_native_messaging_host_main.cc
@@ -23,7 +23,6 @@ #include "build/build_config.h" #include "mojo/core/embedder/embedder.h" #include "remoting/base/auto_thread_task_runner.h" -#include "remoting/base/crash/crash_reporting.h" #include "remoting/base/gaia_oauth_client.h" #include "remoting/base/logging.h" #include "remoting/base/url_request_context_getter.h" @@ -42,11 +41,16 @@ #include "base/apple/scoped_nsautorelease_pool.h" #endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_LINUX) +#include "remoting/base/crash/crash_reporting_crashpad.h" +#endif // BUILDFLAG(IS_LINUX) + #if BUILDFLAG(IS_WIN) #include <windows.h> #include "base/process/process_info.h" #include "base/win/registry.h" +#include "remoting/base/crash/crash_reporting_breakpad.h" #include "remoting/host/pairing_registry_delegate_win.h" #endif // BUILDFLAG(IS_WIN) @@ -95,7 +99,11 @@ // needs to be initialized first, so that the preference for crash-reporting // can be looked up in the config file. if (IsUsageStatsAllowed()) { - InitializeCrashReporting(); +#if BUILDFLAG(IS_LINUX) + InitializeCrashpadReporting(); +#elif BUILDFLAG(IS_WIN) + InitializeBreakpadReporting(); +#endif // BUILDFLAG(IS_LINUX) } #endif // defined(REMOTING_ENABLE_CRASH_REPORTING)
diff --git a/remoting/host/setup/start_host_main.cc b/remoting/host/setup/start_host_main.cc index e70f00f..028002ed 100644 --- a/remoting/host/setup/start_host_main.cc +++ b/remoting/host/setup/start_host_main.cc
@@ -29,7 +29,6 @@ #include "net/ssl/client_cert_store.h" #include "net/url_request/url_request_context_getter.h" #include "remoting/base/certificate_helpers.h" -#include "remoting/base/crash/crash_reporting.h" #include "remoting/base/logging.h" #include "remoting/base/url_request_context_getter.h" #include "remoting/host/setup/cloud_host_starter.h" @@ -46,6 +45,7 @@ #endif // BUILDFLAG(IS_POSIX) #if BUILDFLAG(IS_LINUX) +#include "remoting/base/crash/crash_reporting_crashpad.h" #include "remoting/host/setup/daemon_controller_delegate_linux.h" #include "remoting/host/setup/start_host_as_root.h" #endif // BUILDFLAG(IS_LINUX) @@ -54,6 +54,7 @@ #include <windows.h> #include "base/process/process_info.h" +#include "remoting/base/crash/crash_reporting_breakpad.h" #endif // BUILDFLAG(IS_WIN) namespace remoting { @@ -444,7 +445,11 @@ // We don't have a config file yet so we can't use IsUsageStatsAllowed(), // instead we can just check the command line parameter. if (params.enable_crash_reporting) { - InitializeCrashReporting(); +#if BUILDFLAG(IS_LINUX) + InitializeCrashpadReporting(); +#elif BUILDFLAG(IS_WIN) + InitializeBreakpadReporting(); +#endif // BUILDFLAG(IS_LINUX) } #endif // defined(REMOTING_ENABLE_CRASH_REPORTING)
diff --git a/remoting/host/webauthn/remote_webauthn_main.cc b/remoting/host/webauthn/remote_webauthn_main.cc index 8c5d920e..bfd2319b 100644 --- a/remoting/host/webauthn/remote_webauthn_main.cc +++ b/remoting/host/webauthn/remote_webauthn_main.cc
@@ -18,7 +18,6 @@ #include "mojo/core/embedder/embedder.h" #include "mojo/core/embedder/scoped_ipc_support.h" #include "remoting/base/auto_thread_task_runner.h" -#include "remoting/base/crash/crash_reporting.h" #include "remoting/base/logging.h" #include "remoting/host/base/host_exit_codes.h" #include "remoting/host/chromoting_host_services_client.h" @@ -28,8 +27,14 @@ #include "remoting/host/webauthn/remote_webauthn_caller_security_utils.h" #include "remoting/host/webauthn/remote_webauthn_native_messaging_host.h" +#if BUILDFLAG(IS_LINUX) +#include "remoting/base/crash/crash_reporting_crashpad.h" +#endif // BUILDFLAG(IS_LINUX) + #if BUILDFLAG(IS_WIN) #include <windows.h> + +#include "remoting/base/crash/crash_reporting_breakpad.h" #endif // BUILDFLAG(IS_WIN) namespace remoting { @@ -45,7 +50,11 @@ #if defined(REMOTING_ENABLE_CRASH_REPORTING) if (IsUsageStatsAllowed()) { - InitializeCrashReporting(); +#if BUILDFLAG(IS_LINUX) + InitializeCrashpadReporting(); +#elif BUILDFLAG(IS_WIN) + InitializeBreakpadReporting(); +#endif // BUILDFLAG(IS_LINUX) } #endif // defined(REMOTING_ENABLE_CRASH_REPORTING)
diff --git a/sandbox/policy/win/sandbox_warmup.cc b/sandbox/policy/win/sandbox_warmup.cc index 97d4e5a..4cfcf6e6 100644 --- a/sandbox/policy/win/sandbox_warmup.cc +++ b/sandbox/policy/win/sandbox_warmup.cc
@@ -6,15 +6,10 @@ #include <windows.h> -#include "base/check_op.h" +#include "base/check.h" #include "base/no_destructor.h" #include "sandbox/policy/win/hook_util/hook_util.h" - -// Prototype for ProcessPrng. -// See: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng -extern "C" { -BOOL WINAPI ProcessPrng(PBYTE pbData, SIZE_T cbData); -} +#include "sandbox/win/src/win_utils.h" namespace sandbox::policy { @@ -28,27 +23,10 @@ return g_user_default_lcid; } -// Import bcryptprimitives!ProcessPrng rather than cryptbase!RtlGenRandom to -// avoid opening a handle to \\Device\KsecDD in the renderer. -decltype(&ProcessPrng) GetProcessPrng() { - HMODULE hmod = LoadLibraryW(L"bcryptprimitives.dll"); - CHECK(hmod); - decltype(&ProcessPrng) process_prng_fn = - reinterpret_cast<decltype(&ProcessPrng)>( - GetProcAddress(hmod, "ProcessPrng")); - CHECK(process_prng_fn); - return process_prng_fn; -} - } // namespace void WarmupRandomnessInfrastructure() { - BYTE data[1]; - // TODO(crbug.com/40088338) Call a warmup function exposed by boringssl. - static decltype(&ProcessPrng) process_prng_fn = GetProcessPrng(); - BOOL success = process_prng_fn(data, sizeof(data)); - // ProcessPrng is documented to always return TRUE. - CHECK(success); + sandbox::WarmupRandomnessInfrastructure(); } bool HookDwriteGetUserDefaultLCID() {
diff --git a/sandbox/win/src/process_mitigations_unittest.cc b/sandbox/win/src/process_mitigations_unittest.cc index c3a6d378..141fdb9 100644 --- a/sandbox/win/src/process_mitigations_unittest.cc +++ b/sandbox/win/src/process_mitigations_unittest.cc
@@ -517,6 +517,9 @@ ->RevertedToSelf()) { // Need to warm up gdi32.dll for the test. CHECK(::LoadLibrary(L"gdi32.dll")); + + // Need to warm up random for this test. + sandbox::WarmupRandomnessInfrastructure(); return 0; }
diff --git a/sandbox/win/src/win_utils.cc b/sandbox/win/src/win_utils.cc index 6ebaf2c..7c5923c 100644 --- a/sandbox/win/src/win_utils.cc +++ b/sandbox/win/src/win_utils.cc
@@ -22,6 +22,7 @@ #include <string> #include <vector> +#include "base/check.h" #include "base/containers/span.h" #include "base/numerics/safe_math.h" #include "base/strings/string_util.h" @@ -31,6 +32,12 @@ #include "sandbox/win/src/nt_internals.h" #include "sandbox/win/src/sandbox_nt_util.h" +// Prototype for ProcessPrng. +// See: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng +extern "C" { +BOOL WINAPI ProcessPrng(PBYTE pbData, SIZE_T cbData); +} + namespace { NTSTATUS WrapQueryObject(HANDLE handle, @@ -71,6 +78,18 @@ return data; } +// Import bcryptprimitives!ProcessPrng rather than cryptbase!RtlGenRandom to +// avoid opening a handle to \\Device\KsecDD in the renderer. +decltype(&ProcessPrng) GetProcessPrng() { + HMODULE hmod = LoadLibraryW(L"bcryptprimitives.dll"); + CHECK(hmod); + decltype(&ProcessPrng) process_prng_fn = + reinterpret_cast<decltype(&ProcessPrng)>( + GetProcAddress(hmod, "ProcessPrng")); + CHECK(process_prng_fn); + return process_prng_fn; +} + } // namespace namespace sandbox { @@ -183,4 +202,13 @@ return str.find_first_of(nul) != std::wstring::npos; } +void WarmupRandomnessInfrastructure() { + BYTE data[1]; + // TODO(crbug.com/40088338) Call a warmup function exposed by boringssl. + static decltype(&ProcessPrng) process_prng_fn = GetProcessPrng(); + BOOL success = process_prng_fn(data, sizeof(data)); + // ProcessPrng is documented to always return TRUE. + CHECK(success); +} + } // namespace sandbox
diff --git a/sandbox/win/src/win_utils.h b/sandbox/win/src/win_utils.h index 1efecc2..525992b9 100644 --- a/sandbox/win/src/win_utils.h +++ b/sandbox/win/src/win_utils.h
@@ -80,6 +80,10 @@ // Returns true if the string contains a NUL ('\0') character. bool ContainsNulCharacter(std::wstring_view str); +// Call in a sandboxed process before target lockdown where modules should be +// pre-loaded to support the infrastructure underlying crypto::RandBytes. +void WarmupRandomnessInfrastructure(); + } // namespace sandbox #endif // SANDBOX_WIN_SRC_WIN_UTILS_H_
diff --git a/services/image_annotation/BUILD.gn b/services/image_annotation/BUILD.gn index a7298a7..3331cc89 100644 --- a/services/image_annotation/BUILD.gn +++ b/services/image_annotation/BUILD.gn
@@ -20,7 +20,6 @@ "//components/manta", "//mojo/public/cpp/bindings", "//net", - "//services/data_decoder/public/mojom", "//services/image_annotation/public/mojom", "//services/network/public/cpp", "//ui/accessibility:ax_base", @@ -37,7 +36,6 @@ public_deps = [ ":lib", "//base", - "//services/data_decoder/public/mojom", "//services/image_annotation/public/mojom", "//services/network/public/cpp", "//url", @@ -56,9 +54,6 @@ "//components/manta:manta", "//mojo/public/cpp/bindings", "//net", - "//services/data_decoder/public/cpp", - "//services/data_decoder/public/cpp:test_support", - "//services/data_decoder/public/mojom", "//services/image_annotation/public/cpp", "//services/image_annotation/public/mojom", "//services/network:test_support",
diff --git a/services/image_annotation/DEPS b/services/image_annotation/DEPS index efd0fde..78396ac 100644 --- a/services/image_annotation/DEPS +++ b/services/image_annotation/DEPS
@@ -2,7 +2,6 @@ "+components/google", "+components/manta", "+net", - "+services/data_decoder", "+services/network", "+third_party/skia", "+ui/accessibility",
diff --git a/services/image_annotation/annotator.cc b/services/image_annotation/annotator.cc index 456de81..083438c 100644 --- a/services/image_annotation/annotator.cc +++ b/services/image_annotation/annotator.cc
@@ -970,26 +970,20 @@ ReportServerResponseSizeBytes(json_response->size()); - // Send JSON string to a dedicated service for safe parsing. - GetJsonParser()->Parse( - *json_response, base::JSON_PARSE_RFC, - base::BindOnce(&Annotator::OnResponseJsonParsed, - weak_factory_.GetWeakPtr(), request_keys)); -} + base::JSONReader::Result result = + base::JSONReader::ReadAndReturnValueWithError(*json_response, + base::JSON_PARSE_RFC); -void Annotator::OnResponseJsonParsed(const std::set<RequestKey>& request_keys, - const std::optional<base::Value> json_data, - const std::optional<std::string>& error) { - const bool success = json_data.has_value() && !error.has_value(); + const bool success = result.has_value(); ReportJsonParseSuccess(success); // Extract annotation results for each request key with valid results. if (success) { ProcessResults(request_keys, - UnpackJsonResponse(*json_data, min_ocr_confidence_)); + UnpackJsonResponse(*result, min_ocr_confidence_)); } else { DVLOG(1) << "Parsing server response JSON failed with error: " - << error.value_or("No reason reported."); + << result.error().message; ProcessResults(request_keys, {}); } } @@ -1047,15 +1041,6 @@ } } -data_decoder::mojom::JsonParser* Annotator::GetJsonParser() { - if (!json_parser_) { - client_->BindJsonParser(json_parser_.BindNewPipeAndPassReceiver()); - json_parser_.reset_on_disconnect(); - } - - return json_parser_.get(); -} - void Annotator::RemoveRequestInfo( const RequestKey& request_key, const std::list<ClientRequestInfo>::iterator request_info_it, @@ -1177,22 +1162,22 @@ return; } - GetJsonParser()->Parse( - *json_response, base::JSON_PARSE_RFC, - base::BindOnce(&Annotator::OnServerLangsResponseJsonParsed, - weak_factory_.GetWeakPtr())); -} + base::JSONReader::Result result = + base::JSONReader::ReadAndReturnValueWithError(*json_response, + base::JSON_PARSE_RFC); -void Annotator::OnServerLangsResponseJsonParsed( - std::optional<base::Value> json_data, - const std::optional<std::string>& error) { - if (!json_data.has_value() || error.has_value()) { + if (!result.has_value()) { DVLOG(1) << "Parsing server langs response JSON failed with error: " - << error.value_or("No reason reported."); + << result.error().message; return; } - const base::Value::List* const langs = json_data->GetDict().FindList("langs"); + if (!result->is_dict()) { + DVLOG(1) << "Server langs response JSON is not a dictionary."; + return; + } + + const base::Value::List* const langs = result->GetDict().FindList("langs"); if (!langs) { DVLOG(1) << "No langs in response JSON"; return;
diff --git a/services/image_annotation/annotator.h b/services/image_annotation/annotator.h index 92620da..07461a8a 100644 --- a/services/image_annotation/annotator.h +++ b/services/image_annotation/annotator.h
@@ -24,7 +24,6 @@ #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/remote.h" -#include "services/data_decoder/public/mojom/json_parser.mojom.h" #include "services/image_annotation/public/mojom/image_annotation.mojom.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" @@ -49,9 +48,6 @@ public: virtual ~Client() {} - virtual void BindJsonParser( - mojo::PendingReceiver<data_decoder::mojom::JsonParser> receiver) = 0; - virtual std::vector<std::string> GetAcceptLanguages() = 0; virtual std::vector<std::string> GetTopLanguages() = 0; virtual void RecordLanguageMetrics( @@ -198,10 +194,6 @@ const GURL& server_url, const std::string& api_key); - // Create or reuse a connection to the data decoder service for safe JSON - // parsing. - data_decoder::mojom::JsonParser* GetJsonParser(); - // Removes the given request, reassigning local processing if its associated // image processor had some ongoing. void RemoveRequestInfo(const RequestKey& request_key, @@ -256,10 +248,6 @@ void OnServerLangsResponseReceived( const std::unique_ptr<std::string> json_response); - // Parse the JSON from the reply with server languages. - void OnServerLangsResponseJsonParsed(std::optional<base::Value> json_data, - const std::optional<std::string>& error); - const std::unique_ptr<manta::AnchovyProvider> anchovy_provider_; const std::unique_ptr<Client> client_; @@ -306,9 +294,6 @@ mojo::ReceiverSet<mojom::Annotator> receivers_; - // Should not be used directly; GetJsonParser() should be called instead. - mojo::Remote<data_decoder::mojom::JsonParser> json_parser_; - // A timer used to throttle server request frequency. std::unique_ptr<base::RepeatingTimer> server_request_timer_;
diff --git a/services/image_annotation/annotator_unittest.cc b/services/image_annotation/annotator_unittest.cc index 7e9880a1..ef2c0c5 100644 --- a/services/image_annotation/annotator_unittest.cc +++ b/services/image_annotation/annotator_unittest.cc
@@ -29,9 +29,6 @@ #include "mojo/public/cpp/bindings/receiver_set.h" #include "net/base/net_errors.h" #include "net/http/http_status_code.h" -#include "services/data_decoder/public/cpp/data_decoder.h" -#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" -#include "services/data_decoder/public/mojom/json_parser.mojom.h" #include "services/image_annotation/annotator.h" #include "services/image_annotation/image_annotation_metrics.h" #include "services/image_annotation/public/mojom/image_annotation.mojom.h" @@ -404,11 +401,6 @@ } private: - // Annotator::Client implementation: - void BindJsonParser(mojo::PendingReceiver<data_decoder::mojom::JsonParser> - receiver) override { - decoder_.GetService()->BindJsonParser(std::move(receiver)); - } std::vector<std::string> GetAcceptLanguages() override { return accept_langs_; } @@ -416,7 +408,6 @@ void RecordLanguageMetrics(const std::string& page_language, const std::string& requested_language) override {} - data_decoder::DataDecoder decoder_; std::vector<std::string> accept_langs_ = {"en", "it", "fr"}; std::vector<std::string> top_langs_; }; @@ -429,7 +420,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -536,7 +526,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -644,7 +633,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -760,7 +748,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -817,7 +804,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -901,7 +887,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -996,7 +981,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -1087,7 +1071,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -1146,7 +1129,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -1222,7 +1204,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -1303,7 +1284,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -1373,7 +1353,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -1449,7 +1428,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -1537,7 +1515,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -1682,7 +1659,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -1791,7 +1767,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -1996,7 +1971,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -2195,7 +2169,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; base::HistogramTester histogram_tester; Annotator annotator( @@ -2295,7 +2268,6 @@ TEST(AnnotatorTest, ApiKey) { base::test::TaskEnvironment test_task_env( base::test::TaskEnvironment::TimeSource::MOCK_TIME); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; // A call to a secure Google-owner server URL should include the specified API // key. @@ -2470,7 +2442,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; Annotator annotator( GURL(kTestServerUrl), GURL(kLangsServerUrl), std::string() /* api_key */, @@ -2505,7 +2476,6 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME); TestServerURLLoaderFactory test_url_factory( "https://ia-pa.googleapis.com/v1/"); - data_decoder::test::InProcessDataDecoder in_process_data_decoder; Annotator annotator( GURL(kTestServerUrl), GURL(kLangsServerUrl), std::string() /* api_key */,
diff --git a/services/image_annotation/image_annotation_service.h b/services/image_annotation/image_annotation_service.h index 4388429d..cfd9a208 100644 --- a/services/image_annotation/image_annotation_service.h +++ b/services/image_annotation/image_annotation_service.h
@@ -13,7 +13,6 @@ #include "base/metrics/field_trial_params.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" -#include "services/data_decoder/public/mojom/json_parser.mojom.h" #include "services/image_annotation/annotator.h" #include "services/image_annotation/public/mojom/image_annotation.mojom.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
diff --git a/services/network/cookie_settings_unittest.cc b/services/network/cookie_settings_unittest.cc index 5634a0c..a50b811 100644 --- a/services/network/cookie_settings_unittest.cc +++ b/services/network/cookie_settings_unittest.cc
@@ -1740,9 +1740,8 @@ EXPECT_FALSE(settings.IsCookieAccessible( *cookie, GURL(kRwsMemberURL), net::SiteForCookies(), top_level_origin, net::FirstPartySetMetadata( - net::FirstPartySetEntry(primary, net::SiteType::kAssociated, 1u), - net::FirstPartySetEntry(primary, net::SiteType::kPrimary, - std::nullopt)), + net::FirstPartySetEntry(primary, net::SiteType::kAssociated), + net::FirstPartySetEntry(primary, net::SiteType::kPrimary)), GetCookieSettingOverrides(), &status)); if (IsTPCDEnabled()) { EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( @@ -2250,9 +2249,8 @@ EXPECT_FALSE(settings.AnnotateAndMoveUserBlockedCookies( GURL(kRwsMemberURL), net::SiteForCookies(), &origin, net::FirstPartySetMetadata( - net::FirstPartySetEntry(primary, net::SiteType::kAssociated, 1u), - net::FirstPartySetEntry(primary, net::SiteType::kPrimary, - std::nullopt)), + net::FirstPartySetEntry(primary, net::SiteType::kAssociated), + net::FirstPartySetEntry(primary, net::SiteType::kPrimary)), GetCookieSettingOverrides(), maybe_included_cookies, excluded_cookies)); EXPECT_EQ(0u, maybe_included_cookies.size()); @@ -2295,9 +2293,8 @@ url::Origin top_frame_origin = url::Origin::Create(GURL(kRwsOwnerURL)); net::SchemefulSite primary((GURL(kRwsOwnerURL))); - net::FirstPartySetEntry frame_entry(primary, net::SiteType::kAssociated, 1u); - net::FirstPartySetEntry top_frame_entry(primary, net::SiteType::kPrimary, - std::nullopt); + net::FirstPartySetEntry frame_entry(primary, net::SiteType::kAssociated); + net::FirstPartySetEntry top_frame_entry(primary, net::SiteType::kPrimary); net::CookieAccessResultList maybe_included_cookies = {{*cookie, {}}}; net::CookieAccessResultList excluded_cookies = {};
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc b/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc index 01ad4e0a..868487a3 100644 --- a/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc +++ b/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc
@@ -110,20 +110,15 @@ /*entries=*/ { {kSet1AssociatedSite1, - net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated, - 0)}, + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated)}, {kSet1AssociatedSite2, - net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated, - 1)}, + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated)}, {kSet1Primary, - net::FirstPartySetEntry(kSet1Primary, net::SiteType::kPrimary, - std::nullopt)}, + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kPrimary)}, {kSet2AssociatedSite1, - net::FirstPartySetEntry(kSet2Primary, net::SiteType::kAssociated, - 0)}, + net::FirstPartySetEntry(kSet2Primary, net::SiteType::kAssociated)}, {kSet2Primary, - net::FirstPartySetEntry(kSet2Primary, net::SiteType::kPrimary, - std::nullopt)}, + net::FirstPartySetEntry(kSet2Primary, net::SiteType::kPrimary)}, }, /*aliases=*/{})); } @@ -136,15 +131,14 @@ }; TEST_F(NoopFirstPartySetsAccessDelegateTest, ComputeMetadata) { - EXPECT_EQ(delegate().ComputeMetadata(kSet1AssociatedSite1, &kSet1Primary, - base::NullCallback()), - std::make_optional(std::make_pair( - net::FirstPartySetMetadata( - net::FirstPartySetEntry(kSet1Primary, - net::SiteType::kAssociated, 0), - net::FirstPartySetEntry( - kSet1Primary, net::SiteType::kPrimary, std::nullopt)), - net::FirstPartySetsCacheFilter::MatchInfo()))); + EXPECT_EQ( + delegate().ComputeMetadata(kSet1AssociatedSite1, &kSet1Primary, + base::NullCallback()), + std::make_optional(std::make_pair( + net::FirstPartySetMetadata( + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated), + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kPrimary)), + net::FirstPartySetsCacheFilter::MatchInfo()))); } TEST_F(NoopFirstPartySetsAccessDelegateTest, FindEntries) { @@ -153,11 +147,9 @@ base::NullCallback()), FirstPartySetsAccessDelegate::EntriesResult({ {kSet1AssociatedSite1, - net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated, - 0)}, + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated)}, {kSet2AssociatedSite1, - net::FirstPartySetEntry(kSet2Primary, net::SiteType::kAssociated, - 0)}, + net::FirstPartySetEntry(kSet2Primary, net::SiteType::kAssociated)}, })); } @@ -175,20 +167,15 @@ /*entries=*/ { {kSet1AssociatedSite1, - net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated, - 0)}, + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated)}, {kSet1AssociatedSite2, - net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated, - 1)}, + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated)}, {kSet1Primary, - net::FirstPartySetEntry(kSet1Primary, net::SiteType::kPrimary, - std::nullopt)}, + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kPrimary)}, {kSet2AssociatedSite1, - net::FirstPartySetEntry(kSet2Primary, net::SiteType::kAssociated, - 0)}, + net::FirstPartySetEntry(kSet2Primary, net::SiteType::kAssociated)}, {kSet2Primary, - net::FirstPartySetEntry(kSet2Primary, net::SiteType::kPrimary, - std::nullopt)}, + net::FirstPartySetEntry(kSet2Primary, net::SiteType::kPrimary)}, }, /*aliases=*/{})); } @@ -273,7 +260,7 @@ delegate_remote()->NotifyReady(mojom::FirstPartySetsReadyEvent::New()); - net::FirstPartySetEntry entry(kSet1Primary, net::SiteType::kAssociated, 0); + net::FirstPartySetEntry entry(kSet1Primary, net::SiteType::kAssociated); EXPECT_EQ(future.Get(), std::make_tuple(net::FirstPartySetMetadata(entry, entry), net::FirstPartySetsCacheFilter::MatchInfo())); @@ -286,15 +273,14 @@ delegate_remote()->NotifyReady(mojom::FirstPartySetsReadyEvent::New()); - EXPECT_THAT(future.Get(), - FirstPartySetsAccessDelegate::EntriesResult({ - {kSet1AssociatedSite1, - net::FirstPartySetEntry(kSet1Primary, - net::SiteType::kAssociated, 0)}, - {kSet2AssociatedSite1, - net::FirstPartySetEntry(kSet2Primary, - net::SiteType::kAssociated, 0)}, - })); + EXPECT_THAT( + future.Get(), + FirstPartySetsAccessDelegate::EntriesResult({ + {kSet1AssociatedSite1, + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated)}, + {kSet2AssociatedSite1, + net::FirstPartySetEntry(kSet2Primary, net::SiteType::kAssociated)}, + })); } TEST_F(AsyncFirstPartySetsAccessDelegateTest, OverrideSets_ComputeMetadata) { @@ -303,22 +289,21 @@ { {kSet1AssociatedSite1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - kSet3Primary, net::SiteType::kAssociated, 0))}, + kSet3Primary, net::SiteType::kAssociated))}, {kSet3Primary, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - kSet3Primary, net::SiteType::kPrimary, std::nullopt))}, + kSet3Primary, net::SiteType::kPrimary))}, }) .value(), /*cache_filter=*/std::nullopt)); EXPECT_EQ(ComputeMetadataAndWait(kSet3Primary, &kSet1AssociatedSite1), - std::make_tuple( - net::FirstPartySetMetadata( - net::FirstPartySetEntry( - kSet3Primary, net::SiteType::kPrimary, std::nullopt), - net::FirstPartySetEntry(kSet3Primary, - net::SiteType::kAssociated, 0)), - net::FirstPartySetsCacheFilter::MatchInfo())); + std::make_tuple(net::FirstPartySetMetadata( + net::FirstPartySetEntry( + kSet3Primary, net::SiteType::kPrimary), + net::FirstPartySetEntry( + kSet3Primary, net::SiteType::kAssociated)), + net::FirstPartySetsCacheFilter::MatchInfo())); } TEST_F(AsyncFirstPartySetsAccessDelegateTest, OverrideSets_FindEntries) { @@ -327,7 +312,7 @@ { {kSet3Primary, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - kSet3Primary, net::SiteType::kPrimary, std::nullopt))}, + kSet3Primary, net::SiteType::kPrimary))}, }) .value(), /*cache_filter=*/std::nullopt)); @@ -345,10 +330,10 @@ { {kSet3AssociatedSite1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - kSet3Primary, net::SiteType::kAssociated, 0))}, + kSet3Primary, net::SiteType::kAssociated))}, {kSet3Primary, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - kSet3Primary, net::SiteType::kPrimary, std::nullopt))}, + kSet3Primary, net::SiteType::kPrimary))}, }) .value(), net::FirstPartySetsCacheFilter({{kSet1Primary, kClearAtRunId}}, @@ -361,31 +346,27 @@ match_info.clear_at_run_id = kClearAtRunId; match_info.browser_run_id = kBrowserRunId; - EXPECT_EQ( - ComputeMetadataAndWait(kSet1Primary, &kSet1AssociatedSite1), - std::make_tuple( - net::FirstPartySetMetadata( - net::FirstPartySetEntry(kSet1Primary, net::SiteType::kPrimary, - /*site_index=*/std::nullopt), - net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated, - 0)), - match_info)); + EXPECT_EQ(ComputeMetadataAndWait(kSet1Primary, &kSet1AssociatedSite1), + std::make_tuple(net::FirstPartySetMetadata( + net::FirstPartySetEntry( + kSet1Primary, net::SiteType::kPrimary), + net::FirstPartySetEntry( + kSet1Primary, net::SiteType::kAssociated)), + match_info)); } TEST_F(SyncFirstPartySetsAccessDelegateTest, FindEntries) { - EXPECT_THAT(FindEntriesAndWait({kSet1AssociatedSite1, kSet2AssociatedSite1, - kSet3AssociatedSite1}), - FirstPartySetsAccessDelegate::EntriesResult({ - {kSet1AssociatedSite1, - net::FirstPartySetEntry(kSet1Primary, - net::SiteType::kAssociated, 0)}, - {kSet2AssociatedSite1, - net::FirstPartySetEntry(kSet2Primary, - net::SiteType::kAssociated, 0)}, - {kSet3AssociatedSite1, - net::FirstPartySetEntry(kSet3Primary, - net::SiteType::kAssociated, 0)}, - })); + EXPECT_THAT( + FindEntriesAndWait( + {kSet1AssociatedSite1, kSet2AssociatedSite1, kSet3AssociatedSite1}), + FirstPartySetsAccessDelegate::EntriesResult({ + {kSet1AssociatedSite1, + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated)}, + {kSet2AssociatedSite1, + net::FirstPartySetEntry(kSet2Primary, net::SiteType::kAssociated)}, + {kSet3AssociatedSite1, + net::FirstPartySetEntry(kSet3Primary, net::SiteType::kAssociated)}, + })); } // Verifies the behaviors of the delegate when First-Party Sets are initially @@ -461,7 +442,7 @@ delegate_remote()->NotifyReady(mojom::FirstPartySetsReadyEvent::New()); - net::FirstPartySetEntry entry(kSet1Primary, net::SiteType::kAssociated, 0); + net::FirstPartySetEntry entry(kSet1Primary, net::SiteType::kAssociated); EXPECT_EQ(future.Get(), std::make_tuple(net::FirstPartySetMetadata(entry, entry), net::FirstPartySetsCacheFilter::MatchInfo())); @@ -488,7 +469,7 @@ FirstPartySetsAccessDelegate::EntriesResult( {{kSet1AssociatedSite1, net::FirstPartySetEntry(kSet1Primary, - net::SiteType::kAssociated, 0)}})); + net::SiteType::kAssociated)}})); FindEntriesAndWait({kSet1AssociatedSite1}); delegate().SetEnabled(false); @@ -530,17 +511,16 @@ net::FirstPartySetsContextConfig::Create( {{kSet1AssociatedSite1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - kSet2Primary, net::SiteType::kAssociated, 0))}}) + kSet2Primary, net::SiteType::kAssociated))}}) .value(), /*cache_filter=*/std::nullopt)); EXPECT_EQ(future.Get(), - std::make_tuple( - net::FirstPartySetMetadata( - net::FirstPartySetEntry( - kSet2Primary, net::SiteType::kPrimary, std::nullopt), - net::FirstPartySetEntry(kSet2Primary, - net::SiteType::kAssociated, 0)), - net::FirstPartySetsCacheFilter::MatchInfo())); + std::make_tuple(net::FirstPartySetMetadata( + net::FirstPartySetEntry( + kSet2Primary, net::SiteType::kPrimary), + net::FirstPartySetEntry( + kSet2Primary, net::SiteType::kAssociated)), + net::FirstPartySetsCacheFilter::MatchInfo())); ComputeMetadataAndWait(kSet1AssociatedSite1, &kSet1AssociatedSite1); } @@ -558,14 +538,14 @@ net::FirstPartySetsContextConfig::Create( {{kSet1AssociatedSite1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - kSet2Primary, net::SiteType::kAssociated, 0))}}) + kSet2Primary, net::SiteType::kAssociated))}}) .value(), /*cache_filter=*/std::nullopt)); EXPECT_EQ(future.Get(), FirstPartySetsAccessDelegate::EntriesResult( {{kSet1AssociatedSite1, net::FirstPartySetEntry(kSet2Primary, - net::SiteType::kAssociated, 0)}})); + net::SiteType::kAssociated)}})); FindEntriesAndWait({kSet1AssociatedSite1}); } @@ -615,7 +595,7 @@ delegate_remote()->NotifyReady(mojom::FirstPartySetsReadyEvent::New()); base::RunLoop().RunUntilIdle(); - net::FirstPartySetEntry entry(kSet1Primary, net::SiteType::kAssociated, 0); + net::FirstPartySetEntry entry(kSet1Primary, net::SiteType::kAssociated); EXPECT_EQ( std::make_optional( std::make_pair(net::FirstPartySetMetadata(entry, entry), @@ -639,11 +619,9 @@ base::NullCallback()), FirstPartySetsAccessDelegate::EntriesResult({ {kSet1AssociatedSite1, - net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated, - 0)}, + net::FirstPartySetEntry(kSet1Primary, net::SiteType::kAssociated)}, {kSet2AssociatedSite1, - net::FirstPartySetEntry(kSet2Primary, net::SiteType::kAssociated, - 0)}, + net::FirstPartySetEntry(kSet2Primary, net::SiteType::kAssociated)}, })); } @@ -654,23 +632,22 @@ { {kSet1AssociatedSite1, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - kSet3Primary, net::SiteType::kAssociated, 0))}, + kSet3Primary, net::SiteType::kAssociated))}, {kSet3Primary, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - kSet3Primary, net::SiteType::kPrimary, std::nullopt))}, + kSet3Primary, net::SiteType::kPrimary))}, }) .value(), /*cache_filter=*/std::nullopt)); base::RunLoop().RunUntilIdle(); EXPECT_EQ(ComputeMetadataAndWait(kSet3Primary, &kSet1AssociatedSite1), - std::make_tuple( - net::FirstPartySetMetadata( - net::FirstPartySetEntry( - kSet3Primary, net::SiteType::kPrimary, std::nullopt), - net::FirstPartySetEntry(kSet3Primary, - net::SiteType::kAssociated, 0)), - net::FirstPartySetsCacheFilter::MatchInfo())); + std::make_tuple(net::FirstPartySetMetadata( + net::FirstPartySetEntry( + kSet3Primary, net::SiteType::kPrimary), + net::FirstPartySetEntry( + kSet3Primary, net::SiteType::kAssociated)), + net::FirstPartySetsCacheFilter::MatchInfo())); } TEST_F(AsyncNonwaitingFirstPartySetsAccessDelegateTest, @@ -680,7 +657,7 @@ { {kSet3Primary, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - kSet3Primary, net::SiteType::kPrimary, std::nullopt))}, + kSet3Primary, net::SiteType::kPrimary))}, }) .value(), /*cache_filter=*/std::nullopt));
diff --git a/services/network/first_party_sets/first_party_sets_manager_unittest.cc b/services/network/first_party_sets/first_party_sets_manager_unittest.cc index 39e8405..c849e91 100644 --- a/services/network/first_party_sets/first_party_sets_manager_unittest.cc +++ b/services/network/first_party_sets/first_party_sets_manager_unittest.cc
@@ -89,11 +89,10 @@ net::SchemefulSite example_test(GURL("https://example.test")); net::SchemefulSite aaaa(GURL("https://aaaa.test")); - SetCompleteSets({{aaaa, net::FirstPartySetEntry( - example_test, net::SiteType::kAssociated, 0)}, - {example_test, - net::FirstPartySetEntry( - example_test, net::SiteType::kPrimary, std::nullopt)}}, + SetCompleteSets({{aaaa, net::FirstPartySetEntry(example_test, + net::SiteType::kAssociated)}, + {example_test, net::FirstPartySetEntry( + example_test, net::SiteType::kPrimary)}}, {{example_cctld, example_test}}); EXPECT_THAT(manager().FindEntries( @@ -124,11 +123,10 @@ net::SchemefulSite example_test(GURL("https://example.test")); net::SchemefulSite aaaa(GURL("https://aaaa.test")); - SetCompleteSets({{aaaa, net::FirstPartySetEntry( - example_test, net::SiteType::kAssociated, 0)}, - {example_test, - net::FirstPartySetEntry( - example_test, net::SiteType::kPrimary, std::nullopt)}}, + SetCompleteSets({{aaaa, net::FirstPartySetEntry(example_test, + net::SiteType::kAssociated)}, + {example_test, net::FirstPartySetEntry( + example_test, net::SiteType::kPrimary)}}, {{example_cctld, example_test}}); EXPECT_THAT( @@ -139,13 +137,11 @@ }), UnorderedElementsAre( Pair(example_test, - net::FirstPartySetEntry(example_test, net::SiteType::kPrimary, - std::nullopt)), + net::FirstPartySetEntry(example_test, net::SiteType::kPrimary)), Pair(example_cctld, - net::FirstPartySetEntry(example_test, net::SiteType::kPrimary, - std::nullopt)), + net::FirstPartySetEntry(example_test, net::SiteType::kPrimary)), Pair(aaaa, net::FirstPartySetEntry(example_test, - net::SiteType::kAssociated, 0)))); + net::SiteType::kAssociated)))); } TEST_F(FirstPartySetsManagerEnabledTest, SetCompleteSets_Idempotent) { @@ -157,9 +153,8 @@ // The second call to SetCompleteSets should have no effect. SetCompleteSets( - {{aaaa, net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)}, - {example, net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)}}, + {{aaaa, net::FirstPartySetEntry(example, net::SiteType::kAssociated)}, + {example, net::FirstPartySetEntry(example, net::SiteType::kPrimary)}}, {}); EXPECT_THAT(FindEntriesAndWait({ aaaa, @@ -199,18 +194,14 @@ SetCompleteSets( { {net::SchemefulSite(GURL("https://associatedSite1.test")), - net::FirstPartySetEntry(example_test, net::SiteType::kAssociated, - 0)}, + net::FirstPartySetEntry(example_test, net::SiteType::kAssociated)}, {net::SchemefulSite(GURL("https://associatedSite3.test")), - net::FirstPartySetEntry(example_test, net::SiteType::kAssociated, - 0)}, + net::FirstPartySetEntry(example_test, net::SiteType::kAssociated)}, {example_test, - net::FirstPartySetEntry(example_test, net::SiteType::kPrimary, - std::nullopt)}, + net::FirstPartySetEntry(example_test, net::SiteType::kPrimary)}, {net::SchemefulSite(GURL("https://associatedSite2.test")), - net::FirstPartySetEntry(foo, net::SiteType::kAssociated, 0)}, - {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary, - std::nullopt)}, + net::FirstPartySetEntry(foo, net::SiteType::kAssociated)}, + {foo, net::FirstPartySetEntry(foo, net::SiteType::kPrimary)}, }, {{example_cctld, example_test}}); @@ -243,7 +234,7 @@ { net::FirstPartySetEntry entry( net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kAssociated, 0); + net::SiteType::kAssociated); EXPECT_EQ(future.Get(), net::FirstPartySetMetadata(entry, entry)); } @@ -266,14 +257,13 @@ future.Get(), UnorderedElementsAre( Pair(associatedSite1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)), + net::FirstPartySetEntry(example, net::SiteType::kAssociated)), Pair(example_cctld, - net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)), + net::FirstPartySetEntry(example, net::SiteType::kPrimary)), Pair(associatedSite2, net::FirstPartySetEntry( net::SchemefulSite(GURL("https://foo.test")), - net::SiteType::kAssociated, 0)))); + net::SiteType::kAssociated)))); } class AsyncNonwaitingFirstPartySetsManagerTest @@ -296,7 +286,7 @@ net::FirstPartySetEntry entry( net::SchemefulSite(GURL("https://example.test")), - net::SiteType::kAssociated, 0); + net::SiteType::kAssociated); EXPECT_EQ(net::FirstPartySetMetadata(entry, entry), manager().ComputeMetadata(associatedSite, &associatedSite, @@ -323,14 +313,13 @@ base::NullCallback()), Optional(UnorderedElementsAre( Pair(associatedSite1, - net::FirstPartySetEntry(example, net::SiteType::kAssociated, 0)), + net::FirstPartySetEntry(example, net::SiteType::kAssociated)), Pair(example_cctld, - net::FirstPartySetEntry(example, net::SiteType::kPrimary, - std::nullopt)), + net::FirstPartySetEntry(example, net::SiteType::kPrimary)), Pair(associatedSite2, net::FirstPartySetEntry( net::SchemefulSite(GURL("https://foo.test")), - net::SiteType::kAssociated, 0))))); + net::SiteType::kAssociated))))); } } // namespace network
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc index 536ed91..ff18b7c 100644 --- a/services/network/public/cpp/features.cc +++ b/services/network/public/cpp/features.cc
@@ -534,7 +534,7 @@ // https://wicg.github.io/shared-storage/#batch-update BASE_FEATURE(kSharedStorageTransactionalBatchUpdate, "SharedStorageTransactionalBatchUpdate", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Kill switch for the Interest Group API, i.e. if disabled, the // API exposure will be disabled regardless of the OT config.
diff --git a/services/network/public/cpp/first_party_sets_mojom_traits.cc b/services/network/public/cpp/first_party_sets_mojom_traits.cc index ed006bf9..6829b88 100644 --- a/services/network/public/cpp/first_party_sets_mojom_traits.cc +++ b/services/network/public/cpp/first_party_sets_mojom_traits.cc
@@ -25,14 +25,6 @@ namespace mojo { -bool StructTraits<network::mojom::SiteIndexDataView, - net::FirstPartySetEntry::SiteIndex>:: - Read(network::mojom::SiteIndexDataView index, - net::FirstPartySetEntry::SiteIndex* out) { - *out = net::FirstPartySetEntry::SiteIndex(index.value()); - return true; -} - bool EnumTraits<network::mojom::SiteType, net::SiteType>::FromMojom( network::mojom::SiteType site_type, net::SiteType* out) { @@ -76,7 +68,7 @@ if (!entry.ReadSiteType(&site_type)) return false; - *out = net::FirstPartySetEntry(primary, site_type, std::nullopt); + *out = net::FirstPartySetEntry(primary, site_type); return true; }
diff --git a/services/network/public/cpp/first_party_sets_mojom_traits.h b/services/network/public/cpp/first_party_sets_mojom_traits.h index 06edbdf8..ddf92b5c 100644 --- a/services/network/public/cpp/first_party_sets_mojom_traits.h +++ b/services/network/public/cpp/first_party_sets_mojom_traits.h
@@ -22,18 +22,6 @@ template <> struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS) - StructTraits<network::mojom::SiteIndexDataView, - net::FirstPartySetEntry::SiteIndex> { - static uint32_t value(const net::FirstPartySetEntry::SiteIndex& i) { - return i.value(); - } - - static bool Read(network::mojom::SiteIndexDataView index, - net::FirstPartySetEntry::SiteIndex* out); -}; - -template <> -struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS) EnumTraits<network::mojom::SiteType, net::SiteType> { static network::mojom::SiteType ToMojom(net::SiteType site_type);
diff --git a/services/network/public/cpp/first_party_sets_mojom_traits_unittest.cc b/services/network/public/cpp/first_party_sets_mojom_traits_unittest.cc index 6325001..2fb07e6 100644 --- a/services/network/public/cpp/first_party_sets_mojom_traits_unittest.cc +++ b/services/network/public/cpp/first_party_sets_mojom_traits_unittest.cc
@@ -26,16 +26,6 @@ using testing::Key; using testing::UnorderedElementsAre; -TEST(FirstPartySetsTraitsTest, Roundtrips_SiteIndex) { - net::FirstPartySetEntry::SiteIndex original(1337); - net::FirstPartySetEntry::SiteIndex round_tripped; - - EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::SiteIndex>( - original, round_tripped)); - - EXPECT_EQ(original, round_tripped); -} - TEST(FirstPartySetsTraitsTest, Roundtrips_SiteType) { for (net::SiteType site_type : { net::SiteType::kPrimary, @@ -52,7 +42,7 @@ TEST(FirstPartySetsTraitsTest, Roundtrips_FirstPartySetEntry) { net::SchemefulSite primary(GURL("https://primary.test")); - net::FirstPartySetEntry original(primary, net::SiteType::kAssociated, 1); + net::FirstPartySetEntry original(primary, net::SiteType::kAssociated); net::FirstPartySetEntry round_tripped; EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::FirstPartySetEntry>( @@ -66,10 +56,9 @@ net::SchemefulSite frame_owner(GURL("https://frame.test")); net::SchemefulSite top_frame_owner(GURL("https://top_frame.test")); - net::FirstPartySetEntry frame_entry(frame_owner, net::SiteType::kAssociated, - 1); + net::FirstPartySetEntry frame_entry(frame_owner, net::SiteType::kAssociated); net::FirstPartySetEntry top_frame_entry(top_frame_owner, - net::SiteType::kAssociated, 2); + net::SiteType::kAssociated); auto make_metadata = [&]() { // Use non-default values to ensure serialization/deserialization works @@ -100,20 +89,18 @@ base::Version("1.2.3"), /*entries=*/ { - {a, - net::FirstPartySetEntry(a, net::SiteType::kPrimary, std::nullopt)}, - {b, net::FirstPartySetEntry(a, net::SiteType::kAssociated, 0)}, - {c, - net::FirstPartySetEntry(a, net::SiteType::kService, std::nullopt)}, + {a, net::FirstPartySetEntry(a, net::SiteType::kPrimary)}, + {b, net::FirstPartySetEntry(a, net::SiteType::kAssociated)}, + {c, net::FirstPartySetEntry(a, net::SiteType::kService)}, }, /*aliases=*/{{c_cctld, c}}); original.ApplyManuallySpecifiedSet( net::LocalSetDeclaration::Create( /*set_entries=*/{{a, net::FirstPartySetEntry( - a, net::SiteType::kPrimary, std::nullopt)}, + a, net::SiteType::kPrimary)}, {b, net::FirstPartySetEntry( - a, net::SiteType::kAssociated, 0)}}, + a, net::SiteType::kAssociated)}}, /*aliases=*/{{b_cctld, b}}) .value()); @@ -138,20 +125,18 @@ base::Version(), /*entries=*/ { - {a, - net::FirstPartySetEntry(a, net::SiteType::kPrimary, std::nullopt)}, - {b, net::FirstPartySetEntry(a, net::SiteType::kAssociated, 0)}, - {c, - net::FirstPartySetEntry(a, net::SiteType::kService, std::nullopt)}, + {a, net::FirstPartySetEntry(a, net::SiteType::kPrimary)}, + {b, net::FirstPartySetEntry(a, net::SiteType::kAssociated)}, + {c, net::FirstPartySetEntry(a, net::SiteType::kService)}, }, /*aliases=*/{{c_cctld, c}}); original.ApplyManuallySpecifiedSet( net::LocalSetDeclaration::Create( /*set_entries=*/{{a, net::FirstPartySetEntry( - a, net::SiteType::kPrimary, std::nullopt)}, + a, net::SiteType::kPrimary)}, {b, net::FirstPartySetEntry( - a, net::SiteType::kAssociated, 0)}}, + a, net::SiteType::kAssociated)}}, /*aliases=*/{{b_cctld, b}}) .value()); @@ -180,12 +165,12 @@ const net::FirstPartySetsContextConfig original = net::FirstPartySetsContextConfig::Create( { - {a, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - a, net::SiteType::kPrimary, std::nullopt))}, - {b, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - a, net::SiteType::kAssociated, 0))}, + {a, net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(a, net::SiteType::kPrimary))}, + {b, net::FirstPartySetEntryOverride( + net::FirstPartySetEntry(a, net::SiteType::kAssociated))}, {b_alias, net::FirstPartySetEntryOverride(net::FirstPartySetEntry( - a, net::SiteType::kAssociated, 0))}, + a, net::SiteType::kAssociated))}, {c, net::FirstPartySetEntryOverride()}, }, {{b_alias, b}})
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn index 378bbd2..9631e36 100644 --- a/services/network/public/mojom/BUILD.gn +++ b/services/network/public/mojom/BUILD.gn
@@ -1229,10 +1229,6 @@ { types = [ { - mojom = "network.mojom.SiteIndex" - cpp = "::net::FirstPartySetEntry::SiteIndex" - }, - { mojom = "network.mojom.SiteType" cpp = "::net::SiteType" },
diff --git a/services/network/public/mojom/first_party_sets.mojom b/services/network/public/mojom/first_party_sets.mojom index d38b51f..571014d 100644 --- a/services/network/public/mojom/first_party_sets.mojom +++ b/services/network/public/mojom/first_party_sets.mojom
@@ -7,12 +7,6 @@ import "mojo/public/mojom/base/version.mojom"; import "services/network/public/mojom/schemeful_site.mojom"; -// This struct should match net::FirstPartySetEntry::SiteIndex in -// //net/first_party_sets/first_party_set_entry.h -struct SiteIndex { - uint32 value; -}; - // This enum should match //net/first_party_sets/first_party_set_entry.h. enum SiteType { kPrimary,
diff --git a/services/on_device_model/public/cpp/test_support/fake_service.cc b/services/on_device_model/public/cpp/test_support/fake_service.cc index 44c08c8c3..a72ba5c6 100644 --- a/services/on_device_model/public/cpp/test_support/fake_service.cc +++ b/services/on_device_model/public/cpp/test_support/fake_service.cc
@@ -201,6 +201,19 @@ remote->OnResponse(std::move(chunk)); } + if (options->constraint) { + const auto& constraint = *options->constraint; + auto chunk = mojom::ResponseChunk::New(); + if (constraint.is_json_schema()) { + chunk->text = "Constraint: json " + constraint.get_json_schema() + "\n"; + } else if (constraint.is_regex()) { + chunk->text = "Constraint: regex " + constraint.get_regex() + "\n"; + } else { + chunk->text = "Constraint: unknown\n"; + } + remote->OnResponse(std::move(chunk)); + } + int output_token_count = 0; if (settings_->model_execute_result.empty()) { for (const auto& context : context_) {
diff --git a/services/tracing/DEPS b/services/tracing/DEPS index 2eb00c1..28f8a93 100644 --- a/services/tracing/DEPS +++ b/services/tracing/DEPS
@@ -4,6 +4,7 @@ "+third_party/perfetto/include", "+third_party/perfetto/protos/perfetto", "+third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h", + "+third_party/snappy" ] specific_include_rules = {
diff --git a/services/tracing/public/cpp/BUILD.gn b/services/tracing/public/cpp/BUILD.gn index b84c420e..59e94b3 100644 --- a/services/tracing/public/cpp/BUILD.gn +++ b/services/tracing/public/cpp/BUILD.gn
@@ -136,6 +136,7 @@ "//build:chromecast_buildflags", "//components/system_cpu:system_cpu", "//third_party/perfetto/protos/perfetto/trace/chrome:minimal_complete_lite", + "//third_party/snappy:snappy", ] if (!(is_chromeos && target_cpu == "arm64" && current_cpu == "arm")) {
diff --git a/services/tracing/public/cpp/trace_startup_config.cc b/services/tracing/public/cpp/trace_startup_config.cc index e48529b..b25c07a 100644 --- a/services/tracing/public/cpp/trace_startup_config.cc +++ b/services/tracing/public/cpp/trace_startup_config.cc
@@ -9,6 +9,7 @@ #include <memory> #include <string> +#include "base/base64.h" #include "base/command_line.h" #include "base/files/file_util.h" #include "base/json/json_reader.h" @@ -25,6 +26,7 @@ #include "services/tracing/public/cpp/perfetto/perfetto_config.h" #include "services/tracing/public/mojom/perfetto_service.mojom.h" #include "third_party/perfetto/protos/perfetto/config/track_event/track_event_config.gen.h" +#include "third_party/snappy/src/snappy.h" #if BUILDFLAG(IS_ANDROID) #include "base/android/early_trace_event_binding.h" @@ -120,7 +122,9 @@ DCHECK(IsEnabled()); } else if (EnableFromConfigHandle()) { DCHECK(IsEnabled()); - } else if (EnableFromConfigFile()) { + } else if (EnableFromJsonConfigFile()) { + DCHECK(IsEnabled()); + } else if (EnableFromPerfettoConfigFile()) { DCHECK(IsEnabled()); } else if (EnableFromBackgroundTracing()) { DCHECK(IsEnabled()); @@ -283,7 +287,7 @@ return true; } -bool TraceStartupConfig::EnableFromConfigFile() { +bool TraceStartupConfig::EnableFromJsonConfigFile() { #if BUILDFLAG(IS_ANDROID) base::FilePath trace_config_file(kAndroidTraceConfigFile); #else @@ -318,11 +322,57 @@ DLOG(WARNING) << "Cannot read the trace config file correctly."; return false; } - is_enabled_ = ParseTraceConfigFileContent(trace_config_file_content); - if (!is_enabled_) { + auto config = ParseTraceJsonConfigFileContent(trace_config_file_content); + if (!config) { DLOG(WARNING) << "Cannot parse the trace config file correctly."; + return false; } - return is_enabled_; + perfetto_config_ = *config; + is_enabled_ = true; + return true; +} + +bool TraceStartupConfig::EnableFromPerfettoConfigFile() { + auto* command_line = base::CommandLine::ForCurrentProcess(); + if (!command_line->HasSwitch(switches::kTracePerfettoConfigFile)) { + return false; + } + base::FilePath config_file = + command_line->GetSwitchValuePath(switches::kTracePerfettoConfigFile); + + if (config_file.empty()) { + DLOG(WARNING) << "--perfetto-config-file needs a config file path."; + return false; + } + + if (!base::PathExists(config_file)) { + DLOG(WARNING) << "The perfetto config file does not exist."; + return false; + } + + std::string config_text; + if (!base::ReadFileToString(config_file, &config_text)) { + DLOG(WARNING) << "Cannot read the trace config file correctly."; + return false; + } + + std::optional<perfetto::TraceConfig> config; + if (base::FilePath::CompareEqualIgnoreCase(config_file.Extension(), + FILE_PATH_LITERAL(".pb"))) { + config = ParseSerializedPerfettoConfig(base::as_byte_span(config_text)); + } else { + config = ParseEncodedPerfettoConfig(config_text); + } + if (!config) { + DLOG(WARNING) << "Failed to parse perfetto config file."; + return false; + } + if (AdaptPerfettoConfigForChrome(&*config)) { + DLOG(WARNING) << "Failed to adapt perfetto config file."; + } + perfetto_config_ = *config; + is_enabled_ = true; + return true; } bool TraceStartupConfig::EnableFromBackgroundTracing() { @@ -352,28 +402,29 @@ return true; } -bool TraceStartupConfig::ParseTraceConfigFileContent( +std::optional<perfetto::TraceConfig> +TraceStartupConfig::ParseTraceJsonConfigFileContent( const std::string& content) { std::optional<base::Value::Dict> value = base::JSONReader::ReadDict(content); if (!value) { - return false; + return std::nullopt; } auto* trace_config_dict = value->FindDict(kTraceConfigParam); if (!trace_config_dict) { - return false; + return std::nullopt; } auto chrome_config = base::trace_event::TraceConfig(std::move(*trace_config_dict)); - perfetto_config_ = tracing::GetDefaultPerfettoConfig( + perfetto::TraceConfig perfetto_config = tracing::GetDefaultPerfettoConfig( chrome_config, false, output_format_ != OutputFormat::kProto, perfetto::protos::gen::ChromeConfig::USER_INITIATED, ""); int startup_duration_in_seconds = value->FindInt(kStartupDurationParam).value_or(0); if (startup_duration_in_seconds > 0) { - perfetto_config_.set_duration_ms(startup_duration_in_seconds * 1000); + perfetto_config.set_duration_ms(startup_duration_in_seconds * 1000); } if (auto* result_file = value->FindString(kResultFileParam)) { @@ -386,7 +437,39 @@ "_chrometrace.log"); } - return true; + return perfetto_config; +} + +std::optional<perfetto::TraceConfig> +TraceStartupConfig::ParseSerializedPerfettoConfig( + const base::span<const uint8_t>& config_bytes) { + perfetto::TraceConfig config; + if (config_bytes.empty()) { + return std::nullopt; + } + if (config.ParseFromArray(config_bytes.data(), config_bytes.size())) { + return config; + } + return std::nullopt; +} + +std::optional<perfetto::TraceConfig> +TraceStartupConfig::ParseEncodedPerfettoConfig( + const std::string& config_string) { + std::string serialized_config; + if (!base::Base64Decode(config_string, &serialized_config, + base::Base64DecodePolicy::kForgiving)) { + return std::nullopt; + } + + // `serialized_config` may optionally be compressed. + std::string decompressed_config; + if (!snappy::Uncompress(serialized_config.data(), serialized_config.size(), + &decompressed_config)) { + return ParseSerializedPerfettoConfig(base::as_byte_span(serialized_config)); + } + + return ParseSerializedPerfettoConfig(base::as_byte_span(decompressed_config)); } } // namespace tracing
diff --git a/services/tracing/public/cpp/trace_startup_config.h b/services/tracing/public/cpp/trace_startup_config.h index 452e4a0..ea424dc 100644 --- a/services/tracing/public/cpp/trace_startup_config.h +++ b/services/tracing/public/cpp/trace_startup_config.h
@@ -6,6 +6,7 @@ #define SERVICES_TRACING_PUBLIC_CPP_TRACE_STARTUP_CONFIG_H_ #include "base/component_export.h" +#include "base/containers/span.h" #include "base/files/file_path.h" #include "base/trace_event/trace_config.h" #include "build/build_config.h" @@ -154,11 +155,17 @@ TraceStartupConfig(); bool EnableFromCommandLine(); - bool EnableFromConfigFile(); + bool EnableFromJsonConfigFile(); + bool EnableFromPerfettoConfigFile(); bool EnableFromConfigHandle(); bool EnableFromBackgroundTracing(); - bool ParseTraceConfigFileContent(const std::string& content); + std::optional<perfetto::TraceConfig> ParseTraceJsonConfigFileContent( + const std::string& content); + std::optional<perfetto::TraceConfig> ParseSerializedPerfettoConfig( + const base::span<const uint8_t>& config_bytes); + std::optional<perfetto::TraceConfig> ParseEncodedPerfettoConfig( + const std::string& config_string); bool is_enabled_ = false; perfetto::TraceConfig perfetto_config_;
diff --git a/services/tracing/public/cpp/trace_startup_config_unittest.cc b/services/tracing/public/cpp/trace_startup_config_unittest.cc index a24d668..ecbe887b 100644 --- a/services/tracing/public/cpp/trace_startup_config_unittest.cc +++ b/services/tracing/public/cpp/trace_startup_config_unittest.cc
@@ -7,19 +7,39 @@ #include <algorithm> #include "base/at_exit.h" +#include "base/base64.h" #include "base/command_line.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/ptr_util.h" +#include "base/path_service.h" +#include "base/test/test_proto_loader.h" +#include "base/threading/thread_restrictions.h" #include "components/tracing/common/tracing_switches.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h" #include "third_party/perfetto/protos/perfetto/config/data_source_config.gen.h" +#include "third_party/perfetto/protos/perfetto/config/trace_config.gen.h" namespace tracing { namespace { +perfetto::protos::gen::TraceConfig ParseTracingConfigFromText( + const std::string& proto_text) { + base::ScopedAllowBlockingForTesting allow_blocking; + base::TestProtoLoader config_loader( + base::PathService::CheckedGet(base::DIR_GEN_TEST_DATA_ROOT) + .Append(FILE_PATH_LITERAL( + "third_party/perfetto/protos/perfetto/config/config.descriptor")), + "perfetto.protos.TraceConfig"); + std::string serialized_message; + config_loader.ParseFromText(proto_text, serialized_message); + perfetto::protos::gen::TraceConfig destination; + destination.ParseFromString(serialized_message); + return destination; +} + const char kTraceConfig[] = "{" "\"enable_argument_filter\":true," @@ -32,6 +52,20 @@ "\"record_mode\":\"record-continuously\"" "}"; +constexpr const char kPerfettoConfig[] = R"pb( + duration_ms: 10000 + buffers: { size_kb: 4 fill_policy: RING_BUFFER } + data_sources: { + config: { + name: "track_event" + track_event_config: { + disabled_categories: [ "excluded" ] + enabled_categories: [ "included" ] + } + } + } +)pb"; + std::string GetTraceConfigFileContent(std::string trace_config, std::string startup_duration, std::string result_file) { @@ -105,7 +139,7 @@ EXPECT_FALSE(startup_config_->IsEnabled()); } -TEST_F(TraceStartupConfigTest, ValidContent) { +TEST_F(TraceStartupConfigTest, ValidJsonContent) { std::string content = GetTraceConfigFileContent(kTraceConfig, "10", "trace_result_file.log"); @@ -132,6 +166,47 @@ startup_config_->GetResultFile()); } +TEST_F(TraceStartupConfigTest, ValidProtoContent) { + std::string config_string = + ParseTracingConfigFromText(kPerfettoConfig).SerializeAsString(); + + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + base::FilePath config_file = + temp_dir.GetPath().Append(FILE_PATH_LITERAL("config.pb")); + ASSERT_TRUE(base::WriteFile(config_file, config_string)); + base::CommandLine::ForCurrentProcess()->AppendSwitchPath( + switches::kTracePerfettoConfigFile, config_file); + + Initialize(); + ASSERT_TRUE(startup_config_->IsEnabled()); + auto config = startup_config_->GetPerfettoConfig(); + ASSERT_EQ(1, config.data_sources_size()); + EXPECT_EQ("track_event", config.data_sources()[0].config().name()); + EXPECT_EQ(10000U, config.duration_ms()); +} + +TEST_F(TraceStartupConfigTest, ValidBase64Content) { + std::string config_string = + ParseTracingConfigFromText(kPerfettoConfig).SerializeAsString(); + std::string serialized_config = base::Base64Encode(config_string); + + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + base::FilePath config_file = + temp_dir.GetPath().Append(FILE_PATH_LITERAL("config.txt")); + ASSERT_TRUE(base::WriteFile(config_file, serialized_config)); + base::CommandLine::ForCurrentProcess()->AppendSwitchPath( + switches::kTracePerfettoConfigFile, config_file); + + Initialize(); + ASSERT_TRUE(startup_config_->IsEnabled()); + auto config = startup_config_->GetPerfettoConfig(); + ASSERT_EQ(1, config.data_sources_size()); + EXPECT_EQ("track_event", config.data_sources()[0].config().name()); + EXPECT_EQ(10000U, config.duration_ms()); +} + TEST_F(TraceStartupConfigTest, ValidContentWithOnlyTraceConfig) { std::string content = GetTraceConfigFileContent(kTraceConfig, "", ""); @@ -228,7 +303,7 @@ EXPECT_FALSE(startup_config_->IsEnabled()); } -TEST_F(TraceStartupConfigTest, InvalidContent) { +TEST_F(TraceStartupConfigTest, InvalidJsonContent) { std::string content = "invalid trace config file content"; base::FilePath trace_config_file; @@ -244,6 +319,22 @@ EXPECT_FALSE(startup_config_->IsEnabled()); } +TEST_F(TraceStartupConfigTest, InvalidProtoContent) { + std::string content = "invalid trace config file content"; + + base::FilePath trace_config_file; + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + ASSERT_TRUE( + base::CreateTemporaryFileInDir(temp_dir.GetPath(), &trace_config_file)); + ASSERT_TRUE(base::WriteFile(trace_config_file, content)); + base::CommandLine::ForCurrentProcess()->AppendSwitchPath( + switches::kTracePerfettoConfigFile, trace_config_file); + + Initialize(); + EXPECT_FALSE(startup_config_->IsEnabled()); +} + TEST_F(TraceStartupConfigTest, EmptyContent) { base::FilePath trace_config_file; base::ScopedTempDir temp_dir;
diff --git a/services/viz/public/mojom/compositing/layer_context.mojom b/services/viz/public/mojom/compositing/layer_context.mojom index cfaafd6..33ac1db 100644 --- a/services/viz/public/mojom/compositing/layer_context.mojom +++ b/services/viz/public/mojom/compositing/layer_context.mojom
@@ -40,6 +40,11 @@ // Links trace events on the display side to other events in the client. uint64 trace_id; + // Indicates that this frame is submitted after the primary main frame + // navigating to a session history item, identified by this item sequence + // number. + int64 primary_main_frame_item_sequence_number; + // The page scale factors set by the tree's client. All must be positive, // non-zero. float page_scale_factor;
diff --git a/services/webnn/BUILD.gn b/services/webnn/BUILD.gn index e5104713..4236929c 100644 --- a/services/webnn/BUILD.gn +++ b/services/webnn/BUILD.gn
@@ -24,6 +24,17 @@ deps = [ ":buildflags" ] } +# Public WebNN native headers so they can be visible for dependencies +# of webnn native. +source_set("webnn_headers") { + sources = [ + # Backend headers must be included here so that dependent targets can + # still include them, even if the backends are disabled. + "d3d12_backend.h", + ] + public_deps = [ "//base" ] +} + component("webnn_service") { defines = [ "IS_WEBNN_SERVICE_IMPL" ] @@ -50,6 +61,7 @@ deps = [ ":buildflags", + ":webnn_headers", ":webnn_switches", "//base", "//gpu/command_buffer/service:gles2", @@ -157,8 +169,15 @@ if (webnn_use_ort) { sources += [ + "ort/model_editor.cc", + "ort/model_editor.h", + "ort/ort_data_type.cc", + "ort/ort_data_type.h", + "ort/ort_status.cc", + "ort/ort_status.h", "ort/platform_functions_ort.cc", "ort/platform_functions_ort.h", + "ort/scoped_ort_types.h", ] deps += [ "//third_party/onnxruntime_headers" ] } @@ -208,13 +227,16 @@ if (webnn_use_ort) { sources += [ + "ort/model_editor_test.cc", "ort/platform_functions_ort_test.cc", + "ort/test_base_ort.cc", "ort/test_base_ort.h", ] } deps = [ ":buildflags", + ":webnn_headers", ":webnn_service", "//base", "//base/test:test_support",
diff --git a/services/webnn/coreml/graph_builder_coreml.cc b/services/webnn/coreml/graph_builder_coreml.cc index 6586540..92d4854 100644 --- a/services/webnn/coreml/graph_builder_coreml.cc +++ b/services/webnn/coreml/graph_builder_coreml.cc
@@ -1831,7 +1831,7 @@ AddOperationForReshape(input_id, internal_operand_id, block)); // Points the input_id to the reshaped node's coreml identifier, so that // subsequent operations find the correct inputs. - id_to_operand_info_map()[input_id].coreml_name = + id_to_operand_info_map()[input_id]->coreml_name = GetOperandInfo(internal_operand_id).coreml_name; } return base::ok(); @@ -5734,12 +5734,12 @@ // Prefix is added to internal operands generated for WebNN operations that // need to be decomposed into multiple CoreML operations. CHECK(id_to_operand_info_map() - .try_emplace( - operand_id, - OperandInfo(base::JoinString({kInternalNamePrefix, + .try_emplace(operand_id, std::make_unique<OperandInfo>( + base::JoinString( + {kInternalNamePrefix, base::NumberToString(operand_id)}, kStringSeparator), - dimensions, mil_data_type)) + dimensions, mil_data_type)) .second); return operand_id; } @@ -5780,11 +5780,11 @@ void GraphBuilderCoreml::UpdateCoreMLInputInfoMap(OperandId operand_id) { const mojom::Operand& operand = GetOperand(operand_id); CHECK(id_to_operand_info_map() - .try_emplace(operand_id, - OperandInfo(GetCoreMLNameFromOperand(operand_id), - operand.descriptor.shape(), - OperandTypeToMILDataType( - operand.descriptor.data_type()))) + .try_emplace(operand_id, std::make_unique<OperandInfo>( + GetCoreMLNameFromOperand(operand_id), + operand.descriptor.shape(), + OperandTypeToMILDataType( + operand.descriptor.data_type()))) .second); } @@ -6073,7 +6073,7 @@ GraphBuilderCoreml::Result::GetOperandInfo(OperandId operand_id) const { auto it = id_to_operand_info_map.find(operand_id); CHECK(it != id_to_operand_info_map.end()); - return it->second; + return *it->second; } } // namespace webnn::coreml
diff --git a/services/webnn/coreml/graph_builder_coreml.h b/services/webnn/coreml/graph_builder_coreml.h index e85bcb6..b20f3df 100644 --- a/services/webnn/coreml/graph_builder_coreml.h +++ b/services/webnn/coreml/graph_builder_coreml.h
@@ -24,6 +24,7 @@ #include "services/webnn/public/mojom/webnn_context_provider.mojom.h" #include "services/webnn/public/mojom/webnn_error.mojom-forward.h" #include "services/webnn/public/mojom/webnn_graph.mojom.h" +#include "third_party/abseil-cpp/absl/container/flat_hash_map.h" #include "third_party/coremltools/mlmodel/format/MIL.pb.h" #include "third_party/coremltools/mlmodel/format/Model.pb.h" @@ -100,7 +101,10 @@ [[nodiscard]] const OperandInfo& GetOperandInfo(OperandId operand_id) const; const base::FilePath ml_package_dir; - std::map<OperandId, OperandInfo> id_to_operand_info_map; + // `std::unique_ptr` is used for values to provide pointer stabiliy for + // `GetOperandInfo`. + absl::flat_hash_map<OperandId, std::unique_ptr<OperandInfo>> + id_to_operand_info_map; }; // Factory method that creates a GraphBuilderCoreml, builds and serializes the @@ -572,7 +576,8 @@ const base::FilePath& ml_package_dir() const { return result_->ml_package_dir; } - std::map<OperandId, OperandInfo>& id_to_operand_info_map() const { + absl::flat_hash_map<OperandId, std::unique_ptr<OperandInfo>>& + id_to_operand_info_map() const { return result_->id_to_operand_info_map; }
diff --git a/services/webnn/d3d12_backend.h b/services/webnn/d3d12_backend.h new file mode 100644 index 0000000..fe68fd8 --- /dev/null +++ b/services/webnn/d3d12_backend.h
@@ -0,0 +1,56 @@ +// 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_WEBNN_D3D12_BACKEND_H_ +#define SERVICES_WEBNN_D3D12_BACKEND_H_ + +#include <stdint.h> + +#include <memory> + +#include "base/component_export.h" +#include "third_party/microsoft_dxheaders/src/include/directx/d3d12.h" + +// Windows SDK headers should be included after DirectX headers. +#include <wrl.h> + +namespace webnn::native::d3d12 { + +// WebNNSharedFence is a wrapper of an ID3D12Fence and fence value which is +// signaled when the execution on GPU is completed. +struct COMPONENT_EXPORT(WEBNN_SERVICE) WebNNSharedFence { + virtual Microsoft::WRL::ComPtr<ID3D12Fence> GetD3D12Fence() const = 0; + virtual uint64_t GetFenceValue() const = 0; + virtual ~WebNNSharedFence() = default; +}; + +// WebNNTensor is a native interface which exposes a WebNN tensor in the +// GPU service using backend-specific APIs. Implemented by the WebNN +// service and called by shared image backings to access the tensor. +class COMPONENT_EXPORT(WEBNN_SERVICE) WebNNTensor { + public: + // Begin WebNN access to the underlying buffer held in the `WebNNTensor` + // instance. Input is a fence which will be waited on by WebNN before + // execution resumes. If successful, EndAccessWebNN() must be called to + // BeginAccessWebNN() again. + virtual bool BeginAccessWebNN(Microsoft::WRL::ComPtr<ID3D12Fence> wait_fence, + uint64_t wait_fence_value) = 0; + + // End WebNN access to the underlying buffer held in the `WebNNTensor` + // instance. Outputs a fence to be signaled by WebNN after execution + // completes. If successful, BeginAccessWebNN() must be called to restore + // access to WebNN and to EndAccessWebNN() again. + virtual std::unique_ptr<WebNNSharedFence> EndAccessWebNN() = 0; + + // Retrieves the underlying buffer held in the `WebNNTensor` instance. + // The returned tensor buffer is a committed resource which cannot be used + // externally until EndAccessWebNN() is called. + virtual ID3D12Resource* GetD3D12Buffer() const = 0; + + virtual ~WebNNTensor() = default; +}; + +} // namespace webnn::native::d3d12 + +#endif // SERVICES_WEBNN_D3D12_BACKEND_H_
diff --git a/services/webnn/dml/command_recorder.cc b/services/webnn/dml/command_recorder.cc index 19cfffd..1ed95c3b 100644 --- a/services/webnn/dml/command_recorder.cc +++ b/services/webnn/dml/command_recorder.cc
@@ -126,6 +126,15 @@ command_queue_->submission_fence(), last_submitted_fence_value_)); } + // Before command submission, ensure interop tensors are not accessed by + // the command queue until existing GPU work using them has been completed. + for (auto& [command_buffer, webnn_tensor_impl] : command_tensor_impls_) { + if (webnn_tensor_impl) { + RETURN_IF_FAILED(webnn_tensor_impl->WaitForExternalFenceAndReset( + command_queue_.get())); + } + } + RETURN_IF_FAILED(command_queue_->ExecuteCommandList(command_list_.Get())); last_submitted_fence_value_ = command_queue_->GetLastFenceValue();
diff --git a/services/webnn/dml/context_impl_dml.cc b/services/webnn/dml/context_impl_dml.cc index a8279d7..b64452a 100644 --- a/services/webnn/dml/context_impl_dml.cc +++ b/services/webnn/dml/context_impl_dml.cc
@@ -934,6 +934,10 @@ CHECK(hr == E_OUTOFMEMORY || hr == DXGI_ERROR_DEVICE_RESET); } +CommandQueue* ContextImplDml::GetCommandQueue() const { + return adapter_->command_queue(); +} + void ContextImplDml::RemoveDeviceForTesting() { CHECK_IS_TEST();
diff --git a/services/webnn/dml/context_impl_dml.h b/services/webnn/dml/context_impl_dml.h index 4479df9..37e9c25 100644 --- a/services/webnn/dml/context_impl_dml.h +++ b/services/webnn/dml/context_impl_dml.h
@@ -18,6 +18,7 @@ namespace webnn::dml { class Adapter; +class CommandQueue; class CommandRecorder; class TensorImplDml; @@ -59,6 +60,8 @@ // gracefully terminate the GPU process. void HandleContextLostOrCrash(std::string_view message_for_log, HRESULT hr); + CommandQueue* GetCommandQueue() const; + void RemoveDeviceForTesting(); // The test cases can override the graph/tensor creating behavior by
diff --git a/services/webnn/dml/graph_impl_dml.cc b/services/webnn/dml/graph_impl_dml.cc index 3a7d431..8e3395a 100644 --- a/services/webnn/dml/graph_impl_dml.cc +++ b/services/webnn/dml/graph_impl_dml.cc
@@ -55,6 +55,8 @@ #include "services/webnn/webnn_constant_operand.h" #include "services/webnn/webnn_context_impl.h" #include "services/webnn/webnn_utils.h" +#include "third_party/abseil-cpp/absl/container/flat_hash_map.h" +#include "third_party/abseil-cpp/absl/container/flat_hash_set.h" #include "third_party/fp16/src/include/fp16.h" namespace webnn::dml { @@ -77,7 +79,7 @@ using IdToOperandMap = base::flat_map<OperandId, OperandPtr>; // A map of all node outputs in `dml::GraphBuilderDml` using the mojom operand // id as key. -using IdToNodeOutputMap = std::map<OperandId, const NodeOutput*>; +using IdToNodeOutputMap = absl::flat_hash_map<OperandId, const NodeOutput*>; static constexpr auto kDmlFloatDataTypes = base::MakeFixedFlatSet<DML_TENSOR_DATA_TYPE>( @@ -254,7 +256,7 @@ const base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>>& constant_operands) { base::CheckedNumeric<size_t> total_byte_length(0); - std::map<OperandId, D3D12_RANGE> key_to_d3d12_range_map; + absl::flat_hash_map<OperandId, D3D12_RANGE> key_to_d3d12_range_map; for (const auto& [operand_id, constant_operand] : constant_operands) { auto& d3d12_range = key_to_d3d12_range_map[operand_id]; @@ -287,7 +289,7 @@ const base::flat_map<std::string, OperandDescriptor>& names_to_descriptors) { base::CheckedNumeric<size_t> total_byte_length(0); - std::map<std::string, D3D12_RANGE> key_to_d3d12_range_map; + absl::flat_hash_map<std::string, D3D12_RANGE> key_to_d3d12_range_map; for (auto& [name, descriptor] : names_to_descriptors) { auto& d3d12_range = key_to_d3d12_range_map[name]; @@ -324,7 +326,7 @@ // `buffer_variant` for both constants uploading and binding. For GPU doesn't // support UMA, pass a upload buffer and a default buffer via `buffer_variant` // for uploading and binding separately. -base::expected<std::map<OperandId, DML_BUFFER_BINDING>, HRESULT> +base::expected<absl::flat_hash_map<OperandId, DML_BUFFER_BINDING>, HRESULT> UploadAndCreateConstantBufferBinding( CommandRecorder* command_recorder, const base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>>& @@ -357,7 +359,7 @@ RETURN_UNEXPECTED_IF_FAILED(buffer_to_map->Map(0, nullptr, &mapped_buffer)); - std::map<OperandId, DML_BUFFER_BINDING> key_to_buffer_binding_map; + absl::flat_hash_map<OperandId, DML_BUFFER_BINDING> key_to_buffer_binding_map; for (auto& [operand_id, constant_operand] : constant_operands) { // Copy the input data to the upload heap with byte offset const auto& d3d12_range = @@ -392,7 +394,8 @@ HRESULT MapAndCopyInputDataToBuffer( const base::flat_map<std::string, mojo_base::BigBuffer>& named_inputs, - const std::map<std::string, D3D12_RANGE>& input_name_to_d3d12_range_map, + const absl::flat_hash_map<std::string, D3D12_RANGE>& + input_name_to_d3d12_range_map, ID3D12Resource* buffer) { // Map entire resource to copy the array buffer of input one by one // with byte offset. @@ -451,7 +454,7 @@ constant_operands, GraphBuilderDml& graph_builder, IdToNodeOutputMap& id_to_node_output_map, - std::unordered_map<OperandId, uint32_t>& constant_id_to_input_index_map) { + absl::flat_hash_map<OperandId, uint32_t>& constant_id_to_input_index_map) { const OperandDescriptor operand_descriptor = constant_operands.at(operand_id)->descriptor(); @@ -692,7 +695,8 @@ } std::optional<const Operation*> GetFusibleActivationFromOperation( - const std::map<const Operation*, raw_ptr<const Operation, CtnExperimental>>& + const absl::flat_hash_map<const Operation*, + raw_ptr<const Operation, CtnExperimental>>& operation_to_fusible_standalone_activation_map, const Operation* operation) { const auto activation_iterator = @@ -704,8 +708,9 @@ return std::optional<const Operation*>(); } -std::optional<OperandId> GetFusibleTransposeInputId( - const std::map<OperandId, raw_ptr<const Operation, CtnExperimental>>& +std::optional<uint64_t> GetFusibleTransposeInputId( + const absl::flat_hash_map<OperandId, + raw_ptr<const Operation, CtnExperimental>>& output_id_to_fusible_transpose_map, OperandId input_id) { const auto transpose_iterator = @@ -1303,18 +1308,19 @@ // fused into preceding operations. // The key is the preceding operation which can support fusion. The value is // the standalone activation which can be fused into the preceding operation. - std::map<const Operation*, raw_ptr<const Operation, CtnExperimental>> + absl::flat_hash_map<const Operation*, + raw_ptr<const Operation, CtnExperimental>> operation_to_fusible_standalone_activation_map; // A map of all transposes that can be fused into the following matmul using // transpose's output operand id as the key. - std::map<OperandId, raw_ptr<const Operation, CtnExperimental>> + absl::flat_hash_map<OperandId, raw_ptr<const Operation, CtnExperimental>> output_id_to_fusible_transpose_map; // A set of all operations in `mojom::GraphInfo` which can be fused into // another operation. No DirectML operator node will be created for operations // in this set. - std::unordered_set<const Operation*> fusible_operations_set; + absl::flat_hash_set<const Operation*> fusible_operations_set; }; // The method gets the graph fusion information from `mojom::GraphInfo`, based @@ -1332,7 +1338,7 @@ // A map of all fusible activations in `mojom::GraphInfo` using activation's // input operand id as the key. - std::map<OperandId, raw_ptr<const Operation, CtnExperimental>> + absl::flat_hash_map<OperandId, raw_ptr<const Operation, CtnExperimental>> input_id_to_activation_map; // The case we're interested in includes a fusible base operation with exactly @@ -1381,7 +1387,7 @@ // A map of all matmul operations in `mojom::GraphInfo` using matmul's input // operand id as the key. - std::map<OperandId, const Operation*> input_id_to_matmul_map; + absl::flat_hash_map<OperandId, const Operation*> input_id_to_matmul_map; // This is a scenario where transpose can be fused into the following matmul. // The transpose output solely feeds matmul. The transposed input can be @@ -1408,7 +1414,7 @@ GraphFusionInfo graph_fusion_info; // A map to record how many times each operand id is used as one // operation's input edge or the graph's output edge. - std::map<OperandId, uint32_t> operand_id_to_use_count_map; + absl::flat_hash_map<OperandId, uint32_t> operand_id_to_use_count_map; for (const auto& pair : graph_info->id_to_operand_map) { operand_id_to_use_count_map[pair.first] = 0; } @@ -1526,14 +1532,15 @@ Adapter* adapter, const ContextProperties& context_properties, const Operation* operation, - const std::map<const Operation*, raw_ptr<const Operation, CtnExperimental>>& + const absl::flat_hash_map<const Operation*, + raw_ptr<const Operation, CtnExperimental>>& operation_to_fusible_standalone_activation_map, mojom::GraphInfoPtr& graph_info, base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>>& constant_operands, GraphBuilderDml& graph_builder, IdToNodeOutputMap& id_to_node_output_map, - std::unordered_map<OperandId, uint32_t>& constant_id_to_input_index_map, + absl::flat_hash_map<OperandId, uint32_t>& constant_id_to_input_index_map, OperandId& next_operand_id) { const auto& batch_normalization = operation->get_batch_normalization(); auto& id_to_operand_map = graph_info->id_to_operand_map; @@ -1780,7 +1787,8 @@ const ContextProperties& context_properties, const IdToOperandMap& id_to_operand_map, const Operation* operation, - const std::map<const Operation*, raw_ptr<const Operation, CtnExperimental>>& + const absl::flat_hash_map<const Operation*, + raw_ptr<const Operation, CtnExperimental>>& operation_to_fusible_standalone_activation_map, GraphBuilderDml& graph_builder, IdToNodeOutputMap& id_to_node_output_map) { @@ -2299,7 +2307,8 @@ const ContextProperties& context_properties, const IdToOperandMap& id_to_operand_map, const Operation* operation, - const std::map<const Operation*, raw_ptr<const Operation, CtnExperimental>>& + const absl::flat_hash_map<const Operation*, + raw_ptr<const Operation, CtnExperimental>>& operation_to_fusible_standalone_activation_map, GraphBuilderDml& graph_builder, IdToNodeOutputMap& id_to_node_output_map) { @@ -3566,7 +3575,7 @@ constant_operands, GraphBuilderDml& graph_builder, IdToNodeOutputMap& id_to_node_output_map, - std::unordered_map<OperandId, uint32_t>& constant_id_to_input_index_map, + absl::flat_hash_map<OperandId, uint32_t>& constant_id_to_input_index_map, OperandId& next_operand_id) { // Check feature level by referring to MSDN doc: // https://learn.microsoft.com/en-us/windows/ai/directml/api/ns-directml-dml_activation_gelu_operator_desc @@ -3719,7 +3728,8 @@ const ContextProperties& context_properties, const IdToOperandMap& id_to_operand_map, const Operation* operation, - const std::map<const Operation*, raw_ptr<const Operation, CtnExperimental>>& + const absl::flat_hash_map<const Operation*, + raw_ptr<const Operation, CtnExperimental>>& operation_to_fusible_standalone_activation_map, GraphBuilderDml& graph_builder, IdToNodeOutputMap& id_to_node_output_map) { @@ -3852,7 +3862,7 @@ constant_operands, GraphBuilderDml& graph_builder, IdToNodeOutputMap& id_to_node_output_map, - std::unordered_map<OperandId, uint32_t>& constant_id_to_input_index_map, + absl::flat_hash_map<OperandId, uint32_t>& constant_id_to_input_index_map, OperandId& next_operand_id) { mojom::Operation::Tag op_tag; std::optional<OperandId> initial_hidden_state_operand_id; @@ -4247,14 +4257,15 @@ const ContextProperties& context_properties, const NormalizationPtr& normalization, const Operation* operation, - const std::map<const Operation*, raw_ptr<const Operation, CtnExperimental>>& + const absl::flat_hash_map<const Operation*, + raw_ptr<const Operation, CtnExperimental>>& operation_to_fusible_standalone_activation_map, mojom::GraphInfoPtr& graph_info, base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>>& constant_operands, GraphBuilderDml& graph_builder, IdToNodeOutputMap& id_to_node_output_map, - std::unordered_map<OperandId, uint32_t>& constant_id_to_input_index_map, + absl::flat_hash_map<OperandId, uint32_t>& constant_id_to_input_index_map, OperandId& next_operand_id, base::span<const uint32_t> mean_variance_axes, base::span<const uint32_t> scale_bias_broadcast_axes, @@ -4480,7 +4491,7 @@ constant_operands, GraphBuilderDml& graph_builder, IdToNodeOutputMap& id_to_node_output_map, - std::unordered_map<OperandId, uint32_t>& constant_id_to_input_index_map, + absl::flat_hash_map<OperandId, uint32_t>& constant_id_to_input_index_map, OperandId& next_operand_id) { const std::string& label = lstm.label; IdToOperandMap& id_to_operand_map = graph_info->id_to_operand_map; @@ -5014,9 +5025,11 @@ const ContextProperties& context_properties, const IdToOperandMap& id_to_operand_map, const Operation* operation, - const std::map<const Operation*, raw_ptr<const Operation, CtnExperimental>>& + const absl::flat_hash_map<const Operation*, + raw_ptr<const Operation, CtnExperimental>>& operation_to_fusible_standalone_activation_map, - const std::map<OperandId, raw_ptr<const Operation, CtnExperimental>>& + const absl::flat_hash_map<OperandId, + raw_ptr<const Operation, CtnExperimental>>& output_id_to_fusible_transpose_map, GraphBuilderDml& graph_builder, IdToNodeOutputMap& id_to_node_output_map) { @@ -5457,7 +5470,7 @@ constant_operands, GraphBuilderDml& graph_builder, IdToNodeOutputMap& id_to_node_output_map, - std::unordered_map<OperandId, uint32_t>& constant_id_to_input_index_map, + absl::flat_hash_map<OperandId, uint32_t>& constant_id_to_input_index_map, OperandId& next_operand_id) { const NodeOutput* input = GetNodeOutputForOperand( id_to_node_output_map, triangular->input_operand_id); @@ -6015,7 +6028,7 @@ scoped_refptr<Adapter> adapter, base::WeakPtr<ContextImplDml> context, WebNNContextImpl::CreateGraphImplCallback callback, - std::unordered_map<OperandId, uint32_t> constant_id_to_input_index_map, + absl::flat_hash_map<OperandId, uint32_t> constant_id_to_input_index_map, GraphBufferBindingInfo graph_buffer_binding_info, ComputeResourceInfo compute_resource_info, base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>> @@ -6143,7 +6156,8 @@ } ASSIGN_OR_RETURN( - (std::map<OperandId, DML_BUFFER_BINDING> constant_buffer_binding), + (absl::flat_hash_map<OperandId, DML_BUFFER_BINDING> + constant_buffer_binding), UploadAndCreateConstantBufferBinding( initialization_command_recorder.get(), constant_operands, aligned_byte_length_of_constants.value(), @@ -6362,7 +6376,7 @@ base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>>& constant_operands, GraphBuilderDml& graph_builder, - std::unordered_map<OperandId, uint32_t>& constant_id_to_input_index_map, + absl::flat_hash_map<OperandId, uint32_t>& constant_id_to_input_index_map, GraphBufferBindingInfo& graph_buffer_binding_info) { IdToNodeOutputMap id_to_node_output_map; const IdToOperandMap& id_to_operand_map = graph_info->id_to_operand_map; @@ -6845,7 +6859,7 @@ TRACE_EVENT0("gpu", "dml::GraphImplDml::CreateAndBuild"); GraphBuilderDml graph_builder(adapter->dml_device()); - std::unordered_map<OperandId, uint32_t> constant_id_to_input_index_map; + absl::flat_hash_map<OperandId, uint32_t> constant_id_to_input_index_map; GraphBufferBindingInfo graph_buffer_binding_info; base::expected<void, mojom::ErrorPtr> create_operator_result = GraphImplDml::CreateAndBuildInternal(
diff --git a/services/webnn/dml/graph_impl_dml.h b/services/webnn/dml/graph_impl_dml.h index 660e90e..5636a45 100644 --- a/services/webnn/dml/graph_impl_dml.h +++ b/services/webnn/dml/graph_impl_dml.h
@@ -5,10 +5,8 @@ #ifndef SERVICES_WEBNN_DML_GRAPH_IMPL_DML_H_ #define SERVICES_WEBNN_DML_GRAPH_IMPL_DML_H_ -#include <map> #include <memory> #include <string> -#include <unordered_map> #include <vector> #include "base/containers/flat_map.h" @@ -23,6 +21,7 @@ #include "services/webnn/webnn_constant_operand.h" #include "services/webnn/webnn_context_impl.h" #include "services/webnn/webnn_graph_impl.h" +#include "third_party/abseil-cpp/absl/container/flat_hash_map.h" #include "third_party/microsoft_dxheaders/include/directml.h" // Windows SDK headers should be included after DirectX headers. @@ -40,7 +39,7 @@ template <typename Key> struct AlignedByteLength { size_t total_byte_length = 0; - std::map<Key, D3D12_RANGE> key_to_d3d12_range_map; + absl::flat_hash_map<Key, D3D12_RANGE> key_to_d3d12_range_map; }; // GraphImplDml inherits WebNNGraphImpl to represent a DML graph implementation. @@ -68,12 +67,12 @@ // order. // The index is the DML_INPUT_GRAPH_EDGE_DESC::GraphInputIndex when // creating the DML_GRAPH_DESC. - std::unordered_map<std::string, uint32_t> graph_input_name_to_index_map; + absl::flat_hash_map<std::string, uint32_t> graph_input_name_to_index_map; // The map is used to bind output buffers for the graph execution in // order. // The index is the DML_OUTPUT_GRAPH_EDGE_DESC::GraphOutputIndex when // creating the DML_GRAPH_DESC. - std::unordered_map<std::string, uint32_t> graph_output_name_to_index_map; + absl::flat_hash_map<std::string, uint32_t> graph_output_name_to_index_map; }; static base::expected<void, mojom::ErrorPtr> CreateAndBuildInternal( const ContextProperties& context_properties, @@ -82,7 +81,7 @@ base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>>& constant_operands, GraphBuilderDml& graph_builder, - std::unordered_map<OperandId, uint32_t>& constant_id_to_input_index_map, + absl::flat_hash_map<OperandId, uint32_t>& constant_id_to_input_index_map, GraphBufferBindingInfo& graph_buffer_binding_info); // This method builds and compiles a DML graph from mojom::GraphInfo via @@ -224,7 +223,7 @@ scoped_refptr<Adapter> adapter, base::WeakPtr<ContextImplDml> context, WebNNContextImpl::CreateGraphImplCallback callback, - std::unordered_map<OperandId, uint32_t> constant_id_to_input_index_map, + absl::flat_hash_map<OperandId, uint32_t> constant_id_to_input_index_map, GraphBufferBindingInfo graph_buffer_binding_info, ComputeResourceInfo compute_resource_info, base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>>
diff --git a/services/webnn/dml/tensor_impl_dml.cc b/services/webnn/dml/tensor_impl_dml.cc index 05efe5d..f06c4422 100644 --- a/services/webnn/dml/tensor_impl_dml.cc +++ b/services/webnn/dml/tensor_impl_dml.cc
@@ -5,11 +5,29 @@ #include "services/webnn/dml/tensor_impl_dml.h" #include "mojo/public/cpp/bindings/pending_associated_receiver.h" +#include "services/webnn/dml/command_queue.h" #include "services/webnn/dml/context_impl_dml.h" +#include "services/webnn/dml/error.h" #include "services/webnn/public/mojom/webnn_tensor.mojom.h" namespace webnn::dml { +SharedFence::SharedFence(Microsoft::WRL::ComPtr<ID3D12Fence> fence, + UINT64 fence_value) + : fence(std::move(fence)), fence_value(fence_value) {} + +SharedFence::~SharedFence() = default; + +SharedFence::SharedFence(SharedFence&&) = default; + +Microsoft::WRL::ComPtr<ID3D12Fence> SharedFence::GetD3D12Fence() const { + return fence; +} + +uint64_t SharedFence::GetFenceValue() const { + return fence_value; +} + TensorImplDml::TensorImplDml( mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver, Microsoft::WRL::ComPtr<ID3D12Resource> buffer, @@ -39,4 +57,47 @@ return last_submission_fence_value_; } +HRESULT TensorImplDml::WaitForExternalFenceAndReset( + CommandQueue* command_queue) { + if (wait_fence_external_) { + RETURN_IF_FAILED( + command_queue->WaitForFence(std::move(wait_fence_external_->fence), + wait_fence_external_->fence_value)); + wait_fence_external_.reset(); + } + return S_OK; +} + +bool TensorImplDml::BeginAccessWebNN( + Microsoft::WRL::ComPtr<ID3D12Fence> wait_fence, + uint64_t wait_fence_value) { + CHECK(wait_fence); + + wait_fence_external_.emplace(std::move(wait_fence), wait_fence_value); + return true; +} + +std::unique_ptr<native::d3d12::WebNNSharedFence> +TensorImplDml::EndAccessWebNN() { + CommandQueue* command_queue = + static_cast<ContextImplDml*>(context_.get())->GetCommandQueue(); + + // If WebNN executed no commands using this tensor, the caller's command queue + // will wait on the last wait fence provided. + if (wait_fence_external_) { + SharedFence fence = std::move(wait_fence_external_.value()); + wait_fence_external_.reset(); + return base::WrapUnique(new SharedFence(std::move(fence))); + } + + // Return WebNN's submission fence and the last fence value from execution + // that used this tensor. + return base::WrapUnique(new SharedFence( + {command_queue->submission_fence(), last_submission_fence_value_})); +} + +ID3D12Resource* TensorImplDml::GetD3D12Buffer() const { + return buffer(); +} + } // namespace webnn::dml
diff --git a/services/webnn/dml/tensor_impl_dml.h b/services/webnn/dml/tensor_impl_dml.h index 335b952b..a2a7768 100644 --- a/services/webnn/dml/tensor_impl_dml.h +++ b/services/webnn/dml/tensor_impl_dml.h
@@ -5,6 +5,7 @@ #ifndef SERVICES_WEBNN_DML_TENSOR_IMPL_DML_H_ #define SERVICES_WEBNN_DML_TENSOR_IMPL_DML_H_ +#include "services/webnn/d3d12_backend.h" #include "services/webnn/public/mojom/webnn_tensor.mojom-forward.h" #include "services/webnn/webnn_tensor_impl.h" #include "third_party/microsoft_dxheaders/src/include/directx/d3d12.h" @@ -14,9 +15,25 @@ namespace webnn::dml { +class CommandQueue; class ContextImplDml; -class TensorImplDml final : public WebNNTensorImpl { +struct SharedFence final : public native::d3d12::WebNNSharedFence { + SharedFence(Microsoft::WRL::ComPtr<ID3D12Fence> fence, UINT64 fence_value); + ~SharedFence() override; + + SharedFence(SharedFence&&); + + // native::d3d12::WebNNSharedFence implementation + Microsoft::WRL::ComPtr<ID3D12Fence> GetD3D12Fence() const override; + uint64_t GetFenceValue() const override; + + const Microsoft::WRL::ComPtr<ID3D12Fence> fence; + const uint64_t fence_value; +}; + +class TensorImplDml final : public WebNNTensorImpl, + public native::d3d12::WebNNTensor { public: TensorImplDml(mojo::PendingAssociatedReceiver<mojom::WebNNTensor> receiver, Microsoft::WRL::ComPtr<ID3D12Resource> buffer, @@ -39,10 +56,18 @@ return weak_factory_.GetWeakPtr(); } + HRESULT WaitForExternalFenceAndReset(CommandQueue* command_queue); + private: void ReadTensorImpl(ReadTensorCallback callback) override; void WriteTensorImpl(mojo_base::BigBuffer src_buffer) override; + // native::d3d12::WebNNTensor implementation + bool BeginAccessWebNN(Microsoft::WRL::ComPtr<ID3D12Fence> wait_fence, + uint64_t wait_fence_value) override; + std::unique_ptr<native::d3d12::WebNNSharedFence> EndAccessWebNN() override; + ID3D12Resource* GetD3D12Buffer() const override; + // The D3D12 resource that holds the tensor data. // The buffer must always remain valid after creation and could outlive // the scope of this `TensorImplDml` instance because it may be used @@ -54,6 +79,11 @@ // indicate whether commands have completed execution. uint64_t last_submission_fence_value_ = 0; + // Required input to `BeginAccessWebNN()` to resume WebNN execution after + // this fence is signaled. If no value, there is no need to wait for access to + // the tensor. + std::optional<SharedFence> wait_fence_external_; + base::WeakPtrFactory<TensorImplDml> weak_factory_{this}; };
diff --git a/services/webnn/error.h b/services/webnn/error.h index 8bc5ebdbf..e82fdebf 100644 --- a/services/webnn/error.h +++ b/services/webnn/error.h
@@ -20,6 +20,8 @@ "Invalid tensor from renderer."; inline constexpr char kBadMessageOnBuiltGraphBuilder[] = "Invalid message on an MLGraphBuilder which has already built a graph."; +inline constexpr char kBadMessageInvalidContext[] = + "Invalid context from renderer."; template <typename MojoResultType> mojo::StructPtr<MojoResultType> ToError(const mojom::Error::Code& error_code,
diff --git a/services/webnn/ort/model_editor.cc b/services/webnn/ort/model_editor.cc new file mode 100644 index 0000000..236ae12 --- /dev/null +++ b/services/webnn/ort/model_editor.cc
@@ -0,0 +1,343 @@ +// 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/webnn/ort/model_editor.h" + +#include <numeric> +#include <ranges> + +#include "base/functional/overloaded.h" +#include "base/notreached.h" +#include "base/numerics/checked_math.h" +#include "base/types/fixed_array.h" +#include "services/webnn/ort/ort_data_type.h" +#include "services/webnn/ort/ort_status.h" + +namespace webnn::ort { + +namespace { + +// Domains +constexpr char kOrtDefaultDomain[] = ""; +constexpr char kMSDomain[] = "com.microsoft"; + +// Opset versions +constexpr int32_t kOrtOpsetVersion = 21; + +// EPContext op is used for exporting the compiled model. +// https://onnxruntime.ai/docs/execution-providers/EP-Context-Design.html#onnxruntime-ep-context-cache-feature-design +constexpr int32_t kEPContextOpsetVersion = 1; + +// The minimum size (in bytes) to add the initializer as external data. An +// initializer less than 128 bytes might be used for shape inferencing which +// doesn't support external data. +// https://github.com/microsoft/onnxruntime/blob/c1ef02f74b0d648cc7e8558805fa90846ea11a35/include/onnxruntime/core/session/onnxruntime_c_api.h#L5564 +constexpr size_t kMinExternalDataSize = 128; + +const OrtApi* GetOrtApi() { + return PlatformFunctions::GetInstance()->ort_api(); +} + +const OrtModelEditorApi* GetOrtModelEditorApi() { + return PlatformFunctions::GetInstance()->ort_model_editor_api(); +} + +std::vector<int64_t> VectorUint32ToInt64(base::span<const uint32_t> vec) { + return std::vector<int64_t>(vec.begin(), vec.end()); +} + +size_t CalculateOrtTensorSizeInBytes(base::span<const int64_t> shape, + ONNXTensorElementDataType data_type) { + base::CheckedNumeric<uint64_t> element_size_in_bits; + switch (data_type) { + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: + case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64: { + element_size_in_bits = 64; + break; + } + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32: + case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32: { + element_size_in_bits = 32; + break; + } + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16: { + element_size_in_bits = 16; + break; + } + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8: + case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: { + element_size_in_bits = 8; + break; + } + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT4: + case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT4: { + element_size_in_bits = 4; + break; + } + default: { + NOTREACHED() + << "CalculateOrtTensorSizeInBytes() only supports WebNN data types."; + } + } + auto tensor_size_in_bits = std::accumulate( + shape.begin(), shape.end(), element_size_in_bits, std::multiplies()); + + return ((tensor_size_in_bits + 7) / 8).ValueOrDie<size_t>(); +} + +ScopedOrtValueInfo CreateOrtValueInfo(base::cstring_view name, + const OperandDescriptor& descriptor) { + const OrtApi* ort_api = GetOrtApi(); + ScopedOrtTensorTypeAndShapeInfo tensor_type_and_shape_info; + CHECK_STATUS(ort_api->CreateTensorTypeAndShapeInfo( + ScopedOrtTensorTypeAndShapeInfo::Receiver(tensor_type_and_shape_info) + .get())); + CHECK_STATUS(ort_api->SetTensorElementType( + tensor_type_and_shape_info.get(), + WebnnToOnnxDataType(descriptor.data_type()))); + + std::vector<int64_t> int64_shape = VectorUint32ToInt64(descriptor.shape()); + CHECK_STATUS(ort_api->SetDimensions(tensor_type_and_shape_info.get(), + int64_shape.data(), int64_shape.size())); + + const OrtModelEditorApi* ort_model_editor_api = GetOrtModelEditorApi(); + ScopedOrtTypeInfo type_info; + CHECK_STATUS(ort_model_editor_api->CreateTensorTypeInfo( + tensor_type_and_shape_info.get(), + ScopedOrtTypeInfo::Receiver(type_info).get())); + + ScopedOrtValueInfo value_info; + CHECK_STATUS(ort_model_editor_api->CreateValueInfo( + name.c_str(), type_info.get(), + ScopedOrtValueInfo::Receiver(value_info).get())); + return value_info; +} + +} // namespace + +ModelEditor::ModelInfo::ModelInfo() = default; +ModelEditor::ModelInfo::~ModelInfo() = default; + +ModelEditor::ModelEditor() : model_info_(std::make_unique<ModelInfo>()) { + const OrtApi* ort_api = GetOrtApi(); + // Create a CPU memory info, the constants will always be created in + // CPU memory. + CHECK_STATUS(ort_api->CreateCpuMemoryInfo( + OrtDeviceAllocator, OrtMemTypeDefault, + ScopedOrtMemoryInfo::Receiver(memory_info_).get())); + + const OrtModelEditorApi* ort_model_editor_api = GetOrtModelEditorApi(); + CHECK_STATUS(ort_model_editor_api->CreateGraph( + ScopedOrtGraph::Receiver(graph_).get())); +} + +ModelEditor::~ModelEditor() = default; + +void ModelEditor::AddInput(base::cstring_view name, + const OperandDescriptor& descriptor) { + CHECK(!has_built_); + inputs_.push_back(CreateOrtValueInfo(name, descriptor)); +} + +void ModelEditor::AddOutput(base::cstring_view name, + const OperandDescriptor& descriptor) { + CHECK(!has_built_); + outputs_.push_back(CreateOrtValueInfo(name, descriptor)); +} + +void ModelEditor::AddInitializer(base::cstring_view name, + const WebNNConstantOperand& constant_operand) { + CHECK(!has_built_); + + const OperandDescriptor& descriptor = constant_operand.descriptor(); + AddInitializer(name, WebnnToOnnxDataType(descriptor.data_type()), + VectorUint32ToInt64(descriptor.shape()), + constant_operand.ByteSpan()); +} + +void ModelEditor::AddInitializer(base::cstring_view name, + ONNXTensorElementDataType data_type, + base::span<const int64_t> shape, + base::span<const uint8_t> data) { + CHECK(!has_built_); + + bool use_external_data = data.size() >= kMinExternalDataSize; + if (use_external_data) { + AddInitializerAsExternalData(name, data_type, shape, data); + } else { + AddInitializerAsRawData(name, data_type, shape, data); + } +} + +void ModelEditor::AddInitializerAsRawData(base::cstring_view name, + ONNXTensorElementDataType data_type, + base::span<const int64_t> shape, + base::span<const uint8_t> data) { + const OrtApi* ort_api = GetOrtApi(); + // Get the default CPU allocator, as the initializers will be used during + // graph optimization which will happen on CPU. + OrtAllocator* allocator = nullptr; + CHECK_STATUS(ort_api->GetAllocatorWithDefaultOptions(&allocator)); + CHECK(allocator); + + ScopedOrtValue initializer; + CHECK_STATUS(ort_api->CreateTensorAsOrtValue( + allocator, shape.data(), shape.size(), data_type, + ScopedOrtValue::Receiver(initializer).get())); + + void* mutable_data = nullptr; + CHECK_STATUS(ort_api->GetTensorMutableData(initializer.get(), &mutable_data)); + // `mutable_data` can be nullptr when there is zero dimension in `shape` + // a.k.a. empty tensors. While WebNN doesn't support zero dimensions the ORT + // backend may need this feature in some cases, e.g., the ONNX Reshape op's + // "new shape" can be an empty tensor when reshaping the input tensor to a + // scalar. + + // SAFETY: `mutable_data` was created to hold a tensor of `shape` and + // `data_type`. + UNSAFE_BUFFERS(base::span(static_cast<uint8_t*>(mutable_data), + CalculateOrtTensorSizeInBytes(shape, data_type))) + .copy_from(data); + + const OrtModelEditorApi* ort_model_editor_api = GetOrtModelEditorApi(); + // Graph will own the initializer. + CHECK_STATUS(ort_model_editor_api->AddInitializerToGraph( + graph_.get(), name.c_str(), initializer.release(), + /*data_is_external=*/false)); +} + +void ModelEditor::AddInitializerAsExternalData( + base::cstring_view name, + ONNXTensorElementDataType data_type, + base::span<const int64_t> shape, + base::span<const uint8_t> data) { + // The data will not be copied into the graph, so it must be stored outside. + auto weight = base::HeapArray<uint8_t>::CopiedFrom(data); + model_info_->external_data.push_back(std::move(weight)); + + CHECK_EQ(data.size(), CalculateOrtTensorSizeInBytes(shape, data_type)); + + const OrtApi* ort_api = GetOrtApi(); + ScopedOrtValue initializer; + // TODO(crbug.com/411465403): Use `CreateTensorWithDataAndDeleterAsOrtValue()` + // to let ORT take the ownership of the tensor and free it when no longer in + // use. + CHECK_STATUS(ort_api->CreateTensorWithDataAsOrtValue( + memory_info_.get(), model_info_->external_data.back().data(), + model_info_->external_data.back().size(), shape.data(), shape.size(), + data_type, ScopedOrtValue::Receiver(initializer).get())); + + const OrtModelEditorApi* ort_model_editor_api = GetOrtModelEditorApi(); + // Graph will own the initializer. + CHECK_STATUS(ort_model_editor_api->AddInitializerToGraph( + graph_.get(), name.c_str(), initializer.release(), + /*data_is_external=*/true)); +} + +ScopedOrtOpAttr ModelEditor::CreateAttribute(base::cstring_view name, + OrtOpAttrData data) { + CHECK(!has_built_); + + const OrtApi* ort_api = GetOrtApi(); + ScopedOrtOpAttr attribute; + std::visit(base::Overloaded{ + [&](int64_t int_data) { + CHECK_STATUS(ort_api->CreateOpAttr( + name.c_str(), &int_data, + /*len=*/1, OrtOpAttrType::ORT_OP_ATTR_INT, + ScopedOrtOpAttr::Receiver(attribute).get())); + }, + [&](float float_data) { + CHECK_STATUS(ort_api->CreateOpAttr( + name.c_str(), &float_data, + /*len=*/1, OrtOpAttrType::ORT_OP_ATTR_FLOAT, + ScopedOrtOpAttr::Receiver(attribute).get())); + }, + [&](base::cstring_view string_data) { + CHECK_STATUS(ort_api->CreateOpAttr( + name.c_str(), string_data.data(), string_data.size(), + OrtOpAttrType::ORT_OP_ATTR_STRING, + ScopedOrtOpAttr::Receiver(attribute).get())); + }, + [&](base::span<const int64_t> ints_data) { + CHECK_STATUS(ort_api->CreateOpAttr( + name.c_str(), ints_data.data(), ints_data.size(), + OrtOpAttrType::ORT_OP_ATTR_INTS, + ScopedOrtOpAttr::Receiver(attribute).get())); + }, + [&](base::span<const float> floats_data) { + CHECK_STATUS(ort_api->CreateOpAttr( + name.c_str(), floats_data.data(), floats_data.size(), + OrtOpAttrType::ORT_OP_ATTR_FLOATS, + ScopedOrtOpAttr::Receiver(attribute).get())); + }, + [&](base::span<const char*> strings_data) { + CHECK_STATUS(ort_api->CreateOpAttr( + name.c_str(), strings_data.data(), strings_data.size(), + OrtOpAttrType::ORT_OP_ATTR_STRINGS, + ScopedOrtOpAttr::Receiver(attribute).get())); + }}, + data); + + return attribute; +} + +void ModelEditor::AddNode(base::cstring_view op_type, + base::cstring_view node_name, + base::span<const char*> inputs, + base::span<const char*> outputs, + base::span<ScopedOrtOpAttr> attributes) { + CHECK(!has_built_); + + base::FixedArray<OrtOpAttr*> node_attrs(attributes.size()); + std::ranges::transform(attributes, node_attrs.begin(), + [](auto& attr) { return attr.release(); }); + + const OrtModelEditorApi* ort_model_editor_api = GetOrtModelEditorApi(); + // Node will own the attributes. + ScopedOrtNode node; + CHECK_STATUS(ort_model_editor_api->CreateNode( + op_type.c_str(), kOrtDefaultDomain, node_name.c_str(), inputs.data(), + inputs.size(), outputs.data(), outputs.size(), node_attrs.data(), + node_attrs.size(), ScopedOrtNode::Receiver(node).get())); + // Graph will own the node. + CHECK_STATUS( + ort_model_editor_api->AddNodeToGraph(graph_.get(), node.release())); +} + +std::unique_ptr<ModelEditor::ModelInfo> ModelEditor::BuildAndTakeModelInfo() { + CHECK(!has_built_); + + const OrtModelEditorApi* ort_model_editor_api = GetOrtModelEditorApi(); + // Graph will own the inputs and outputs. + base::FixedArray<OrtValueInfo*> graph_inputs(inputs_.size()); + std::ranges::transform(inputs_, graph_inputs.begin(), + [](auto& input) { return input.release(); }); + CHECK_STATUS(ort_model_editor_api->SetGraphInputs( + graph_.get(), graph_inputs.data(), graph_inputs.size())); + + base::FixedArray<OrtValueInfo*> graph_outputs(outputs_.size()); + std::ranges::transform(outputs_, graph_outputs.begin(), + [](auto& output) { return output.release(); }); + CHECK_STATUS(ort_model_editor_api->SetGraphOutputs( + graph_.get(), graph_outputs.data(), graph_outputs.size())); + + std::array<const char*, 2> domains = {kOrtDefaultDomain, kMSDomain}; + std::array<int32_t, 2> opset_versions = {kOrtOpsetVersion, + kEPContextOpsetVersion}; + CHECK_STATUS(ort_model_editor_api->CreateModel( + domains.data(), opset_versions.data(), domains.size(), + ScopedOrtModel::Receiver(model_info_->model).get())); + + // Model will own the graph. + CHECK_STATUS(ort_model_editor_api->AddGraphToModel(model_info_->model.get(), + graph_.release())); + + has_built_ = true; + + return std::move(model_info_); +} + +} // namespace webnn::ort
diff --git a/services/webnn/ort/model_editor.h b/services/webnn/ort/model_editor.h new file mode 100644 index 0000000..7c8016f --- /dev/null +++ b/services/webnn/ort/model_editor.h
@@ -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. + +#ifndef SERVICES_WEBNN_ORT_MODEL_EDITOR_H_ +#define SERVICES_WEBNN_ORT_MODEL_EDITOR_H_ + +#include <memory> +#include <variant> +#include <vector> + +#include "base/component_export.h" +#include "base/containers/heap_array.h" +#include "base/containers/span.h" +#include "base/strings/cstring_view.h" +#include "services/webnn/ort/scoped_ort_types.h" +#include "services/webnn/public/cpp/operand_descriptor.h" +#include "services/webnn/webnn_constant_operand.h" + +namespace webnn::ort { + +class COMPONENT_EXPORT(WEBNN_SERVICE) ModelEditor { + public: + struct COMPONENT_EXPORT(WEBNN_SERVICE) ModelInfo { + ModelInfo(); + ModelInfo(const ModelInfo&) = delete; + ModelInfo& operator=(const ModelInfo&) = delete; + ~ModelInfo(); + + ScopedOrtModel model; + // The external data should be kept alive during graph inferencing. + std::vector<base::HeapArray<uint8_t>> external_data; + }; + + ModelEditor(); + ~ModelEditor(); + ModelEditor(const ModelEditor&) = delete; + ModelEditor& operator=(const ModelEditor&) = delete; + + void AddInput(base::cstring_view name, const OperandDescriptor& descriptor); + + void AddOutput(base::cstring_view name, const OperandDescriptor& descriptor); + + void AddInitializer(base::cstring_view name, + const WebNNConstantOperand& constant_operand); + + // Add an initializer directly into the ONNX model. + // This method could be useful for converting a WebNN operator's attribute to + // an ONNX model initializer. For example, the reshape operator's new shape is + // a tensor/initializer input in ONNX spec. + void AddInitializer(base::cstring_view name, + ONNXTensorElementDataType data_type, + base::span<const int64_t> shape, + base::span<const uint8_t> data); + + using OrtOpAttrData = std::variant<int64_t, + float, + base::cstring_view, + base::span<const int64_t>, + base::span<const float>, + base::span<const char*>>; + ScopedOrtOpAttr CreateAttribute(base::cstring_view name, OrtOpAttrData data); + + // The ownership of `attributes` will be transferred and should not be used + // after this call. + void AddNode(base::cstring_view op_type, + base::cstring_view node_name, + base::span<const char*> inputs, + base::span<const char*> outputs, + base::span<ScopedOrtOpAttr> attributes = {}); + + // No further methods should be called on this class after calling this + // method. + std::unique_ptr<ModelInfo> BuildAndTakeModelInfo(); + + private: + // Add an initializer and copy the data into the graph. + void AddInitializerAsRawData(base::cstring_view name, + ONNXTensorElementDataType data_type, + base::span<const int64_t> shape, + base::span<const uint8_t> data); + + // Add an initializer and copy the data into `ModelInfo::external_data`. + // TODO(crbug.com/411452041): Consider transferring the constant data instead + // of copying. + void AddInitializerAsExternalData(base::cstring_view name, + ONNXTensorElementDataType data_type, + base::span<const int64_t> shape, + base::span<const uint8_t> data); + + // Describes where the constant buffer resides in memory. + ScopedOrtMemoryInfo memory_info_; + + std::vector<ScopedOrtValueInfo> inputs_; + std::vector<ScopedOrtValueInfo> outputs_; + + ScopedOrtGraph graph_; + + std::unique_ptr<ModelInfo> model_info_; + + bool has_built_ = false; +}; + +} // namespace webnn::ort + +#endif // SERVICES_WEBNN_ORT_MODEL_EDITOR_H_
diff --git a/services/webnn/ort/model_editor_test.cc b/services/webnn/ort/model_editor_test.cc new file mode 100644 index 0000000..48a3c89 --- /dev/null +++ b/services/webnn/ort/model_editor_test.cc
@@ -0,0 +1,136 @@ +// 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/webnn/ort/model_editor.h" + +#include <array> +#include <memory> +#include <vector> + +#include "base/containers/heap_array.h" +#include "base/strings/cstring_view.h" +#include "services/webnn/ort/scoped_ort_types.h" +#include "services/webnn/ort/test_base_ort.h" +#include "services/webnn/public/cpp/operand_descriptor.h" +#include "services/webnn/webnn_constant_operand.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace webnn::ort { + +class WebNNOrtModelEditorTest : public TestBaseOrt {}; + +TEST_F(WebNNOrtModelEditorTest, AddAndGather) { + ModelEditor model_editor; + + // Add an input. + constexpr base::cstring_view input = "input"; + auto input_desc = OperandDescriptor::CreateForDeserialization( + OperandDataType::kUint32, {4, 2, 4}); + ASSERT_TRUE(input_desc.has_value()); + model_editor.AddInput(input, input_desc.value()); + + // Add two initializers. + constexpr base::cstring_view add_initializer = "add_initializer"; + std::array<uint32_t, 32> add_initializer_data; // 128 bytes + add_initializer_data.fill(1); + auto add_initializer_desc = OperandDescriptor::CreateForDeserialization( + OperandDataType::kUint32, {4, 2, 4}); + ASSERT_TRUE(add_initializer_desc.has_value()); + WebNNConstantOperand add_initializer_operand( + std::move(add_initializer_desc.value()), + base::HeapArray<uint8_t>::CopiedFrom( + base::as_byte_span(add_initializer_data))); + model_editor.AddInitializer(add_initializer, add_initializer_operand); + + constexpr base::cstring_view gather_indices_initializer = + "gather_indices_initializer"; + std::array<int64_t, 4> gather_indices_initializer_data = {0, 1, 0, + 1}; // 32 bytes + auto gather_indices_initializer_desc = + OperandDescriptor::CreateForDeserialization(OperandDataType::kInt64, {4}); + ASSERT_TRUE(gather_indices_initializer_desc.has_value()); + WebNNConstantOperand gather_indices_initializer_operand( + std::move(gather_indices_initializer_desc.value()), + base::HeapArray<uint8_t>::CopiedFrom( + base::as_byte_span(gather_indices_initializer_data))); + model_editor.AddInitializer(gather_indices_initializer, + gather_indices_initializer_operand); + + // Add Add node. + constexpr base::cstring_view add_output = "add_output"; + std::array<const char*, 2> add_inputs = {input.c_str(), + add_initializer.c_str()}; + std::array<const char*, 1> add_outputs = {add_output.c_str()}; + model_editor.AddNode( + /*op_type=*/"Add", /*node_name=*/"add", add_inputs, add_outputs); + + // Add Gather node. + int64_t axis = 1; + std::array<ScopedOrtOpAttr, 1> gather_attrs = { + model_editor.CreateAttribute(/*name=*/"axis", axis)}; + + constexpr base::cstring_view output = "output"; + std::array<const char*, 2> gather_inputs = { + add_output.c_str(), gather_indices_initializer.c_str()}; + std::array<const char*, 1> gather_outputs = {output.c_str()}; + model_editor.AddNode( + /*op_type=*/"Gather", /*node_name=*/"gather", gather_inputs, + gather_outputs, gather_attrs); + + // Add an output. + model_editor.AddOutput(output, OperandDescriptor::CreateForDeserialization( + OperandDataType::kUint32, {4, 4, 4}) + .value()); + + std::unique_ptr<ModelEditor::ModelInfo> model_info = + model_editor.BuildAndTakeModelInfo(); + ASSERT_NE(model_info, nullptr); + + // `add_initializer` data should be saved into `external_data` since it + // reaches `kMinExternalDataSize`. + EXPECT_EQ(model_info->external_data.size(), 1u); + EXPECT_TRUE(model_info->model.is_valid()); +} + +TEST_F(WebNNOrtModelEditorTest, ReshapeToScalar) { + ModelEditor model_editor; + + // Add an input. + constexpr base::cstring_view input = "input"; + auto input_desc = OperandDescriptor::CreateForDeserialization( + OperandDataType::kInt32, {1, 1, 1, 1}); + ASSERT_TRUE(input_desc.has_value()); + model_editor.AddInput(input, input_desc.value()); + + // Add an initializer which is an empty tensor that represents an empty shape + // of a scalar. + constexpr base::cstring_view new_shape_initializer = "new_shape_initializer"; + model_editor.AddInitializer(new_shape_initializer, + ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32, + /*shape=*/{0}, /*data=*/{}); + + // Add Reshape node. + constexpr base::cstring_view output = "output"; + std::array<const char*, 2> reshape_inputs = {input.c_str(), + new_shape_initializer.c_str()}; + std::array<const char*, 1> reshape_outputs = {output.c_str()}; + model_editor.AddNode( + /*op_type=*/"Reshape", /*node_name=*/"reshape", reshape_inputs, + reshape_outputs); + + // Add an output. + auto output_desc = + OperandDescriptor::CreateForDeserialization(OperandDataType::kInt32, {}); + ASSERT_TRUE(output_desc.has_value()); + model_editor.AddOutput(output, output_desc.value()); + + std::unique_ptr<ModelEditor::ModelInfo> model_info = + model_editor.BuildAndTakeModelInfo(); + ASSERT_NE(model_info, nullptr); + + EXPECT_EQ(model_info->external_data.size(), 0u); + EXPECT_TRUE(model_info->model.is_valid()); +} + +} // namespace webnn::ort
diff --git a/services/webnn/ort/ort_data_type.cc b/services/webnn/ort/ort_data_type.cc new file mode 100644 index 0000000..238b705c --- /dev/null +++ b/services/webnn/ort/ort_data_type.cc
@@ -0,0 +1,34 @@ +// 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/webnn/ort/ort_data_type.h" + +namespace webnn::ort { + +ONNXTensorElementDataType WebnnToOnnxDataType(OperandDataType data_type) { + switch (data_type) { + case OperandDataType::kFloat32: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT; + case OperandDataType::kFloat16: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16; + case OperandDataType::kInt32: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32; + case OperandDataType::kUint32: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32; + case OperandDataType::kInt64: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64; + case OperandDataType::kUint64: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64; + case OperandDataType::kInt8: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8; + case OperandDataType::kUint8: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8; + case OperandDataType::kInt4: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_INT4; + case OperandDataType::kUint4: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT4; + } +} + +} // namespace webnn::ort
diff --git a/services/webnn/ort/ort_data_type.h b/services/webnn/ort/ort_data_type.h new file mode 100644 index 0000000..3946df89 --- /dev/null +++ b/services/webnn/ort/ort_data_type.h
@@ -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. + +#ifndef SERVICES_WEBNN_ORT_ORT_DATA_TYPE_H_ +#define SERVICES_WEBNN_ORT_ORT_DATA_TYPE_H_ + +#include "services/webnn/public/cpp/operand_descriptor.h" +#include "third_party/onnxruntime_headers/src/include/onnxruntime/core/session/onnxruntime_c_api.h" + +namespace webnn::ort { + +ONNXTensorElementDataType WebnnToOnnxDataType(OperandDataType data_type); + +} // namespace webnn::ort + +#endif // SERVICES_WEBNN_ORT_ORT_DATA_TYPE_H_
diff --git a/services/webnn/ort/ort_status.cc b/services/webnn/ort/ort_status.cc new file mode 100644 index 0000000..2182761 --- /dev/null +++ b/services/webnn/ort/ort_status.cc
@@ -0,0 +1,30 @@ +// 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/webnn/ort/ort_status.h" + +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" +#include "services/webnn/ort/platform_functions_ort.h" +#include "third_party/onnxruntime_headers/src/include/onnxruntime/core/session/onnxruntime_c_api.h" + +namespace webnn::ort { + +namespace internal { + +std::string OrtStatusFatalMessage(OrtStatus* status) { + CHECK(status); + + constexpr char kOrtErrorCode[] = "[WebNN] ORT status error code: "; + constexpr char kOrtErrorMessage[] = " error message: "; + const OrtApi* ort_api = PlatformFunctions::GetInstance()->ort_api(); + return base::StrCat( + {kOrtErrorCode, + base::NumberToString(static_cast<int>(ort_api->GetErrorCode(status))), + kOrtErrorMessage, ort_api->GetErrorMessage(status)}); +} + +} // namespace internal + +} // namespace webnn::ort
diff --git a/services/webnn/ort/ort_status.h b/services/webnn/ort/ort_status.h new file mode 100644 index 0000000..ce27817 --- /dev/null +++ b/services/webnn/ort/ort_status.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 SERVICES_WEBNN_ORT_ORT_STATUS_H_ +#define SERVICES_WEBNN_ORT_ORT_STATUS_H_ + +#include <string> + +#include "base/logging.h" + +struct OrtStatus; + +namespace webnn::ort { + +namespace internal { + +std::string OrtStatusFatalMessage(OrtStatus* status); + +} // namespace internal + +#define CHECK_STATUS(expr) \ + if (OrtStatus* status = (expr)) { \ + LOG(FATAL) << internal::OrtStatusFatalMessage(status); \ + } + +} // namespace webnn::ort + +#endif // SERVICES_WEBNN_ORT_ORT_STATUS_H_
diff --git a/services/webnn/ort/platform_functions_ort_test.cc b/services/webnn/ort/platform_functions_ort_test.cc index 9dff93e6..4fa4004 100644 --- a/services/webnn/ort/platform_functions_ort_test.cc +++ b/services/webnn/ort/platform_functions_ort_test.cc
@@ -9,18 +9,7 @@ namespace webnn::ort { -class WebNNOrtPlatformFunctionsTest : public testing::Test { - public: - void SetUp() override; -}; - -void WebNNOrtPlatformFunctionsTest::SetUp() { - // Skip tests if the loading platform functions fail. - // In order to be able to run this test suite successfully, the developer - // needs to place a copy of onnxruntime.dll which supports ORT_API_VERSION - // defined in onnxruntime_c_api.h into Chromium module folder before. - SKIP_TEST_IF(!PlatformFunctions::GetInstance()); -} +class WebNNOrtPlatformFunctionsTest : public TestBaseOrt {}; TEST_F(WebNNOrtPlatformFunctionsTest, AllFunctionsLoaded) { PlatformFunctions* platformFunctions = PlatformFunctions::GetInstance();
diff --git a/services/webnn/ort/scoped_ort_types.h b/services/webnn/ort/scoped_ort_types.h new file mode 100644 index 0000000..3b75221b --- /dev/null +++ b/services/webnn/ort/scoped_ort_types.h
@@ -0,0 +1,111 @@ +// 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_WEBNN_ORT_SCOPED_ORT_TYPES_H_ +#define SERVICES_WEBNN_ORT_SCOPED_ORT_TYPES_H_ + +#include <type_traits> + +#include "base/scoped_generic.h" +#include "services/webnn/ort/platform_functions_ort.h" +#include "third_party/onnxruntime_headers/src/include/onnxruntime/core/session/onnxruntime_c_api.h" + +namespace webnn::ort { + +namespace internal { + +template <typename T> + requires std::is_pointer<T>::value +struct ScopedOrtTypeTraitsHelper; + +template <typename T> + requires std::is_pointer<T>::value +struct ScopedOrtTypeTraits { + static T InvalidValue() { return nullptr; } + static void Free(T value) { ScopedOrtTypeTraitsHelper<T>::Free(value); } +}; + +template <> +struct ScopedOrtTypeTraitsHelper<OrtValue*> { + static void Free(OrtValue* value) { + PlatformFunctions::GetInstance()->ort_api()->ReleaseValue(value); + } +}; + +template <> +struct ScopedOrtTypeTraitsHelper<OrtMemoryInfo*> { + static void Free(OrtMemoryInfo* value) { + PlatformFunctions::GetInstance()->ort_api()->ReleaseMemoryInfo(value); + } +}; + +template <> +struct ScopedOrtTypeTraitsHelper<OrtOpAttr*> { + static void Free(OrtOpAttr* value) { + PlatformFunctions::GetInstance()->ort_api()->ReleaseOpAttr(value); + } +}; + +template <> +struct ScopedOrtTypeTraitsHelper<OrtTypeInfo*> { + static void Free(OrtTypeInfo* value) { + PlatformFunctions::GetInstance()->ort_api()->ReleaseTypeInfo(value); + } +}; + +template <> +struct ScopedOrtTypeTraitsHelper<OrtTensorTypeAndShapeInfo*> { + static void Free(OrtTensorTypeAndShapeInfo* value) { + PlatformFunctions::GetInstance()->ort_api()->ReleaseTensorTypeAndShapeInfo( + value); + } +}; + +template <> +struct ScopedOrtTypeTraitsHelper<OrtValueInfo*> { + static void Free(OrtValueInfo* value) { + PlatformFunctions::GetInstance()->ort_api()->ReleaseValueInfo(value); + } +}; + +template <> +struct ScopedOrtTypeTraitsHelper<OrtNode*> { + static void Free(OrtNode* value) { + PlatformFunctions::GetInstance()->ort_api()->ReleaseNode(value); + } +}; + +template <> +struct ScopedOrtTypeTraitsHelper<OrtGraph*> { + static void Free(OrtGraph* value) { + PlatformFunctions::GetInstance()->ort_api()->ReleaseGraph(value); + } +}; + +template <> +struct ScopedOrtTypeTraitsHelper<OrtModel*> { + static void Free(OrtModel* value) { + PlatformFunctions::GetInstance()->ort_api()->ReleaseModel(value); + } +}; + +template <typename T> +using ScopedOrtType = base::ScopedGeneric<T*, ScopedOrtTypeTraits<T*>>; + +} // namespace internal + +using ScopedOrtValue = internal::ScopedOrtType<OrtValue>; +using ScopedOrtMemoryInfo = internal::ScopedOrtType<OrtMemoryInfo>; +using ScopedOrtOpAttr = internal::ScopedOrtType<OrtOpAttr>; +using ScopedOrtTypeInfo = internal::ScopedOrtType<OrtTypeInfo>; +using ScopedOrtTensorTypeAndShapeInfo = + internal::ScopedOrtType<OrtTensorTypeAndShapeInfo>; +using ScopedOrtValueInfo = internal::ScopedOrtType<OrtValueInfo>; +using ScopedOrtNode = internal::ScopedOrtType<OrtNode>; +using ScopedOrtGraph = internal::ScopedOrtType<OrtGraph>; +using ScopedOrtModel = internal::ScopedOrtType<OrtModel>; + +} // namespace webnn::ort + +#endif // SERVICES_WEBNN_ORT_SCOPED_ORT_TYPES_H_
diff --git a/services/webnn/ort/test_base_ort.cc b/services/webnn/ort/test_base_ort.cc new file mode 100644 index 0000000..5fa6276 --- /dev/null +++ b/services/webnn/ort/test_base_ort.cc
@@ -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. + +#include "services/webnn/ort/test_base_ort.h" + +#include "services/webnn/ort/platform_functions_ort.h" + +namespace webnn::ort { + +void TestBaseOrt::SetUp() { + // Skip tests if the loading platform functions fail. + // In order to be able to run this test suite successfully, the developer + // needs to place a copy of onnxruntime.dll which supports ORT_API_VERSION + // defined in onnxruntime_c_api.h into Chromium module folder before. + if (!PlatformFunctions::GetInstance()) { + GTEST_SKIP() << "!PlatformFunctions::GetInstance()"; + } +} + +} // namespace webnn::ort
diff --git a/services/webnn/ort/test_base_ort.h b/services/webnn/ort/test_base_ort.h index 854d64af..6adcabe1 100644 --- a/services/webnn/ort/test_base_ort.h +++ b/services/webnn/ort/test_base_ort.h
@@ -7,11 +7,13 @@ #include "testing/gtest/include/gtest/gtest.h" -// GTEST_SKIP() will let method return directly. -#define SKIP_TEST_IF(condition) \ - do { \ - if (condition) \ - GTEST_SKIP() << #condition; \ - } while (0) +namespace webnn::ort { + +class TestBaseOrt : public testing::Test { + public: + void SetUp() override; +}; + +} // namespace webnn::ort #endif // SERVICES_WEBNN_ORT_TEST_BASE_ORT_H_
diff --git a/services/webnn/public/cpp/webnn_trace_unittest.cc b/services/webnn/public/cpp/webnn_trace_unittest.cc index b7250ae..b77bf63 100644 --- a/services/webnn/public/cpp/webnn_trace_unittest.cc +++ b/services/webnn/public/cpp/webnn_trace_unittest.cc
@@ -20,6 +20,7 @@ #include "base/trace_event/trace_event.h" #include "base/trace_event/trace_log.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/container/flat_hash_map.h" namespace webnn { @@ -59,8 +60,8 @@ // End tracing, return tracing data in a map of event // name->(begin_event_counts, end_event_counts) - std::map<std::string, std::pair<int, int>> EndTracing() { - std::map<std::string, std::pair<int, int>> event_counts; + absl::flat_hash_map<std::string, std::pair<int, int>> EndTracing() { + absl::flat_hash_map<std::string, std::pair<int, int>> event_counts; base::trace_event::TraceResultBuffer::SimpleOutput json_data; base::trace_event::TraceLog::GetInstance()->SetDisabled(); base::RunLoop run_loop;
diff --git a/services/webnn/tflite/graph_builder_tflite.h b/services/webnn/tflite/graph_builder_tflite.h index bf39351..f986301 100644 --- a/services/webnn/tflite/graph_builder_tflite.h +++ b/services/webnn/tflite/graph_builder_tflite.h
@@ -24,6 +24,7 @@ #include "services/webnn/public/cpp/webnn_types.h" #include "services/webnn/public/mojom/webnn_context_provider.mojom-forward.h" #include "services/webnn/public/mojom/webnn_graph.mojom-forward.h" +#include "third_party/abseil-cpp/absl/container/flat_hash_map.h" #include "third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h" #include "third_party/tflite/src/tensorflow/compiler/mlir/lite/schema/schema_generated.h" @@ -825,7 +826,7 @@ // | Relu // [output] | // [output] - std::map<OperandId, TensorInfo> operand_to_tensor_info_map_; + absl::flat_hash_map<OperandId, TensorInfo> operand_to_tensor_info_map_; // The following std::vector<Offset<tflite:XXX>>> stores the weights of model // and the tensor information (shape, data type).
diff --git a/services/webnn/webnn_context_provider_impl.cc b/services/webnn/webnn_context_provider_impl.cc index fe7c12b..a3b30e81 100644 --- a/services/webnn/webnn_context_provider_impl.cc +++ b/services/webnn/webnn_context_provider_impl.cc
@@ -98,7 +98,8 @@ } // static -void WebNNContextProviderImpl::CreateForTesting( +base::optional_ref<WebNNContextProviderImpl> +WebNNContextProviderImpl::CreateForTesting( mojo::PendingReceiver<mojom::WebNNContextProvider> receiver, WebNNStatus status, LoseAllContextsCallback lose_all_contexts_callback) { @@ -123,11 +124,14 @@ DISABLE_WEBNN_FOR_NPU); } - mojo::MakeSelfOwnedReceiver<WebNNContextProvider>( - base::WrapUnique(new WebNNContextProviderImpl( - /*shared_context_state=*/nullptr, std::move(gpu_feature_info), - std::move(gpu_info), std::move(lose_all_contexts_callback))), - std::move(receiver)); + // Cast is safe because only a WebNNContextProviderImpl can be created. + return static_cast<WebNNContextProviderImpl*>( + mojo::MakeSelfOwnedReceiver<WebNNContextProvider>( + base::WrapUnique(new WebNNContextProviderImpl( + /*shared_context_state=*/nullptr, std::move(gpu_feature_info), + std::move(gpu_info), std::move(lose_all_contexts_callback))), + std::move(receiver)) + ->impl()); } void WebNNContextProviderImpl::OnConnectionError(WebNNContextImpl* impl) { @@ -220,4 +224,16 @@ mojom::CreateContextResult::NewSuccess(std::move(success))); } +base::optional_ref<WebNNContextImpl> +WebNNContextProviderImpl::GetWebNNContextImplForTesting( + const blink::WebNNContextToken& handle) { + CHECK_IS_TEST(); + const auto it = impls_.find(handle); + if (it == impls_.end()) { + mojo::ReportBadMessage(kBadMessageInvalidContext); + return std::nullopt; + } + return it->get(); +} + } // namespace webnn
diff --git a/services/webnn/webnn_context_provider_impl.h b/services/webnn/webnn_context_provider_impl.h index 3c1d4fd9..492404f 100644 --- a/services/webnn/webnn_context_provider_impl.h +++ b/services/webnn/webnn_context_provider_impl.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/component_export.h" +#include "base/types/optional_ref.h" #include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/config/gpu_feature_info.h" #include "gpu/config/gpu_info.h" @@ -54,7 +55,10 @@ kWebNNEnabled = 3, }; - static void CreateForTesting( + // Called to create a WebNNContextProviderImpl as a self-owned receiver. + // Optionally returns a reference to the WebNNContextProviderImpl to test + // interop. + static base::optional_ref<WebNNContextProviderImpl> CreateForTesting( mojo::PendingReceiver<mojom::WebNNContextProvider> receiver, WebNNStatus status = WebNNStatus::kWebNNEnabled, LoseAllContextsCallback lose_all_contexts_callback = base::BindOnce([]() { @@ -69,6 +73,12 @@ // process to destroy all contexts. void DestroyContextsAndKillGpuProcess(std::string_view reason); #endif // BUILDFLAG(IS_WIN) + + // Retrieves a `WebNNContextImpl` instance created from this provider. + // Emits a bad message if a context with the given handle does not exist. + base::optional_ref<WebNNContextImpl> GetWebNNContextImplForTesting( + const blink::WebNNContextToken& handle); + using WebNNContextImplSet = base::flat_set< std::unique_ptr<WebNNContextImpl>, WebNNObjectImpl<blink::WebNNContextToken>::Comparator<WebNNContextImpl>>;
diff --git a/services/webnn/webnn_tensor_impl_backend_test.cc b/services/webnn/webnn_tensor_impl_backend_test.cc index dbc07d3..871fb39 100644 --- a/services/webnn/webnn_tensor_impl_backend_test.cc +++ b/services/webnn/webnn_tensor_impl_backend_test.cc
@@ -23,12 +23,18 @@ #include "services/webnn/public/mojom/webnn_context.mojom.h" #include "services/webnn/public/mojom/webnn_context_provider.mojom.h" #include "services/webnn/public/mojom/webnn_tensor.mojom.h" +#include "services/webnn/webnn_context_impl.h" #include "services/webnn/webnn_context_provider_impl.h" +#include "services/webnn/webnn_tensor_impl.h" #include "testing/gtest/include/gtest/gtest.h" #if BUILDFLAG(IS_WIN) #include "services/webnn/dml/adapter.h" +#include "services/webnn/dml/command_queue.h" +#include "services/webnn/dml/command_recorder.h" +#include "services/webnn/dml/tensor_impl_dml.h" #include "services/webnn/dml/test_base.h" +#include "services/webnn/dml/utils.h" #endif // BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_MAC) @@ -89,6 +95,7 @@ base::test::ScopedFeatureList scoped_feature_list_; scoped_refptr<dml::Adapter> adapter_; + raw_ptr<WebNNContextProviderImpl, DanglingUntriaged> provider_impl_ = nullptr; mojo::Remote<mojom::WebNNContextProvider> webnn_provider_remote_; }; @@ -105,9 +112,12 @@ // DirectML version 1.2 or DML_FEATURE_LEVEL_2_1, so skip the tests if the // DirectML version doesn't support this feature. SKIP_TEST_IF(!adapter_->IsDMLDeviceCompileGraphSupportedForTesting()); - - WebNNContextProviderImpl::CreateForTesting( - webnn_provider_remote_.BindNewPipeAndPassReceiver()); + // Testing WebGpuInterop usage relies on the WebNNContextProvider + // interface implementation in order to lookup WebNNTensorImpls from + // non-WebNNContextProviderImpls. + provider_impl_ = WebNNContextProviderImpl::CreateForTesting( + webnn_provider_remote_.BindNewPipeAndPassReceiver()) + .as_ptr(); } #elif BUILDFLAG(IS_MAC) class WebNNTensorImplBackendTest : public testing::Test { @@ -424,6 +434,392 @@ EXPECT_FALSE(bad_message_helper.GetLastBadMessage().has_value()); } +// Testing for WebGPUInterop requires backend-specific APIs to +// synchronize contents and simulate usage from another command queue. +#if BUILDFLAG(IS_WIN) + +class WebNNTensorImplDmlBackendTest : public WebNNTensorImplBackendTest { + public: + void SetUp() override { + WebNNTensorImplBackendTest::SetUp(); + + if (!webnn_provider_remote_.is_bound()) { + GTEST_SKIP() << "WebNN not supported on this platform."; + } + + base::expected<CreateContextSuccess, webnn::mojom::Error::Code> + context_result = CreateWebNNContext(); + if (!context_result.has_value() && + context_result.error() == mojom::Error::Code::kNotSupportedError) { + GTEST_SKIP() << "WebNN not supported on this platform."; + } else { + webnn_context_remote_ = + std::move(context_result.value().webnn_context_remote); + webnn_context_handle_ = + std::move(context_result.value().webnn_context_handle); + } + + ASSERT_TRUE(webnn_context_remote_.is_bound()); + } + + base::WeakPtr<native::d3d12::WebNNTensor> GetWebNNTensor( + const blink::WebNNTensorToken& webnn_tensor_handle) const { + base::optional_ref<WebNNContextImpl> context_impl = + provider_impl_->GetWebNNContextImplForTesting(webnn_context_handle_); + return static_cast<dml::TensorImplDml*>( + context_impl->GetWebNNTensorImpl(webnn_tensor_handle).as_ptr()) + ->AsWeakPtr(); + } + + protected: + mojo::Remote<mojom::WebNNContext> webnn_context_remote_; + blink::WebNNContextToken webnn_context_handle_; +}; + +void WriteTensorData(base::span<const uint8_t> src_data, + ID3D12Resource* dst_buffer) { + void* mapped_upload_data = nullptr; + ASSERT_HRESULT_SUCCEEDED(dst_buffer->Map(0, nullptr, &mapped_upload_data)); + // SAFETY: `dst_buffer` was constructed with size `src_data.size()`. + UNSAFE_BUFFERS( + base::span(static_cast<uint8_t*>(mapped_upload_data), src_data.size())) + .copy_from(src_data); + dst_buffer->Unmap(0, nullptr); +} + +bool IsFenceCompleted(ID3D12Fence* fence, uint64_t fence_value) { + return fence->GetCompletedValue() >= fence_value; +} + +// Verify calling end access twice outputs the same fence and resource. +TEST_F(WebNNTensorImplDmlBackendTest, EndAccessWebNNTwiceTest) { + BadMessageTestHelper bad_message_helper; + + mojo::AssociatedRemote<mojom::WebNNTensor> webnn_tensor_remote; + blink::WebNNTensorToken webnn_tensor_handle; + base::expected<CreateTensorSuccess, webnn::mojom::Error::Code> + create_tensor_result = CreateWebNNTensor( + webnn_context_remote_, + mojom::TensorInfo::New( + OperandDescriptor::UnsafeCreateForTesting( + OperandDataType::kUint8, std::array<uint32_t, 2>{2, 2}), + MLTensorUsage{MLTensorUsageFlags::kWebGpuInterop})); + if (create_tensor_result.has_value()) { + webnn_tensor_remote = + std::move(create_tensor_result.value().webnn_tensor_remote); + webnn_tensor_handle = + std::move(create_tensor_result.value().webnn_tensor_handle); + } + + ASSERT_TRUE(webnn_tensor_remote.is_bound()); + + webnn_context_remote_.FlushForTesting(); + + base::WeakPtr<native::d3d12::WebNNTensor> webnn_tensor = + GetWebNNTensor(webnn_tensor_handle); + ASSERT_TRUE(webnn_tensor); + + std::unique_ptr<native::d3d12::WebNNSharedFence> webnn_fence_to_wait_for_1 = + webnn_tensor->EndAccessWebNN(); + ASSERT_TRUE(webnn_fence_to_wait_for_1); + + // Ensure nothing to wait for if no WebNN work prior to EndAccessWebNN(). + EXPECT_TRUE(IsFenceCompleted(webnn_fence_to_wait_for_1->GetD3D12Fence().Get(), + webnn_fence_to_wait_for_1->GetFenceValue())); + + EXPECT_TRUE(webnn_tensor->BeginAccessWebNN( + webnn_fence_to_wait_for_1->GetD3D12Fence(), + webnn_fence_to_wait_for_1->GetFenceValue())); + + std::unique_ptr<native::d3d12::WebNNSharedFence> webnn_fence_to_wait_for_2 = + webnn_tensor->EndAccessWebNN(); + ASSERT_TRUE(webnn_fence_to_wait_for_2); + + // End access again on the same tensor should return the same fence. + EXPECT_EQ(webnn_fence_to_wait_for_2->GetD3D12Fence().Get(), + webnn_fence_to_wait_for_1->GetD3D12Fence().Get()); + + EXPECT_FALSE(bad_message_helper.GetLastBadMessage().has_value()); +} + +// Verify tensor cannot be used before end access. +TEST_F(WebNNTensorImplDmlBackendTest, UsageAfterBeginAccessWebNNTest) { + BadMessageTestHelper bad_message_helper; + + mojo::AssociatedRemote<mojom::WebNNTensor> webnn_tensor_remote; + blink::WebNNTensorToken webnn_tensor_handle; + base::expected<CreateTensorSuccess, webnn::mojom::Error::Code> + create_tensor_result = CreateWebNNTensor( + webnn_context_remote_, + mojom::TensorInfo::New( + OperandDescriptor::UnsafeCreateForTesting( + OperandDataType::kUint8, std::array<uint32_t, 2>{2, 2}), + MLTensorUsage{MLTensorUsageFlags::kWebGpuInterop, + MLTensorUsageFlags::kWrite, + MLTensorUsageFlags::kRead})); + if (create_tensor_result.has_value()) { + webnn_tensor_remote = + std::move(create_tensor_result.value().webnn_tensor_remote); + webnn_tensor_handle = + std::move(create_tensor_result.value().webnn_tensor_handle); + } + + ASSERT_TRUE(webnn_tensor_remote.is_bound()); + + webnn_context_remote_.FlushForTesting(); + + base::WeakPtr<native::d3d12::WebNNTensor> webnn_tensor = + GetWebNNTensor(webnn_tensor_handle); + ASSERT_TRUE(webnn_tensor); + + // Ensure WebNN can use the tensor before access begins. + constexpr uint64_t kTensorSize = 4ull; + const std::array<const uint8_t, kTensorSize> input_data{0xAA, 0xAA, 0xAA, + 0xAA}; + webnn_tensor_remote->WriteTensor(mojo_base::BigBuffer(input_data)); + webnn_tensor_remote.FlushForTesting(); + + std::unique_ptr<native::d3d12::WebNNSharedFence> webnn_fence_to_wait_for = + webnn_tensor->EndAccessWebNN(); + ASSERT_TRUE(webnn_fence_to_wait_for); + + EXPECT_TRUE( + webnn_tensor->BeginAccessWebNN(webnn_fence_to_wait_for->GetD3D12Fence(), + webnn_fence_to_wait_for->GetFenceValue())); + + // Ensure the WebNN can still use the tensor after begin access. + { + base::test::TestFuture<mojom::ReadTensorResultPtr> read_tensor_future; + webnn_tensor_remote->ReadTensor(read_tensor_future.GetCallback()); + mojom::ReadTensorResultPtr read_create_tensor_result = + read_tensor_future.Take(); + ASSERT_FALSE(read_create_tensor_result->is_error()); + EXPECT_TRUE( + IsBufferDataEqual(mojo_base::BigBuffer(input_data), + std::move(read_create_tensor_result->get_buffer()))); + } + + EXPECT_FALSE(bad_message_helper.GetLastBadMessage().has_value()); +} + +// Verify access between queues: WebNN and an external one. +TEST_F(WebNNTensorImplDmlBackendTest, AccessOnDifferentQueueTest) { + BadMessageTestHelper bad_message_helper; + + mojo::AssociatedRemote<mojom::WebNNTensor> webnn_tensor_remote; + blink::WebNNTensorToken webnn_tensor_handle; + base::expected<CreateTensorSuccess, webnn::mojom::Error::Code> + create_tensor_result = CreateWebNNTensor( + webnn_context_remote_, + mojom::TensorInfo::New( + OperandDescriptor::UnsafeCreateForTesting( + OperandDataType::kUint8, std::array<uint32_t, 2>{2, 2}), + MLTensorUsage{MLTensorUsageFlags::kWebGpuInterop, + MLTensorUsageFlags::kRead})); + if (create_tensor_result.has_value()) { + webnn_tensor_remote = + std::move(create_tensor_result.value().webnn_tensor_remote); + webnn_tensor_handle = + std::move(create_tensor_result.value().webnn_tensor_handle); + } + + ASSERT_TRUE(webnn_tensor_remote.is_bound()); + + webnn_context_remote_.FlushForTesting(); + + // Simulate access by creating an external queue, recorder, and a + // buffer. + scoped_refptr<dml::CommandQueue> command_queue = + dml::CommandQueue::Create(adapter_->d3d12_device()); + ASSERT_NE(command_queue, nullptr); + + auto create_recorder_result = + dml::CommandRecorder::Create(command_queue, adapter_->dml_device()); + ASSERT_TRUE(create_recorder_result.has_value()); + std::unique_ptr<dml::CommandRecorder> command_recorder = + std::move(create_recorder_result.value()); + + constexpr uint64_t kTensorSize = 4ull; + const std::array<const uint8_t, kTensorSize> input_data = {0xAA, 0xAA, 0xAA, + 0xAA}; + Microsoft::WRL::ComPtr<ID3D12Resource> upload_buffer; + ASSERT_HRESULT_SUCCEEDED( + dml::CreateUploadBuffer(adapter_->d3d12_device(), input_data.size(), + L"Upload_Buffer", upload_buffer)); + ASSERT_NE(upload_buffer, nullptr); + + // SAFETY: `upload_buffer` was constructed with size `input_data.size()`. + UNSAFE_BUFFERS(WriteTensorData( + base::span(input_data.data(), input_data.size()), upload_buffer.Get())); + + base::WeakPtr<native::d3d12::WebNNTensor> webnn_tensor = + GetWebNNTensor(webnn_tensor_handle); + ASSERT_TRUE(webnn_tensor); + + // Simulate multi-queue usage via GPU copy. + // + // Step | WebNN queue | Other queue + // ----------------------------------- + // 1. Signal + // 2. |---------> Wait + // 3. GPU copy + // 4. Signal + // 5. Wait <-----------| + // 6. GPU copy + // 7. Signal + // 8. |---------> Wait + // 9. GPU copy + // 10. Signal + // 11. Wait <-----------| + // 12. GPU copy + // 13. Signal + // 14. |----------> Wait + + std::unique_ptr<native::d3d12::WebNNSharedFence> webnn_fence_to_wait_for_1 = + webnn_tensor->EndAccessWebNN(); + ASSERT_TRUE(webnn_fence_to_wait_for_1); + + // Step 1. End access with no WebNN work should not require a wait. + ASSERT_TRUE(IsFenceCompleted(webnn_fence_to_wait_for_1->GetD3D12Fence().Get(), + webnn_fence_to_wait_for_1->GetFenceValue())); + + { + ASSERT_HRESULT_SUCCEEDED(command_recorder->Open()); + UploadBufferWithBarrier(command_recorder.get(), + webnn_tensor->GetD3D12Buffer(), upload_buffer, + kTensorSize); + ASSERT_HRESULT_SUCCEEDED(command_recorder->CloseAndExecute()); + } + + ASSERT_TRUE(webnn_tensor->BeginAccessWebNN( + command_queue->submission_fence(), command_queue->GetLastFenceValue())); + + // Step 5. Ensure WebNN can use the tensor after begin access. + { + base::test::TestFuture<mojom::ReadTensorResultPtr> read_tensor_future; + webnn_tensor_remote->ReadTensor(read_tensor_future.GetCallback()); + mojom::ReadTensorResultPtr read_create_tensor_result = + read_tensor_future.Take(); + ASSERT_FALSE(read_create_tensor_result->is_error()); + EXPECT_TRUE( + IsBufferDataEqual(mojo_base::BigBuffer(input_data), + std::move(read_create_tensor_result->get_buffer()))); + } + + // Ensure WebNN waited until the other queue completed. + ASSERT_TRUE(IsFenceCompleted(command_queue->submission_fence(), + command_queue->GetLastFenceValue())); + + // Step 8. Simulate more external queue use with new data. + std::unique_ptr<native::d3d12::WebNNSharedFence> webnn_fence_to_wait_for_2 = + webnn_tensor->EndAccessWebNN(); + ASSERT_TRUE(webnn_fence_to_wait_for_2); + + const std::array<const uint8_t, kTensorSize> new_input_data = {0xBB, 0xBB, + 0xBB, 0xBB}; + { + // SAFETY: `upload_buffer` was constructed with size + // `new_input_data.size()`. + UNSAFE_BUFFERS(WriteTensorData( + base::span(new_input_data.data(), new_input_data.size()), + upload_buffer.Get())); + + ASSERT_HRESULT_SUCCEEDED(command_queue->WaitForFence( + webnn_fence_to_wait_for_2->GetD3D12Fence(), + webnn_fence_to_wait_for_2->GetFenceValue())); + ASSERT_HRESULT_SUCCEEDED(command_recorder->Open()); + UploadBufferWithBarrier(command_recorder.get(), + webnn_tensor->GetD3D12Buffer(), upload_buffer, + kTensorSize); + ASSERT_HRESULT_SUCCEEDED(command_recorder->CloseAndExecute()); + } + + ASSERT_TRUE(webnn_tensor->BeginAccessWebNN( + command_queue->submission_fence(), command_queue->GetLastFenceValue())); + + // Step 11. WebNN should be able to use the tensor after begin access. + { + base::test::TestFuture<mojom::ReadTensorResultPtr> read_tensor_future; + webnn_tensor_remote->ReadTensor(read_tensor_future.GetCallback()); + mojom::ReadTensorResultPtr read_create_tensor_result = + read_tensor_future.Take(); + ASSERT_FALSE(read_create_tensor_result->is_error()); + EXPECT_TRUE( + IsBufferDataEqual(mojo_base::BigBuffer(new_input_data), + std::move(read_create_tensor_result->get_buffer()))); + } + + EXPECT_FALSE(bad_message_helper.GetLastBadMessage().has_value()); +} + +// Verify end access with no WebNN work in-between returns the last fence +// without WebNN calling wait. +TEST_F(WebNNTensorImplDmlBackendTest, NoWebNNQueueAccessInBetweenTest) { + BadMessageTestHelper bad_message_helper; + + mojo::AssociatedRemote<mojom::WebNNTensor> webnn_tensor_remote; + blink::WebNNTensorToken webnn_tensor_handle; + base::expected<CreateTensorSuccess, webnn::mojom::Error::Code> + create_tensor_result = CreateWebNNTensor( + webnn_context_remote_, + mojom::TensorInfo::New( + OperandDescriptor::UnsafeCreateForTesting( + OperandDataType::kUint8, std::array<uint32_t, 2>{2, 2}), + MLTensorUsage{MLTensorUsageFlags::kWebGpuInterop})); + if (create_tensor_result.has_value()) { + webnn_tensor_remote = + std::move(create_tensor_result.value().webnn_tensor_remote); + webnn_tensor_handle = + std::move(create_tensor_result.value().webnn_tensor_handle); + } + + ASSERT_TRUE(webnn_tensor_remote.is_bound()); + + webnn_context_remote_.FlushForTesting(); + + // Simulate access by creating an external queue. + scoped_refptr<dml::CommandQueue> command_queue = + dml::CommandQueue::Create(adapter_->d3d12_device()); + ASSERT_NE(command_queue, nullptr); + + base::WeakPtr<native::d3d12::WebNNTensor> webnn_tensor = + GetWebNNTensor(webnn_tensor_handle); + ASSERT_TRUE(webnn_tensor); + + // End access without any WebNN work prior returns WebNN's submission + // fence which should be completed. + std::unique_ptr<native::d3d12::WebNNSharedFence> webnn_fence_to_wait_for_1 = + webnn_tensor->EndAccessWebNN(); + ASSERT_TRUE(webnn_fence_to_wait_for_1); + + ASSERT_TRUE(IsFenceCompleted(webnn_fence_to_wait_for_1->GetD3D12Fence().Get(), + webnn_fence_to_wait_for_1->GetFenceValue())); + + // Initialize the external queue's submission fence to a non-zero value to + // ensure it has not been signaled by WebNN's queue. + const uint64_t initialValue = 0xFF; + command_queue->submission_fence()->Signal(initialValue); + + ASSERT_TRUE(webnn_tensor->BeginAccessWebNN(command_queue->submission_fence(), + initialValue + 1)); + + // Calling end access again, with no WebNN work, should + // return the last fence without WebNN calling wait on it. + std::unique_ptr<native::d3d12::WebNNSharedFence> webnn_fence_to_wait_for_2 = + webnn_tensor->EndAccessWebNN(); + ASSERT_TRUE(webnn_fence_to_wait_for_2); + + EXPECT_EQ(command_queue->submission_fence(), + webnn_fence_to_wait_for_2->GetD3D12Fence().Get()); + + EXPECT_FALSE( + IsFenceCompleted(command_queue->submission_fence(), initialValue + 1)); + + EXPECT_FALSE(bad_message_helper.GetLastBadMessage().has_value()); +} + +#endif // BUILDFLAG(IS_WIN) + } // namespace } // namespace webnn::test
diff --git a/testing/buildbot/buildbot_json_magic_substitutions.py b/testing/buildbot/buildbot_json_magic_substitutions.py index a196ab9..702f257 100644 --- a/testing/buildbot/buildbot_json_magic_substitutions.py +++ b/testing/buildbot/buildbot_json_magic_substitutions.py
@@ -20,6 +20,9 @@ MAGIC_SUBSTITUTION_PREFIX = '$$MAGIC_SUBSTITUTION_' GpuDevice = collections.namedtuple('GpuDevice', ['vendor', 'device']) +ANDROID_DESKTOP_BOARD_GPUS = { + 'brya': GpuDevice('8086', '46a8'), +} CROS_BOARD_GPUS = { 'volteer': GpuDevice('8086', '9a49'), } @@ -47,6 +50,18 @@ 'oriole': GpuDevice('13b5', '92020010,92020000'), } + +def AndroidDesktopTelemetryRemote(test_config, _, tester_config): + """Substitutes the correct Android Desktop remote Telemetry arguments.""" + assert _IsAndroid(tester_config) + if not _GetAndroidDesktopBoardName(test_config): + return [] + return [ + '--device=variable_lab_dut_hostname', + '--connect-to-device-over-network', + ] + + def ChromeOSTelemetryRemote(test_config, _, tester_config): """Substitutes the correct CrOS remote Telemetry arguments. @@ -93,6 +108,13 @@ ] +def _GetAndroidDesktopBoardName(test_config): + """Helper function to determine what Android Desktop board is being used.""" + dimensions = test_config.get('swarming', {}).get('dimensions') + assert dimensions is not None + return dimensions.get('label-board') + + def _GetChromeOSBoardName(test_config): """Helper function to determine what ChromeOS board is being used.""" @@ -120,6 +142,11 @@ return dimensions.get('device_type', 'amd64-generic') +def _IsAndroidDesktopBot(test_config, tester_config): + """Helper function to determine if a bot is an Android Desktop bot.""" + return _IsAndroid(tester_config) and _GetAndroidDesktopBoardName(test_config) + + def _IsSkylabBot(tester_config): """Helper function to determine if a bot is a Skylab ChromeOS bot.""" return (tester_config.get('browser_config') == 'cros-chrome' @@ -142,6 +169,8 @@ tester_config: A dict containing the configuration for the builder that |test_config| is for. """ + if _IsAndroidDesktopBot(test_config, tester_config): + return _GPUExpectedVendorIdAndroidDesktop(test_config) if _IsSkylabBot(tester_config): return _GPUExpectedVendorIdSkylab(test_config) dimensions = test_config.get('swarming', {}).get('dimensions') @@ -173,6 +202,13 @@ return ['--expected-vendor-id', vendor_ids.pop()] +def _GPUExpectedVendorIdAndroidDesktop(test_config): + board = _GetAndroidDesktopBoardName(test_config) + assert board is not None + gpu_device = ANDROID_DESKTOP_BOARD_GPUS.get(board, GpuDevice('0', '0')) + return ['--expected-vendor-id', gpu_device.vendor] + + def _GPUExpectedVendorIdSkylab(test_config): cros_board = test_config.get('cros_board') assert cros_board is not None @@ -192,6 +228,8 @@ tester_config: A dict containing the configuration for the builder that |test_config| is for. """ + if _IsAndroidDesktopBot(test_config, tester_config): + return _GPUExpectedDeviceIdAndroidDesktop(test_config) if _IsSkylabBot(tester_config): return _GPUExpectedDeviceIdSkylab(test_config) dimensions = test_config.get('swarming', {}).get('dimensions') @@ -229,6 +267,13 @@ return retval +def _GPUExpectedDeviceIdAndroidDesktop(test_config): + board = _GetAndroidDesktopBoardName(test_config) + assert board is not None + gpu_device = ANDROID_DESKTOP_BOARD_GPUS.get(board, GpuDevice('0', '0')) + return ['--expected-device-id', gpu_device.device] + + def _GPUExpectedDeviceIdSkylab(test_config): cros_board = test_config.get('cros_board') assert cros_board is not None
diff --git a/testing/buildbot/buildbot_json_magic_substitutions_unittest.py b/testing/buildbot/buildbot_json_magic_substitutions_unittest.py index 1d93c7c..76c3004 100755 --- a/testing/buildbot/buildbot_json_magic_substitutions_unittest.py +++ b/testing/buildbot/buildbot_json_magic_substitutions_unittest.py
@@ -9,7 +9,7 @@ import buildbot_json_magic_substitutions as magic_substitutions -def CreateConfigWithPool(pool, device_type=None): +def CreateConfigWithPool(pool, device_type=None, board=None): dims = { 'name': 'test_name', 'swarming': { @@ -20,9 +20,35 @@ } if device_type: dims['swarming']['dimensions']['device_type'] = device_type + if board: + dims['swarming']['dimensions']['label-board'] = board return dims +class AndroidDesktopTelemetryRemoteTest(unittest.TestCase): + + def testNonAndroid(self): + test_config = CreateConfigWithPool('chromium.tests', board='brya') + with self.assertRaises(AssertionError): + magic_substitutions.AndroidDesktopTelemetryRemote(test_config, None, + {'os_type': 'linux'}) + + def testNoBoard(self): + test_config = CreateConfigWithPool('chromium.tests') + self.assertEqual( + magic_substitutions.AndroidDesktopTelemetryRemote( + test_config, None, {'os_type': 'android'}), []) + + def testSuccess(self): + test_config = CreateConfigWithPool('chromium.tests', board='brya') + self.assertEqual( + magic_substitutions.AndroidDesktopTelemetryRemote( + test_config, None, {'os_type': 'android'}), [ + '--device=variable_lab_dut_hostname', + '--connect-to-device-over-network', + ]) + + class ChromeOSTelemetryRemoteTest(unittest.TestCase): def testVirtualMachineSubstitutions(self): @@ -160,6 +186,40 @@ with self.assertRaises(AssertionError): magic_substitutions.GPUExpectedVendorId({}, None, {}) + def testAndroidDesktopKnownBoard(self): + test_config = { + 'name': 'test_name', + 'swarming': { + 'dimensions': { + 'label-board': 'brya', + }, + }, + } + tester_config = { + 'os_type': 'android', + } + self.assertEqual( + magic_substitutions.GPUExpectedVendorId(test_config, None, + tester_config), + ['--expected-vendor-id', '8086']) + + def testAndroidDesktopUnknownBoard(self): + test_config = { + 'name': 'test_name', + 'swarming': { + 'dimensions': { + 'label-board': 'fake_board', + }, + }, + } + tester_config = { + 'os_type': 'android', + } + self.assertEqual( + magic_substitutions.GPUExpectedVendorId(test_config, None, + tester_config), + ['--expected-vendor-id', '0']) + def testSkylabKnownBoard(self): test_config = { 'name': 'test_name', @@ -226,6 +286,38 @@ with self.assertRaises(AssertionError): magic_substitutions.GPUExpectedDeviceId({}, None, {}) + def testAndroidDesktopKnownBoard(self): + test_config = { + 'name': 'test_name', + 'swarming': { + 'dimensions': { + 'label-board': 'brya', + }, + }, + } + tester_config = { + 'os_type': 'android', + } + self.assertDeviceIdCorrectness( + magic_substitutions.GPUExpectedDeviceId(test_config, None, + tester_config), ['46a8']) + + def testAndroidDesktopUnknownBoard(self): + test_config = { + 'name': 'test_name', + 'swarming': { + 'dimensions': { + 'label-board': 'fake_board', + }, + }, + } + tester_config = { + 'os_type': 'android', + } + self.assertDeviceIdCorrectness( + magic_substitutions.GPUExpectedDeviceId(test_config, None, + tester_config), ['0']) + def testSkylabKnownBoard(self): test_config = { 'name': 'test_name',
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json index 5c525bf..98be8ea 100644 --- a/testing/buildbot/chromium.perf.json +++ b/testing/buildbot/chromium.perf.json
@@ -106,7 +106,7 @@ "can_use_on_swarming_builders": true, "dimensions": { "dut_state": "ready", - "label-board": "byra", + "label-board": "brya", "label-pool": "chrome.tests.perf", "os": "Android", "pool": "chrome"
diff --git a/testing/buildbot/chromium.perf.pinpoint.json b/testing/buildbot/chromium.perf.pinpoint.json index 306f3368..70348c8 100644 --- a/testing/buildbot/chromium.perf.pinpoint.json +++ b/testing/buildbot/chromium.perf.pinpoint.json
@@ -25,7 +25,7 @@ "can_use_on_swarming_builders": true, "dimensions": { "dut_state": "ready", - "label-board": "byra", + "label-board": "brya", "label-pool": "chrome.tests.perf", "os": "Android", "pool": "chrome"
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn index 7f1a3141..1ea8e6c 100644 --- a/testing/buildbot/filters/BUILD.gn +++ b/testing/buildbot/filters/BUILD.gn
@@ -385,6 +385,7 @@ "//testing/buildbot/filters/android.emulator_12.gl_unittests.filter", "//testing/buildbot/filters/win.win_arm64.gl_unittests.filter", "//testing/buildbot/filters/win.amd.5500xt.gl_unittests.filter", + "//testing/buildbot/filters/win.nvidia.gtx.1660.gl_unittests.filter", ] }
diff --git a/testing/buildbot/filters/ozone-linux.browser_tests_mutter.filter b/testing/buildbot/filters/ozone-linux.browser_tests_mutter.filter index 5a757f4..9074ff4 100644 --- a/testing/buildbot/filters/ozone-linux.browser_tests_mutter.filter +++ b/testing/buildbot/filters/ozone-linux.browser_tests_mutter.filter
@@ -1,4 +1,5 @@ -# TODO(crbug.com/395595608) Failing due to per-surface scaling. +# TODO(crbug.com/348590032) Failing as test relies on window.devicePixelRatio +# which doesn't work with per-window scaling. -All/GetDisplayMediaHiDpiBrowserTest.Capture/1 # Very flaky/failing on mutter (less flaky/passing on weston)
diff --git a/testing/buildbot/filters/pixel_tests.filter b/testing/buildbot/filters/pixel_tests.filter index 7c00fe5..881a6875 100644 --- a/testing/buildbot/filters/pixel_tests.filter +++ b/testing/buildbot/filters/pixel_tests.filter
@@ -19,6 +19,7 @@ BrowserViewScrimPixelTest.* BubbleFrameViewBrowserTest.* BubbleSignInPromoInteractiveUITest.* +CaptionBubbleBrowserTest.* ChromeLabs*UiTest.* ChromeSignoutConfirmationPromptPixelTest.* ChromeSignoutConfirmationPromptWithExtensionsPixelTest.*
diff --git a/testing/buildbot/filters/trees_in_viz.content_browsertests.filter b/testing/buildbot/filters/trees_in_viz.content_browsertests.filter index 5eb7e30..cb89cf51 100644 --- a/testing/buildbot/filters/trees_in_viz.content_browsertests.filter +++ b/testing/buildbot/filters/trees_in_viz.content_browsertests.filter
@@ -9,7 +9,6 @@ -All/CompositedScrollingMetricTest.RecordCorrectScrollingThread/NonComposited_RasterInducingScroll -All/NavigationBrowserTestPaintHoldingSubframe.BasicInProcessIframe/0 -All/NavigationBrowserTestPaintHoldingSubframe.BasicInProcessIframe/1 --All/RenderWidgetHostItemSequenceNumberInRenderFrameMetadataTest.ItemSequenceNumberExpectedNoContentChange/SameDoc -PrerenderBrowserDeathTest.PrerenderCannotHaveInnerContents -RenderFrameHostImplDeathTest.ReloadInPendingDeletionOrBFCache -SecurityExploitBrowserTest.AllowBindingsForNonWebUIProcess
diff --git a/testing/buildbot/filters/win.nvidia.gtx.1660.gl_unittests.filter b/testing/buildbot/filters/win.nvidia.gtx.1660.gl_unittests.filter new file mode 100644 index 0000000..cf557d76 --- /dev/null +++ b/testing/buildbot/filters/win.nvidia.gtx.1660.gl_unittests.filter
@@ -0,0 +1,2 @@ +# crbug.com/415086846 +-*DCompPresenter*
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index dd9fc79..159ef3a 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl
@@ -261,6 +261,7 @@ ], 'android_args': [ '$$MAGIC_SUBSTITUTION_GPUTelemetryNoRootForUnrootedDevices', + '$$MAGIC_SUBSTITUTION_AndroidDesktopTelemetryRemote', '--initial-find-device-attempts=3', ], 'chromeos_args': [ @@ -866,8 +867,8 @@ 'swarming': { 'dimensions': { 'display_attached': '1', - 'gpu': '10de:2184-31.0.15.4601', - 'os': 'Windows-10-19045', + 'gpu': '10de:2184-32.0.15.7602', + 'os': 'Windows-11-26100', 'pool': 'chromium.tests.gpu', }, },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 9a285d856..5a8c902 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -8834,6 +8834,24 @@ ] } ], + "EnterpriseFileSystemAccessDeepScan": [ + { + "platforms": [ + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "EnterpriseFileSystemAccessDeepScan" + ] + } + ] + } + ], "EnterpriseUpdatedProfileCreationScreen": [ { "platforms": [ @@ -10224,7 +10242,7 @@ ] } ], - "GwpAsanAndroid2024": [ + "GwpAsan2024Android": [ { "platforms": [ "android", @@ -10232,11 +10250,20 @@ ], "experiments": [ { - "name": "TripleBrowserReservation", + "name": "CombinedGreedyArmForVariationsPresubmit", "params": { + "BrowserAllocationSamplingMultiplier": "1500", + "BrowserAllocationSamplingRange": "16", "BrowserMaxAllocations": "210", "BrowserMaxMetadata": "765", - "BrowserTotalPages": "1536" + "BrowserTotalPages": "1536", + "GpuAllocationSamplingMultiplier": "1500", + "GpuAllocationSamplingRange": "16", + "GpuMaxAllocations": "140", + "GpuMaxMetadata": "510", + "GpuTotalPages": "1024", + "RendererAllocationSamplingMultiplier": "1500", + "RendererAllocationSamplingRange": "12" }, "enable_features": [ "GwpAsanMalloc", @@ -10246,20 +10273,59 @@ ] } ], - "GwpAsanDesktop2024": [ + "GwpAsan2024LinuxCros": [ { "platforms": [ "chromeos", - "linux", + "linux" + ], + "experiments": [ + { + "name": "CombinedGreedyArmForVariationsPresubmit", + "params": { + "BrowserAllocationSamplingMultiplier": "1200", + "BrowserAllocationSamplingRange": "10", + "BrowserMaxAllocations": "150", + "BrowserMaxMetadata": "630", + "BrowserTotalPages": "6144", + "GpuAllocationSamplingMultiplier": "1200", + "GpuAllocationSamplingRange": "10", + "GpuMaxAllocations": "100", + "GpuMaxMetadata": "420", + "GpuTotalPages": "4096", + "RendererAllocationSamplingMultiplier": "800", + "RendererAllocationSamplingRange": "10" + }, + "enable_features": [ + "GwpAsanMalloc", + "GwpAsanPartitionAlloc" + ] + } + ] + } + ], + "GwpAsan2024WinMac": [ + { + "platforms": [ + "windows", "mac" ], "experiments": [ { - "name": "TripleBrowserReservation", + "name": "CombinedGreedyArmForVariationsPresubmit", "params": { + "BrowserAllocationSamplingMultiplier": "800", + "BrowserAllocationSamplingRange": "10", "BrowserMaxAllocations": "210", "BrowserMaxMetadata": "765", - "BrowserTotalPages": "6144" + "BrowserTotalPages": "6144", + "GpuAllocationSamplingMultiplier": "800", + "GpuAllocationSamplingRange": "10", + "GpuMaxAllocations": "140", + "GpuMaxMetadata": "510", + "GpuTotalPages": "4096", + "RendererAllocationSamplingMultiplier": "600", + "RendererAllocationSamplingRange": "10" }, "enable_features": [ "GwpAsanMalloc", @@ -11177,6 +11243,21 @@ ] } ], + "IOSAutofillRefillForForms": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AutofillRefillForFormsIos" + ] + } + ] + } + ], "IOSAutofillThrottleDocumentFormScan": [ { "platforms": [ @@ -13185,35 +13266,6 @@ ] } ], - "LightweightUAFDetector": [ - { - "platforms": [ - "windows" - ], - "experiments": [ - { - "name": "Enabled_20240130", - "params": { - "AllocationSamplingMultiplier": "100", - "EvictionTaskIntervalMs": "5000", - "MaxAllocations": "1400", - "MaxMetadata": "5100", - "MaxTotalSize": "131072", - "Mode": "Random", - "TotalSizeHighWaterMark": "104857", - "TotalSizeLowWaterMark": "91750" - }, - "enable_features": [ - "LightweightUafDetector" - ], - "disable_features": [ - "GwpAsanMalloc", - "GwpAsanPartitionAlloc" - ] - } - ] - } - ], "LinkCrossDeviceDogFoodFeedback": [ { "platforms": [ @@ -14618,6 +14670,21 @@ ] } ], + "NonModalSignInPromo": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "NonModalSignInPromo" + ] + } + ] + } + ], "NonStandardAppearanceValueSliderVertical": [ { "platforms": [ @@ -17335,6 +17402,7 @@ { "platforms": [ "android", + "android_webview", "chromeos", "chromeos_lacros", "linux", @@ -21295,6 +21363,32 @@ ] } ], + "SearchEnginePreconnect2": [ + { + "platforms": [ + "android", + "chromeos", + "chromeos_lacros", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "EnabledWithbase_60_30_30_30__20250507", + "params": { + "IdleTimeoutInSeconds": "60", + "MaxPreconnectRetryInterval": "30", + "MaxShortSessionThreshold": "30", + "PingIntervalInSeconds": "30" + }, + "enable_features": [ + "SearchEnginePreconnect2" + ] + } + ] + } + ], "SearchEnginePreconnectInterval": [ { "platforms": [
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium index 3f47276..044587a 100644 --- a/third_party/abseil-cpp/README.chromium +++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@ License: Apache-2.0 License File: LICENSE Version: N/A -Revision: 2bbec17a3f20da4d908e5627aa72b46f48e064ac +Revision: 1b52dcb350289b262a105471a75ef6c001beecae Security Critical: yes Shipped: yes
diff --git a/third_party/abseil-cpp/absl/base/config.h b/third_party/abseil-cpp/absl/base/config.h index 7514b86..f3cafbd 100644 --- a/third_party/abseil-cpp/absl/base/config.h +++ b/third_party/abseil-cpp/absl/base/config.h
@@ -530,13 +530,12 @@ // ABSL_HAVE_STD_STRING_VIEW // -// Checks whether C++17 std::string_view is available. +// Deprecated: always defined to 1. +// std::string_view was added in C++17, which means all versions of C++ +// supported by Abseil have it. #ifdef ABSL_HAVE_STD_STRING_VIEW #error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set." -#elif defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L -#define ABSL_HAVE_STD_STRING_VIEW 1 -#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ - ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L +#else #define ABSL_HAVE_STD_STRING_VIEW 1 #endif @@ -561,13 +560,10 @@ // Indicates whether absl::string_view is an alias for std::string_view. #if !defined(ABSL_OPTION_USE_STD_STRING_VIEW) #error options.h is misconfigured. -#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 || \ - (ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \ - !defined(ABSL_HAVE_STD_STRING_VIEW)) +#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 #undef ABSL_USES_STD_STRING_VIEW #elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \ - (ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \ - defined(ABSL_HAVE_STD_STRING_VIEW)) + ABSL_OPTION_USE_STD_STRING_VIEW == 2 #define ABSL_USES_STD_STRING_VIEW 1 #else #error options.h is misconfigured.
diff --git a/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h b/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h index 0f07bcf..c2a757b 100644 --- a/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h +++ b/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h
@@ -49,6 +49,7 @@ #include <functional> #include <memory> #include <string> +#include <string_view> #include <type_traits> #include "absl/base/config.h" @@ -58,10 +59,6 @@ #include "absl/strings/cord.h" #include "absl/strings/string_view.h" -#ifdef ABSL_HAVE_STD_STRING_VIEW -#include <string_view> -#endif - namespace absl { ABSL_NAMESPACE_BEGIN namespace container_internal { @@ -113,8 +110,6 @@ template <> struct HashEq<absl::Cord> : StringHashEq {}; -#ifdef ABSL_HAVE_STD_STRING_VIEW - template <typename TChar> struct BasicStringHash { using is_transparent = void; @@ -153,8 +148,6 @@ template <> struct HashEq<std::u32string_view> : BasicStringHashEq<char32_t> {}; -#endif // ABSL_HAVE_STD_STRING_VIEW - // Supports heterogeneous lookup for pointers and smart pointers. template <class T> struct HashEq<T*> {
diff --git a/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc b/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc index 912d119..9a39b07 100644 --- a/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc +++ b/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc
@@ -16,6 +16,7 @@ #include <cstddef> #include <functional> +#include <string_view> #include <type_traits> #include <utility> @@ -28,10 +29,6 @@ #include "absl/strings/cord_test_helpers.h" #include "absl/strings/string_view.h" -#ifdef ABSL_HAVE_STD_STRING_VIEW -#include <string_view> -#endif - namespace absl { ABSL_NAMESPACE_BEGIN namespace container_internal { @@ -118,9 +115,6 @@ } TEST(BasicStringViewTest, WStringEqWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_eq<std::wstring> eq; EXPECT_TRUE(eq(L"a", L"a")); EXPECT_TRUE(eq(L"a", std::wstring_view(L"a"))); @@ -128,13 +122,9 @@ EXPECT_FALSE(eq(L"a", L"b")); EXPECT_FALSE(eq(L"a", std::wstring_view(L"b"))); EXPECT_FALSE(eq(L"a", std::wstring(L"b"))); -#endif } TEST(BasicStringViewTest, WStringViewEqWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_eq<std::wstring_view> eq; EXPECT_TRUE(eq(L"a", L"a")); EXPECT_TRUE(eq(L"a", std::wstring_view(L"a"))); @@ -142,13 +132,9 @@ EXPECT_FALSE(eq(L"a", L"b")); EXPECT_FALSE(eq(L"a", std::wstring_view(L"b"))); EXPECT_FALSE(eq(L"a", std::wstring(L"b"))); -#endif } TEST(BasicStringViewTest, U16StringEqWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_eq<std::u16string> eq; EXPECT_TRUE(eq(u"a", u"a")); EXPECT_TRUE(eq(u"a", std::u16string_view(u"a"))); @@ -156,13 +142,9 @@ EXPECT_FALSE(eq(u"a", u"b")); EXPECT_FALSE(eq(u"a", std::u16string_view(u"b"))); EXPECT_FALSE(eq(u"a", std::u16string(u"b"))); -#endif } TEST(BasicStringViewTest, U16StringViewEqWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_eq<std::u16string_view> eq; EXPECT_TRUE(eq(u"a", u"a")); EXPECT_TRUE(eq(u"a", std::u16string_view(u"a"))); @@ -170,13 +152,9 @@ EXPECT_FALSE(eq(u"a", u"b")); EXPECT_FALSE(eq(u"a", std::u16string_view(u"b"))); EXPECT_FALSE(eq(u"a", std::u16string(u"b"))); -#endif } TEST(BasicStringViewTest, U32StringEqWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_eq<std::u32string> eq; EXPECT_TRUE(eq(U"a", U"a")); EXPECT_TRUE(eq(U"a", std::u32string_view(U"a"))); @@ -184,13 +162,9 @@ EXPECT_FALSE(eq(U"a", U"b")); EXPECT_FALSE(eq(U"a", std::u32string_view(U"b"))); EXPECT_FALSE(eq(U"a", std::u32string(U"b"))); -#endif } TEST(BasicStringViewTest, U32StringViewEqWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_eq<std::u32string_view> eq; EXPECT_TRUE(eq(U"a", U"a")); EXPECT_TRUE(eq(U"a", std::u32string_view(U"a"))); @@ -198,85 +172,60 @@ EXPECT_FALSE(eq(U"a", U"b")); EXPECT_FALSE(eq(U"a", std::u32string_view(U"b"))); EXPECT_FALSE(eq(U"a", std::u32string(U"b"))); -#endif } TEST(BasicStringViewTest, WStringHashWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_hash<std::wstring> hash; auto h = hash(L"a"); EXPECT_EQ(h, hash(std::wstring_view(L"a"))); EXPECT_EQ(h, hash(std::wstring(L"a"))); EXPECT_NE(h, hash(std::wstring_view(L"b"))); EXPECT_NE(h, hash(std::wstring(L"b"))); -#endif } TEST(BasicStringViewTest, WStringViewHashWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_hash<std::wstring_view> hash; auto h = hash(L"a"); EXPECT_EQ(h, hash(std::wstring_view(L"a"))); EXPECT_EQ(h, hash(std::wstring(L"a"))); EXPECT_NE(h, hash(std::wstring_view(L"b"))); EXPECT_NE(h, hash(std::wstring(L"b"))); -#endif } TEST(BasicStringViewTest, U16StringHashWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_hash<std::u16string> hash; auto h = hash(u"a"); EXPECT_EQ(h, hash(std::u16string_view(u"a"))); EXPECT_EQ(h, hash(std::u16string(u"a"))); EXPECT_NE(h, hash(std::u16string_view(u"b"))); EXPECT_NE(h, hash(std::u16string(u"b"))); -#endif } TEST(BasicStringViewTest, U16StringViewHashWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_hash<std::u16string_view> hash; auto h = hash(u"a"); EXPECT_EQ(h, hash(std::u16string_view(u"a"))); EXPECT_EQ(h, hash(std::u16string(u"a"))); EXPECT_NE(h, hash(std::u16string_view(u"b"))); EXPECT_NE(h, hash(std::u16string(u"b"))); -#endif } TEST(BasicStringViewTest, U32StringHashWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_hash<std::u32string> hash; auto h = hash(U"a"); EXPECT_EQ(h, hash(std::u32string_view(U"a"))); EXPECT_EQ(h, hash(std::u32string(U"a"))); EXPECT_NE(h, hash(std::u32string_view(U"b"))); EXPECT_NE(h, hash(std::u32string(U"b"))); -#endif } TEST(BasicStringViewTest, U32StringViewHashWorks) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else hash_default_hash<std::u32string_view> hash; auto h = hash(U"a"); EXPECT_EQ(h, hash(std::u32string_view(U"a"))); EXPECT_EQ(h, hash(std::u32string(U"a"))); EXPECT_NE(h, hash(std::u32string_view(U"b"))); EXPECT_NE(h, hash(std::u32string(U"b"))); -#endif } struct NoDeleter {
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc index f19e87b..339e662 100644 --- a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc +++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc
@@ -295,9 +295,14 @@ ABSL_UNREACHABLE(); } -size_t DropDeletesWithoutResizeAndPrepareInsert(CommonFields& common, - const PolicyFunctions& policy, - size_t new_hash) { +void PrepareInsertCommon(CommonFields& common) { + common.increment_size(); + common.maybe_increment_generation_on_insert(); +} + +size_t DropDeletesWithoutResizeAndPrepareInsert( + CommonFields& common, const PolicyFunctions& __restrict policy, + size_t new_hash) { void* set = &common; void* slot_array = common.slot_array(); const size_t capacity = common.capacity(); @@ -399,7 +404,7 @@ PrepareInsertCommon(common); ResetGrowthLeft(common); FindInfo find_info = find_first_non_full(common, new_hash); - SetCtrlInLargeTable(common, find_info.offset, H2(new_hash), policy.slot_size); + SetCtrlInLargeTable(common, find_info.offset, H2(new_hash), slot_size); common.infoz().RecordInsert(new_hash, find_info.probe_length); common.infoz().RecordRehash(total_probe_length); return find_info.offset; @@ -555,8 +560,9 @@ SetCtrlInLargeTable(c, index, ctrl_t::kDeleted, slot_size); } -void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy, - void* alloc, bool reuse, bool soo_enabled) { +void ClearBackingArray(CommonFields& c, + const PolicyFunctions& __restrict policy, void* alloc, + bool reuse, bool soo_enabled) { if (reuse) { c.set_size_to_zero(); ABSL_SWISSTABLE_ASSERT(!soo_enabled || c.capacity() > SooCapacity()); @@ -587,10 +593,9 @@ // This function is used for reserving or rehashing non-empty tables. // This use case is rare so the function is type erased. // Returns the total probe length. -size_t FindNewPositionsAndTransferSlots(CommonFields& common, - const PolicyFunctions& policy, - ctrl_t* old_ctrl, void* old_slots, - size_t old_capacity) { +size_t FindNewPositionsAndTransferSlots( + CommonFields& common, const PolicyFunctions& __restrict policy, + ctrl_t* old_ctrl, void* old_slots, size_t old_capacity) { void* new_slots = common.slot_array(); const void* hash_fn = policy.hash_fn(common); const size_t slot_size = policy.slot_size; @@ -614,7 +619,8 @@ } template <ResizeNonSooMode kMode> -void ResizeNonSooImpl(CommonFields& common, const PolicyFunctions& policy, +void ResizeNonSooImpl(CommonFields& common, + const PolicyFunctions& __restrict policy, size_t new_capacity, HashtablezInfoHandle infoz) { ABSL_SWISSTABLE_ASSERT(IsValidCapacity(new_capacity)); ABSL_SWISSTABLE_ASSERT(new_capacity > policy.soo_capacity()); @@ -667,7 +673,7 @@ } void ResizeEmptyNonAllocatedTableImpl(CommonFields& common, - const PolicyFunctions& policy, + const PolicyFunctions& __restrict policy, size_t new_capacity, bool force_infoz) { ABSL_SWISSTABLE_ASSERT(IsValidCapacity(new_capacity)); ABSL_SWISSTABLE_ASSERT(new_capacity > policy.soo_capacity()); @@ -690,10 +696,9 @@ // After transferring the slot, sets control and slots in CommonFields. // It is rare to resize an SOO table with one element to a large size. // Requires: `c` contains SOO data. -void InsertOldSooSlotAndInitializeControlBytes(CommonFields& c, - const PolicyFunctions& policy, - size_t hash, ctrl_t* new_ctrl, - void* new_slots) { +void InsertOldSooSlotAndInitializeControlBytes( + CommonFields& c, const PolicyFunctions& __restrict policy, size_t hash, + ctrl_t* new_ctrl, void* new_slots) { ABSL_SWISSTABLE_ASSERT(c.size() == policy.soo_capacity()); ABSL_SWISSTABLE_ASSERT(policy.soo_enabled); size_t new_capacity = c.capacity(); @@ -728,7 +733,8 @@ ABSL_SWISSTABLE_ASSERT(common.size() == policy.soo_capacity()); } -void ResizeFullSooTable(CommonFields& common, const PolicyFunctions& policy, +void ResizeFullSooTable(CommonFields& common, + const PolicyFunctions& __restrict policy, size_t new_capacity, ResizeFullSooTableSamplingMode sampling_mode) { AssertFullSoo(common, policy); @@ -912,8 +918,8 @@ // Returns the total probe length. template <typename ProbedItem> ABSL_ATTRIBUTE_NOINLINE size_t DecodeAndInsertImpl( - CommonFields& c, const PolicyFunctions& policy, const ProbedItem* start, - const ProbedItem* end, void* old_slots) { + CommonFields& c, const PolicyFunctions& __restrict policy, + const ProbedItem* start, const ProbedItem* end, void* old_slots) { const size_t new_capacity = c.capacity(); void* new_slots = c.slot_array(); @@ -949,9 +955,9 @@ // We marked them in control bytes as kSentinel. // Hash recomputation and full probing is done here. // This use case should be extremely rare. -ABSL_ATTRIBUTE_NOINLINE size_t -ProcessProbedMarkedElements(CommonFields& c, const PolicyFunctions& policy, - ctrl_t* old_ctrl, void* old_slots, size_t start) { +ABSL_ATTRIBUTE_NOINLINE size_t ProcessProbedMarkedElements( + CommonFields& c, const PolicyFunctions& __restrict policy, ctrl_t* old_ctrl, + void* old_slots, size_t start) { size_t old_capacity = PreviousCapacity(c.capacity()); const size_t slot_size = policy.slot_size; void* new_slots = c.slot_array(); @@ -1029,7 +1035,7 @@ // Finds new position for each element and transfers it to the new slots. // Returns the total probe length. size_t DecodeAndInsertToTable(CommonFields& common, - const PolicyFunctions& policy, + const PolicyFunctions& __restrict policy, void* old_slots) const { if (pos_ == buffer_) { return 0; @@ -1103,7 +1109,7 @@ // Finds new position for each element and transfers it to the new slots. // Returns the total probe length. ABSL_ATTRIBUTE_NOINLINE size_t DecodeAndInsertToTableOverflow( - CommonFields& common, const PolicyFunctions& policy, + CommonFields& common, const PolicyFunctions& __restrict policy, void* old_slots) const { ABSL_SWISSTABLE_ASSERT(local_buffer_full_ && "must not be called when local buffer is not full"); @@ -1136,7 +1142,8 @@ // Different encoder is used depending on the capacity of the table. // Returns total probe length. template <typename Encoder> -size_t GrowToNextCapacity(CommonFields& common, const PolicyFunctions& policy, +size_t GrowToNextCapacity(CommonFields& common, + const PolicyFunctions& __restrict policy, ctrl_t* old_ctrl, void* old_slots) { using ProbedItem = typename Encoder::ProbedItem; ABSL_SWISSTABLE_ASSERT(common.capacity() <= ProbedItem::kMaxNewCapacity); @@ -1154,10 +1161,9 @@ // Grows to next capacity for relatively small tables so that even if all // elements are probed, we don't need to overflow the local buffer. // Returns total probe length. -size_t GrowToNextCapacityThatFitsInLocalBuffer(CommonFields& common, - const PolicyFunctions& policy, - ctrl_t* old_ctrl, - void* old_slots) { +size_t GrowToNextCapacityThatFitsInLocalBuffer( + CommonFields& common, const PolicyFunctions& __restrict policy, + ctrl_t* old_ctrl, void* old_slots) { ABSL_SWISSTABLE_ASSERT(common.capacity() <= kMaxLocalBufferNewCapacity); return GrowToNextCapacity< ProbedItemEncoder<ProbedItem4Bytes, /*kGuaranteedFitToBuffer=*/true>>( @@ -1167,20 +1173,20 @@ // Grows to next capacity with different encodings. Returns total probe length. // These functions are useful to simplify profile analysis. size_t GrowToNextCapacity4BytesEncoder(CommonFields& common, - const PolicyFunctions& policy, + const PolicyFunctions& __restrict policy, ctrl_t* old_ctrl, void* old_slots) { return GrowToNextCapacity<ProbedItemEncoder<ProbedItem4Bytes>>( common, policy, old_ctrl, old_slots); } size_t GrowToNextCapacity8BytesEncoder(CommonFields& common, - const PolicyFunctions& policy, + const PolicyFunctions& __restrict policy, ctrl_t* old_ctrl, void* old_slots) { return GrowToNextCapacity<ProbedItemEncoder<ProbedItem8Bytes>>( common, policy, old_ctrl, old_slots); } -size_t GrowToNextCapacity16BytesEncoder(CommonFields& common, - const PolicyFunctions& policy, - ctrl_t* old_ctrl, void* old_slots) { +size_t GrowToNextCapacity16BytesEncoder( + CommonFields& common, const PolicyFunctions& __restrict policy, + ctrl_t* old_ctrl, void* old_slots) { return GrowToNextCapacity<ProbedItemEncoder<ProbedItem16Bytes>>( common, policy, old_ctrl, old_slots); } @@ -1188,10 +1194,9 @@ // Grows to next capacity for tables with relatively large capacity so that we // can't guarantee that all probed elements fit in the local buffer. Returns // total probe length. -size_t GrowToNextCapacityOverflowLocalBuffer(CommonFields& common, - const PolicyFunctions& policy, - ctrl_t* old_ctrl, - void* old_slots) { +size_t GrowToNextCapacityOverflowLocalBuffer( + CommonFields& common, const PolicyFunctions& __restrict policy, + ctrl_t* old_ctrl, void* old_slots) { const size_t new_capacity = common.capacity(); if (ABSL_PREDICT_TRUE(new_capacity <= ProbedItem4Bytes::kMaxNewCapacity)) { return GrowToNextCapacity4BytesEncoder(common, policy, old_ctrl, old_slots); @@ -1207,7 +1212,7 @@ // capacity of the table. Returns total probe length. ABSL_ATTRIBUTE_NOINLINE size_t GrowToNextCapacityDispatch(CommonFields& common, - const PolicyFunctions& policy, + const PolicyFunctions& __restrict policy, ctrl_t* old_ctrl, void* old_slots) { const size_t new_capacity = common.capacity(); if (ABSL_PREDICT_TRUE(new_capacity <= kMaxLocalBufferNewCapacity)) { @@ -1221,9 +1226,9 @@ // Grows to next capacity and prepares insert for the given new_hash. // Returns the offset of the new element. -size_t GrowToNextCapacityAndPrepareInsert(CommonFields& common, - const PolicyFunctions& policy, - size_t new_hash) { +size_t GrowToNextCapacityAndPrepareInsert( + CommonFields& common, const PolicyFunctions& __restrict policy, + size_t new_hash) { ABSL_SWISSTABLE_ASSERT(common.growth_left() == 0); const size_t old_capacity = common.capacity(); ABSL_SWISSTABLE_ASSERT(old_capacity == 0 || @@ -1321,9 +1326,9 @@ // Called whenever the table needs to vacate empty slots either by removing // tombstones via rehash or growth to next capacity. ABSL_ATTRIBUTE_NOINLINE -size_t RehashOrGrowToNextCapacityAndPrepareInsert(CommonFields& common, - const PolicyFunctions& policy, - size_t new_hash) { +size_t RehashOrGrowToNextCapacityAndPrepareInsert( + CommonFields& common, const PolicyFunctions& __restrict policy, + size_t new_hash) { const size_t cap = common.capacity(); ABSL_ASSUME(cap > 0); if (cap > Group::kWidth && @@ -1380,7 +1385,8 @@ // Slow path for PrepareInsertNonSoo that is called when the table has deleted // slots or need to be resized or rehashed. size_t PrepareInsertNonSooSlow(CommonFields& common, - const PolicyFunctions& policy, size_t hash) { + const PolicyFunctions& __restrict policy, + size_t hash) { const GrowthInfo growth_info = common.growth_info(); ABSL_SWISSTABLE_ASSERT(!growth_info.HasNoDeletedAndGrowthLeft()); if (ABSL_PREDICT_TRUE(growth_info.HasNoGrowthLeftAndNoDeleted())) { @@ -1402,7 +1408,6 @@ return target.offset; } - // Resizes empty non-allocated SOO table to NextCapacity(SooCapacity()), // forces the table to be sampled and prepares the insert. // SOO tables need to switch from SOO to heap in order to store the infoz. @@ -1411,7 +1416,8 @@ // 2. `c.empty()`. ABSL_ATTRIBUTE_NOINLINE size_t GrowEmptySooTableToNextCapacityForceSamplingAndPrepareInsert( - CommonFields& common, const PolicyFunctions& policy, size_t new_hash) { + CommonFields& common, const PolicyFunctions& __restrict policy, + size_t new_hash) { ResizeEmptyNonAllocatedTableImpl(common, policy, NextCapacity(SooCapacity()), /*force_infoz=*/true); PrepareInsertCommon(common); @@ -1428,9 +1434,9 @@ // 2. `c.empty()`. // 3. `new_size > policy.soo_capacity()`. // The table will be attempted to be sampled. -void ReserveEmptyNonAllocatedTableToFitNewSize(CommonFields& common, - const PolicyFunctions& policy, - size_t new_size) { +void ReserveEmptyNonAllocatedTableToFitNewSize( + CommonFields& common, const PolicyFunctions& __restrict policy, + size_t new_size) { ValidateMaxSize(new_size, policy.slot_size); ABSL_ASSUME(new_size > 0); ResizeEmptyNonAllocatedTableImpl(common, policy, SizeToCapacity(new_size), @@ -1447,7 +1453,8 @@ // 1. `c.capacity() > policy.soo_capacity()` OR `!c.empty()`. // Reserving already allocated tables is considered to be a rare case. ABSL_ATTRIBUTE_NOINLINE void ReserveAllocatedTable( - CommonFields& common, const PolicyFunctions& policy, size_t new_size) { + CommonFields& common, const PolicyFunctions& __restrict policy, + size_t new_size) { const size_t cap = common.capacity(); ValidateMaxSize(new_size, policy.slot_size); ABSL_ASSUME(new_size > 0); @@ -1474,15 +1481,16 @@ return &common; } -void ResizeAllocatedTableWithSeedChange(CommonFields& common, - const PolicyFunctions& policy, - size_t new_capacity) { +void ResizeAllocatedTableWithSeedChange( + CommonFields& common, const PolicyFunctions& __restrict policy, + size_t new_capacity) { ResizeNonSooImpl<ResizeNonSooMode::kGuaranteedAllocated>( common, policy, new_capacity, common.infoz()); } void ReserveEmptyNonAllocatedTableToFitBucketCount( - CommonFields& common, const PolicyFunctions& policy, size_t bucket_count) { + CommonFields& common, const PolicyFunctions& __restrict policy, + size_t bucket_count) { size_t new_capacity = NormalizeCapacity(bucket_count); ValidateMaxSize(CapacityToGrowth(new_capacity), policy.slot_size); ResizeEmptyNonAllocatedTableImpl(common, policy, new_capacity, @@ -1491,10 +1499,9 @@ // Resizes a full SOO table to the NextCapacity(SooCapacity()). template <size_t SooSlotMemcpySize, bool TransferUsesMemcpy> -size_t GrowSooTableToNextCapacityAndPrepareInsert(CommonFields& common, - const PolicyFunctions& policy, - size_t new_hash, - ctrl_t soo_slot_ctrl) { +size_t GrowSooTableToNextCapacityAndPrepareInsert( + CommonFields& common, const PolicyFunctions& __restrict policy, + size_t new_hash, ctrl_t soo_slot_ctrl) { AssertSoo(common, policy); if (ABSL_PREDICT_FALSE(soo_slot_ctrl == ctrl_t::kEmpty)) { // The table is empty, it is only used for forced sampling of SOO tables. @@ -1566,14 +1573,15 @@ } void GrowFullSooTableToNextCapacityForceSampling( - CommonFields& common, const PolicyFunctions& policy) { + CommonFields& common, const PolicyFunctions& __restrict policy) { AssertFullSoo(common, policy); ResizeFullSooTable( common, policy, NextCapacity(SooCapacity()), ResizeFullSooTableSamplingMode::kForceSampleNoResizeIfUnsampled); } -void Rehash(CommonFields& common, const PolicyFunctions& policy, size_t n) { +void Rehash(CommonFields& common, const PolicyFunctions& __restrict policy, + size_t n) { const size_t cap = common.capacity(); auto clear_backing_array = [&]() { @@ -1640,7 +1648,7 @@ } } -void Copy(CommonFields& common, const PolicyFunctions& policy, +void Copy(CommonFields& common, const PolicyFunctions& __restrict policy, const CommonFields& other, absl::FunctionRef<void(void*, const void*)> copy_fn) { const size_t size = other.size(); @@ -1716,7 +1724,8 @@ } void ReserveTableToFitNewSize(CommonFields& common, - const PolicyFunctions& policy, size_t new_size) { + const PolicyFunctions& __restrict policy, + size_t new_size) { common.reset_reserved_growth(new_size); common.set_reservation_size(new_size); ABSL_SWISSTABLE_ASSERT(new_size > policy.soo_capacity()); @@ -1736,7 +1745,8 @@ ReserveAllocatedTable(common, policy, new_size); } -size_t PrepareInsertNonSoo(CommonFields& common, const PolicyFunctions& policy, +size_t PrepareInsertNonSoo(CommonFields& common, + const PolicyFunctions& __restrict policy, size_t hash, FindInfo target) { const bool rehash_for_bug_detection = common.should_rehash_for_bug_detection_on_insert() &&
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h index 512c946..3bc86d1 100644 --- a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h +++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
@@ -1827,11 +1827,6 @@ const PolicyFunctions& policy, size_t new_capacity); -inline void PrepareInsertCommon(CommonFields& common) { - common.increment_size(); - common.maybe_increment_generation_on_insert(); -} - // ClearBackingArray clears the backing array, either modifying it in place, // or creating a new one based on the value of "reuse". // REQUIRES: c.capacity > 0
diff --git a/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake b/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake index cc0f4bb..7d8af92 100644 --- a/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake +++ b/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake
@@ -23,6 +23,7 @@ "-Wno-implicit-int-conversion" "-Wno-missing-prototypes" "-Wno-missing-variable-declarations" + "-Wno-nullability-completeness" "-Wno-shadow" "-Wno-shorten-64-to-32" "-Wno-sign-compare" @@ -139,7 +140,6 @@ "-Winvalid-constexpr" "-Wliteral-conversion" "-Wmissing-declarations" - "-Wnullability-completeness" "-Woverlength-strings" "-Wpointer-arith" "-Wself-assign" @@ -165,6 +165,7 @@ "-Wno-implicit-int-conversion" "-Wno-missing-prototypes" "-Wno-missing-variable-declarations" + "-Wno-nullability-completeness" "-Wno-shadow" "-Wno-shorten-64-to-32" "-Wno-sign-compare"
diff --git a/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl b/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl index 35319f0..23896e9 100644 --- a/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl +++ b/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl
@@ -24,6 +24,7 @@ "-Wno-implicit-int-conversion", "-Wno-missing-prototypes", "-Wno-missing-variable-declarations", + "-Wno-nullability-completeness", "-Wno-shadow", "-Wno-shorten-64-to-32", "-Wno-sign-compare", @@ -140,7 +141,6 @@ "-Winvalid-constexpr", "-Wliteral-conversion", "-Wmissing-declarations", - "-Wnullability-completeness", "-Woverlength-strings", "-Wpointer-arith", "-Wself-assign", @@ -166,6 +166,7 @@ "-Wno-implicit-int-conversion", "-Wno-missing-prototypes", "-Wno-missing-variable-declarations", + "-Wno-nullability-completeness", "-Wno-shadow", "-Wno-shorten-64-to-32", "-Wno-sign-compare",
diff --git a/third_party/abseil-cpp/absl/copts/copts.py b/third_party/abseil-cpp/absl/copts/copts.py index 941528e..8cf8f31 100644 --- a/third_party/abseil-cpp/absl/copts/copts.py +++ b/third_party/abseil-cpp/absl/copts/copts.py
@@ -93,6 +93,7 @@ "-Wno-implicit-int-conversion", "-Wno-missing-prototypes", "-Wno-missing-variable-declarations", + "-Wno-nullability-completeness", "-Wno-shadow", "-Wno-shorten-64-to-32", "-Wno-sign-compare",
diff --git a/third_party/abseil-cpp/absl/debugging/internal/decode_rust_punycode.h b/third_party/abseil-cpp/absl/debugging/internal/decode_rust_punycode.h index b1b1c97..44aad8a 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/decode_rust_punycode.h +++ b/third_party/abseil-cpp/absl/debugging/internal/decode_rust_punycode.h
@@ -23,10 +23,10 @@ namespace debugging_internal { struct DecodeRustPunycodeOptions { - const char* punycode_begin; - const char* punycode_end; - char* out_begin; - char* out_end; + const char* absl_nonnull punycode_begin; + const char* absl_nonnull punycode_end; + char* absl_nonnull out_begin; + char* absl_nonnull out_end; }; // Given Rust Punycode in `punycode_begin .. punycode_end`, writes the
diff --git a/third_party/abseil-cpp/absl/debugging/internal/demangle.cc b/third_party/abseil-cpp/absl/debugging/internal/demangle.cc index dc15b8e..5f62ebb 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/demangle.cc +++ b/third_party/abseil-cpp/absl/debugging/internal/demangle.cc
@@ -484,36 +484,6 @@ static bool IsDigit(char c) { return c >= '0' && c <= '9'; } -// Returns true if "str" is a function clone suffix. These suffixes are used -// by GCC 4.5.x and later versions (and our locally-modified version of GCC -// 4.4.x) to indicate functions which have been cloned during optimization. -// We treat any sequence (.<alpha>+.<digit>+)+ as a function clone suffix. -// Additionally, '_' is allowed along with the alphanumeric sequence. -static bool IsFunctionCloneSuffix(const char *str) { - size_t i = 0; - while (str[i] != '\0') { - bool parsed = false; - // Consume a single [.<alpha> | _]*[.<digit>]* sequence. - if (str[i] == '.' && (IsAlpha(str[i + 1]) || str[i + 1] == '_')) { - parsed = true; - i += 2; - while (IsAlpha(str[i]) || str[i] == '_') { - ++i; - } - } - if (str[i] == '.' && IsDigit(str[i + 1])) { - parsed = true; - i += 2; - while (IsDigit(str[i])) { - ++i; - } - } - if (!parsed) - return false; - } - return true; // Consumed everything in "str". -} - static bool EndsWith(State *state, const char chr) { return state->parse_state.out_cur_idx > 0 && state->parse_state.out_cur_idx < state->out_end_idx && @@ -2932,7 +2902,7 @@ if (ParseMangledName(state)) { if (RemainingInput(state)[0] != '\0') { // Drop trailing function clone suffix, if any. - if (IsFunctionCloneSuffix(RemainingInput(state))) { + if (RemainingInput(state)[0] == '.') { return true; } // Append trailing version suffix if any.
diff --git a/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc b/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc index 9c8225a..2012184 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc +++ b/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc
@@ -556,14 +556,15 @@ EXPECT_TRUE(Demangle("_ZL3Foov.part.9.165493.constprop.775.31805", tmp, sizeof(tmp))); EXPECT_STREQ("Foo()", tmp); - // Invalid (. without anything else), should not demangle. - EXPECT_FALSE(Demangle("_ZL3Foov.", tmp, sizeof(tmp))); - // Invalid (. with mix of alpha and digits), should not demangle. - EXPECT_FALSE(Demangle("_ZL3Foov.abc123", tmp, sizeof(tmp))); - // Invalid (.clone. not followed by number), should not demangle. - EXPECT_FALSE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp))); - // Invalid (.constprop. not followed by number), should not demangle. - EXPECT_FALSE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp))); + // Other suffixes should demangle too. + EXPECT_TRUE(Demangle("_ZL3Foov.", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + EXPECT_TRUE(Demangle("_ZL3Foov.abc123", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + EXPECT_TRUE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + EXPECT_TRUE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); } TEST(Demangle, Discriminators) {
diff --git a/third_party/abseil-cpp/absl/hash/hash_test.cc b/third_party/abseil-cpp/absl/hash/hash_test.cc index c3182f1..7582f54 100644 --- a/third_party/abseil-cpp/absl/hash/hash_test.cc +++ b/third_party/abseil-cpp/absl/hash/hash_test.cc
@@ -29,6 +29,7 @@ #include <ostream> #include <set> #include <string> +#include <string_view> #include <tuple> #include <type_traits> #include <unordered_map> @@ -55,10 +56,6 @@ #include <filesystem> // NOLINT #endif -#ifdef ABSL_HAVE_STD_STRING_VIEW -#include <string_view> -#endif - namespace { using ::absl::hash_test_internal::is_hashable; @@ -495,22 +492,15 @@ } TEST(HashValueTest, WStringView) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else EXPECT_TRUE((is_hashable<std::wstring_view>::value)); EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( std::wstring_view(), std::wstring_view(L"ABC"), std::wstring_view(L"ABC"), std::wstring_view(L"Some other different string_view"), std::wstring_view(L"Iñtërnâtiônàlizætiøn")))); -#endif } TEST(HashValueTest, U16StringView) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else EXPECT_TRUE((is_hashable<std::u16string_view>::value)); EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( @@ -518,13 +508,9 @@ std::u16string_view(u"ABC"), std::u16string_view(u"Some other different string_view"), std::u16string_view(u"Iñtërnâtiônàlizætiøn")))); -#endif } TEST(HashValueTest, U32StringView) { -#ifndef ABSL_HAVE_STD_STRING_VIEW - GTEST_SKIP(); -#else EXPECT_TRUE((is_hashable<std::u32string_view>::value)); EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( @@ -532,7 +518,6 @@ std::u32string_view(U"ABC"), std::u32string_view(U"Some other different string_view"), std::u32string_view(U"Iñtërnâtiônàlizætiøn")))); -#endif } TEST(HashValueTest, StdFilesystemPath) {
diff --git a/third_party/abseil-cpp/absl/hash/internal/hash.h b/third_party/abseil-cpp/absl/hash/internal/hash.h index c7916b5..63b35490 100644 --- a/third_party/abseil-cpp/absl/hash/internal/hash.h +++ b/third_party/abseil-cpp/absl/hash/internal/hash.h
@@ -65,6 +65,7 @@ #include <memory> #include <set> #include <string> +#include <string_view> #include <tuple> #include <type_traits> #include <unordered_map> @@ -92,10 +93,6 @@ #include <filesystem> // NOLINT #endif -#ifdef ABSL_HAVE_STD_STRING_VIEW -#include <string_view> -#endif - namespace absl { ABSL_NAMESPACE_BEGIN @@ -640,8 +637,6 @@ WeaklyMixedInteger{str.size()}); } -#ifdef ABSL_HAVE_STD_STRING_VIEW - // Support std::wstring_view, std::u16string_view and std::u32string_view. template <typename Char, typename H, typename = absl::enable_if_t<std::is_same<Char, wchar_t>::value || @@ -653,8 +648,6 @@ WeaklyMixedInteger{str.size()}); } -#endif // ABSL_HAVE_STD_STRING_VIEW - #if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \ (!defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) || \ __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 130000) && \
diff --git a/third_party/abseil-cpp/absl/log/CMakeLists.txt b/third_party/abseil-cpp/absl/log/CMakeLists.txt index 6aae05d..130897f 100644 --- a/third_party/abseil-cpp/absl/log/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/log/CMakeLists.txt
@@ -218,6 +218,7 @@ absl::span absl::strerror absl::strings + absl::strings_internal absl::time ) @@ -395,6 +396,7 @@ DEPS absl::config absl::strings + absl::strings_internal absl::span )
diff --git a/third_party/abseil-cpp/absl/log/internal/BUILD.bazel b/third_party/abseil-cpp/absl/log/internal/BUILD.bazel index 44ec71b..953b690 100644 --- a/third_party/abseil-cpp/absl/log/internal/BUILD.bazel +++ b/third_party/abseil-cpp/absl/log/internal/BUILD.bazel
@@ -205,6 +205,7 @@ "//absl/log:log_sink_registry", "//absl/memory", "//absl/strings", + "//absl/strings:internal", "//absl/time", "//absl/types:span", ], @@ -218,6 +219,7 @@ deps = [ "//absl/base:config", "//absl/strings", + "//absl/strings:internal", "//absl/types:span", ], )
diff --git a/third_party/abseil-cpp/absl/log/internal/BUILD.gn b/third_party/abseil-cpp/absl/log/internal/BUILD.gn index 54fe654..fda8e48d 100644 --- a/third_party/abseil-cpp/absl/log/internal/BUILD.gn +++ b/third_party/abseil-cpp/absl/log/internal/BUILD.gn
@@ -124,6 +124,7 @@ "//third_party/abseil-cpp/absl/log:log_sink_registry", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/strings:internal", "//third_party/abseil-cpp/absl/strings:string_view", "//third_party/abseil-cpp/absl/time", "//third_party/abseil-cpp/absl/types:span", @@ -134,6 +135,7 @@ public = [ "append_truncated.h" ] deps = [ "//third_party/abseil-cpp/absl/base:config", + "//third_party/abseil-cpp/absl/strings:internal", "//third_party/abseil-cpp/absl/strings:string_view", "//third_party/abseil-cpp/absl/types:span", ]
diff --git a/third_party/abseil-cpp/absl/log/internal/append_truncated.h b/third_party/abseil-cpp/absl/log/internal/append_truncated.h index f0e7912..d420a8b 100644 --- a/third_party/abseil-cpp/absl/log/internal/append_truncated.h +++ b/third_party/abseil-cpp/absl/log/internal/append_truncated.h
@@ -17,8 +17,10 @@ #include <cstddef> #include <cstring> +#include <string_view> #include "absl/base/config.h" +#include "absl/strings/internal/utf8.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" @@ -33,6 +35,32 @@ dst.remove_prefix(src.size()); return src.size(); } +// Likewise, but it also takes a wide character string and transforms it into a +// UTF-8 encoded byte string regardless of the current locale. +// - On platforms where `wchar_t` is 2 bytes (e.g., Windows), the input is +// treated as UTF-16. +// - On platforms where `wchar_t` is 4 bytes (e.g., Linux, macOS), the input +// is treated as UTF-32. +inline size_t AppendTruncated(std::wstring_view src, absl::Span<char> &dst) { + absl::strings_internal::ShiftState state; + size_t total_bytes_written = 0; + for (const wchar_t wc : src) { + // If the destination buffer might not be large enough to write the next + // character, stop. + if (dst.size() < absl::strings_internal::kMaxEncodedUTF8Size) break; + size_t bytes_written = + absl::strings_internal::WideToUtf8(wc, dst.data(), state); + if (bytes_written == static_cast<size_t>(-1)) { + // Invalid character. Encode REPLACEMENT CHARACTER (U+FFFD) instead. + constexpr wchar_t kReplacementCharacter = L'\uFFFD'; + bytes_written = absl::strings_internal::WideToUtf8(kReplacementCharacter, + dst.data(), state); + } + dst.remove_prefix(bytes_written); + total_bytes_written += bytes_written; + } + return total_bytes_written; +} // Likewise, but `n` copies of `c`. inline size_t AppendTruncated(char c, size_t n, absl::Span<char> &dst) { if (n > dst.size()) n = dst.size();
diff --git a/third_party/abseil-cpp/absl/log/internal/check_op.h b/third_party/abseil-cpp/absl/log/internal/check_op.h index dc7d19e..72534028 100644 --- a/third_party/abseil-cpp/absl/log/internal/check_op.h +++ b/third_party/abseil-cpp/absl/log/internal/check_op.h
@@ -224,7 +224,7 @@ void MakeCheckOpValueString(std::ostream& os, char v); void MakeCheckOpValueString(std::ostream& os, signed char v); void MakeCheckOpValueString(std::ostream& os, unsigned char v); -void MakeCheckOpValueString(std::ostream& os, const void* p); +void MakeCheckOpValueString(std::ostream& os, const void* absl_nullable p); namespace detect_specialization { @@ -266,8 +266,9 @@ double operator<<(std::ostream&, double value); long double operator<<(std::ostream&, long double value); bool operator<<(std::ostream&, bool value); -const void* operator<<(std::ostream&, const void* value); -const void* operator<<(std::ostream&, std::nullptr_t); +const void* absl_nullable operator<<(std::ostream&, + const void* absl_nullable value); +const void* absl_nullable operator<<(std::ostream&, std::nullptr_t); // These `char` overloads are specified like this in the standard, so we have to // write them exactly the same to ensure the call is ambiguous. @@ -281,13 +282,14 @@ template <typename Traits> unsigned char operator<<(std::basic_ostream<char, Traits>&, unsigned char); template <typename Traits> -const char* operator<<(std::basic_ostream<char, Traits>&, const char*); +const char* absl_nonnull operator<<(std::basic_ostream<char, Traits>&, + const char* absl_nonnull); template <typename Traits> -const signed char* operator<<(std::basic_ostream<char, Traits>&, - const signed char*); +const signed char* absl_nonnull operator<<(std::basic_ostream<char, Traits>&, + const signed char* absl_nonnull); template <typename Traits> -const unsigned char* operator<<(std::basic_ostream<char, Traits>&, - const unsigned char*); +const unsigned char* absl_nonnull operator<<(std::basic_ostream<char, Traits>&, + const unsigned char* absl_nonnull); // This overload triggers when the call is not ambiguous. // It means that T is being printed with some overload not on this list. @@ -312,7 +314,8 @@ void Append(absl::string_view text); void Append(size_t length, char ch); - friend void AbslFormatFlush(StringifySink* sink, absl::string_view text); + friend void AbslFormatFlush(StringifySink* absl_nonnull sink, + absl::string_view text); private: std::ostream& os_; @@ -376,10 +379,12 @@ ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(unsigned char); ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const std::string&); ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const absl::string_view&); -ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const char*); -ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const signed char*); -ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const unsigned char*); -ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void*); +ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const char* absl_nonnull); +ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN( + const signed char* absl_nonnull); +ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN( + const unsigned char* absl_nonnull); +ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void* absl_nonnull); #undef ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN // `ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT` skips formatting the Check_OP result
diff --git a/third_party/abseil-cpp/absl/log/internal/log_message.cc b/third_party/abseil-cpp/absl/log/internal/log_message.cc index aaaaf03..07d17a02 100644 --- a/third_party/abseil-cpp/absl/log/internal/log_message.cc +++ b/third_party/abseil-cpp/absl/log/internal/log_message.cc
@@ -27,10 +27,12 @@ #include <algorithm> #include <array> #include <atomic> +#include <cwchar> #include <ios> #include <memory> #include <ostream> #include <string> +#include <string_view> #include <tuple> #include "absl/base/attributes.h" @@ -47,12 +49,14 @@ #include "absl/log/internal/globals.h" #include "absl/log/internal/log_format.h" #include "absl/log/internal/log_sink_set.h" +#include "absl/log/internal/nullguard.h" #include "absl/log/internal/proto.h" #include "absl/log/internal/structured_proto.h" #include "absl/log/log_entry.h" #include "absl/log/log_sink.h" #include "absl/log/log_sink_registry.h" #include "absl/memory/memory.h" +#include "absl/strings/internal/utf8.h" #include "absl/strings/string_view.h" #include "absl/time/clock.h" #include "absl/time/time.h" @@ -403,6 +407,35 @@ CopyToEncodedBuffer<StringType::kNotLiteral>(v); return *this; } + +LogMessage& LogMessage::operator<<(const std::wstring& v) { + CopyToEncodedBuffer<StringType::kNotLiteral>(v); + return *this; +} + +LogMessage& LogMessage::operator<<(std::wstring_view v) { + CopyToEncodedBuffer<StringType::kNotLiteral>(v); + return *this; +} + +template <> +LogMessage& LogMessage::operator<< <const wchar_t*>( + const wchar_t* absl_nullable const& v) { + if (v == nullptr) { + CopyToEncodedBuffer<StringType::kNotLiteral>( + absl::string_view(kCharNull.data(), kCharNull.size() - 1)); + } else { + CopyToEncodedBuffer<StringType::kNotLiteral>( + std::wstring_view(v, wcsnlen(v, data_->encoded_remaining().size()))); + } + return *this; +} + +LogMessage& LogMessage::operator<<(wchar_t v) { + CopyToEncodedBuffer<StringType::kNotLiteral>(std::wstring_view(&v, 1)); + return *this; +} + LogMessage& LogMessage::operator<<(std::ostream& (*m)(std::ostream& os)) { OstreamView view(*data_); data_->manipulated << m; @@ -625,6 +658,37 @@ template void LogMessage::CopyToEncodedBuffer< LogMessage::StringType::kNotLiteral>(char ch, size_t num); +template <LogMessage::StringType str_type> +void LogMessage::CopyToEncodedBuffer(std::wstring_view str) { + auto encoded_remaining_copy = data_->encoded_remaining(); + constexpr uint8_t tag_value = str_type == StringType::kLiteral + ? ValueTag::kStringLiteral + : ValueTag::kString; + size_t max_str_byte_length = + absl::strings_internal::kMaxEncodedUTF8Size * str.length(); + auto value_start = + EncodeMessageStart(EventTag::kValue, + BufferSizeFor(tag_value, WireType::kLengthDelimited) + + max_str_byte_length, + &encoded_remaining_copy); + auto str_start = EncodeMessageStart(tag_value, max_str_byte_length, + &encoded_remaining_copy); + if (str_start.data()) { + log_internal::AppendTruncated(str, encoded_remaining_copy); + EncodeMessageLength(str_start, &encoded_remaining_copy); + EncodeMessageLength(value_start, &encoded_remaining_copy); + data_->encoded_remaining() = encoded_remaining_copy; + } else { + // The field header(s) did not fit; zero `encoded_remaining()` so we don't + // write anything else later. + data_->encoded_remaining().remove_suffix(data_->encoded_remaining().size()); + } +} +template void LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>( + std::wstring_view str); +template void LogMessage::CopyToEncodedBuffer< + LogMessage::StringType::kNotLiteral>(std::wstring_view str); + template void LogMessage::CopyToEncodedBufferWithStructuredProtoField< LogMessage::StringType::kLiteral>(StructuredProtoField field, absl::string_view str); @@ -682,17 +746,13 @@ *this << "Check failed: " << failure_msg << " "; } -LogMessageFatal::~LogMessageFatal() { - FailWithoutStackTrace(); -} +LogMessageFatal::~LogMessageFatal() { FailWithoutStackTrace(); } LogMessageDebugFatal::LogMessageDebugFatal(const char* absl_nonnull file, int line) : LogMessage(file, line, absl::LogSeverity::kFatal) {} -LogMessageDebugFatal::~LogMessageDebugFatal() { - FailWithoutStackTrace(); -} +LogMessageDebugFatal::~LogMessageDebugFatal() { FailWithoutStackTrace(); } LogMessageQuietlyDebugFatal::LogMessageQuietlyDebugFatal( const char* absl_nonnull file, int line) @@ -700,9 +760,7 @@ SetFailQuietly(); } -LogMessageQuietlyDebugFatal::~LogMessageQuietlyDebugFatal() { - FailQuietly(); -} +LogMessageQuietlyDebugFatal::~LogMessageQuietlyDebugFatal() { FailQuietly(); } LogMessageQuietlyFatal::LogMessageQuietlyFatal(const char* absl_nonnull file, int line) @@ -717,9 +775,7 @@ *this << "Check failed: " << failure_msg << " "; } -LogMessageQuietlyFatal::~LogMessageQuietlyFatal() { - FailQuietly(); -} +LogMessageQuietlyFatal::~LogMessageQuietlyFatal() { FailQuietly(); } #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(pop) #endif
diff --git a/third_party/abseil-cpp/absl/log/internal/log_message.h b/third_party/abseil-cpp/absl/log/internal/log_message.h index e7eff47b..1aaf05e 100644 --- a/third_party/abseil-cpp/absl/log/internal/log_message.h +++ b/third_party/abseil-cpp/absl/log/internal/log_message.h
@@ -27,12 +27,15 @@ #ifndef ABSL_LOG_INTERNAL_LOG_MESSAGE_H_ #define ABSL_LOG_INTERNAL_LOG_MESSAGE_H_ +#include <wchar.h> + #include <cstddef> #include <ios> #include <memory> #include <ostream> #include <streambuf> #include <string> +#include <string_view> #include <type_traits> #include "absl/base/attributes.h" @@ -158,6 +161,13 @@ LogMessage& operator<<(const std::string& v); LogMessage& operator<<(absl::string_view v); + // Wide string overloads (since std::ostream does not provide them). + LogMessage& operator<<(const std::wstring& v); + LogMessage& operator<<(std::wstring_view v); + // `const wchar_t*` is handled by `operator<< <const wchar_t*>`. + LogMessage& operator<<(wchar_t* absl_nullable v); + LogMessage& operator<<(wchar_t v); + // Handle stream manipulators e.g. std::endl. LogMessage& operator<<(std::ostream& (*absl_nonnull m)(std::ostream& os)); LogMessage& operator<<(std::ios_base& (*absl_nonnull m)(std::ios_base& os)); @@ -169,17 +179,20 @@ // this template for every value of `SIZE` encountered in each source code // file. That significantly increases linker input sizes. Inlining is cheap // because the argument to this overload is almost always a string literal so - // the call to `strlen` can be replaced at compile time. The overload for - // `char[]` below should not be inlined. The compiler typically does not have - // the string at compile time and cannot replace the call to `strlen` so - // inlining it increases the binary size. See the discussion on + // the call to `strlen` can be replaced at compile time. The overloads for + // `char[]`/`wchar_t[]` below should not be inlined. The compiler typically + // does not have the string at compile time and cannot replace the call to + // `strlen` so inlining it increases the binary size. See the discussion on // cl/107527369. template <int SIZE> LogMessage& operator<<(const char (&buf)[SIZE]); + template <int SIZE> + LogMessage& operator<<(const wchar_t (&buf)[SIZE]); // This prevents non-const `char[]` arrays from looking like literals. template <int SIZE> LogMessage& operator<<(char (&buf)[SIZE]) ABSL_ATTRIBUTE_NOINLINE; + // `wchar_t[SIZE]` is handled by `operator<< <const wchar_t*>`. // Types that support `AbslStringify()` are serialized that way. // Types that don't support `AbslStringify()` but do support streaming into a @@ -243,6 +256,8 @@ void CopyToEncodedBuffer(absl::string_view str) ABSL_ATTRIBUTE_NOINLINE; template <StringType str_type> void CopyToEncodedBuffer(char ch, size_t num) ABSL_ATTRIBUTE_NOINLINE; + template <StringType str_type> + void CopyToEncodedBuffer(std::wstring_view str) ABSL_ATTRIBUTE_NOINLINE; // Copies `field` to the encoded buffer, then appends `str` after it // (truncating `str` if necessary to fit). @@ -273,6 +288,22 @@ absl_nonnull std::unique_ptr<LogMessageData> data_; }; +// Explicitly specializes the generic operator<< for `const wchar_t*` +// arguments. +// +// This method is used instead of a non-template `const wchar_t*` overload, +// as the latter was found to take precedence over the array template +// (`operator<<(const wchar_t(&)[SIZE])`) when handling string literals. +// This specialization ensures the array template now correctly processes +// literals. +template <> +LogMessage& LogMessage::operator<< <const wchar_t*>( + const wchar_t* absl_nullable const& v); + +inline LogMessage& LogMessage::operator<<(wchar_t* absl_nullable v) { + return operator<<(const_cast<const wchar_t*>(v)); +} + // Helper class so that `AbslStringify()` can modify the LogMessage. class StringifySink final { public: @@ -317,6 +348,12 @@ return *this; } +template <int SIZE> +LogMessage& LogMessage::operator<<(const wchar_t (&buf)[SIZE]) { + CopyToEncodedBuffer<StringType::kLiteral>(buf); + return *this; +} + // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE` template <int SIZE> LogMessage& LogMessage::operator<<(char (&buf)[SIZE]) { @@ -358,6 +395,10 @@ size_t num); extern template void LogMessage::CopyToEncodedBuffer< LogMessage::StringType::kNotLiteral>(char ch, size_t num); +extern template void LogMessage::CopyToEncodedBuffer< + LogMessage::StringType::kLiteral>(std::wstring_view str); +extern template void LogMessage::CopyToEncodedBuffer< + LogMessage::StringType::kNotLiteral>(std::wstring_view str); // `LogMessageFatal` ensures the process will exit in failure after logging this // message.
diff --git a/third_party/abseil-cpp/absl/log/log_format_test.cc b/third_party/abseil-cpp/absl/log/log_format_test.cc index ecd69683..f4e33c9 100644 --- a/third_party/abseil-cpp/absl/log/log_format_test.cc +++ b/third_party/abseil-cpp/absl/log/log_format_test.cc
@@ -15,12 +15,14 @@ #include <math.h> +#include <cstring> #include <iomanip> #include <ios> #include <limits> #include <ostream> #include <sstream> #include <string> +#include <string_view> #include <type_traits> #ifdef __ANDROID__ @@ -28,6 +30,7 @@ #endif #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/config.h" #include "absl/log/check.h" #include "absl/log/internal/test_matchers.h" #include "absl/log/log.h" @@ -44,6 +47,7 @@ using ::absl::log_internal::RawEncodedMessage; using ::absl::log_internal::TextMessage; using ::absl::log_internal::TextPrefix; +using ::testing::_; using ::testing::AllOf; using ::testing::AnyOf; using ::testing::Each; @@ -124,6 +128,33 @@ LOG(INFO) << value; } +TEST(WideCharLogFormatTest, Printable) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("€")), + ENCODED_MESSAGE(HasValues( + ElementsAre(ValueWithStr(Eq("€")))))))); + + test_sink.StartCapturingLogs(); + const wchar_t value = L'\u20AC'; + LOG(INFO) << value; +} + +TEST(WideCharLogFormatTest, Unprintable) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + // Using NEL (Next Line) Unicode character (U+0085). + // It is encoded as "\xC2\x85" in UTF-8. + constexpr wchar_t wide_value = L'\u0085'; + constexpr char value[] = "\xC2\x85"; + EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(value)), + ENCODED_MESSAGE(HasValues(ElementsAre( + ValueWithStr(Eq(value)))))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << wide_value; +} + template <typename T> class UnsignedIntLogFormatTest : public testing::Test {}; using UnsignedIntTypes = Types<unsigned short, unsigned int, // NOLINT @@ -635,7 +666,7 @@ template <typename T> class VoidPtrLogFormatTest : public testing::Test {}; -using VoidPtrTypes = Types<void *, const void *>; +using VoidPtrTypes = Types<void*, const void*>; TYPED_TEST_SUITE(VoidPtrLogFormatTest, VoidPtrTypes); TYPED_TEST(VoidPtrLogFormatTest, Null) { @@ -676,11 +707,10 @@ template <typename T> class VolatilePtrLogFormatTest : public testing::Test {}; -using VolatilePtrTypes = - Types<volatile void*, const volatile void*, volatile char*, - const volatile char*, volatile signed char*, - const volatile signed char*, volatile unsigned char*, - const volatile unsigned char*>; +using VolatilePtrTypes = Types< + volatile void*, const volatile void*, volatile char*, const volatile char*, + volatile signed char*, const volatile signed char*, volatile unsigned char*, + const volatile unsigned char*, volatile wchar_t*, const volatile wchar_t*>; TYPED_TEST_SUITE(VolatilePtrLogFormatTest, VolatilePtrTypes); TYPED_TEST(VolatilePtrLogFormatTest, Null) { @@ -784,6 +814,38 @@ LOG(INFO) << value; } +template <typename T> +class WideCharPtrLogFormatTest : public testing::Test {}; +using WideCharPtrTypes = Types<wchar_t, const wchar_t>; +TYPED_TEST_SUITE(WideCharPtrLogFormatTest, WideCharPtrTypes); + +TYPED_TEST(WideCharPtrLogFormatTest, Null) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + TypeParam* const value = nullptr; + + EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("(null)")), + ENCODED_MESSAGE(HasValues(ElementsAre( + ValueWithStr(Eq("(null)")))))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << value; +} + +TYPED_TEST(WideCharPtrLogFormatTest, NonNull) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + TypeParam data[] = {'v', 'a', 'l', 'u', 'e', '\0'}; + TypeParam* const value = data; + + EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("value")), + ENCODED_MESSAGE(HasValues(ElementsAre( + ValueWithStr(Eq("value")))))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << value; +} + TEST(BoolLogFormatTest, True) { absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); @@ -836,6 +898,17 @@ LOG(INFO) << "value"; } +TEST(LogFormatTest, WideStringLiteral) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("value")), + ENCODED_MESSAGE(HasValues(ElementsAre( + ValueWithLiteral(Eq("value")))))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << L"value"; +} + TEST(LogFormatTest, CharArray) { absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); @@ -854,6 +927,125 @@ LOG(INFO) << value; } +TEST(LogFormatTest, WideCharArray) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + wchar_t value[] = L"value"; + + EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("value")), + ENCODED_MESSAGE(HasValues(ElementsAre( + ValueWithStr(Eq("value")))))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << value; +} + +// Comprehensive test string for validating wchar_t to UTF-8 conversion. +// See details in absl/strings/internal/utf8_test.cc. +// +// clang-format off +#define ABSL_LOG_INTERNAL_WIDE_LITERAL L"Holá €1 你好 שָׁלוֹם 👍🏻🇺🇸👩❤️💋👨 中" +#define ABSL_LOG_INTERNAL_UTF8_LITERAL u8"Holá €1 你好 שָׁלוֹם 👍🏻🇺🇸👩❤️💋👨 中" +// clang-format on + +absl::string_view GetUtf8TestString() { + // `u8""` forces UTF-8 encoding; MSVC will default to e.g. CP1252 (and warn) + // without it. However, the resulting character type differs between pre-C++20 + // (`char`) and C++20 (`char8_t`). So we reinterpret_cast to `char*` and wrap + // it in a `string_view`. + static const absl::string_view kUtf8TestString( + reinterpret_cast<const char*>(ABSL_LOG_INTERNAL_UTF8_LITERAL), + sizeof(ABSL_LOG_INTERNAL_UTF8_LITERAL) - 1); + return kUtf8TestString; +} + +template <typename T> +class WideStringLogFormatTest : public testing::Test {}; +using StringTypes = + Types<std::wstring, const std::wstring, wchar_t[], const wchar_t*>; +TYPED_TEST_SUITE(WideStringLogFormatTest, StringTypes); + +TYPED_TEST(WideStringLogFormatTest, NonLiterals) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + TypeParam value = ABSL_LOG_INTERNAL_WIDE_LITERAL; + absl::string_view utf8_value = GetUtf8TestString(); + + EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)), + ENCODED_MESSAGE(HasValues(ElementsAre( + ValueWithStr(Eq(utf8_value)))))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << value; +} + +TEST(WideStringLogFormatTest, StringView) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + std::wstring_view value = ABSL_LOG_INTERNAL_WIDE_LITERAL; + absl::string_view utf8_value = GetUtf8TestString(); + + EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)), + ENCODED_MESSAGE(HasValues(ElementsAre( + ValueWithStr(Eq(utf8_value)))))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << value; +} + +TEST(WideStringLogFormatTest, Literal) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + absl::string_view utf8_value = GetUtf8TestString(); + + EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)), + ENCODED_MESSAGE(HasValues(ElementsAre( + ValueWithLiteral(Eq(utf8_value)))))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << ABSL_LOG_INTERNAL_WIDE_LITERAL; +} + +#undef ABSL_LOG_INTERNAL_WIDE_LITERAL +#undef ABSL_LOG_INTERNAL_UTF8_LITERAL + +TYPED_TEST(WideStringLogFormatTest, InvalidCharactersAreReplaced) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + TypeParam value = L"AAA \xDC00 BBB"; + // NOLINTNEXTLINE(readability/utf8) + absl::string_view utf8_value = "AAA � BBB"; + + EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)), + ENCODED_MESSAGE(HasValues(ElementsAre( + ValueWithStr(Eq(utf8_value)))))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << value; +} + +TYPED_TEST(WideStringLogFormatTest, EmptyWideString) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + TypeParam value = L""; + + EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("")), + ENCODED_MESSAGE(HasValues( + ElementsAre(ValueWithStr(Eq("")))))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << value; +} + +TEST(WideStringLogFormatTest, MixedNarrowAndWideStrings) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + EXPECT_CALL(test_sink, Log(_, _, "1234")); + + test_sink.StartCapturingLogs(); + LOG(INFO) << "1" << L"2" << "3" << L"4"; +} + class CustomClass {}; std::ostream& operator<<(std::ostream& os, const CustomClass&) { return os << "CustomClass{}"; @@ -1675,6 +1867,29 @@ LOG(INFO) << std::string(2 * absl::log_internal::kLogMessageBufferSize, 'x'); } +TEST(StructuredLoggingOverflowTest, TruncatesWideStrings) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + // This message is too long and should be truncated to some unspecified size + // no greater than the buffer size but not too much less either. It should be + // truncated rather than discarded. + EXPECT_CALL( + test_sink, + Send(AllOf( + TextMessage(AllOf( + SizeIs(AllOf(Ge(absl::log_internal::kLogMessageBufferSize - 256), + Le(absl::log_internal::kLogMessageBufferSize))), + Each(Eq('x')))), + ENCODED_MESSAGE(HasOneStrThat(AllOf( + SizeIs(AllOf(Ge(absl::log_internal::kLogMessageBufferSize - 256), + Le(absl::log_internal::kLogMessageBufferSize))), + Each(Eq('x')))))))); + + test_sink.StartCapturingLogs(); + LOG(INFO) << std::wstring(2 * absl::log_internal::kLogMessageBufferSize, + L'x'); +} + struct StringLike { absl::string_view data; };
diff --git a/third_party/abseil-cpp/absl/meta/type_traits.h b/third_party/abseil-cpp/absl/meta/type_traits.h index 5e57a15..ba57e52 100644 --- a/third_party/abseil-cpp/absl/meta/type_traits.h +++ b/third_party/abseil-cpp/absl/meta/type_traits.h
@@ -38,6 +38,7 @@ #include <cstddef> #include <functional> #include <string> +#include <string_view> #include <type_traits> #include <vector> @@ -48,10 +49,6 @@ #include <span> // NOLINT(build/c++20) #endif -#ifdef ABSL_HAVE_STD_STRING_VIEW -#include <string_view> -#endif - // Defines the default alignment. `__STDCPP_DEFAULT_NEW_ALIGNMENT__` is a C++17 // feature. #if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) @@ -507,10 +504,8 @@ struct IsView : std::integral_constant<bool, std::is_pointer<T>::value || IsViewImpl<T>::value> {}; -#ifdef ABSL_HAVE_STD_STRING_VIEW template <typename Char, typename Traits> struct IsView<std::basic_string_view<Char, Traits>> : std::true_type {}; -#endif #ifdef __cpp_lib_span template <typename T>
diff --git a/third_party/abseil-cpp/absl/meta/type_traits_test.cc b/third_party/abseil-cpp/absl/meta/type_traits_test.cc index bcf90d73..7c2dbbcf 100644 --- a/third_party/abseil-cpp/absl/meta/type_traits_test.cc +++ b/third_party/abseil-cpp/absl/meta/type_traits_test.cc
@@ -16,6 +16,7 @@ #include <cstdint> #include <string> +#include <string_view> #include <type_traits> #include <utility> #include <vector> @@ -26,10 +27,6 @@ #include "absl/time/clock.h" #include "absl/time/time.h" -#ifdef ABSL_HAVE_STD_STRING_VIEW -#include <string_view> -#endif - namespace { using ::testing::StaticAssertTypeEq; @@ -45,12 +42,10 @@ "string is an owner, not a view"); static_assert(IsOwnerAndNotView<std::wstring>::value, "wstring is an owner, not a view"); -#ifdef ABSL_HAVE_STD_STRING_VIEW static_assert(!IsOwnerAndNotView<std::string_view>::value, "string_view is a view, not an owner"); static_assert(!IsOwnerAndNotView<std::wstring_view>::value, "wstring_view is a view, not an owner"); -#endif template <class T, class U> struct simple_pair {
diff --git a/third_party/abseil-cpp/absl/status/internal/statusor_internal.h b/third_party/abseil-cpp/absl/status/internal/statusor_internal.h index ca7c550..e9866113 100644 --- a/third_party/abseil-cpp/absl/status/internal/statusor_internal.h +++ b/third_party/abseil-cpp/absl/status/internal/statusor_internal.h
@@ -39,7 +39,8 @@ struct HasConversionOperatorToStatusOr : std::false_type {}; template <typename T, typename U> -void test(char (*)[sizeof(std::declval<U>().operator absl::StatusOr<T>())]); +void test(char (*absl_nullable)[sizeof( + std::declval<U>().operator absl::StatusOr<T>())]); template <typename T, typename U> struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))>
diff --git a/third_party/abseil-cpp/absl/status/statusor.h b/third_party/abseil-cpp/absl/status/statusor.h index 5257af0..6142a2f 100644 --- a/third_party/abseil-cpp/absl/status/statusor.h +++ b/third_party/abseil-cpp/absl/status/statusor.h
@@ -520,8 +520,8 @@ // REQUIRES: `this->ok() == true`, otherwise the behavior is undefined. // // Use `this->ok()` to verify that there is a current value. - const T* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND; - T* operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND; + const T* absl_nonnull operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND; + T* absl_nonnull operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND; // StatusOr<T>::value_or() //
diff --git a/third_party/abseil-cpp/absl/strings/cordz_test_helpers.h b/third_party/abseil-cpp/absl/strings/cordz_test_helpers.h index 98117099..66232db 100644 --- a/third_party/abseil-cpp/absl/strings/cordz_test_helpers.h +++ b/third_party/abseil-cpp/absl/strings/cordz_test_helpers.h
@@ -34,16 +34,15 @@ ABSL_NAMESPACE_BEGIN // Returns the CordzInfo for the cord, or nullptr if the cord is not sampled. -inline const cord_internal::CordzInfo* absl_nullable GetCordzInfoForTesting( +inline const cord_internal::CordzInfo* GetCordzInfoForTesting( const Cord& cord) { if (!cord.contents_.is_tree()) return nullptr; return cord.contents_.cordz_info(); } // Returns true if the provided cordz_info is in the list of sampled cords. -inline bool CordzInfoIsListed( - const cord_internal::CordzInfo* absl_nonnull cordz_info, - cord_internal::CordzSampleToken token = {}) { +inline bool CordzInfoIsListed(const cord_internal::CordzInfo* cordz_info, + cord_internal::CordzSampleToken token = {}) { for (const cord_internal::CordzInfo& info : token) { if (cordz_info == &info) return true; } @@ -121,7 +120,7 @@ // Wrapper struct managing a small CordRep `rep` struct TestCordRep { - cord_internal::CordRepFlat* absl_nonnull rep; + cord_internal::CordRepFlat* rep; TestCordRep() { rep = cord_internal::CordRepFlat::New(100);
diff --git a/third_party/abseil-cpp/absl/strings/internal/cord_internal.h b/third_party/abseil-cpp/absl/strings/internal/cord_internal.h index b55b412..cf1f703 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cord_internal.h +++ b/third_party/abseil-cpp/absl/strings/internal/cord_internal.h
@@ -635,7 +635,7 @@ poison(); } - void CopyInlineToString(std::string* absl_nonnull dst) const { + void CopyInlineToString(std::string* dst) const { assert(!is_tree()); // As Cord can store only 15 bytes it is smaller than std::string's // small string optimization buffer size. Therefore we will always trigger
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc index 103c85d1..01e4e42 100644 --- a/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc +++ b/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc
@@ -26,6 +26,7 @@ #include <cstring> #include <cwchar> #include <string> +#include <string_view> #include <type_traits> #include "absl/base/config.h" @@ -38,10 +39,6 @@ #include "absl/strings/numbers.h" #include "absl/strings/string_view.h" -#if defined(ABSL_HAVE_STD_STRING_VIEW) -#include <string_view> -#endif - namespace absl { ABSL_NAMESPACE_BEGIN namespace str_format_internal { @@ -459,13 +456,11 @@ return {ConvertStringArg(v, conv, sink)}; } -#if defined(ABSL_HAVE_STD_STRING_VIEW) StringConvertResult FormatConvertImpl(std::wstring_view v, const FormatConversionSpecImpl conv, FormatSinkImpl* sink) { return {ConvertStringArg(v.data(), v.size(), conv, sink)}; } -#endif StringPtrConvertResult FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h b/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h index 309161d..021013f 100644 --- a/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h +++ b/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h
@@ -26,6 +26,7 @@ #include <memory> #include <sstream> #include <string> +#include <string_view> #include <type_traits> #include <utility> @@ -37,10 +38,6 @@ #include "absl/strings/internal/str_format/extension.h" #include "absl/strings/string_view.h" -#if defined(ABSL_HAVE_STD_STRING_VIEW) -#include <string_view> -#endif - namespace absl { ABSL_NAMESPACE_BEGIN @@ -228,7 +225,6 @@ StringConvertResult FormatConvertImpl(string_view v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); -#if defined(ABSL_HAVE_STD_STRING_VIEW) StringConvertResult FormatConvertImpl(std::wstring_view v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); @@ -239,7 +235,6 @@ return FormatConvertImpl(absl::string_view(v.data(), v.size()), conv, sink); } #endif // !ABSL_USES_STD_STRING_VIEW -#endif // ABSL_HAVE_STD_STRING_VIEW using StringPtrConvertResult = ArgConvertResult<FormatConversionCharSetUnion( FormatConversionCharSetInternal::s, @@ -651,15 +646,10 @@ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const wchar_t*, __VA_ARGS__); \ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::wstring, __VA_ARGS__) -#if defined(ABSL_HAVE_STD_STRING_VIEW) #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \ ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_NO_WSTRING_VIEW_( \ __VA_ARGS__); \ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::wstring_view, __VA_ARGS__) -#else -#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \ - ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_NO_WSTRING_VIEW_(__VA_ARGS__) -#endif ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc index baffe05..e4fa44e 100644 --- a/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc +++ b/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
@@ -27,6 +27,7 @@ #include <set> #include <sstream> #include <string> +#include <string_view> #include <thread> // NOLINT #include <type_traits> #include <vector> @@ -46,10 +47,6 @@ #include "absl/types/optional.h" #include "absl/types/span.h" -#if defined(ABSL_HAVE_STD_STRING_VIEW) -#include <string_view> -#endif - namespace absl { ABSL_NAMESPACE_BEGIN namespace str_format_internal { @@ -322,10 +319,8 @@ TestStringConvert(std::string("hello")); TestStringConvert(std::wstring(L"hello")); TestStringConvert(string_view("hello")); -#if defined(ABSL_HAVE_STD_STRING_VIEW) TestStringConvert(std::string_view("hello")); TestStringConvert(std::wstring_view(L"hello")); -#endif // ABSL_HAVE_STD_STRING_VIEW } TEST_F(FormatConvertTest, NullString) {
diff --git a/third_party/abseil-cpp/absl/strings/str_cat.h b/third_party/abseil-cpp/absl/strings/str_cat.h index eafd8a3f..84db0f6 100644 --- a/third_party/abseil-cpp/absl/strings/str_cat.h +++ b/third_party/abseil-cpp/absl/strings/str_cat.h
@@ -111,7 +111,7 @@ #include "absl/strings/numbers.h" #include "absl/strings/string_view.h" -#if defined(ABSL_HAVE_STD_STRING_VIEW) && !defined(ABSL_USES_STD_STRING_VIEW) +#if !defined(ABSL_USES_STD_STRING_VIEW) #include <string_view> #endif @@ -191,26 +191,26 @@ template <typename Int> explicit Hex( Int v, PadSpec spec = absl::kNoPad, - typename std::enable_if<sizeof(Int) == 1 && - !std::is_pointer<Int>::value>::type* = nullptr) + std::enable_if_t<sizeof(Int) == 1 && !std::is_pointer<Int>::value, bool> = + true) : Hex(spec, static_cast<uint8_t>(v)) {} template <typename Int> explicit Hex( Int v, PadSpec spec = absl::kNoPad, - typename std::enable_if<sizeof(Int) == 2 && - !std::is_pointer<Int>::value>::type* = nullptr) + std::enable_if_t<sizeof(Int) == 2 && !std::is_pointer<Int>::value, bool> = + true) : Hex(spec, static_cast<uint16_t>(v)) {} template <typename Int> explicit Hex( Int v, PadSpec spec = absl::kNoPad, - typename std::enable_if<sizeof(Int) == 4 && - !std::is_pointer<Int>::value>::type* = nullptr) + std::enable_if_t<sizeof(Int) == 4 && !std::is_pointer<Int>::value, bool> = + true) : Hex(spec, static_cast<uint32_t>(v)) {} template <typename Int> explicit Hex( Int v, PadSpec spec = absl::kNoPad, - typename std::enable_if<sizeof(Int) == 8 && - !std::is_pointer<Int>::value>::type* = nullptr) + std::enable_if_t<sizeof(Int) == 8 && !std::is_pointer<Int>::value, bool> = + true) : Hex(spec, static_cast<uint64_t>(v)) {} template <typename Pointee> explicit Hex(Pointee* absl_nullable v, PadSpec spec = absl::kNoPad) @@ -262,7 +262,7 @@ template <typename Int> explicit Dec(Int v, PadSpec spec = absl::kNoPad, - typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr) + std::enable_if_t<sizeof(Int) <= 8, bool> = true) : value(v >= 0 ? static_cast<uint64_t>(v) : uint64_t{0} - static_cast<uint64_t>(v)), width(spec == absl::kNoPad ? 1 @@ -366,7 +366,7 @@ ABSL_ATTRIBUTE_LIFETIME_BOUND) : piece_(pc) {} -#if defined(ABSL_HAVE_STD_STRING_VIEW) && !defined(ABSL_USES_STD_STRING_VIEW) +#if !defined(ABSL_USES_STD_STRING_VIEW) AlphaNum(std::string_view pc // NOLINT(runtime/explicit) ABSL_ATTRIBUTE_LIFETIME_BOUND) : piece_(pc.data(), pc.size()) {}
diff --git a/third_party/abseil-cpp/absl/strings/str_cat_test.cc b/third_party/abseil-cpp/absl/strings/str_cat_test.cc index 4de379eb5..a3bd42c 100644 --- a/third_party/abseil-cpp/absl/strings/str_cat_test.cc +++ b/third_party/abseil-cpp/absl/strings/str_cat_test.cc
@@ -21,6 +21,7 @@ #include <cstdlib> #include <limits> #include <string> +#include <string_view> #include <vector> #include "gtest/gtest.h" @@ -28,10 +29,6 @@ #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" -#if defined(ABSL_HAVE_STD_STRING_VIEW) -#include <string_view> -#endif - #ifdef __ANDROID__ // Android assert messages only go to system log, so death tests cannot inspect // the message for matching. @@ -219,13 +216,11 @@ EXPECT_EQ(result, ""); } -#if defined(ABSL_HAVE_STD_STRING_VIEW) TEST(StrCat, StdStringView) { std::string_view pieces[] = {"Hello", ", ", "World", "!"}; EXPECT_EQ(absl::StrCat(pieces[0], pieces[1], pieces[2], pieces[3]), "Hello, World!"); } -#endif // ABSL_HAVE_STD_STRING_VIEW TEST(StrCat, NullConstCharPtr) { const char* null = nullptr;
diff --git a/third_party/abseil-cpp/absl/strings/string_view_test.cc b/third_party/abseil-cpp/absl/strings/string_view_test.cc index 7064cc7..0a2a7a97 100644 --- a/third_party/abseil-cpp/absl/strings/string_view_test.cc +++ b/third_party/abseil-cpp/absl/strings/string_view_test.cc
@@ -34,7 +34,7 @@ #include "absl/base/config.h" #include "absl/meta/type_traits.h" -#if defined(ABSL_HAVE_STD_STRING_VIEW) || defined(__ANDROID__) +#if defined(ABSL_USES_STD_STRING_VIEW) || defined(__ANDROID__) // We don't control the death messaging when using std::string_view. // Android assert messages only go to system log, so death tests cannot inspect // the message for matching.
diff --git a/third_party/abseil-cpp/absl/strings/substitute.h b/third_party/abseil-cpp/absl/strings/substitute.h index 08f64e9..c93b1cc 100644 --- a/third_party/abseil-cpp/absl/strings/substitute.h +++ b/third_party/abseil-cpp/absl/strings/substitute.h
@@ -187,12 +187,13 @@ // vector<bool>::reference and const_reference require special help to convert // to `Arg` because it requires two user defined conversions. - template <typename T, - absl::enable_if_t< - std::is_class<T>::value && - (std::is_same<T, std::vector<bool>::reference>::value || - std::is_same<T, std::vector<bool>::const_reference>::value)>* = - nullptr> + template < + typename T, + std::enable_if_t< + std::is_class<T>::value && + (std::is_same<T, std::vector<bool>::reference>::value || + std::is_same<T, std::vector<bool>::const_reference>::value), + bool> = true> Arg(T value) // NOLINT(google-explicit-constructor) : Arg(static_cast<bool>(value)) {} @@ -237,7 +238,7 @@ : (1 << (*format - '0')); } -constexpr const char* SkipNumber(const char* absl_nonnull format) { +constexpr const char* absl_nonnull SkipNumber(const char* absl_nonnull format) { return !*format ? format : (format + 1); }
diff --git a/third_party/abseil-cpp/absl/types/span.h b/third_party/abseil-cpp/absl/types/span.h index 444b2ae6..39e6a8a5 100644 --- a/third_party/abseil-cpp/absl/types/span.h +++ b/third_party/abseil-cpp/absl/types/span.h
@@ -202,10 +202,11 @@ public: using element_type = T; using value_type = absl::remove_cv_t<T>; - // TODO(b/316099902) - pointer should be Nullable<T*>, but this makes it hard - // to recognize foreach loops as safe. - using pointer = T*; - using const_pointer = const T*; + // TODO(b/316099902) - pointer should be absl_nullable, but this makes it hard + // to recognize foreach loops as safe. absl_nullability_unknown is currently + // used to suppress -Wnullability-completeness warnings. + using pointer = T* absl_nullability_unknown; + using const_pointer = const T* absl_nullability_unknown; using reference = T&; using const_reference = const T&; using iterator = pointer;
diff --git a/third_party/abseil-cpp/ci/cmake_common.sh b/third_party/abseil-cpp/ci/cmake_common.sh index 3e14ca3..484230cd 100644 --- a/third_party/abseil-cpp/ci/cmake_common.sh +++ b/third_party/abseil-cpp/ci/cmake_common.sh
@@ -14,6 +14,6 @@ # The commit of GoogleTest to be used in the CMake tests in this directory. # Keep this in sync with the commit in the MODULE.bazel file. -readonly ABSL_GOOGLETEST_VERSION="1.16.0" +readonly ABSL_GOOGLETEST_VERSION="1.17.0" readonly ABSL_GOOGLETEST_DOWNLOAD_URL="https://github.com/google/googletest/releases/download/v${ABSL_GOOGLETEST_VERSION}/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
diff --git a/third_party/abseil-cpp/ci/linux_arm_clang-latest_libcxx_bazel.sh b/third_party/abseil-cpp/ci/linux_arm_clang-latest_libcxx_bazel.sh index d9e5992..631a8bd 100755 --- a/third_party/abseil-cpp/ci/linux_arm_clang-latest_libcxx_bazel.sh +++ b/third_party/abseil-cpp/ci/linux_arm_clang-latest_libcxx_bazel.sh
@@ -51,12 +51,12 @@ BAZEL_EXTRA_ARGS="--remote_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}" fi -# Avoid depending on external sites like GitHub by checking --distdir for -# external dependencies first. -# https://docs.bazel.build/versions/master/guide.html#distdir -if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then - DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}" - BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}" +# Use Bazel Vendor mode to reduce reliance on external dependencies. +# See https://bazel.build/external/vendor and the Dockerfile for +# an explaination of how this works. +if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then + DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}" + BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}" fi for std in ${STD}; do @@ -71,13 +71,13 @@ --rm \ ${DOCKER_EXTRA_ARGS:-} \ ${DOCKER_CONTAINER} \ - /bin/sh -c " + /bin/bash --login -c " cp -r /abseil-cpp-ro/* /abseil-cpp/ if [ -n \"${ALTERNATE_OPTIONS:-}\" ]; then cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1 fi /usr/local/bin/bazel test ... \ - --action_env=CC=clang-18 \ + --action_env=CC=clang-19 \ --compilation_mode=\"${compilation_mode}\" \ --copt=\"${exceptions_mode}\" \ --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \
diff --git a/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh b/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh index c83f3a0..cfc5510 100755 --- a/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh +++ b/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -73,32 +73,33 @@ --rm \ ${DOCKER_EXTRA_ARGS:-} \ ${DOCKER_CONTAINER} \ + /bin/bash --login -c " /usr/local/bin/bazel test ... \ - --action_env="CC=/opt/llvm/clang/bin/clang" \ - --action_env="BAZEL_CXXOPTS=-std=${std}:-nostdinc++" \ - --action_env="BAZEL_LINKOPTS=-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \ - --action_env="CPLUS_INCLUDE_PATH=/opt/llvm/libcxx/include/c++/v1" \ - --compilation_mode="${compilation_mode}" \ - --copt="${exceptions_mode}" \ - --copt="-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1" \ - --copt="-fsanitize=address" \ - --copt="-fsanitize=${UBSAN_CHECKS}" \ - --copt="-fno-sanitize-recover=${UBSAN_CHECKS}" \ - --copt="-fno-sanitize-blacklist" \ + --action_env=\"CC=/opt/llvm/clang/bin/clang\" \ + --action_env=\"BAZEL_CXXOPTS=-std=${std}:-nostdinc++\" \ + --action_env=\"BAZEL_LINKOPTS=-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib\" \ + --action_env=\"CPLUS_INCLUDE_PATH=/opt/llvm/libcxx/include/c++/v1\" \ + --compilation_mode=\"${compilation_mode}\" \ + --copt=\"${exceptions_mode}\" \ + --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \ + --copt=\"-fsanitize=address\" \ + --copt=\"-fsanitize=${UBSAN_CHECKS}\" \ + --copt=\"-fno-sanitize-recover=${UBSAN_CHECKS}\" \ + --copt=\"-fno-sanitize-blacklist\" \ --copt=-Werror \ --enable_bzlmod=true \ --features=external_include_paths \ --keep_going \ - --linkopt="-fsanitize=address" \ - --linkopt="-fsanitize-link-c++-runtime" \ + --linkopt=\"-fsanitize=address\" \ + --linkopt=\"-fsanitize-link-c++-runtime\" \ --show_timestamps \ - --test_env="ASAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer" \ - --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \ - --test_env="UBSAN_OPTIONS=print_stacktrace=1" \ - --test_env="UBSAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer" \ + --test_env=\"ASAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer\" \ + --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \ + --test_env=\"UBSAN_OPTIONS=print_stacktrace=1\" \ + --test_env=\"UBSAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer\" \ --test_output=errors \ - --test_tag_filters="-benchmark,-noasan" \ - ${BAZEL_EXTRA_ARGS:-} + --test_tag_filters=\"-benchmark,-noasan\" \ + ${BAZEL_EXTRA_ARGS:-}" done done done
diff --git a/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_bazel.sh b/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_bazel.sh index 832a9d8b..5c51d15 100755 --- a/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_bazel.sh +++ b/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_bazel.sh
@@ -51,12 +51,12 @@ BAZEL_EXTRA_ARGS="--remote_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}" fi -# Avoid depending on external sites like GitHub by checking --distdir for -# external dependencies first. -# https://docs.bazel.build/versions/master/guide.html#distdir -if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then - DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}" - BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}" +# Use Bazel Vendor mode to reduce reliance on external dependencies. +# See https://bazel.build/external/vendor and the Dockerfile for +# an explaination of how this works. +if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then + DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}" + BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}" fi for std in ${STD}; do @@ -71,7 +71,7 @@ --rm \ ${DOCKER_EXTRA_ARGS:-} \ ${DOCKER_CONTAINER} \ - /bin/sh -c " + /bin/bash --login -c " cp -r /abseil-cpp-ro/* /abseil-cpp/ if [ -n \"${ALTERNATE_OPTIONS:-}\" ]; then cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
diff --git a/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_tsan_bazel.sh b/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_tsan_bazel.sh index 82b4dd1..c9ea22d 100755 --- a/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_tsan_bazel.sh +++ b/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_tsan_bazel.sh
@@ -51,12 +51,12 @@ BAZEL_EXTRA_ARGS="--remote_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}" fi -# Avoid depending on external sites like GitHub by checking --distdir for -# external dependencies first. -# https://docs.bazel.build/versions/master/guide.html#distdir -if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then - DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}" - BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}" +# Use Bazel Vendor mode to reduce reliance on external dependencies. +# See https://bazel.build/external/vendor and the Dockerfile for +# an explaination of how this works. +if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then + DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}" + BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}" fi for std in ${STD}; do @@ -70,28 +70,29 @@ --rm \ ${DOCKER_EXTRA_ARGS:-} \ ${DOCKER_CONTAINER} \ + /bin/bash --login -c " /usr/local/bin/bazel test ... \ - --action_env="CC=/opt/llvm/clang/bin/clang" \ - --action_env="BAZEL_CXXOPTS=-std=${std}:-nostdinc++" \ - --action_env="BAZEL_LINKOPTS=-L/opt/llvm/libcxx-tsan/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx-tsan/lib" \ - --action_env="CPLUS_INCLUDE_PATH=/opt/llvm/libcxx-tsan/include/c++/v1" \ - --build_tag_filters="-notsan" \ - --compilation_mode="${compilation_mode}" \ - --copt="${exceptions_mode}" \ - --copt="-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1" \ - --copt="-fsanitize=thread" \ - --copt="-fno-sanitize-blacklist" \ + --action_env=\"CC=/opt/llvm/clang/bin/clang\" \ + --action_env=\"BAZEL_CXXOPTS=-std=${std}:-nostdinc++\" \ + --action_env=\"BAZEL_LINKOPTS=-L/opt/llvm/libcxx-tsan/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx-tsan/lib\" \ + --action_env=\"CPLUS_INCLUDE_PATH=/opt/llvm/libcxx-tsan/include/c++/v1\" \ + --build_tag_filters=\"-notsan\" \ + --compilation_mode=\"${compilation_mode}\" \ + --copt=\"${exceptions_mode}\" \ + --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \ + --copt=\"-fsanitize=thread\" \ + --copt=\"-fno-sanitize-blacklist\" \ --copt=-Werror \ --enable_bzlmod=true \ --features=external_include_paths \ --keep_going \ - --linkopt="-fsanitize=thread" \ + --linkopt=\"-fsanitize=thread\" \ --show_timestamps \ - --test_env="TSAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer" \ - --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \ + --test_env=\"TSAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer\" \ + --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \ --test_output=errors \ - --test_tag_filters="-benchmark,-notsan" \ - ${BAZEL_EXTRA_ARGS:-} + --test_tag_filters=\"-benchmark,-notsan\" \ + ${BAZEL_EXTRA_ARGS:-}" done done done
diff --git a/third_party/abseil-cpp/ci/linux_clang-latest_libstdcxx_bazel.sh b/third_party/abseil-cpp/ci/linux_clang-latest_libstdcxx_bazel.sh index 06aef62..a1620e0 100755 --- a/third_party/abseil-cpp/ci/linux_clang-latest_libstdcxx_bazel.sh +++ b/third_party/abseil-cpp/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -51,12 +51,12 @@ BAZEL_EXTRA_ARGS="--remote_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}" fi -# Avoid depending on external sites like GitHub by checking --distdir for -# external dependencies first. -# https://docs.bazel.build/versions/master/guide.html#distdir -if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then - DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}" - BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}" +# Use Bazel Vendor mode to reduce reliance on external dependencies. +# See https://bazel.build/external/vendor and the Dockerfile for +# an explaination of how this works. +if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then + DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}" + BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}" fi for std in ${STD}; do @@ -70,26 +70,27 @@ --rm \ ${DOCKER_EXTRA_ARGS:-} \ ${DOCKER_CONTAINER} \ + /bin/bash --login -c " /usr/local/bin/bazel test ... \ - --action_env="CC=/opt/llvm/clang/bin/clang" \ - --action_env="BAZEL_CXXOPTS=-std=${std}" \ - --compilation_mode="${compilation_mode}" \ - --copt="--gcc-toolchain=/usr/local" \ - --copt="-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1" \ - --copt="${exceptions_mode}" \ - --copt="-march=haswell" \ + --action_env=\"CC=/opt/llvm/clang/bin/clang\" \ + --action_env=\"BAZEL_CXXOPTS=-std=${std}\" \ + --compilation_mode=\"${compilation_mode}\" \ + --copt=\"--gcc-toolchain=/usr/local\" \ + --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \ + --copt=\"${exceptions_mode}\" \ + --copt=\"-march=haswell\" \ --copt=-Werror \ - --define="absl=1" \ + --define=\"absl=1\" \ --enable_bzlmod=true \ --features=external_include_paths \ --keep_going \ - --linkopt="--gcc-toolchain=/usr/local" \ + --linkopt=\"--gcc-toolchain=/usr/local\" \ --show_timestamps \ - --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \ - --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \ + --test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \ + --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \ --test_output=errors \ --test_tag_filters=-benchmark \ - ${BAZEL_EXTRA_ARGS:-} + ${BAZEL_EXTRA_ARGS:-}" done done done
diff --git a/third_party/abseil-cpp/ci/linux_docker_containers.sh b/third_party/abseil-cpp/ci/linux_docker_containers.sh index 3f824a8..0f454716 100644 --- a/third_party/abseil-cpp/ci/linux_docker_containers.sh +++ b/third_party/abseil-cpp/ci/linux_docker_containers.sh
@@ -16,7 +16,7 @@ # Test scripts should source this file to get the identifiers. readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20230612" -readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20241218" -readonly LINUX_ARM_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_arm_hybrid-latest:20250224" -readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20241218" -readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20250205" +readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250430" +readonly LINUX_ARM_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_arm_hybrid-latest:20250430" +readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250430" +readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20250430"
diff --git a/third_party/abseil-cpp/ci/linux_gcc-floor_libstdcxx_bazel.sh b/third_party/abseil-cpp/ci/linux_gcc-floor_libstdcxx_bazel.sh index 74d996ab5..b683b60 100755 --- a/third_party/abseil-cpp/ci/linux_gcc-floor_libstdcxx_bazel.sh +++ b/third_party/abseil-cpp/ci/linux_gcc-floor_libstdcxx_bazel.sh
@@ -51,12 +51,12 @@ BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}" fi -# Avoid depending on external sites like GitHub by checking --distdir for -# external dependencies first. -# https://docs.bazel.build/versions/master/guide.html#distdir -if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then - DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}" - BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}" +# Use Bazel Vendor mode to reduce reliance on external dependencies. +# See https://bazel.build/external/vendor and the Dockerfile for +# an explaination of how this works. +if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then + DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}" + BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}" fi for std in ${STD}; do @@ -70,22 +70,23 @@ --rm \ ${DOCKER_EXTRA_ARGS:-} \ ${DOCKER_CONTAINER} \ + /bin/bash --login -c " /usr/local/bin/bazel test ... \ - --action_env="CC=/usr/local/bin/gcc" \ - --action_env="BAZEL_CXXOPTS=-std=${std}" \ - --compilation_mode="${compilation_mode}" \ - --copt="${exceptions_mode}" \ - --copt="-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1" \ + --action_env=\"CC=/usr/local/bin/gcc\" \ + --action_env=\"BAZEL_CXXOPTS=-std=${std}\" \ + --compilation_mode=\"${compilation_mode}\" \ + --copt=\"${exceptions_mode}\" \ + --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \ --copt=-Werror \ - --define="absl=1" \ + --define=\"absl=1\" \ --features=external_include_paths \ --keep_going \ --show_timestamps \ - --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \ - --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \ + --test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \ + --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \ --test_output=errors \ --test_tag_filters=-benchmark \ - ${BAZEL_EXTRA_ARGS:-} + ${BAZEL_EXTRA_ARGS:-}" done done done
diff --git a/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_bazel.sh b/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_bazel.sh index 2daa132..b092c1d 100755 --- a/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_bazel.sh +++ b/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -51,12 +51,12 @@ BAZEL_EXTRA_ARGS="--remote_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}" fi -# Avoid depending on external sites like GitHub by checking --distdir for -# external dependencies first. -# https://docs.bazel.build/versions/master/guide.html#distdir -if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then - DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}" - BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}" +# Use Bazel Vendor mode to reduce reliance on external dependencies. +# See https://bazel.build/external/vendor and the Dockerfile for +# an explaination of how this works. +if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then + DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}" + BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}" fi for std in ${STD}; do @@ -71,7 +71,7 @@ --rm \ ${DOCKER_EXTRA_ARGS:-} \ ${DOCKER_CONTAINER} \ - /bin/sh -c " + /bin/bash --login -c " cp -r /abseil-cpp-ro/* /abseil-cpp/ if [ -n \"${ALTERNATE_OPTIONS:-}\" ]; then cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
diff --git a/third_party/abseil-cpp/ci/macos_xcode_bazel.sh b/third_party/abseil-cpp/ci/macos_xcode_bazel.sh index 51ffde8d..b05cfac 100755 --- a/third_party/abseil-cpp/ci/macos_xcode_bazel.sh +++ b/third_party/abseil-cpp/ci/macos_xcode_bazel.sh
@@ -27,7 +27,7 @@ fi # If we are running on Kokoro, check for a versioned Bazel binary. -KOKORO_GFILE_BAZEL_BIN="bazel-8.0.0-darwin-x86_64" +KOKORO_GFILE_BAZEL_BIN="bazel-8.2.1-darwin-x86_64" if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}" chmod +x ${BAZEL_BIN} @@ -35,11 +35,10 @@ BAZEL_BIN="bazel" fi -# Avoid depending on external sites like GitHub by checking --distdir for -# external dependencies first. -# https://docs.bazel.build/versions/master/guide.html#distdir -if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then - BAZEL_EXTRA_ARGS="--distdir=${KOKORO_GFILE_DIR}/distdir ${BAZEL_EXTRA_ARGS:-}" +# Use Bazel Vendor mode to reduce reliance on external dependencies. +if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then + tar -xf "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" -C "${TMP}/" + BAZEL_EXTRA_ARGS="--vendor_dir=\"${TMP}/abseil-cpp_vendor\" ${BAZEL_EXTRA_ARGS:-}" fi # Print the compiler and Bazel versions.
diff --git a/third_party/abseil-cpp/ci/windows_clangcl_bazel.bat b/third_party/abseil-cpp/ci/windows_clangcl_bazel.bat index f9512ef..26fd5af 100755 --- a/third_party/abseil-cpp/ci/windows_clangcl_bazel.bat +++ b/third_party/abseil-cpp/ci/windows_clangcl_bazel.bat
@@ -21,6 +21,14 @@ CD %~dp0\.. if %errorlevel% neq 0 EXIT /B 1 +:: Use Bazel Vendor mode to reduce reliance on external dependencies. +IF EXIST "%KOKORO_GFILE_DIR%\distdir\abseil-cpp_vendor.tar.gz" ( + tar --force-local -xf "%KOKORO_GFILE_DIR%\distdir\abseil-cpp_vendor.tar.gz" -C c:\ + SET VENDOR_FLAG=--vendor_dir=c:\abseil-cpp_vendor +) ELSE ( + SET VENDOR_FLAG= +) + :: Set the standard version, [c++17|c++20|c++latest] :: https://msdn.microsoft.com/en-us/library/mt490614.aspx :: The default is c++17 if not set on command line. @@ -39,7 +47,7 @@ :: /google/data/rw/teams/absl/kokoro/windows. :: :: TODO(absl-team): Remove -Wno-microsoft-cast -%KOKORO_GFILE_DIR%\bazel-8.0.0-windows-x86_64.exe ^ +%KOKORO_GFILE_DIR%\bazel-8.2.1-windows-x86_64.exe ^ test ... ^ --compilation_mode=%COMPILATION_MODE% ^ --compiler=clang-cl ^ @@ -47,7 +55,6 @@ --copt=-Wno-microsoft-cast ^ --cxxopt=/std:%STD% ^ --define=absl=1 ^ - --distdir=%KOKORO_GFILE_DIR%\distdir ^ --enable_bzlmod=true ^ --extra_execution_platforms=//:x64_windows-clang-cl ^ --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl ^ @@ -55,7 +62,8 @@ --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" ^ --test_env=TZDIR="%CD%\absl\time\internal\cctz\testdata\zoneinfo" ^ --test_output=errors ^ - --test_tag_filters=-benchmark + --test_tag_filters=-benchmark ^ + %VENDOR_FLAG% if %errorlevel% neq 0 EXIT /B 1 EXIT /B 0
diff --git a/third_party/abseil-cpp/ci/windows_msvc_bazel.bat b/third_party/abseil-cpp/ci/windows_msvc_bazel.bat index e0cd016..bbb57b4 100755 --- a/third_party/abseil-cpp/ci/windows_msvc_bazel.bat +++ b/third_party/abseil-cpp/ci/windows_msvc_bazel.bat
@@ -18,6 +18,14 @@ CD %~dp0\.. if %errorlevel% neq 0 EXIT /B 1 +:: Use Bazel Vendor mode to reduce reliance on external dependencies. +IF EXIST "%KOKORO_GFILE_DIR%\distdir\abseil-cpp_vendor.tar.gz" ( + tar --force-local -xf "%KOKORO_GFILE_DIR%\distdir\abseil-cpp_vendor.tar.gz" -C c:\ + SET VENDOR_FLAG=--vendor_dir=c:\abseil-cpp_vendor +) ELSE ( + SET VENDOR_FLAG= +) + :: Set the standard version, [c++17|c++latest] :: https://msdn.microsoft.com/en-us/library/mt490614.aspx :: The default is c++17 if not set on command line. @@ -34,19 +42,19 @@ :: To upgrade Bazel, first download a new binary from :: https://github.com/bazelbuild/bazel/releases and copy it to :: /google/data/rw/teams/absl/kokoro/windows. -%KOKORO_GFILE_DIR%\bazel-8.0.0-windows-x86_64.exe ^ +"%KOKORO_GFILE_DIR%\bazel-8.2.1-windows-x86_64.exe" ^ test ... ^ --compilation_mode=%COMPILATION_MODE% ^ --copt=/WX ^ --copt=/std:%STD% ^ --define=absl=1 ^ - --distdir=%KOKORO_GFILE_DIR%\distdir ^ --enable_bzlmod=true ^ --keep_going ^ --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" ^ --test_env=TZDIR="%CD%\absl\time\internal\cctz\testdata\zoneinfo" ^ --test_output=errors ^ - --test_tag_filters=-benchmark + --test_tag_filters=-benchmark ^ + %VENDOR_FLAG% if %errorlevel% neq 0 EXIT /B 1 EXIT /B 0
diff --git a/third_party/abseil-cpp/ci/windows_msvc_cmake.bat b/third_party/abseil-cpp/ci/windows_msvc_cmake.bat index c2d9e42..62cdb70 100755 --- a/third_party/abseil-cpp/ci/windows_msvc_cmake.bat +++ b/third_party/abseil-cpp/ci/windows_msvc_cmake.bat
@@ -16,7 +16,7 @@ :: The version of GoogleTest to be used in the CMake tests in this directory. :: Keep this in sync with the version in the WORKSPACE file. -SET ABSL_GOOGLETEST_VERSION=1.16.0 +SET ABSL_GOOGLETEST_VERSION=1.17.0 SET ABSL_GOOGLETEST_DOWNLOAD_URL=https://github.com/google/googletest/releases/download/v%ABSL_GOOGLETEST_VERSION%/googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz :: Replace '\' with '/' in Windows paths for CMake.
diff --git a/third_party/abseil-cpp/symbols_arm64_dbg.def b/third_party/abseil-cpp/symbols_arm64_dbg.def index 14e46ace..c6f40ac 100644 --- a/third_party/abseil-cpp/symbols_arm64_dbg.def +++ b/third_party/abseil-cpp/symbols_arm64_dbg.def
@@ -245,6 +245,7 @@ ??$?6PEAX@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEAX@Z ??$?6PEBD@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEBD@Z ??$?6PEBX@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEBX@Z + ??$?6PEB_W@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEB_W@Z ??$?6_J@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_J@Z ??$?6_K@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_K@Z ??$?6_N@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_N@Z @@ -422,8 +423,10 @@ ??$ConvertIntArg@_W@str_format_internal@absl@@YA_N_WVFormatConversionSpecImpl@01@PEAVFormatSinkImpl@01@@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXD_K@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXD_K@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$00@LogMessage@log_internal@absl@@AEAAXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$0A@@LogMessage@log_internal@absl@@AEAAXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$CreateDefault@$0A@@CommonFields@container_internal@absl@@SA?AV012@XZ @@ -2346,10 +2349,13 @@ ??4uint128@absl@@QEAAAEAV01@_K@Z ??5absl@@YA?AVuint128@0@V10@H@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@AEBV?$basic_string@_WU?$char_traits@_W@__Cr@std@@V?$allocator@_W@23@@__Cr@std@@@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@H@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@P6AAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV345@@Z@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@P6AAEAVios_base@__Cr@std@@AEAV345@@Z@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@V?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@_W@Z ??6absl@@YA?AVuint128@0@V10@H@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@AEBVCord@0@@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@AEBVStatus@0@@Z @@ -2845,6 +2851,7 @@ ?AppendTreeToTree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@W4MethodIdentifier@CordzUpdateTracker@53@@Z ?AppendTruncated@log_internal@absl@@YA_KD_KAEAV?$Span@D@2@@Z ?AppendTruncated@log_internal@absl@@YA_KV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV?$Span@D@2@@Z + ?AppendTruncated@log_internal@absl@@YA_KV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@AEAV?$Span@D@2@@Z ?ApplyMask@MaskedPointer@flags_internal@absl@@AEAAX_K@Z ?ApplySubstitutions@strings_internal@absl@@YAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@45@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@45@@Z ?AreItersFromSameContainer@container_internal@absl@@YA_NPEBW4ctrl_t@12@0AEBQEBX1@Z @@ -3745,7 +3752,6 @@ ?Post@StdcppWaiter@synchronization_internal@absl@@QEAAXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertCommon@container_internal@absl@@YAXAEAVCommonFields@12@@Z ?PrepareInsertNonSoo@container_internal@absl@@YA_KAEAVCommonFields@12@AEBUPolicyFunctions@12@_KUFindInfo@12@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z
diff --git a/third_party/abseil-cpp/symbols_arm64_rel.def b/third_party/abseil-cpp/symbols_arm64_rel.def index c6ad2fa..ad256a4 100644 --- a/third_party/abseil-cpp/symbols_arm64_rel.def +++ b/third_party/abseil-cpp/symbols_arm64_rel.def
@@ -16,6 +16,7 @@ ??$?6PEAX@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEAX@Z ??$?6PEBD@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEBD@Z ??$?6PEBX@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEBX@Z + ??$?6PEB_W@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEB_W@Z ??$?6_J@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_J@Z ??$?6_K@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_K@Z ??$?6_N@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_N@Z @@ -57,8 +58,10 @@ ??$ConvertIntArg@_W@str_format_internal@absl@@YA_N_WVFormatConversionSpecImpl@01@PEAVFormatSinkImpl@01@@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXD_K@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXD_K@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$00@LogMessage@log_internal@absl@@AEAAXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$0A@@LogMessage@log_internal@absl@@AEAAXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$DeallocateBackingArray@$07V?$allocator@D@__Cr@std@@@container_internal@absl@@YAXPEAX_KPEAW4ctrl_t@01@11_N@Z @@ -296,9 +299,12 @@ ??4CrcCordState@crc_internal@absl@@QEAAAEAV012@AEBV012@@Z ??4FlagsUsageConfig@absl@@QEAAAEAU01@AEBU01@@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@AEBV?$basic_string@_WU?$char_traits@_W@__Cr@std@@V?$allocator@_W@23@@__Cr@std@@@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@P6AAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV345@@Z@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@P6AAEAVios_base@__Cr@std@@AEAV345@@Z@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@V?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@_W@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@AEBVCord@0@@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@AEBVStatus@0@@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@Vint128@0@@Z
diff --git a/third_party/abseil-cpp/symbols_x64_dbg.def b/third_party/abseil-cpp/symbols_x64_dbg.def index db9f1cc..3175b4f 100644 --- a/third_party/abseil-cpp/symbols_x64_dbg.def +++ b/third_party/abseil-cpp/symbols_x64_dbg.def
@@ -245,6 +245,7 @@ ??$?6PEAX@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEAX@Z ??$?6PEBD@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEBD@Z ??$?6PEBX@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEBX@Z + ??$?6PEB_W@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEB_W@Z ??$?6_J@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_J@Z ??$?6_K@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_K@Z ??$?6_N@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_N@Z @@ -422,8 +423,10 @@ ??$ConvertIntArg@_W@str_format_internal@absl@@YA_N_WVFormatConversionSpecImpl@01@PEAVFormatSinkImpl@01@@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXD_K@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXD_K@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$00@LogMessage@log_internal@absl@@AEAAXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$0A@@LogMessage@log_internal@absl@@AEAAXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$CreateDefault@$0A@@CommonFields@container_internal@absl@@SA?AV012@XZ @@ -2348,10 +2351,13 @@ ??4uint128@absl@@QEAAAEAV01@_K@Z ??5absl@@YA?AVuint128@0@V10@H@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@AEBV?$basic_string@_WU?$char_traits@_W@__Cr@std@@V?$allocator@_W@23@@__Cr@std@@@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@H@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@P6AAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV345@@Z@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@P6AAEAVios_base@__Cr@std@@AEAV345@@Z@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@V?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@_W@Z ??6absl@@YA?AVuint128@0@V10@H@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@AEBVCord@0@@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@AEBVStatus@0@@Z @@ -2847,6 +2853,7 @@ ?AppendTreeToTree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@W4MethodIdentifier@CordzUpdateTracker@53@@Z ?AppendTruncated@log_internal@absl@@YA_KD_KAEAV?$Span@D@2@@Z ?AppendTruncated@log_internal@absl@@YA_KV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV?$Span@D@2@@Z + ?AppendTruncated@log_internal@absl@@YA_KV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@AEAV?$Span@D@2@@Z ?ApplyMask@MaskedPointer@flags_internal@absl@@AEAAX_K@Z ?ApplySubstitutions@strings_internal@absl@@YAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@45@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@45@@Z ?AreItersFromSameContainer@container_internal@absl@@YA_NPEBW4ctrl_t@12@0AEBQEBX1@Z @@ -3749,7 +3756,6 @@ ?Post@StdcppWaiter@synchronization_internal@absl@@QEAAXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertCommon@container_internal@absl@@YAXAEAVCommonFields@12@@Z ?PrepareInsertNonSoo@container_internal@absl@@YA_KAEAVCommonFields@12@AEBUPolicyFunctions@12@_KUFindInfo@12@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z
diff --git a/third_party/abseil-cpp/symbols_x64_rel.def b/third_party/abseil-cpp/symbols_x64_rel.def index 05c9783c..7564af2a 100644 --- a/third_party/abseil-cpp/symbols_x64_rel.def +++ b/third_party/abseil-cpp/symbols_x64_rel.def
@@ -16,6 +16,7 @@ ??$?6PEAX@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEAX@Z ??$?6PEBD@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEBD@Z ??$?6PEBX@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEBX@Z + ??$?6PEB_W@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEB_W@Z ??$?6_J@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_J@Z ??$?6_K@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_K@Z ??$?6_N@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_N@Z @@ -57,8 +58,10 @@ ??$ConvertIntArg@_W@str_format_internal@absl@@YA_N_WVFormatConversionSpecImpl@01@PEAVFormatSinkImpl@01@@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXD_K@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXD_K@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$00@LogMessage@log_internal@absl@@AEAAXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$0A@@LogMessage@log_internal@absl@@AEAAXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$DeallocateBackingArray@$07V?$allocator@D@__Cr@std@@@container_internal@absl@@YAXPEAX_KPEAW4ctrl_t@01@11_N@Z @@ -297,9 +300,12 @@ ??4CrcCordState@crc_internal@absl@@QEAAAEAV012@AEBV012@@Z ??4FlagsUsageConfig@absl@@QEAAAEAU01@AEBU01@@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@AEBV?$basic_string@_WU?$char_traits@_W@__Cr@std@@V?$allocator@_W@23@@__Cr@std@@@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@P6AAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV345@@Z@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@P6AAEAVios_base@__Cr@std@@AEAV345@@Z@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@V?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@_W@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@AEBVCord@0@@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@AEBVStatus@0@@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@Vint128@0@@Z
diff --git a/third_party/abseil-cpp/symbols_x64_rel_asan.def b/third_party/abseil-cpp/symbols_x64_rel_asan.def index 456c01a..d12f237 100644 --- a/third_party/abseil-cpp/symbols_x64_rel_asan.def +++ b/third_party/abseil-cpp/symbols_x64_rel_asan.def
@@ -19,6 +19,7 @@ ??$?6PEAX@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEAX@Z ??$?6PEBD@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEBD@Z ??$?6PEBX@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEBX@Z + ??$?6PEB_W@LogMessage@log_internal@absl@@QEAAAEAV012@AEBQEB_W@Z ??$?6_J@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_J@Z ??$?6_K@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_K@Z ??$?6_N@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_N@Z @@ -62,8 +63,10 @@ ??$ConvertIntArg@_W@str_format_internal@absl@@YA_N_WVFormatConversionSpecImpl@01@PEAVFormatSinkImpl@01@@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXD_K@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXD_K@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AEAAXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$00@LogMessage@log_internal@absl@@AEAAXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$0A@@LogMessage@log_internal@absl@@AEAAXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$DeallocateBackingArray@$07V?$allocator@D@__Cr@std@@@container_internal@absl@@YAXPEAX_KPEAW4ctrl_t@01@11_N@Z @@ -310,9 +313,12 @@ ??4InlineData@cord_internal@absl@@QEAAAEAV012@AEBV012@@Z ??4InlineRep@Cord@absl@@QEAAAEAV012@$$QEAV012@@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@AEBV?$basic_string@_WU?$char_traits@_W@__Cr@std@@V?$allocator@_W@23@@__Cr@std@@@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@P6AAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV345@@Z@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@P6AAEAVios_base@__Cr@std@@AEAV345@@Z@Z ??6LogMessage@log_internal@absl@@QEAAAEAV012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@V?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QEAAAEAV012@_W@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@AEBVCord@0@@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@AEBVStatus@0@@Z ??6absl@@YAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAV123@Vint128@0@@Z @@ -971,7 +977,6 @@ ?Post@StdcppWaiter@synchronization_internal@absl@@QEAAXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertCommon@container_internal@absl@@YAXAEAVCommonFields@12@@Z ?PrepareInsertNonSoo@container_internal@absl@@YA_KAEAVCommonFields@12@AEBUPolicyFunctions@12@_KUFindInfo@12@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z
diff --git a/third_party/abseil-cpp/symbols_x86_dbg.def b/third_party/abseil-cpp/symbols_x86_dbg.def index 3aa6864e..a2f02fe 100644 --- a/third_party/abseil-cpp/symbols_x86_dbg.def +++ b/third_party/abseil-cpp/symbols_x86_dbg.def
@@ -245,6 +245,7 @@ ??$?6PAX@LogMessage@log_internal@absl@@QAEAAV012@ABQAX@Z ??$?6PBD@LogMessage@log_internal@absl@@QAEAAV012@ABQBD@Z ??$?6PBX@LogMessage@log_internal@absl@@QAEAAV012@ABQBX@Z + ??$?6PB_W@LogMessage@log_internal@absl@@QAEAAV012@ABQB_W@Z ??$?6_J@LogMessage@log_internal@absl@@QAEAAV012@AB_J@Z ??$?6_K@LogMessage@log_internal@absl@@QAEAAV012@AB_K@Z ??$?6_N@LogMessage@log_internal@absl@@QAEAAV012@AB_N@Z @@ -422,8 +423,10 @@ ??$ConvertIntArg@_W@str_format_internal@absl@@YA_N_WVFormatConversionSpecImpl@01@PAVFormatSinkImpl@01@@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AAEXDI@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AAEXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AAEXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AAEXDI@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AAEXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AAEXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$00@LogMessage@log_internal@absl@@AAEXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$0A@@LogMessage@log_internal@absl@@AAEXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$CreateDefault@$0A@@CommonFields@container_internal@absl@@SA?AV012@XZ @@ -2346,10 +2349,13 @@ ??4uint128@absl@@QAEAAV01@_K@Z ??5absl@@YA?AVuint128@0@V10@H@Z ??6LogMessage@log_internal@absl@@QAEAAV012@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QAEAAV012@ABV?$basic_string@_WU?$char_traits@_W@__Cr@std@@V?$allocator@_W@23@@__Cr@std@@@Z ??6LogMessage@log_internal@absl@@QAEAAV012@H@Z ??6LogMessage@log_internal@absl@@QAEAAV012@P6AAAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAV345@@Z@Z ??6LogMessage@log_internal@absl@@QAEAAV012@P6AAAVios_base@__Cr@std@@AAV345@@Z@Z ??6LogMessage@log_internal@absl@@QAEAAV012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QAEAAV012@V?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QAEAAV012@_W@Z ??6absl@@YA?AVuint128@0@V10@H@Z ??6absl@@YAAAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAV123@ABVCord@0@@Z ??6absl@@YAAAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAV123@ABVStatus@0@@Z @@ -2845,6 +2851,7 @@ ?AppendTreeToTree@InlineRep@Cord@absl@@QAEXPAUCordRep@cord_internal@3@W4MethodIdentifier@CordzUpdateTracker@53@@Z ?AppendTruncated@log_internal@absl@@YAIDIAAV?$Span@D@2@@Z ?AppendTruncated@log_internal@absl@@YAIV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAV?$Span@D@2@@Z + ?AppendTruncated@log_internal@absl@@YAIV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@AAV?$Span@D@2@@Z ?ApplyMask@MaskedPointer@flags_internal@absl@@AAEXI@Z ?ApplySubstitutions@strings_internal@absl@@YAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@45@PAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@45@@Z ?AreItersFromSameContainer@container_internal@absl@@YA_NPBW4ctrl_t@12@0ABQBX1@Z @@ -3747,7 +3754,6 @@ ?Post@StdcppWaiter@synchronization_internal@absl@@QAEXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QAEXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QAEX_JIIIG@Z - ?PrepareInsertCommon@container_internal@absl@@YAXAAVCommonFields@12@@Z ?PrepareInsertNonSoo@container_internal@absl@@YAIAAVCommonFields@12@ABUPolicyFunctions@12@IUFindInfo@12@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AAEXXZ ?PrepareToModify@Status@absl@@CAPAVStatusRep@status_internal@2@I@Z
diff --git a/third_party/abseil-cpp/symbols_x86_rel.def b/third_party/abseil-cpp/symbols_x86_rel.def index bb4bb38..3316635 100644 --- a/third_party/abseil-cpp/symbols_x86_rel.def +++ b/third_party/abseil-cpp/symbols_x86_rel.def
@@ -16,6 +16,7 @@ ??$?6PAX@LogMessage@log_internal@absl@@QAEAAV012@ABQAX@Z ??$?6PBD@LogMessage@log_internal@absl@@QAEAAV012@ABQBD@Z ??$?6PBX@LogMessage@log_internal@absl@@QAEAAV012@ABQBX@Z + ??$?6PB_W@LogMessage@log_internal@absl@@QAEAAV012@ABQB_W@Z ??$?6_J@LogMessage@log_internal@absl@@QAEAAV012@AB_J@Z ??$?6_K@LogMessage@log_internal@absl@@QAEAAV012@AB_K@Z ??$?6_N@LogMessage@log_internal@absl@@QAEAAV012@AB_N@Z @@ -57,8 +58,10 @@ ??$ConvertIntArg@_W@str_format_internal@absl@@YA_N_WVFormatConversionSpecImpl@01@PAVFormatSinkImpl@01@@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AAEXDI@Z ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AAEXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$00@LogMessage@log_internal@absl@@AAEXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AAEXDI@Z ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AAEXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$CopyToEncodedBuffer@$0A@@LogMessage@log_internal@absl@@AAEXV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$00@LogMessage@log_internal@absl@@AAEXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$CopyToEncodedBufferWithStructuredProtoField@$0A@@LogMessage@log_internal@absl@@AAEXUStructuredProtoField@12@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$DeallocateBackingArray@$03V?$allocator@D@__Cr@std@@@container_internal@absl@@YAXPAXIPAW4ctrl_t@01@II_N@Z @@ -305,9 +308,12 @@ ??4CrcCordState@crc_internal@absl@@QAEAAV012@ABV012@@Z ??4FlagsUsageConfig@absl@@QAEAAU01@ABU01@@Z ??6LogMessage@log_internal@absl@@QAEAAV012@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QAEAAV012@ABV?$basic_string@_WU?$char_traits@_W@__Cr@std@@V?$allocator@_W@23@@__Cr@std@@@Z ??6LogMessage@log_internal@absl@@QAEAAV012@P6AAAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAV345@@Z@Z ??6LogMessage@log_internal@absl@@QAEAAV012@P6AAAVios_base@__Cr@std@@AAV345@@Z@Z ??6LogMessage@log_internal@absl@@QAEAAV012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QAEAAV012@V?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@@Z + ??6LogMessage@log_internal@absl@@QAEAAV012@_W@Z ??6absl@@YAAAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAV123@ABVCord@0@@Z ??6absl@@YAAAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAV123@ABVStatus@0@@Z ??6absl@@YAAAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAV123@Vint128@0@@Z
diff --git a/third_party/android_deps/autorolled/build.gradle b/third_party/android_deps/autorolled/build.gradle index c4bd0e8..86a0abb 100644 --- a/third_party/android_deps/autorolled/build.gradle +++ b/third_party/android_deps/autorolled/build.gradle
@@ -383,7 +383,7 @@ repositories { google() mavenCentral() - // {{ANDROIDX_REPO}} + // <ANDROIDX_REPO> } dependencies {
diff --git a/third_party/android_deps/autorolled/build.gradle.template b/third_party/android_deps/autorolled/build.gradle.template index cd8939be..e92336d 100644 --- a/third_party/android_deps/autorolled/build.gradle.template +++ b/third_party/android_deps/autorolled/build.gradle.template
@@ -18,7 +18,7 @@ repositories { google() mavenCentral() - // {{ANDROIDX_REPO}} + // <ANDROIDX_REPO> } dependencies {
diff --git a/third_party/android_deps/fetch_all.py b/third_party/android_deps/fetch_all.py index 4eb470d5..bfac798 100755 --- a/third_party/android_deps/fetch_all.py +++ b/third_party/android_deps/fetch_all.py
@@ -367,10 +367,10 @@ build_gradle = os.path.join(subdir, _BUILD_GRADLE) src_path = pathlib.Path(android_deps_dir) / original_path data = src_path.read_text() - if '// {{ANDROIDX_REPO}}' in data: + if '// <ANDROIDX_REPO>' in data: version = fetch_util.get_current_androidx_version() repo_url = fetch_util.make_androidx_maven_url(version) - data = data.replace('// {{ANDROIDX_REPO}}', + data = data.replace('// <ANDROIDX_REPO>', f'maven {{ url "{repo_url}" }}') dst_path = pathlib.Path(build_android_deps_dir) / build_gradle dst_path.parent.mkdir()
diff --git a/third_party/androidx/BUILD.gn b/third_party/androidx/BUILD.gn index 4ad1c33ac..eea1a4c1 100644 --- a/third_party/androidx/BUILD.gn +++ b/third_party/androidx/BUILD.gn
@@ -23,6 +23,7 @@ ":androidx_lifecycle_lifecycle_runtime_java", ":androidx_lifecycle_lifecycle_viewmodel_java", ":androidx_lifecycle_lifecycle_viewmodel_savedstate_java", + ":androidx_navigationevent_navigationevent_java", ":androidx_savedstate_savedstate_java", ":androidx_tracing_tracing_java", "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_core_java", @@ -58,7 +59,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. androidx_android_aar_prebuilt( "androidx_annotation_annotation_experimental_java") { - aar_path = "../androidx/cipd/libs/androidx_annotation_annotation_experimental/annotation-experimental-1.5.0-SNAPSHOT.aar" + aar_path = "../androidx/cipd/libs/androidx_annotation_annotation_experimental/annotation-experimental-1.5.0.aar" info_path = "../androidx/committed/libs/androidx_annotation_annotation_experimental/androidx_annotation_annotation_experimental.info" enable_bytecode_checks = false deps = [ "//third_party/kotlin_stdlib:kotlin_stdlib_java" ] @@ -618,7 +619,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. androidx_android_aar_prebuilt("androidx_documentfile_documentfile_java") { - aar_path = "../androidx/cipd/libs/androidx_documentfile_documentfile/documentfile-1.1.0-SNAPSHOT.aar" + aar_path = "../androidx/cipd/libs/androidx_documentfile_documentfile/documentfile-1.1.0.aar" info_path = "../androidx/committed/libs/androidx_documentfile_documentfile/androidx_documentfile_documentfile.info" enable_bytecode_checks = false deps = [ @@ -1477,7 +1478,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. androidx_android_aar_prebuilt("androidx_tvprovider_tvprovider_java") { - aar_path = "../androidx/cipd/libs/androidx_tvprovider_tvprovider/tvprovider-1.1.0-SNAPSHOT.aar" + aar_path = "../androidx/cipd/libs/androidx_tvprovider_tvprovider/tvprovider-1.1.0.aar" info_path = "../androidx/committed/libs/androidx_tvprovider_tvprovider/androidx_tvprovider_tvprovider.info" enable_bytecode_checks = false deps = [ @@ -3023,6 +3024,37 @@ } # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. + androidx_java_group("androidx_navigationevent_navigationevent_java") { + # To remove visibility constraint, add this dependency to + # //third_party/androidx/build.gradle. + visibility = [ + ":*", + "//third_party/android_deps:*", + ] + deps = [ ":androidx_navigationevent_navigationevent_android_java" ] + } + + # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. + androidx_android_aar_prebuilt( + "androidx_navigationevent_navigationevent_android_java") { + aar_path = "../androidx/cipd/libs/androidx_navigationevent_navigationevent_android/navigationevent-android-1.0.0-SNAPSHOT.aar" + info_path = "../androidx/committed/libs/androidx_navigationevent_navigationevent_android/androidx_navigationevent_navigationevent_android.info" + enable_bytecode_checks = false + + # To remove visibility constraint, add this dependency to + # //third_party/androidx/build.gradle. + visibility = [ + ":*", + "//third_party/android_deps:*", + ] + deps = [ + ":androidx_annotation_annotation_java", + ":androidx_core_core_viewtree_java", + "//third_party/kotlin_stdlib:kotlin_stdlib_java", + ] + } + + # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. androidx_java_group("androidx_paging_paging_common_java") { # To remove visibility constraint, add this dependency to # //third_party/androidx/build.gradle. @@ -3105,6 +3137,7 @@ deps = [ ":androidx_collection_collection_java", ":androidx_core_core_java", + "//third_party/android_deps:org_jspecify_jspecify_java", ] }
diff --git a/third_party/androidx/additional_readme_paths.json b/third_party/androidx/additional_readme_paths.json index 8eea2cb..6122ad2 100644 --- a/third_party/androidx/additional_readme_paths.json +++ b/third_party/androidx/additional_readme_paths.json
@@ -117,6 +117,7 @@ "committed/libs/androidx_navigation_navigation_common_android", "committed/libs/androidx_navigation_navigation_compose_android", "committed/libs/androidx_navigation_navigation_runtime_android", + "committed/libs/androidx_navigationevent_navigationevent_android", "committed/libs/androidx_paging_paging_common_android", "committed/libs/androidx_paging_paging_common_ktx", "committed/libs/androidx_paging_paging_compose_android",
diff --git a/third_party/androidx/bill_of_materials.json b/third_party/androidx/bill_of_materials.json index 2e8948c..04e8d58 100644 --- a/third_party/androidx/bill_of_materials.json +++ b/third_party/androidx/bill_of_materials.json
@@ -22,7 +22,7 @@ { "name": "annotation-experimental", "group": "androidx.annotation", - "version": "1.5.0-SNAPSHOT" + "version": "1.5.0" }, { "name": "annotation-jvm", @@ -432,7 +432,7 @@ { "name": "documentfile", "group": "androidx.documentfile", - "version": "1.1.0-SNAPSHOT" + "version": "1.1.0" }, { "name": "drawerlayout", @@ -765,6 +765,16 @@ "version": "2.10.0-SNAPSHOT" }, { + "name": "navigationevent", + "group": "androidx.navigationevent", + "version": "1.0.0-SNAPSHOT" + }, + { + "name": "navigationevent-android", + "group": "androidx.navigationevent", + "version": "1.0.0-SNAPSHOT" + }, + { "name": "paging-common", "group": "androidx.paging", "version": "3.4.0-SNAPSHOT" @@ -1032,7 +1042,7 @@ { "name": "tvprovider", "group": "androidx.tvprovider", - "version": "1.1.0-SNAPSHOT" + "version": "1.1.0" }, { "name": "vectordrawable",
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle index 89d73ef..08a0495 100644 --- a/third_party/androidx/build.gradle +++ b/third_party/androidx/build.gradle
@@ -19,7 +19,7 @@ versionCache['androidx.activity:activity-compose'] = '1.12.0-SNAPSHOT' versionCache['androidx.activity:activity-ktx'] = '1.12.0-SNAPSHOT' versionCache['androidx.annotation:annotation'] = '1.10.0-SNAPSHOT' -versionCache['androidx.annotation:annotation-experimental'] = '1.5.0-SNAPSHOT' +versionCache['androidx.annotation:annotation-experimental'] = '1.5.0' versionCache['androidx.annotation:annotation-jvm'] = '1.10.0-SNAPSHOT' versionCache['androidx.appcompat:appcompat'] = '1.8.0-SNAPSHOT' versionCache['androidx.appcompat:appcompat-resources'] = '1.8.0-SNAPSHOT' @@ -101,7 +101,7 @@ versionCache['androidx.datastore:datastore-core-android'] = '1.2.0-SNAPSHOT' versionCache['androidx.datastore:datastore-core-okio'] = '1.2.0-SNAPSHOT' versionCache['androidx.datastore:datastore-core-okio-jvm'] = '1.2.0-SNAPSHOT' -versionCache['androidx.documentfile:documentfile'] = '1.1.0-SNAPSHOT' +versionCache['androidx.documentfile:documentfile'] = '1.1.0' versionCache['androidx.drawerlayout:drawerlayout'] = '1.3.0-SNAPSHOT' versionCache['androidx.dynamicanimation:dynamicanimation'] = '1.1.0' versionCache['androidx.emoji2:emoji2'] = '1.6.0-SNAPSHOT' @@ -168,6 +168,8 @@ versionCache['androidx.navigation:navigation-compose-android'] = '2.10.0-SNAPSHOT' versionCache['androidx.navigation:navigation-runtime'] = '2.10.0-SNAPSHOT' versionCache['androidx.navigation:navigation-runtime-android'] = '2.10.0-SNAPSHOT' +versionCache['androidx.navigationevent:navigationevent'] = '1.0.0-SNAPSHOT' +versionCache['androidx.navigationevent:navigationevent-android'] = '1.0.0-SNAPSHOT' versionCache['androidx.paging:paging-common'] = '3.4.0-SNAPSHOT' versionCache['androidx.paging:paging-common-android'] = '3.4.0-SNAPSHOT' versionCache['androidx.paging:paging-common-ktx'] = '3.4.0-SNAPSHOT' @@ -221,7 +223,7 @@ versionCache['androidx.tracing:tracing-perfetto-binary'] = '1.0.0' versionCache['androidx.tracing:tracing-perfetto-handshake'] = '1.0.0' versionCache['androidx.transition:transition'] = '1.7.0-SNAPSHOT' -versionCache['androidx.tvprovider:tvprovider'] = '1.1.0-SNAPSHOT' +versionCache['androidx.tvprovider:tvprovider'] = '1.1.0' versionCache['androidx.vectordrawable:vectordrawable'] = '1.2.0' versionCache['androidx.vectordrawable:vectordrawable-animated'] = '1.2.0' versionCache['androidx.versionedparcelable:versionedparcelable'] = '1.2.1' @@ -302,7 +304,7 @@ google() maven { // This URL is generated by the fetch_all_androidx.py script. - url 'https://androidx.dev/snapshots/builds/13452791/artifacts/repository' + url 'https://androidx.dev/snapshots/builds/13464459/artifacts/repository' } mavenCentral() }
diff --git a/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium b/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium index 315e5df..fae631c 100644 --- a/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium +++ b/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium
@@ -1,7 +1,7 @@ Name: Experimental annotation Short Name: annotation-experimental -URL: https://developer.android.com/jetpack/androidx/releases/annotation#1.5.0-SNAPSHOT -Version: 1.5.0-SNAPSHOT +URL: https://developer.android.com/jetpack/androidx/releases/annotation#1.5.0 +Version: 1.5.0 License: Apache-2.0 License File: LICENSE CPEPrefix: unknown
diff --git a/third_party/androidx/committed/libs/androidx_documentfile_documentfile/README.chromium b/third_party/androidx/committed/libs/androidx_documentfile_documentfile/README.chromium index 6363a80f..d67ee2d 100644 --- a/third_party/androidx/committed/libs/androidx_documentfile_documentfile/README.chromium +++ b/third_party/androidx/committed/libs/androidx_documentfile_documentfile/README.chromium
@@ -1,7 +1,7 @@ Name: Document File Short Name: documentfile -URL: https://developer.android.com/jetpack/androidx/releases/documentfile#1.1.0-SNAPSHOT -Version: 1.1.0-SNAPSHOT +URL: https://developer.android.com/jetpack/androidx/releases/documentfile#1.1.0 +Version: 1.1.0 License: Apache-2.0 License File: LICENSE CPEPrefix: unknown
diff --git a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/LICENSE b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/LICENSE
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff --git a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium new file mode 100644 index 0000000..09b3065 --- /dev/null +++ b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium
@@ -0,0 +1,16 @@ +Name: Navigation Event +Short Name: navigationevent-android +URL: https://developer.android.com/jetpack/androidx/releases/navigationevent#1.0.0-SNAPSHOT +Version: 1.0.0-SNAPSHOT +License: Apache-2.0 +License File: LICENSE +CPEPrefix: unknown +Security Critical: yes +Shipped: yes +License Android Compatible: yes + +Description: +Provides APIs to easily intercept platform navigation events, including swipes and clicks, to provide a consistent API surface for handling these events. + +Local Modifications: +No modifications.
diff --git a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/androidx_navigationevent_navigationevent_android.info b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/androidx_navigationevent_navigationevent_android.info new file mode 100644 index 0000000..5e597cab --- /dev/null +++ b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/androidx_navigationevent_navigationevent_android.info
@@ -0,0 +1,16 @@ +# Generated by //build/android/gyp/aar.py +# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen". + +aidl = [] +assets = [] +has_classes_jar = true +has_native_libraries = false +has_proguard_flags = true +has_r_text_file = true +is_manifest_empty = true +manifest_package = "androidx.navigationevent" +resources = [ + "res/values/values.xml" +] +subjar_tuples = [] +subjars = []
diff --git a/third_party/androidx/committed/libs/androidx_tvprovider_tvprovider/README.chromium b/third_party/androidx/committed/libs/androidx_tvprovider_tvprovider/README.chromium index d691a7f..203264d 100644 --- a/third_party/androidx/committed/libs/androidx_tvprovider_tvprovider/README.chromium +++ b/third_party/androidx/committed/libs/androidx_tvprovider_tvprovider/README.chromium
@@ -1,7 +1,7 @@ Name: TV Provider Short Name: tvprovider -URL: https://developer.android.com/jetpack/androidx/releases/tvprovider#1.1.0-SNAPSHOT -Version: 1.1.0-SNAPSHOT +URL: https://developer.android.com/jetpack/androidx/releases/tvprovider#1.1.0 +Version: 1.1.0 License: Apache-2.0 License File: LICENSE CPEPrefix: unknown
diff --git a/third_party/angle b/third_party/angle index 2d61c57..02bc00c 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 2d61c576f0dd8a1a5ef5adeefe19101c5ea64eb7 +Subproject commit 02bc00c406237810c435277a13f742d14cd16782
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 8e80459f..e340190 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -2149,26 +2149,6 @@ "Prerender2EarlyDocumentLifecycleUpdate", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kPrerender2WarmUpCompositor, - "Prerender2WarmUpCompositor", - base::FEATURE_ENABLED_BY_DEFAULT); -const base::FeatureParam<Prerender2WarmUpCompositorTriggerPoint>::Option - prerender2_warm_up_compositor_trigger_point[] = { - {Prerender2WarmUpCompositorTriggerPoint::kDidCommitLoad, - "did_commit_load"}, - {Prerender2WarmUpCompositorTriggerPoint:: - kDidDispatchDOMContentLoadedEvent, - "did_dispatch_dom_content_loaded_event"}, - {Prerender2WarmUpCompositorTriggerPoint::kDidFinishLoad, - "did_finish_load"}, -}; -BASE_FEATURE_ENUM_PARAM(Prerender2WarmUpCompositorTriggerPoint, - kPrerender2WarmUpCompositorTriggerPoint, - &kPrerender2WarmUpCompositor, - "trigger_point", - Prerender2WarmUpCompositorTriggerPoint::kDidCommitLoad, - &prerender2_warm_up_compositor_trigger_point); - // Enable limiting previews loading hints to specific resource types. BASE_FEATURE(kPreviewsResourceLoadingHintsSpecificResourceTypes, "PreviewsResourceLoadingHintsSpecificResourceTypes", @@ -2841,6 +2821,10 @@ "WebviewAccelerateSmallCanvases", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kNoReferrerForPreloadFromSubresource, + "NoReferrerForPreloadFromSubresource", + base::FEATURE_ENABLED_BY_DEFAULT); + // When adding new features or constants for features, please keep the features // sorted by identifier name (e.g. `kAwesomeFeature`), and the constants for // that feature grouped with the associated feature.
diff --git a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc index 009f356..9fe216a 100644 --- a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc +++ b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
@@ -73,7 +73,6 @@ out->dns_prefetching_enabled = data.dns_prefetching_enabled(); out->data_saver_enabled = data.data_saver_enabled(); out->local_storage_enabled = data.local_storage_enabled(); - out->databases_enabled = data.databases_enabled(); out->tabs_to_links = data.tabs_to_links(); out->disable_ipc_flooding_protection = data.disable_ipc_flooding_protection(); out->hyperlink_auditing_enabled = data.hyperlink_auditing_enabled();
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 4adbfe7..4fb83eb 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -1458,19 +1458,6 @@ BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE( kPrerender2EarlyDocumentLifecycleUpdate); -// Enables to warm up compositor on certain loading event of prerender initial -// navigation. The feature `kWarmUpCompositor` in cc is required to enable this -// feature. Please see crbug.com/41496019 for more details. -BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kPrerender2WarmUpCompositor); -enum class Prerender2WarmUpCompositorTriggerPoint { - kDidCommitLoad, - kDidDispatchDOMContentLoadedEvent, - kDidFinishLoad, -}; -BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM( - Prerender2WarmUpCompositorTriggerPoint, - kPrerender2WarmUpCompositorTriggerPoint); - // Firing pagehide events for intended prerender cancellation. See // crbug.com/353628449 for more details. BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kPageHideEventForPrerender2); @@ -1848,6 +1835,9 @@ BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kWebviewAccelerateSmallCanvases); +// Kill switch for https://crbug.com/415810136. +BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kNoReferrerForPreloadFromSubresource); + // When adding new features or constants for features, please keep the features // sorted by identifier name (e.g. `kAwesomeFeature`), and the constants for // that feature grouped with the associated feature.
diff --git a/third_party/blink/public/common/web_preferences/web_preferences.h b/third_party/blink/public/common/web_preferences/web_preferences.h index 85f312a..15117b45 100644 --- a/third_party/blink/public/common/web_preferences/web_preferences.h +++ b/third_party/blink/public/common/web_preferences/web_preferences.h
@@ -75,7 +75,6 @@ // 'Save-Data: on'. bool data_saver_enabled = false; bool local_storage_enabled = false; - bool databases_enabled = false; bool tabs_to_links = true; bool disable_ipc_flooding_protection = false; bool hyperlink_auditing_enabled = true;
diff --git a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h index 1173ace..86e4152 100644 --- a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h +++ b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
@@ -150,10 +150,6 @@ return r.local_storage_enabled; } - static bool databases_enabled(const blink::web_pref::WebPreferences& r) { - return r.databases_enabled; - } - static bool tabs_to_links(const blink::web_pref::WebPreferences& r) { return r.tabs_to_links; }
diff --git a/third_party/blink/public/mojom/printing/web_printing.mojom b/third_party/blink/public/mojom/printing/web_printing.mojom index 76073fb6..d797e97 100644 --- a/third_party/blink/public/mojom/printing/web_printing.mojom +++ b/third_party/blink/public/mojom/printing/web_printing.mojom
@@ -18,6 +18,12 @@ kTwoSidedShortEdge }; +enum WebPrintQuality { + kDraft, + kNormal, + kHigh +}; + enum WebPrintColorMode { kColor, kMonochrome @@ -154,6 +160,9 @@ WebPrintColorMode print_color_mode_default; array<WebPrintColorMode> print_color_mode_supported; + WebPrintQuality print_quality_default; + array<WebPrintQuality> print_quality_supported; + WebPrinterState printer_state; string printer_state_message; array<WebPrinterStateReason> printer_state_reasons; @@ -190,6 +199,7 @@ WebPrintingOrientationRequested? orientation_requested; gfx.mojom.Size? printer_resolution; WebPrintColorMode? print_color_mode; + WebPrintQuality? print_quality; WebPrintingSides? sides; };
diff --git a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom index ffd46eb..41d33c9 100644 --- a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom +++ b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
@@ -141,7 +141,6 @@ // 'Save-Data: on'. bool data_saver_enabled; bool local_storage_enabled; - bool databases_enabled; bool tabs_to_links; bool disable_ipc_flooding_protection; bool hyperlink_auditing_enabled;
diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h index 6ea4a0f..202a7b6 100644 --- a/third_party/blink/public/web/web_local_frame.h +++ b/third_party/blink/public/web/web_local_frame.h
@@ -524,7 +524,7 @@ gfx::Rect&) const = 0; // Supports commands like Undo, Redo, Cut, Copy, Paste, SelectAll, - // Unselect, etc. See EditorCommand.cpp for the full list of supported + // Unselect, etc. See editor_command_names.h for the full list of supported // commands. virtual bool ExecuteCommand(const WebString&) = 0; virtual bool ExecuteCommand(const WebString&, const WebString& value) = 0;
diff --git a/third_party/blink/public/web/web_widget.h b/third_party/blink/public/web/web_widget.h index f4781f2..59e4b3bc 100644 --- a/third_party/blink/public/web/web_widget.h +++ b/third_party/blink/public/web/web_widget.h
@@ -78,9 +78,7 @@ virtual void SetCompositorVisible(bool visible) = 0; // Asks the compositor to request warming up and request a new frame sink - // speculatively. This is an experimental function and only used if - // `kWarmUpCompositor` is enabled. Please see crbug.com/41496019 - // for more details. + // speculatively even if invisible. virtual void WarmUpCompositor() = 0; // Returns the current size of the WebWidget.
diff --git a/third_party/blink/renderer/core/css/css_gradient_value.cc b/third_party/blink/renderer/core/css/css_gradient_value.cc index e9a3469..e941c14 100644 --- a/third_party/blink/renderer/core/css/css_gradient_value.cc +++ b/third_party/blink/renderer/core/css/css_gradient_value.cc
@@ -122,10 +122,9 @@ } } - // TODO(crbug.com/979895): This is the result of a refactoring, which might - // have revealed an existing bug with calculated lengths. Investigate. - return !offset_ || offset_->IsMathFunctionValue() || - !To<CSSNumericLiteralValue>(*offset_).IsFontRelativeLength(); + return !offset_ || + (!offset_->IsMathFunctionValue() && + !To<CSSNumericLiteralValue>(*offset_).IsFontRelativeLength()); } void CSSGradientColorStop::Trace(Visitor* visitor) const {
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 52d347ab..cb4b789 100644 --- a/third_party/blink/renderer/core/css/css_image_value.cc +++ b/third_party/blink/renderer/core/css/css_image_value.cc
@@ -103,11 +103,11 @@ ImageResourceContent* image_content = document.GetStyleEngine().CacheImageContent(params); cached_image_ = MakeGarbageCollected<StyleFetchedImage>( - image_content, *url_data.MakeResolvedIfDanglingMarkup(document), - document, + image_content, document, params.GetImageRequestBehavior() == FetchParameters::ImageRequestBehavior::kDeferImageLoad, - override_image_resolution); + url_data.IsFromOriginCleanStyleSheet(), url_data.IsAdRelated(), + params.Url(), override_image_resolution); } return cached_image_.Get(); } @@ -167,6 +167,13 @@ 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 d2188598f..41fa958b 100644 --- a/third_party/blink/renderer/core/css/css_image_value.h +++ b/third_party/blink/renderer/core/css/css_image_value.h
@@ -68,9 +68,10 @@ bool Equals(const CSSImageValue&) const; CSSImageValue* ComputedCSSValue() const { - return MakeGarbageCollected<CSSImageValue>(*UrlData().MakeComputed(), + return MakeGarbageCollected<CSSImageValue>(*UrlData().MakeAbsolute(), cached_image_.Get()); } + CSSImageValue* ComputedCSSValueMaybeLocal() const; CSSImageValue* Clone() const { return MakeGarbageCollected<CSSImageValue>(*UrlData().MakeWithoutReferrer(),
diff --git a/third_party/blink/renderer/core/css/css_math_function_value.cc b/third_party/blink/renderer/core/css/css_math_function_value.cc index 417aeff6..70019c2 100644 --- a/third_party/blink/renderer/core/css/css_math_function_value.cc +++ b/third_party/blink/renderer/core/css/css_math_function_value.cc
@@ -70,11 +70,6 @@ return ClampToPermittedRange(expression_->DoubleValue()); } -double CSSMathFunctionValue::ComputeDegrees() const { - DCHECK_EQ(kCalcAngle, expression_->Category()); - return ClampToPermittedRange(*expression_->ComputeValueInCanonicalUnit()); -} - double CSSMathFunctionValue::ComputeDegrees( const CSSLengthResolver& length_resolver) const { DCHECK_EQ(kCalcAngle, expression_->Category());
diff --git a/third_party/blink/renderer/core/css/css_math_function_value.h b/third_party/blink/renderer/core/css/css_math_function_value.h index 42ef6aa..8c9c9575 100644 --- a/third_party/blink/renderer/core/css/css_math_function_value.h +++ b/third_party/blink/renderer/core/css/css_math_function_value.h
@@ -77,7 +77,6 @@ double DoubleValue() const; double ComputeSeconds(const CSSLengthResolver&) const; - double ComputeDegrees() const; double ComputeDegrees(const CSSLengthResolver&) const; double ComputeLengthPx(const CSSLengthResolver&) const; double ComputeDotsPerPixel(const CSSLengthResolver&) const;
diff --git a/third_party/blink/renderer/core/css/css_primitive_value.cc b/third_party/blink/renderer/core/css/css_primitive_value.cc index 43956cc1..24cd7b48 100644 --- a/third_party/blink/renderer/core/css/css_primitive_value.cc +++ b/third_party/blink/renderer/core/css/css_primitive_value.cc
@@ -277,15 +277,6 @@ NOTREACHED(); } -// TODO(crbug.com/1133390): When we support <frequency>, we must clamp like -// <time>. -double CSSPrimitiveValue::ComputeDegrees() const { - double result = IsCalculated() - ? To<CSSMathFunctionValue>(this)->ComputeDegrees() - : To<CSSNumericLiteralValue>(this)->ComputeDegrees(); - return CSSValueClampingUtils::ClampAngle(result); -} - double CSSPrimitiveValue::ComputeDegrees( const CSSLengthResolver& length_resolver) const { double result =
diff --git a/third_party/blink/renderer/core/css/css_primitive_value.h b/third_party/blink/renderer/core/css/css_primitive_value.h index c12eb1e..d8473a6 100644 --- a/third_party/blink/renderer/core/css/css_primitive_value.h +++ b/third_party/blink/renderer/core/css/css_primitive_value.h
@@ -377,8 +377,6 @@ // |CSSPrimitiveValue| that's not of any of its subclasses. static CSSPrimitiveValue* CreateFromLength(const Length& value, float zoom); - double ComputeDegrees() const; - double ComputeDegrees(const CSSLengthResolver&) const; double ComputeSeconds(const CSSLengthResolver&) const; double ComputeDotsPerPixel(const CSSLengthResolver&) const;
diff --git a/third_party/blink/renderer/core/css/css_uri_value_test.cc b/third_party/blink/renderer/core/css/css_uri_value_test.cc index 563c072..b3efe7f4 100644 --- a/third_party/blink/renderer/core/css/css_uri_value_test.cc +++ b/third_party/blink/renderer/core/css/css_uri_value_test.cc
@@ -16,7 +16,7 @@ cssvalue::CSSURIValue* rel = MakeGarbageCollected<cssvalue::CSSURIValue>( *MakeGarbageCollected<CSSUrlData>( AtomicString("a"), KURL("http://foo.com/a"), Referrer(), - /*origin_clean=*/true, /*is_ad_related=*/false)); + OriginClean::kTrue, /*is_ad_related=*/false)); cssvalue::CSSURIValue* abs = rel->ComputedCSSValue(KURL("http://bar.com"), WTF::TextEncoding()); EXPECT_EQ("url(\"http://bar.com/a\")", abs->CssText()); @@ -26,7 +26,7 @@ cssvalue::CSSURIValue* rel = MakeGarbageCollected<cssvalue::CSSURIValue>( *MakeGarbageCollected<CSSUrlData>( AtomicString("http://baz.com/a"), KURL("http://baz.com/a"), - Referrer(), /*origin_clean=*/true, /*is_ad_related=*/false)); + Referrer(), OriginClean::kTrue, /*is_ad_related=*/false)); cssvalue::CSSURIValue* abs = rel->ComputedCSSValue(KURL("http://bar.com"), WTF::TextEncoding()); EXPECT_EQ("url(\"http://baz.com/a\")", abs->CssText()); @@ -36,7 +36,7 @@ cssvalue::CSSURIValue* rel = MakeGarbageCollected<cssvalue::CSSURIValue>( *MakeGarbageCollected<CSSUrlData>( AtomicString("#a"), KURL("http://baz.com/a"), Referrer(), - /*origin_clean=*/true, /*is_ad_related=*/false)); + OriginClean::kTrue, /*is_ad_related=*/false)); cssvalue::CSSURIValue* abs = rel->ComputedCSSValue(KURL("http://bar.com"), WTF::TextEncoding()); EXPECT_EQ("url(\"#a\")", abs->CssText()); @@ -45,7 +45,7 @@ TEST(CSSURIValueTest, EmptyComputedCSSValue) { cssvalue::CSSURIValue* rel = MakeGarbageCollected<cssvalue::CSSURIValue>( *MakeGarbageCollected<CSSUrlData>(g_empty_atom, KURL(), Referrer(), - /*origin_clean=*/true, + OriginClean::kTrue, /*is_ad_related=*/false)); cssvalue::CSSURIValue* abs = rel->ComputedCSSValue(KURL("http://bar.com"), WTF::TextEncoding());
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 2efe98f..ad3ae90e 100644 --- a/third_party/blink/renderer/core/css/css_url_data.cc +++ b/third_party/blink/renderer/core/css/css_url_data.cc
@@ -30,21 +30,21 @@ CSSUrlData::CSSUrlData(const AtomicString& unresolved_url, const KURL& resolved_url, const Referrer& referrer, - bool is_from_origin_clean_style_sheet, + OriginClean origin_clean, bool is_ad_related) : 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_from_origin_clean_style_sheet_(origin_clean == OriginClean::kTrue), is_ad_related_(is_ad_related), + is_local_(unresolved_url.StartsWith('#')), potentially_dangling_markup_(resolved_url.PotentiallyDanglingMarkup()) {} CSSUrlData::CSSUrlData(const AtomicString& resolved_url) : CSSUrlData(resolved_url, KURL(resolved_url), Referrer(), - /*is_from_origin_clean_style_sheet=*/true, + OriginClean::kTrue, /*is_ad_related=*/false) {} KURL CSSUrlData::ResolveUrl(const Document& document) const { @@ -82,13 +82,13 @@ return true; } -const CSSUrlData* CSSUrlData::MakeComputed() const { - if (relative_url_.empty() || is_local_ || absolute_url_.empty()) { +const CSSUrlData* CSSUrlData::MakeAbsolute() const { + if (relative_url_.empty()) { return this; } - return MakeGarbageCollected<CSSUrlData>( - absolute_url_, KURL(absolute_url_), Referrer(), - is_from_origin_clean_style_sheet_, is_ad_related_); + return MakeGarbageCollected<CSSUrlData>(absolute_url_, KURL(absolute_url_), + Referrer(), GetOriginClean(), + is_ad_related_); } const CSSUrlData* CSSUrlData::MakeResolved( @@ -101,29 +101,19 @@ ? KURL(base_url, relative_url_, charset) : KURL(base_url, relative_url_); if (is_local_) { - return MakeGarbageCollected<CSSUrlData>( - relative_url_, resolved_url, Referrer(), - is_from_origin_clean_style_sheet_, is_ad_related_); + return MakeGarbageCollected<CSSUrlData>(relative_url_, resolved_url, + Referrer(), GetOriginClean(), + is_ad_related_); } return MakeGarbageCollected<CSSUrlData>( AtomicString(resolved_url.GetString()), resolved_url, Referrer(), - is_from_origin_clean_style_sheet_, is_ad_related_); -} - -const CSSUrlData* CSSUrlData::MakeResolvedIfDanglingMarkup( - const Document& document) const { - if (!potentially_dangling_markup_) { - return this; - } - return MakeGarbageCollected<CSSUrlData>( - relative_url_, ResolveUrl(document), referrer_, - is_from_origin_clean_style_sheet_, is_ad_related_); + GetOriginClean(), is_ad_related_); } const CSSUrlData* CSSUrlData::MakeWithoutReferrer() const { - return MakeGarbageCollected<CSSUrlData>( - relative_url_, KURL(absolute_url_), Referrer(), - is_from_origin_clean_style_sheet_, is_ad_related_); + return MakeGarbageCollected<CSSUrlData>(relative_url_, KURL(absolute_url_), + Referrer(), GetOriginClean(), + is_ad_related_); } bool CSSUrlData::IsLocal(const Document& document) const {
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 db94c0b..1169bbf 100644 --- a/third_party/blink/renderer/core/css/css_url_data.h +++ b/third_party/blink/renderer/core/css/css_url_data.h
@@ -22,6 +22,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_URL_DATA_H_ #include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/css/css_origin_clean.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/weborigin/referrer.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" @@ -41,7 +42,7 @@ CSSUrlData(const AtomicString& unresolved_url, const KURL& resolved_url, const Referrer&, - bool is_from_origin_clean_style_sheet, + OriginClean, bool is_ad_related); // Create URL data with a resolved (absolute) URL. Generally used for @@ -56,19 +57,14 @@ // Document. Returns true if the resolved URL changed, otherwise false. bool ReResolveUrl(const Document&) const; - // Returns a copy of this URL data suitable for computed value. - const CSSUrlData* MakeComputed() const; + // Returns an absolutized copy of this URL data (suitable for computed value). + const CSSUrlData* MakeAbsolute() const; // Returns a copy where the unresolved URL has been resolved against // `base_url` (using `charset` encoding if valid). const CSSUrlData* MakeResolved(const KURL& base_url, const WTF::TextEncoding& charset) const; - // Returns a copy with the URL (re)resolved against the base URL of the - // document if there's is potential risk of "dangling markup". Otherwise - // returns itself. - const CSSUrlData* MakeResolvedIfDanglingMarkup(const Document&) const; - // Returns a copy where the referrer has been reset. const CSSUrlData* MakeWithoutReferrer() const; @@ -84,6 +80,10 @@ bool IsFromOriginCleanStyleSheet() const { return is_from_origin_clean_style_sheet_; } + OriginClean GetOriginClean() const { + return is_from_origin_clean_style_sheet_ ? OriginClean::kTrue + : OriginClean::kFalse; + } bool IsAdRelated() const { return is_ad_related_; } // Returns true if this URL is "local" to the specified Document (either by @@ -101,9 +101,6 @@ 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_; @@ -111,6 +108,8 @@ // 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/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc index 310706bb..a12c93d5 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
@@ -1670,7 +1670,9 @@ AtomicString url_string = url.ToAtomicString(); return MakeGarbageCollected<CSSUrlData>( url_string, context.CompleteNonEmptyURL(url_string), - context.GetReferrer(), context.IsOriginClean(), context.IsAdRelated()); + context.GetReferrer(), + context.IsOriginClean() ? OriginClean::kTrue : OriginClean::kFalse, + context.IsAdRelated()); } } // namespace
diff --git a/third_party/blink/renderer/core/css/selector_checker-inl.h b/third_party/blink/renderer/core/css/selector_checker-inl.h index 72c22651..04e9f40 100644 --- a/third_party/blink/renderer/core/css/selector_checker-inl.h +++ b/third_party/blink/renderer/core/css/selector_checker-inl.h
@@ -163,6 +163,16 @@ tag_q_name.NamespaceURI() == g_star_atom; } case CSSSelector::kClass: + if (!element->CouldHaveClass(selector->Value())) { +#if DCHECK_IS_ON() + DCHECK(!element->HasClass() || + !element->ClassNames().Contains(selector->Value())) + << element << " should have matched class " << selector->Value() + << ", Bloom bits on element are " + << element->AttributeOrClassBloomFilterForDebug(); +#endif + return false; + } return element->HasClass() && element->ClassNames().Contains(selector->Value()); case CSSSelector::kId: @@ -221,7 +231,7 @@ DCHECK(element.CouldHaveAttribute(attr)) << element << " should have contained attribute " << attr << ", Bloom bits on element are " - << element.AttributeBloomFilterForDebug(); + << element.AttributeOrClassBloomFilterForDebug(); #endif return attribute_item.Value() == value || (case_insensitive &&
diff --git a/third_party/blink/renderer/core/css/selector_checker.cc b/third_party/blink/renderer/core/css/selector_checker.cc index 5f9c9e4..d7270263 100644 --- a/third_party/blink/renderer/core/css/selector_checker.cc +++ b/third_party/blink/renderer/core/css/selector_checker.cc
@@ -906,7 +906,7 @@ DCHECK(element.CouldHaveAttribute(selector_attr)) << element << " should have contained attribute " << selector_attr << ", Bloom bits on element are " - << element.AttributeBloomFilterForDebug(); + << element.AttributeOrClassBloomFilterForDebug(); #endif if (AttributeValueMatches(attribute_item, match, selector_value, @@ -960,6 +960,16 @@ case CSSSelector::kUniversalTag: return MatchesUniversalTagName(element, selector.TagQName()); case CSSSelector::kClass: + if (!element.CouldHaveClass(selector.Value())) { +#if DCHECK_IS_ON() + DCHECK(!element.HasClass() || + !element.ClassNames().Contains(selector.Value())) + << element << " should have matched class " << selector.Value() + << ", Bloom bits on element are " + << element.AttributeOrClassBloomFilterForDebug(); +#endif + return false; + } return element.HasClass() && element.ClassNames().Contains(selector.Value()); case CSSSelector::kId:
diff --git a/third_party/blink/renderer/core/css/selector_query.cc b/third_party/blink/renderer/core/css/selector_query.cc index 741ec2c..ad591f0 100644 --- a/third_party/blink/renderer/core/css/selector_query.cc +++ b/third_party/blink/renderer/core/css/selector_query.cc
@@ -160,9 +160,20 @@ const AtomicString& class_name, const CSSSelector* selector, typename SelectorQueryTrait::OutputType& output) { + const Element::TinyBloomFilter filter = Element::FilterForString(class_name); + SelectorChecker checker(SelectorChecker::kQueryingRules); for (Element& element : ElementTraversal::DescendantsOf(root_node)) { QUERY_STATS_INCREMENT(fast_class); + if (!element.CouldHaveClassWithPrecomputedFilter(filter)) { +#if DCHECK_IS_ON() + DCHECK(!element.HasClassName(class_name)) + << element << " should have contained class " << class_name + << ", Bloom bits on element are " + << element.AttributeOrClassBloomFilterForDebug(); +#endif + continue; + } if (!element.HasClassName(class_name)) { continue; } @@ -263,7 +274,8 @@ const bool needs_synchronize_attribute = NeedsSynchronizeAttribute(selector_attr, is_html_doc); - const uint32_t filter = Element::FilterForAttribute(selector_attr); + const Element::TinyBloomFilter filter = + Element::FilterForAttribute(selector_attr); for (Element& element : ElementTraversal::DescendantsOf(root_node)) { QUERY_STATS_INCREMENT(fast_scan); @@ -308,7 +320,7 @@ DCHECK(element.CouldHaveAttributeWithPrecomputedFilter(filter)) << element << " should have contained attribute " << selector_attr << ", Bloom bits on element are " - << element.AttributeBloomFilterForDebug(); + << element.AttributeOrClassBloomFilterForDebug(); #endif if (AttributeValueMatchesExact(attribute_item, selector_value,
diff --git a/third_party/blink/renderer/core/dom/container_node.cc b/third_party/blink/renderer/core/dom/container_node.cc index e0e8252..c898ab2 100644 --- a/third_party/blink/renderer/core/dom/container_node.cc +++ b/third_party/blink/renderer/core/dom/container_node.cc
@@ -557,7 +557,7 @@ DCHECK(firstChild() == next_child); SetFirstChild(&new_child); } - new_child.SetParentOrShadowHostNode(this); + new_child.SetParentNode(this); new_child.SetPreviousSibling(prev); new_child.SetNextSibling(&next_child); } @@ -568,7 +568,7 @@ #endif DCHECK(ScriptForbiddenScope::IsScriptForbidden()); - child.SetParentOrShadowHostNode(this); + child.SetParentNode(this); if (last_child_) { child.SetPreviousSibling(last_child_); last_child_->SetNextSibling(&child); @@ -1031,7 +1031,7 @@ old_child.SetPreviousSibling(nullptr); old_child.SetNextSibling(nullptr); - old_child.SetParentOrShadowHostNode(nullptr); + old_child.SetParentNode(nullptr); GetDocument().AdoptIfNeeded(old_child); }
diff --git a/third_party/blink/renderer/core/dom/document_fragment.cc b/third_party/blink/renderer/core/dom/document_fragment.cc index c548af0e..d6d0575 100644 --- a/third_party/blink/renderer/core/dom/document_fragment.cc +++ b/third_party/blink/renderer/core/dom/document_fragment.cc
@@ -113,7 +113,7 @@ Node* next_child = firstChild(); do { Node* child = next_child; - child->SetParentOrShadowHostNode(nullptr); + child->SetParentNode(nullptr); child->SetPreviousSibling(nullptr); next_child = child->nextSibling(); child->SetNextSibling(nullptr);
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index faceadb6..780a330 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1283,7 +1283,8 @@ // be in non-ancestor shadow trees. We don't want to leak references into // those scopes, so retarget the elements. if (RuntimeEnabledFeatures::ShadowRootReferenceTargetEnabled( - GetExecutionContext()) && elements) { + GetExecutionContext()) && + elements) { std::transform(elements->begin(), elements->end(), elements->begin(), [this](Element* element) { return &this->GetTreeScope().Retarget(*element); @@ -3283,6 +3284,9 @@ GetElementData()->SetClass(new_class_string); } const SpaceSplitString& new_classes = GetElementData()->ClassNames(); + for (const AtomicString& class_name : new_classes) { + attribute_or_class_bloom_ |= FilterForString(class_name); + } GetDocument().GetStyleEngine().ClassChangedForElement(old_classes, new_classes, *this); } @@ -3354,9 +3358,11 @@ ShareableElementData::CreateWithAttributes(attribute_vector); } - attribute_bloom_ = 0; + // NOTE: AttributeChanged() will add back the class names (if any), + // so it is safe to reset the filter here. + attribute_or_class_bloom_ = 0; for (const Attribute& attribute : attribute_vector) { - attribute_bloom_ |= FilterForAttribute(attribute.GetName()); + attribute_or_class_bloom_ |= FilterForAttribute(attribute.GetName()); } } @@ -5418,7 +5424,7 @@ } } EnsureElementRareData().SetShadowRoot(*shadow_root); - shadow_root->SetParentOrShadowHostNode(this); + shadow_root->SetShadowHostNode(this); shadow_root->SetParentTreeScope(GetTreeScope()); shadow_root->InsertedInto(*this); @@ -6681,7 +6687,7 @@ DidRemoveAttribute(name, value_being_removed); } - // TODO(sesse): Consider recalculating attribute_bloom_ filter here, + // TODO(sesse): Consider recalculating attribute_or_class_bloom_ filter here, // so that it reflects the removal (but beware of pathological cases // where removing all attributes send us into O(n²)). } @@ -6689,7 +6695,7 @@ void Element::AppendAttributeInternal(const QualifiedName& name, const AtomicString& value, AttributeModificationReason reason) { - attribute_bloom_ |= FilterForAttribute(name); + attribute_or_class_bloom_ |= FilterForAttribute(name); if (reason != AttributeModificationReason::kBySynchronizationOfLazyAttribute) { @@ -10198,7 +10204,7 @@ setNonce(other.nonce()); } - attribute_bloom_ = other.attribute_bloom_; + attribute_or_class_bloom_ = other.attribute_or_class_bloom_; } void Element::CreateUniqueElementData() {
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h index 7a73542..be85231 100644 --- a/third_party/blink/renderer/core/dom/element.h +++ b/third_party/blink/renderer/core/dom/element.h
@@ -750,13 +750,21 @@ return CouldHaveAttributeWithPrecomputedFilter( FilterForAttribute(attribute_name)); } + bool CouldHaveClass(const AtomicString& class_name) const { + return CouldHaveClassWithPrecomputedFilter(FilterForString(class_name)); + } - // A variant of CouldHaveAttribute() that allows you to compute + // A variant of CouldHave{Attribute,Class}() that allows you to compute // the filter ahead-of-time; useful if you want to test many elements - // against the same attribute name. - static uint32_t FilterForAttribute(const QualifiedName& attribute_name) { - unsigned hash = attribute_name.LocalNameUpper().Hash(); - uint32_t filter = 0; + // against the same attribute/class name. + using TinyBloomFilter = uint32_t; + static TinyBloomFilter FilterForAttribute( + const QualifiedName& attribute_name) { + return FilterForString(attribute_name.LocalNameUpper()); + } + static TinyBloomFilter FilterForString(const AtomicString& str) { + unsigned hash = str.Hash(); + TinyBloomFilter filter = 0; // Build a 32-bit Bloom filter, with k=2. We extract the two // (5-bit) hashes that we need from non-overlapping parts of the // (24-bit) String hash, which should be independent. @@ -764,11 +772,16 @@ filter |= 1u << ((hash >> 5) & 31); return filter; } - bool CouldHaveAttributeWithPrecomputedFilter(uint32_t filter) const { - return (attribute_bloom_ & filter) == filter; + bool CouldHaveAttributeWithPrecomputedFilter(TinyBloomFilter filter) const { + return (attribute_or_class_bloom_ & filter) == filter; + } + bool CouldHaveClassWithPrecomputedFilter(TinyBloomFilter filter) const { + return (attribute_or_class_bloom_ & filter) == filter; } #if DCHECK_IS_ON() - uint32_t AttributeBloomFilterForDebug() const { return attribute_bloom_; } + TinyBloomFilter AttributeOrClassBloomFilterForDebug() const { + return attribute_or_class_bloom_; + } #endif // Step 5 of https://dom.spec.whatwg.org/#concept-node-clone @@ -2238,11 +2251,12 @@ subtle::UncompressedMember<const ComputedStyle> computed_style_; Member<ElementData> element_data_; - // A tiny Bloom filter for which attribute names we have; saves going to - // ElementData if the attribute doesn't exist. May have false positives, - // of course. We do not currently update this when attributes are removed, - // only when they are added. Attribute _values_ are not part of this filter. - uint32_t attribute_bloom_ = 0; + // A tiny Bloom filter for which attribute names and class names we have; + // saves going to ElementData if the attribute/class doesn't exist. May have + // false positives, of course. We do not currently update this when + // attributes/classes are removed, only when they are added. Attribute + // _values_ are not part of this filter, except for the values of class="". + uint32_t attribute_or_class_bloom_ = 0; }; template <>
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc index 36b22659..66009173 100644 --- a/third_party/blink/renderer/core/dom/node.cc +++ b/third_party/blink/renderer/core/dom/node.cc
@@ -325,8 +325,8 @@ Node::Node(TreeScope* tree_scope, ConstructionType type) : node_flags_(type), - parent_or_shadow_host_node_(nullptr), tree_scope_(tree_scope), + parent_or_shadow_host_node_(kParentNodeTag, nullptr), previous_(nullptr), next_(nullptr), layout_object_(nullptr), @@ -3713,8 +3713,8 @@ } void Node::Trace(Visitor* visitor) const { - visitor->Trace(parent_or_shadow_host_node_); visitor->Trace(tree_scope_); + visitor->Trace(parent_or_shadow_host_node_); visitor->Trace(previous_); visitor->Trace(next_); visitor->Trace(layout_object_);
diff --git a/third_party/blink/renderer/core/dom/node.h b/third_party/blink/renderer/core/dom/node.h index e8061e4..0ba574f 100644 --- a/third_party/blink/renderer/core/dom/node.h +++ b/third_party/blink/renderer/core/dom/node.h
@@ -215,7 +215,8 @@ virtual void setNodeValue(const String&, ExceptionState& = ASSERT_NO_EXCEPTION); ContainerNode* parentNode() const { - return IsShadowRoot() ? nullptr : ParentOrShadowHostNode(); + return reinterpret_cast<ContainerNode*>( + parent_or_shadow_host_node_.TryGetAs<ParentNodeTag>()); } Element* parentElement() const; @@ -456,7 +457,13 @@ bool IsDocumentNode() const; bool IsTreeScope() const; - bool IsShadowRoot() const { return IsDocumentFragment() && IsTreeScope(); } + bool IsShadowRoot() const { + const bool result = parent_or_shadow_host_node_.Is<ShadowHostTag>(); +#if DCHECK_IS_ON() + DCHECK(!result || (IsDocumentFragment() && IsTreeScope())); +#endif + return result; + } bool IsActiveSlot() const; bool IsSlotable() const { return IsTextNode() || IsElementNode(); } @@ -484,7 +491,8 @@ // Node's parent, shadow tree host. ContainerNode* ParentOrShadowHostNode() const; Element* ParentOrShadowHostElement() const; - void SetParentOrShadowHostNode(ContainerNode*); + void SetParentNode(ContainerNode*); + void SetShadowHostNode(ContainerNode*); // Knows about all kinds of hosts. ContainerNode* ParentOrShadowHostOrTemplateHostNode() const; @@ -590,13 +598,15 @@ // a micro-benchmark regression (https://crbug.com/926343). void SetStyleChangeOnInsertion() { DCHECK(isConnected()); - if (ShouldSkipMarkingStyleDirty()) + if (ShouldSkipMarkingStyleDirty()) { return; + } if (InvalidationTracingFlag::IsEnabled()) [[unlikely]] { MaybeAddNodeInsertedTraceEvent(); } - if (!NeedsStyleRecalc()) + if (!NeedsStyleRecalc()) { SetStyleChange(kLocalStyleChange); + } MarkAncestorsWithChildNeedsStyleRecalc(); } @@ -607,8 +617,9 @@ DCHECK(IsElementNode()); DCHECK(isConnected()); DCHECK(parentElement() && !GetStyleRecalcParent()); - if (!NeedsStyleRecalc()) + if (!NeedsStyleRecalc()) { SetStyleChange(kLocalStyleChange); + } } bool NeedsReattachLayoutTree() const { @@ -1246,6 +1257,14 @@ void InvalidateIfHasEffectiveAppearance() const; private: + static constexpr struct ParentNodeTag { + } kParentNodeTag; + static constexpr struct ShadowHostTag { + } kShadowHostTag; + + using TaggedParentOrShadowHostNode = + subtle::TaggedUncompressedMember<Node, ParentNodeTag, ShadowHostTag>; + Node* ToNode() final; bool IsUserActionElementActive() const; @@ -1274,10 +1293,10 @@ // EventTarget ends with a single 32-bit member, so put one 32-bit member // first to avoid padding on 64-bit. uint32_t node_flags_; - // Both parent and tree_scope are hot accessed members. Keep them uncompressed + // Both tree_scope and parent are hot accessed members. Keep them uncompressed // for performance reasons. - subtle::UncompressedMember<Node> parent_or_shadow_host_node_; subtle::UncompressedMember<TreeScope> tree_scope_; + TaggedParentOrShadowHostNode parent_or_shadow_host_node_; // Compressed members and flags are after uncompressed members to minimize // padding. Member<Node> previous_; @@ -1286,14 +1305,22 @@ Member<NodeRareData> data_; }; -inline void Node::SetParentOrShadowHostNode(ContainerNode* parent) { +inline void Node::SetParentNode(ContainerNode* parent) { DCHECK(IsMainThread()); - parent_or_shadow_host_node_ = reinterpret_cast<Node*>(parent); + parent_or_shadow_host_node_.SetAs<ParentNodeTag>( + reinterpret_cast<Node*>(parent)); +} + +inline void Node::SetShadowHostNode(ContainerNode* shadow_host) { + DCHECK(IsMainThread()); + parent_or_shadow_host_node_.SetAs<ShadowHostTag>( + reinterpret_cast<Node*>(shadow_host)); } inline ContainerNode* Node::ParentOrShadowHostNode() const { DCHECK(IsMainThread()); - return reinterpret_cast<ContainerNode*>(parent_or_shadow_host_node_.Get()); + return reinterpret_cast<ContainerNode*>( + parent_or_shadow_host_node_.GetUntagged()); } // Allow equality comparisons of Nodes by reference or pointer, interchangeably.
diff --git a/third_party/blink/renderer/core/dom/pseudo_element.cc b/third_party/blink/renderer/core/dom/pseudo_element.cc index 87cfbc9e..fbb127f7 100644 --- a/third_party/blink/renderer/core/dom/pseudo_element.cc +++ b/third_party/blink/renderer/core/dom/pseudo_element.cc
@@ -285,7 +285,7 @@ view_transition_name_(view_transition_name) { DCHECK_NE(pseudo_id, kPseudoIdNone); parent->GetTreeScope().AdoptIfNeeded(*this); - SetParentOrShadowHostNode(parent); + SetParentNode(parent); SetHasCustomStyleCallbacks(); if ((pseudo_id == kPseudoIdBefore || pseudo_id == kPseudoIdAfter) && parent->HasTagName(html_names::kInputTag)) { @@ -395,7 +395,7 @@ DetachLayoutTree(); Element* parent = ParentOrShadowHostElement(); GetDocument().AdoptIfNeeded(*this); - SetParentOrShadowHostNode(nullptr); + SetParentNode(nullptr); RemovedFrom(*parent); }
diff --git a/third_party/blink/renderer/core/editing/local_caret_rect_test.cc b/third_party/blink/renderer/core/editing/local_caret_rect_test.cc index d6f1e7a5..0e9abf1 100644 --- a/third_party/blink/renderer/core/editing/local_caret_rect_test.cc +++ b/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
@@ -779,18 +779,25 @@ Position position4 = RuntimeEnabledFeatures::TextareaLineEndingsAsBrEnabled() ? Position(br_in_2nd_line, 0) : Position(inner_text, 4); - EXPECT_EQ(LocalCaretRect(position4.AnchorNode()->GetLayoutObject(), - PhysicalRect(0, 10, 1, 10)), - LocalCaretRectOfPosition( - PositionWithAffinity(position4, TextAffinity::kDownstream))); + PhysicalRect local_rect4 = + RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled() + ? PhysicalRect(0, 0, 1, 10) + : PhysicalRect(0, 10, 1, 10); + EXPECT_EQ( + LocalCaretRect(position4.AnchorNode()->GetLayoutObject(), local_rect4), + LocalCaretRectOfPosition( + PositionWithAffinity(position4, TextAffinity::kDownstream))); // Test the third line. const Node* placeholder_br = textarea->InnerEditorElement()->lastChild(); Position position5 = RuntimeEnabledFeatures::TextareaLineEndingsAsBrEnabled() ? Position(placeholder_br, 0) : Position(inner_text, 5); - EXPECT_EQ(LocalCaretRect(placeholder_br->GetLayoutObject(), - PhysicalRect(0, 20, 1, 10)), + PhysicalRect local_rect5 = + RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled() + ? PhysicalRect(0, 0, 1, 10) + : PhysicalRect(0, 20, 1, 10); + EXPECT_EQ(LocalCaretRect(placeholder_br->GetLayoutObject(), local_rect5), LocalCaretRectOfPosition( PositionWithAffinity(position5, TextAffinity::kDownstream))); }
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc index 8fbe8a7b..4d1a925 100644 --- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc +++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -544,43 +544,6 @@ } // static -void ContentSecurityPolicy::FillInCSPHashValues( - const String& source, - WTF::HashSet<IntegrityAlgorithm> hash_algorithms_used, - Vector<network::mojom::blink::CSPHashSourcePtr>& csp_hash_values) { - // Any additions or subtractions from this struct should also modify the - // respective entries in the kSupportedPrefixes array in - // SourceListDirective::parseHash(). - static const struct { - IntegrityAlgorithm csp_hash_algorithm; - HashAlgorithm algorithm; - } kAlgorithmMap[] = {{IntegrityAlgorithm::kSha256, kHashAlgorithmSha256}, - {IntegrityAlgorithm::kSha384, kHashAlgorithmSha384}, - {IntegrityAlgorithm::kSha512, kHashAlgorithmSha512}}; - - // Only bother normalizing the source/computing digests if there are any - // checks to be done. - if (hash_algorithms_used.empty()) { - return; - } - - StringUTF8Adaptor utf8_source(source, - Utf8ConversionMode::kStrictReplacingErrors); - - for (const auto& algorithm_map : kAlgorithmMap) { - DigestValue digest; - if (hash_algorithms_used.Contains(algorithm_map.csp_hash_algorithm)) { - bool digest_success = ComputeDigest( - algorithm_map.algorithm, base::as_byte_span(utf8_source), digest); - if (digest_success) { - csp_hash_values.push_back(network::mojom::blink::CSPHashSource::New( - algorithm_map.csp_hash_algorithm, Vector<uint8_t>(digest))); - } - } - } -} - -// static bool ContentSecurityPolicy::CheckHashAgainstPolicy( Vector<network::mojom::blink::CSPHashSourcePtr>& csp_hash_values, const network::mojom::blink::ContentSecurityPolicy& csp,
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h index 5b50c33..2bd49c33 100644 --- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h +++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -458,11 +458,6 @@ const IntegrityMetadataSet& = IntegrityMetadataSet(), ParserDisposition = kParserInserted); - static void FillInCSPHashValues( - const String& source, - WTF::HashSet<IntegrityAlgorithm> hash_algorithms_used, - Vector<network::mojom::blink::CSPHashSourcePtr>& csp_hash_values); - // checks a vector of csp hashes against policy, probably a good idea // to use in tandem with FillInCSPHashValues. static bool CheckHashAgainstPolicy(
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc index b92e4cc..0285c93f 100644 --- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc +++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -1034,4 +1034,40 @@ return OperativeDirective(csp, type); } +void FillInCSPHashValues( + const String& source, + const WTF::HashSet<IntegrityAlgorithm>& hash_algorithms_used, + Vector<network::mojom::blink::CSPHashSourcePtr>& csp_hash_values) { + // Any additions or subtractions from this struct should also modify the + // respective entries in the kSupportedPrefixes array in + // SourceListDirective::parseHash(). + static const struct { + IntegrityAlgorithm csp_hash_algorithm; + HashAlgorithm algorithm; + } kAlgorithmMap[] = {{IntegrityAlgorithm::kSha256, kHashAlgorithmSha256}, + {IntegrityAlgorithm::kSha384, kHashAlgorithmSha384}, + {IntegrityAlgorithm::kSha512, kHashAlgorithmSha512}}; + + // Only bother normalizing the source/computing digests if there are any + // checks to be done. + if (hash_algorithms_used.empty()) { + return; + } + + StringUTF8Adaptor utf8_source(source, + Utf8ConversionMode::kStrictReplacingErrors); + + for (const auto& algorithm_map : kAlgorithmMap) { + DigestValue digest; + if (hash_algorithms_used.Contains(algorithm_map.csp_hash_algorithm)) { + bool digest_success = ComputeDigest( + algorithm_map.algorithm, base::as_byte_span(utf8_source), digest); + if (digest_success) { + csp_hash_values.push_back(network::mojom::blink::CSPHashSource::New( + algorithm_map.csp_hash_algorithm, Vector<uint8_t>(digest))); + } + } + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.h b/third_party/blink/renderer/core/frame/csp/csp_directive_list.h index 26adc510..6f38ffd 100644 --- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.h +++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
@@ -162,6 +162,11 @@ const network::mojom::blink::ContentSecurityPolicy& csp, CSPDirectiveName type); +void FillInCSPHashValues( + const String& source, + const WTF::HashSet<IntegrityAlgorithm>& hash_algorithms_used, + Vector<network::mojom::blink::CSPHashSourcePtr>& csp_hash_values); + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CSP_DIRECTIVE_LIST_H_
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc index 479dd8a7..ffad482 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc +++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -400,8 +400,6 @@ void LocalFrameClientImpl::DispatchDidDispatchDOMContentLoadedEvent() { if (web_frame_->Client()) web_frame_->Client()->DidDispatchDOMContentLoadedEvent(); - - web_frame_->DidDispatchDOMContentLoadedEvent(); } void LocalFrameClientImpl::DispatchDidLoadResourceFromMemoryCache(
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc index b5b166c..96b0b13d 100644 --- a/third_party/blink/renderer/core/frame/remote_frame.cc +++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -212,7 +212,8 @@ frame_request.GetResourceRequest(), fetch_client_settings_object, window, frame_request.GetFrameType(), window->GetFrame() ? window->GetFrame()->GetContentSettingsClient() - : nullptr); + : nullptr, + window->GetFrame()); if (NavigationShouldReplaceCurrentHistoryEntry(frame_load_type)) frame_load_type = WebFrameLoadType::kReplaceCurrentItem;
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc index 61fd7ff4..b9adaba 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -2597,48 +2597,19 @@ return GetFrame()->GetPage()->GetChromeClient().GetWebView(); } -bool WebLocalFrameImpl::ShouldWarmUpCompositorOnPrerenderFromThisPoint( - features::Prerender2WarmUpCompositorTriggerPoint trigger_point) { - static const bool is_warm_up_compositor_enabled = - base::FeatureList::IsEnabled(::features::kWarmUpCompositor); - if (!is_warm_up_compositor_enabled) { - return false; - } - +bool WebLocalFrameImpl::ShouldWarmUpCompositor() { if (!GetFrame()->IsOutermostMainFrame()) { return false; } - if (!GetFrame()->GetPage() || !GetFrame()->GetPage()->IsPrerendering() || - !GetFrame()->GetPage()->ShouldWarmUpCompositorOnPrerender()) { - return false; - } - - static const bool is_prerender2_warm_up_compositor_enabled = - base::FeatureList::IsEnabled(features::kPrerender2WarmUpCompositor); - // TODO(crbug.com/41496019): Seek the best point to start warm-up. - static const auto prerender2_warm_up_compositor_trigger_point = - features::kPrerender2WarmUpCompositorTriggerPoint.Get(); - if (!is_prerender2_warm_up_compositor_enabled || - prerender2_warm_up_compositor_trigger_point != trigger_point) { - return false; - } - - return true; + // It can be effective for prerendering pages to consider warming up their + // composers before they are activated and visible. + return GetFrame()->GetPage() && GetFrame()->GetPage()->IsPrerendering() && + GetFrame()->GetPage()->ShouldWarmUpCompositorOnPrerender(); } void WebLocalFrameImpl::DidCommitLoad() { - if (frame_widget_ && - ShouldWarmUpCompositorOnPrerenderFromThisPoint( - features::Prerender2WarmUpCompositorTriggerPoint::kDidCommitLoad)) { - frame_widget_->WarmUpCompositor(); - } -} - -void WebLocalFrameImpl::DidDispatchDOMContentLoadedEvent() { - if (frame_widget_ && ShouldWarmUpCompositorOnPrerenderFromThisPoint( - features::Prerender2WarmUpCompositorTriggerPoint:: - kDidDispatchDOMContentLoadedEvent)) { + if (frame_widget_ && ShouldWarmUpCompositor()) { frame_widget_->WarmUpCompositor(); } } @@ -2657,12 +2628,6 @@ if (!Client()) return; - if (frame_widget_ && - ShouldWarmUpCompositorOnPrerenderFromThisPoint( - features::Prerender2WarmUpCompositorTriggerPoint::kDidFinishLoad)) { - frame_widget_->WarmUpCompositor(); - } - if (WebPluginContainerImpl* plugin = GetFrame()->GetWebPluginContainer()) plugin->DidFinishLoading();
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h index 87d933b..7ec474c 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -529,7 +529,6 @@ void SetFindEndstateFocusAndSelection(); void DidCommitLoad(); - void DidDispatchDOMContentLoadedEvent(); void DidFailLoad(const ResourceError&, WebHistoryCommitType); void DidFinish(); void DidFinishLoadForPrinting(); @@ -663,10 +662,8 @@ mojom::blink::BackForwardCacheNotRestoredReasonsPtr ConvertNotRestoredReasons( const mojom::BackForwardCacheNotRestoredReasonsPtr& reasons_struct); - // If true, requests compositor warm-up when the page is under prerendering. - // Please see crbug.com/41496019 for more details. - bool ShouldWarmUpCompositorOnPrerenderFromThisPoint( - features::Prerender2WarmUpCompositorTriggerPoint trigger_point); + // Returns whether we should perform compositor warm-up. + bool ShouldWarmUpCompositor(); WebLocalFrameClient* client_;
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 b86614ad..d5ede9a 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
@@ -2477,7 +2477,8 @@ } bool HTMLInputElement::IsFirstTextInputInAncestorSelect() const { - if (!RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled() || + if ((!RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled() && + !RuntimeEnabledFeatures::SelectAccessibilityNestedInputEnabled()) || !first_ancestor_select_) { return false; } @@ -2485,7 +2486,8 @@ } HTMLSelectElement* HTMLInputElement::FirstAncestorSelectElement() const { - if (!RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled()) { + if (!RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled() && + !RuntimeEnabledFeatures::SelectAccessibilityNestedInputEnabled()) { return nullptr; } return first_ancestor_select_;
diff --git a/third_party/blink/renderer/core/html/forms/html_option_element.cc b/third_party/blink/renderer/core/html/forms/html_option_element.cc index 3aa6f80..b9ef112 100644 --- a/third_party/blink/renderer/core/html/forms/html_option_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_option_element.cc
@@ -730,8 +730,10 @@ if (key == keywords::kArrowUp) { if (auto* previous_option = options.PreviousFocusableOption(*this)) { previous_option->Focus(focus_params); - } else if (RuntimeEnabledFeatures:: - SelectAccessibilityReparentInputEnabled() && + } else if ((RuntimeEnabledFeatures:: + SelectAccessibilityReparentInputEnabled() || + RuntimeEnabledFeatures:: + SelectAccessibilityNestedInputEnabled()) && select->FirstDescendantTextInput()) { select->FirstDescendantTextInput()->Focus(focus_params); }
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc index 4ffde71d..845218f 100644 --- a/third_party/blink/renderer/core/html/forms/html_select_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -134,8 +134,10 @@ if (record->attributeName() == html_names::kTabindexAttr || record->attributeName() == html_names::kContenteditableAttr) { AddDescendantDisallowedErrorToNode(*record->target()); - } else if (RuntimeEnabledFeatures:: - SelectAccessibilityReparentInputEnabled() && + } else if ((RuntimeEnabledFeatures:: + SelectAccessibilityReparentInputEnabled() || + RuntimeEnabledFeatures:: + SelectAccessibilityNestedInputEnabled()) && record->attributeName() == html_names::kTypeAttr) { if (auto* input = DynamicTo<HTMLInputElement>(record->target())) { if (input->IsTextField()) { @@ -216,7 +218,8 @@ } void MaybeAddDescendantTextInput(Node* node) { - if (RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled()) { + if (RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled() || + RuntimeEnabledFeatures::SelectAccessibilityNestedInputEnabled()) { if (auto* input = DynamicTo<HTMLInputElement>(node); input && input->IsTextField()) { select_->AddDescendantTextInput(input); @@ -225,7 +228,8 @@ } void MaybeRemoveDescendantTextInput(Node* node) { - if (RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled()) { + if (RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled() || + RuntimeEnabledFeatures::SelectAccessibilityNestedInputEnabled()) { if (auto* input = DynamicTo<HTMLInputElement>(node); input && input->IsTextField()) { select_->RemoveDescendantTextInput(input); @@ -327,7 +331,8 @@ return parent && IsA<HTMLSelectElement>(*parent) && !ElementTraversal::PreviousSibling(node); } - if (RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled()) { + if (RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled() || + RuntimeEnabledFeatures::SelectAccessibilityNestedInputEnabled()) { // <select>s are allowed to have one <input> before the options. We should // probably find a way to figure out if the <input> is actually placed // before the <option>s or not. @@ -449,7 +454,8 @@ } bool IsAllowedDescendantOfSelect(const Node& descendant, const Node& parent) { - if (RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled()) { + if (RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled() || + RuntimeEnabledFeatures::SelectAccessibilityNestedInputEnabled()) { // <select>s are allowed to have one text <input>, although it should be // placed before any of the <option>s. if (select_->FirstDescendantTextInput() == descendant) { @@ -2356,14 +2362,16 @@ } void HTMLSelectElement::AddDescendantTextInput(HTMLInputElement* input) { - CHECK(RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled()); + CHECK(RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled() || + RuntimeEnabledFeatures::SelectAccessibilityNestedInputEnabled()); CHECK(input->IsTextField()); descendant_text_inputs_.Add(input); input->SetFirstAncestorSelectElement(this); } void HTMLSelectElement::RemoveDescendantTextInput(HTMLInputElement* input) { - CHECK(RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled()); + CHECK(RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled() || + RuntimeEnabledFeatures::SelectAccessibilityNestedInputEnabled()); descendant_text_inputs_.Remove(input); input->SetFirstAncestorSelectElement(nullptr); }
diff --git a/third_party/blink/renderer/core/html/forms/select_type.cc b/third_party/blink/renderer/core/html/forms/select_type.cc index f81577523..4833c283 100644 --- a/third_party/blink/renderer/core/html/forms/select_type.cc +++ b/third_party/blink/renderer/core/html/forms/select_type.cc
@@ -151,7 +151,9 @@ HTMLElement* element_to_focus = nullptr; if (auto* input = select->FirstDescendantTextInput(); input && - RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled()) { + (RuntimeEnabledFeatures:: + SelectAccessibilityReparentInputEnabled() || + RuntimeEnabledFeatures::SelectAccessibilityNestedInputEnabled())) { // If there is a filter input at the top of the picker, then that // should be focused instead of options when opening. element_to_focus = input;
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 0a82b714..630d974 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
@@ -86,6 +86,41 @@ return Position(); } +void AppendWrappedNode(const Element& container, + const Node& node, + const OffsetMapping& mapping, + InlineCursor& cursor, + Position& break_position, + StringBuilder& result) { + if (IsA<HTMLBRElement>(node)) { + if (RuntimeEnabledFeatures::TextareaLineEndingsAsBrEnabled() && + !TextControlElement::IsPlaceholderBreakElement(&node)) { + result.Append(kNewlineCharacter); + } else { + DCHECK_EQ(&node, container.lastChild()); + } + } else if (auto* text_node = DynamicTo<Text>(node)) { + String data = text_node->data(); + unsigned length = data.length(); + unsigned position = 0; + while (break_position.AnchorNode() == node && + static_cast<unsigned>(break_position.OffsetInContainerNode()) <= + length) { + unsigned break_offset = break_position.OffsetInContainerNode(); + if (break_offset > position) { + result.Append(data, position, break_offset - position); + position = break_offset; + result.Append(kNewlineCharacter); + } + break_position = GetNextSoftBreak(mapping, cursor); + } + result.Append(data, position, length - position); + } + while (break_position.AnchorNode() == node) { + break_position = GetNextSoftBreak(mapping, cursor); + } +} + } // namespace TextControlElement::TextControlElement(const QualifiedName& tag_name, @@ -1015,6 +1050,34 @@ if (!layout_object) return Value(); + if (RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled()) { + StringBuilder result; + bool has_valid_ifcs = false; + for (auto* anonymous = To<LayoutBlockFlow>(layout_object->FirstChild()); + anonymous; anonymous = To<LayoutBlockFlow>(anonymous->NextSibling())) { + InlineCursor cursor(*anonymous); + if (!cursor) { + continue; + } + const auto* mapping = InlineNode::GetOffsetMapping(anonymous); + if (!mapping) { + continue; + } + has_valid_ifcs = true; + Position break_position = GetNextSoftBreak(*mapping, cursor); + const Node* node = anonymous->FirstChild() + ? anonymous->FirstChild()->GetNode() + : nullptr; + for (; node && node->GetLayoutObject() && + node->GetLayoutObject()->Parent() == anonymous; + node = node->nextSibling()) { + AppendWrappedNode(*inner_text, *node, *mapping, cursor, break_position, + result); + } + } + return has_valid_ifcs ? result.ReleaseString() : Value(); + } + if (layout_object->IsLayoutNGObject()) { InlineCursor cursor(*layout_object); if (!cursor) @@ -1025,32 +1088,8 @@ Position break_position = GetNextSoftBreak(*mapping, cursor); StringBuilder result; for (Node& node : NodeTraversal::DescendantsOf(*inner_text)) { - if (IsA<HTMLBRElement>(node)) { - if (RuntimeEnabledFeatures::TextareaLineEndingsAsBrEnabled() && - !IsPlaceholderBreakElement(&node)) { - result.Append(kNewlineCharacter); - } else { - DCHECK_EQ(&node, inner_text->lastChild()); - } - } else if (auto* text_node = DynamicTo<Text>(node)) { - String data = text_node->data(); - unsigned length = data.length(); - unsigned position = 0; - while (break_position.AnchorNode() == node && - static_cast<unsigned>(break_position.OffsetInContainerNode()) <= - length) { - unsigned break_offset = break_position.OffsetInContainerNode(); - if (break_offset > position) { - result.Append(data, position, break_offset - position); - position = break_offset; - result.Append(kNewlineCharacter); - } - break_position = GetNextSoftBreak(*mapping, cursor); - } - result.Append(data, position, length - position); - } - while (break_position.AnchorNode() == node) - break_position = GetNextSoftBreak(*mapping, cursor); + AppendWrappedNode(*inner_text, node, *mapping, cursor, break_position, + result); } return result.ToString(); }
diff --git a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc index ca0fa78..3f04043 100644 --- a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc +++ b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
@@ -150,7 +150,12 @@ ? EUserModify::kReadOnly : EUserModify::kReadWritePlaintextOnly); style_builder.SetDisplay(EDisplay::kBlock); - style_builder.SetHasLineIfEmpty(true); + // HasLineIfEmpty is unnecessary for <textarea> with anonymous IFCs because: + // - <textarea> has the placeholder break element. + // - HasLineIfEmpty is harmful for internal anonymous blocks. + if (!RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled()) { + style_builder.SetHasLineIfEmpty(true); + } if (!start_style.ApplyControlFixedSize(host)) { Length caret_width(GetDocument().View()->CaretWidth(), Length::kFixed); if (IsHorizontalWritingMode(style_builder.GetWritingMode())) { @@ -162,6 +167,7 @@ style_builder.SetShouldIgnoreOverflowPropertyForInlineBlockBaseline(); if (!IsA<HTMLTextAreaElement>(host)) { + style_builder.SetHasLineIfEmpty(true); style_builder.SetScrollbarColor(nullptr); style_builder.SetWhiteSpace(EWhiteSpace::kPre); style_builder.SetOverflowWrap(EOverflowWrap::kNormal);
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc index 71ebf70..c5f6e87 100644 --- a/third_party/blink/renderer/core/html/html_element.cc +++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -2791,7 +2791,7 @@ AtomicString(url), GetDocument().CompleteURL(url), Referrer(GetExecutionContext()->OutgoingReferrer(), GetExecutionContext()->GetReferrerPolicy()), - /*origin_clean=*/true, /*is_ad_related=*/false)); + OriginClean::kTrue, false /* is_ad_related */)); if (initiator_name) { image_value->SetInitiator(initiator_name); }
diff --git a/third_party/blink/renderer/core/layout/block_node.cc b/third_party/blink/renderer/core/layout/block_node.cc index a3974f93f..75633e4 100644 --- a/third_party/blink/renderer/core/layout/block_node.cc +++ b/third_party/blink/renderer/core/layout/block_node.cc
@@ -38,6 +38,7 @@ #include "third_party/blink/renderer/core/layout/inline/inline_cursor.h" #include "third_party/blink/renderer/core/layout/inline/inline_node.h" #include "third_party/blink/renderer/core/layout/layout_block_flow.h" +#include "third_party/blink/renderer/core/layout/layout_box_utils.h" #include "third_party/blink/renderer/core/layout/layout_inline.h" #include "third_party/blink/renderer/core/layout/layout_input_node.h" #include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni index ce3ce1f..2fef536 100644 --- a/third_party/blink/renderer/core/layout/build.gni +++ b/third_party/blink/renderer/core/layout/build.gni
@@ -133,6 +133,7 @@ "forms/layout_fieldset.h", "forms/layout_text_control.cc", "forms/layout_text_control.h", + "forms/layout_text_control_inner_editor.cc", "forms/layout_text_control_inner_editor.h", "forms/layout_text_control_multi_line.cc", "forms/layout_text_control_multi_line.h", @@ -723,6 +724,7 @@ "flex/flex_layout_algorithm_test.cc", "forms/fieldset_layout_algorithm_test.cc", "forms/layout_fieldset_test.cc", + "forms/layout_text_control_inner_editor_test.cc", "forms/layout_text_control_single_line_test.cc", "forms/layout_text_control_test.cc", "fragmentation_test.cc",
diff --git a/third_party/blink/renderer/core/layout/forms/layout_text_control_inner_editor.cc b/third_party/blink/renderer/core/layout/forms/layout_text_control_inner_editor.cc new file mode 100644 index 0000000..03a002d1 --- /dev/null +++ b/third_party/blink/renderer/core/layout/forms/layout_text_control_inner_editor.cc
@@ -0,0 +1,76 @@ +// 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/core/layout/forms/layout_text_control_inner_editor.h" + +#include "third_party/blink/renderer/core/html/forms/html_text_area_element.h" + +namespace blink { + +LayoutTextControlInnerEditor::LayoutTextControlInnerEditor(Element* element) + : LayoutBlockFlow(element), + is_multiline_(IsA<HTMLTextAreaElement>(element->OwnerShadowHost()) && + RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled()) {} + +void LayoutTextControlInnerEditor::AddChild(LayoutObject* new_child, + LayoutObject* before_child) { + NOT_DESTROYED(); + if (!is_multiline_) { + LayoutBlockFlow::AddChild(new_child, before_child); + return; + } + + // If a <textarea> has a value "line1\nline2\n", a + // TextControlInnerEditorElement for the <textarea> has the following DOM + // structure: + // + // TextControlInnerEditorElement + // * Text "line1" + // * HTMLBRElement + // * Text "line2" + // * HTMLBRElement + // * HTMLBRElement id="textarea-placeholder-break" + // + // This function wraps a pair of a Text and an HTMLBRElement with an anonymous + // block. So a child of LayoutTextControlInnerEditor must be an anonymous + // LayoutBlockFlow. + // Exception: It can have non-anonymous blocks during "TestRendering". + // See blink::ReplacementFragment. + // + // LayoutTextControlInnerEditor + // * LayoutBlockFlow (anonymous) + // - LayoutText "line1" + // - LayoutBR + // * LayoutBlockFlow (anonymous) + // - LayoutText "line2" + // - LayoutBR + // * LayoutBlockFlow (anonymous) + // - LayoutBR + + if (!before_child) { + auto* last_anonymous = DynamicTo<LayoutBlockFlow>(LastChild()); + if (last_anonymous && !last_anonymous->LastChild()->IsBR()) { + last_anonymous->AddChild(new_child); + return; + } + auto* anonymous = LayoutBlockFlow::CreateAnonymous(&GetDocument(), Style()); + LayoutBlockFlow::AddChild(anonymous); + anonymous->AddChild(new_child); + return; + } + + DCHECK(FirstChild()); + auto* before_parent = To<LayoutBlockFlow>(before_child->Parent()); + if (!new_child->IsBR()) { + before_parent->AddChild(new_child, before_child); + return; + } + auto* anonymous = LayoutBlockFlow::CreateAnonymous(&GetDocument(), Style()); + LayoutBlockFlow::AddChild(anonymous, before_parent); + before_parent->MoveChildrenTo(anonymous, before_parent->FirstChild(), + before_child, /* full_remove_insert */ true); + anonymous->AddChild(new_child); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/forms/layout_text_control_inner_editor.h b/third_party/blink/renderer/core/layout/forms/layout_text_control_inner_editor.h index bd9d478a..010192b 100644 --- a/third_party/blink/renderer/core/layout/forms/layout_text_control_inner_editor.h +++ b/third_party/blink/renderer/core/layout/forms/layout_text_control_inner_editor.h
@@ -13,13 +13,23 @@ // in <input> and <textarea>. class LayoutTextControlInnerEditor final : public LayoutBlockFlow { public: - explicit LayoutTextControlInnerEditor(Element* element) - : LayoutBlockFlow(element) {} + explicit LayoutTextControlInnerEditor(Element* element); const char* GetName() const override { NOT_DESTROYED(); return "LayoutTextControlInnerEditor"; } + + bool IsTextControlInnerEditor() const override { + NOT_DESTROYED(); + return true; + } + + void AddChild(LayoutObject* new_child, + LayoutObject* before_child = nullptr) override; + + private: + const bool is_multiline_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/forms/layout_text_control_inner_editor_test.cc b/third_party/blink/renderer/core/layout/forms/layout_text_control_inner_editor_test.cc new file mode 100644 index 0000000..7cc7edb --- /dev/null +++ b/third_party/blink/renderer/core/layout/forms/layout_text_control_inner_editor_test.cc
@@ -0,0 +1,121 @@ +// 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/core/testing/core_unit_test_helper.h" + +namespace blink { + +class LayoutTextControlInnerEditorTest : public RenderingTest {}; + +TEST_F(LayoutTextControlInnerEditorTest, AddChildWithoutTrailingLf) { + if (!RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled()) { + return; + } + SetBodyInnerHTML("<textarea id=ta>foo\nbar</textarea>"); + const auto* ta = GetLayoutBoxByElementId("ta"); + const auto* inner_editor = To<LayoutBlockFlow>(ta->FirstChildBox()); + ASSERT_TRUE(inner_editor); + + // The first anonymous block should have a LayoutText and a LayoutBR. + const auto* child = inner_editor->FirstChild(); + ASSERT_TRUE(child); + EXPECT_TRUE(child->IsAnonymousBlockFlow()); + const auto* grand_child = child->SlowFirstChild(); + ASSERT_TRUE(grand_child); + EXPECT_TRUE(grand_child->IsText()); + grand_child = grand_child->NextSibling(); + ASSERT_TRUE(grand_child); + EXPECT_TRUE(grand_child->IsBR()); + EXPECT_FALSE(grand_child->NextSibling()); + + // The second anonymous block should have only a LayoutText. + child = child->NextSibling(); + ASSERT_TRUE(child); + EXPECT_TRUE(child->IsAnonymousBlockFlow()); + grand_child = child->SlowFirstChild(); + ASSERT_TRUE(grand_child); + EXPECT_TRUE(grand_child->IsText()); + EXPECT_FALSE(grand_child->NextSibling()); + + child = child->NextSibling(); + EXPECT_FALSE(child); +} + +TEST_F(LayoutTextControlInnerEditorTest, AddChildWithTrailingLf) { + if (!RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled()) { + return; + } + SetBodyInnerHTML("<textarea id=ta>foo\nbar\n</textarea>"); + const auto* ta = GetLayoutBoxByElementId("ta"); + const auto* inner_editor = To<LayoutBlockFlow>(ta->FirstChildBox()); + ASSERT_TRUE(inner_editor); + + // The first anonymous block should have a LayoutText and a LayoutBR. + const auto* child = inner_editor->FirstChild(); + ASSERT_TRUE(child); + EXPECT_TRUE(child->IsAnonymousBlockFlow()); + const auto* grand_child = child->SlowFirstChild(); + ASSERT_TRUE(grand_child); + EXPECT_TRUE(grand_child->IsText()); + grand_child = grand_child->NextSibling(); + ASSERT_TRUE(grand_child); + EXPECT_TRUE(grand_child->IsBR()); + EXPECT_FALSE(grand_child->NextSibling()); + + // The second anonymous block should have a LayoutText and a LayoutBR. + child = child->NextSibling(); + ASSERT_TRUE(child); + EXPECT_TRUE(child->IsAnonymousBlockFlow()); + grand_child = child->SlowFirstChild(); + ASSERT_TRUE(grand_child); + EXPECT_TRUE(grand_child->IsText()); + grand_child = grand_child->NextSibling(); + ASSERT_TRUE(grand_child); + EXPECT_TRUE(grand_child->IsBR()); + EXPECT_FALSE(grand_child->NextSibling()); + + // The third anonymous block should have only a placeholder break. + child = child->NextSibling(); + ASSERT_TRUE(child); + EXPECT_TRUE(child->IsAnonymousBlockFlow()); + grand_child = child->SlowFirstChild(); + ASSERT_TRUE(grand_child); + EXPECT_TRUE(grand_child->IsBR()); + EXPECT_FALSE(grand_child->NextSibling()); + + EXPECT_FALSE(child->NextSibling()); +} + +TEST_F(LayoutTextControlInnerEditorTest, RemoveChildWithoutTrailingLf) { + if (!RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled()) { + return; + } + SetBodyInnerHTML("<textarea id=ta>foo\nbar</textarea>"); + const auto* ta = GetLayoutBoxByElementId("ta"); + const auto* inner_editor = To<LayoutBlockFlow>(ta->FirstChildBox()); + ASSERT_TRUE(inner_editor); + auto* inner_editor_element = To<Element>(inner_editor->GetNode()); + + // There should be two anonymous blocks before editing. + const auto* child = inner_editor->FirstChild(); + EXPECT_TRUE(child->IsAnonymousBlockFlow()); + child = child->NextSibling(); + EXPECT_TRUE(child); + EXPECT_TRUE(child->IsAnonymousBlockFlow()); + EXPECT_FALSE(child->NextSibling()); + + // Remove "bar". + auto* child_node = inner_editor_element->lastChild(); + ASSERT_TRUE(child_node); + EXPECT_TRUE(child_node->IsTextNode()); + child_node->remove(); + UpdateAllLifecyclePhasesForTest(); + + // There should be one anonymous block after editing. + child = inner_editor->FirstChild(); + EXPECT_TRUE(child->IsAnonymousBlockFlow()); + EXPECT_FALSE(child->NextSibling()); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/forms/layout_text_control_test.cc b/third_party/blink/renderer/core/layout/forms/layout_text_control_test.cc index c80900b6..263c0215 100644 --- a/third_party/blink/renderer/core/layout/forms/layout_text_control_test.cc +++ b/third_party/blink/renderer/core/layout/forms/layout_text_control_test.cc
@@ -24,8 +24,15 @@ } // Return the LayoutText from inside a text control's user agent shadow tree. LayoutText* GetInnerLayoutText(TextControlElement* control) { - return To<LayoutText>( - control->InnerEditorElement()->GetLayoutObject()->SlowFirstChild()); + auto* editor_box = control->InnerEditorElement()->GetLayoutObject(); + if (!RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled()) { + return To<LayoutText>(editor_box->SlowFirstChild()); + } + if (auto* anonymous_block = + DynamicTo<LayoutBlockFlow>(editor_box->SlowFirstChild())) { + return To<LayoutText>(anonymous_block->FirstChild()); + } + return To<LayoutText>(editor_box->SlowFirstChild()); } // Focus on |control|, select 1-3 characters, get the first LayoutText, and
diff --git a/third_party/blink/renderer/core/layout/grid/grid_named_line_collection.h b/third_party/blink/renderer/core/layout/grid/grid_named_line_collection.h index 7547e873..2ebdb578 100644 --- a/third_party/blink/renderer/core/layout/grid/grid_named_line_collection.h +++ b/third_party/blink/renderer/core/layout/grid/grid_named_line_collection.h
@@ -6,11 +6,10 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_GRID_NAMED_LINE_COLLECTION_H_ #include "third_party/blink/renderer/core/style/grid_enums.h" -#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" +#include "third_party/blink/renderer/core/style/named_grid_lines_map.h" namespace blink { -using NamedGridLinesMap = HashMap<String, Vector<wtf_size_t>>; struct ComputedGridTrackList; class GridNamedLineCollection {
diff --git a/third_party/blink/renderer/core/layout/inline/inline_cursor_test.cc b/third_party/blink/renderer/core/layout/inline/inline_cursor_test.cc index 4160771..182aa9e0 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_cursor_test.cc +++ b/third_party/blink/renderer/core/layout/inline/inline_cursor_test.cc
@@ -426,13 +426,26 @@ textarea.InnerEditorElement()->GetLayoutObject(); const LayoutBlockFlow& block_flow = *To<LayoutBlockFlow>(textarea_layout); - InlineCursor move_to_end_of_line(block_flow); - // Preparing the InlineCursor to start from beginning - // of second line(Empty Line). - move_to_end_of_line.MoveToNextLine(); + // Preparing the InlineCursor to start from beginning of the second line + // (Empty Line). + const LayoutBlockFlow* second_anonymous = + RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled() + ? To<LayoutBlockFlow>(block_flow.FirstChild()->NextSibling()) + : nullptr; + InlineCursor move_to_end_of_line(second_anonymous ? *second_anonymous + : block_flow); + if (!second_anonymous) { + // Preparing the InlineCursor to start from beginning + // of second line(Empty Line). + move_to_end_of_line.MoveToNextLine(); + } InlineCursor next_line = move_to_end_of_line.CursorForDescendants(); // Verify if it has been successfully placed at the correct position. - EXPECT_EQ(4u, next_line.Current().TextStartOffset()); + if (!second_anonymous) { + EXPECT_EQ(4u, next_line.Current().TextStartOffset()); + } else { + EXPECT_EQ(0u, next_line.Current().TextStartOffset()); + } const PositionWithAffinity end_position = move_to_end_of_line.PositionForEndOfLine(); if (RuntimeEnabledFeatures::TextareaLineEndingsAsBrEnabled()) { @@ -451,13 +464,26 @@ textarea.InnerEditorElement()->GetLayoutObject(); const LayoutBlockFlow& block_flow = *To<LayoutBlockFlow>(textarea_layout); - InlineCursor move_to_end_of_line(block_flow); - // Preparing the InlineCursor to start from beginning - // of second line(Empty Line). - move_to_end_of_line.MoveToNextLine(); + // Preparing the InlineCursor to start from beginning of the second line + // (Empty Line). + const LayoutBlockFlow* second_anonymous = + RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled() + ? To<LayoutBlockFlow>(block_flow.FirstChild()->NextSibling()) + : nullptr; + InlineCursor move_to_end_of_line(second_anonymous ? *second_anonymous + : block_flow); + if (!second_anonymous) { + // Preparing the InlineCursor to start from beginning + // of second line(Empty Line). + move_to_end_of_line.MoveToNextLine(); + } InlineCursor next_line = move_to_end_of_line.CursorForDescendants(); // Verify if it has been successfully placed at the correct position. - EXPECT_EQ(4u, next_line.Current().TextStartOffset()); + if (!second_anonymous) { + EXPECT_EQ(4u, next_line.Current().TextStartOffset()); + } else { + EXPECT_EQ(0u, next_line.Current().TextStartOffset()); + } const PositionWithAffinity end_position = move_to_end_of_line.PositionForEndOfLine(); if (RuntimeEnabledFeatures::TextareaLineEndingsAsBrEnabled()) {
diff --git a/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm_test.cc index a8c33c62..abcca3c 100644 --- a/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm_test.cc +++ b/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm_test.cc
@@ -66,8 +66,12 @@ HTMLTextAreaElement* textarea = To<HTMLTextAreaElement>(GetElementById(id)); DCHECK(textarea); - InlineCursor cursor(*To<LayoutBlockFlow>( - textarea->InnerEditorElement()->GetLayoutObject())); + LayoutBlockFlow* block_flow = + To<LayoutBlockFlow>(textarea->InnerEditorElement()->GetLayoutObject()); + if (RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled()) { + block_flow = To<LayoutBlockFlow>(block_flow->FirstChild()); + } + InlineCursor cursor(*block_flow); cursor.MoveToFirstLine(); EXPECT_TRUE(cursor.IsNotNull());
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc index 4677515c..77098d3 100644 --- a/third_party/blink/renderer/core/layout/layout_block_flow.cc +++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -84,6 +84,10 @@ !block.IsScrollMarkerGroup(); } +bool IsInnerEditorChild(const LayoutBlockFlow& block) { + return block.Parent() && block.Parent()->IsTextControlInnerEditor(); +} + } // anonymous namespace struct SameSizeAsLayoutBlockFlow : public LayoutBlock { @@ -221,7 +225,7 @@ static bool IsMergeableAnonymousBlock(const LayoutBlockFlow* block) { return block->IsAnonymousBlockFlow() && !block->BeingDestroyed() && - !block->IsViewTransitionRoot(); + !block->IsViewTransitionRoot() && !IsInnerEditorChild(*block); } void LayoutBlockFlow::RemoveChild(LayoutObject* old_child) { @@ -232,6 +236,7 @@ LayoutBox::RemoveChild(old_child); return; } + const bool is_inner_editor_child = IsAnonymous() && IsInnerEditorChild(*this); // If this child is a block, and if our previous and next siblings are both // anonymous blocks with inline content, then we can go ahead and fold the @@ -274,6 +279,24 @@ LayoutBlock::RemoveChild(old_child); + if (is_inner_editor_child && !BeingDestroyed()) { + if (old_child->IsBR() && FirstChild()) { + // We removed a LayoutBR from `this`. If this still contains LayoutTexts, + // we move them to the next anonymous block. Then, remove `this` from the + // parent. + if (auto* next_anonymous = To<LayoutBlockFlow>(NextSibling())) { + CHECK(next_anonymous->IsAnonymous()); + MoveAllChildrenTo(next_anonymous, next_anonymous->FirstChild(), + /* full_remove_insert */ true); + } + } + if (!FirstChild() && Parent()) { + Parent()->RemoveChild(this); + Destroy(); + } + return; + } + LayoutObject* child = prev ? prev : next; auto* child_block_flow = DynamicTo<LayoutBlockFlow>(child); if (child_block_flow && !child_block_flow->PreviousSibling() && @@ -287,7 +310,9 @@ if (FirstChild() && !BeingDestroyed() && !old_child->IsFloatingOrOutOfFlowPositioned() && - !old_child->IsAnonymousBlockFlow()) { + !old_child->IsAnonymousBlockFlow() && + !(RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled() && + IsTextControlInnerEditor())) { // If the child we're removing means that we can now treat all children as // inline without the need for anonymous blocks, then do that. MakeChildrenInlineIfPossible();
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index a739462..06d4ccd 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -237,10 +237,14 @@ } const auto* inner_editor = textarea.InnerEditorElement(); + const auto* reference_box = + inner_editor ? inner_editor->GetLayoutBox() : nullptr; + if (RuntimeEnabledFeatures::TextareaMultipleIfcsEnabled() && reference_box && + reference_box->FirstChildBox()) { + reference_box = reference_box->FirstChildBox(); + } const LayoutUnit line_height = - inner_editor && inner_editor->GetLayoutBox() - ? inner_editor->GetLayoutBox()->FirstLineHeight() - : box.FirstLineHeight(); + reference_box ? reference_box->FirstLineHeight() : box.FirstLineHeight(); return line_height * textarea.rows() + scrollbar_thickness; }
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 fde70c2..ec149a5 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
@@ -53,7 +53,7 @@ // // This class actually doesn't have the box model but it exposes some common // functions or concepts that sub-classes can extend upon. For example, there -// are accessors for margins, borders, paddings and borderBoundingBox(). +// are accessors for margins, borders, and paddings. // // The reason for this partial implementation is that the 2 classes inheriting // from it (LayoutBox and LayoutInline) have different requirements but need to @@ -61,7 +61,7 @@ // // An important member of this class is PaintLayer, which is stored in a rare- // data pattern (see: Layer()). PaintLayers are instantiated for several reasons -// based on the return value of layerTypeRequired(). +// based on the return value of LayerTypeRequired(). // Interestingly, most SVG objects inherit from LayoutSVGModelObject and thus // can't have a PaintLayer. This is an unfortunate artifact of our // design as it limits code sharing and prevents hardware accelerating SVG @@ -438,7 +438,7 @@ // structure via remove/insert/appendChildNode. // Since they are typically called only to move objects around within // anonymous blocks (which only have layers in the case of column spans), the - // default for fullRemoveInsert is false rather than true. + // default for `full_remove_insert` is false rather than true. void MoveChildTo(LayoutBoxModelObject* to_box_model_object, LayoutObject* child, LayoutObject* before_child, @@ -461,9 +461,10 @@ MoveChildrenTo(to_box_model_object, SlowFirstChild(), nullptr, before_child, full_remove_insert); } - // Move all of the kids from |startChild| up to but excluding |endChild|. 0 - // can be passed as the |endChild| to denote that all the kids from - // |startChild| onwards should be moved. + // Move all of the kids from `start_child` up to but excluding `end_child`. 0 + // can be passed as the `end_child` to denote that all the kids from + // `start_child` onwards should be moved. Nothing happens if start_child == + // end_child. void MoveChildrenTo(LayoutBoxModelObject* to_box_model_object, LayoutObject* start_child, LayoutObject* end_child,
diff --git a/third_party/blink/renderer/core/layout/layout_input_node.h b/third_party/blink/renderer/core/layout/layout_input_node.h index d189c29..0272d1e 100644 --- a/third_party/blink/renderer/core/layout/layout_input_node.h +++ b/third_party/blink/renderer/core/layout/layout_input_node.h
@@ -13,7 +13,6 @@ #include "third_party/blink/renderer/core/layout/geometry/axis.h" #include "third_party/blink/renderer/core/layout/geometry/logical_size.h" #include "third_party/blink/renderer/core/layout/layout_box.h" -#include "third_party/blink/renderer/core/layout/layout_box_utils.h" #include "third_party/blink/renderer/core/layout/list/layout_outside_list_marker.h" #include "third_party/blink/renderer/platform/geometry/layout_unit.h" #include "third_party/blink/renderer/platform/text/writing_mode.h"
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc index 0734df1c..bbc1945 100644 --- a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc +++ b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
@@ -29,6 +29,7 @@ #include "third_party/blink/renderer/core/css/resolver/style_resolver.h" #include "third_party/blink/renderer/core/layout/fragmentation_utils.h" #include "third_party/blink/renderer/core/layout/geometry/writing_mode_converter.h" +#include "third_party/blink/renderer/core/layout/layout_box_utils.h" #include "third_party/blink/renderer/core/layout/layout_multi_column_set.h" #include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h" #include "third_party/blink/renderer/core/layout/layout_view.h"
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc index 529e24c..5d502c94 100644 --- a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc +++ b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
@@ -29,6 +29,7 @@ #include "third_party/blink/renderer/core/editing/position_with_affinity.h" #include "third_party/blink/renderer/core/layout/fragmentation_utils.h" #include "third_party/blink/renderer/core/layout/geometry/box_strut.h" +#include "third_party/blink/renderer/core/layout/layout_box_utils.h" #include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h" #include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h" #include "third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.h"
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index e201aa73d..0866009 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -4930,7 +4930,8 @@ // styling may apply to the entire subtree. for (LayoutObject* child = SlowFirstChild(); child; child = child->NextSibling()) { - if (!child->IsSelected()) { + // Anonymous objects never be IsSelected(). See SetSelectionStateIfNeeded(). + if (!child->IsSelected() && !child->IsAnonymous()) { continue; } if (child->CanBeSelectionLeaf()) {
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index c2d1156..71a8508 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -994,6 +994,10 @@ NOT_DESTROYED(); return false; } + virtual bool IsTextControlInnerEditor() const { + NOT_DESTROYED(); + return false; + } virtual bool IsTextField() const { NOT_DESTROYED(); return false;
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc index 6e6d864..41bb7c9 100644 --- a/third_party/blink/renderer/core/layout/layout_text.cc +++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -1056,14 +1056,8 @@ void LayoutText::TextDidChangeWithoutInvalidation() { NOT_DESTROYED(); TextOffsetMap offset_map; - String original_text = - (RuntimeEnabledFeatures::UseOriginalDomOffsetsForOffsetMapEnabled() && - GetDocument().GetSettings() && - GetDocument().GetSettings()->GetPasswordEchoEnabled()) - ? OriginalText() - : text_; - wtf_size_t original_length = original_text.length(); - text_ = TransformAndSecureText(original_text, offset_map); + wtf_size_t original_length = text_.length(); + text_ = TransformAndSecureText(text_, offset_map); SetVariableLengthTransformResult(original_length, offset_map); if (auto* secure_text_timer = SecureTextTimer::ActiveInstanceFor(this)) { // text_ may be updated later before timer fires. We invalidate the
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 d675f05..b88fe93b 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
@@ -428,6 +428,12 @@ // block-size of the table column / table column group. LogicalRect sections_bounding_box; for (const PhysicalFragmentLink& child : fragment.Children()) { + if (child->IsLayoutObjectDestroyedOrMoved()) { + // This code may be run on a dirty layout tree. The scroll anchor code, + // for instance, essentially always works on a dirty tree, and may + // invoke LayoutTableColumn::PhysicalLocation(), so that we end up here. + continue; + } if (child->IsTableSection()) { LogicalRect section_rect = table_converter.ToLogical( PhysicalRect(child.offset, child->Size()));
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc index bb0848d..eb4422f9 100644 --- a/third_party/blink/renderer/core/loader/frame_loader.cc +++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -1797,7 +1797,7 @@ MixedContentChecker::UpgradeInsecureRequest( resource_request, fetch_client_settings_object, window_for_logging, - frame_type, frame_->GetContentSettingsClient()); + frame_type, frame_->GetContentSettingsClient(), frame_); } void FrameLoader::WriteIntoTrace(perfetto::TracedValue context) const {
diff --git a/third_party/blink/renderer/core/loader/mixed_content_checker.cc b/third_party/blink/renderer/core/loader/mixed_content_checker.cc index c3a04f6..92fbcfc 100644 --- a/third_party/blink/renderer/core/loader/mixed_content_checker.cc +++ b/third_party/blink/renderer/core/loader/mixed_content_checker.cc
@@ -318,6 +318,31 @@ } // static +bool MixedContentChecker::IsMixedContentRestrictedInFrameContext( + LocalFrame* frame) { + if (!frame) { + return false; + } + // Check the top frame first. + Frame& top = frame->Tree().Top(); + if (SchemeRegistry::ShouldTreatURLSchemeAsRestrictingMixedContent( + top.GetSecurityContext() + ->GetSecurityOrigin() + ->GetOriginOrPrecursorOriginIfOpaque() + ->Protocol())) { + return true; + } + if (SchemeRegistry::ShouldTreatURLSchemeAsRestrictingMixedContent( + frame->GetSecurityContext() + ->GetSecurityOrigin() + ->GetOriginOrPrecursorOriginIfOpaque() + ->Protocol())) { + return true; + } + return false; +} + +// static Frame* MixedContentChecker::InWhichFrameIsContentMixed(LocalFrame* frame, const KURL& url) { // Frameless requests cannot be mixed content. @@ -858,14 +883,22 @@ mojom::blink::RequestContextType type, WebContentSettingsClient* settings_client, const ResourceRequest& resource_request, - ExecutionContext* execution_context_for_logging) { - const HttpsState https_state = fetch_client_settings_object->GetHttpsState(); + ExecutionContext* execution_context_for_logging, + LocalFrame* frame) { const KURL& request_url = resource_request.Url(); // We are currently not autoupgrading plugin loaded content, which is why // check_mode_for_plugin is hardcoded to kStrict. + bool settings_restricts_mixed_content; + if (frame) { + settings_restricts_mixed_content = + IsMixedContentRestrictedInFrameContext(frame); + } else { + settings_restricts_mixed_content = + fetch_client_settings_object->GetHttpsState() == HttpsState::kModern; + } if (!base::FeatureList::IsEnabled( blink::features::kMixedContentAutoupgrade) || - https_state == HttpsState::kNone || + !settings_restricts_mixed_content || MixedContent::ContextTypeFromRequestContext( type, MixedContent::CheckModeForPlugin::kStrict) != mojom::blink::MixedContentContextType::kOptionallyBlockable) { @@ -1000,7 +1033,8 @@ const FetchClientSettingsObject* fetch_client_settings_object, ExecutionContext* execution_context_for_logging, mojom::RequestContextFrameType frame_type, - WebContentSettingsClient* settings_client) { + WebContentSettingsClient* settings_client, + LocalFrame* frame) { // We always upgrade requests that meet any of the following criteria: // 1. Are for subresources. // 2. Are for nested frames. @@ -1025,7 +1059,7 @@ if (context == mojom::blink::RequestContextType::UNSPECIFIED || !MixedContentChecker::ShouldAutoupgrade( fetch_client_settings_object, context, settings_client, - resource_request, execution_context_for_logging)) { + resource_request, execution_context_for_logging, frame)) { return; } // We set the upgrade if insecure flag regardless of whether we autoupgrade
diff --git a/third_party/blink/renderer/core/loader/mixed_content_checker.h b/third_party/blink/renderer/core/loader/mixed_content_checker.h index 1c8149e..39e3c66 100644 --- a/third_party/blink/renderer/core/loader/mixed_content_checker.h +++ b/third_party/blink/renderer/core/loader/mixed_content_checker.h
@@ -112,7 +112,8 @@ mojom::blink::RequestContextType type, WebContentSettingsClient* settings_client, const ResourceRequest& resource_request, - ExecutionContext* execution_context_for_logging); + ExecutionContext* execution_context_for_logging, + LocalFrame* frame); static mojom::blink::MixedContentContextType ContextTypeForInspector( LocalFrame*, @@ -152,7 +153,8 @@ const FetchClientSettingsObject* fetch_client_settings_object, ExecutionContext* execution_context_for_logging, mojom::RequestContextFrameType, - WebContentSettingsClient* settings_client); + WebContentSettingsClient* settings_client, + LocalFrame* frame); static MixedContent::CheckModeForPlugin DecideCheckModeForPlugin(Settings*); @@ -162,6 +164,8 @@ private: FRIEND_TEST_ALL_PREFIXES(MixedContentCheckerTest, HandleCertificateError); + static bool IsMixedContentRestrictedInFrameContext(LocalFrame* frame); + static Frame* InWhichFrameIsContentMixed(LocalFrame*, const KURL&); static ConsoleMessage* CreateConsoleMessageAboutFetch(
diff --git a/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc b/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc index 56a4545e..c95b504 100644 --- a/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc +++ b/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc
@@ -16,6 +16,8 @@ #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/public/mojom/loader/mixed_content.mojom-blink.h" #include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h" +#include "third_party/blink/renderer/core/execution_context/security_context.h" +#include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/loader/empty_clients.h" @@ -349,7 +351,9 @@ // These are not used in test, but need to be implemented since they are pure // virtual. const KURL& BaseUrl() const override { return url; } - const SecurityOrigin* GetSecurityOrigin() const override { return nullptr; } + const SecurityOrigin* GetSecurityOrigin() const override { + return origin_.get(); + } network::mojom::ReferrerPolicy GetReferrerPolicy() const override { return network::mojom::ReferrerPolicy::kAlways; } @@ -362,10 +366,19 @@ const override { return set; } + void SetSecurityOrigin(String origin_url, String reference_origin) { + KURL origin_kurl(origin_url); + scoped_refptr<SecurityOrigin> reference = + SecurityOrigin::CreateFromString(reference_origin); + origin_ = SecurityOrigin::CreateWithReferenceOrigin(KURL(origin_url), + reference.get()); + } + scoped_refptr<SecurityOrigin> GetSecurityOrigin() { return origin_; } private: const KURL url = KURL("https://example.test"); const InsecureNavigationsSet set; + scoped_refptr<SecurityOrigin> origin_; }; TEST(MixedContentCheckerTest, @@ -376,12 +389,17 @@ request.SetRequestContext(mojom::blink::RequestContextType::AUDIO); TestFetchClientSettingsObject* settings = MakeGarbageCollected<TestFetchClientSettingsObject>(); + settings->SetSecurityOrigin("https://example.test", ""); // Used to get a non-null document. DummyPageHolder holder; + holder.GetFrame() + .DomWindow() + ->GetSecurityContext() + .SetSecurityOriginForTesting(settings->GetSecurityOrigin()); MixedContentChecker::UpgradeInsecureRequest( request, settings, holder.GetDocument().GetExecutionContext(), - mojom::RequestContextFrameType::kTopLevel, nullptr); + mojom::RequestContextFrameType::kTopLevel, nullptr, &holder.GetFrame()); EXPECT_FALSE(request.IsAutomaticUpgrade()); EXPECT_TRUE(request.UpgradeIfInsecure()); @@ -394,12 +412,18 @@ request.SetRequestContext(mojom::blink::RequestContextType::AUDIO); TestFetchClientSettingsObject* settings = MakeGarbageCollected<TestFetchClientSettingsObject>(); + settings->SetSecurityOrigin("https://example.test", ""); + // Used to get a non-null document. DummyPageHolder holder; + holder.GetFrame() + .DomWindow() + ->GetSecurityContext() + .SetSecurityOriginForTesting(settings->GetSecurityOrigin()); MixedContentChecker::UpgradeInsecureRequest( request, settings, holder.GetDocument().GetExecutionContext(), - mojom::RequestContextFrameType::kTopLevel, nullptr); + mojom::RequestContextFrameType::kTopLevel, nullptr, &holder.GetFrame()); EXPECT_TRUE(request.IsAutomaticUpgrade()); EXPECT_TRUE(request.UpgradeIfInsecure()); @@ -413,12 +437,18 @@ request.SetRequestContext(mojom::blink::RequestContextType::AUDIO); TestFetchClientSettingsObject* settings = MakeGarbageCollected<TestFetchClientSettingsObject>(); + settings->SetSecurityOrigin("https://example.test", ""); + // Used to get a non-null document. DummyPageHolder holder; + holder.GetFrame() + .DomWindow() + ->GetSecurityContext() + .SetSecurityOriginForTesting(settings->GetSecurityOrigin()); MixedContentChecker::UpgradeInsecureRequest( request, settings, holder.GetDocument().GetExecutionContext(), - mojom::RequestContextFrameType::kTopLevel, nullptr); + mojom::RequestContextFrameType::kTopLevel, nullptr, &holder.GetFrame()); EXPECT_FALSE(request.IsAutomaticUpgrade()); EXPECT_FALSE(request.UpgradeIfInsecure()); @@ -432,15 +462,76 @@ request.SetRequestContext(mojom::blink::RequestContextType::AUDIO); TestFetchClientSettingsObject* settings = MakeGarbageCollected<TestFetchClientSettingsObject>(); + settings->SetSecurityOrigin("https://example.test", ""); + // Used to get a non-null document. DummyPageHolder holder; + holder.GetFrame() + .DomWindow() + ->GetSecurityContext() + .SetSecurityOriginForTesting(settings->GetSecurityOrigin()); MixedContentChecker::UpgradeInsecureRequest( request, settings, holder.GetDocument().GetExecutionContext(), - mojom::RequestContextFrameType::kTopLevel, nullptr); + mojom::RequestContextFrameType::kTopLevel, nullptr, &holder.GetFrame()); EXPECT_FALSE(request.IsAutomaticUpgrade()); EXPECT_FALSE(request.UpgradeIfInsecure()); } +TEST(MixedContentCheckerTest, + AutoupgradeMixedContentInOpaqueOriginIfPrecursorIsSecure) { + test::TaskEnvironment task_environment; + ResourceRequest request; + request.SetUrl(KURL("http://example.test")); + request.SetRequestContext(mojom::blink::RequestContextType::IMAGE); + TestFetchClientSettingsObject* settings = + MakeGarbageCollected<TestFetchClientSettingsObject>(); + // Set the security origin to an opaque one, with a secure precursor. + settings->SetSecurityOrigin( + "data:text/html,<img src=http://example.test/insecureimage.jpg>", + "https://example.test"); + + // Used to get a non-null document. + DummyPageHolder holder; + holder.GetFrame() + .DomWindow() + ->GetSecurityContext() + .SetSecurityOriginForTesting(settings->GetSecurityOrigin()); + + MixedContentChecker::UpgradeInsecureRequest( + request, settings, holder.GetDocument().GetExecutionContext(), + mojom::RequestContextFrameType::kTopLevel, nullptr, &holder.GetFrame()); + + EXPECT_TRUE(request.IsAutomaticUpgrade()); + EXPECT_TRUE(request.UpgradeIfInsecure()); +} + +TEST(MixedContentCheckerTest, + DontAutoupgradeMixedContentInOpaqueOriginIfPrecursorIsNotSecure) { + test::TaskEnvironment task_environment; + ResourceRequest request; + request.SetUrl(KURL("http://example.test")); + request.SetRequestContext(mojom::blink::RequestContextType::IMAGE); + TestFetchClientSettingsObject* settings = + MakeGarbageCollected<TestFetchClientSettingsObject>(); + // Set the security origin to an opaque one, with a not secure precursor. + settings->SetSecurityOrigin( + "data:text/html,<img src=http://example.test/insecureimage.jpg>", + "http://example.test"); + + // Used to get a non-null document. + DummyPageHolder holder; + holder.GetFrame() + .DomWindow() + ->GetSecurityContext() + .SetSecurityOriginForTesting(settings->GetSecurityOrigin()); + + MixedContentChecker::UpgradeInsecureRequest( + request, settings, holder.GetDocument().GetExecutionContext(), + mojom::RequestContextFrameType::kTopLevel, nullptr, &holder.GetFrame()); + + EXPECT_FALSE(request.IsAutomaticUpgrade()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc index 6dbb02e..c9a105a 100644 --- a/third_party/blink/renderer/core/loader/preload_helper.cc +++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/core/loader/preload_helper.h" +#include "base/feature_list.h" #include "base/metrics/histogram_functions.h" #include "base/timer/elapsed_timer.h" #include "third_party/blink/public/common/features.h" @@ -246,6 +247,23 @@ } } +bool IsSubresourceLoad(PreloadHelper::LoadLinksFromHeaderMode mode) { + switch (mode) { + case PreloadHelper::LoadLinksFromHeaderMode::kDocumentBeforeCommit: + case PreloadHelper::LoadLinksFromHeaderMode:: + kDocumentAfterCommitWithoutViewport: + case PreloadHelper::LoadLinksFromHeaderMode:: + kDocumentAfterCommitWithViewport: + case PreloadHelper::LoadLinksFromHeaderMode::kDocumentAfterLoadCompleted: + return false; + case PreloadHelper::LoadLinksFromHeaderMode::kSubresourceFromMemoryCache: + case PreloadHelper::LoadLinksFromHeaderMode::kSubresourceNotFromMemoryCache: + return true; + default: + NOTREACHED(); + } +} + } // namespace void PreloadHelper::DnsPrefetchIfNeeded( @@ -790,6 +808,15 @@ LinkLoadParameters params(header, base_url); bool change_rel_to_prefetch = false; + // For security purposes, set `referrerpolicy: "no-referrer"` in link loads + // from subresources. See https://crbug.com/415810136 for details. + if (base::FeatureList::IsEnabled( + blink::features::kNoReferrerForPreloadFromSubresource)) { + if (IsSubresourceLoad(mode)) { + params.referrer_policy = network::mojom::ReferrerPolicy::kNever; + } + } + if (params.rel.IsLinkPreload() && recursive_prefetch_token) { // Only preload headers are expected to have a recursive prefetch token // In response to that token's existence, we treat the request as a
diff --git a/third_party/blink/renderer/core/loader/resource/font_resource_test.cc b/third_party/blink/renderer/core/loader/resource/font_resource_test.cc index fd44637..f381ca4d 100644 --- a/third_party/blink/renderer/core/loader/resource/font_resource_test.cc +++ b/third_party/blink/renderer/core/loader/resource/font_resource_test.cc
@@ -257,7 +257,7 @@ *MakeGarbageCollected<CSSUrlData>( AtomicString(url.GetString()), url, Referrer(document.Url(), document.GetReferrerPolicy()), - /*origin_clean=*/true, /*is_ad_related=*/false)); + OriginClean::kTrue, false /* is_ad_related */)); auto* src_value = CSSFontFaceSrcValue::Create(src_uri_value, nullptr /* world */);
diff --git a/third_party/blink/renderer/core/loader/worker_fetch_context.cc b/third_party/blink/renderer/core/loader/worker_fetch_context.cc index f6117f1..d6df000 100644 --- a/third_party/blink/renderer/core/loader/worker_fetch_context.cc +++ b/third_party/blink/renderer/core/loader/worker_fetch_context.cc
@@ -242,7 +242,7 @@ MixedContentChecker::UpgradeInsecureRequest( request, &GetResourceFetcherProperties().GetFetchClientSettingsObject(), global_scope_, mojom::blink::RequestContextFrameType::kNone, - global_scope_->ContentSettingsClient()); + global_scope_->ContentSettingsClient(), nullptr); } void WorkerFetchContext::PopulateResourceRequestBeforeCacheAccess(
diff --git a/third_party/blink/renderer/core/page/page.h b/third_party/blink/renderer/core/page/page.h index 7412056..038c2c38 100644 --- a/third_party/blink/renderer/core/page/page.h +++ b/third_party/blink/renderer/core/page/page.h
@@ -715,12 +715,8 @@ bool is_prerendering_ = false; String prerender_metric_suffix_; - // If true, warms up compositor on a certain loading event if the page is - // under prerendering. Only valid when the cc feature `kWarmUpCompositor` - // (controls the independent cc internal feature) and blink feature - // `kPrerender2WarmUpCompositor` (manages the trigger point of that cc - // feature for prerender case) are enabled. Please see crbug.com/41496019 for - // more details. + // If true, warms up compositor on `WebLocalFrameImpl::DidCommitLoad` if the + // page is under prerendering. bool should_warm_up_compositor_on_prerender_ = false; // If true, prepares the paint tree if the page is under prerendering. bool should_prepare_paint_tree_on_prerender_ = false;
diff --git a/third_party/blink/renderer/core/paint/inline_paint_context.cc b/third_party/blink/renderer/core/paint/inline_paint_context.cc index 21b65b3..0de61e20 100644 --- a/third_party/blink/renderer/core/paint/inline_paint_context.cc +++ b/third_party/blink/renderer/core/paint/inline_paint_context.cc
@@ -123,8 +123,7 @@ return 0; } if (decorations->size() == 1 && - (decorations->front().Lines() == style->GetTextDecorationLine() || - !RuntimeEnabledFeatures::CssDecoratingBoxPseudoFixEnabled())) { + decorations->front().Lines() == style->GetTextDecorationLine()) { inline_context_->ClearDecoratingBoxes(saved_decorating_boxes_); PushDecoratingBox(item, *layout_object, *style, *decorations); return 1;
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index 33aeade..148bfd23 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -761,208 +761,8 @@ const ComputedStyle& other) const { StyleDifference diff; uint64_t field_diff = FieldInvalidationDiff(*this, other); - while (field_diff) { - FieldDifference field = - static_cast<FieldDifference>(field_diff & (~field_diff + 1)); - field_diff &= field_diff - 1; // Clear the lowest bit. - switch (field) { - case kAccentColor: - if (AccentColorResolved() != other.AccentColorResolved()) { - diff.SetNeedsNormalPaintInvalidation(); - } - break; - case kBackground: - if (!BackgroundInternal().VisuallyEqual(other.BackgroundInternal())) { - diff.SetNeedsNormalPaintInvalidation(); - } - break; - case kBackgroundColor: - // If the background-color change is not due to a composited animation, - // then paint invalidation is required; but we can defer the decision - // until we know whether the color change will be rendered by the - // compositor. - diff.SetBackgroundColorChanged(); - break; - case kBlendMode: - diff.SetBlendModeChanged(); - break; - case kBorderImage: - if (!BorderVisualOverflowEqual(other)) { - diff.SetNeedsRecomputeVisualOverflow(); - } - break; - case kBorderOutlineVisitedColor: - if (BorderOutlineVisitedColorChanged(other)) { - diff.SetNeedsNormalPaintInvalidation(); - } - break; - case kBorderRadius: - diff.SetBorderRadiusChanged(); - break; - case kBorderVisual: - if (!BorderVisuallyEqual(other)) { - diff.SetNeedsNormalPaintInvalidation(); - } - break; - case kBorderWidth: - if (BorderTopWidth() != other.BorderTopWidth() || - BorderRightWidth() != other.BorderRightWidth() || - BorderBottomWidth() != other.BorderBottomWidth() || - BorderLeftWidth() != other.BorderLeftWidth()) { - diff.SetNeedsFullLayout(); - } - break; - case kClip: { - bool has_clip = HasOutOfFlowPosition() && !HasAutoClip(); - bool other_has_clip = - other.HasOutOfFlowPosition() && !other.HasAutoClip(); - if (has_clip != other_has_clip || - (has_clip && Clip() != other.Clip())) { - diff.SetCSSClipChanged(); - } - break; - } - case kClipPath: - diff.SetClipPathChanged(); - break; - case kColor: - diff.SetTextDecorationOrColorChanged(); - // If the (current)color changes and a filter or backdrop-filter uses - // it, the filter or backdrop-filter needs to be updated. - if (HasFilter() && Filter().UsesCurrentColor()) { - diff.SetFilterChanged(); - } - if (HasBackdropFilter() && BackdropFilter().UsesCurrentColor()) { - diff.SetCompositingReasonsChanged(); - } - break; - case kCompositing: - diff.SetCompositingReasonsChanged(); - break; - case kCornerShape: - // Unused. - break; - case kCurrentcolor: - // If a property has a value that contains a <color> that depends on - // 'currentcolor', for example: - // - // background-image: linear-gradient(currentColor, #fff) - // background-color: color-mix(in srgb, currentcolor ...) - // - // If the (current)color has changed, we need to recompute it even - // though the old and new property values are identical. - // - // NOTE: This is also handled to some degree by - // LayoutObject::AdjustStyleDifference. We should probably - // re-distribute the responsibilities between these two locations. - if ((GetCurrentColor() != other.GetCurrentColor() || - GetInternalVisitedCurrentColor() != - other.GetInternalVisitedCurrentColor()) && - HasPropertyDependingOnCurrentColor()) { - diff.SetNeedsNormalPaintInvalidation(); - } - break; - case kFilterData: - diff.SetFilterChanged(); - break; - case kHasTransform: - if (HasTransform() != other.HasTransform()) { - diff.SetOtherTransformPropertyChanged(); - } - break; - case kInset: - if (!diff.NeedsFullLayout() && HasInFlowPosition()) { - diff.SetNeedsPositionedMovementLayout(); - } - break; - case kLayout: - diff.SetNeedsFullLayout(); - break; - case kMargin: - if (!HasOutOfFlowPosition()) { - diff.SetNeedsFullLayout(); - } - break; - case kMask: - diff.SetMaskChanged(); - break; - case kOpacity: - diff.SetOpacityChanged(); - break; - case kOutline: - if (!OutlineVisuallyEqual(other)) { - diff.SetNeedsNormalPaintInvalidation(); - diff.SetNeedsRecomputeVisualOverflow(); - } - break; - case kOutOfFlow: - if (!diff.NeedsFullLayout() && HasOutOfFlowPosition()) { - diff.SetNeedsPositionedMovementLayout(); - } - break; - case kPaint: - diff.SetNeedsNormalPaintInvalidation(); - break; - case kReshape: - diff.SetNeedsReshape(); - diff.SetNeedsFullLayout(); - diff.SetNeedsNormalPaintInvalidation(); - break; - case kScrollAnchor: - diff.SetScrollAnchorDisablingPropertyChanged(); - break; - case kScrollbarColor: - if (UsedScrollbarColor() != other.UsedScrollbarColor()) { - diff.SetNeedsNormalPaintInvalidation(); - } - break; - case kScrollbarStyle: - if (HasPseudoElementStyle(kPseudoIdScrollbar) != - other.HasPseudoElementStyle(kPseudoIdScrollbar) || - UsesStandardScrollbarStyle() != - other.UsesStandardScrollbarStyle()) { - diff.SetNeedsFullLayout(); - diff.SetNeedsNormalPaintInvalidation(); - } - break; - case kStroke: - if (HasStroke() != other.HasStroke() || - HasDashArray() != other.HasDashArray()) { - diff.SetNeedsFullLayout(); - } - break; - case kTextDecoration: - diff.SetTextDecorationOrColorChanged(); - if (TextDecorationVisualOverflowChanged(other)) { - diff.SetNeedsRecomputeVisualOverflow(); - } - break; - case kTransformData: - diff.SetTransformDataChanged(); - break; - case kTransformOther: - diff.SetOtherTransformPropertyChanged(); - break; - case kTransformProperty: - diff.SetTransformPropertyChanged(); - break; - case kVisibility: - if ((Visibility() == EVisibility::kCollapse) != - (other.Visibility() == EVisibility::kCollapse)) { - diff.SetNeedsFullLayout(); - } - break; - case kVisualOverflow: - diff.SetNeedsRecomputeVisualOverflow(); - break; - case kZIndex: - diff.SetZIndexChanged(); - break; - } - } - - if (ShouldWrapLine() != other.ShouldWrapLine()) { + if ((field_diff & kReshape) || ShouldWrapLine() != other.ShouldWrapLine()) { diff.SetNeedsReshape(); diff.SetNeedsFullLayout(); diff.SetNeedsNormalPaintInvalidation(); @@ -981,34 +781,124 @@ diff.SetNeedsNormalPaintInvalidation(); } - if (!diff.NeedsFullLayout()) { - if (IsDisplayLayoutCustomBox() && - DiffNeedsFullLayoutForLayoutCustom(document, other)) { - diff.SetNeedsFullLayout(); - } - if (DisplayLayoutCustomParentName() && - DiffNeedsFullLayoutForLayoutCustomChild(document, other)) { - diff.SetNeedsFullLayout(); + if (!diff.NeedsFullLayout() && + DiffNeedsFullLayout(document, other, field_diff)) { + diff.SetNeedsFullLayout(); + } + + if (!diff.NeedsLayout()) { + if ((field_diff & kOutOfFlow) && HasOutOfFlowPosition()) { + diff.SetNeedsPositionedMovementLayout(); + } else if ((field_diff & kInset) && HasInFlowPosition()) { + diff.SetNeedsPositionedMovementLayout(); } } - if (!diff.NeedsNormalPaintInvalidation() && PaintImagesInternal()) { - for (const auto& image : PaintImagesInternal()->Images()) { - DCHECK(image); - if (DiffNeedsPaintInvalidationForPaintImage(*image, other, document)) { - diff.SetNeedsNormalPaintInvalidation(); - break; - } - } + if (!diff.NeedsNormalPaintInvalidation() && + DiffNeedsNormalPaintInvalidation(document, other, field_diff)) { + diff.SetNeedsNormalPaintInvalidation(); + } + + if (DiffNeedsRecomputeVisualOverflow(other, field_diff)) { + diff.SetNeedsRecomputeVisualOverflow(); } if (DiffCompositingReasonsChanged(other, field_diff)) { diff.SetCompositingReasonsChanged(); } + if (field_diff & kBackgroundColor) { + // If the background color change is not due to a composited animation, + // then paint invalidation is required; but we can defer the decision until + // we know whether the color change will be rendered by the compositor. + diff.SetBackgroundColorChanged(); + } + if (field_diff & kBlendMode) { + diff.SetBlendModeChanged(); + } + if (field_diff & kBorderRadius) { + diff.SetBorderRadiusChanged(); + } + if (field_diff & kClip) { + bool has_clip = HasOutOfFlowPosition() && !HasAutoClip(); + bool other_has_clip = other.HasOutOfFlowPosition() && !other.HasAutoClip(); + if (has_clip != other_has_clip || (has_clip && Clip() != other.Clip())) { + diff.SetCSSClipChanged(); + } + } + if (field_diff & kClipPath) { + diff.SetClipPathChanged(); + } + if (field_diff & kColor) { + diff.SetTextDecorationOrColorChanged(); + } + if (field_diff & kFilterData) { + diff.SetFilterChanged(); + } + if (field_diff & kHasTransform) { + if (HasTransform() != other.HasTransform()) { + diff.SetOtherTransformPropertyChanged(); + } + } + if (field_diff & kMask) { + diff.SetMaskChanged(); + } + if (field_diff & kOpacity) { + diff.SetOpacityChanged(); + } + if (field_diff & kScrollbarColor) { + if (UsedScrollbarColor() != other.UsedScrollbarColor()) { + diff.SetNeedsNormalPaintInvalidation(); + } + } + if (field_diff & kScrollbarStyle) { + if (HasPseudoElementStyle(kPseudoIdScrollbar) != + other.HasPseudoElementStyle(kPseudoIdScrollbar) || + UsesStandardScrollbarStyle() != other.UsesStandardScrollbarStyle()) { + diff.SetNeedsFullLayout(); + diff.SetNeedsNormalPaintInvalidation(); + } + } + if (field_diff & kTextDecoration) { + diff.SetTextDecorationOrColorChanged(); + } + if (field_diff & kTransformData) { + diff.SetTransformDataChanged(); + } + if (field_diff & kTransformOther) { + diff.SetOtherTransformPropertyChanged(); + } + if (field_diff & kTransformProperty) { + diff.SetTransformPropertyChanged(); + } + if (field_diff & kVisibility) { + if ((Visibility() == EVisibility::kCollapse) != + (other.Visibility() == EVisibility::kCollapse)) { + diff.SetNeedsFullLayout(); + } + } + if (field_diff & kZIndex) { + diff.SetZIndexChanged(); + } + + // If the (current)color changes and a filter or backdrop-filter uses it, the + // filter or backdrop-filter needs to be updated. This reads + // `diff.TextDecorationOrColorChanged()` and so needs to be after the setters, + // above. + if (diff.TextDecorationOrColorChanged()) { + if (HasFilter() && Filter().UsesCurrentColor()) { + diff.SetFilterChanged(); + } + if (HasBackdropFilter() && BackdropFilter().UsesCurrentColor()) { + // This could be optimized with a targeted backdrop-filter-changed + // invalidation. + diff.SetCompositingReasonsChanged(); + } + } + // The following condition needs to be at last, because it may depend on // conditions in diff computed above. - if (diff.TransformChanged()) { + if ((field_diff & kScrollAnchor) || diff.TransformChanged()) { diff.SetScrollAnchorDisablingPropertyChanged(); } @@ -1056,6 +946,48 @@ return false; } +bool ComputedStyle::DiffNeedsFullLayout(const Document& document, + const ComputedStyle& other, + uint64_t field_diff) const { + if (field_diff & kLayout) { + return true; + } + + if (field_diff & kBorderWidth) { + if (BorderTopWidth() != other.BorderTopWidth() || + BorderRightWidth() != other.BorderRightWidth() || + BorderBottomWidth() != other.BorderBottomWidth() || + BorderLeftWidth() != other.BorderLeftWidth()) { + return true; + } + } + + if ((field_diff & kMargin) && !HasOutOfFlowPosition()) { + return true; + } + + if (field_diff & kStroke) { + if (HasStroke() != other.HasStroke()) { + return true; + } + if (HasDashArray() != other.HasDashArray()) { + return true; + } + } + + if (IsDisplayLayoutCustomBox() && + DiffNeedsFullLayoutForLayoutCustom(document, other)) { + return true; + } + + if (DisplayLayoutCustomParentName() && + DiffNeedsFullLayoutForLayoutCustomChild(document, other)) { + return true; + } + + return false; +} + bool ComputedStyle::DiffNeedsFullLayoutForLayoutCustom( const Document& document, const ComputedStyle& other) const { @@ -1115,6 +1047,70 @@ return false; } +bool ComputedStyle::DiffNeedsNormalPaintInvalidation( + const Document& document, + const ComputedStyle& other, + uint64_t field_diff) const { + if (field_diff & kPaint) { + return true; + } + + if ((field_diff & kAccentColor) && + AccentColorResolved() != other.AccentColorResolved()) { + return true; + } + + if ((field_diff & kOutline) && !OutlineVisuallyEqual(other)) { + return true; + } + + if ((field_diff & kBackground) && + !BackgroundInternal().VisuallyEqual(other.BackgroundInternal())) { + return true; + } + + if (field_diff & kCurrentcolor) { + // If a property has a value that contains a <color> that depends on + // 'currentcolor', for example: + // + // background-image: linear-gradient(currentColor, #fff) + // background-color: color-mix(in srgb, currentcolor ...) + // + // If the (current)color has changed, we need to recompute it even though + // the old and new property values are identical. + // + // NOTE: This is also handled to some degree by + // LayoutObject::AdjustStyleDifference. We should probably re-distribute + // the responsibilities between these two locations. + if ((GetCurrentColor() != other.GetCurrentColor() || + GetInternalVisitedCurrentColor() != + other.GetInternalVisitedCurrentColor()) && + HasPropertyDependingOnCurrentColor()) { + return true; + } + } + + if ((field_diff & kBorderVisual) && !BorderVisuallyEqual(other)) { + return true; + } + + if ((field_diff & kBorderOutlineVisitedColor) && + BorderOutlineVisitedColorChanged(other)) { + return true; + } + + if (PaintImagesInternal()) { + for (const auto& image : PaintImagesInternal()->Images()) { + DCHECK(image); + if (DiffNeedsPaintInvalidationForPaintImage(*image, other, document)) { + return true; + } + } + } + + return false; +} + bool ComputedStyle::DiffNeedsPaintInvalidationForPaintImage( const StyleImage& image, const ComputedStyle& other, @@ -1196,8 +1192,35 @@ other); } +bool ComputedStyle::DiffNeedsRecomputeVisualOverflow( + const ComputedStyle& other, + uint64_t field_diff) const { + if (field_diff & kVisualOverflow) { + return true; + } + + if ((field_diff & kBorderImage) && !BorderVisualOverflowEqual(other)) { + return true; + } + + if ((field_diff & kOutline) && !OutlineVisuallyEqual(other)) { + return true; + } + + if ((field_diff & kTextDecoration) && + TextDecorationVisualOverflowChanged(other)) { + return true; + } + + return false; +} + bool ComputedStyle::DiffCompositingReasonsChanged(const ComputedStyle& other, uint64_t field_diff) const { + if (field_diff & kCompositing) { + return true; + } + if (UsedTransformStyle3D() != other.UsedTransformStyle3D()) { return true; }
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h index b6b3fef1..61cc0ef 100644 --- a/third_party/blink/renderer/core/style/computed_style.h +++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2611,14 +2611,22 @@ bool DiffNeedsFullLayoutAndPaintInvalidation(const ComputedStyle& other, uint64_t field_diff) const; + bool DiffNeedsFullLayout(const Document&, + const ComputedStyle& other, + uint64_t field_diff) const; bool DiffNeedsFullLayoutForLayoutCustom(const Document&, const ComputedStyle& other) const; bool DiffNeedsFullLayoutForLayoutCustomChild( const Document&, const ComputedStyle& other) const; + bool DiffNeedsNormalPaintInvalidation(const Document&, + const ComputedStyle& other, + uint64_t field_diff) const; bool DiffNeedsPaintInvalidationForPaintImage(const StyleImage&, const ComputedStyle& other, const Document&) const; + bool DiffNeedsRecomputeVisualOverflow(const ComputedStyle& other, + uint64_t field_diff) const; bool DiffCompositingReasonsChanged(const ComputedStyle& other, uint64_t field_diff) const; bool PotentialCompositingReasonsFor3DTransformChanged(
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 d1b2f74b..18fbf0c 100644 --- a/third_party/blink/renderer/core/style/style_fetched_image.cc +++ b/third_party/blink/renderer/core/style/style_fetched_image.cc
@@ -37,13 +37,17 @@ namespace blink { StyleFetchedImage::StyleFetchedImage(ImageResourceContent* image, - const CSSUrlData& url_data, const Document& document, bool is_lazyload_possibly_deferred, + bool is_from_origin_clean_style_sheet, + bool is_ad_related, + const KURL& url, const float override_image_resolution) - : url_data_(url_data), - document_(document), - override_image_resolution_(override_image_resolution) { + : document_(document), + url_(url), + override_image_resolution_(override_image_resolution), + is_from_origin_clean_style_sheet_(is_from_origin_clean_style_sheet), + is_ad_related_(is_ad_related) { is_image_resource_ = true; is_lazyload_possibly_deferred_ = is_lazyload_possibly_deferred; @@ -67,8 +71,10 @@ if (!other.IsImageResource()) { return false; } + const auto& other_image = To<StyleFetchedImage>(other); - return image_ == other_image.image_ && *url_data_ == *other_image.url_data_ && + + return image_ == other_image.image_ && url_ == other_image.url_ && EqualResolutions(override_image_resolution_, other_image.override_image_resolution_); } @@ -95,7 +101,12 @@ CSSValue* StyleFetchedImage::CssValue() const { return MakeGarbageCollected<CSSImageValue>( - *url_data_->MakeComputed(), const_cast<StyleFetchedImage*>(this)); + *MakeGarbageCollected<CSSUrlData>( + AtomicString(url_.GetString()), url_, Referrer(), + is_from_origin_clean_style_sheet_ ? OriginClean::kTrue + : OriginClean::kFalse, + is_ad_related_), + const_cast<StyleFetchedImage*>(this)); } CSSValue* StyleFetchedImage::ComputedCSSValue(const ComputedStyle&, @@ -129,10 +140,6 @@ return false; } -bool StyleFetchedImage::IsFromOriginCleanStyleSheet() const { - return url_data_->IsFromOriginCleanStyleSheet(); -} - float StyleFetchedImage::ApplyImageResolution(float multiplier) const { const Image& image = *image_->GetImage(); if (image.IsBitmapImage() && override_image_resolution_ > 0.0f) { @@ -153,7 +160,7 @@ gfx::SizeF size; if (auto* svg_image = DynamicTo<SVGImage>(image)) { const SVGImageViewInfo* view_info = - SVGImageForContainer::CreateViewInfo(*svg_image, FragmentIdentifier()); + SVGImageForContainer::CreateViewInfo(*svg_image, url_); const gfx::SizeF unzoomed_default_object_size = gfx::ScaleSize(default_object_size, 1 / multiplier); size = SVGImageForContainer::ConcreteObjectSize( @@ -172,7 +179,7 @@ NaturalSizingInfo sizing_info; if (auto* svg_image = DynamicTo<SVGImage>(image)) { const SVGImageViewInfo* view_info = - SVGImageForContainer::CreateViewInfo(*svg_image, FragmentIdentifier()); + SVGImageForContainer::CreateViewInfo(*svg_image, url_); sizing_info = SVGImageForContainer::GetNaturalDimensions(*svg_image, view_info) .value_or(NaturalSizingInfo::None()); @@ -191,7 +198,7 @@ Image& image = *image_->GetImage(); if (auto* svg_image = DynamicTo<SVGImage>(image)) { const SVGImageViewInfo* view_info = - SVGImageForContainer::CreateViewInfo(*svg_image, FragmentIdentifier()); + SVGImageForContainer::CreateViewInfo(*svg_image, url_); std::optional<NaturalSizingInfo> natural_sizing_info = SVGImageForContainer::GetNaturalDimensions(*svg_image, view_info); return natural_sizing_info && !natural_sizing_info->IsNone(); @@ -244,7 +251,7 @@ return image; } const SVGImageViewInfo* view_info = - SVGImageForContainer::CreateViewInfo(*svg_image, FragmentIdentifier()); + SVGImageForContainer::CreateViewInfo(*svg_image, url_); return SVGImageForContainer::Create( *svg_image, target_size, style.EffectiveZoom(), view_info, document.GetStyleEngine().ResolveColorSchemeForEmbedding(&style)); @@ -286,26 +293,12 @@ return true; } -const String& StyleFetchedImage::FragmentIdentifier() const { - if (cached_fragment_identifier_.IsNull()) { - cached_fragment_identifier_ = - KURL(url_data_->ResolvedUrl()).FragmentIdentifier().ToString(); - // If URL does not have a fragment identifier we'll get a null - // String. Normalize to the empty String to avoid repeated URL resolving. - if (!cached_fragment_identifier_) { - cached_fragment_identifier_ = g_empty_string; - } - } - return cached_fragment_identifier_; -} - bool StyleFetchedImage::CanBeSpeculativelyDecoded() const { return false; } void StyleFetchedImage::Trace(Visitor* visitor) const { visitor->Trace(image_); - visitor->Trace(url_data_); visitor->Trace(document_); StyleImage::Trace(visitor); ImageResourceObserver::Trace(visitor);
diff --git a/third_party/blink/renderer/core/style/style_fetched_image.h b/third_party/blink/renderer/core/style/style_fetched_image.h index 0b34e14..89992cb 100644 --- a/third_party/blink/renderer/core/style/style_fetched_image.h +++ b/third_party/blink/renderer/core/style/style_fetched_image.h
@@ -34,7 +34,6 @@ namespace blink { -class CSSUrlData; class Document; // This class represents an <image> that loads a single image resource (the @@ -45,9 +44,11 @@ public: StyleFetchedImage(ImageResourceContent* image, - const CSSUrlData& url_data, const Document& document, bool is_lazyload_possibly_deferred, + bool is_from_origin_clean_style_sheet, + bool is_ad_related, + const KURL& url, const float override_image_resolution = 0.0f); ~StyleFetchedImage() override; @@ -65,7 +66,6 @@ bool IsLoading() const override; bool ErrorOccurred() const override; bool IsAccessAllowed(String&) const override; - bool IsFromOriginCleanStyleSheet() const override; NaturalSizingInfo GetNaturalSizingInfo( float multiplier, @@ -91,6 +91,10 @@ void Trace(Visitor*) const override; + bool IsFromOriginCleanStyleSheet() const override { + return is_from_origin_clean_style_sheet_; + } + private: bool IsEqual(const StyleImage&) const override; void Prefinalize(); @@ -104,16 +108,19 @@ bool GetImageAnimationPolicy(mojom::blink::ImageAnimationPolicy&) override; bool CanBeSpeculativelyDecoded() const override; - const String& FragmentIdentifier() const; - - mutable String cached_fragment_identifier_; Member<ImageResourceContent> image_; - Member<const CSSUrlData> url_data_; Member<const Document> document_; + const KURL url_; + // This overrides an images natural resolution. // A value of zero indicates no override. const float override_image_resolution_; + + const bool is_from_origin_clean_style_sheet_; + + // Whether this was created by an ad-related CSSParserContext. + const bool is_ad_related_; }; template <>
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 ae73f17e..4eabef3 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_->ComputedCSSValue(); + return resource_css_value_->ComputedCSSValueMaybeLocal(); } bool StyleMaskSourceImage::CanRender() const {
diff --git a/third_party/blink/renderer/core/url_pattern/BUILD.gn b/third_party/blink/renderer/core/url_pattern/BUILD.gn index 84616fbc3..c5f78da5 100644 --- a/third_party/blink/renderer/core/url_pattern/BUILD.gn +++ b/third_party/blink/renderer/core/url_pattern/BUILD.gn
@@ -13,6 +13,7 @@ "url_pattern_canon.h", "url_pattern_component.cc", "url_pattern_component.h", + "url_pattern_options.h", ] public_deps = [
diff --git a/third_party/blink/renderer/core/url_pattern/url_pattern.cc b/third_party/blink/renderer/core/url_pattern/url_pattern.cc index eab01e9..22c3e12c 100644 --- a/third_party/blink/renderer/core/url_pattern/url_pattern.cc +++ b/third_party/blink/renderer/core/url_pattern/url_pattern.cc
@@ -547,8 +547,7 @@ if (exception_state.HadException()) return nullptr; - Options urlpattern_options; - urlpattern_options.ignore_case = options->ignoreCase(); + auto urlpattern_options = Options::FromV8URLPatternOptions(options); return MakeGarbageCollected<URLPattern>( protocol_component, username_component, password_component, @@ -564,7 +563,7 @@ Component* pathname, Component* search, Component* hash, - Options options, + const Options& options, base::PassKey<URLPattern> key) : protocol_(protocol), username_(username),
diff --git a/third_party/blink/renderer/core/url_pattern/url_pattern.h b/third_party/blink/renderer/core/url_pattern/url_pattern.h index c51c78a..c2be7a1 100644 --- a/third_party/blink/renderer/core/url_pattern/url_pattern.h +++ b/third_party/blink/renderer/core/url_pattern/url_pattern.h
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_url_pattern_component.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/url_pattern/url_pattern_component.h" +#include "third_party/blink/renderer/core/url_pattern/url_pattern_options.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/liburlpattern/parse.h" @@ -24,9 +25,8 @@ class CORE_EXPORT URLPattern : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); - struct Options final { - bool ignore_case; - }; + + using Options = url_pattern::Options; using Component = url_pattern::Component; public: @@ -72,7 +72,7 @@ Component* pathname, Component* search, Component* hash, - Options options, + const Options& options, base::PassKey<URLPattern> key); bool test(ScriptState* script_state,
diff --git a/third_party/blink/renderer/core/url_pattern/url_pattern_options.h b/third_party/blink/renderer/core/url_pattern/url_pattern_options.h new file mode 100644 index 0000000..fea7b83 --- /dev/null +++ b/third_party/blink/renderer/core/url_pattern/url_pattern_options.h
@@ -0,0 +1,32 @@ +// 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_CORE_URL_PATTERN_URL_PATTERN_OPTIONS_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_URL_PATTERN_URL_PATTERN_OPTIONS_H_ + +#include "base/check.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_url_pattern_options.h" + +namespace blink { + +class URLPatternOptions; + +namespace url_pattern { + +// A struct corresponds to `URLPatternOptions` in url_pattern_options.idl. +struct Options { + bool ignore_case = false; + + static Options FromV8URLPatternOptions(const URLPatternOptions* options) { + CHECK(options); + CHECK(options->hasIgnoreCase()); + + return {.ignore_case = options->ignoreCase()}; + } +}; + +} // namespace url_pattern +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_URL_PATTERN_URL_PATTERN_OPTIONS_H_
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc index 75c13500..7d39283 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -4459,7 +4459,8 @@ } AXObject* AXNodeObject::ChooserPopup() const { - if (RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled()) { + if (RuntimeEnabledFeatures::SelectAccessibilityReparentInputEnabled() || + RuntimeEnabledFeatures::SelectAccessibilityNestedInputEnabled()) { // The first input inside of a select filters the listbox, and therefore // controls it. if (auto* input = DynamicTo<HTMLInputElement>(GetNode())) {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc index 73efa1a..8d9a7a8 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
@@ -457,10 +457,11 @@ } } -base::span<std::pair<QualifiedName, uint32_t>> +base::span<std::pair<QualifiedName, Element::TinyBloomFilter>> AXRelationCache::GetTextRelationAttributes() { // Avoid issues with commas within the type name in DEFINE_STATIC_LOCAL(). - using QualifiedNameArray = std::array<std::pair<QualifiedName, uint32_t>, 3>; + using QualifiedNameArray = + std::array<std::pair<QualifiedName, Element::TinyBloomFilter>, 3>; DEFINE_STATIC_LOCAL( QualifiedNameArray, text_attributes, ({{html_names::kAriaLabelledbyAttr, @@ -563,10 +564,11 @@ } } -base::span<std::pair<QualifiedName, uint32_t>> +base::span<std::pair<QualifiedName, Element::TinyBloomFilter>> AXRelationCache::GetOtherRelationAttributes() { // Avoid issues with commas within the type name in DEFINE_STATIC_LOCAL(). - using QualifiedNameArray = std::array<std::pair<QualifiedName, uint32_t>, 5>; + using QualifiedNameArray = + std::array<std::pair<QualifiedName, Element::TinyBloomFilter>, 5>; DEFINE_STATIC_LOCAL( QualifiedNameArray, attributes, ({{html_names::kAriaControlsAttr,
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc index 8c102f3..b1b4965 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc +++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio.cc
@@ -52,12 +52,6 @@ using IntRangeSet = blink::media_constraints::NumericRangeSet<int>; using StringSet = blink::media_constraints::DiscreteSet<std::string>; -// The presence of a MediaStreamAudioSource object indicates whether the source -// in question is currently in use, or not. This convenience enum helps -// identifying whether a source is available and, if so, whether it has audio -// processing enabled or disabled. -enum class SourceType { kNone, kUnprocessed, kNoApmProcessed, kApmProcessed }; - // The sample size is set to 16 due to the Signed-16 format representation. int32_t GetSampleSize() { return media::SampleFormatToBitsPerChannel(media::kSampleFormatS16); @@ -120,35 +114,44 @@ std::tuple<double, bool, EcModeScore, int> score; }; -// This class represents the output of DeviceContainer::InfoFromSource and is -// used to obtain information regarding an active source, if that exists. +// Information regarding an active source, if that exists. class SourceInfo { public: - SourceInfo(SourceType type, - const AudioProcessingProperties& properties, - std::optional<int> channels, - std::optional<int> sample_rate, - std::optional<double> latency) - : type_(type), - properties_(properties), + static std::optional<SourceInfo> FromSource( + blink::MediaStreamAudioSource* source) { + if (!source) { + return std::nullopt; + } + + media::AudioParameters source_parameters = source->GetAudioParameters(); + std::optional<AudioProcessingProperties> properties = + source->GetAudioProcessingProperties(); + CHECK(properties); + + return SourceInfo(*properties, source_parameters.channels(), + source_parameters.sample_rate(), + source_parameters.GetBufferDuration().InSecondsF()); + } + + const AudioProcessingProperties& properties() const { return properties_; } + int channels() const { return channels_; } + int sample_rate() const { return sample_rate_; } + double latency() const { return latency_; } + + private: + SourceInfo(const AudioProcessingProperties& properties, + int channels, + int sample_rate, + double latency) + : properties_(properties), channels_(std::move(channels)), sample_rate_(std::move(sample_rate)), latency_(latency) {} - bool HasActiveSource() { return type_ != SourceType::kNone; } - - SourceType type() { return type_; } - const AudioProcessingProperties& properties() { return properties_; } - const std::optional<int>& channels() { return channels_; } - const std::optional<int>& sample_rate() { return sample_rate_; } - const std::optional<double>& latency() { return latency_; } - - private: - const SourceType type_; const AudioProcessingProperties properties_; - const std::optional<int> channels_; - const std::optional<int> sample_rate_; - const std::optional<double> latency_; + const int channels_; + const int sample_rate_; + const double latency_; }; // Container for each independent boolean constrainable property. @@ -394,17 +397,17 @@ is_device_capture_(true) {} EchoCancellationContainer(Vector<EchoCancellationType> allowed_values, - bool has_active_source, + std::optional<SourceInfo> source_info, bool is_device_capture, media::AudioParameters device_parameters, - AudioProcessingProperties properties, bool is_reconfiguration_allowed) : ec_mode_allowed_values_( EchoCancellationTypeSet(std::move(allowed_values))), device_parameters_(device_parameters), is_device_capture_(is_device_capture) { - if (!has_active_source) + if (!source_info) { return; + } // If HW echo cancellation is used, reconfiguration is not always supported // and only the current values are allowed. Otherwise, allow all possible @@ -421,17 +424,17 @@ // Allowing it when the system echo cancellation is enforced via flag, // for evaluation purposes. media::IsSystemEchoCancellationEnforced() || - properties.echo_cancellation_type != + source_info->properties().echo_cancellation_type != EchoCancellationType::kEchoCancellationSystem; #endif if (is_reconfiguration_allowed && is_aec_reconfiguration_supported) { return; } - ec_mode_allowed_values_ = - EchoCancellationTypeSet({properties.echo_cancellation_type}); + ec_mode_allowed_values_ = EchoCancellationTypeSet( + {source_info->properties().echo_cancellation_type}); ec_allowed_values_ = - BoolSet({properties.echo_cancellation_type != + BoolSet({source_info->properties().echo_cancellation_type != EchoCancellationType::kEchoCancellationDisabled}); } @@ -723,7 +726,7 @@ // related |parameters.effects()|, and (b) any combination of processing // properties settings. static ProcessingBasedContainer CreateApmProcessedContainer( - const SourceInfo& source_info, + std::optional<SourceInfo> source_info, mojom::blink::MediaStreamType stream_type, bool is_device_capture, const media::AudioParameters& device_parameters, @@ -748,7 +751,7 @@ // allowed by the |parameters.effects()|, or none, while (b) all other // processing properties settings cannot be enabled. static ProcessingBasedContainer CreateNoApmProcessedContainer( - const SourceInfo& source_info, + std::optional<SourceInfo> source_info, bool is_device_capture, const media::AudioParameters& device_parameters, bool is_reconfiguration_allowed) { @@ -771,7 +774,7 @@ // allowed by the |parameters.effects()|, or none, while (c) all processing // properties settings cannot be enabled. static ProcessingBasedContainer CreateUnprocessedContainer( - const SourceInfo& source_info, + std::optional<SourceInfo> source_info, bool is_device_capture, const media::AudioParameters& device_parameters, bool is_reconfiguration_allowed) { @@ -946,7 +949,7 @@ IntRangeSet sample_size_range, Vector<int> channels_set, IntRangeSet sample_rate_range, - SourceInfo source_info, + std::optional<SourceInfo> source_info, bool is_device_capture, media::AudioParameters device_parameters, bool is_reconfiguration_allowed) @@ -963,9 +966,8 @@ EchoCancellationType::kEchoCancellationSystem); } echo_cancellation_container_ = EchoCancellationContainer( - std::move(echo_cancellation_types), source_info.HasActiveSource(), - is_device_capture, device_parameters, source_info.properties(), - is_reconfiguration_allowed); + std::move(echo_cancellation_types), source_info, is_device_capture, + device_parameters, is_reconfiguration_allowed); auto_gain_control_container_ = AutoGainControlContainer(auto_gain_control_set); @@ -977,9 +979,8 @@ // Allow the full set of supported values when the device is not open or // when the candidate settings would open the device using an unprocessed // source. - if (!source_info.HasActiveSource() || - (is_reconfiguration_allowed && - processing_type_ == ProcessingType::kUnprocessed)) { + if (!source_info || (is_reconfiguration_allowed && + processing_type_ == ProcessingType::kUnprocessed)) { return; } @@ -988,19 +989,16 @@ // for this is that opening multiple instances of the APM is costly. // TODO(crbug.com/1147928): Consider removing this restriction. auto_gain_control_container_ = AutoGainControlContainer( - BoolSet({source_info.properties().auto_gain_control})); + BoolSet({source_info->properties().auto_gain_control})); - noise_suppression_container_ = - BooleanContainer(BoolSet({source_info.properties().noise_suppression})); + noise_suppression_container_ = BooleanContainer( + BoolSet({source_info->properties().noise_suppression})); - DCHECK(source_info.channels()); - channels_container_ = IntegerDiscreteContainer({*source_info.channels()}); - DCHECK(source_info.sample_rate() != std::nullopt); + channels_container_ = IntegerDiscreteContainer({source_info->channels()}); sample_rate_container_ = IntegerRangeContainer( - IntRangeSet::FromValue(*source_info.sample_rate())); - DCHECK(source_info.latency() != std::nullopt); + IntRangeSet::FromValue(source_info->sample_rate())); latency_container_ = - DoubleRangeContainer(DoubleRangeSet::FromValue(*source_info.latency())); + DoubleRangeContainer(DoubleRangeSet::FromValue(source_info->latency())); } // The allowed latency is expressed in a range latencies in seconds. @@ -1078,8 +1076,8 @@ // must be initialized such that their only supported values correspond to // the source settings. Otherwise, the containers are initialized to contain // all possible values. - SourceInfo source_info = - InfoFromSource(capability.source(), device_parameters_.effects()); + std::optional<SourceInfo> source_info = + SourceInfo::FromSource(capability.source()); // Three variations of the processing-based container. Each variant is // associated to a different type of audio processing configuration, namely @@ -1098,8 +1096,9 @@ is_reconfiguration_allowed)); DCHECK_EQ(processing_based_containers_.size(), 3u); - if (source_info.type() == SourceType::kNone) - return; + if (!source_info) { + return; + } blink::MediaStreamAudioSource* source = capability.source(); boolean_containers_[kDisableLocalEcho] = @@ -1262,48 +1261,6 @@ {kDisableLocalEcho, &ConstraintSet::disable_local_echo}, {kRenderToAssociatedSink, &ConstraintSet::render_to_associated_sink}}; - // Utility function to determine which version of this class should be - // allocated depending on the |source| provided. - static SourceInfo InfoFromSource(blink::MediaStreamAudioSource* source, - int effects) { - SourceType source_type; - AudioProcessingProperties properties; - auto* processed_source = ProcessedLocalAudioSource::From(source); - std::optional<int> channels; - std::optional<int> sample_rate; - std::optional<double> latency; - - if (!source) { - source_type = SourceType::kNone; - } else { - media::AudioParameters source_parameters = source->GetAudioParameters(); - channels = source_parameters.channels(); - sample_rate = source_parameters.sample_rate(); - latency = source_parameters.GetBufferDuration().InSecondsF(); - properties = *(source->GetAudioProcessingProperties()); - - if (!processed_source) { - source_type = SourceType::kUnprocessed; - properties.DisableDefaultProperties(); - - // It is possible, however, that the HW echo canceller is enabled. In - // such case the property for echo cancellation type should be updated - // accordingly. - if (effects & media::AudioParameters::ECHO_CANCELLER) { - properties.echo_cancellation_type = - EchoCancellationType::kEchoCancellationSystem; - } - } else { - source_type = properties.EchoCancellationIsWebRtcProvided() - ? SourceType::kApmProcessed - : SourceType::kNoApmProcessed; - properties = processed_source->audio_processing_properties(); - } - } - - return SourceInfo(source_type, properties, channels, sample_rate, latency); - } - media::AudioParameters device_parameters_; StringContainer device_id_container_; StringContainer group_id_container_;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame.cc b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame.cc index 647bca2..27a8cc2b 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame.cc
@@ -61,15 +61,6 @@ current_metadata->sequenceNumber() != new_metadata->sequenceNumber())) { return SetMetadataValidationOutcome{false, "Bad sequenceNumber"}; } - if (RuntimeEnabledFeatures::RTCEncodedAudioFrameAbsCaptureTimeEnabled()) { - if (new_metadata->hasAbsCaptureTime() != - current_metadata->hasAbsCaptureTime() || - (new_metadata->hasAbsCaptureTime() && - current_metadata->absCaptureTime() != - new_metadata->absCaptureTime())) { - return SetMetadataValidationOutcome{false, "Bad absoluteCaptureTime"}; - } - } if (!new_metadata->hasRtpTimestamp()) { return SetMetadataValidationOutcome{false, "Bad rtpTimestamp"}; } @@ -171,11 +162,6 @@ if (delegate_->SequenceNumber()) { metadata->setSequenceNumber(*delegate_->SequenceNumber()); } - if (RuntimeEnabledFeatures::RTCEncodedAudioFrameAbsCaptureTimeEnabled()) { - if (delegate_->AbsCaptureTime()) { - metadata->setAbsCaptureTime(*delegate_->AbsCaptureTime()); - } - } metadata->setRtpTimestamp(delegate_->RtpTimestamp()); if (delegate_->MimeType()) { metadata->setMimeType(WTF::String::FromUTF8(*delegate_->MimeType()));
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.cc b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.cc index 59e7038..dfde719e 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.cc
@@ -106,12 +106,6 @@ return contributing_sources_; } -std::optional<uint64_t> RTCEncodedAudioFrameDelegate::AbsCaptureTime() const { - base::AutoLock lock(lock_); - return webrtc_frame_ ? webrtc_frame_->AbsoluteCaptureTimestamp() - : std::nullopt; -} - std::optional<base::TimeTicks> RTCEncodedAudioFrameDelegate::ReceiveTime() const { base::AutoLock lock(lock_);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.h b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.h index 682f49f..0adab343 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_delegate.h
@@ -41,7 +41,6 @@ std::optional<std::string> MimeType() const; std::optional<uint16_t> SequenceNumber() const; Vector<uint32_t> ContributingSources() const; - std::optional<uint64_t> AbsCaptureTime() const; std::optional<base::TimeTicks> ReceiveTime() const; std::optional<base::TimeTicks> CaptureTime() const; std::optional<base::TimeDelta> SenderCaptureTimeOffset() const;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_metadata.idl b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_metadata.idl index 16c994d0..ee7eb8d 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_metadata.idl +++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_metadata.idl
@@ -11,7 +11,6 @@ octet payloadType; DOMString mimeType; unsigned short? sequenceNumber; - [RuntimeEnabled=RTCEncodedAudioFrameAbsCaptureTime] unsigned long long absCaptureTime; unsigned long rtpTimestamp; [RuntimeEnabled=RTCEncodedFrameTimestamps] DOMHighResTimeStamp receiveTime; [RuntimeEnabled=RTCEncodedFrameTimestamps] DOMHighResTimeStamp captureTime;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_test.cc index 3e00b76e..9cf2b63 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame_test.cc
@@ -50,7 +50,6 @@ ON_CALL(*frame, GetContributingSources()).WillByDefault(Return(csrcs)); ON_CALL(*frame, GetPayloadType()).WillByDefault(Return(13)); ON_CALL(*frame, SequenceNumber()).WillByDefault(Return(20)); - ON_CALL(*frame, AbsoluteCaptureTimestamp()).WillByDefault(Return(70050)); ON_CALL(*frame, GetTimestamp()).WillByDefault(Return(17)); ON_CALL(*frame, GetMimeType()).WillByDefault(Return("image")); } @@ -62,7 +61,6 @@ ON_CALL(*frame, GetContributingSources()).WillByDefault(Return(csrcs)); ON_CALL(*frame, GetPayloadType()).WillByDefault(Return(13)); ON_CALL(*frame, SequenceNumber()).WillByDefault(Return(20)); - ON_CALL(*frame, AbsoluteCaptureTimestamp()).WillByDefault(Return(70050)); ON_CALL(*frame, GetTimestamp()).WillByDefault(Return(17)); ON_CALL(*frame, GetMimeType()).WillByDefault(Return("image")); if (window) { @@ -84,7 +82,6 @@ new_metadata->setPayloadType(13); new_metadata->setMimeType("image"); new_metadata->setSequenceNumber(20); - new_metadata->setAbsCaptureTime(70050); new_metadata->setRtpTimestamp(110); return new_metadata; } @@ -108,7 +105,6 @@ EXPECT_EQ(13, retrieved_metadata->payloadType()); EXPECT_EQ("image", retrieved_metadata->mimeType()); EXPECT_EQ(20u, retrieved_metadata->sequenceNumber()); - EXPECT_EQ(70050u, retrieved_metadata->absCaptureTime()); EXPECT_EQ(17u, retrieved_metadata->rtpTimestamp()); EXPECT_TRUE(retrieved_metadata->hasReceiveTime()); // The precision for DOMHighResTimestamp is 0.1ms. Test equality by making @@ -204,7 +200,6 @@ EXPECT_FALSE(new_frame->getMetadata(execution_context)->hasPayloadType()); EXPECT_FALSE(new_frame->getMetadata(execution_context)->hasMimeType()); EXPECT_FALSE(new_frame->getMetadata(execution_context)->hasSequenceNumber()); - EXPECT_FALSE(new_frame->getMetadata(execution_context)->hasAbsCaptureTime()); EXPECT_EQ(new_frame->getMetadata(execution_context)->rtpTimestamp(), 0u); EXPECT_FALSE(new_frame->getMetadata(execution_context)->hasReceiveTime()); } @@ -329,7 +324,6 @@ EXPECT_EQ(13, new_frame_metadata->payloadType()); EXPECT_EQ("image", new_frame_metadata->mimeType()); EXPECT_EQ(20u, new_frame_metadata->sequenceNumber()); - EXPECT_EQ(70050u, new_frame_metadata->absCaptureTime()); EXPECT_EQ(17u, new_frame_metadata->rtpTimestamp()); EXPECT_FALSE(new_frame_metadata->hasReceiveTime()); } @@ -369,8 +363,6 @@ EXPECT_EQ(new_metadata->mimeType(), new_frame_metadata->mimeType()); EXPECT_EQ(new_metadata->sequenceNumber(), new_frame_metadata->sequenceNumber()); - EXPECT_EQ(new_metadata->absCaptureTime(), - new_frame_metadata->absCaptureTime()); EXPECT_EQ(new_metadata->rtpTimestamp(), new_frame_metadata->rtpTimestamp()); EXPECT_FALSE(new_metadata->hasReceiveTime()); }
diff --git a/third_party/blink/renderer/modules/printing/web_printing_type_converters.cc b/third_party/blink/renderer/modules/printing/web_printing_type_converters.cc index 64b895d0..44c4fe2 100644 --- a/third_party/blink/renderer/modules/printing/web_printing_type_converters.cc +++ b/third_party/blink/renderer/modules/printing/web_printing_type_converters.cc
@@ -64,6 +64,10 @@ using V8ColorMode = blink::V8WebPrintColorMode; using MojomColorMode = blink::mojom::blink::WebPrintColorMode; +// print-quality: +using V8Quality = blink::V8WebPrintQuality; +using MojomQuality = blink::mojom::blink::WebPrintQuality; + // printer-state: using V8PrinterState = blink::V8WebPrinterState; using MojomPrinterState = blink::mojom::blink::WebPrinterState; @@ -272,6 +276,34 @@ }; template <> +struct TypeConverter<V8Quality, MojomQuality> { + static V8Quality Convert(const MojomQuality& quality) { + switch (quality) { + case MojomQuality::kDraft: + return V8Quality(V8Quality::Enum::kDraft); + case MojomQuality::kNormal: + return V8Quality(V8Quality::Enum::kNormal); + case MojomQuality::kHigh: + return V8Quality(V8Quality::Enum::kHigh); + } + } +}; + +template <> +struct TypeConverter<MojomQuality, V8Quality> { + static MojomQuality Convert(const V8Quality& quality) { + switch (quality.AsEnum()) { + case V8Quality::Enum::kDraft: + return MojomQuality::kDraft; + case V8Quality::Enum::kNormal: + return MojomQuality::kNormal; + case V8Quality::Enum::kHigh: + return MojomQuality::kHigh; + } + } +}; + +template <> struct TypeConverter<V8PrinterState::Enum, MojomPrinterState> { static V8PrinterState::Enum Convert(const MojomPrinterState& printer_state) { switch (printer_state) { @@ -466,6 +498,16 @@ new_attributes.print_color_mode_supported)); } +void ProcessPrintQuality( + const mojom::blink::WebPrinterAttributes& new_attributes, + WebPrinterAttributes* current_attributes) { + current_attributes->setPrintQualityDefault( + mojo::ConvertTo<V8Quality>(new_attributes.print_quality_default)); + current_attributes->setPrintQualitySupported( + mojo::ConvertTo<Vector<V8Quality>>( + new_attributes.print_quality_supported)); +} + void ProcessSides(const mojom::blink::WebPrinterAttributes& new_attributes, WebPrinterAttributes* current_attributes) { if (new_attributes.sides_default) { @@ -499,6 +541,7 @@ blink::ProcessOrientationRequested(*printer_attributes, attributes); blink::ProcessPrinterResolution(*printer_attributes, attributes); blink::ProcessPrintColorMode(*printer_attributes, attributes); + blink::ProcessPrintQuality(*printer_attributes, attributes); blink::ProcessSides(*printer_attributes, attributes); attributes->setPrinterState( @@ -543,6 +586,10 @@ attributes->print_color_mode = mojo::ConvertTo<MojomColorMode>(pjt_attributes->printColorMode()); } + if (pjt_attributes->hasPrintQuality()) { + attributes->print_quality = + mojo::ConvertTo<MojomQuality>(pjt_attributes->printQuality()); + } if (pjt_attributes->hasSides()) { attributes->sides = mojo::ConvertTo<MojomSides>(pjt_attributes->sides()); }
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition.cc b/third_party/blink/renderer/modules/speech/speech_recognition.cc index aad1a2d..22d74e1 100644 --- a/third_party/blink/renderer/modules/speech/speech_recognition.cc +++ b/third_party/blink/renderer/modules/speech/speech_recognition.cc
@@ -90,8 +90,7 @@ if (phrases->length() > 0 && mode_ == V8SpeechRecognitionMode::Enum::kCloudOnly) { ErrorOccurred(media::mojom::blink::SpeechRecognitionError::New( - media::mojom::blink::SpeechRecognitionErrorCode:: - kRecognitionContextNotSupported, + media::mojom::blink::SpeechRecognitionErrorCode::kPhrasesNotSupported, media::mojom::blink::SpeechAudioErrorDetails::kNone)); return; } @@ -123,8 +122,7 @@ if (phrases_->length() > 0 && mode == V8SpeechRecognitionMode::Enum::kCloudOnly && !started_) { ErrorOccurred(media::mojom::blink::SpeechRecognitionError::New( - media::mojom::blink::SpeechRecognitionErrorCode:: - kRecognitionContextNotSupported, + media::mojom::blink::SpeechRecognitionErrorCode::kPhrasesNotSupported, media::mojom::blink::SpeechAudioErrorDetails::kNone)); return; }
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition_error_event.cc b/third_party/blink/renderer/modules/speech/speech_recognition_error_event.cc index a45ab59..fe6ec8c 100644 --- a/third_party/blink/renderer/modules/speech/speech_recognition_error_event.cc +++ b/third_party/blink/renderer/modules/speech/speech_recognition_error_event.cc
@@ -51,9 +51,8 @@ return "bad-grammar"; case media::mojom::blink::SpeechRecognitionErrorCode::kLanguageNotSupported: return "language-not-supported"; - case media::mojom::blink::SpeechRecognitionErrorCode:: - kRecognitionContextNotSupported: - return "recognition-context-not-supported"; + case media::mojom::blink::SpeechRecognitionErrorCode::kPhrasesNotSupported: + return "phrases-not-supported"; case media::mojom::blink::SpeechRecognitionErrorCode::kNoMatch: NOTREACHED(); }
diff --git a/third_party/blink/renderer/platform/fonts/shaping/font_features.cc b/third_party/blink/renderer/platform/fonts/shaping/font_features.cc index b5f8b64..6d9364b 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/font_features.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/font_features.cc
@@ -39,18 +39,6 @@ return features.size() == 1 && features[0] == kChws; } -const hb_feature_t* FontFeatures::ToHarfBuzzData() const { - return reinterpret_cast<const hb_feature_t*>(features_.data()); -} - -std::optional<uint32_t> FontFeatures::FindValueForTesting(uint32_t tag) const { - for (const FontFeatureRange& feature : features_) { - if (feature.tag == tag) - return feature.value; - } - return std::nullopt; -} - template <wtf_size_t InlineCapacity> void FontFeatureRange::FromFontDescription( const FontDescription& description, @@ -261,15 +249,14 @@ } } -void FontFeatures::Initialize(const FontDescription& description) { - FontFeatureRange::FromFontDescription(description, features_); -} - // // Explicitly instantiate template functions. // template PLATFORM_EXPORT void FontFeatureRange::FromFontDescription( const FontDescription&, Vector<FontFeatureRange, FontFeatureRange::kInitialSize>&); +template PLATFORM_EXPORT void FontFeatureRange::FromFontDescription( + const FontDescription&, + FontFeatures&); } // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/font_features.h b/third_party/blink/renderer/platform/fonts/shaping/font_features.h index a5ad3d3d..8e0bc7c 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/font_features.h +++ b/third_party/blink/renderer/platform/fonts/shaping/font_features.h
@@ -44,8 +44,6 @@ // // Represents an OpenType font feature with its value and text range. // -// This struct has the same size and layout as `hb_feature_t`. -// struct PLATFORM_EXPORT FontFeatureRange : public FontFeatureValue { // The size produced by `FromFontDescription()` for the initial style. static constexpr wtf_size_t kInitialSize = 1; @@ -58,6 +56,11 @@ // True if the list is for the initial style. static bool IsInitial(base::span<const FontFeatureRange>); + // This struct has the same size and layout as `hb_feature_t`. + static const hb_feature_t* ToHarfBuzzData(const FontFeatureRange* features) { + return reinterpret_cast<const hb_feature_t*>(features); + } + uint32_t start = 0; uint32_t end = static_cast<uint32_t>(-1); }; @@ -65,49 +68,7 @@ // // Represents a list of `FontFeatureRange`. // -class PLATFORM_EXPORT FontFeatures { - public: - FontFeatures() = default; - explicit FontFeatures(base::span<const FontFeatureRange> features) - : features_(features) {} - - // Initialize the list from |Font|. - void Initialize(const FontDescription&); - - wtf_size_t size() const { return features_.size(); } - bool IsEmpty() const { return features_.empty(); } - - const FontFeatureRange& operator[](wtf_size_t i) const { - return features_[i]; - } - explicit operator base::span<const FontFeatureRange>() { return features_; } - const hb_feature_t* ToHarfBuzzData() const; - - std::optional<uint32_t> FindValueForTesting(uint32_t tag) const; - - void Reserve(wtf_size_t new_capacity) { features_.reserve(new_capacity); } - - void Append(const FontFeatureRange& feature) { features_.push_back(feature); } - void Insert(const FontFeatureRange& feature) { - features_.push_front(feature); - } - void AppendVector(const FontFeatures& features) { - features_.AppendVector(features.features_); - } - - void EraseAt(wtf_size_t position, wtf_size_t length) { - features_.EraseAt(position, length); - } - void Shrink(wtf_size_t size) { features_.Shrink(size); } - - using FeatureArray = Vector<FontFeatureRange, 6>; - using const_iterator = FeatureArray::const_iterator; - const_iterator begin() const { return features_.begin(); } - const_iterator end() const { return features_.end(); } - - private: - FeatureArray features_; -}; +using FontFeatures = Vector<FontFeatureRange, 6>; } // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/font_features_test.cc b/third_party/blink/renderer/platform/fonts/shaping/font_features_test.cc index 34de94c3..2ce80720 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/font_features_test.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/font_features_test.cc
@@ -20,6 +20,15 @@ // class FontFeaturesTest : public testing::Test {}; +std::optional<uint32_t> FindValue(uint32_t tag, const FontFeatures& features) { + for (const FontFeatureRange& feature : features) { + if (feature.tag == tag) { + return feature.value; + } + } + return std::nullopt; +} + static const FontOrientation orientations[] = { FontOrientation::kHorizontal, FontOrientation::kVerticalRotated, @@ -46,13 +55,13 @@ FontDescription font_description; font_description.SetOrientation(GetOrientation()); FontFeatures features; - features.Initialize(font_description); + FontFeatureRange::FromFontDescription(font_description, features); if (IsHorizontal()) { - EXPECT_EQ(features.FindValueForTesting(chws), 1u); - EXPECT_EQ(features.FindValueForTesting(vchw), std::nullopt); + EXPECT_EQ(FindValue(chws, features), 1u); + EXPECT_EQ(FindValue(vchw, features), std::nullopt); } else { - EXPECT_EQ(features.FindValueForTesting(chws), std::nullopt); - EXPECT_EQ(features.FindValueForTesting(vchw), 1u); + EXPECT_EQ(FindValue(chws, features), std::nullopt); + EXPECT_EQ(FindValue(vchw, features), 1u); } } @@ -68,13 +77,13 @@ font_description.SetOrientation(GetOrientation()); font_description.SetFeatureSettings(settings); FontFeatures features; - features.Initialize(font_description); + FontFeatureRange::FromFontDescription(font_description, features); if (IsHorizontal()) { - EXPECT_EQ(features.FindValueForTesting(chws), value); - EXPECT_EQ(features.FindValueForTesting(vchw), std::nullopt); + EXPECT_EQ(FindValue(chws, features), value); + EXPECT_EQ(FindValue(vchw, features), std::nullopt); } else { - EXPECT_EQ(features.FindValueForTesting(chws), std::nullopt); - EXPECT_EQ(features.FindValueForTesting(vchw), value); + EXPECT_EQ(FindValue(chws, features), std::nullopt); + EXPECT_EQ(FindValue(vchw, features), value); } } } @@ -95,9 +104,9 @@ font_description.SetOrientation(GetOrientation()); font_description.SetFeatureSettings(settings); FontFeatures features; - features.Initialize(font_description); - EXPECT_EQ(features.FindValueForTesting(chws), std::nullopt); - EXPECT_EQ(features.FindValueForTesting(vchw), std::nullopt); + FontFeatureRange::FromFontDescription(font_description, features); + EXPECT_EQ(FindValue(chws, features), std::nullopt); + EXPECT_EQ(FindValue(vchw, features), std::nullopt); } } @@ -117,10 +126,10 @@ font_description.SetOrientation(GetOrientation()); font_description.SetFeatureSettings(settings); FontFeatures features; - features.Initialize(font_description); + FontFeatureRange::FromFontDescription(font_description, features); // Check all features are enabled. for (const hb_tag_t tag : tags) - EXPECT_EQ(features.FindValueForTesting(tag), 1u); + EXPECT_EQ(FindValue(tag, features), 1u); } } // namespace
diff --git a/third_party/blink/renderer/platform/fonts/shaping/han_kerning.cc b/third_party/blink/renderer/platform/fonts/shaping/han_kerning.cc index b9cc13e..5dd3e01 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/han_kerning.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/han_kerning.cc
@@ -291,9 +291,9 @@ : HB_TAG('v', 'h', 'a', 'l'); features_ = features; num_features_before_ = features->size(); - features->Reserve(features->size() + indices.size()); + features->reserve(features->size() + indices.size()); for (const wtf_size_t i : indices) { - features->Append({{tag, 1}, i, i + 1}); + features->push_back(FontFeatureRange{{tag, 1}, i, i + 1}); } }
diff --git a/third_party/blink/renderer/platform/fonts/shaping/han_kerning.h b/third_party/blink/renderer/platform/fonts/shaping/han_kerning.h index ac75d99b..468b484 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/han_kerning.h +++ b/third_party/blink/renderer/platform/fonts/shaping/han_kerning.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_HAN_KERNING_H_ #include "base/gtest_prod_util.h" +#include "third_party/blink/renderer/platform/fonts/shaping/font_features.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/text/han_kerning_char_type.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" @@ -15,7 +16,6 @@ namespace blink { class FontDescription; -class FontFeatures; class LayoutLocale; class SimpleFontData;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/han_kerning_test.cc b/third_party/blink/renderer/platform/fonts/shaping/han_kerning_test.cc index 47eaa84..0f4a072 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/han_kerning_test.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/han_kerning_test.cc
@@ -173,7 +173,8 @@ const SimpleFontData* noto_cjk_data = noto_cjk->PrimaryFont(); EXPECT_TRUE(noto_cjk_data); FontFeatures features; - features.Append({{{'T', 'E', 'S', 'T'}, 1}, 0, static_cast<unsigned>(-1)}); + features.push_back(FontFeatureRange{ + {{'T', 'E', 'S', 'T'}, 1}, 0, static_cast<unsigned>(-1)}); EXPECT_EQ(features.size(), 1u); const String text(u"国)(国"); {
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc index 56aa7d4..fdd6e695a 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
@@ -382,9 +382,9 @@ !resolved_features.empty()) { // Insert `resolved_features` before `font_features`. variant_features.emplace(); - variant_features->Reserve(resolved_features.size() + font_features.size()); + variant_features->reserve(resolved_features.size() + font_features.size()); for (const FontFeatureValue& feature : resolved_features) { - variant_features->Append({feature}); + variant_features->push_back(FontFeatureRange{feature}); } variant_features->AppendVector(font_features); } @@ -401,7 +401,8 @@ ? HarfBuzzFace::kPrepareForVerticalLayout : HarfBuzzFace::kNoVerticalLayout, specified_size); - hb_shape(hb_font, buffer, argument_features.ToHarfBuzzData(), + hb_shape(hb_font, buffer, + FontFeatureRange::ToHarfBuzzData(argument_features.data()), argument_features.size()); if (!face->ShouldSubpixelPosition()) { RoundHarfBuzzBufferPositions(buffer); @@ -897,7 +898,7 @@ void CapsFeatureSettingsScopedOverlay::PrependCounting( const FontFeatureRange& feature) { - features_->Insert(feature); + features_->push_front(feature); count_features_++; }
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc index 4c105e9..67520f0 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -72,7 +72,7 @@ Vector<int> offsets; } glyph_data; Member<void*> pointer2[2]; - int integers[6]; + int integers[5]; }; ASSERT_SIZE(ShapeResultRun, SameSizeAsRunInfo); @@ -764,7 +764,7 @@ const ShapeResultRun& run) const { auto glyph_offsets = run.glyph_data_.GetOffsets<has_non_zero_glyph_offsets>(); auto total_advance = InlineLayoutUnit::FromFloatRound(initial_advance); - bool is_horizontal = HB_DIRECTION_IS_HORIZONTAL(run.direction_); + bool is_horizontal = run.IsHorizontal(); for (const auto& glyph_data : run.glyph_data_) { glyph_callback(context, run.start_index_ + glyph_data.character_index, glyph_data.glyph, *glyph_offsets, total_advance, @@ -802,7 +802,7 @@ auto glyph_offsets = run.glyph_data_.GetOffsets<has_non_zero_glyph_offsets>(); auto total_advance = InlineLayoutUnit::FromFloatRound(initial_advance); unsigned run_start = run.start_index_ + index_offset; - bool is_horizontal = HB_DIRECTION_IS_HORIZONTAL(run.direction_); + bool is_horizontal = run.IsHorizontal(); const SimpleFontData* font_data = run.font_data_.Get(); if (run.IsLtr()) { // Left-to-right @@ -1600,9 +1600,8 @@ return run->start_index_ > start_index; }; - auto it = std::lower_bound( - runs_.begin(), runs_.end(), run->start_index_, - HB_DIRECTION_IS_FORWARD(run->direction_) ? ltr_comparer : rtl_comparer); + auto it = std::lower_bound(runs_.begin(), runs_.end(), run->start_index_, + run->IsLtr() ? ltr_comparer : rtl_comparer); if (it != runs_.end()) { runs_.insert(static_cast<wtf_size_t>(it - runs_.begin()), run); } else { @@ -2029,7 +2028,7 @@ output->Append(", #chars="); output->AppendNumber(run.num_characters_); output->Append(", dir="); - output->AppendNumber(static_cast<uint32_t>(run.direction_)); + output->AppendNumber(run.hb_direction_); output->Append(", glyphs["); output->AppendNumber(run.glyph_data_.size()); output->Append("]{");
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h index cca612a..5aa0fc3 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h
@@ -68,7 +68,7 @@ num_characters_(num_characters), width_(0.0f), script_(script), - direction_(dir), + hb_direction_(dir), canvas_rotation_(canvas_rotation) {} ShapeResultRun(const ShapeResultRun& other) @@ -79,7 +79,7 @@ num_characters_(other.num_characters_), width_(other.width_), script_(other.script_), - direction_(other.direction_), + hb_direction_(other.hb_direction_), canvas_rotation_(other.canvas_rotation_) {} void Trace(Visitor* visitor) const { @@ -90,9 +90,14 @@ unsigned NumGlyphs() const { return glyph_data_.size(); } bool HasLigatures() const { return NumGlyphs() < num_characters_; } - bool IsLtr() const { return HB_DIRECTION_IS_FORWARD(direction_); } - bool IsRtl() const { return HB_DIRECTION_IS_BACKWARD(direction_); } - bool IsHorizontal() const { return HB_DIRECTION_IS_HORIZONTAL(direction_); } + hb_direction_t HbDirection() const { + return static_cast<hb_direction_t>(hb_direction_); + } + bool IsLtr() const { return HB_DIRECTION_IS_FORWARD(HbDirection()); } + bool IsRtl() const { return HB_DIRECTION_IS_BACKWARD(HbDirection()); } + bool IsHorizontal() const { + return HB_DIRECTION_IS_HORIZONTAL(HbDirection()); + } CanvasRotationInVertical CanvasRotation() const { return canvas_rotation_; } unsigned NextSafeToBreakOffset(unsigned) const; unsigned PreviousSafeToBreakOffset(unsigned) const; @@ -138,7 +143,7 @@ } auto* run = MakeGarbageCollected<ShapeResultRun>( - font_data_.Get(), direction_, canvas_rotation_, script_, + font_data_.Get(), HbDirection(), canvas_rotation_, script_, start_index_ + start, number_of_glyphs, number_of_characters); run->glyph_data_.CopyFromRange(glyphs); @@ -163,8 +168,8 @@ } DCHECK_LT(start_index_, other.start_index_); auto* run = MakeGarbageCollected<ShapeResultRun>( - font_data_.Get(), direction_, canvas_rotation_, script_, start_index_, - glyph_data_.size() + other.glyph_data_.size(), + font_data_.Get(), HbDirection(), canvas_rotation_, script_, + start_index_, glyph_data_.size() + other.glyph_data_.size(), num_characters_ + other.num_characters_); // Note: We populate |graphemes_| on demand, e.g. hit testing. const int index_adjust = other.start_index_ - start_index_; @@ -192,8 +197,8 @@ bool CanMerge(const ShapeResultRun& other) const { return start_index_ + num_characters_ == other.start_index_ && canvas_rotation_ == other.canvas_rotation_ && - font_data_ == other.font_data_ && direction_ == other.direction_ && - script_ == other.script_ && + font_data_ == other.font_data_ && + hb_direction_ == other.hb_direction_ && script_ == other.script_ && glyph_data_.size() + other.glyph_data_.size() < HarfBuzzRunGlyphData::kMaxCharacterIndex + 1; } @@ -389,7 +394,7 @@ float width_; hb_script_t script_; - hb_direction_t direction_; + uint8_t hb_direction_; // hb_direction_t // For upright-in-vertical we need to tell the ShapeResultBloberizer to rotate // the canvas back 90deg for this ShapeResultRun.
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc index ea2d258..e56368d 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc
@@ -186,7 +186,7 @@ new_result->runs_.ReserveInitialCapacity(parts_.size()); for (const auto& part : RunsOrParts()) { auto* new_run = MakeGarbageCollected<ShapeResultRun>( - part.run_->font_data_.Get(), part.run_->direction_, + part.run_->font_data_.Get(), part.run_->HbDirection(), part.run_->canvas_rotation_, part.run_->script_, part.start_index_, part.NumGlyphs(), part.num_characters_); new_run->glyph_data_.CopyFromRange(part.range_); @@ -394,7 +394,7 @@ auto glyph_offsets = part.GetGlyphOffsets<has_non_zero_glyph_offsets>(); const auto& run = part.run_; auto total_advance = InlineLayoutUnit::FromFloatRound(initial_advance); - bool is_horizontal = HB_DIRECTION_IS_HORIZONTAL(run->direction_); + bool is_horizontal = run->IsHorizontal(); const SimpleFontData* font_data = run->font_data_.Get(); const unsigned character_index_offset_for_glyph_data = CharacterIndexOffsetForGlyphData(part); @@ -437,7 +437,7 @@ auto glyph_offsets = part.GetGlyphOffsets<has_non_zero_glyph_offsets>(); auto total_advance = InlineLayoutUnit::FromFloatRound(initial_advance); const auto& run = part.run_; - bool is_horizontal = HB_DIRECTION_IS_HORIZONTAL(run->direction_); + bool is_horizontal = run->IsHorizontal(); const SimpleFontData* font_data = run->font_data_.Get(); const unsigned character_index_offset_for_glyph_data = CharacterIndexOffsetForGlyphData(part);
diff --git a/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc b/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc index a9bdab7..c4dce0909 100644 --- a/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc +++ b/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc
@@ -46,28 +46,21 @@ } sk_sp<SkTypeface> MakeTypefaceDefaultFontMgr(sk_sp<SkData> data) { -#if !(BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)) - if (RuntimeEnabledFeatures::FontationsFontBackendEnabled()) { - return SkTypeface_Make_Fontations(data, SkFontArguments()); - } +#if BUILDFLAG(IS_WIN) + return FontCache::Get().FontManager()->makeFromData(data, 0); #endif - sk_sp<SkFontMgr> font_manager; -#if BUILDFLAG(IS_WIN) - font_manager = FontCache::Get().FontManager(); -#else - font_manager = skia::DefaultFontMgr(); +#if BUILDFLAG(IS_APPLE) + return skia::DefaultFontMgr()->makeFromData(data, 0); #endif - return font_manager->makeFromData(data, 0); + +#if !(BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)) + return SkTypeface_Make_Fontations(data, SkFontArguments()); +#endif } #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) sk_sp<SkTypeface> MakeTypefaceFallback(sk_sp<SkData> data) { -#if BUILDFLAG(ENABLE_FREETYPE) - if (!RuntimeEnabledFeatures::FontationsFontBackendEnabled()) { - return SkFontMgr_New_Custom_Empty()->makeFromData(data, 0); - } -#endif return SkTypeface_Make_Fontations(data, SkFontArguments()); } #endif
diff --git a/third_party/blink/renderer/platform/fonts/web_font_typeface_factory_test.cc b/third_party/blink/renderer/platform/fonts/web_font_typeface_factory_test.cc index d124980..cf14ee2 100644 --- a/third_party/blink/renderer/platform/fonts/web_font_typeface_factory_test.cc +++ b/third_party/blink/renderer/platform/fonts/web_font_typeface_factory_test.cc
@@ -8,7 +8,6 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/platform/fonts/opentype/font_format_check.h" -#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #if BUILDFLAG(IS_WIN) #include "third_party/blink/renderer/platform/fonts/win/dwrite_font_format_support.h" @@ -111,24 +110,6 @@ g_expect_fontations); } -TEST(WebFontTypefaceFactoryTest, COLRV0FontationsNonWin) { - ScopedFontationsFontBackendForTest scoped_fontations(false); - sk_sp<SkData> data = SkData::MakeEmpty(); - MockFontFormatCheck mock_font_format_check(data); - EXPECT_CALL(mock_font_format_check, IsColrCpalColorFontV0()) - .Times(AtLeast(1)) - .WillRepeatedly(Return(true)); - sk_sp<SkTypeface> out_typeface; - WebFontTypefaceFactory::CreateTypeface(SkData::MakeEmpty(), out_typeface, - mock_font_format_check, -#if BUILDFLAG(IS_WIN) - g_expect_system -#else - g_expect_fontations -#endif - ); -} - TEST(WebFontTypefaceFactoryTest, FontationsSelectedVariableSystem) { sk_sp<SkData> data = SkData::MakeEmpty(); MockFontFormatCheck mock_font_format_check(data);
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc index d1db4f4..380d6b87 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -399,7 +399,6 @@ RasterInterface()->WritePixels(client_si->mailbox(), x, y, client_si->GetTextureTarget(), SkPixmap(orig_info, pixels, row_bytes)); - resource()->GetSyncToken(); // If the overdraw optimization kicked in, we need to indicate that the // pixels do not need to be cleared, otherwise the subsequent
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc index d9d02f1..9d850e4 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
@@ -272,12 +272,19 @@ // the current swap buffer's sync token. sync_token = current_swap_buffer_->GetSyncToken(); - // This holds a ref on the SwapBuffers that will keep it alive until the - // mailbox is released (and while the release callback is running). - *out_release_callback = - WTF::BindOnce(&WebGPUSwapBufferProvider::MailboxReleased, - scoped_refptr<WebGPUSwapBufferProvider>(this), - std::move(current_swap_buffer_)); + // We are binding current_swap_buffer_ to callback that can be destroyed on a + // different thread, so make sure we don't have any non thread-safe state. + CHECK(!current_swap_buffer_->mailbox_texture); + // This holds a ref on the current_swap_buffer_ that will keep it alive until + // the mailbox is released (and while the release callback is running). Note, + // that callback can be invoked only on this thread, but can be destroyed on + // any thread in case this thread was terminated. Ref to SwapBuffers is enough + // to keep underlying resources alive, so we don't need to hold ref to + // WebGPUSwapBufferProvider itself. + *out_release_callback = WTF::BindOnce( + &WebGPUSwapBufferProvider::MailboxReleased, + weak_ptr_factory_.GetWeakPtr(), base::PlatformThread::CurrentRef(), + std::move(current_swap_buffer_)); return shared_image; } @@ -351,6 +358,8 @@ } void WebGPUSwapBufferProvider::MailboxReleased( + base::WeakPtr<WebGPUSwapBufferProvider> provider, + base::PlatformThreadRef thread_ref, scoped_refptr<SwapBuffer> swap_buffer, const gpu::SyncToken& sync_token, bool lost_resource) { @@ -361,7 +370,14 @@ if (lost_resource) return; - swap_buffer_pool_->ReleaseImage(std::move(swap_buffer)); + // This callback should never run on different thread. In case our thread was + // destroyed, callback should be discarded (it can be discarded on any + // thread). + CHECK_EQ(thread_ref, base::PlatformThread::CurrentRef()); + + if (provider) { + provider->swap_buffer_pool_->ReleaseImage(std::move(swap_buffer)); + } } WebGPUSwapBufferProvider::SwapBuffer::SwapBuffer(
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h index f01f95c8..3c050d2 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h +++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
@@ -147,9 +147,11 @@ ~SwapBuffer() override; }; - void MailboxReleased(scoped_refptr<SwapBuffer> swap_buffer, - const gpu::SyncToken& sync_token, - bool lost_resource); + static void MailboxReleased(base::WeakPtr<WebGPUSwapBufferProvider> provider, + base::PlatformThreadRef thread_ref, + scoped_refptr<SwapBuffer> swap_buffer, + const gpu::SyncToken& sync_token, + bool lost_resource); // This method will dissociate current Dawn Texture (produced by // GetNewTexture()) from the mailbox so that the mailbox can be used by other @@ -178,6 +180,8 @@ scoped_refptr<gpu::ClientSharedImage> front_buffer_shared_image_; gpu::SyncToken front_buffer_sync_token_; + + base::WeakPtrFactory<WebGPUSwapBufferProvider> weak_ptr_factory_{this}; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc index 6ce4021..261efe3 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
@@ -337,17 +337,16 @@ EXPECT_TRUE( provider_->PrepareTransferableResource(&resource3, &release_callback3)); - // Release resources one by one, the provider should only be freed when the - // last one is called. + // Release resources one by one and expect shared images to be destroyed. provider_ = nullptr; std::move(release_callback1).Run(gpu::SyncToken(), false /* lostResource */); - ASSERT_EQ(provider_alive_, true); + EXPECT_EQ(sii_->shared_image_count(), 2u); std::move(release_callback2).Run(gpu::SyncToken(), false /* lostResource */); - ASSERT_EQ(provider_alive_, true); + EXPECT_EQ(sii_->shared_image_count(), 1u); std::move(release_callback3).Run(gpu::SyncToken(), false /* lostResource */); - ASSERT_EQ(provider_alive_, false); + EXPECT_EQ(sii_->shared_image_count(), 0u); } TEST_F(WebGPUSwapBufferProviderTest, VerifyResizingProperlyAffectsResources) {
diff --git a/third_party/blink/renderer/platform/heap/member.h b/third_party/blink/renderer/platform/heap/member.h index d078ec7..af76ef0 100644 --- a/third_party/blink/renderer/platform/heap/member.h +++ b/third_party/blink/renderer/platform/heap/member.h
@@ -14,6 +14,7 @@ #include "third_party/blink/renderer/platform/wtf/hash_traits.h" #include "third_party/blink/renderer/platform/wtf/type_traits.h" #include "v8/include/cppgc/member.h" // IWYU pragma: export +#include "v8/include/cppgc/tagged-member.h" namespace blink { @@ -27,8 +28,13 @@ using UntracedMember = cppgc::UntracedMember<T>; namespace subtle { + template <typename T> using UncompressedMember = cppgc::subtle::UncompressedMember<T>; + +template <typename T, typename Tag1, typename Tag2> +using TaggedUncompressedMember = + cppgc::subtle::TaggedUncompressedMember<T, Tag1, Tag2>; } template <typename T>
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index e15c6bc..c710a7e 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1164,11 +1164,6 @@ status: "experimental", }, { - // crbug.com/392927981 - name: "CssDecoratingBoxPseudoFix", - status: "stable", - }, - { name: "CSSDynamicRangeLimit", status: "stable", }, @@ -2289,10 +2284,6 @@ status: {"Android": "", "default": "stable"}, }, { - name: "FontationsFontBackend", - status: "stable", - }, - { name: "FontFamilyPostscriptMatchingCTMigration", }, { @@ -3918,10 +3909,6 @@ status: "experimental", }, { - name: "RTCEncodedAudioFrameAbsCaptureTime", - status: "experimental", - }, - { name: "RTCEncodedFrameSetMetadata", status: "experimental", origin_trial_feature_name: "RTCEncodedFrameSetMetadata", @@ -4155,6 +4142,15 @@ }, { // Implements improved accessibility mappings for having an <input> + // inside of a <select> by keeping the child <input> in the a11y tree at + // the same place that its at in the DOM tree, but automatically setting + // up a controls relationship to the menu list popup. + name: "SelectAccessibilityNestedInput", + status: "test", + depends_on: ["CustomizableSelect"], + }, + { + // Implements improved accessibility mappings for having an <input> // inside of a <select> by reparenting the child <input> in the // accessibility tree to be a sibling of the menu list popup. name: "SelectAccessibilityReparentInput", @@ -4648,6 +4644,12 @@ status: "experimental", }, { + // crbug.com/341564372 + name: "TextareaMultipleIfcs", + status: "experimental", + depends_on: ["FastSelectionSync", "TextareaLineEndingsAsBr"], + }, + { // killswitch for fix in M137 name: "TextareaStableResizing", status: "stable", @@ -4909,12 +4911,6 @@ }, }, { - // This flag uses the original DOM text for input when the password - // echo is enabled to create the offset_map. - name: "UseOriginalDomOffsetsForOffsetMap", - status: "stable", - }, - { name: "UsePositionForPointInFlexibleBoxWithSingleChildElement", status: "stable", },
diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc index 7253162..c5b20ad3 100644 --- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc +++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
@@ -339,10 +339,9 @@ // When the compositor is not visible it would not request a // LayerTreeFrameSink so this is a race where it requested one on the // compositor thread while becoming non-visible on the main thread. In that - // case, we can wait for it to become visible again before replying. If - // `kWarmUpCompositor` is enabled and warm-up is triggered, a - // LayerTreeFrameSink is requested even if non-visible state. We can ignore - // this branch in that case. If not enabled, `ShouldWarmUp()` is always false. + // case, we can wait for it to become visible again before replying. + // If the warm-up is triggered, a LayerTreeFrameSink is requested even if + // non-visible state. We can ignore this branch in that case. if (!layer_tree_host_->ShouldWarmUp() && !layer_tree_host_->IsVisible()) { frame_sink_state_ = FrameSinkState::kRequestBufferedInvisible; return; @@ -371,10 +370,8 @@ // LayerTreeFrameSink is being processed, then if it fails we would arrive // here. Since the compositor does not request a LayerTreeFrameSink while not // visible, we can delay trying again until becoming visible again. - // If `kWarmUpCompositor` is enabled and warm-up is - // triggered, a LayerTreeFrameSink is requested even if non-visible state. We - // can ignore this branch in that case. If not enabled, `ShouldWarmUp()` is - // always false. + // If the warm-up is triggered, a LayerTreeFrameSink is requested even if + // non-visible state. We can ignore this branch in that case. if (!layer_tree_host_->ShouldWarmUp() && !layer_tree_host_->IsVisible()) { frame_sink_state_ = FrameSinkState::kRequestBufferedInvisible; return;
diff --git a/third_party/blink/tools/BUILD.gn b/third_party/blink/tools/BUILD.gn index e50ed9d..cabc012 100644 --- a/third_party/blink/tools/BUILD.gn +++ b/third_party/blink/tools/BUILD.gn
@@ -54,7 +54,6 @@ # Common expectation "//third_party/blink/web_tests/LeakExpectations", - "//third_party/blink/web_tests/MobileTestExpectations", "//third_party/blink/web_tests/NeverFixTests", "//third_party/blink/web_tests/SlowTests", "//third_party/blink/web_tests/StaleTestExpectations",
diff --git a/third_party/blink/tools/blinkpy/w3c/import_notifier.py b/third_party/blink/tools/blinkpy/w3c/import_notifier.py index 88ef5cd..7d71e34 100644 --- a/third_party/blink/tools/blinkpy/w3c/import_notifier.py +++ b/third_party/blink/tools/blinkpy/w3c/import_notifier.py
@@ -82,9 +82,6 @@ self.finder = path_finder.PathFinder(host.filesystem) self.default_port = host.port_factory.get() - self.default_port.set_option_default('additional_expectations', [ - self.finder.path_from_web_tests('MobileTestExpectations'), - ]) self.default_port.set_option_default('test_types', typing.get_args(TestType)) self.owners_extractor = DirectoryOwnersExtractor(host)
diff --git a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py index 7c38cb5..602c3b5 100644 --- a/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py +++ b/third_party/blink/tools/blinkpy/web_tests/lint_test_expectations.py
@@ -448,7 +448,6 @@ finder = PathFinder(host.filesystem) # Add all extra expectation files to be linted. options.additional_expectations.extend([ - finder.path_from_web_tests('MobileTestExpectations'), finder.path_from_web_tests('WebGPUExpectations'), ]) # The checks and list of expectation files are generally not
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/android.py b/third_party/blink/tools/blinkpy/web_tests/port/android.py index 492cd8f2..f18e199 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/android.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/android.py
@@ -53,8 +53,6 @@ self.path_to_generic_test_expectations_file(), self._filesystem.join(self.web_tests_dir(), 'NeverFixTests'), self._filesystem.join(self.web_tests_dir(), - 'MobileTestExpectations'), - self._filesystem.join(self.web_tests_dir(), 'StaleTestExpectations'), self._filesystem.join(self.web_tests_dir(), 'SlowTests') ]))
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/webview.py b/third_party/blink/tools/blinkpy/web_tests/port/webview.py index ccc5c83..0f760bd 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/webview.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/webview.py
@@ -52,8 +52,6 @@ self.path_to_generic_test_expectations_file(), self._filesystem.join(self.web_tests_dir(), 'NeverFixTests'), self._filesystem.join(self.web_tests_dir(), - 'MobileTestExpectations'), - self._filesystem.join(self.web_tests_dir(), 'StaleTestExpectations'), self._filesystem.join(self.web_tests_dir(), 'SlowTests') ]))
diff --git a/third_party/blink/web_tests/MobileTestExpectations b/third_party/blink/web_tests/MobileTestExpectations deleted file mode 100644 index 0dd61fb5..0000000 --- a/third_party/blink/web_tests/MobileTestExpectations +++ /dev/null
@@ -1,209 +0,0 @@ -# tags: [ Webview Android ] -# tags: [ Release Debug ] -# results: [ Timeout Crash Pass Failure Skip ] -# conflict_resolution: Override - -# This is the main failure suppression file for ChromeAndroid and Chrome Webview -# Web Platform Tests. - -# pointerevents tests -crbug.com/349397104 [ Android ] external/wpt/pointerevents/capturing_boundary_event_handler_at_ua_shadowdom.html?mouse [ Pass Timeout ] -crbug.com/349397104 [ Android ] external/wpt/pointerevents/capturing_boundary_event_handler_at_ua_shadowdom.html?pen [ Pass Timeout ] -crbug.com/349397104 [ Android ] external/wpt/pointerevents/capturing_boundary_event_handler_at_ua_shadowdom.html?touch [ Failure Pass Timeout ] -crbug.com/349397104 [ Android ] external/wpt/pointerevents/compat/pointerevent_touch-action_two-finger_interaction.html [ Failure Pass ] -crbug.com/349397104 [ Android ] external/wpt/pointerevents/pointerevent_after_target_appended.html?pen [ Failure Pass ] -crbug.com/349397104 [ Android ] external/wpt/pointerevents/pointerevent_attributes.html?mouse-right-nonstandard [ Failure Pass ] -crbug.com/349397104 [ Android ] external/wpt/pointerevents/pointerevent_attributes.html?pen-right [ Failure Pass ] -crbug.com/349397104 [ Android ] external/wpt/pointerevents/pointerevent_click_is_a_pointerevent_multiple_clicks.html?mouse [ Pass Timeout ] -crbug.com/349397104 [ Android ] external/wpt/pointerevents/pointerevent_click_is_a_pointerevent_multiple_clicks.html?touch [ Failure Pass Timeout ] -crbug.com/349397104 [ Android ] external/wpt/pointerevents/pointerevent_pointerleave_after_pointercancel_touch.html [ Failure Pass ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/capturing_boundary_event_handler_at_ua_shadowdom.html?pen [ Failure Pass ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/capturing_boundary_event_handler_at_ua_shadowdom.html?touch [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/compat/pointerevent_mouseevent_key_pressed.html [ Failure ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/compat/pointerevent_touch-action_two-finger_interaction.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointer-events-none-skip-scroll-will-change-in-iframe.html [ Failure Pass ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_after_target_appended_interleaved.tentative.html?mouse [ Pass Timeout ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_after_target_appended_interleaved.tentative.html?touch [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_after_target_appended.html?touch [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_after_target_removed_interleaved.tentative.html?touch [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_after_target_removed.html?pen [ Pass Timeout ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_after_target_removed.html?touch [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_attributes.html?mouse [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_attributes.html?mouse-nonstandard [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_attributes.html?mouse-right [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_attributes.html?mouse-right-nonstandard [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_attributes.html?pen [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_attributes.html?pen-nonstandard [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_attributes.html?pen-right [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_attributes.html?pen-right-nonstandard [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_attributes.html?touch [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_attributes.html?touch-nonstandard [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_change-touch-action-onpointerdown_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_click_during_capture.html?mouse-auxclick [ Failure ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_click_during_capture.html?mouse-click [ Failure ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_click_is_a_pointerevent_multiple_clicks.html?touch [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_click_is_a_pointerevent.html?touch [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_fractional_coordinates.html?touch [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_iframe-touch-action-none_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_movementxy.html?mouse [ Failure ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_movementxy.html?pen [ Failure ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_movementxy.html?touch [ Failure ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_pointercancel_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_pointerId_scope.html [ Failure ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_pointerleave_after_pointercancel_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_pointerout_after_pointercancel_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-auto-css_touch.html [ Failure Timeout ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-button-none-test_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-none_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch.html [ Failure Timeout ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-inherit_parent-none_touch.html [ Failure Pass ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-mouse.html [ Timeout ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-pan-down-css_touch.html [ Failure Timeout ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-pan-right-css_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-pan-up-css_touch.html [ Failure Timeout ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch.html [ Failure Timeout ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch.html [ Failure Timeout ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch.html [ Skip Timeout ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-svg-none-test_touch.html [ Skip Timeout ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-table-none-test_touch.html [ Skip Timeout ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerevent_touch-adjustment_click_target.html [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerlock/pointerevent_movementxy_with_pointerlock.html [ Failure ] -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/pointerup_after_pointerdown_target_removed.html?touch [ Failure ] # Flaky output -crbug.com/349397104 [ Webview ] external/wpt/pointerevents/touch-action-with-swipe-dir-change.html?touch [ Failure ] # Flaky output -crbug.com/349397104 external/wpt/pointerevents/coalesced_events_attributes_under_load.https.optional.html?mouse [ Skip Timeout ] -crbug.com/349397104 external/wpt/pointerevents/coalesced_events_attributes_under_load.https.optional.html?pen [ Skip Timeout ] -crbug.com/349397104 external/wpt/pointerevents/coalesced_events_attributes_under_load.https.optional.html?touch [ Skip Timeout ] -crbug.com/349397104 external/wpt/pointerevents/pointer-events-none-skip-scroll-in-iframe.html [ Failure Pass ] -crbug.com/349397104 external/wpt/pointerevents/pointerevent_contextmenu_is_a_pointerevent.html?touch [ Failure Timeout ] # Flaky output -crbug.com/349397104 external/wpt/pointerevents/pointerevent_touch-action-span-none-test_touch.html [ Skip Timeout ] -crbug.com/349397104 external/wpt/pointerevents/pointerlock/pointerevent_getCoalescedEvents_when_pointerlocked.https.html [ Failure Pass ] -crbug.com/349397104 external/wpt/pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture.html [ Failure Pass ] - -# Incompatible with both Chrome Android and Webview -# SharedWorker interface -crbug.com/40290702 external/wpt/background-fetch/idlharness.https.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/content-index/idlharness.https.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/cookie-store/idlharness.https.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/dom/idlharness.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/encoding/idlharness.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/event-timing/idlharness.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/fetch/api/idlharness.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/hr-time/idlharness.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/IndexedDB/idlharness.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/notifications/idlharness.https.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/payment-handler/idlharness.https.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/performance-timeline/idlharness.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/push-api/idlharness.https.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/service-workers/idlharness.https.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/shape-detection/idlharness.https.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/streams/idlharness.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/user-timing/idlharness.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/webtransport/idlharness.https.any.sharedworker.html [ Failure ] -crbug.com/40290702 external/wpt/xhr/idlharness.any.sharedworker.html [ Failure ] -# Compute Pressure -crbug.com/341537009 external/wpt/compute-pressure/idlharness.https.any.html [ Failure ] -crbug.com/341537009 external/wpt/compute-pressure/idlharness.https.any.sharedworker.html [ Failure ] -crbug.com/341537009 external/wpt/compute-pressure/idlharness.https.any.worker.html [ Failure ] -# MediaDevices.ondevicechange -crbug.com/671461 external/wpt/mediacapture-streams/idlharness.https.window.html [ Failure ] - -# Incompatible with Webview -# Refer to android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt -crbug.com/40417848 [ Webview ] external/wpt/speech-api/idlharness.window.html [ Failure ] -crbug.com/40652382 [ WebView ] external/wpt/webxr/* [ Failure ] -crbug.com/41441927 [ WebView ] external/wpt/webusb/* [ Failure ] -crbug.com/41492543 [ Webview ] external/wpt/webtransport/idlharness.https.any.html [ Failure ] -crbug.com/41492543 [ Webview ] external/wpt/webtransport/idlharness.https.any.serviceworker.html [ Failure ] -crbug.com/41492543 [ Webview ] external/wpt/webtransport/idlharness.https.any.worker.html [ Failure ] -crbug.com/925997 [ Webview ] external/wpt/mediasession/idlharness.window.html [ Failure ] -crbug.com/334063352 [ WebView ] external/wpt/picture-in-picture/idlharness.window.html [ Failure ] -crbug.com/421921 [ Webview ] external/wpt/push-api/idlharness.https.any.serviceworker.html [ Failure ] - -# Other failing/timeout tests -[ Android ] external/wpt/visual-viewport/resize-event-order.html [ Timeout ] -[ Android ] external/wpt/visual-viewport/viewport-resize-event-on-load-overflowing-page.html [ Failure ] -[ Webview ] external/wpt/compat/idlharness.window.html [ Failure ] -[ Webview ] external/wpt/html-media-capture/idlharness.window.html [ Failure ] -[ Webview ] external/wpt/media-capabilities/idlharness.any.html [ Pass Timeout ] -[ Webview ] external/wpt/navigation-timing/idlharness.window.html [ Failure Pass ] -[ Webview ] external/wpt/selection/idlharness.window.html [ Failure ] -[ Webview ] external/wpt/shape-detection/idlharness.https.any.html [ Failure ] -[ Webview ] external/wpt/shape-detection/idlharness.https.any.serviceworker.html [ Failure ] -[ Webview ] external/wpt/shape-detection/idlharness.https.any.worker.html [ Failure ] -[ Webview ] external/wpt/uievents/idlharness.window.html [ Failure ] -external/wpt/web-animations/idlharness.window.html [ Failure ] -external/wpt/webrtc/idlharness.https.window.html [ Skip Timeout ] - -# Flaky tests -[ Android ] external/wpt/visual-viewport/viewport-scrollbars-cause-resize.html [ Failure Pass ] -[ Android ] external/wpt/visual-viewport/viewport-unscaled-size.html [ Failure Pass ] -[ Webview ] external/wpt/largest-contentful-paint/idlharness.html [ Pass Timeout ] -[ Webview ] external/wpt/storage/idlharness.https.any.worker.html [ Failure Pass ] -[ Webview ] external/wpt/streams/idlharness.any.worker.html [ Failure Pass Timeout ] -[ Webview ] external/wpt/visual-viewport/viewport-scrollbars-cause-resize-in-iframe.html [ Failure Pass ] -[ Webview ] external/wpt/webauthn/idlharness.https.window.html [ Failure Pass ] -[ Webview ] external/wpt/webrtc-encoded-transform/idlharness.https.window.html [ Failure Pass ] -crbug.com/372119113 [ Webview ] external/wpt/visual-viewport/scroll-event-order.html [ Crash Failure Pass Timeout ] # Flaky output -crbug.com/372097205 external/wpt/visual-viewport/page-and-offset-in-iframe.html [ Crash Failure Pass ] - -# Stack (with nondeterministic memory addresses) is dumped into `*-expected.txt`. -[ Webview ] external/wpt/idle-detection/idlharness-worker.https.window.html [ Failure ] -[ Webview ] external/wpt/idle-detection/idlharness.https.window.html [ Failure Timeout ] -[ Webview ] external/wpt/screen-wake-lock/idlharness.https.window.html [ Failure ] -[ Webview ] external/wpt/webmidi/idlharness.https.window.html [ Failure ] - -# Webdriver tests timeout on Android -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/context_created/original_opener.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/create/invalid.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/locate_nodes/invalid.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/navigate/navigate_beforeunload.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/navigate/navigate.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/navigation_started/navigation_started.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/user_prompt_opened/handler.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/simulate_adapter/context.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/simulate_adapter/invalid.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/simulate_adapter/state.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/simulate_preconnected_peripheral/simulate_preconnected_peripheral.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/add_intercept/url_patterns.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/continue_request/method.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/continue_response/status_code.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/continue_with_auth/invalid.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/provide_response/status_code.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/response_completed/response_completed.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/response_started/response_started.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/storage/delete_cookies/filter.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/storage/get_cookies/filter.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/web_extension/install/install.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/web_extension/install/invalid.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/web_extension/uninstall/invalid.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/web_extension/uninstall/uninstall.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/back/back.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/dismiss_alert/dismiss.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/element_clear/clear.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/element_clear/disabled.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/element_click/navigate.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/element_send_keys/file_upload.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/element_send_keys/interactability.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/find_element_from_element/find.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/find_element_from_shadow_root/find.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/find_elements_from_element/find.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/find_elements_from_shadow_root/find.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/forward/forward.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/get_element_attribute/get.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/get_element_property/get.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/get_window_rect/user_prompts.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/is_element_enabled/enabled.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/maximize_window/user_prompts.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/new_session/response.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/perform_actions/key_events.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/perform_actions/pointer_mouse_drag.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/perform_actions/pointer_mouse.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/perform_actions/pointer_touch.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/send_alert_text/send.py [ Skip Timeout ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/set_window_rect/user_prompts.py [ Failure ] -crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/interop/beforeunload_prompt.py [ Skip Timeout ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 688f917..2a22f57 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2404,16 +2404,16 @@ # `wdspec` tests external/wpt/webdriver/tests/classic/element_send_keys/interactability.py [ Failure ] # Flaky output -external/wpt/webdriver/tests/classic/element_click/navigate.py [ Failure ] # Flaky output +[ Linux ] external/wpt/webdriver/tests/classic/element_click/navigate.py [ Failure ] # Flaky output external/wpt/webdriver/tests/bidi/network/add_intercept/invalid.py [ Timeout ] external/wpt/webdriver/tests/bidi/network/add_intercept/phases.py [ Failure Timeout ] -crbug.com/324436866 external/wpt/webdriver/tests/bidi/network/response_started/response_started.py [ Failure Timeout ] +crbug.com/324436866 [ Linux ] external/wpt/webdriver/tests/bidi/network/response_started/response_started.py [ Failure Timeout ] crbug.com/381127883 external/wpt/webdriver/tests/bidi/network/response_started/response_started_cached.py [ Failure Timeout ] crbug.com/1502331 external/wpt/webdriver/tests/classic/perform_actions/pointer_pen.py [ Failure Pass ] crbug.com/626703 external/wpt/webdriver/tests/bidi/network/auth_required/auth_required.py [ Failure Timeout ] -external/wpt/webdriver/tests/bidi/network/add_intercept/url_patterns.py [ Timeout ] +[ Linux ] external/wpt/webdriver/tests/bidi/network/add_intercept/url_patterns.py [ Timeout ] external/wpt/webdriver/tests/bidi/browsing_context/capture_screenshot/frame.py [ Failure ] # Flaky output -crbug.com/324436866 external/wpt/webdriver/tests/bidi/browsing_context/navigation_started/navigation_started.py [ Failure Timeout ] +crbug.com/324436866 [ Linux ] external/wpt/webdriver/tests/bidi/browsing_context/navigation_started/navigation_started.py [ Failure Timeout ] external/wpt/webdriver/tests/bidi/browsing_context/print/invalid.py [ Timeout ] external/wpt/webdriver/tests/bidi/browsing_context/user_prompt_opened/user_prompt_opened.py [ Failure Pass Timeout ] crbug.com/324436866 external/wpt/webdriver/tests/bidi/browser/remove_user_context/user_context.py [ Failure Pass Timeout ] @@ -2429,7 +2429,7 @@ crbug.com/1507773 external/wpt/webdriver/tests/classic/get_element_attribute/get.py [ Failure Pass Timeout ] crbug.com/1507773 external/wpt/webdriver/tests/classic/is_element_enabled/enabled.py [ Failure Pass Timeout ] crbug.com/1499775 external/wpt/webdriver/tests/bidi/browsing_context/locate_nodes/context.py [ Failure ] -crbug.com/1499775 external/wpt/webdriver/tests/bidi/browsing_context/locate_nodes/invalid.py [ Pass Timeout ] +crbug.com/1499775 [ Linux ] external/wpt/webdriver/tests/bidi/browsing_context/locate_nodes/invalid.py [ Pass Timeout ] crbug.com/1499775 external/wpt/webdriver/tests/bidi/browsing_context/locate_nodes/start_nodes.py [ Failure ] crbug.com/1499775 external/wpt/webdriver/tests/bidi/input/perform_actions/pointer_mouse_multiclick.py [ Failure Timeout ] crbug.com/324436866 external/wpt/webdriver/tests/bidi/browsing_context/print/context.py [ Failure Pass Timeout ] @@ -2437,7 +2437,7 @@ crbug.com/626703 external/wpt/webdriver/tests/bidi/input/set_files/invalid.py [ Failure Timeout ] external/wpt/webdriver/tests/bidi/input/set_files/set_files.py [ Timeout ] [ Debug ] external/wpt/webdriver/tests/bidi/network/add_intercept/contexts.py [ Failure Pass Timeout ] -[ Debug ] external/wpt/webdriver/tests/bidi/storage/delete_cookies/filter.py [ Timeout ] +[ Linux Debug ] external/wpt/webdriver/tests/bidi/storage/delete_cookies/filter.py [ Timeout ] [ Debug ] external/wpt/webdriver/tests/bidi/storage/delete_cookies/invalid.py [ Timeout ] [ Debug ] external/wpt/webdriver/tests/bidi/storage/get_cookies/invalid.py [ Timeout ] external/wpt/webdriver/tests/bidi/browsing_context/close/prompt_unload.py [ Timeout ] @@ -2559,6 +2559,147 @@ crbug.com/40268415 [ Debug Mac15-arm64 ] external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/no-cors.https.html [ Crash ] crbug.com/40268415 [ Debug Win11-arm64 ] external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/no-cors.https.html [ Crash ] +# Test Expectations for Chrome Android/WebView +# Incompatible with both Chrome Android and Webview +# SharedWorker interface +crbug.com/40290702 [ Android ] external/wpt/background-fetch/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/content-index/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/cookie-store/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/dom/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/encoding/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/event-timing/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/fetch/api/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/hr-time/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/IndexedDB/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/notifications/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/payment-handler/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/performance-timeline/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/push-api/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/service-workers/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/shape-detection/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/streams/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/user-timing/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/webtransport/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Android ] external/wpt/xhr/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/background-fetch/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/content-index/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/cookie-store/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/dom/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/encoding/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/event-timing/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/fetch/api/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/hr-time/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/IndexedDB/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/notifications/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/payment-handler/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/performance-timeline/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/push-api/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/service-workers/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/shape-detection/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/streams/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/user-timing/idlharness.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/webtransport/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/40290702 [ Webview ] external/wpt/xhr/idlharness.any.sharedworker.html [ Failure ] +# Compute Pressure +crbug.com/341537009 [ Android ] external/wpt/compute-pressure/idlharness.https.any.html [ Failure ] +crbug.com/341537009 [ Android ] external/wpt/compute-pressure/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/341537009 [ Android ] external/wpt/compute-pressure/idlharness.https.any.worker.html [ Failure ] +crbug.com/341537009 [ Webview ] external/wpt/compute-pressure/idlharness.https.any.html [ Failure ] +crbug.com/341537009 [ Webview ] external/wpt/compute-pressure/idlharness.https.any.sharedworker.html [ Failure ] +crbug.com/341537009 [ Webview ] external/wpt/compute-pressure/idlharness.https.any.worker.html [ Failure ] +# MediaDevices.ondevicechange +crbug.com/671461 [ Android ] external/wpt/mediacapture-streams/idlharness.https.window.html [ Failure ] +crbug.com/671461 [ Webview ] external/wpt/mediacapture-streams/idlharness.https.window.html [ Failure ] + +# Incompatible with Webview +# Refer to android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt +crbug.com/40417848 [ Webview ] external/wpt/speech-api/idlharness.window.html [ Failure ] +crbug.com/40652382 [ Webview ] external/wpt/webxr/* [ Failure ] +crbug.com/41441927 [ Webview ] external/wpt/webusb/* [ Failure ] +crbug.com/41492543 [ Webview ] external/wpt/webtransport/idlharness.https.any.html [ Failure ] +crbug.com/41492543 [ Webview ] external/wpt/webtransport/idlharness.https.any.serviceworker.html [ Failure ] +crbug.com/41492543 [ Webview ] external/wpt/webtransport/idlharness.https.any.worker.html [ Failure ] +crbug.com/925997 [ Webview ] external/wpt/mediasession/idlharness.window.html [ Failure ] +crbug.com/334063352 [ Webview ] external/wpt/picture-in-picture/idlharness.window.html [ Failure ] +crbug.com/421921 [ Webview ] external/wpt/push-api/idlharness.https.any.serviceworker.html [ Failure ] + +# Other failing/timeout tests +[ Android ] external/wpt/visual-viewport/resize-event-order.html [ Timeout ] +[ Android ] external/wpt/visual-viewport/viewport-resize-event-on-load-overflowing-page.html [ Failure ] +[ Webview ] external/wpt/compat/idlharness.window.html [ Failure ] +[ Webview ] external/wpt/html-media-capture/idlharness.window.html [ Failure ] +[ Webview ] external/wpt/media-capabilities/idlharness.any.html [ Pass Timeout ] +[ Webview ] external/wpt/navigation-timing/idlharness.window.html [ Failure Pass ] +[ Webview ] external/wpt/selection/idlharness.window.html [ Failure ] +[ Webview ] external/wpt/shape-detection/idlharness.https.any.html [ Failure ] +[ Webview ] external/wpt/shape-detection/idlharness.https.any.serviceworker.html [ Failure ] +[ Webview ] external/wpt/shape-detection/idlharness.https.any.worker.html [ Failure ] +[ Webview ] external/wpt/uievents/idlharness.window.html [ Failure ] +[ Webview ] external/wpt/web-animations/idlharness.window.html [ Failure ] +[ Webview ] external/wpt/webrtc/idlharness.https.window.html [ Skip Timeout ] +[ Android ] external/wpt/web-animations/idlharness.window.html [ Failure ] +[ Android ] external/wpt/webrtc/idlharness.https.window.html [ Skip Timeout ] + +# Flaky tests +[ Android ] external/wpt/visual-viewport/viewport-scrollbars-cause-resize.html [ Failure Pass ] +[ Android ] external/wpt/visual-viewport/viewport-unscaled-size.html [ Failure Pass ] +[ Webview ] external/wpt/largest-contentful-paint/idlharness.html [ Pass Timeout ] +[ Webview ] external/wpt/storage/idlharness.https.any.worker.html [ Failure Pass ] +[ Webview ] external/wpt/streams/idlharness.any.worker.html [ Failure Pass Timeout ] +[ Webview ] external/wpt/visual-viewport/viewport-scrollbars-cause-resize-in-iframe.html [ Failure Pass ] +[ Webview ] external/wpt/webauthn/idlharness.https.window.html [ Failure Pass ] +[ Webview ] external/wpt/webrtc-encoded-transform/idlharness.https.window.html [ Failure Pass ] +crbug.com/372119113 [ Webview ] external/wpt/visual-viewport/scroll-event-order.html [ Crash Failure Pass Timeout ] # Flaky output +crbug.com/403340566 [ Webview ] external/wpt/visual-viewport/page-and-offset-in-iframe.html [ Crash Failure Pass Timeout ] +crbug.com/372097205 [ Android ] external/wpt/visual-viewport/page-and-offset-in-iframe.html [ Crash Failure Pass ] + +# Stack (with nondeterministic memory addresses) is dumped into `*-expected.txt`. +[ Webview ] external/wpt/idle-detection/idlharness-worker.https.window.html [ Failure ] +[ Webview ] external/wpt/idle-detection/idlharness.https.window.html [ Failure Timeout ] +[ Webview ] external/wpt/screen-wake-lock/idlharness.https.window.html [ Failure ] +[ Webview ] external/wpt/webmidi/idlharness.https.window.html [ Failure ] + +# Webdriver tests timeout on Android +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/context_created/original_opener.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/create/invalid.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/locate_nodes/invalid.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/navigate/navigate_beforeunload.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/navigate/navigate.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/navigation_started/navigation_started.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/browsing_context/user_prompt_opened/handler.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/simulate_adapter/context.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/simulate_adapter/invalid.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/simulate_adapter/state.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/simulate_preconnected_peripheral/simulate_preconnected_peripheral.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/add_intercept/url_patterns.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/continue_request/method.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/continue_response/status_code.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/continue_with_auth/invalid.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/provide_response/status_code.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/response_completed/response_completed.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/network/response_started/response_started.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/storage/delete_cookies/filter.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/storage/get_cookies/filter.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/web_extension/install/install.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/web_extension/install/invalid.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/web_extension/uninstall/invalid.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/bidi/web_extension/uninstall/uninstall.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/back/back.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/dismiss_alert/dismiss.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/element_clear/clear.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/element_clear/disabled.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/element_click/navigate.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/element_send_keys/file_upload.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/get_element_property/get.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/get_window_rect/user_prompts.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/maximize_window/user_prompts.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/new_session/response.py [ Failure ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/perform_actions/key_events.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/perform_actions/pointer_mouse_drag.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/perform_actions/pointer_mouse.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/send_alert_text/send.py [ Skip Timeout ] +crbug.com/395962971 [ Android ] external/wpt/webdriver/tests/classic/set_window_rect/user_prompts.py [ Failure ] + # ====== Test expectations added to unblock wpt-importer ====== crbug.com/413633034 external/wpt/html/webappapis/scripting/event-loops/new-scroll-event-dispatched-at-next-updating-rendering-time.html [ Failure ] crbug.com/406036293 [ Mac ] external/wpt/css/css-overflow/keyboard-scroll.html [ Failure Pass ] @@ -2765,7 +2906,6 @@ crbug.com/403345125 external/wpt/css/css-writing-modes/available-size-021.html [ Failure ] crbug.com/403345125 external/wpt/css/css-writing-modes/available-size-022.html [ Failure ] crbug.com/403345125 external/wpt/css/css-writing-modes/available-size-023.html [ Failure ] -crbug.com/403340566 [ Webview ] external/wpt/visual-viewport/page-and-offset-in-iframe.html [ Timeout ] crbug.com/403340566 [ Win11-arm64 ] external/wpt/visual-viewport/page-and-offset-in-iframe.html [ Timeout ] crbug.com/402195188 [ Mac14 ] external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-to-unsafe-none.https.html?5-6 [ Crash ] crbug.com/401111779 [ Mac15-arm64 ] external/wpt/webrtc-stats/getStats-remote-candidate-ufrag.html [ Timeout ] @@ -3011,7 +3151,7 @@ crbug.com/381127882 external/wpt/css/css-rhythm/content-based-height-rounds-up-to-step-unit.html [ Failure ] crbug.com/381127882 external/wpt/css/css-rhythm/definite-height-rounds-up-to-next-multiple-of-step-unit.html [ Failure ] crbug.com/381127882 external/wpt/css/css-rhythm/definite-height-rounds-up-to-step-unit.html [ Failure ] -crbug.com/381127883 external/wpt/webdriver/tests/bidi/network/continue_request/method.py [ Failure Timeout ] +crbug.com/381127883 [ Linux ] external/wpt/webdriver/tests/bidi/network/continue_request/method.py [ Failure Timeout ] crbug.com/380409684 [ Mac14 ] external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-to-unsafe-none.https.html?7-8 [ Crash ] crbug.com/380327161 [ Mac13 ] external/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_drag.html [ Timeout ] crbug.com/380327161 [ Win10.20h2 ] external/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_drag.html [ Timeout ] @@ -3142,7 +3282,6 @@ crbug.com/375262152 external/wpt/html/semantics/embedded-content/the-img-element/update-the-image-data/src-then-lazy-load.html [ Timeout ] crbug.com/374812621 external/wpt/encrypted-media/media-element-event-handler-attributes.html [ Timeout ] crbug.com/375204273 [ Mac13 ] external/wpt/fs/FileSystemObserver.https.tentative.any.worker.html [ Failure Timeout ] -crbug.com/372103377 [ Webview ] external/wpt/visual-viewport/scroll-event-order.html [ Crash ] crbug.com/371061343 [ Mac ] external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-fragment-nosw.https.html [ Skip Timeout ] crbug.com/371061343 [ Mac ] external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-fragment.https.html [ Skip Timeout ] crbug.com/371061343 [ Mac ] external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/protocol-handler-path.https.html [ Skip Timeout ] @@ -3235,11 +3374,7 @@ crbug.com/360956937 [ Mac15-arm64 ] external/wpt/webrtc-encoded-transform/script-transform-sendKeyFrameRequest.https.html [ Skip Timeout ] crbug.com/360956937 [ Mac15 ] external/wpt/webrtc-encoded-transform/script-transform-sendKeyFrameRequest.https.html [ Skip Timeout ] [ Win11-arm64 ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html [ Crash Failure ] -[ Webview ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html [ Crash Failure ] [ Win11-arm64 ] external/wpt/pointerevents/pointerevent_touch-action-none-css_touch.html [ Crash Failure ] -[ Webview ] external/wpt/pointerevents/pointerevent_touch-action-none-css_touch.html [ Crash Failure ] -crbug.com/360246424 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-button-none-test_touch.html [ Crash Failure ] -crbug.com/360246424 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-none_touch.html [ Crash Failure ] crbug.com/360246809 [ Mac15 ] external/wpt/fs/FileSystemFileHandle-sync-access-handle-back-forward-cache.https.tentative.window.html [ Skip Timeout ] crbug.com/360246809 [ Linux ] external/wpt/fs/FileSystemFileHandle-sync-access-handle-back-forward-cache.https.tentative.window.html [ Skip Timeout ] crbug.com/360201083 [ Mac15-arm64 ] external/wpt/webrtc-encoded-transform/RTCRtpScriptTransform-bad-chunk.https.html [ Timeout ] @@ -3322,7 +3457,6 @@ crbug.com/352088182 [ Win11-arm64 ] virtual/no-auto-wpt-origin-isolation/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/going-back.sub.https.html [ Timeout ] [ Win11-arm64 ] virtual/fenced-frame-mparch-internal/wpt_internal/fenced_frame/disable-untrusted-network.https.html [ Timeout ] crbug.com/351703751 [ Win11-arm64 ] external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.https.any.html [ Failure Timeout ] -crbug.com/350779641 [ Webview ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html [ Crash Failure ] crbug.com/350823140 [ Win11-arm64 ] virtual/no-auto-wpt-origin-isolation/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-yes-subdomainport.sub.https.html [ Timeout ] crbug.com/350792702 external/wpt/trusted-types/trusted-types-reporting.html [ Skip Timeout ] [ Win11-arm64 ] virtual/fenced-frame-mparch-internal/wpt_internal/fenced_frame/revoke-service-workers.https.html [ Failure Timeout ] @@ -3902,11 +4036,11 @@ crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html [ Skip Timeout ] crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html [ Skip Timeout ] crbug.com/626703 external/wpt/fetch/content-type/response.window.html [ Timeout ] -crbug.com/357931030 external/wpt/webdriver/tests/bidi/browsing_context/navigate/navigate.py [ Timeout ] +crbug.com/357931030 [ Linux ] external/wpt/webdriver/tests/bidi/browsing_context/navigate/navigate.py [ Timeout ] crbug.com/356498699 external/wpt/webdriver/tests/bidi/browsing_context/navigation_failed/navigation_failed.py [ Failure Timeout ] crbug.com/626703 [ Release ] external/wpt/webdriver/tests/bidi/browsing_context/user_prompt_closed/user_prompt_closed.py [ Failure ] # Flaky output -crbug.com/626703 external/wpt/webdriver/tests/classic/element_clear/clear.py [ Failure Timeout ] -crbug.com/626703 external/wpt/webdriver/tests/bidi/network/continue_with_auth/invalid.py [ Timeout ] +crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/classic/element_clear/clear.py [ Failure Timeout ] +crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/bidi/network/continue_with_auth/invalid.py [ Timeout ] crbug.com/626703 external/wpt/webdriver/tests/classic/element_send_keys/send_keys.py [ Failure ] # Some WebXR tests that have become flaky @@ -4791,8 +4925,8 @@ # Prefetching inspector protocol test is flaky crbug.com/40854799 virtual/prefetch/http/tests/inspector-protocol/prefetch/request-will-be-sent.https.js [ Failure Pass ] crbug.com/40854799 virtual/prefetch/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ] -crbug.com/40854799 virtual/prefetch-serviceworker/http/tests/inspector-protocol/prefetch/request-will-be-sent.https.js [ Failure Pass ] -crbug.com/40854799 virtual/prefetch-serviceworker/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ] +crbug.com/40854799 virtual/prefetch-sw/http/tests/inspector-protocol/prefetch/request-will-be-sent.https.js [ Failure Pass ] +crbug.com/40854799 virtual/prefetch-sw/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ] crbug.com/40854799 virtual/prerender2-fallback-prefetch-spec-rules-prefetch/http/tests/inspector-protocol/prefetch/request-will-be-sent.https.js [ Failure Pass ] crbug.com/40854799 virtual/prerender2-fallback-prefetch-spec-rules-prefetch/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ] @@ -6300,8 +6434,6 @@ crbug.com/40146374 virtual/select-parser-relaxation-opt-out/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-picker-interactive-element-focus.tentative.html [ Failure ] crbug.com/40146374 virtual/select-parser-relaxation-opt-out/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.html [ Failure ] -crbug.com/415205686 editing/input/selectall-in-input-with-text-security.html [ Crash Failure ] - # Flaky on headless_shell_wpt_tests crbug.com/40146374 external/wpt/html/semantics/forms/the-select-element/customizable-select/select-option-images.tentative.html [ Failure Pass ] @@ -8295,7 +8427,7 @@ external/wpt/webdriver/tests/bidi/browsing_context/create/background.py [ Failure Pass ] external/wpt/webdriver/tests/bidi/browsing_context/set_viewport/viewport.py [ Failure Pass ] external/wpt/webdriver/tests/bidi/network/remove_intercept/remove_intercept.py [ Failure Pass Timeout ] -external/wpt/webdriver/tests/bidi/network/response_completed/response_completed.py [ Failure Pass Timeout ] +[ Linux ] external/wpt/webdriver/tests/bidi/network/response_completed/response_completed.py [ Failure Pass Timeout ] # Gardener 2024-03-21 (PST) crbug.com/330668788 [ Linux ] external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cues-enter-seeking.html [ Failure Pass ] @@ -8929,9 +9061,9 @@ crbug.com/377777852 [ Linux ] virtual/private-aggregation-developer-mode/wpt_internal/private-aggregation/shared-storage-filtering-id-sends-report.https.window.html [ Pass Timeout ] crbug.com/377927602 external/wpt/selection/caret/collapse-pre-linestart-2.html [ Failure Pass ] crbug.com/377927602 external/wpt/selection/caret/editing-host-has-only-invisible-br.html [ Failure Pass Timeout ] -crbug.com/377938333 external/wpt/webdriver/tests/bidi/browsing_context/context_created/original_opener.py [ Failure Pass Timeout ] +crbug.com/377938333 [ Linux ] external/wpt/webdriver/tests/bidi/browsing_context/context_created/original_opener.py [ Failure Pass Timeout ] crbug.com/377938333 external/wpt/webdriver/tests/bidi/browsing_context/print/page.py [ Failure Pass Timeout ] -crbug.com/377938333 external/wpt/webdriver/tests/classic/element_clear/disabled.py [ Failure Pass Timeout ] +crbug.com/377938333 [ Linux ] external/wpt/webdriver/tests/classic/element_clear/disabled.py [ Failure Pass Timeout ] crbug.com/377938333 external/wpt/webdriver/tests/classic/execute_async_script/arguments.py [ Failure Pass Timeout ] crbug.com/377938333 external/wpt/webdriver/tests/classic/find_element/find.py [ Failure Pass Timeout ] crbug.com/377938333 external/wpt/webdriver/tests/classic/navigate_to/file.py [ Failure Pass Timeout ] @@ -9208,12 +9340,13 @@ crbug.com/414243950 [ Linux ] virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.sharedworker.html?cpu [ Crash ] crbug.com/414243950 [ Linux ] virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.worker.html?cpu [ Crash ] -# Gardener 2025-04-30 -crbug.com/324536287 external/wpt/soft-navigation-heuristics/interaction-with-paint-before-back.tentative.html [ Failure Pass ] - # Gardener 2025-05-01 crbug.com/411161567 [ Linux ] accessibility/interest-target.html [ Failure Pass ] +crbug.com/407751668 http/tests/devtools/elements/styles-4/styles-overloaded-shorthand.js [ Failure Pass ] +crbug.com/407751668 http/tests/devtools/elements/styles-4/styles-properties-overload.js [ Failure Pass ] +crbug.com/407751668 http/tests/devtools/elements/styles-4/styles-update-from-js.js [ Failure Pass ] + # Gardener 2025-05-05 crbug.com/413289778 [ Mac12 ] wpt_internal/fedcm/fedcm-cache-manifest.https.html [ Failure ] crbug.com/415747471 [ Mac ] virtual/text-antialias/international/bidi-CS-after-AN.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 8d2f75a..82ec477 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -886,18 +886,6 @@ "args": ["--enable-font-antialiasing", "--text-contrast=0.5", "--text-gamma=0.0"], "expires": "Jan 1, 2026" }, - " Temporary test suite running virtual/text-antialias using FreeType, until ", - " we are ready to remove FreeType and stop rolling FreeType into Chromium. ", - " Until then, we need pixel coverage for font rendering tests running through ", - " FreeType. ", - { - "prefix": "text-antialias-freetype", - "owners": ["drott@chromium.org"], - "platforms": ["Linux"], - "bases": [ "virtual/text-antialias" ], - "args": ["--enable-font-antialiasing", "--disable-features=FontationsFontBackend"], - "expires": "Jul 1, 2025" - }, { "prefix": "text-contrast-gamma", "owners": ["kschmi@microsoft.com"], @@ -1673,7 +1661,7 @@ "expires": "Oct 1, 2025" }, { - "prefix": "prefetch-serviceworker", + "prefix": "prefetch-sw", "owners": ["hiroshige@chromium.org"], "platforms": ["Linux", "Mac", "Win"], "bases": [
diff --git a/third_party/blink/web_tests/accessibility/inline-text-textarea-expected.txt b/third_party/blink/web_tests/accessibility/inline-text-textarea-expected.txt index b5226e7..502256ff 100644 --- a/third_party/blink/web_tests/accessibility/inline-text-textarea-expected.txt +++ b/third_party/blink/web_tests/accessibility/inline-text-textarea-expected.txt
@@ -3,7 +3,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". PASS firstInlineTextBoxBefore.isEqual(firstInlineTextBoxAfter) is false -FAIL lastInlineTextBoxBefore.isEqual(lastInlineTextBoxAfter) should be true. Was false. +PASS lastInlineTextBoxBefore.isEqual(lastInlineTextBoxAfter) is true PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/blink/web_tests/editing/input/selectall-in-input-with-text-security.html b/third_party/blink/web_tests/editing/input/selectall-in-input-with-text-security.html deleted file mode 100644 index e6faa01..0000000 --- a/third_party/blink/web_tests/editing/input/selectall-in-input-with-text-security.html +++ /dev/null
@@ -1,19 +0,0 @@ -<!doctype html> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<title>This test should not crash.</title> -<input type="password" id="testnode"> -<script> -async_test( t => { - window.addEventListener('DOMContentLoaded', () => { - internals.settings.setPasswordEchoEnabled(true); - const testnode = document.getElementById('testnode'); - testnode.focus(); - document.execCommand("InsertHTML", false, "12x̲̅45"); - document.execCommand("selectAll"); - t.step_timeout(()=>{ - t.done(); - },1100); - }); -}, 'The renderer should not crash'); -</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-images/linear-gradient-calc-em-units-ref.html b/third_party/blink/web_tests/external/wpt/css/css-images/linear-gradient-calc-em-units-ref.html new file mode 100644 index 0000000..be13be8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-images/linear-gradient-calc-em-units-ref.html
@@ -0,0 +1,7 @@ +<!DOCTYPE html> +<title>CSS Test Reference</title> +<style> + div { width: 100px; height: 100px; } +</style> +<div style="background: linear-gradient(blue 20px, yellow)"></div> +<div style="background: linear-gradient(blue 60px, yellow)"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-images/linear-gradient-calc-em-units.html b/third_party/blink/web_tests/external/wpt/css/css-images/linear-gradient-calc-em-units.html new file mode 100644 index 0000000..e764e628 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-images/linear-gradient-calc-em-units.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>CSS Images Test: Linear gradient with em in calc()</title> +<link rel="help" href="https://drafts.csswg.org/css-images/#linear-gradients"> +<link rel="match" href="linear-gradient-calc-em-units-ref.html"> +<style> + div { + width: 100px; + height: 100px; + background: linear-gradient(blue calc(2em), yellow); + } + #em1 { + font-size: 10px; + } + #em2 { + font-size: 30px; + } +</style> +<div id="em1"></div> +<div id="em2"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/table-col-and-dead-row-group-crash.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/table-col-and-dead-row-group-crash.html new file mode 100644 index 0000000..e6e90a6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/table-col-and-dead-row-group-crash.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://issues.chromium.org/issues/416061199"> +<div style="display:table;"> + <div style="display:table-column-group;"></div> + <div id="e13" style="display:table-row-group;"> + <div style="height:200vh;"></div> + x + </div> +</div> +<script> + window.scroll(0, 100); + e13.style.display = "none"; +</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 new file mode 100644 index 0000000..e79da1e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/urls/fragment-only-expected.txt
@@ -0,0 +1,13 @@ +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/encoding/OWNERS b/third_party/blink/web_tests/external/wpt/encoding/OWNERS index 4392ef47..4a32e24 100644 --- a/third_party/blink/web_tests/external/wpt/encoding/OWNERS +++ b/third_party/blink/web_tests/external/wpt/encoding/OWNERS
@@ -1 +1,2 @@ ricea@chromium.org +yyanagisawa@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/interaction-with-paint-before-back.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/interaction-with-paint-before-back.tentative.html index 7b884f2..5961a6e 100644 --- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/interaction-with-paint-before-back.tentative.html +++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/interaction-with-paint-before-back.tentative.html
@@ -1,73 +1,93 @@ -<!DOCTYPE HTML> +<!doctype html> <html> -<head> -<meta charset="utf-8"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/resources/testdriver.js"></script> -<script src="/resources/testdriver-vendor.js"></script> -<script src="resources/soft-navigation-helper.js"></script> -</head> -<body> - <main id=main> - <div> - <a id=link><img src="/images/lcp-256x256.png" id="img"></a> - <a id=not_nav><img src="/images/lcp-16x16.png"></a> + <head> + <meta charset="utf-8" /> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + </head> + <body> + <div id="main"> + <div id="almost_soft_nav_div"> + A click will almost initiate a soft nav, by (1) mutating the DOM by adding an image; (2) + causing the image to be painted. + </div> + <div id="soft_nav_div"> + A click will initiate a soft nav, by (1) mutating the DOM by adding an image; (2) causing + the image to be painted; (3) updating the URL via history.back(), but without causing a hard + navigation. + </div> </div> - </main> - <script> - // Push state a couple of times - history.pushState({}, "", "foobar.html"); - history.pushState({}, "", "anotherOne.html"); - - (async () => { - const link = document.getElementById("link"); - // Trigger a user interaction that doesn't result in a soft navigation, but - // does paint. - await (async () => { - const not_nav = document.getElementById("not_nav"); - let non_soft_nav_click; - const non_soft_nav_click_promise = - new Promise(r => { non_soft_nav_click = r; }); - not_nav.addEventListener("click", () => { - addImageToMain("lcp-133x106.png", "not_soft_nav_image"); - (new PerformanceObserver(non_soft_nav_click)).observe({type: "element"}); - }); - if (test_driver) { - test_driver.click(not_nav); - } - await non_soft_nav_click_promise; - })(); - const url = URL + "?" + counter; - link.addEventListener("click", () => { - // Add an LCP element. - const img = new Image(); - img.src = '/images/lcp-100x500.png' + "?" + Math.random(); - document.getElementById("main").appendChild(img); - history.back(); - }); - promise_test(async t => { - const soft_nav_promise = waitOnSoftNav(); - if (test_driver) { - test_driver.click(link); - } - await soft_nav_promise; - assert_equals( - document.softNavigations, 1, - 'Single Soft Navigation detected'); - const [entries, options] = await new Promise(resolve => { - (new PerformanceObserver((list, obs, options) => resolve( - [list.getEntries(), options]))).observe( - {type: 'soft-navigation', buffered: true}); + <script> + promise_test( + async (t) => { + // Setup a click handler for 'almost_soft_nav_div', which adds a + // specific, identifiable image 'almost_soft_nav_img' to the document. + document.getElementById("almost_soft_nav_div").addEventListener("click", () => { + const img = new Image(); + img.src = "/images/lcp-133x106.png"; + img.elementTiming = "almost_soft_nav_img"; + document.getElementById("main").appendChild(img); }); - assert_equals(entries.length, 1, - "Performance observer got an entry"); - }, "Ensure that soft navigation entry emitted through a synchronous " + - "event that modified DOM and committed a same document navigation, " + - "and that was preceded by a user intreaction that resulted in a " + - "contentful paint is properly detected."); - })(); - </script> -</body> + // Also set up a click handler for 'soft_nav_div', for adding + // another image, but in addition to what we do for the almost soft nav + // above, also let the handler change the URL, by invoking + // history.back(). We prepare with pushState for the history.back() + // invocation, to avoid triggering a hard navigation. + const test_origin = new URL(location.href).origin; + history.pushState({}, "", "/foo.html"); // We will observe this below. + history.pushState({}, "", "/bar.html"); // Prep for history.back(). + document.getElementById("soft_nav_div").addEventListener("click", () => { + const img = new Image(); + img.src = "/images/lcp-133x106.png"; + document.getElementById("main").appendChild(img); + history.back(); // URL change triggering the soft nav + }); + + // Now, click almost_soft_nav_div, and observe that time image + // was rendered but no soft nav was triggered. + { + const element_timing_promise = new Promise((resolve) => { + new PerformanceObserver(resolve).observe({ type: "element", buffered: true }); + }); + if (test_driver) { + test_driver.click(almost_soft_nav_div); + } + // Returns entries of type PerformanceElementTiming, see + // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceElementTiming. + const entries = (await element_timing_promise).getEntries(); + assert_equals(entries.length, 1); + assert_equals( + entries[0].identifier, + "almost_soft_nav_img", + "Image based on the user interaction was painted.", + ); + assert_equals(document.softNavigations, 0, "No soft navigation detected."); + } + + // Now, click soft_nav_div, and observe the detected soft navigation. + { + const soft_nav_promise = new Promise((resolve) => { + new PerformanceObserver(resolve).observe({ type: "soft-navigation", buffered: true }); + }); + if (test_driver) { + test_driver.click(soft_nav_div); + } + // Returns entries of type SoftNavigationEntry, see + // https://github.com/WICG/soft-navigations/ + const entries = (await soft_nav_promise).getEntries(); + assert_equals(document.softNavigations, 1, "Single soft navigation detected"); + assert_equals(entries.length, 1, "Performance observer got an entry"); + assert_equals(entries[0].name, test_origin + "/foo.html"); + } + }, + "Ensure that soft navigation entry emitted through a synchronous " + + "event that modified DOM and committed a same document navigation, " + + "and that was preceded by a user interaction that resulted in a " + + "contentful paint is properly detected.", + ); + </script> + </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/log.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/log.https.any.js index 011beef..8ed807b 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/log.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/log.https.any.js
@@ -14,11 +14,8 @@ // MLOperand log(MLOperand input); -const getLogPrecisionTolerance = (graphResources) => { - const toleranceValueDict = {float32: 1 / 1024, float16: 1 / 1024}; - const expectedDataType = - getExpectedDataTypeOfSingleOutput(graphResources.expectedOutputs); - return {metricType: 'ATOL', value: toleranceValueDict[expectedDataType]}; +const getLogPrecisionTolerance = () => { + return {metricType: 'ULP', value: 8}; }; const logTests = [
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sign.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sign.https.any.js index 4c3a330..004c03b 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sign.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sign.https.any.js
@@ -122,7 +122,8 @@ 'graph': { 'inputs': { 'signInput': { - 'data': [-1, 0, 1, 2], + // int32 range: [/* -(2**31) */ -2147483648, /* 2**31 - 1 */ 2147483647] + 'data': [-2147483648, 0, 2147483646, 2147483647], 'descriptor': {shape: [2, 2], dataType: 'int32'} } }, @@ -166,7 +167,8 @@ 'graph': { 'inputs': { 'signInput': { - 'data': [-1, 0, 1, 2, -2, -1, 0, 1], + // int8 range: [/* -(2**7) */ -128, /* 2**7 - 1 */ 127] + 'data': [-128, 0, 1, 2, -2, -1, 0, 127], 'descriptor': {shape: [1, 2, 2, 2], dataType: 'int8'} } },
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-clone.https.html b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-clone.https.html index 9f07713..c93f8b3 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-clone.https.html +++ b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-clone.https.html
@@ -37,7 +37,7 @@ const original = result.value; let clone = structuredClone(original); assert_equals(original.timestamp, clone.timestamp); - assert_equals(original.getMetadata().absCaptureTime, clone.getMetadata().absCaptureTime); + assert_equals(original.getMetadata().captureTime, clone.getMetadata().captureTime); assert_array_equals(Array.from(original.data), Array.from(clone.data)); await writer2.write(clone); resolve();
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-metadata.https.html b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-metadata.https.html index 435e1c0..df4577c5 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-metadata.https.html +++ b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCEncodedAudioFrame-metadata.https.html
@@ -39,7 +39,7 @@ assert_true(original.getMetadata().hasOwnProperty('receiveTime')); assert_true(original.getMetadata().receiveTime > 0); assert_equals(original.getMetadata().rtpTimestamp, newFrame.getMetadata().rtpTimestamp); - assert_equals(original.getMetadata().absCaptureTime, newFrame.getMetadata().absCaptureTime); + assert_equals(original.getMetadata().captureTime, newFrame.getMetadata().captureTime); assert_equals(original.getMetadata().receiveTime, newFrame.getMetadata().receiveTime); assert_array_equals(Array.from(original.data), Array.from(newFrame.data)); await writer2.write(newFrame); @@ -83,7 +83,7 @@ assert_not_equals(original.getMetadata().rtpTimestamp, newFrame.getMetadata().rtpTimestamp); assert_equals(newMetadata.rtpTimestamp, newFrame.getMetadata().rtpTimestamp); assert_equals(original.getMetadata().receiveTime, newFrame.getMetadata().receiveTime); - assert_equals(original.getMetadata().absCaptureTime, newFrame.getMetadata().absCaptureTime); + assert_equals(original.getMetadata().captureTime, newFrame.getMetadata().captureTime); assert_array_equals(Array.from(original.data), Array.from(newFrame.data)); await writer2.write(newFrame); resolve();
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCPeerConnection-insertable-streams.js b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCPeerConnection-insertable-streams.js index 0bf820ac..f3873e1 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCPeerConnection-insertable-streams.js +++ b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/tentative/RTCPeerConnection-insertable-streams.js
@@ -30,7 +30,7 @@ metadata1.payloadType == metadata2.payloadType && areArraysEqual( metadata1.contributingSources, metadata2.contributingSources) && - metadata1.absCaptureTime == metadata2.absCaptureTime && + metadata1.captureTime == metadata2.captureTime && metadata1.frameId === metadata2.frameId && areArraysEqual(metadata1.dependencies, metadata2.dependencies) && metadata1.spatialIndex === metadata2.spatialIndex &&
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/ellipsis-platform-font-change-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/ellipsis-platform-font-change-expected.png deleted file mode 100644 index 9970a54..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/ellipsis-platform-font-change-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/emphasis-complex-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/emphasis-complex-expected.png deleted file mode 100644 index b007456..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/emphasis-complex-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/fake-italic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/fake-italic-expected.png deleted file mode 100644 index 98438466..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/fake-italic-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/font-features/caps-native-synthesis-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/font-features/caps-native-synthesis-expected.png deleted file mode 100644 index 383456b..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/font-features/caps-native-synthesis-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/font-size-adjust-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/font-size-adjust-expected.png deleted file mode 100644 index 44108e26..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/font-size-adjust-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/international/arabic-vertical-offset-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/international/arabic-vertical-offset-expected.png deleted file mode 100644 index 512b78f..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/international/arabic-vertical-offset-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/midword-break-before-surrogate-pair-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/midword-break-before-surrogate-pair-expected.png deleted file mode 100644 index 71fc612..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/midword-break-before-surrogate-pair-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/shadow-translucent-fill-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/shadow-translucent-fill-expected.png deleted file mode 100644 index da6f277..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/shadow-translucent-fill-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/shaping/same-script-different-lang-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/shaping/same-script-different-lang-expected.png deleted file mode 100644 index 38e3b71..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/shaping/same-script-different-lang-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/webfont-synthetic-bold-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/webfont-synthetic-bold-expected.png deleted file mode 100644 index d0a2638..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias-freetype/virtual/text-antialias/webfont-synthetic-bold-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/log.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/log.https.any_gpu-expected.txt deleted file mode 100644 index fd19bb8..0000000 --- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/log.https.any_gpu-expected.txt +++ /dev/null
@@ -1,17 +0,0 @@ -This is a testharness.js-based test. -[FAIL] log float16 positive 0D scalar - assert_array_approx_equals: test log float16 property 0, expected 4.15625 +/- 0.0009765625, expected 4.15625 but got 4.15234375 -[FAIL] log float16 positive 1D constant tensor - assert_array_approx_equals: test log float16 property 0, expected 4.15625 +/- 0.0009765625, expected 4.15625 but got 4.15234375 -[FAIL] log float16 positive 1D tensor - assert_array_approx_equals: test log float16 property 0, expected 4.15625 +/- 0.0009765625, expected 4.15625 but got 4.15234375 -[FAIL] log float16 positive 2D tensor - assert_array_approx_equals: test log float16 property 0, expected 4.15625 +/- 0.0009765625, expected 4.15625 but got 4.15234375 -[FAIL] log float16 positive 3D tensor - assert_array_approx_equals: test log float16 property 0, expected 4.15625 +/- 0.0009765625, expected 4.15625 but got 4.15234375 -[FAIL] log float16 positive 4D tensor - assert_array_approx_equals: test log float16 property 0, expected 4.15625 +/- 0.0009765625, expected 4.15625 but got 4.15234375 -[FAIL] log float16 positive 5D tensor - assert_array_approx_equals: test log float16 property 0, expected 4.15625 +/- 0.0009765625, expected 4.15625 but got 4.15234375 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/printing/print-color-adjust-001-expected.html b/third_party/blink/web_tests/printing/print-color-adjust-001-expected.html new file mode 100644 index 0000000..efcbef834 --- /dev/null +++ b/third_party/blink/web_tests/printing/print-color-adjust-001-expected.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<script> + if (window.testRunner) { + testRunner.setPrinting(); + if (window.internals) + internals.settings.setShouldPrintBackgrounds(false); + } +</script> +<p>Test passes if there is nothing below.</p>
diff --git a/third_party/blink/web_tests/printing/print-color-adjust-001.html b/third_party/blink/web_tests/printing/print-color-adjust-001.html new file mode 100644 index 0000000..be21172f --- /dev/null +++ b/third_party/blink/web_tests/printing/print-color-adjust-001.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<title>print-color-adjust:economy is initial value</title> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-color-adjust-1/#print-color-adjust"> +<script> + if (window.testRunner) { + testRunner.setPrinting(); + if (window.internals) + internals.settings.setShouldPrintBackgrounds(false); + } +</script> +<p>Test passes if there is nothing below.</p> +<div style="height:100px; background:red;"></div>
diff --git a/third_party/blink/web_tests/printing/print-color-adjust-002-expected.html b/third_party/blink/web_tests/printing/print-color-adjust-002-expected.html new file mode 100644 index 0000000..b3d8a40 --- /dev/null +++ b/third_party/blink/web_tests/printing/print-color-adjust-002-expected.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<script> + if (window.testRunner) { + testRunner.setPrinting(); + if (window.internals) + internals.settings.setShouldPrintBackgrounds(false); + } +</script> +<p>Test passes if there is no red on this page.</p>
diff --git a/third_party/blink/web_tests/printing/print-color-adjust-002.html b/third_party/blink/web_tests/printing/print-color-adjust-002.html new file mode 100644 index 0000000..6e4ba2a5 --- /dev/null +++ b/third_party/blink/web_tests/printing/print-color-adjust-002.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<title>print-color-adjust:economy is initial value</title> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-color-adjust-1/#print-color-adjust"> +<script> + if (window.testRunner) { + testRunner.setPrinting(); + if (window.internals) + internals.settings.setShouldPrintBackgrounds(false); + } +</script> +<style> + body { + background: red; + } +</style> +<p>Test passes if there is no red on this page.</p>
diff --git a/third_party/blink/web_tests/printing/print-color-adjust-003-expected.html b/third_party/blink/web_tests/printing/print-color-adjust-003-expected.html new file mode 100644 index 0000000..05e500a --- /dev/null +++ b/third_party/blink/web_tests/printing/print-color-adjust-003-expected.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<script> + if (window.testRunner) { + testRunner.setPrinting(); + if (window.internals) + internals.settings.setShouldPrintBackgrounds(false); + } +</script> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div style="width:100px; height:100px; print-color-adjust:exact; background-color:green;"></div>
diff --git a/third_party/blink/web_tests/printing/print-color-adjust-003.html b/third_party/blink/web_tests/printing/print-color-adjust-003.html new file mode 100644 index 0000000..2c064e7 --- /dev/null +++ b/third_party/blink/web_tests/printing/print-color-adjust-003.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>print-color-adjust inheritance and nesting</title> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-color-adjust-1/#print-color-adjust"> +<script> + if (window.testRunner) { + testRunner.setPrinting(); + if (window.internals) + internals.settings.setShouldPrintBackgrounds(false); + } +</script> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div style="width:110px; height:110px; print-color-adjust:economy; background:red;"> + <div style="float:left; width:50px; height:100px; print-color-adjust:exact; background:green;"></div> + <div style="display:flow-root; width:50px; print-color-adjust:exact;"> + <div style="width:50px; height:100px; background:green;"></div> + <div style="height:10px; print-color-adjust:economy; background:red;"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/virtual/prefetch-serviceworker/DIR_METADATA b/third_party/blink/web_tests/virtual/prefetch-sw/DIR_METADATA similarity index 100% rename from third_party/blink/web_tests/virtual/prefetch-serviceworker/DIR_METADATA rename to third_party/blink/web_tests/virtual/prefetch-sw/DIR_METADATA
diff --git a/third_party/blink/web_tests/virtual/prefetch-serviceworker/README.md b/third_party/blink/web_tests/virtual/prefetch-sw/README.md similarity index 100% rename from third_party/blink/web_tests/virtual/prefetch-serviceworker/README.md rename to third_party/blink/web_tests/virtual/prefetch-sw/README.md
diff --git a/third_party/blink/web_tests/virtual/text-antialias-freetype/README.md b/third_party/blink/web_tests/virtual/text-antialias-freetype/README.md deleted file mode 100644 index df99b69..0000000 --- a/third_party/blink/web_tests/virtual/text-antialias-freetype/README.md +++ /dev/null
@@ -1,4 +0,0 @@ -Temporary test suite running virtual/text-antialias using FreeType, until -we are ready to remove FreeType and stop rolling FreeType into Chromium. -Until then, we need pixel coverage for font rendering tests running through -FreeType.
diff --git a/third_party/boringssl/src b/third_party/boringssl/src index 0f1d0df..864a235 160000 --- a/third_party/boringssl/src +++ b/third_party/boringssl/src
@@ -1 +1 @@ -Subproject commit 0f1d0df6183d6ddf0b4d7a10bf80122c7ec260e6 +Subproject commit 864a235afcf4d2575b1eab8de96fbf0d84f6cda9
diff --git a/third_party/catapult b/third_party/catapult index 52ad7cf..64c31ff 160000 --- a/third_party/catapult +++ b/third_party/catapult
@@ -1 +1 @@ -Subproject commit 52ad7cf544050f01f47c070716b9dae8eb9fab2b +Subproject commit 64c31ffa4d735add4a7e7520a52e0e3160216132
diff --git a/third_party/chromite b/third_party/chromite index 73e7b77..96096c3 160000 --- a/third_party/chromite +++ b/third_party/chromite
@@ -1 +1 @@ -Subproject commit 73e7b77d6878e58c3d26d5fe0d5877cf9ac44597 +Subproject commit 96096c3c83cbe537782e84dfc12981f146723f6a
diff --git a/third_party/crossbench b/third_party/crossbench index 35e8177a..73e0cfe 160000 --- a/third_party/crossbench +++ b/third_party/crossbench
@@ -1 +1 @@ -Subproject commit 35e8177a7d7594203c543fe3875fd587b949fca2 +Subproject commit 73e0cfe22e2699bf14bedb489c0b39ba1bc03702
diff --git a/third_party/dawn b/third_party/dawn index 5b595fd..dfe3855 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit 5b595fdbcfc1d0d79354ab74f675c564273874c7 +Subproject commit dfe3855e5d0b5367a598e60674766ffa1c894c71
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index cd65015..e5e1d2e 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit cd650159ff9210d83ed1e1aaf02b1c071d5123b3 +Subproject commit e5e1d2ed56cb0ad0c82a0b36295cae4578d8a226
diff --git a/third_party/eigen3/README.chromium b/third_party/eigen3/README.chromium index 337dbcdc..386b8ba6 100644 --- a/third_party/eigen3/README.chromium +++ b/third_party/eigen3/README.chromium
@@ -1,8 +1,8 @@ Name: Eigen Short Name: eigen3 URL: https://gitlab.com/libeigen/eigen -Version: 464c1d097891a1462ab28bf8bb763c1683883892 -Date: 2025-03-13 +Version: 729443409942a1816ddf74b95224003b83f4925c +Date: 2025-05-07 License: MPL-2.0 License File: LICENSE Security Critical: Yes
diff --git a/third_party/eigen3/src b/third_party/eigen3/src index 464c1d0..7294434 160000 --- a/third_party/eigen3/src +++ b/third_party/eigen3/src
@@ -1 +1 @@ -Subproject commit 464c1d097891a1462ab28bf8bb763c1683883892 +Subproject commit 729443409942a1816ddf74b95224003b83f4925c
diff --git a/third_party/glslang/src b/third_party/glslang/src index fc9889c..9635880 160000 --- a/third_party/glslang/src +++ b/third_party/glslang/src
@@ -1 +1 @@ -Subproject commit fc9889c889561c5882e83819dcaffef5ed45529b +Subproject commit 963588074b26326ff0426c8953c1235213309bdb
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src index d7bdad4..e3e030e 160000 --- a/third_party/llvm-libc/src +++ b/third_party/llvm-libc/src
@@ -1 +1 @@ -Subproject commit d7bdad4ef86b827a96469b1dfdfcfa1218930e59 +Subproject commit e3e030ec6ee1674bf2195d0cfd0a4bf5fee16537
diff --git a/third_party/pdfium b/third_party/pdfium index e265bde6..b8e8a35 160000 --- a/third_party/pdfium +++ b/third_party/pdfium
@@ -1 +1 @@ -Subproject commit e265bde6fee233a96f87ca46464dd662531e0f90 +Subproject commit b8e8a35d09143db3342b94ddef076c03aa46159f
diff --git a/third_party/rust/font_types/OWNERS b/third_party/rust/font_types/OWNERS new file mode 100644 index 0000000..8dd30b61 --- /dev/null +++ b/third_party/rust/font_types/OWNERS
@@ -0,0 +1 @@ +file://third_party/rust/skrifa/OWNERS
diff --git a/third_party/rust/read_fonts/OWNERS b/third_party/rust/read_fonts/OWNERS new file mode 100644 index 0000000..8dd30b61 --- /dev/null +++ b/third_party/rust/read_fonts/OWNERS
@@ -0,0 +1 @@ +file://third_party/rust/skrifa/OWNERS
diff --git a/third_party/rust/skrifa/OWNERS b/third_party/rust/skrifa/OWNERS new file mode 100644 index 0000000..e6c414c4 --- /dev/null +++ b/third_party/rust/skrifa/OWNERS
@@ -0,0 +1,2 @@ +bungeman@google.com +drott@chromium.org
diff --git a/third_party/spirv-headers/src b/third_party/spirv-headers/src index bab63ff..6d0784e 160000 --- a/third_party/spirv-headers/src +++ b/third_party/spirv-headers/src
@@ -1 +1 @@ -Subproject commit bab63ff679c41eb75fc67dac76e1dc44426101e1 +Subproject commit 6d0784e9f1ab92c17eeea94821b2465c14a52be9
diff --git a/third_party/spirv-tools/src b/third_party/spirv-tools/src index 8e9165a..e8864ed 160000 --- a/third_party/spirv-tools/src +++ b/third_party/spirv-tools/src
@@ -1 +1 @@ -Subproject commit 8e9165a3d162967a424dcf2ff645a98b50381cce +Subproject commit e8864edbebe9fb9872c6c95b2363b490c6105a15
diff --git a/third_party/swiftshader b/third_party/swiftshader index 093b4d8..930d46d 160000 --- a/third_party/swiftshader +++ b/third_party/swiftshader
@@ -1 +1 @@ -Subproject commit 093b4d82a49affdcc5e6d68cc17aa0c33c82e9a2 +Subproject commit 930d46d31b5d637f313fd5ef55da2bbf053c26c1
diff --git a/third_party/tflite/BUILD.gn b/third_party/tflite/BUILD.gn index 561d69f..1ccc957a 100644 --- a/third_party/tflite/BUILD.gn +++ b/third_party/tflite/BUILD.gn
@@ -11,6 +11,7 @@ import("//third_party/mediapipe/features.gni") import("//third_party/protobuf/proto_library.gni") import("//third_party/tflite/features.gni") +import("//third_party/tflite/tf_version.gni") import("//third_party/tflite/tflite_target.gni") proto_library("tflite_proto") { @@ -48,7 +49,13 @@ "src/third_party/xla/third_party/tsl", "//third_party/pthreadpool/src/include", ] - defines = [ "TFL_STATIC_LIBRARY_BUILD" ] + defines = [ + "TFL_STATIC_LIBRARY_BUILD", + "TF_MAJOR_VERSION=" + tf_version_major, + "TF_MINOR_VERSION=" + tf_version_minor, + "TF_PATCH_VERSION=" + tf_version_patch, + "TF_VERSION_SUFFIX", + ] if (is_android) { libs = [ "log" ] }
diff --git a/third_party/tflite/README.chromium b/third_party/tflite/README.chromium index ee4b5f9..b5c84b7 100644 --- a/third_party/tflite/README.chromium +++ b/third_party/tflite/README.chromium
@@ -1,8 +1,8 @@ Name: TensorFlow Lite Short Name: tflite URL: https://github.com/tensorflow/tensorflow -Version: 829a168408c4422b4290eba063287542a608382e -Date: 2025-04-28 +Version: c4aa8ff91256b43fe0cecc246c77a00e2145b3bd +Date: 2025-05-07 License: Caffe, Apache-2.0 License File: LICENSE Security Critical: Yes
diff --git a/third_party/tflite/generate_tf_version_gni.py b/third_party/tflite/generate_tf_version_gni.py new file mode 100755 index 0000000..e7570da --- /dev/null +++ b/third_party/tflite/generate_tf_version_gni.py
@@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +# 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. +"""Convert tf_version.bzl to tf_version.gni.""" + +import os +import re +import sys + +_TMPL = ''' +# 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. + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# +# THIS FILE IS AUTO-GENERATED. DO NOT EDIT. +# +# See //third_party/tflite/generate_tf_version_gni.py +# +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +tf_version_major = %TF_VERSION_MAJOR% +tf_version_minor = %TF_VERSION_MINOR% +tf_version_patch = %TF_VERSION_PATCH% +'''.lstrip() + + +def _tflite_dir() -> str: + """Returns the absolute path of //third_party/tflite/.""" + return os.path.dirname(os.path.realpath(__file__)) + + +def _tensorflow_dir() -> str: + """Returns the absolute path of //third_party/tflite/src/tensorflow/.""" + return os.path.join(_tflite_dir(), "src", "tensorflow") + + +def main(): + with open(os.path.join(_tensorflow_dir(), 'tf_version.bzl'), 'r') as f: + content = f.read() + + match = re.search(r'TF_VERSION = "(\d+).(\d+).(\d+)"', content) + if not match: + print("Error: Could not find TF_VERSION in tf_version.bzl") + sys.exit(1) + + with open(os.path.join(_tflite_dir(), 'tf_version.gni'), 'w') as f: + f.write(_TMPL.replace('%TF_VERSION_MAJOR%', match.group(1)) \ + .replace('%TF_VERSION_MINOR%', match.group(2)) \ + .replace('%TF_VERSION_PATCH%', match.group(3))) + + +if __name__ == '__main__': + main()
diff --git a/third_party/tflite/src b/third_party/tflite/src index 829a168..c4aa8ff 160000 --- a/third_party/tflite/src +++ b/third_party/tflite/src
@@ -1 +1 @@ -Subproject commit 829a168408c4422b4290eba063287542a608382e +Subproject commit c4aa8ff91256b43fe0cecc246c77a00e2145b3bd
diff --git a/third_party/tflite/tf_version.gni b/third_party/tflite/tf_version.gni new file mode 100644 index 0000000..f381ee0 --- /dev/null +++ b/third_party/tflite/tf_version.gni
@@ -0,0 +1,19 @@ +# 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. + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# +# THIS FILE IS AUTO-GENERATED. DO NOT EDIT. +# +# See //third_party/tflite/generate_tf_version_gni.py +# +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +tf_version_major = 2 +tf_version_minor = 20 +tf_version_patch = 0
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps index 96793fb0..0b78635 160000 --- a/third_party/vulkan-deps +++ b/third_party/vulkan-deps
@@ -1 +1 @@ -Subproject commit 96793fb0ff6fb5d4328cc6f71d84f5cb2d835daf +Subproject commit 0b7863549d960381696d3cd7485ac6a284122e15
diff --git a/third_party/vulkan-headers/src b/third_party/vulkan-headers/src index e2e53a7..9c77de5c 160000 --- a/third_party/vulkan-headers/src +++ b/third_party/vulkan-headers/src
@@ -1 +1 @@ -Subproject commit e2e53a724677f6eba8ff0ce1ccb64ee321785cbd +Subproject commit 9c77de5c3dd216f28e407eec65ed9c0a296c1f74
diff --git a/third_party/vulkan-loader/src b/third_party/vulkan-loader/src index fb78607..fefd7ed 160000 --- a/third_party/vulkan-loader/src +++ b/third_party/vulkan-loader/src
@@ -1 +1 @@ -Subproject commit fb78607414e154c7a5c01b23177ba719c8a44909 +Subproject commit fefd7ed96ef9994f0080dbd078822b07d8637918
diff --git a/third_party/vulkan-tools/src b/third_party/vulkan-tools/src index 0b81967..ba13d38 160000 --- a/third_party/vulkan-tools/src +++ b/third_party/vulkan-tools/src
@@ -1 +1 @@ -Subproject commit 0b8196724e4ad28cc7459b82a9b75f252c08cb3e +Subproject commit ba13d38d06830f714a93c5bb159e6e4bacacf0bc
diff --git a/third_party/vulkan-utility-libraries/src b/third_party/vulkan-utility-libraries/src index 4e246c5..be40e67 160000 --- a/third_party/vulkan-utility-libraries/src +++ b/third_party/vulkan-utility-libraries/src
@@ -1 +1 @@ -Subproject commit 4e246c56ec5afb5ad66b9b04374d39ac04675c8e +Subproject commit be40e67892c83d4752ccfbee7ce690ea88087d2b
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src index cea6ec1..17cf818 160000 --- a/third_party/vulkan-validation-layers/src +++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@ -Subproject commit cea6ec1cdd37494c1f0fc5619c6c356ac33372fb +Subproject commit 17cf8188d8b49bafb6c2f8ecede238f8d2dec5bf
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src index e5e17d8..8b48ab0 160000 --- a/third_party/webgpu-cts/src +++ b/third_party/webgpu-cts/src
@@ -1 +1 @@ -Subproject commit e5e17d8bb639438e1c99cbf367928a242c3bdef6 +Subproject commit 8b48ab0e88b1c6716598ffa1218783acb0691771
diff --git a/third_party/webrtc b/third_party/webrtc index d69d080..8ae8263 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit d69d0808c37b4ea338e59a58837ef180023316a6 +Subproject commit 8ae8263ecc04b6fd78886e9906194e71a574f88c
diff --git a/third_party/webxr_test_pages/update_bucket.py b/third_party/webxr_test_pages/update_bucket.py index 53749d1..a9d7ccd 100755 --- a/third_party/webxr_test_pages/update_bucket.py +++ b/third_party/webxr_test_pages/update_bucket.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2019 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.
diff --git a/third_party/webxr_test_pages/webxr-samples/gamepad.html b/third_party/webxr_test_pages/webxr-samples/gamepad.html index 8d9190d..c2e4600 100644 --- a/third_party/webxr_test_pages/webxr-samples/gamepad.html +++ b/third_party/webxr_test_pages/webxr-samples/gamepad.html
@@ -153,7 +153,7 @@ class GamepadBoxSet { constructor(button_count, y) { this.button_y = y; - ensure_gamepad_boxes(button_count); + this.ensure_gamepad_boxes(button_count); } ensure_gamepad_boxes(button_count) { @@ -170,7 +170,7 @@ } update_state(gamepad) { - ensure_gamepad_boxes(gamepad.buttons.length); + this.ensure_gamepad_boxes(gamepad.buttons.length); // A button press (pressing and then releasing a button) will change // the associated box's color from red to green (or from green to red
diff --git a/third_party/xnnpack/BUILD.gn b/third_party/xnnpack/BUILD.gn index 351b7d25..89cc476 100644 --- a/third_party/xnnpack/BUILD.gn +++ b/third_party/xnnpack/BUILD.gn
@@ -109,6 +109,8 @@ ":f16-vunary_sse2-no-sse3", ":f32-argmaxpool_sse2-no-sse3", ":f32-argmaxpool_x64", + ":f32-avgpool_avx-no-avx2-no-f16c-no-fma", + ":f32-avgpool_avx512f", ":f32-avgpool_sse2-no-sse3", ":f32-avgpool_x64", ":f32-conv-hwc2chw_sse-no-sse2", @@ -200,7 +202,7 @@ ":f32-vbinary_x64", ":f32-vclamp_avx-no-avx2-no-f16c-no-fma", ":f32-vclamp_avx512f", - ":f32-vclamp_sse-no-sse2", + ":f32-vclamp_sse2-no-sse3", ":f32-vclamp_x64", ":f32-vcmul_avx512f", ":f32-vcmul_f16c-fma-no-avx2", @@ -233,7 +235,7 @@ ":f32-vhswish_avx-no-avx2-no-f16c-no-fma", ":f32-vhswish_avx512f", ":f32-vhswish_f16c-fma-no-avx2", - ":f32-vhswish_sse-no-sse2", + ":f32-vhswish_sse2-no-sse3", ":f32-vhswish_x64", ":f32-vlog_avx512f", ":f32-vlog_f16c-fma-avx2", @@ -247,6 +249,9 @@ ":f32-vlrelu_x64", ":f32-vmulcaddc_sse-no-sse2", ":f32-vmulcaddc_x64", + ":f32-vrelu_avx-no-avx2-no-f16c-no-fma", + ":f32-vrelu_avx512f", + ":f32-vrelu_sse2-no-sse3", ":f32-vrelu_x64", ":f32-vrnd_avx-no-avx2-no-f16c-no-fma", ":f32-vrnd_avx512f", @@ -419,6 +424,12 @@ ":qs8-vmulc_sse2-no-sse3", ":qs8-vmulc_sse4.1-no-sse4.2", ":qs8-vmulc_x64", + ":qs8-vprelu_f16c-fma-avx2", + ":qs8-vprelu_x64", + ":qs8-vpreluc_f16c-fma-avx2", + ":qs8-vpreluc_x64", + ":qs8-vrpreluc_f16c-fma-avx2", + ":qs8-vrpreluc_x64", ":qu8-dwconv_avx-no-avx2-no-f16c-no-fma", ":qu8-dwconv_f16c-fma-avx2", ":qu8-dwconv_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl", @@ -480,6 +491,12 @@ ":qu8-vmulc_sse2-no-sse3", ":qu8-vmulc_sse4.1-no-sse4.2", ":qu8-vmulc_x64", + ":qu8-vprelu_f16c-fma-avx2", + ":qu8-vprelu_x64", + ":qu8-vpreluc_f16c-fma-avx2", + ":qu8-vpreluc_x64", + ":qu8-vrpreluc_f16c-fma-avx2", + ":qu8-vrpreluc_x64", ":reference_x64", ":s8-ibilinear_sse2-no-sse3", ":s8-ibilinear_sse4.1-no-sse4.2", @@ -598,6 +615,8 @@ ":f16-vunary_sse2-no-sse3_standalone", ":f32-argmaxpool_sse2-no-sse3_standalone", ":f32-argmaxpool_x64_standalone", + ":f32-avgpool_avx-no-avx2-no-f16c-no-fma_standalone", + ":f32-avgpool_avx512f_standalone", ":f32-avgpool_sse2-no-sse3_standalone", ":f32-avgpool_x64_standalone", ":f32-conv-hwc2chw_sse-no-sse2_standalone", @@ -689,7 +708,7 @@ ":f32-vbinary_x64_standalone", ":f32-vclamp_avx-no-avx2-no-f16c-no-fma_standalone", ":f32-vclamp_avx512f_standalone", - ":f32-vclamp_sse-no-sse2_standalone", + ":f32-vclamp_sse2-no-sse3_standalone", ":f32-vclamp_x64_standalone", ":f32-vcmul_avx512f_standalone", ":f32-vcmul_f16c-fma-no-avx2_standalone", @@ -722,7 +741,7 @@ ":f32-vhswish_avx-no-avx2-no-f16c-no-fma_standalone", ":f32-vhswish_avx512f_standalone", ":f32-vhswish_f16c-fma-no-avx2_standalone", - ":f32-vhswish_sse-no-sse2_standalone", + ":f32-vhswish_sse2-no-sse3_standalone", ":f32-vhswish_x64_standalone", ":f32-vlog_avx512f_standalone", ":f32-vlog_f16c-fma-avx2_standalone", @@ -736,6 +755,9 @@ ":f32-vlrelu_x64_standalone", ":f32-vmulcaddc_sse-no-sse2_standalone", ":f32-vmulcaddc_x64_standalone", + ":f32-vrelu_avx-no-avx2-no-f16c-no-fma_standalone", + ":f32-vrelu_avx512f_standalone", + ":f32-vrelu_sse2-no-sse3_standalone", ":f32-vrelu_x64_standalone", ":f32-vrnd_avx-no-avx2-no-f16c-no-fma_standalone", ":f32-vrnd_avx512f_standalone", @@ -908,6 +930,12 @@ ":qs8-vmulc_sse2-no-sse3_standalone", ":qs8-vmulc_sse4.1-no-sse4.2_standalone", ":qs8-vmulc_x64_standalone", + ":qs8-vprelu_f16c-fma-avx2_standalone", + ":qs8-vprelu_x64_standalone", + ":qs8-vpreluc_f16c-fma-avx2_standalone", + ":qs8-vpreluc_x64_standalone", + ":qs8-vrpreluc_f16c-fma-avx2_standalone", + ":qs8-vrpreluc_x64_standalone", ":qu8-dwconv_avx-no-avx2-no-f16c-no-fma_standalone", ":qu8-dwconv_f16c-fma-avx2_standalone", ":qu8-dwconv_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl_standalone", @@ -969,6 +997,12 @@ ":qu8-vmulc_sse2-no-sse3_standalone", ":qu8-vmulc_sse4.1-no-sse4.2_standalone", ":qu8-vmulc_x64_standalone", + ":qu8-vprelu_f16c-fma-avx2_standalone", + ":qu8-vprelu_x64_standalone", + ":qu8-vpreluc_f16c-fma-avx2_standalone", + ":qu8-vpreluc_x64_standalone", + ":qu8-vrpreluc_f16c-fma-avx2_standalone", + ":qu8-vrpreluc_x64_standalone", ":reference_x64_standalone", ":s8-ibilinear_sse2-no-sse3_standalone", ":s8-ibilinear_sse4.1-no-sse4.2_standalone", @@ -1133,6 +1167,9 @@ ":f32-vtanh_arm64", ":f32-vunary_arm64", ":operators_arm64", + ":pf16-gemm_arch=armv8.2-a+sve+sve2", + ":pf32-gemm_arch=armv8.2-a+sve+sve2", + ":pqs8-qc8w-gemm_arch=armv8.2-a+sve+sve2", ":qd8-f16-qb4w-gemm_arch=armv8.2-a+dotprod+fp16", ":qd8-f16-qb4w-gemm_arch=armv8.2-a+fp16", ":qd8-f16-qb4w-gemm_arch=armv8.2-a+i8mm+fp16", @@ -1165,6 +1202,7 @@ ":qp8-f32-qb4w-gemm_arch=armv8.2-a+i8mm+fp16", ":qp8-f32-qc4w-gemm_arch=armv8.2-a+dotprod", ":qp8-f32-qc4w-gemm_arch=armv8.2-a+i8mm+fp16", + ":qp8-f32-qc4w-gemm_arch=armv8.2-a+sve+sve2", ":qp8-f32-qc8w-gemm_arch=armv8.2-a+dotprod", ":qp8-f32-qc8w-gemm_arch=armv8.2-a+i8mm+fp16", ":qs8-dwconv_arm64", @@ -1192,6 +1230,9 @@ ":qs8-vlrelu_arm64", ":qs8-vmul_arm64", ":qs8-vmulc_arm64", + ":qs8-vprelu_arm64", + ":qs8-vpreluc_arm64", + ":qs8-vrpreluc_arm64", ":qu8-dwconv_arm64", ":qu8-f32-vcvt_arm64", ":qu8-gemm_arch=armv8.2-a+fp16+dotprod", @@ -1206,6 +1247,9 @@ ":qu8-vlrelu_arm64", ":qu8-vmul_arm64", ":qu8-vmulc_arm64", + ":qu8-vprelu_arm64", + ":qu8-vpreluc_arm64", + ":qu8-vrpreluc_arm64", ":reference_arm64", ":s8-ibilinear_arm64", ":s8-maxpool_arm64", @@ -1220,15 +1264,18 @@ ":u8-rdminmax_arm64", ":u8-rminmax_arm64", ":u8-vclamp_arm64", + ":x16-pack-lh_arch=armv8.2-a+sve+sve2", ":x16-packw_arm64", ":x16-transposec_arm64", ":x16-x32-packw_arm64", ":x24-transposec_arm64", + ":x32-pack-lh_arch=armv8.2-a+sve+sve2", ":x32-packw_arm64", ":x32-transposec_arm64", ":x32-unpool_arm64", ":x64-transposec_arm64", ":x8-lut_arm64", + ":x8-pack-lh_arch=armv8.2-a+sve+sve2", ":x8-packq_arm64", ":x8-packw_arm64", ":x8-transposec_arm64", @@ -1334,6 +1381,9 @@ ":f32-vtanh_arm64_standalone", ":f32-vunary_arm64_standalone", ":operators_arm64_standalone", + ":pf16-gemm_arch=armv8.2-a+sve+sve2_standalone", + ":pf32-gemm_arch=armv8.2-a+sve+sve2_standalone", + ":pqs8-qc8w-gemm_arch=armv8.2-a+sve+sve2_standalone", ":qd8-f16-qb4w-gemm_arch=armv8.2-a+dotprod+fp16_standalone", ":qd8-f16-qb4w-gemm_arch=armv8.2-a+fp16_standalone", ":qd8-f16-qb4w-gemm_arch=armv8.2-a+i8mm+fp16_standalone", @@ -1366,6 +1416,7 @@ ":qp8-f32-qb4w-gemm_arch=armv8.2-a+i8mm+fp16_standalone", ":qp8-f32-qc4w-gemm_arch=armv8.2-a+dotprod_standalone", ":qp8-f32-qc4w-gemm_arch=armv8.2-a+i8mm+fp16_standalone", + ":qp8-f32-qc4w-gemm_arch=armv8.2-a+sve+sve2_standalone", ":qp8-f32-qc8w-gemm_arch=armv8.2-a+dotprod_standalone", ":qp8-f32-qc8w-gemm_arch=armv8.2-a+i8mm+fp16_standalone", ":qs8-dwconv_arm64_standalone", @@ -1393,6 +1444,9 @@ ":qs8-vlrelu_arm64_standalone", ":qs8-vmul_arm64_standalone", ":qs8-vmulc_arm64_standalone", + ":qs8-vprelu_arm64_standalone", + ":qs8-vpreluc_arm64_standalone", + ":qs8-vrpreluc_arm64_standalone", ":qu8-dwconv_arm64_standalone", ":qu8-f32-vcvt_arm64_standalone", ":qu8-gemm_arch=armv8.2-a+fp16+dotprod_standalone", @@ -1407,6 +1461,9 @@ ":qu8-vlrelu_arm64_standalone", ":qu8-vmul_arm64_standalone", ":qu8-vmulc_arm64_standalone", + ":qu8-vprelu_arm64_standalone", + ":qu8-vpreluc_arm64_standalone", + ":qu8-vrpreluc_arm64_standalone", ":reference_arm64_standalone", ":s8-ibilinear_arm64_standalone", ":s8-maxpool_arm64_standalone", @@ -1421,15 +1478,18 @@ ":u8-rdminmax_arm64_standalone", ":u8-rminmax_arm64_standalone", ":u8-vclamp_arm64_standalone", + ":x16-pack-lh_arch=armv8.2-a+sve+sve2_standalone", ":x16-packw_arm64_standalone", ":x16-transposec_arm64_standalone", ":x16-x32-packw_arm64_standalone", ":x24-transposec_arm64_standalone", + ":x32-pack-lh_arch=armv8.2-a+sve+sve2_standalone", ":x32-packw_arm64_standalone", ":x32-transposec_arm64_standalone", ":x32-unpool_arm64_standalone", ":x64-transposec_arm64_standalone", ":x8-lut_arm64_standalone", + ":x8-pack-lh_arch=armv8.2-a+sve+sve2_standalone", ":x8-packq_arm64_standalone", ":x8-packw_arm64_standalone", ":x8-transposec_arm64_standalone", @@ -2403,7 +2463,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f16-f32acc-rsum/gen/f16-f32acc-rsum-avx512skx-u64-acc4.c", + "src/src/f16-f32acc-rsum/gen/f16-f32acc-rsum-avx512skx-u32-acc2.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -2435,7 +2495,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f16-f32acc-rsum/gen/f16-f32acc-rsum-avx512skx-u64-acc4.c", + "src/src/f16-f32acc-rsum/gen/f16-f32acc-rsum-avx512skx-u32-acc2.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -4444,6 +4504,114 @@ } } + source_set("f32-avgpool_avx-no-avx2-no-f16c-no-fma") { + cflags = [ + "-mavx", + "-mno-avx2", + "-mno-f16c", + "-mno-fma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/f32-avgpool/gen/f32-avgpool-9p-minmax-avx-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("f32-avgpool_avx-no-avx2-no-f16c-no-fma_standalone") { + cflags = [ + "-mavx", + "-mno-avx2", + "-mno-f16c", + "-mno-fma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/f32-avgpool/gen/f32-avgpool-9p-minmax-avx-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("f32-avgpool_avx512f") { + cflags = [ "-mavx512f" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/f32-avgpool/gen/f32-avgpool-9p-minmax-avx512f-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("f32-avgpool_avx512f_standalone") { + cflags = [ "-mavx512f" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/f32-avgpool/gen/f32-avgpool-9p-minmax-avx512f-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + source_set("f32-avgpool_sse2-no-sse3") { cflags = [ "-mno-sse3", @@ -8719,7 +8887,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-rsum/gen/f32-rsum-avx512f-u64-acc4.c", + "src/src/f32-rsum/gen/f32-rsum-avx512f-u32-acc2.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -8742,7 +8910,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-rsum/gen/f32-rsum-avx512f-u64-acc4.c", + "src/src/f32-rsum/gen/f32-rsum-avx512f-u32-acc2.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -9039,7 +9207,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vapproxgelu/gen/f32-vapproxgelu-avx512f-rational-12-10-nr.c", + "src/src/f32-vapproxgelu/gen/f32-vapproxgelu-avx512f-rational-12-10-div.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -9062,7 +9230,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vapproxgelu/gen/f32-vapproxgelu-avx512f-rational-12-10-nr.c", + "src/src/f32-vapproxgelu/gen/f32-vapproxgelu-avx512f-rational-12-10-div.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -9663,7 +9831,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vclamp/gen/f32-vclamp-avx-u16.c", + "src/src/f32-vclamp/gen/f32-vclamp-avx.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -9691,7 +9859,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vclamp/gen/f32-vclamp-avx-u16.c", + "src/src/f32-vclamp/gen/f32-vclamp-avx.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -9717,7 +9885,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vclamp/gen/f32-vclamp-avx512f-u16.c", + "src/src/f32-vclamp/gen/f32-vclamp-avx512f.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -9740,7 +9908,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vclamp/gen/f32-vclamp-avx512f-u16.c", + "src/src/f32-vclamp/gen/f32-vclamp-avx512f.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -9761,15 +9929,15 @@ } } - source_set("f32-vclamp_sse-no-sse2") { + source_set("f32-vclamp_sse2-no-sse3") { cflags = [ - "-mno-sse2", - "-msse", + "-mno-sse3", + "-msse2", ] sources = [ "src/include/xnnpack.h", - "src/src/f32-vclamp/gen/f32-vclamp-sse-u8.c", + "src/src/f32-vclamp/gen/f32-vclamp-sse2.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -9787,15 +9955,15 @@ } # This is a target that cannot depend on //base. - source_set("f32-vclamp_sse-no-sse2_standalone") { + source_set("f32-vclamp_sse2-no-sse3_standalone") { cflags = [ - "-mno-sse2", - "-msse", + "-mno-sse3", + "-msse2", ] sources = [ "src/include/xnnpack.h", - "src/src/f32-vclamp/gen/f32-vclamp-sse-u8.c", + "src/src/f32-vclamp/gen/f32-vclamp-sse2.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -9821,7 +9989,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vclamp/gen/f32-vclamp-scalar-u4.c", + "src/src/f32-vclamp/gen/f32-vclamp-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -9844,7 +10012,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vclamp/gen/f32-vclamp-scalar-u4.c", + "src/src/f32-vclamp/gen/f32-vclamp-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -10367,7 +10535,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vcos/gen/f32-vcos-avx512f-rational-5-4-nr.c", + "src/src/f32-vcos/gen/f32-vcos-avx512f-rational-5-4-div.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -10390,7 +10558,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vcos/gen/f32-vcos-avx512f-rational-5-4-nr.c", + "src/src/f32-vcos/gen/f32-vcos-avx512f-rational-5-4-div.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11176,7 +11344,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vgelu/gen/f32-vgelu-avx512f-rational-12-10-nr.c", + "src/src/f32-vgelu/gen/f32-vgelu-avx512f-rational-12-10-div.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11199,7 +11367,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vgelu/gen/f32-vgelu-avx512f-rational-12-10-nr.c", + "src/src/f32-vgelu/gen/f32-vgelu-avx512f-rational-12-10-div.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11391,7 +11559,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-avx-u16.c", + "src/src/f32-vhswish/gen/f32-vhswish-avx.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11419,7 +11587,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-avx-u16.c", + "src/src/f32-vhswish/gen/f32-vhswish-avx.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11445,7 +11613,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-avx512f-u16.c", + "src/src/f32-vhswish/gen/f32-vhswish-avx512f.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11468,7 +11636,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-avx512f-u16.c", + "src/src/f32-vhswish/gen/f32-vhswish-avx512f.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11498,7 +11666,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-fma3-u16.c", + "src/src/f32-vhswish/gen/f32-vhswish-fma3.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11525,7 +11693,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-fma3-u16.c", + "src/src/f32-vhswish/gen/f32-vhswish-fma3.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11546,15 +11714,15 @@ } } - source_set("f32-vhswish_sse-no-sse2") { + source_set("f32-vhswish_sse2-no-sse3") { cflags = [ - "-mno-sse2", - "-msse", + "-mno-sse3", + "-msse2", ] sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-sse-u8.c", + "src/src/f32-vhswish/gen/f32-vhswish-sse2.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11572,15 +11740,15 @@ } # This is a target that cannot depend on //base. - source_set("f32-vhswish_sse-no-sse2_standalone") { + source_set("f32-vhswish_sse2-no-sse3_standalone") { cflags = [ - "-mno-sse2", - "-msse", + "-mno-sse3", + "-msse2", ] sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-sse-u8.c", + "src/src/f32-vhswish/gen/f32-vhswish-sse2.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11606,7 +11774,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-scalar-u4.c", + "src/src/f32-vhswish/gen/f32-vhswish-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -11629,7 +11797,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-scalar-u4.c", + "src/src/f32-vhswish/gen/f32-vhswish-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -12288,12 +12456,175 @@ } } + source_set("f32-vrelu_avx-no-avx2-no-f16c-no-fma") { + cflags = [ + "-mavx", + "-mno-avx2", + "-mno-f16c", + "-mno-fma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/f32-vrelu/gen/f32-vrelu-avx.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("f32-vrelu_avx-no-avx2-no-f16c-no-fma_standalone") { + cflags = [ + "-mavx", + "-mno-avx2", + "-mno-f16c", + "-mno-fma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/f32-vrelu/gen/f32-vrelu-avx.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("f32-vrelu_avx512f") { + cflags = [ "-mavx512f" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/f32-vrelu/gen/f32-vrelu-avx512f.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("f32-vrelu_avx512f_standalone") { + cflags = [ "-mavx512f" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/f32-vrelu/gen/f32-vrelu-avx512f.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("f32-vrelu_sse2-no-sse3") { + cflags = [ + "-mno-sse3", + "-msse2", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/f32-vrelu/gen/f32-vrelu-sse2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("f32-vrelu_sse2-no-sse3_standalone") { + cflags = [ + "-mno-sse3", + "-msse2", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/f32-vrelu/gen/f32-vrelu-sse2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + source_set("f32-vrelu_x64") { cflags = [] sources = [ "src/include/xnnpack.h", - "src/src/f32-vrelu/gen/f32-vrelu-scalar-u8.c", + "src/src/f32-vrelu/gen/f32-vrelu-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -12316,7 +12647,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vrelu/gen/f32-vrelu-scalar-u8.c", + "src/src/f32-vrelu/gen/f32-vrelu-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -13301,7 +13632,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vsin/gen/f32-vsin-avx512f-rational-5-4-nr.c", + "src/src/f32-vsin/gen/f32-vsin-avx512f-rational-5-4-div.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -13324,7 +13655,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vsin/gen/f32-vsin-avx512f-rational-5-4-nr.c", + "src/src/f32-vsin/gen/f32-vsin-avx512f-rational-5-4-div.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -13839,7 +14170,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vtanh/gen/f32-vtanh-avx512f-rational-9-8-nr.c", + "src/src/f32-vtanh/gen/f32-vtanh-avx512f-rational-9-8-div.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -13862,7 +14193,7 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vtanh/gen/f32-vtanh-avx512f-rational-9-8-nr.c", + "src/src/f32-vtanh/gen/f32-vtanh-avx512f-rational-9-8-div.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -22566,6 +22897,324 @@ } } + source_set("qs8-vprelu_f16c-fma-avx2") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vprelu/gen/qs8-vprelu-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qs8-vprelu_f16c-fma-avx2_standalone") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vprelu/gen/qs8-vprelu-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qs8-vprelu_x64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vprelu/gen/qs8-vprelu-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qs8-vprelu_x64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vprelu/gen/qs8-vprelu-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qs8-vpreluc_f16c-fma-avx2") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vpreluc/gen/qs8-vpreluc-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qs8-vpreluc_f16c-fma-avx2_standalone") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vpreluc/gen/qs8-vpreluc-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qs8-vpreluc_x64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vpreluc/gen/qs8-vpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qs8-vpreluc_x64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vpreluc/gen/qs8-vpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qs8-vrpreluc_f16c-fma-avx2") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vrpreluc/gen/qs8-vrpreluc-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qs8-vrpreluc_f16c-fma-avx2_standalone") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vrpreluc/gen/qs8-vrpreluc-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qs8-vrpreluc_x64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vrpreluc/gen/qs8-vrpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qs8-vrpreluc_x64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vrpreluc/gen/qs8-vrpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + source_set("qu8-dwconv_avx-no-avx2-no-f16c-no-fma") { cflags = [ "-mavx", @@ -26037,6 +26686,324 @@ } } + source_set("qu8-vprelu_f16c-fma-avx2") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vprelu/gen/qu8-vprelu-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qu8-vprelu_f16c-fma-avx2_standalone") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vprelu/gen/qu8-vprelu-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qu8-vprelu_x64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vprelu/gen/qu8-vprelu-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qu8-vprelu_x64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vprelu/gen/qu8-vprelu-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qu8-vpreluc_f16c-fma-avx2") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vpreluc/gen/qu8-vpreluc-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qu8-vpreluc_f16c-fma-avx2_standalone") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vpreluc/gen/qu8-vpreluc-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qu8-vpreluc_x64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vpreluc/gen/qu8-vpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qu8-vpreluc_x64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vpreluc/gen/qu8-vpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qu8-vrpreluc_f16c-fma-avx2") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vrpreluc/gen/qu8-vrpreluc-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qu8-vrpreluc_f16c-fma-avx2_standalone") { + cflags = [ + "-mavx2", + "-mf16c", + "-mfma", + ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vrpreluc/gen/qu8-vrpreluc-avx2-u16.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qu8-vrpreluc_x64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vrpreluc/gen/qu8-vrpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qu8-vrpreluc_x64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vrpreluc/gen/qu8-vrpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + source_set("reference_x64") { cflags = [] @@ -33958,8 +34925,8 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vclamp/gen/f32-vclamp-neon-u16.c", - "src/src/f32-vclamp/gen/f32-vclamp-scalar-u4.c", + "src/src/f32-vclamp/gen/f32-vclamp-neon.c", + "src/src/f32-vclamp/gen/f32-vclamp-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -33982,8 +34949,8 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vclamp/gen/f32-vclamp-neon-u16.c", - "src/src/f32-vclamp/gen/f32-vclamp-scalar-u4.c", + "src/src/f32-vclamp/gen/f32-vclamp-neon.c", + "src/src/f32-vclamp/gen/f32-vclamp-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -34329,8 +35296,8 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-neon-u16.c", - "src/src/f32-vhswish/gen/f32-vhswish-scalar-u4.c", + "src/src/f32-vhswish/gen/f32-vhswish-neon.c", + "src/src/f32-vhswish/gen/f32-vhswish-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -34353,8 +35320,8 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vhswish/gen/f32-vhswish-neon-u16.c", - "src/src/f32-vhswish/gen/f32-vhswish-scalar-u4.c", + "src/src/f32-vhswish/gen/f32-vhswish-neon.c", + "src/src/f32-vhswish/gen/f32-vhswish-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -34535,7 +35502,8 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vrelu/gen/f32-vrelu-scalar-u8.c", + "src/src/f32-vrelu/gen/f32-vrelu-neon.c", + "src/src/f32-vrelu/gen/f32-vrelu-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -34558,7 +35526,8 @@ sources = [ "src/include/xnnpack.h", - "src/src/f32-vrelu/gen/f32-vrelu-scalar-u8.c", + "src/src/f32-vrelu/gen/f32-vrelu-neon.c", + "src/src/f32-vrelu/gen/f32-vrelu-scalar.c", ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -35065,6 +36034,157 @@ } } + source_set("pf16-gemm_arch=armv8.2-a+sve+sve2") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/pf16-gemm/pf16-gemm-32x32-minmax-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("pf16-gemm_arch=armv8.2-a+sve+sve2_standalone") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/pf16-gemm/pf16-gemm-32x32-minmax-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("pf32-gemm_arch=armv8.2-a+sve+sve2") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/pf32-gemm/pf32-gemm-1x32-minmax-neonsme2.c", + "src/src/pf32-gemm/pf32-gemm-32x32-minmax-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("pf32-gemm_arch=armv8.2-a+sve+sve2_standalone") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/pf32-gemm/pf32-gemm-1x32-minmax-neonsme2.c", + "src/src/pf32-gemm/pf32-gemm-32x32-minmax-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("pqs8-qc8w-gemm_arch=armv8.2-a+sve+sve2") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/pqs8-qc8w-gemm/pqs8-qc8w-gemm-1x32c4-minmax-neonsme2.c", + "src/src/pqs8-qc8w-gemm/pqs8-qc8w-gemm-32x32c4-minmax-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("pqs8-qc8w-gemm_arch=armv8.2-a+sve+sve2_standalone") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/pqs8-qc8w-gemm/pqs8-qc8w-gemm-1x32c4-minmax-neonsme2.c", + "src/src/pqs8-qc8w-gemm/pqs8-qc8w-gemm-32x32c4-minmax-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + source_set("qd8-f16-qb4w-gemm_arch=armv8.2-a+dotprod+fp16") { cflags = [ "-march=armv8.2-a+dotprod+fp16" ] @@ -36755,6 +37875,57 @@ } } + source_set("qp8-f32-qc4w-gemm_arch=armv8.2-a+sve+sve2") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qp8-f32-qc4w-gemm/qp8-f32-qc4w-gemm-minmax-1x128c4-neonsme2.c", + "src/src/qp8-f32-qc4w-gemm/qp8-f32-qc4w-gemm-minmax-32x128c4-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qp8-f32-qc4w-gemm_arch=armv8.2-a+sve+sve2_standalone") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qp8-f32-qc4w-gemm/qp8-f32-qc4w-gemm-minmax-1x128c4-neonsme2.c", + "src/src/qp8-f32-qc4w-gemm/qp8-f32-qc4w-gemm-minmax-32x128c4-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + source_set("qp8-f32-qc8w-gemm_arch=armv8.2-a+dotprod") { cflags = [ "-march=armv8.2-a+dotprod" ] @@ -38260,6 +39431,153 @@ } } + source_set("qs8-vprelu_arm64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vprelu/gen/qs8-vprelu-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qs8-vprelu_arm64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vprelu/gen/qs8-vprelu-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qs8-vpreluc_arm64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vpreluc/gen/qs8-vpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qs8-vpreluc_arm64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vpreluc/gen/qs8-vpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qs8-vrpreluc_arm64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vrpreluc/gen/qs8-vrpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qs8-vrpreluc_arm64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qs8-vrpreluc/gen/qs8-vrpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + source_set("qu8-dwconv_arm64") { cflags = [] @@ -39046,6 +40364,153 @@ } } + source_set("qu8-vprelu_arm64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vprelu/gen/qu8-vprelu-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qu8-vprelu_arm64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vprelu/gen/qu8-vprelu-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qu8-vpreluc_arm64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vpreluc/gen/qu8-vpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qu8-vpreluc_arm64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vpreluc/gen/qu8-vpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + + source_set("qu8-vrpreluc_arm64") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vrpreluc/gen/qu8-vrpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("qu8-vrpreluc_arm64_standalone") { + cflags = [] + + sources = [ + "src/include/xnnpack.h", + "src/src/qu8-vrpreluc/gen/qu8-vrpreluc-scalar-u8.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + source_set("reference_arm64") { cflags = [] @@ -39854,6 +41319,55 @@ } } + source_set("x16-pack-lh_arch=armv8.2-a+sve+sve2") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/x16-pack-lh/x16-packlh-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("x16-pack-lh_arch=armv8.2-a+sve+sve2_standalone") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/x16-pack-lh/x16-packlh-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + source_set("x16-packw_arm64") { cflags = [] @@ -40060,6 +41574,55 @@ } } + source_set("x32-pack-lh_arch=armv8.2-a+sve+sve2") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/x32-pack-lh/x32-packlh-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("x32-pack-lh_arch=armv8.2-a+sve+sve2_standalone") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/x32-pack-lh/x32-packlh-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + source_set("x32-packw_arm64") { cflags = [] @@ -40333,6 +41896,55 @@ } } + source_set("x8-pack-lh_arch=armv8.2-a+sve+sve2") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/x8-pack-lh/x8--packlh-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_config" ] + } + + # This is a target that cannot depend on //base. + source_set("x8-pack-lh_arch=armv8.2-a+sve+sve2_standalone") { + cflags = [ "-march=armv8.2-a+sve+sve2" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/x8-pack-lh/x8--packlh-neonsme2.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + source_set("x8-packq_arm64") { cflags = []
diff --git a/third_party/xnnpack/README.chromium b/third_party/xnnpack/README.chromium index 6c543e9..daa3c43 100644 --- a/third_party/xnnpack/README.chromium +++ b/third_party/xnnpack/README.chromium
@@ -1,8 +1,8 @@ Name: XNNPACK Short Name: xnnpack URL: https://github.com/google/xnnpack -Version: 05eec89fee573a08d841fbaf11db0357586fc6ae -Date: 2025-04-28 +Version: 1b2beba83092bed68775b6e2433596627988c74b +Date: 2025-05-07 License: BSD-3-Clause License File: src/LICENSE Security Critical: Yes
diff --git a/third_party/xnnpack/build_identifier.c b/third_party/xnnpack/build_identifier.c index 05fb2b9..58a24d3 100644 --- a/third_party/xnnpack/build_identifier.c +++ b/third_party/xnnpack/build_identifier.c
@@ -34,7 +34,7 @@ // - external/xnnpack+/src/f16-f32acc-igemm/gen/f16-f32acc-igemm-4x16-minmax-avx2-broadcast.c // - external/xnnpack+/src/f16-f32acc-rdsum/gen/f16-f32acc-rdsum-7p7x-avx512skx-c64.c // - external/xnnpack+/src/f16-f32acc-rdsum/gen/f16-f32acc-rdsum-7p7x-f16c-c32.c -// - external/xnnpack+/src/f16-f32acc-rsum/gen/f16-f32acc-rsum-avx512skx-u64-acc4.c +// - external/xnnpack+/src/f16-f32acc-rsum/gen/f16-f32acc-rsum-avx512skx-u32-acc2.c // - external/xnnpack+/src/f16-f32acc-rsum/gen/f16-f32acc-rsum-f16c-u32-acc4.c // - external/xnnpack+/src/f16-ibilinear/gen/f16-ibilinear-fma3-c8.c // - external/xnnpack+/src/f16-maxpool/gen/f16-maxpool-9p-minmax-avx2-u16.c @@ -116,6 +116,8 @@ // - external/xnnpack+/src/f16-vunary/gen/f16-vsqr-f16c-u16.c // - external/xnnpack+/src/f32-argmaxpool/f32-argmaxpool-9p8x-scalar-c1.c // - external/xnnpack+/src/f32-argmaxpool/f32-argmaxpool-9p8x-sse2-c4.c +// - external/xnnpack+/src/f32-avgpool/gen/f32-avgpool-9p-minmax-avx-u8.c +// - external/xnnpack+/src/f32-avgpool/gen/f32-avgpool-9p-minmax-avx512f-u16.c // - external/xnnpack+/src/f32-avgpool/gen/f32-avgpool-9p-minmax-scalar-u1.c // - external/xnnpack+/src/f32-avgpool/gen/f32-avgpool-9p-minmax-sse2-u4.c // - external/xnnpack+/src/f32-conv-hwc2chw/f32-conv-hwc2chw-3x3s2p1c3x4-scalar-1x1.c @@ -304,7 +306,7 @@ // - external/xnnpack+/src/f32-rminmax/gen/f32-rminmax-scalar-u4-acc4.c // - external/xnnpack+/src/f32-rminmax/gen/f32-rminmax-sse-u16-acc4.c // - external/xnnpack+/src/f32-rsum/gen/f32-rsum-avx-u32-acc4.c -// - external/xnnpack+/src/f32-rsum/gen/f32-rsum-avx512f-u64-acc4.c +// - external/xnnpack+/src/f32-rsum/gen/f32-rsum-avx512f-u32-acc2.c // - external/xnnpack+/src/f32-rsum/gen/f32-rsum-scalar-u4-acc4.c // - external/xnnpack+/src/f32-rsum/gen/f32-rsum-sse-u16-acc4.c // - external/xnnpack+/src/f32-spmm/gen/f32-spmm-32x1-minmax-sse.c @@ -312,7 +314,7 @@ // - external/xnnpack+/src/f32-spmm/gen/f32-spmm-8x2-minmax-scalar.c // - external/xnnpack+/src/f32-spmm/gen/f32-spmm-8x4-minmax-scalar.c // - external/xnnpack+/src/f32-vapproxgelu/gen/f32-vapproxgelu-avx-rational-12-10-div.c -// - external/xnnpack+/src/f32-vapproxgelu/gen/f32-vapproxgelu-avx512f-rational-12-10-nr.c +// - external/xnnpack+/src/f32-vapproxgelu/gen/f32-vapproxgelu-avx512f-rational-12-10-div.c // - external/xnnpack+/src/f32-vapproxgelu/gen/f32-vapproxgelu-fma3-rational-12-10-div.c // - external/xnnpack+/src/f32-vapproxgelu/gen/f32-vapproxgelu-scalar-rational-12-10-div.c // - external/xnnpack+/src/f32-vapproxgelu/gen/f32-vapproxgelu-sse2-rational-12-10-div.c @@ -392,10 +394,10 @@ // - external/xnnpack+/src/f32-vbinary/gen/f32-vsubc-avx512f-u32.c // - external/xnnpack+/src/f32-vbinary/gen/f32-vsubc-scalar-u8.c // - external/xnnpack+/src/f32-vbinary/gen/f32-vsubc-sse-u8.c -// - external/xnnpack+/src/f32-vclamp/gen/f32-vclamp-avx-u16.c -// - external/xnnpack+/src/f32-vclamp/gen/f32-vclamp-avx512f-u16.c -// - external/xnnpack+/src/f32-vclamp/gen/f32-vclamp-scalar-u4.c -// - external/xnnpack+/src/f32-vclamp/gen/f32-vclamp-sse-u8.c +// - external/xnnpack+/src/f32-vclamp/gen/f32-vclamp-avx.c +// - external/xnnpack+/src/f32-vclamp/gen/f32-vclamp-avx512f.c +// - external/xnnpack+/src/f32-vclamp/gen/f32-vclamp-scalar.c +// - external/xnnpack+/src/f32-vclamp/gen/f32-vclamp-sse2.c // - external/xnnpack+/src/f32-vcmul/gen/f32-vcmul-avx512f-u32.c // - external/xnnpack+/src/f32-vcmul/gen/f32-vcmul-fma3-u16.c // - external/xnnpack+/src/f32-vcmul/gen/f32-vcmul-scalar-u4.c @@ -413,7 +415,7 @@ // - external/xnnpack+/src/f32-vcopysign/gen/f32-vrcopysignc-scalar.c // - external/xnnpack+/src/f32-vcopysign/gen/f32-vrcopysignc-sse2.c // - external/xnnpack+/src/f32-vcos/gen/f32-vcos-avx-rational-5-4-div.c -// - external/xnnpack+/src/f32-vcos/gen/f32-vcos-avx512f-rational-5-4-nr.c +// - external/xnnpack+/src/f32-vcos/gen/f32-vcos-avx512f-rational-5-4-div.c // - external/xnnpack+/src/f32-vcos/gen/f32-vcos-fma3-rational-5-4-div.c // - external/xnnpack+/src/f32-vcos/gen/f32-vcos-scalar-rational-5-4-div.c // - external/xnnpack+/src/f32-vcos/gen/f32-vcos-sse2-rational-5-4-div.c @@ -429,15 +431,15 @@ // - external/xnnpack+/src/f32-vexp/gen/f32-vexp-scalar-rational-3-2-div.c // - external/xnnpack+/src/f32-vexp/gen/f32-vexp-sse2-rational-3-2-div.c // - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-avx-rational-12-10-div.c -// - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-avx512f-rational-12-10-nr.c +// - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-avx512f-rational-12-10-div.c // - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-fma3-rational-12-10-div.c // - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-scalar-rational-12-10-div.c // - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-sse2-rational-12-10-div.c -// - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-avx-u16.c -// - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-avx512f-u16.c -// - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-fma3-u16.c -// - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-scalar-u4.c -// - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-sse-u8.c +// - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-avx.c +// - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-avx512f.c +// - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-fma3.c +// - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-scalar.c +// - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-sse2.c // - external/xnnpack+/src/f32-vlog/gen/f32-vlog-avx2-rational-3-3-div.c // - external/xnnpack+/src/f32-vlog/gen/f32-vlog-avx512f-rational-3-3-div.c // - external/xnnpack+/src/f32-vlog/gen/f32-vlog-fma3-rational-3-3-div.c @@ -450,7 +452,10 @@ // - external/xnnpack+/src/f32-vlrelu/gen/f32-vlrelu-sse41-u8.c // - external/xnnpack+/src/f32-vmulcaddc/gen/f32-vmulcaddc-c1-minmax-scalar-2x.c // - external/xnnpack+/src/f32-vmulcaddc/gen/f32-vmulcaddc-c4-minmax-sse-2x.c -// - external/xnnpack+/src/f32-vrelu/gen/f32-vrelu-scalar-u8.c +// - external/xnnpack+/src/f32-vrelu/gen/f32-vrelu-avx.c +// - external/xnnpack+/src/f32-vrelu/gen/f32-vrelu-avx512f.c +// - external/xnnpack+/src/f32-vrelu/gen/f32-vrelu-scalar.c +// - external/xnnpack+/src/f32-vrelu/gen/f32-vrelu-sse2.c // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndd-avx-u16.c // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndd-avx512f-u16.c // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndd-scalar-libm-u1.c @@ -488,7 +493,7 @@ // - external/xnnpack+/src/f32-vsigmoid/gen/f32-vsigmoid-sse2-rr2-lut64-p2-div-u8.c // - external/xnnpack+/src/f32-vsigmoid/gen/f32-vsigmoid-sse41-rr2-lut64-p2-div-u8.c // - external/xnnpack+/src/f32-vsin/gen/f32-vsin-avx-rational-5-4-div.c -// - external/xnnpack+/src/f32-vsin/gen/f32-vsin-avx512f-rational-5-4-nr.c +// - external/xnnpack+/src/f32-vsin/gen/f32-vsin-avx512f-rational-5-4-div.c // - external/xnnpack+/src/f32-vsin/gen/f32-vsin-fma3-rational-5-4-div.c // - external/xnnpack+/src/f32-vsin/gen/f32-vsin-scalar-rational-5-4-div.c // - external/xnnpack+/src/f32-vsin/gen/f32-vsin-sse2-rational-5-4-div.c @@ -498,7 +503,7 @@ // - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt-u1.c // - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-sse-rsqrt-u12.c // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-avx-rational-9-8-div.c -// - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-avx512f-rational-9-8-nr.c +// - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-avx512f-rational-9-8-div.c // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-fma3-rational-9-8-div.c // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-scalar-rational-9-8-div.c // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-sse2-rational-9-8-div.c @@ -778,6 +783,12 @@ // - external/xnnpack+/src/qs8-vmulc/gen/qs8-vmulc-minmax-fp32-scalar-u4.c // - external/xnnpack+/src/qs8-vmulc/gen/qs8-vmulc-minmax-fp32-sse2-mul16-ld64-u8.c // - external/xnnpack+/src/qs8-vmulc/gen/qs8-vmulc-minmax-fp32-sse41-mul16-ld64-u16.c +// - external/xnnpack+/src/qs8-vprelu/gen/qs8-vprelu-avx2-u16.c +// - external/xnnpack+/src/qs8-vprelu/gen/qs8-vprelu-scalar-u8.c +// - external/xnnpack+/src/qs8-vpreluc/gen/qs8-vpreluc-avx2-u16.c +// - external/xnnpack+/src/qs8-vpreluc/gen/qs8-vpreluc-scalar-u8.c +// - external/xnnpack+/src/qs8-vrpreluc/gen/qs8-vrpreluc-avx2-u16.c +// - external/xnnpack+/src/qs8-vrpreluc/gen/qs8-vrpreluc-scalar-u8.c // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-25p16c-minmax-fp32-avx-mul16.c // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-25p16c-minmax-fp32-avx2-mul32.c // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-25p1c-minmax-fp32-scalar-fmagic.c @@ -870,6 +881,12 @@ // - external/xnnpack+/src/qu8-vmulc/gen/qu8-vmulc-minmax-fp32-scalar-u4.c // - external/xnnpack+/src/qu8-vmulc/gen/qu8-vmulc-minmax-fp32-sse2-mul16-ld64-u8.c // - external/xnnpack+/src/qu8-vmulc/gen/qu8-vmulc-minmax-fp32-sse41-mul16-ld64-u16.c +// - external/xnnpack+/src/qu8-vprelu/gen/qu8-vprelu-avx2-u16.c +// - external/xnnpack+/src/qu8-vprelu/gen/qu8-vprelu-scalar-u8.c +// - external/xnnpack+/src/qu8-vpreluc/gen/qu8-vpreluc-avx2-u16.c +// - external/xnnpack+/src/qu8-vpreluc/gen/qu8-vpreluc-scalar-u8.c +// - external/xnnpack+/src/qu8-vrpreluc/gen/qu8-vrpreluc-avx2-u16.c +// - external/xnnpack+/src/qu8-vrpreluc/gen/qu8-vrpreluc-scalar-u8.c // - external/xnnpack+/src/reference/packing.cc // - external/xnnpack+/src/s8-ibilinear/gen/s8-ibilinear-scalar-c1.c // - external/xnnpack+/src/s8-ibilinear/gen/s8-ibilinear-sse2-c8.c @@ -980,10 +997,10 @@ #include <string.h> static const uint8_t xnn_build_identifier[] = { - 130, 58, 183, 43, 114, 118, 244, 22, - 152, 70, 241, 236, 226, 135, 69, 64, - 197, 128, 0, 148, 83, 67, 102, 82, - 19, 124, 87, 75, 153, 251, 85, 233 + 111, 182, 175, 28, 10, 59, 117, 199, + 161, 4, 44, 68, 47, 182, 3, 207, + 101, 198, 29, 180, 128, 137, 252, 57, + 60, 17, 99, 112, 242, 192, 175, 208 }; size_t xnn_experimental_get_build_identifier_size() {
diff --git a/third_party/xnnpack/src b/third_party/xnnpack/src index 05eec89..1b2beba 160000 --- a/third_party/xnnpack/src +++ b/third_party/xnnpack/src
@@ -1 +1 @@ -Subproject commit 05eec89fee573a08d841fbaf11db0357586fc6ae +Subproject commit 1b2beba83092bed68775b6e2433596627988c74b
diff --git a/tools/android/nullaway/null_mark.py b/tools/android/nullaway/null_mark.py index a998c2e..0b677e2a 100755 --- a/tools/android/nullaway/null_mark.py +++ b/tools/android/nullaway/null_mark.py
@@ -9,7 +9,7 @@ import re import subprocess -_SRC_ROOT = (pathlib.Path(__file__).parents[3]) +_SRC_ROOT = pathlib.Path(__file__).parents[3] _GOOGLE_JAVA_FORMAT = (_SRC_ROOT / 'third_party' / 'google-java-format' / 'google-java-format')
diff --git a/tools/android/nullaway/run_annotator_on_chrome_java.py b/tools/android/nullaway/run_annotator_on_chrome_java.py new file mode 100755 index 0000000..ee7e4e1 --- /dev/null +++ b/tools/android/nullaway/run_annotator_on_chrome_java.py
@@ -0,0 +1,199 @@ +#!/usr/bin/env python3 +# 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. + +import argparse +import logging +import os +import pathlib +import re +import shlex +import shutil +import subprocess +import sys + +_SRC_ROOT = pathlib.Path(__file__).parents[3] +sys.path.insert(1, str(_SRC_ROOT / 'build/android/gyp')) + +from util import build_utils +import action_helpers + +_ANNOTATOR_JAR = ('../NullAwayAnnotator/annotator-core/build/libs/' + 'annotator-core-1.3.16-SNAPSHOT.jar') +_CHROME_JAVA_TURBINE_JAR = 'obj/chrome/android/chrome_java.turbine.jar' + + +def _read_file(path): + return pathlib.Path(path).read_text() + + +def _write_file(path, data): + return pathlib.Path(path).write_text(data) + + +def _find_unmarked(java_files): + ret = set() + for path in java_files: + data = _read_file(path) + if '@NullUnmarked' in data or '@SuppressWarnings("NullAway' in data: + ret.add(path) + return sorted(ret) + + +def _read_build_config_value(path, key): + value = build_utils.ExpandFileArgs([f'@FileArg({path}:{key})'])[0] + return action_helpers.parse_gn_list(value) + + +def main(): + logging.basicConfig(format='%(message)s', level=logging.INFO) + parser = argparse.ArgumentParser() + parser.add_argument('--loud', + action='store_true', + help='Print compiler while annotating output') + args = parser.parse_args() + + if not os.path.exists('args.gn'): + parser.error('Must be run from within output directory.') + if not os.path.exists(_ANNOTATOR_JAR): + parser.error('Annotator .jar not found. Follow steps to build it.') + if not os.path.exists(_CHROME_JAVA_TURBINE_JAR): + parser.error('Run "autoninja chrome/android:chrome_java" first.') + + # Compile only files that are @NullMarked (to speed things up). + java_files = _read_file( + 'gen/chrome/android/chrome_java.sources').splitlines() + java_files = [p for p in java_files if '@NullMarked' in _read_file(p)] + sources_path = 'null-away-chrome-java-sources.txt' + _write_file(sources_path, '\n'.join(java_files)) + logging.info( + 'Running annotator over %d @NullMarked files within chrome_java', + len(java_files)) + logging.info('This will probably take 3-5 minutes 🐢🐢🐢') + + classpath = [ + 'obj/third_party/android_sdk/android_sdk_java.ijar.jar', + _CHROME_JAVA_TURBINE_JAR, + ] + classpath += _read_build_config_value( + 'gen/chrome/android/chrome_java.build_config.json', + 'javac_full_interface_classpath') + + processor_path = _read_build_config_value( + 'gen/tools/android/errorprone_plugin/errorprone_plugin.build_config.json', + 'classpath') + processor_path.append(_ANNOTATOR_JAR) + + contract_annotations = [ + 'org.chromium.build.annotations.Contract', + 'org.chromium.support_lib_boundary.util.Contract', + ] + init_methods = [ + 'android.app.Application.onCreate', + 'android.app.Activity.onCreate', + 'android.app.Service.onCreate', + 'android.app.backup.BackupAgent.onCreate', + 'android.content.ContentProvider.attachInfo', + 'android.content.ContentProvider.onCreate', + 'android.content.ContextWrapper.attachBaseContext', + 'androidx.preference.PreferenceFragmentCompat.onCreatePreferences', + ] + errorprone_args = [ + '-Xplugin:ErrorProne', + '-XepDisableAllChecks', + '-Xep:NullAway:ERROR', + '-Xep:AnnotatorScanner:ERROR', + '-XepOpt:NullAway:OnlyNullMarked', + '-XepOpt:NullAway:CustomContractAnnotations=' + + ','.join(contract_annotations), + '-XepOpt:NullAway:CastToNonNullMethod=org.chromium.build.NullUtil.assumeNonNull', + '-XepOpt:NullAway:AssertsEnabled=true', + '-XepOpt:NullAway:AcknowledgeRestrictiveAnnotations=true', + '-XepOpt:Nullaway:AcknowledgeAndroidRecent=true', + '-XepOpt:NullAway:JSpecifyMode=true', + '-XepOpt:NullAway:KnownInitializers=' + ','.join(init_methods), + '-XepOpt:AnnotatorScanner:ConfigPath=../nullaway_scanner.xml', + '-XepOpt:NullAway:SerializeFixMetadata=true', + '-XepOpt:NullAway:FixSerializationConfigPath=../nullaway_config.xml', + ] + javac_cmd = [ + '../../third_party/jdk/current/bin/javac', '-g', '-parameters', + '--release', '17', '-encoding', 'UTF-8', '-sourcepath', ':', + '-Xlint:-dep-ann', '-Xlint:-removal', '-J-XX:+PerfDisableSharedMem', + '-Xmaxerrs', '100000', '-Xmaxwarns', '100000', + '-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED', + '-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', + '-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', + '-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED', + '-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED', + '-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED', + '-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', + '-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', + '-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', + '-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', + ' '.join(errorprone_args), '-XDcompilePolicy=simple', + '-XDshould-stop.ifError=FLOW', '-XDshould-stop.ifNoError=FLOW', + '-processorpath', ':'.join(processor_path), '-d', + 'nullaway-annotator-output', '-classpath', ':'.join(classpath), + f'@{sources_path}' + ] + + outdir = os.path.abspath('annotator-out') + if os.path.exists(outdir): + shutil.rmtree(outdir) + + compile_script = f'nullaway-annotator-compile.sh' + compile_logs = f'nullaway-annotator-compile.log' + if os.path.exists(compile_logs): + os.unlink(compile_logs) + + _write_file( + compile_script, f"""\ +#!/bin/bash +set -e +echo -e "\n\n============= START OF COMPILE =============" >> {compile_logs} +{shlex.join(javac_cmd)} 2>&1 | tee -a {compile_logs} +""") + os.chmod(compile_script, 0o744) + + cmd = build_utils.JavaCmd() + [ + '-jar', _ANNOTATOR_JAR, '-bc', f'./{compile_script}', '-n', + 'org.chromium.build.annotations.Nullable', '-d', outdir, '-cp', + '../nullaway_config.tsv', '-cn', 'NULLAWAY', '-sre', + 'org.chromium.build.annotations.NullUnmarked', '-i', + 'org.chromium.build.annotations.Initializer' + ] + if args.loud: + cmd += ['--redirect-build-output-stderr'] + + result = subprocess.run(cmd).returncode + logging.warning('🪵 Error Prone output (find warnings here):\n%s', + os.path.abspath(compile_logs)) + + if result: + print('😰 Command failed.') + sys.exit(result) + + unmarked_files = _find_unmarked(java_files) + + if unmarked_files: + for path in unmarked_files: + data = _read_file(path) + # Leave a whitespace change as a hint it was nullunmarked. + data = data.replace('@NullUnmarked ', '\t') + data = data.replace('@SuppressWarnings("NullAway.Init")', '\t') + _write_file(path, data) + + print(""" +The following files have unresolved warnings, which have been marked by \\t \ +characters. + +Files:""") + print('\n'.join(unmarked_files)) + else: + print('No suppressions remained after auto-annotating.') + + +if __name__ == '__main__': + main()
diff --git a/tools/crates/gnrt/lib/condition.rs b/tools/crates/gnrt/lib/condition.rs index e0fae30..5a417711 100644 --- a/tools/crates/gnrt/lib/condition.rs +++ b/tools/crates/gnrt/lib/condition.rs
@@ -14,99 +14,91 @@ /// Representation of a `Condition` associated with a conditional/optional /// dependency. #[derive(Clone, Debug, Eq, PartialEq)] -pub enum Condition { - /// The condition is always false. In other words, supported Chromium - /// builds never meet this condition. - /// - /// Example: `#[cfg(target_arch = "powerpc")]`. - AlwaysFalse, - /// The condition is always true. - /// - /// Example: `#[cfg(not(target_arch = "powerpc"))]`. - AlwaysTrue, - /// The conditional dependency applies to a subset of target triples - /// - /// For example `#[cfg(target_os = "windows")]` translates into - /// `Condition::TripleSet(...)`. - TripleSet(HashSet<RustTargetTriple>), - /// Some of the [conditional - /// compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) directives - /// weren't recognized by `gnrt`. - /// - /// The `String` is an error message. - /// - /// In some cases such terms will "disappear" - e.g. `unknown_cfg && - /// always_false` is the same as `always_false`. When these terms do - /// not disappear, then it may mean that supporting a new crate would - /// require teaching `gnrt` about the new kinds of configuration. - Unsupported(String), -} +pub struct Condition(Result<HashSet<RustTargetTriple>, String>); impl Condition { pub fn is_always_false(&self) -> bool { - *self == Condition::AlwaysFalse + self.0.as_ref().is_ok_and(|triple_set| triple_set.is_empty()) + } + + /// Creates a `Condition` that is never met - target platforms supported in + /// Chromium builds never meet this condition. For example + /// `#[cfg(target_arch = "powerpc")]` is effectively equivalent to + /// `Condition::always_false()`. + pub fn always_false() -> Self { + Condition(Ok(HashSet::new())) + } + + fn is_always_true(&self) -> bool { + self.0.as_ref().is_ok_and(|triple_set| *triple_set == *RustTargetTriple::all()) + } + + /// Creates a `Condition` that is always true - *all* target platforms + /// supported in Chromium builds meet this condition. For example + /// `#[cfg(not(target_arch = "powerpc"))]` is effectively equivalent to + /// `Condition::always_true()`. + pub fn always_true() -> Self { + Condition(Ok(RustTargetTriple::all().clone())) } fn from_triple(triple: RustTargetTriple) -> Self { - Condition::TripleSet([triple].into()) + Self::from_triple_set([triple].into()) } fn from_triple_set(set: HashSet<RustTargetTriple>) -> Self { - if set.is_empty() { - Condition::AlwaysFalse - } else if set == *RustTargetTriple::all() { - Condition::AlwaysTrue - } else { - Condition::TripleSet(set) - } + Condition(Ok(set)) } pub fn or(lhs: Condition, rhs: Condition) -> Self { + // First check if one of the operands (potentially an `Err` variant!) + // can be ignored (when the other operand `is_always_true`). + if lhs.is_always_true() { + return lhs; + } + if rhs.is_always_true() { + return rhs; + } match (lhs, rhs) { - (Condition::AlwaysFalse, other) | (other, Condition::AlwaysFalse) => other.clone(), - (Condition::AlwaysTrue, _) | (_, Condition::AlwaysTrue) => Condition::AlwaysTrue, - (err @ Condition::Unsupported(_), _) | (_, err @ Condition::Unsupported(_)) => { - err.clone() - } - (Condition::TripleSet(lhs), Condition::TripleSet(rhs)) => { - Condition::from_triple_set(&lhs | &rhs) - } + (err @ Condition(Err(_)), _) | (_, err @ Condition(Err(_))) => err.clone(), + (Condition(Ok(lhs)), Condition(Ok(rhs))) => Condition::from_triple_set(&lhs | &rhs), } } pub fn and(lhs: Condition, rhs: Condition) -> Self { + // First check if one of the operands (potentially an `Err` variant!) + // can be ignored (when the other operand `is_always_false`). + if lhs.is_always_false() { + return lhs; + } + if rhs.is_always_false() { + return rhs; + } match (lhs, rhs) { - (Condition::AlwaysFalse, _) | (_, Condition::AlwaysFalse) => Condition::AlwaysFalse, - (Condition::AlwaysTrue, other) | (other, Condition::AlwaysTrue) => other, - (err @ Condition::Unsupported(_), _) | (_, err @ Condition::Unsupported(_)) => err, - (Condition::TripleSet(lhs), Condition::TripleSet(rhs)) => { - Condition::from_triple_set(&lhs & &rhs) - } + (err @ Condition(Err(_)), _) | (_, err @ Condition(Err(_))) => err.clone(), + (Condition(Ok(lhs)), Condition(Ok(rhs))) => Condition::from_triple_set(&lhs & &rhs), } } fn not(other: Condition) -> Self { match other { - Condition::AlwaysFalse => Condition::AlwaysTrue, - Condition::AlwaysTrue => Condition::AlwaysFalse, - err @ Condition::Unsupported(_) => err, - Condition::TripleSet(value) => Condition::TripleSet(negate_triple_set(&value)), + err @ Condition(Err(_)) => err, + Condition(Ok(triple_set)) => Condition(Ok(negate_triple_set(&triple_set))), } } pub fn to_handlebars_value(&self) -> Result<Option<String>> { - match self { - Condition::AlwaysTrue => Ok(None), - Condition::TripleSet(set) => Ok(Some(format_as_gn_expr::format(set))), - Condition::AlwaysFalse => unreachable!( - "AlwaysFalse dependencies should be filtered out \ - by `fn collect_dependencies` from `deps.rs`" - ), - Condition::Unsupported(err) => { - Err(anyhow!("{err}") - .context("Failed to translate `#[cfg(...)]` into a GN condition")) + assert!( + !self.is_always_false(), + "'always false' dependencies should be filtered out \ + by `fn collect_dependencies` from `deps.rs`" + ); + self.0.as_ref().map_err(|msg| anyhow!("{msg}")).map(|triple_set| { + if *triple_set == *RustTargetTriple::all() { + None + } else { + Some(format_as_gn_expr::format(triple_set)) } - } + }) } pub fn from_target_spec(spec: &target_spec::TargetSpec) -> Self { @@ -313,7 +305,7 @@ exprs .iter() .map(cfg_expr_to_condition) - .fold(Condition::AlwaysTrue, |accumulated, condition| { + .fold(Condition::always_true(), |accumulated, condition| { Condition::and(accumulated, condition) }) } @@ -324,7 +316,7 @@ exprs .iter() .map(cfg_expr_to_condition) - .fold(Condition::AlwaysFalse, |accumulated, condition| { + .fold(Condition::always_false(), |accumulated, condition| { Condition::or(accumulated, condition) }) } @@ -364,8 +356,8 @@ if let Some(value_to_triple_set_map) = PROP_NAME_TO_PROP_VALUE_TO_TRIPLE_SET.get(key) { match value_to_triple_set_map.get(value) { - None => return Condition::AlwaysFalse, - Some(set) => return Condition::TripleSet(set.clone()), + None => return Condition::always_false(), + Some(set) => return Condition::from_triple_set(set.clone()), } } @@ -376,7 +368,7 @@ // therefore we treat this as `AlwaysFalse`. See also // https://crbug.com/404598090#comment4. log::warn!("Treating unrecogized `#[cfg({key} = \"{value}\")]` as `AlwaysFalse"); - Condition::AlwaysFalse + Condition::always_false() } /// `name` should correspond to https://doc.rust-lang.org/reference/conditional-compilation.html#r-cfg.option-name @@ -390,24 +382,24 @@ // We don't support `windows_raw_dylib` in Chromium. See also // https://github.com/rust-lang/rust/issues/58713 if ["windows_raw_dylib"].contains(&name) { - return Condition::AlwaysFalse; + return Condition::always_false(); } // See https://doc.rust-lang.org/reference/conditional-compilation.html#debug_assertions if name == "debug_assertions" { - // Returning `AlwaysTrue` is not 100% correct and may bring in unnecessary + // Returning "always true" is not 100% correct and may bring in unnecessary // dependencies. But this conservative behavior shouldn't cause any // major issues. // // TODO(https://crbug.com/402096443): Handle this by tracking not only a set of // `RustTargetTriple` but also a parallel set/bitflag of `RustDebugConfig` (with // just two bits - on and off). - return Condition::AlwaysTrue; + return Condition::always_true(); } // See https://doc.rust-lang.org/reference/conditional-compilation.html#test if name == "test" { - // Returning `AlwaysTrue` is not 100% correct and may bring in unnecessary + // Returning "always true" is not 100% correct and may bring in unnecessary // dependencies. But this seems unlikely, given that test-only // dependencies should be listed in the `[dev-dependencies]` section of // `Cargo.toml` and reported as `guppy::DependencyKind::Development`. @@ -415,7 +407,7 @@ // issues. // // TODO(https://crbug.com/402096443): Handle this better. - return Condition::AlwaysTrue; + return Condition::always_true(); } // `name` is not something that is documented in @@ -424,7 +416,7 @@ // And therefore we treat this as `AlwaysFalse`. See also // https://crbug.com/404598090#comment4. log::warn!("Treating unrecogized `#[cfg({name})]` as `AlwaysFalse"); - Condition::AlwaysFalse + Condition::always_false() } /// `value` should correspond to https://doc.rust-lang.org/reference/conditional-compilation.html#r-cfg.panic.values @@ -432,19 +424,21 @@ // `//build/config/compiler/BUILD.gn` always hardcodes `-Cpanic=abort` into // `rustflags`. match value { - "abort" => Condition::AlwaysTrue, - "unwind" => Condition::AlwaysFalse, - _ => Condition::Unsupported(format!( + "abort" => Condition::always_true(), + "unwind" => Condition::always_false(), + _ => Condition(Err(format!( "Unrecognized panic configuration: `#[cfg(panic = \"{value}\")]`" - )), + ))), } } fn triple_to_condition(triple: &str) -> Condition { - match triple.parse() { - Ok(triple) => Condition::from_triple(triple), - Err(_) => Condition::AlwaysFalse, - } + triple.parse().map(Condition::from_triple).unwrap_or_else( + // Triples outside of `//build/rust/known-target-triples.txt` won't parse. + // Such target triples are never used in Chromium builds and therefore we + // represent tham as "always false". + |_err| Condition::always_false(), + ) } #[cfg(test)] @@ -470,7 +464,7 @@ let condition = condition_from_test_expr(expr); match condition.to_handlebars_value() { Ok(Some(s)) => s, - Ok(None) => panic!("Got `AlwaysTrue` / `None` when formatting `{expr}`"), + Ok(None) => panic!("Got 'always true' / `None` when formatting `{expr}`"), Err(err) => panic!("Error when formatting `{expr}`: `{err}`"), } } @@ -605,7 +599,7 @@ // Simplification of one of the real expressions below. "all(target_os = \"linux\", target_env = \"\")", ), - Condition::AlwaysFalse, + Condition::always_false(), ); assert_eq!( gn_condition_from_test_expr( @@ -621,4 +615,21 @@ "(is_linux || is_chromeos) || is_android", ); } + + /// Test that unsupported terms disappear when possible + /// (i.e. that we don't needlessly propagate an error). + #[test] + fn test_err_suppression() { + let err = Condition(Err("some err msg".to_string())); + assert_eq!(Condition::always_true(), Condition::or(Condition::always_true(), err.clone()),); + assert_eq!(Condition::always_true(), Condition::or(err.clone(), Condition::always_true()),); + assert_eq!( + Condition::always_false(), + Condition::and(Condition::always_false(), err.clone()), + ); + assert_eq!( + Condition::always_false(), + Condition::and(err.clone(), Condition::always_false()), + ); + } }
diff --git a/tools/crates/gnrt/lib/deps.rs b/tools/crates/gnrt/lib/deps.rs index eae2413..7f90722 100644 --- a/tools/crates/gnrt/lib/deps.rs +++ b/tools/crates/gnrt/lib/deps.rs
@@ -282,7 +282,7 @@ |link: &PackageLink, dep_kind: DependencyKind| -> Condition { let key = get_link_key(link); if !cargo_set_links.contains(&key) { - return Condition::AlwaysFalse; + return Condition::always_false(); } let dep_kind = match dep_kind { DependencyKind::Normal => guppy::DependencyKind::Normal, @@ -354,7 +354,7 @@ } /// Graph traversal resolver that rejects dependency links that would have been -/// `AlwaysFalse` on Chromium platforms. +/// `Condition::is_always_false` on Chromium platforms. struct PackageResolver<'a> { extra_config: &'a BuildConfig, memoization_tables: &'a mut MemoizationTables, @@ -390,7 +390,7 @@ ] }) .reduce(Condition::or) - .unwrap_or(Condition::AlwaysTrue); + .unwrap_or_else(Condition::always_true); self.package_conditions.insert(package.into(), condition.clone()); condition } @@ -402,7 +402,7 @@ ) -> Condition { let req = link.req_for_kind(dep_kind); if !req.is_present() { - Condition::AlwaysFalse + Condition::always_false() } else { let baseline_condition = self.get_package_condition(&link.from()); Condition::and( @@ -457,7 +457,7 @@ let mut result = HashMap::new(); let mut insert_if_present = |link: PackageLink, kind: DependencyKind| { let condition = condition_getter(&link, kind); - if condition != Condition::AlwaysFalse { + if !condition.is_always_false() { let features = match kind { // ... => `build.rs` deps only care about host-side features. DependencyKind::Build => get_features(cargo_set.host_features()), @@ -490,13 +490,13 @@ fn get_condition(platform_status: PlatformStatus) -> Condition { use PlatformStatus::*; match platform_status { - Never => Condition::AlwaysFalse, - Always => Condition::AlwaysTrue, + Never => Condition::always_false(), + Always => Condition::always_true(), PlatformDependent { eval } => eval .target_specs() .iter() .map(Condition::from_target_spec) - .fold(Condition::AlwaysFalse, Condition::or), + .fold(Condition::always_false(), Condition::or), } } @@ -506,10 +506,8 @@ ) -> Vec<DepOfDep> { package .direct_links() - .filter_map(|link| match condition_getter(&link) { - Condition::AlwaysFalse => None, - other_condition => Some((link, other_condition)), - }) + .map(|link| (link, condition_getter(&link))) + .filter(|&(_link, ref condition)| !condition.is_always_false()) .map(|(link, condition)| DepOfDep { package_name: link.to().name().to_string(), use_name: link.resolved_name().to_string(), @@ -678,7 +676,7 @@ package_name: "bar".to_string(), use_name: "baz".to_string(), version: Version::new(0, 1, 0), - condition: Condition::AlwaysTrue, + condition: Condition::always_true(), } ); assert_eq!( @@ -687,7 +685,7 @@ package_name: "time".to_string(), use_name: "time".to_string(), version: Version::new(0, 3, 14), - condition: Condition::AlwaysTrue, + condition: Condition::always_true(), } ); @@ -717,7 +715,7 @@ package_name: "autocfg".to_string(), use_name: "autocfg".to_string(), version: Version::new(1, 1, 0), - condition: Condition::AlwaysTrue, + condition: Condition::always_true(), } ); assert!(dependencies[i].build_script.as_ref().is_some_and(|path| { @@ -784,7 +782,7 @@ package_name: "serde_derive".to_string(), use_name: "serde_derive".to_string(), version: Version::new(1, 0, 139), - condition: Condition::AlwaysTrue, + condition: Condition::always_true(), } ); @@ -806,7 +804,7 @@ package_name: "proc-macro2".to_string(), use_name: "proc_macro2".to_string(), version: Version::new(1, 0, 40), - condition: Condition::AlwaysTrue, + condition: Condition::always_true(), } ); assert_eq!( @@ -815,7 +813,7 @@ package_name: "quote".to_string(), use_name: "quote".to_string(), version: Version::new(1, 0, 20), - condition: Condition::AlwaysTrue, + condition: Condition::always_true(), } ); assert_eq!( @@ -824,7 +822,7 @@ package_name: "syn".to_string(), use_name: "syn".to_string(), version: Version::new(1, 0, 98), - condition: Condition::AlwaysTrue, + condition: Condition::always_true(), } ); @@ -845,7 +843,7 @@ package_name: "proc-macro2".to_string(), use_name: "proc_macro2".to_string(), version: Version::new(1, 0, 40), - condition: Condition::AlwaysTrue, + condition: Condition::always_true(), } ); assert_eq!( @@ -854,7 +852,7 @@ package_name: "quote".to_string(), use_name: "quote".to_string(), version: Version::new(1, 0, 20), - condition: Condition::AlwaysTrue, + condition: Condition::always_true(), } ); assert_eq!( @@ -863,7 +861,7 @@ package_name: "unicode-ident".to_string(), use_name: "unicode_ident".to_string(), version: Version::new(1, 0, 1), - condition: Condition::AlwaysTrue, + condition: Condition::always_true(), } );
diff --git a/tools/cygprofile/generate_orderfile.pydeps b/tools/cygprofile/generate_orderfile.pydeps index 7555de0..08b16e8 100644 --- a/tools/cygprofile/generate_orderfile.pydeps +++ b/tools/cygprofile/generate_orderfile.pydeps
@@ -54,7 +54,6 @@ //third_party/catapult/devil/devil/devil_env.py //third_party/catapult/devil/devil/utils/__init__.py //third_party/catapult/devil/devil/utils/cmd_helper.py -//third_party/catapult/devil/devil/utils/host_utils.py //third_party/catapult/devil/devil/utils/lazy/__init__.py //third_party/catapult/devil/devil/utils/lazy/weak_constant.py //third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/tools/mb/mb.py b/tools/mb/mb.py index 47fb735..5f6a92c 100755 --- a/tools/mb/mb.py +++ b/tools/mb/mb.py
@@ -1709,6 +1709,7 @@ or 'is_chromeos_device=true' in vals['gn_args']) is_cros_device = 'is_chromeos_device=true' in vals['gn_args'] is_ios = 'target_os="ios"' in vals['gn_args'] + is_linux = 'target_os="linux"' in vals['gn_args'] # pylint: disable=consider-using-ternary is_mac = ((self.platform == 'darwin' and not is_ios) or 'target_os="mac"' in vals['gn_args']) @@ -1721,8 +1722,10 @@ # that one Ozone build can be used to run different backends. Currently, # tests are executed for the headless and X11 backends and both can run # under Xvfb on Linux. - use_xvfb = (self.platform.startswith('linux') and not is_android - and not is_fuchsia and not is_cros_device) + if 'target_os' not in vals['gn_args']: + use_xvfb = self.platform.startswith('linux') + else: + use_xvfb = is_linux or (is_cros and not is_cros_device) asan = 'is_asan=true' in vals['gn_args'] lsan = 'is_lsan=true' in vals['gn_args']
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 76e40bed..50f1eba 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -48605,6 +48605,8 @@ <suffix name="ExtensionsMenu" label="For Extensions menu opening."/> <suffix name="ExtensionsRequestAccessButton" label="For Extensions request access button feature."/> + <suffix name="ExtensionsZeroStatePromo" + label="For promoting extensions to users with no extensions."/> <suffix name="FeatureNotificationGuideDefaultBrowserNotificationShown" label="For feature notification guide default browser notification feature. (obsolete)"/>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 6cb8d3fc..ba81a8a9 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -12276,6 +12276,7 @@ <int value="-668114930" label="WindowsFollowCursor:disabled"/> <int value="-667952041" label="CCTRealTimeEngagementSignals:enabled"/> <int value="-667517406" label="overscroll-history-navigation"/> + <int value="-667213800" label="PinnedTabToastOnClose:disabled"/> <int value="-667018797" label="OmniboxUIExperimentBlueTitlesAndGrayUrlsOnPageSuggestions:disabled"/> <int value="-666712735" label="FeedShare:disabled"/> @@ -15100,6 +15101,7 @@ <int value="408190863" label="OmniboxDisableInstantExtendedLimit:disabled"/> <int value="408469366" label="NtpHistoryClustersModuleSuggestionChipHeader:disabled"/> + <int value="409097421" label="EnablePixAccountLinking:enabled"/> <int value="409174264" label="camera-super-res-override"/> <int value="409566604" label="IntentPickerPWAPersistence:enabled"/> <int value="409622437" label="disable-buffer-bw-compression"/> @@ -15629,6 +15631,7 @@ <int value="625725485" label="FilesTrash:enabled"/> <int value="625916211" label="ConchSystemAudioFromMic:disabled"/> <int value="626349796" label="ArcVmMemorySize:disabled"/> + <int value="626413969" label="PinnedTabToastOnClose:enabled"/> <int value="626662478" label="Canvas2DHibernation:disabled"/> <int value="628302973" label="NTPSnippets:enabled"/> <int value="628438173" label="AccessibilityPerformanceFiltering:enabled"/> @@ -19575,6 +19578,7 @@ <int value="2094335682" label="StreamlinedUsbPrinterSetup:enabled"/> <int value="2095250358" label="EnableBluetoothSerialPortProfileInSerialApi:disabled"/> + <int value="2095569369" label="EnablePixAccountLinking:disabled"/> <int value="2095740699" label="OmniboxPedalsBatch3:disabled"/> <int value="2096688830" label="RequestDesktopSitePerSiteIph:disabled"/> <int value="2096736155" label="BrowsingDataLifetimeManager:enabled"/>
diff --git a/tools/metrics/histograms/metadata/bookmarks/enums.xml b/tools/metrics/histograms/metadata/bookmarks/enums.xml index b5ba6cd..9247c73 100644 --- a/tools/metrics/histograms/metadata/bookmarks/enums.xml +++ b/tools/metrics/histograms/metadata/bookmarks/enums.xml
@@ -110,7 +110,6 @@ <int value="20" label="Help center"/> <int value="21" label="Open bookmark (via double-click / enter)"/> <int value="22" label="Open folder (via double-click / enter)"/> - <int value="23" label="Open in split view"/> </enum> <!-- LINT.IfChange(BookmarkReorderDropTarget) -->
diff --git a/tools/metrics/histograms/metadata/custom_tabs/enums.xml b/tools/metrics/histograms/metadata/custom_tabs/enums.xml index a6fdaca..87d08f0 100644 --- a/tools/metrics/histograms/metadata/custom_tabs/enums.xml +++ b/tools/metrics/histograms/metadata/custom_tabs/enums.xml
@@ -267,6 +267,25 @@ <int value="3" label="High-end and Pip"/> </enum> +<enum name="TwaLaunchHandlerClientMode"> + <int value="0" label="Initial intent (client mode is ignored)"/> + <int value="1" label="Client mode navigate_existing"/> + <int value="2" label="Client mode navigate_new"/> + <int value="3" label="Client mode focus_existing"/> + <int value="4" label="Client mode auto"/> +</enum> + +<enum name="TwaLaunchHandlerFailureReason"> + <int value="0" label="Target URL verification failed"/> + <int value="1" label="Current page URL verification failed"/> +</enum> + +<enum name="TwaLaunchHandlerFileHandling"> + <int value="0" label="No files"/> + <int value="1" label="Single file"/> + <int value="2" label="Multiple files"/> +</enum> + <enum name="VisibleTab"> <int value="0" label="Custom Tab"/> <int value="1" label="Chrome Tab"/>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml index e224b082..ba9264ec 100644 --- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml +++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -932,6 +932,43 @@ </token> </histogram> +<histogram name="TrustedWebActivity.LaunchHandler.ClientMode" + enum="TwaLaunchHandlerClientMode" expires_after="2026-05-01"> + <owner>tkachenkoo@google.com</owner> + <owner>sselyvon@google.com</owner> + <owner>cros-web-apps-team@google.com</owner> + <summary> + Records the client mode of a web app launched through Trusted Web Activity. + Client mode is a part of Launch Handler API. Recorded on Trusted Web + Activity startup if the Launch Handler API is enabled. + </summary> +</histogram> + +<histogram name="TrustedWebActivity.LaunchHandler.FailureReason" + enum="TwaLaunchHandlerFailureReason" expires_after="2026-05-01"> + <owner>tkachenkoo@google.com</owner> + <owner>sselyvon@google.com</owner> + <owner>cros-web-apps-team@google.com</owner> + <summary> + Records the verification failure that caused launch queue to not be notified + in Trusted Web Activity, if any. Recorded on Trusted Web Activity startup if + the Launch Handler API is enabled. + </summary> +</histogram> + +<histogram name="TrustedWebActivity.LaunchHandler.FileHandling" + enum="TwaLaunchHandlerFileHandling" expires_after="2026-05-01"> + <owner>tkachenkoo@google.com</owner> + <owner>sselyvon@google.com</owner> + <owner>cros-web-apps-team@google.com</owner> + <summary> + Records the usage of file handling API in Trusted Web Activities, as part of + Launch Handler API. Recorded on Trusted Web Activity startup if the Launch + Handler API is enabled. If file handling is not used, NO_FILES will be + reported. + </summary> +</histogram> + <histogram name="TrustedWebActivity.Notification.PermissionRequestResult" enum="ContentSetting" expires_after="2025-10-01"> <owner>peconn@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/enterprise/histograms.xml b/tools/metrics/histograms/metadata/enterprise/histograms.xml index 88bb75e..71663ca 100644 --- a/tools/metrics/histograms/metadata/enterprise/histograms.xml +++ b/tools/metrics/histograms/metadata/enterprise/histograms.xml
@@ -429,6 +429,20 @@ </summary> </histogram> +<histogram name="Enterprise.CertificateStore.LevelDB.InitStatus.{Retry}" + units="code" expires_after="2026-02-10"> + <owner>seblalancette@chromium.org</owner> + <owner>cbe-device-trust-eng@google.com</owner> + <summary> + Captures the initialization status returned after initializing {Retry} a + LevelDB database instance used by the managed client certificates store. + </summary> + <token key="Retry"> + <variant name="NoRetry" summary="without retry"/> + <variant name="WithRetry" summary="with retry"/> + </token> +</histogram> + <histogram name="Enterprise.ClientCertificate.{Level}.CreateCertificate.Success.HasCert" enum="BooleanSuccess" expires_after="2026-02-10">
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml index 9e4d268..9df7665 100644 --- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml +++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -202,6 +202,10 @@ <variant name="IPH_ExtensionsMenu" summary="extensions menu opened"/> <variant name="IPH_ExtensionsRequestAccessButton" summary="extensions request access button shown"/> + <variant name="IPH_ExtensionsZeroStatePromo" + summary="message shown anchored to the three dots app menu suggesting + users with no extensions installed to explore the IPH_Chrome + Web Store."/> <variant name="IPH_FeatureNotificationGuideDefaultBrowserNotificationShown" summary="(obsolete) feature notification guide default browser notification"/>
diff --git a/tools/metrics/histograms/metadata/linux/histograms.xml b/tools/metrics/histograms/metadata/linux/histograms.xml index c8ea6076..5471162 100644 --- a/tools/metrics/histograms/metadata/linux/histograms.xml +++ b/tools/metrics/histograms/metadata/linux/histograms.xml
@@ -165,7 +165,7 @@ <histogram name="Linux.X11.XInput2" enum="BooleanEnabled" expires_after="2025-10-21"> - <owner>aycyang@chromium.org</owner> + <owner>hidehiko@chromium.org</owner> <owner>thomasanderson@chromium.org</owner> <summary>Whether X Input Extension version 2.x is available.</summary> </histogram>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index 3c2d520..a5a1242b 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -632,6 +632,21 @@ </summary> </histogram> +<histogram name="HttpCache.NoVarySearch.EntriesAddedDuringLoading" + units="entries" expires_after="2025-12-16"> + <owner>ricea@chromium.org</owner> + <owner>net-dev@chromium.org</owner> + <summary> + Number of entries that were added to the NoVarySearchCache while the + previously persisted cache was being loaded from disk. This is logged once + per successful call to NoVarySearchCacheStorage::Load(), which is once per + on-the-record NetworkContext. + + This can be considered an approximation of how many requests missed the + benefit of the NoVarySearchCache due to the load being slow. + </summary> +</histogram> + <histogram name="HttpCache.NoVarySearch.EntriesLoaded" units="entries" expires_after="2025-12-16"> <owner>ricea@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml index ee8cad6..a6b1d36 100644 --- a/tools/metrics/histograms/metadata/network/histograms.xml +++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -5530,6 +5530,30 @@ </summary> </histogram> +<histogram name="NetworkService.IpProtection.{ProxyLayer}.TokenCount.{Event}" + units="tokens" expires_after="2025-10-01"> + <owner>abhipatel@chromium.org</owner> + <owner>src/components/ip_protection/OWNERS</owner> + <summary> + Records the number of IP Protection auth tokens involved in a specific event + for {ProxyLayer}. The histogram indicates that {Event}. Allows calculation + of tokens lost to other causes (e.g. shutdown) by comparing Requested vs. + (Spent + Expired). Recorded when tokens are successfully fetched, spent, or + garbage-collected. Expected counts are typically 1 for Spent, and + potentially higher for Requested/Expired (up to batch size or cache size). + </summary> + <token key="ProxyLayer"> + <variant name="ProxyA"/> + <variant name="ProxyB"/> + </token> + <token key="Event"> + <variant name="Expired" summary="Token removed from cache due to expiry."/> + <variant name="Requested" + summary="Tokens successfully fetched and cached."/> + <variant name="Spent" summary="Token used for a proxy connection."/> + </token> +</histogram> + <histogram name="NetworkService.IpProtection.{ProxyLayer}.TokenExpirationRate" units="tokens" expires_after="2025-10-26"> <owner>djmitche@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml index 687d647..5afed18 100644 --- a/tools/metrics/histograms/metadata/omnibox/histograms.xml +++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -2034,6 +2034,22 @@ </histogram> <histogram + name="Omnibox.SearchPrefetch.DuplicateSearchTermsAgeAheadOfNavigationalPrefetch" + units="ms" expires_after="2025-09-14"> + <owner>lingqi@chromium.org</owner> + <owner>nhiroki@chromium.org</owner> + <owner>chrome-prerendering@google.com</owner> + <summary> + Measures the duration between when the search terms are visited and when the + same search terms are prefetched by navigational prefetch predictor. + + Recorded at + SearchPrefetchService::RecordPotentialDuplicateSearchTermsAheadofNavigationalPrefetch + when the same search terms are prefetch by navigational prefetch predictor. + </summary> +</histogram> + +<histogram name="Omnibox.SearchPrefetch.SearchWhatYouTypedWasAlsoSuggested.{HistoryOrSuggest}" enum="Boolean" expires_after="2023-05-02"> <owner>ryansturm@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/permissions/enums.xml b/tools/metrics/histograms/metadata/permissions/enums.xml index d2e83330..a598995 100644 --- a/tools/metrics/histograms/metadata/permissions/enums.xml +++ b/tools/metrics/histograms/metadata/permissions/enums.xml
@@ -177,11 +177,6 @@ <!-- LINT.ThenChange(//components/permissions/permission_request_enums.h:PermissionPredictionSource) --> -<enum name="PermissionPredictionThresholdSource"> - <int value="0" label="MODEL_METADATA"/> - <int value="1" label="HARDCODED_FALLBACK"/> -</enum> - <enum name="PermissionPromptDismissMethod"> <int value="0" label="Unspecified"/> <int value="1" label="Back navigation"/>
diff --git a/tools/metrics/histograms/metadata/permissions/histograms.xml b/tools/metrics/histograms/metadata/permissions/histograms.xml index 0a812a8..591f6118 100644 --- a/tools/metrics/histograms/metadata/permissions/histograms.xml +++ b/tools/metrics/histograms/metadata/permissions/histograms.xml
@@ -949,17 +949,6 @@ </summary> </histogram> -<histogram name="Permissions.PredictionService.PredictionThresholdSource" - enum="PermissionPredictionThresholdSource" expires_after="2025-01-05"> - <owner>ravjit@chromium.org</owner> - <owner>src/components/permissions/PERMISSIONS_OWNERS</owner> - <summary> - Recorded whenever on-device Permissions prediciton service model is - executed. Records if the threshold value for the non-grant score is obtained - from the model's metadata or if the default fallback was used. - </summary> -</histogram> - <histogram name="Permissions.PredictionService.Response.{PermissionType}" enum="BooleanIgnored" expires_after="2025-09-14"> <owner>ravjit@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml index 765822a..ac19fd0 100644 --- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml +++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -1288,7 +1288,7 @@ </histogram> <histogram name="SafeBrowsing.FileTypeUpdate.DynamicUpdateVersion" - units="FileTypePolicies Version" expires_after="2025-05-18"> + units="FileTypePolicies Version" expires_after="2026-01-06"> <owner>drubery@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -1322,7 +1322,7 @@ </histogram> <histogram name="SafeBrowsing.FileTypeUpdate.ResourceBundleResult" - enum="SBFileTypeUpdateResult" expires_after="2025-05-18"> + enum="SBFileTypeUpdateResult" expires_after="2026-01-06"> <owner>drubery@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -1335,7 +1335,7 @@ </histogram> <histogram name="SafeBrowsing.FileTypeUpdate.ResourceBundleVersion" - units="FileTypePolicies Version" expires_after="2025-06-22"> + units="FileTypePolicies Version" expires_after="2026-01-06"> <owner>drubery@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/security/histograms.xml b/tools/metrics/histograms/metadata/security/histograms.xml index 2db67cd..5962708 100644 --- a/tools/metrics/histograms/metadata/security/histograms.xml +++ b/tools/metrics/histograms/metadata/security/histograms.xml
@@ -198,7 +198,7 @@ </histogram> <histogram name="Security.GwpAsan.CrashAnalysisResult.{Allocator}" - enum="GwpAsanCrashAnalysisResult" expires_after="2025-05-04"> + enum="GwpAsanCrashAnalysisResult" expires_after="2026-05-04"> <owner>glazunov@google.com</owner> <owner>mpdenton@chromium.org</owner> <owner>chrome-memory-tok@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml index 3872829..8efda94c 100644 --- a/tools/metrics/histograms/metadata/signin/histograms.xml +++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -3059,6 +3059,29 @@ </summary> </histogram> +<histogram name="Signin.SyncOptIn.IdentityPill.DurationBeforeClick" units="ms" + expires_after="2026-01-12"> + <owner>ernn@google.com</owner> + <owner>chrome-signin-team@google.com</owner> + <summary> + Records the time between the history sync opt-in identity pill promo is + opened and the user interacts with it (clicks on it). If the user doesn't + click the identity pill, the histogram should not be recorded. + </summary> +</histogram> + +<histogram name="Signin.SyncOptIn.IdentityPill.Shown" enum="SigninAccessPoint" + expires_after="2026-01-12"> + <owner>ernn@google.com</owner> + <owner>chrome-signin-team@google.com</owner> + <summary> + Counts the number of times the history sync opt-in identity pill was shown. + + Note: This is only recorded for `kHistorySyncOptinExpansionPill*` access + points. + </summary> +</histogram> + <histogram name="Signin.SyncOptIn.Offered" enum="SigninAccessPoint" expires_after="2026-01-12"> <owner>ernn@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/toasts/enums.xml b/tools/metrics/histograms/metadata/toasts/enums.xml index 49c907b..f312f3f 100644 --- a/tools/metrics/histograms/metadata/toasts/enums.xml +++ b/tools/metrics/histograms/metadata/toasts/enums.xml
@@ -72,6 +72,7 @@ <int value="13" label="User joined collaboration"/> <int value="14" label="Collaboration removed"/> <int value="15" label="Video Frame Copied"/> + <int value="16" label="Close pinned tab confirmation toast"/> </enum> <!-- LINT.ThenChange(/chrome/browser/ui/toasts/api/toast_id.h:ToastId) -->
diff --git a/tools/perf/core/bot_platforms.py b/tools/perf/core/bot_platforms.py index b058d2b..d47e3cb 100644 --- a/tools/perf/core/bot_platforms.py +++ b/tools/perf/core/bot_platforms.py
@@ -516,7 +516,6 @@ # TODO(crbug.com/338630584): Remove it when other benchmarks can be run on # Android. _CROSSBENCH_ANDROID = frozenset([ - _crossbench_speedometer3_0(arguments=['--fileserver']), _crossbench_speedometer3(arguments=['--fileserver']), _crossbench_loadline_phone(arguments=[ '--cool-down-threshold=moderate',
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py index abf2a42..c3b8b797 100755 --- a/tools/perf/core/perf_data_generator.py +++ b/tools/perf/core/perf_data_generator.py
@@ -633,7 +633,7 @@ 'pool': 'chrome', 'os': 'Android', 'label-pool': 'chrome.tests.perf', - 'label-board': 'byra', + 'label-board': 'brya', }, 'server': 'https://chromeos-swarming.appspot.com',
diff --git a/tools/perf/core/shard_maps/android-pixel6-perf-pgo_map.json b/tools/perf/core/shard_maps/android-pixel6-perf-pgo_map.json index 555a0e333..42c97928 100644 --- a/tools/perf/core/shard_maps/android-pixel6-perf-pgo_map.json +++ b/tools/perf/core/shard_maps/android-pixel6-perf-pgo_map.json
@@ -47,7 +47,7 @@ "2": { "benchmarks": { "rendering.mobile": { - "end": 83, + "end": 82, "abridged": false }, "jetstream2": { @@ -65,8 +65,8 @@ "3": { "benchmarks": { "rendering.mobile": { - "begin": 83, - "end": 166, + "begin": 82, + "end": 164, "abridged": false }, "jetstream2": { @@ -84,8 +84,8 @@ "4": { "benchmarks": { "rendering.mobile": { - "begin": 166, - "end": 247, + "begin": 164, + "end": 245, "abridged": false }, "jetstream2": { @@ -103,8 +103,8 @@ "5": { "benchmarks": { "rendering.mobile": { - "begin": 247, - "end": 327, + "begin": 245, + "end": 324, "abridged": false }, "speedometer3": { @@ -116,7 +116,7 @@ "6": { "benchmarks": { "rendering.mobile": { - "begin": 327, + "begin": 324, "abridged": false }, "speedometer2": { @@ -145,12 +145,6 @@ } }, "crossbench": { - "speedometer_3.0": { - "display_name": "speedometer3.0.crossbench", - "arguments": [ - "--fileserver" - ] - }, "speedometer_3": { "display_name": "speedometer3.crossbench", "arguments": [ @@ -160,18 +154,18 @@ } }, "extra_infos": { - "num_stories": 499, + "num_stories": 498, "predicted_min_shard_time": 916.0, "predicted_min_shard_index": 0, "predicted_max_shard_time": 7856.0, "predicted_max_shard_index": 1, "shard #0": 916.0, "shard #1": 7856.0, - "shard #2": 2861.0, - "shard #3": 2862.0, - "shard #4": 2845.0, - "shard #5": 2871.0, - "shard #6": 2720.0, - "shard #7": 3001.0 + "shard #2": 2836.0, + "shard #3": 2841.0, + "shard #4": 2847.0, + "shard #5": 2839.0, + "shard #6": 2796.0, + "shard #7": 2941.0 } }
diff --git a/tools/perf/core/shard_maps/android-pixel6-perf_map.json b/tools/perf/core/shard_maps/android-pixel6-perf_map.json index 2de1f36..489f9ee5 100644 --- a/tools/perf/core/shard_maps/android-pixel6-perf_map.json +++ b/tools/perf/core/shard_maps/android-pixel6-perf_map.json
@@ -189,7 +189,7 @@ "abridged": false }, "rendering.mobile": { - "end": 19, + "end": 18, "abridged": false } }, @@ -205,8 +205,8 @@ "7": { "benchmarks": { "rendering.mobile": { - "begin": 19, - "end": 140, + "begin": 18, + "end": 139, "abridged": false } } @@ -214,8 +214,8 @@ "8": { "benchmarks": { "rendering.mobile": { - "begin": 140, - "end": 261, + "begin": 139, + "end": 260, "abridged": false } } @@ -223,8 +223,8 @@ "9": { "benchmarks": { "rendering.mobile": { - "begin": 261, - "end": 366, + "begin": 260, + "end": 365, "abridged": false } } @@ -232,7 +232,7 @@ "10": { "benchmarks": { "rendering.mobile": { - "begin": 366, + "begin": 365, "abridged": false }, "rendering.mobile.notracing": { @@ -266,12 +266,6 @@ } }, "crossbench": { - "speedometer_3.0": { - "display_name": "speedometer3.0.crossbench", - "arguments": [ - "--fileserver" - ] - }, "speedometer_3": { "display_name": "speedometer3.crossbench", "arguments": [ @@ -328,7 +322,7 @@ } }, "extra_infos": { - "num_stories": 1136, + "num_stories": 1135, "predicted_min_shard_time": 3580.0, "predicted_min_shard_index": 12, "predicted_max_shard_time": 7376.0, @@ -339,11 +333,11 @@ "shard #3": 7376.0, "shard #4": 7376.0, "shard #5": 3604.0, - "shard #6": 3615.0, - "shard #7": 3591.0, - "shard #8": 3607.0, - "shard #9": 3604.0, - "shard #10": 3619.0, + "shard #6": 3589.0, + "shard #7": 3585.0, + "shard #8": 3614.0, + "shard #9": 3597.0, + "shard #10": 3591.0, "shard #11": 3636.0, "shard #12": 3580.0, "shard #13": 3977.0
diff --git a/tools/perf/process_perf_results.pydeps b/tools/perf/process_perf_results.pydeps index 21ce947..f38f8f5 100644 --- a/tools/perf/process_perf_results.pydeps +++ b/tools/perf/process_perf_results.pydeps
@@ -112,7 +112,6 @@ ../../third_party/catapult/devil/devil/utils/__init__.py ../../third_party/catapult/devil/devil/utils/cmd_helper.py ../../third_party/catapult/devil/devil/utils/geometry.py -../../third_party/catapult/devil/devil/utils/host_utils.py ../../third_party/catapult/devil/devil/utils/lazy/__init__.py ../../third_party/catapult/devil/devil/utils/lazy/weak_constant.py ../../third_party/catapult/devil/devil/utils/logging_common.py
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index 303a294..fdb44409 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -373,7 +373,7 @@ <item id="promise_app_service" added_in_milestone="114" content_hash_code="07856112" os_list="chromeos" file_path="chrome/browser/apps/app_service/promise_apps/promise_app_almanac_connector.cc" /> <item id="safe_browsing_hashprefix_realtime_lookup_ohttp" added_in_milestone="114" content_hash_code="0817ae7d" os_list="linux,windows,chromeos,android" file_path="components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.cc" /> <item id="gaia_auth_rotate_bound_cookies" added_in_milestone="115" content_hash_code="04014185" os_list="linux,windows" file_path="chrome/browser/signin/bound_session_credentials/bound_session_refresh_cookie_fetcher.cc" /> - <item id="crash_file_uploader" added_in_milestone="115" content_hash_code="05f6902f" os_list="linux,windows" file_path="remoting/host/crash/crash_file_uploader.cc" /> + <item id="crash_file_uploader" added_in_milestone="115" content_hash_code="05f6902f" os_list="windows" file_path="remoting/host/crash/crash_file_uploader.cc" /> <item id="glanceables_classroom_integration" added_in_milestone="115" content_hash_code="048f5ccb" os_list="chromeos" file_path="chrome/browser/ui/ash/glanceables/glanceables_classroom_client_impl.cc" /> <item id="promise_app_service_download_icon" added_in_milestone="115" content_hash_code="00521032" os_list="chromeos" file_path="chrome/browser/apps/app_service/promise_apps/promise_app_service.cc" /> <item id="iwa_update_manifest_fetcher" added_in_milestone="116" type="completing" content_hash_code="0031297e" os_list="linux,windows,chromeos" semantics_fields="4,5,7,8,9" policy_fields="-1" file_path="chrome/browser/web_applications/isolated_web_apps/update_manifest/update_manifest_fetcher.cc" />
diff --git a/tools/typescript/definitions/bookmark_manager_private.d.ts b/tools/typescript/definitions/bookmark_manager_private.d.ts index 2579edd4..9aa0f18 100644 --- a/tools/typescript/definitions/bookmark_manager_private.d.ts +++ b/tools/typescript/definitions/bookmark_manager_private.d.ts
@@ -23,11 +23,6 @@ elements: BookmarkNodeDataElement[]; } - interface OpenInNewTabParams { - active?: boolean; - split?: boolean; - } - export function copy(idList: string[]): Promise<void>; export function cut(idList: string[]): Promise<void>; export function paste(parentId: string, selectedIdList?: string[]): @@ -43,8 +38,7 @@ export function removeTrees(idList: string[]): Promise<void>; export function undo(): void; export function redo(): void; - export function openInNewTab( - id: string, params?: OpenInNewTabParams): void; + export function openInNewTab(id: string, active: boolean): void; export function openInNewWindow(idList: string[], incognito: boolean): void; export function openInNewTabGroup(idList: string[]): void;
diff --git a/tools/typescript/definitions/pending.d.ts b/tools/typescript/definitions/pending.d.ts index 497b1f9f..cae6447 100644 --- a/tools/typescript/definitions/pending.d.ts +++ b/tools/typescript/definitions/pending.d.ts
@@ -79,4 +79,9 @@ /** The values as a flattened one-dimensional array. */ data: number[]; -} \ No newline at end of file +} + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/ +interface Set<T> { + difference(other: Set<T>): Set<T>; +}
diff --git a/tools/utr/output_adapter.py b/tools/utr/output_adapter.py index a2d68b5..8464ae43 100644 --- a/tools/utr/output_adapter.py +++ b/tools/utr/output_adapter.py
@@ -94,6 +94,7 @@ 'read gclient': logging.DEBUG, 'write output_properties_file': logging.DEBUG, 'prepare skylab tests.': logging.DEBUG, + 'update invocation instructions': logging.DEBUG, } # Setup logger for printing to the same line logger = logging.getLogger('single_line_logger')
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn index bb5185a..e5e10c86 100644 --- a/ui/android/BUILD.gn +++ b/ui/android/BUILD.gn
@@ -402,6 +402,7 @@ "java/src/org/chromium/ui/dragdrop/DropDataProviderImpl.java", "java/src/org/chromium/ui/dragdrop/DropDataProviderUtils.java", "java/src/org/chromium/ui/drawable/AnimationLooper.java", + "java/src/org/chromium/ui/drawable/BorderDrawable.java", "java/src/org/chromium/ui/drawable/StateListDrawableBuilder.java", "java/src/org/chromium/ui/events/devices/InputDeviceObserver.java", "java/src/org/chromium/ui/gfx/Animation.java",
diff --git a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java index ee31091..b2460f7 100644 --- a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java +++ b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
@@ -26,6 +26,7 @@ import org.chromium.base.ContentUriUtils; import org.chromium.base.ContextUtils; import org.chromium.base.Log; +import org.chromium.base.MathUtils; import org.chromium.base.TraceEvent; import org.chromium.base.metrics.RecordHistogram; import org.chromium.build.annotations.NullMarked; @@ -782,9 +783,8 @@ float offsetX = 0.0f; float offsetY = 0.0f; - // TODO(crbug.com/405067297): support multi-finger events on the trackpad (scroll) if (event.isFromSource(InputDevice.SOURCE_TOUCHPAD)) { - event = updateTrackpadButtonState(event); + event = updateTrackpadCapturedButtonState(event); // Ignore calculating the offset if we don't have the previous event trackpad position if (mIsLastTrackpadPositionValid) { @@ -799,6 +799,14 @@ mLastTrackpadPositionX = event.getX(); mLastTrackpadPositionY = event.getY(); + event = updateTrackpadCapturedScrollEvent(event, offsetX, offsetY); + + // Cancel any calculated offset, since scroll events shouldn't affect trackpad position + if (event.getAction() == MotionEvent.ACTION_SCROLL) { + offsetX = 0; + offsetY = 0; + } + // Invalidate the trackpad position for these cases: // ACTION_UP: No pointer on the trackpad, the position data is stale // ACTION_POINTER_UP & ACTION_POINTER_DOWN: Multiple trackpad pointers causes the main @@ -828,7 +836,7 @@ return ret; } - private static MotionEvent updateTrackpadButtonState(MotionEvent event) { + private static MotionEvent updateTrackpadCapturedButtonState(MotionEvent event) { if (event.getAction() != MotionEvent.ACTION_BUTTON_PRESS && event.getAction() != MotionEvent.ACTION_BUTTON_RELEASE) { return event; @@ -864,6 +872,59 @@ event.getFlags()); } + // TODO(https://crbug.com/415730929): Scroll movement has no momentum + // TODO(https://crbug.com/415730915): Move helper methods to a util class + // When the pointer is captured, multi-touch gestures are not supported, this supports 2 finger + // move to count as a scroll gesture + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + public static MotionEvent updateTrackpadCapturedScrollEvent( + MotionEvent event, float offsetX, float offsetY) { + if (event.getAction() != MotionEvent.ACTION_MOVE + || event.getPointerCount() != 2 + || (offsetX == 0 && offsetY == 0)) { + return event; + } + + // TODO(https://crbug.com/415730915): Cache the input device resolution + InputDevice inputDevice = InputDevice.getDevice(event.getDeviceId()); + // Resolution is how many pixels per millimeters on the trackpad + float xAxisResolution = 1; + float yAxisResolution = 1; + if (inputDevice != null) { + xAxisResolution = inputDevice.getMotionRange(MotionEvent.AXIS_X).getResolution(); + yAxisResolution = inputDevice.getMotionRange(MotionEvent.AXIS_Y).getResolution(); + } + + // TODO(https://crbug.com/415730929): inverse scrolling is not respected, doesn't seem that + // the setting value is exposed from the OS. + float xDirection = MathUtils.clamp(offsetX / xAxisResolution, -1, 1); + float yDirection = MathUtils.clamp(offsetY / yAxisResolution, -1, 1); + + MotionEvent.PointerCoords updatedPointerCoords = new MotionEvent.PointerCoords(); + event.getPointerCoords(0, updatedPointerCoords); + updatedPointerCoords.setAxisValue(MotionEvent.AXIS_HSCROLL, xDirection); + updatedPointerCoords.setAxisValue(MotionEvent.AXIS_VSCROLL, yDirection); + + MotionEvent.PointerCoords[] updatedPointerCoordsList = getPointerCoordsForEvent(event); + updatedPointerCoordsList[0] = updatedPointerCoords; + + return MotionEvent.obtain( + event.getDownTime(), + event.getEventTime(), + MotionEvent.ACTION_SCROLL, + event.getPointerCount(), + getPointerPropertiesForEvent(event), + updatedPointerCoordsList, + event.getMetaState(), + event.getButtonState(), + event.getXPrecision(), + event.getYPrecision(), + event.getDeviceId(), + event.getEdgeFlags(), + event.getSource(), + event.getFlags()); + } + private static MotionEvent.PointerProperties[] getPointerPropertiesForEvent(MotionEvent event) { MotionEvent.PointerProperties[] ret = new MotionEvent.PointerProperties[event.getPointerCount()];
diff --git a/ui/android/java/src/org/chromium/ui/base/MimeTypeUtils.java b/ui/android/java/src/org/chromium/ui/base/MimeTypeUtils.java index a9b3b740..cf52d45 100644 --- a/ui/android/java/src/org/chromium/ui/base/MimeTypeUtils.java +++ b/ui/android/java/src/org/chromium/ui/base/MimeTypeUtils.java
@@ -10,7 +10,6 @@ import androidx.annotation.IntDef; -import org.chromium.base.BuildInfo; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; import org.chromium.url.GURL; @@ -84,11 +83,11 @@ /** * @param mimeType The mime type associated with an operation that needs a permission. * @return The name of the Android permission to request. Returns null if no permission will - * allow access to the file, for example on Android T+ where READ_EXTERNAL_STORAGE has - * been replaced with a handful of READ_MEDIA_* permissions. + * allow access to the file, for example on Android T+ where READ_EXTERNAL_STORAGE has been + * replaced with a handful of READ_MEDIA_* permissions. */ public @Nullable static String getPermissionNameForMimeType(@MimeTypeUtils.Type int mimeType) { - if (useExternalStoragePermission()) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { return Manifest.permission.READ_EXTERNAL_STORAGE; } @@ -109,10 +108,4 @@ return clipDescription.hasMimeType(CHROME_MIMETYPE_TAB) || clipDescription.hasMimeType(CHROME_MIMETYPE_TAB_GROUP); } - - static boolean useExternalStoragePermission() { - // Extracted into a helper method for easy testing. Can be replaced with test annotations - // once Robolectric recognizes SDK = T. - return Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || !BuildInfo.targetsAtLeastT(); - } }
diff --git a/ui/android/java/src/org/chromium/ui/drawable/BorderDrawable.java b/ui/android/java/src/org/chromium/ui/drawable/BorderDrawable.java new file mode 100644 index 0000000..d432c029 --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/drawable/BorderDrawable.java
@@ -0,0 +1,72 @@ +// 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. + +package org.chromium.ui.drawable; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; + +import androidx.annotation.ColorInt; + +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; + +/** + * A custom {@link Drawable} designed to render a rounded rectangular border within the drawable's + * bounds. This class provides flexibility in defining the border's width, color, corner radius, and + * insets. It leverages the Android drawing framework to efficiently draw this border on a {@link + * Canvas}. + */ +@NullMarked +public class BorderDrawable extends Drawable { + private final Paint mBorderPaint; + private final int mInsets; + private final float mBorderRadius; + + /** + * Constructs a {@link BorderDrawable}. + * + * @param borderWidth The width of the border to draw, in pixels. + * @param insets The insets to apply inside the bounds before drawing the border, in pixels. + * @param borderColor The color of the border. + * @param borderRadius The radius of the corners of the border, in pixels. + */ + public BorderDrawable( + int borderWidth, int insets, @ColorInt int borderColor, float borderRadius) { + mInsets = insets; + mBorderRadius = borderRadius; + mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mBorderPaint.setColor(borderColor); + mBorderPaint.setStyle(Paint.Style.STROKE); + mBorderPaint.setStrokeWidth(borderWidth); + } + + @Override + public void draw(Canvas canvas) { + RectF bounds = new RectF(getBounds()); + bounds.inset(mInsets, mInsets); + canvas.drawRoundRect(bounds, mBorderRadius, mBorderRadius, mBorderPaint); + } + + @Override + public void setAlpha(int alpha) { + mBorderPaint.setAlpha(alpha); + invalidateSelf(); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + mBorderPaint.setColorFilter(colorFilter); + invalidateSelf(); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } +}
diff --git a/ui/android/junit/src/org/chromium/ui/base/EventForwarderTest.java b/ui/android/junit/src/org/chromium/ui/base/EventForwarderTest.java index b2bbb38..95a81d4 100644 --- a/ui/android/junit/src/org/chromium/ui/base/EventForwarderTest.java +++ b/ui/android/junit/src/org/chromium/ui/base/EventForwarderTest.java
@@ -4,6 +4,8 @@ package org.chromium.ui.base; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; @@ -417,6 +419,16 @@ } @Test + public void testCapturedPointerTrackpadScrollEvent() { + MotionEvent event = getTrackpadEvent(MotionEvent.ACTION_MOVE, 0, 2); + MotionEvent updatedEvent = EventForwarder.updateTrackpadCapturedScrollEvent(event, 10, -10); + + assertEquals(MotionEvent.ACTION_SCROLL, updatedEvent.getAction()); + assertTrue(updatedEvent.getAxisValue(MotionEvent.AXIS_HSCROLL) > 0); + assertTrue(updatedEvent.getAxisValue(MotionEvent.AXIS_VSCROLL) < 0); + } + + @Test public void testCapturedPointerMouseMoveEvent() { EventForwarder eventForwarder = new EventForwarder(NATIVE_EVENT_FORWARDER_ID, true, true); @@ -531,13 +543,17 @@ } private static MotionEvent getTrackpadEvent(int action, int buttonState) { + return getTrackpadEvent(action, buttonState, 1); + } + + private static MotionEvent getTrackpadEvent(int action, int buttonState, int pointersCnt) { return MotionEvent.obtain( 0, 0, action, - 1, - getToolTypeFingerProperties(1), - getPointerCoords(1), + pointersCnt, + getToolTypeFingerProperties(pointersCnt), + getPointerCoords(pointersCnt), 0, buttonState, 0,
diff --git a/ui/android/junit/src/org/chromium/ui/base/MimeTypeUtilsTest.java b/ui/android/junit/src/org/chromium/ui/base/MimeTypeUtilsTest.java index 4f9a7630..e7c4c47 100644 --- a/ui/android/junit/src/org/chromium/ui/base/MimeTypeUtilsTest.java +++ b/ui/android/junit/src/org/chromium/ui/base/MimeTypeUtilsTest.java
@@ -19,8 +19,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.url.GURL; @@ -115,7 +113,7 @@ } @Test - @Config(shadows = {ShadowMimeTypeUtilsForT.class}) + @Config(sdk = VERSION_CODES.TIRAMISU) public void testPermissionForMimeTypeAndroidT() { assertEquals( "Wrong permission for audio mime type", @@ -137,13 +135,4 @@ private void updateMockGurlSpec(String spec) { doReturn(spec).when(mMockedUrl).getSpec(); } - - @Implements(MimeTypeUtils.class) - @SuppressWarnings("UnusedMethod") // Error Prone does not know about shadows. - private static class ShadowMimeTypeUtilsForT { - @Implementation - public static boolean useExternalStoragePermission() { - return false; - } - } }
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc index e8276d62..dc2e73d8 100644 --- a/ui/android/view_android.cc +++ b/ui/android/view_android.cc
@@ -10,10 +10,8 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" -#include "base/auto_reset.h" #include "base/containers/adapters.h" #include "base/containers/contains.h" -#include "base/debug/dump_without_crashing.h" #include "base/memory/raw_ptr.h" #include "base/not_fatal_until.h" #include "cc/slim/layer.h" @@ -277,12 +275,6 @@ } void ViewAndroid::RemoveAllChildren(bool attached_to_window) { - // Modifying children during hit testing can cause issues - // (crbug.com/407571917). Log a non-fatal report if this happens. - if (is_hit_testing_) { - base::debug::DumpWithoutCrashing(); - } - auto it = children_.begin(); while (it != children_.end()) { if (attached_to_window) @@ -302,11 +294,6 @@ std::list<raw_ptr<ViewAndroid, CtnExperimental>>::iterator it = std::ranges::find(children_, child); CHECK(it != children_.end(), base::NotFatalUntil::M130); - // Modifying children during hit testing can cause issues - // (crbug.com/407571917). Log a non-fatal report if this happens. - if (is_hit_testing_) { - base::debug::DumpWithoutCrashing(); - } children_.erase(it); child->parent_ = nullptr; } @@ -737,8 +724,6 @@ } } - base::AutoReset<bool> reset_is_hit_testing(&is_hit_testing_, true); - if (!children_.empty()) { gfx::PointF offset_point(point); offset_point.Offset(-bounds_dips_.x(), -bounds_dips_.y());
diff --git a/ui/android/view_android.h b/ui/android/view_android.h index e528d1e..8dca981 100644 --- a/ui/android/view_android.h +++ b/ui/android/view_android.h
@@ -320,11 +320,6 @@ const base::android::ScopedJavaLocalRef<jobject> GetViewAndroidDelegate() const; - // True if a hit test is currently being performed on this ViewAndroid or its - // descendants. This is used to detect and log cases where the view hierarchy - // is modified (e.g., a child is removed) during hit testing, which can lead - // to unexpected behavior or crashes. - bool is_hit_testing_ = false; std::list<raw_ptr<ViewAndroid, CtnExperimental>> children_; base::ObserverList<ViewAndroidObserver>::Unchecked observer_list_; scoped_refptr<cc::slim::Layer> layer_;
diff --git a/ui/compositor/debug_utils.cc b/ui/compositor/debug_utils.cc index 70ace71d0..12e380c 100644 --- a/ui/compositor/debug_utils.cc +++ b/ui/compositor/debug_utils.cc
@@ -59,8 +59,6 @@ break; case ui::LAYER_TEXTURED: *out << " textured"; - if (layer->fills_bounds_opaquely()) - *out << " opaque"; break; case ui::LAYER_SOLID_COLOR: *out << " solid"; @@ -70,6 +68,10 @@ break; } + if (layer->fills_bounds_opaquely()) { + *out << " opaque"; + } + if (!layer->visible()) *out << " !visible";
diff --git a/ui/display/BUILD.gn b/ui/display/BUILD.gn index e598004..491b8006 100644 --- a/ui/display/BUILD.gn +++ b/ui/display/BUILD.gn
@@ -69,6 +69,8 @@ "mac/display_link_mac.h", "mac/display_link_mac.mm", "mac/screen_mac.mm", + "mac/screen_mac_headless.h", + "mac/screen_mac_headless.mm", ] } @@ -147,6 +149,7 @@ } if (is_mac) { + deps += [ "//components/headless/screen_info" ] frameworks = [ "AppKit.framework", "CoreGraphics.framework",
diff --git a/ui/display/mac/DEPS b/ui/display/mac/DEPS new file mode 100644 index 0000000..4a3d7376 --- /dev/null +++ b/ui/display/mac/DEPS
@@ -0,0 +1,5 @@ +specific_include_rules = { + "screen_mac_headless\.mm": [ + "+components/headless/screen_info", + ], +}
diff --git a/ui/display/mac/screen_mac.mm b/ui/display/mac/screen_mac.mm index 874ac9d..033ebc00 100644 --- a/ui/display/mac/screen_mac.mm +++ b/ui/display/mac/screen_mac.mm
@@ -21,6 +21,8 @@ #include "base/apple/bridging.h" #include "base/apple/foundation_util.h" #include "base/apple/scoped_cftyperef.h" +#include "base/check_deref.h" +#include "base/command_line.h" #include "base/functional/bind.h" #include "base/i18n/rtl.h" #include "base/logging.h" @@ -32,11 +34,13 @@ #include "components/device_event_log/device_event_log.h" #include "ui/display/display.h" #include "ui/display/display_change_notifier.h" +#include "ui/display/mac/screen_mac_headless.h" #include "ui/display/util/display_util.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/icc_profile.h" #include "ui/gfx/mac/coordinate_conversion.h" #include "ui/gfx/native_widget_types.h" +#include "ui/gfx/switches.h" extern "C" { Boolean CGDisplayUsesForceToGray(void); @@ -611,6 +615,13 @@ } Screen* CreateNativeScreen() { + const base::CommandLine& command_line = + CHECK_DEREF(base::CommandLine::ForCurrentProcess()); + + if (command_line.HasSwitch(switches::kHeadless)) { + return new ScreenMacHeadless; + } + return new ScreenMac; }
diff --git a/ui/display/mac/screen_mac_headless.h b/ui/display/mac/screen_mac_headless.h new file mode 100644 index 0000000..708cd0b8 --- /dev/null +++ b/ui/display/mac/screen_mac_headless.h
@@ -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. + +#ifndef UI_DISPLAY_MAC_SCREEN_MAC_HEADLESS_H_ +#define UI_DISPLAY_MAC_SCREEN_MAC_HEADLESS_H_ + +#include "ui/display/display.h" +#include "ui/display/screen_base.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/native_widget_types.h" + +namespace display { + +class ScreenMacHeadless : public ScreenBase { + public: + ScreenMacHeadless(); + + ScreenMacHeadless(const ScreenMacHeadless&) = delete; + ScreenMacHeadless& operator=(const ScreenMacHeadless&) = delete; + + ~ScreenMacHeadless() override; + + // display::Screen overrides: + gfx::Point GetCursorScreenPoint() override; + bool IsWindowUnderCursor(gfx::NativeWindow window) override; + gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override; + gfx::NativeWindow GetLocalProcessWindowAtPoint( + const gfx::Point& point, + const std::set<gfx::NativeWindow>& ignore) override; + Display GetDisplayNearestWindow(gfx::NativeWindow window) const override; + bool IsHeadless() const override; + + private: + void CreateDisplayList(); +}; + +} // namespace display + +#endif // UI_DISPLAY_MAC_SCREEN_MAC_HEADLESS_H_
diff --git a/ui/display/mac/screen_mac_headless.mm b/ui/display/mac/screen_mac_headless.mm new file mode 100644 index 0000000..2ae6774 --- /dev/null +++ b/ui/display/mac/screen_mac_headless.mm
@@ -0,0 +1,125 @@ +// 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/display/mac/screen_mac_headless.h" + +#import <AppKit/AppKit.h> + +#include <vector> + +#include "base/check_deref.h" +#include "base/command_line.h" +#include "base/containers/flat_set.h" +#include "base/types/expected.h" +#include "components/headless/screen_info/headless_screen_info.h" +#include "ui/display/util/display_util.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/mac/coordinate_conversion.h" +#include "ui/gfx/switches.h" + +namespace display { + +namespace { + +// Headless display ids are synthesized sequential numbers. +constexpr int64_t kHeadlessDisplayIdBase = 1; + +std::vector<headless::HeadlessScreenInfo> GetHeadlessScreenInfos() { + std::vector<headless::HeadlessScreenInfo> screen_infos; + + const base::CommandLine& command_line = + CHECK_DEREF(base::CommandLine::ForCurrentProcess()); + + if (command_line.HasSwitch(switches::kScreenInfo)) { + const std::string switch_value = + command_line.GetSwitchValueASCII(switches::kScreenInfo); + base::expected<std::vector<headless::HeadlessScreenInfo>, std::string> + screen_infos_or_error = + headless::HeadlessScreenInfo::FromString(switch_value); + CHECK(screen_infos_or_error.has_value()) << screen_infos_or_error.error(); + screen_infos = screen_infos_or_error.value(); + } else { + screen_infos.push_back(headless::HeadlessScreenInfo()); + } + + return screen_infos; +} + +} // namespace + +ScreenMacHeadless::ScreenMacHeadless() { + CreateDisplayList(); +} + +ScreenMacHeadless::~ScreenMacHeadless() = default; + +void ScreenMacHeadless::CreateDisplayList() { + std::vector<headless::HeadlessScreenInfo> screen_infos = + GetHeadlessScreenInfos(); + CHECK(!screen_infos.empty()); + + bool is_primary = true; + base::flat_set<int64_t> internal_display_ids; + for (const headless::HeadlessScreenInfo& it : screen_infos) { + static int64_t synthesized_display_id = kHeadlessDisplayIdBase; + Display display(synthesized_display_id++); + display.set_label(it.label); + display.set_color_depth(it.color_depth); + display.SetScaleAndBounds(it.device_pixel_ratio, it.bounds); + + if (!it.work_area_insets.IsEmpty()) { + display.UpdateWorkAreaFromInsets(it.work_area_insets); + } + + if (it.rotation) { + CHECK(Display::IsValidRotation(it.rotation)); + display.SetRotationAsDegree(it.rotation); + } + + if (it.is_internal) { + internal_display_ids.insert(display.id()); + } + + ProcessDisplayChanged(display, is_primary); + is_primary = false; + } + + SetInternalDisplayIds(internal_display_ids); +} + +gfx::Point ScreenMacHeadless::GetCursorScreenPoint() { + return gfx::Point(); +} + +bool ScreenMacHeadless::IsWindowUnderCursor(gfx::NativeWindow window) { + return GetWindowAtScreenPoint(GetCursorScreenPoint()) == window; +} + +gfx::NativeWindow ScreenMacHeadless::GetWindowAtScreenPoint( + const gfx::Point& point) { + return gfx::NativeWindow(); +} + +gfx::NativeWindow ScreenMacHeadless::GetLocalProcessWindowAtPoint( + const gfx::Point& point, + const std::set<gfx::NativeWindow>& ignore) { + return gfx::NativeWindow(); +} + +Display ScreenMacHeadless::GetDisplayNearestWindow( + gfx::NativeWindow window) const { + if (window && GetNumDisplays() > 1) { + if (NSWindow* ns_window = window.GetNativeNSWindow()) { + const gfx::Rect bounds = gfx::ScreenRectFromNSRect([ns_window frame]); + return GetDisplayMatching(bounds); + } + } + return GetPrimaryDisplay(); +} + +bool ScreenMacHeadless::IsHeadless() const { + return true; +} + +} // namespace display
diff --git a/ui/events/event.cc b/ui/events/event.cc index 1c13f6a2..cff87755 100644 --- a/ui/events/event.cc +++ b/ui/events/event.cc
@@ -10,8 +10,6 @@ #include <string> #include <utility> -#include "base/debug/crash_logging.h" -#include "base/debug/dump_without_crashing.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram.h" @@ -888,24 +886,8 @@ // Check if this is a key repeat. This must be called before initial flags // processing, e.g: NormalizeFlags(), to avoid issues like crbug.com/1069690. - if (synthesize_key_repeat_enabled_ && IsRepeated(GetLastKeyEvent())) { - if (!(flags() & EF_IS_REPEAT) && !(code_ == DomCode::ALT_LEFT)) { - // If this branch is reached, it means that IsRepeated thinks this should - // be a repeat key event, while the native event repeat information was - // either incorrect or not preserved. This is unexpected, but execution - // is permitted to continue as it is no worse than the old behavior. - // - // An exception is made for Alt, which is known to cause IsRepeated to - // erroneously return true when Alt+Tab is used to rapidly toggle focus. - // - // TODO(https://crbug.com/411681432) Remove IsRepeated once it is deemed - // strictly redundant. - SCOPED_CRASH_KEY_STRING32("ui", "key_code", GetCodeString()); - SCOPED_CRASH_KEY_STRING32("ui", "key_event_type", GetName()); - base::debug::DumpWithoutCrashing(); - } + if (synthesize_key_repeat_enabled_ && IsRepeated(GetLastKeyEvent())) SetFlags(flags() | EF_IS_REPEAT); - } #if BUILDFLAG(IS_LINUX) NormalizeFlags();
diff --git a/ui/gfx/android/achoreographer_compat.cc b/ui/gfx/android/achoreographer_compat.cc index 49cccfa..e367f4a 100644 --- a/ui/gfx/android/achoreographer_compat.cc +++ b/ui/gfx/android/achoreographer_compat.cc
@@ -47,7 +47,8 @@ } AChoreographerCompat33::AChoreographerCompat33() { - if (!base::android::BuildInfo::GetInstance()->is_at_least_t()) { + if (base::android::BuildInfo::GetInstance()->sdk_int() < + base::android::SDK_VERSION_T) { supported = false; return; }
diff --git a/ui/gl/gl_features.cc b/ui/gl/gl_features.cc index 6aac7eb..ddd12a8f 100644 --- a/ui/gl/gl_features.cc +++ b/ui/gl/gl_features.cc
@@ -168,11 +168,11 @@ bool IsAndroidFrameDeadlineEnabled() { #if BUILDFLAG(IS_ANDROID) - static bool enabled = - base::android::BuildInfo::GetInstance()->is_at_least_t() && - gfx::AChoreographerCompat33::Get().supported && - gfx::SurfaceControl::SupportsSetFrameTimeline() && - gfx::SurfaceControl::SupportsSetEnableBackPressure(); + static bool enabled = base::android::BuildInfo::GetInstance()->sdk_int() >= + base::android::SDK_VERSION_T && + gfx::AChoreographerCompat33::Get().supported && + gfx::SurfaceControl::SupportsSetFrameTimeline() && + gfx::SurfaceControl::SupportsSetEnableBackPressure(); return enabled; #else return false;
diff --git a/ui/gtk/gtk_key_bindings_handler.cc b/ui/gtk/gtk_key_bindings_handler.cc index 291c428..48c8397 100644 --- a/ui/gtk/gtk_key_bindings_handler.cc +++ b/ui/gtk/gtk_key_bindings_handler.cc
@@ -68,8 +68,6 @@ ui::TextEditCommand::MOVE_UP}, {{ui::KeyboardCode::VKEY_P, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN}, ui::TextEditCommand::MOVE_UP_AND_MODIFY_SELECTION}, - {{ui::KeyboardCode::VKEY_T, ui::EF_CONTROL_DOWN}, - ui::TextEditCommand::TRANSPOSE}, {{ui::KeyboardCode::VKEY_U, ui::EF_CONTROL_DOWN}, ui::TextEditCommand::DELETE_TO_BEGINNING_OF_LINE}, {{ui::KeyboardCode::VKEY_W, ui::EF_CONTROL_DOWN},
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc index 66b8dcf..afa10e2 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view.cc +++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -397,21 +397,6 @@ this}; }; -class BubbleDialogDelegate::ThemeObserver : public ViewObserver { - public: - explicit ThemeObserver(BubbleDialogDelegate* delegate) : delegate_(delegate) { - observation_.Observe(delegate->GetContentsView()); - } - - void OnViewThemeChanged(views::View* view) override { - delegate_->UpdateColorsFromTheme(); - } - - private: - const raw_ptr<BubbleDialogDelegate> delegate_; - base::ScopedObservation<View, ViewObserver> observation_{this}; -}; - class BubbleDialogDelegateView::CloseOnDeactivatePin::Pins { public: Pins() = default; @@ -475,11 +460,9 @@ RegisterWidgetInitializedCallback(base::BindOnce( [](BubbleDialogDelegate* bubble_delegate) { - bubble_delegate->theme_observer_ = - std::make_unique<ThemeObserver>(bubble_delegate); // Call the theme callback to make sure the initial theme is picked up // by the BubbleDialogDelegate. - bubble_delegate->UpdateColorsFromTheme(); + bubble_delegate->UpdateFrameColor(); }, this)); @@ -727,6 +710,17 @@ } } +void BubbleDialogDelegate::SetBackgroundColor(ui::ColorVariant color) { + if (color_ == color) { + return; + } + + color_ = color; + if (GetWidget()) { + UpdateFrameColor(); + } +} + void BubbleDialogDelegate::SetArrow(BubbleBorder::Arrow arrow) { SetArrowWithoutResizing(arrow); // If SetArrow() is called before CreateWidget(), there's no need to update @@ -1133,7 +1127,7 @@ } } -void BubbleDialogDelegate::UpdateColorsFromTheme() { +void BubbleDialogDelegate::UpdateFrameColor() { View* const contents_view = GetContentsView(); DCHECK(contents_view);
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.h b/ui/views/bubble/bubble_dialog_delegate_view.h index 19ac071..9ff1a7e 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view.h +++ b/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -448,7 +448,7 @@ // be a good fit for the UI you are building. ui::ColorVariant background_color() const { return color_; } - void set_background_color(ui::ColorVariant color) { color_ = color; } + void SetBackgroundColor(ui::ColorVariant color); void set_force_create_contents_background( bool force_create_contents_background) { @@ -578,7 +578,6 @@ class AnchorViewObserver; class AnchorWidgetObserver; class BubbleWidgetObserver; - class ThemeObserver; FRIEND_TEST_ALL_PREFIXES(BubbleDialogDelegateViewTest, VisibleWidgetShowsInkDropOnAttaching); @@ -593,7 +592,6 @@ friend class AnchorWidgetObserver; friend class BubbleWidgetObserver; friend class TestBubbleUmaLogger; - friend class ThemeObserver; friend class BubbleBorderDelegate; friend class BubbleWindowTargeter; @@ -611,9 +609,7 @@ void OnBubbleWidgetPaintAsActiveChanged(); void OnDeactivate(); - - // Update the bubble color from the NativeTheme unless it was explicitly set. - void UpdateColorsFromTheme(); + void UpdateFrameColor(); // Notify this bubble that it is now the primary anchored bubble. When a new // bubble becomes the primary anchor, the previous primary silently loses its @@ -636,7 +632,6 @@ std::unique_ptr<AnchorViewObserver> anchor_view_observer_; std::unique_ptr<AnchorWidgetObserver> anchor_widget_observer_; std::unique_ptr<BubbleWidgetObserver> bubble_widget_observer_; - std::unique_ptr<ThemeObserver> theme_observer_; bool adjust_if_offscreen_ = true; bool focus_traversable_from_anchor_view_ = true; ViewTracker highlighted_button_tracker_; @@ -679,7 +674,7 @@ bool paint_client_to_layer_ = false; // If true, contents view will be forced to create a solid color background in - // UpdateColorsFromTheme(). + // `UpdateFrameColor()`. bool force_create_contents_background_ = false; #if BUILDFLAG(IS_MAC)
diff --git a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc index 19d2870..4d214f3 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc +++ b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
@@ -219,7 +219,7 @@ Widget::InitParams::CLIENT_OWNS_WIDGET, Widget::InitParams::TYPE_WINDOW); TestBubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); - bubble_delegate->set_background_color(SK_ColorGREEN); + bubble_delegate->SetBackgroundColor(SK_ColorGREEN); Widget* bubble_widget = BubbleDialogDelegateView::CreateBubble(bubble_delegate); EXPECT_EQ(bubble_delegate, bubble_widget->widget_delegate());
diff --git a/ui/views/examples/bubble_example.cc b/ui/views/examples/bubble_example.cc index 9f5f5c5..e11ce52 100644 --- a/ui/views/examples/bubble_example.cc +++ b/ui/views/examples/bubble_example.cc
@@ -140,7 +140,7 @@ // |bubble| will be destroyed by its widget when the widget is destroyed. auto bubble = std::make_unique<ExampleBubble>(*button, arrow); - bubble->set_background_color(colors[(color_index++) % std::size(colors)]); + bubble->SetBackgroundColor(colors[(color_index++) % std::size(colors)]); bubble->set_shadow(shadow); if (persistent) { bubble->set_close_on_deactivate(false);
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index ac502de..9a42a64f 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc
@@ -1015,17 +1015,6 @@ void HWNDMessageHandler::SizeConstraintsChanged() { LONG style = GetWindowLong(hwnd(), GWL_STYLE); - // Ignore if this is not a standard window. - if (style & static_cast<LONG>(WS_POPUP | WS_CHILD)) { - // Allow Glic to become resizable dynamically. - // TODO(404947780): this should be allowed for all widgets. thestig@ - // suggested to scope the change to glic and and let other widgets to bypass - // the restriction on their own schedule. - if (debugging_id() != "GlicWidget") { - return; - } - } - // Key style considerations: // - WS_THICKFRAME: Enables resizing. Cannot be used with translucent // windows (see CalculateWindowStylesFromInitParams() for details).
diff --git a/v8 b/v8 index 84b3ee9..7f56d60 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 84b3ee97fdd8f2df1e477b0cc79b893707da21b1 +Subproject commit 7f56d608e37d27607c638cdb4d9995bd7ad4d68c