diff --git a/AUTHORS b/AUTHORS index 4221dafb..6008db6 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -330,6 +330,7 @@ Dave Vandyke <kzar@kzar.co.uk> David Benjamin <davidben@mit.edu> David Brown <develop.david.brown@gmail.com> +David Cernoch <dcernoch@uplandsoftware.com> David Davidovic <david@davidovic.io> David Erceg <erceg.david@gmail.com> David Faden <dfaden@gmail.com>
diff --git a/DEPS b/DEPS index 1a7aa4dd..37f94eddb 100644 --- a/DEPS +++ b/DEPS
@@ -276,23 +276,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. - 'src_internal_revision': '7f38ae2436442ada9c5c9c059547f64e6961de04', + 'src_internal_revision': '014be7b57c088d653120c5997fea33b52107a768', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'c2b103c89e370ea00d0cc918c92d81fa712ff058', + 'skia_revision': 'a9e8d004f0ea4088f8a333cc36e7c019542fcf7e', # 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': '15c092afb8cad2be5d5a62d970ee38b16a14645b', + 'v8_revision': '4bd0d4731ea90ff9460eeb6d5cfc6cc1127363d3', # 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': '6dc14dedf85a49786d5503fdf5e692d87d57bb2d', + 'angle_revision': '0dabfe5a6ac5377854a3f5ee673d56315c175e71', # 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': 'f6ad529e86e441bad3210b0b714dca7faa99b0f8', + 'swiftshader_revision': '64af4180372914d6d3f37749a5fab2bc3f43a7f9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -300,11 +300,11 @@ # 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': 'bca2d72c5e3174f0e1b541fb0a3d6bdf31c23825', + 'boringssl_revision': 'd4b6eb542d4fd109baacd550935efd00c521e674', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Fuchsia sdk # and whatever else without interference from each other. - 'fuchsia_version': 'version:26.20250110.4.1', + 'fuchsia_version': 'version:26.20250117.5.1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling google-toolbox-for-mac # and whatever else without interference from each other. @@ -352,7 +352,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling chromium_variations # and whatever else without interference from each other. - 'chromium_variations_revision': 'ecd1b2bcb2bca351b58c2d19cf3f149c2ffea50f', + 'chromium_variations_revision': '187d83f8ee5fbe166ce2b668b65b67fa9b940c7f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. @@ -372,7 +372,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': 'd023fd41cb61a756301922cb329b5524c7e7110d', + 'devtools_frontend_revision': 'c6bb3b2ce900d42eefac9c72600ea69e74d40943', # 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. @@ -396,7 +396,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': '42451fad80b27c0fa7332b9d0566ff037d708b04', + 'dawn_revision': '4548f0cdeb8bef00bbce127760a0cda8bdaa9fb7', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -496,7 +496,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': '3fec72bd5608491ec977142db828cc42b88f0ef3', + 'llvm_libc_revision': '12809bfa855813dcef51871e2ee3155e53ed35ea', # If you change this, also update the libc++ revision in # //buildtools/deps_revisions.gni. @@ -1110,7 +1110,7 @@ }, 'src/chrome/release_scripts': { - 'url': Var('chrome_git') + '/chrome/tools/release/scripts' + '@' + 'b37cf13dae4ea8bdbff22cee2b4820c94c83bab8', + 'url': Var('chrome_git') + '/chrome/tools/release/scripts' + '@' + 'cc3ac97c66a56f4218fee70f28958eaf11ef5d66', 'condition': 'checkout_chrome_release_scripts', }, @@ -1439,7 +1439,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '327a12f72fb1020336bddcf8c48c34ca9807eea1', + '7305a3c6540fa265dc3796f66a575054fafab42a', 'condition': 'checkout_android and checkout_src_internal', }, @@ -1934,7 +1934,7 @@ 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'ea75de4c3baba538f4758d507dd304136cfeab52', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '80d1969422e75e8e9eecafa46074074b289e2568', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -2436,7 +2436,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c28325f6986bd765e5610569211234e403a47a0f', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '943a0d89925e7f9a898c2e49c41feb9bf5dab71e', 'src/base/tracing/test/data': { 'bucket': 'perfetto', @@ -2659,7 +2659,7 @@ Var('chromium_git') + '/external/github.com/google/ruy.git' + '@' + '83fd40d730feb0804fafbc2d8814bcc19a17b2e5', 'src/third_party/search_engines_data/resources': - Var('chromium_git') + '/external/search_engines_data.git' + '@' + '797c94d72b29932c8095bd7885ae26b7ed267db9', + Var('chromium_git') + '/external/search_engines_data.git' + '@' + '34ba850d314fced586dfaaf5b099c4906ce17b2d', 'src/third_party/skia': Var('skia_git') + '/skia.git' + '@' + Var('skia_revision'), @@ -2809,7 +2809,7 @@ Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'), 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '88833e6d22580fa7b358eb5ee551e1b4989fed71', + Var('webrtc_git') + '/src.git' + '@' + 'b0038dd14a1cc637ffbc48e36e55bd96452eef5d', # 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. @@ -2946,7 +2946,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'rLhPt0SI0dlLTaBTVzDCrJ1DBRAKAE3Z4lDnlE4qN_MC', + 'version': 'KJNjd5A4IUXeIHn-ur1hHdryL_rRrO6Pm5G3OC3bJ1MC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -2957,7 +2957,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'JJBjEL8Gb9xdnh0gAGWgHUNOOC8oxf9x3YtCDTFVgI4C', + 'version': 'r3XXx_HKMw-S2DL0iZxM2kfhbX1AGfC63plVgmnxV6cC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3422,17 +3422,6 @@ 'dep_type': 'cipd', }, - 'src/third_party/android_deps/cipd/libs/com_google_dagger_hilt_core': { - 'packages': [ - { - 'package': 'chromium/third_party/android_deps/libs/com_google_dagger_hilt_core', - 'version': 'version:2@2.52.cr1', - }, - ], - 'condition': 'checkout_android and non_git_source', - 'dep_type': 'cipd', - }, - 'src/third_party/android_deps/cipd/libs/com_google_errorprone_error_prone_annotations': { 'packages': [ { @@ -4549,7 +4538,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - '46e2e655940ecae3d363c4f438c1aabeaa5669e8', + '63647fd54313ac65206bb1093278b8e2e73bfcf8', 'condition': 'checkout_ios and checkout_src_internal', }, @@ -4561,7 +4550,7 @@ 'src/remoting/internal': { 'url': Var('chrome_git') + '/chrome/remoting/internal.git' + '@' + - 'bc8e5dbe2ea801d77d77ed8400e752f631f352a8', + 'f4b7da7fe40499ad775d1b2a730f4cd1de4ac05c', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/aw_feature_map.cc b/android_webview/browser/aw_feature_map.cc index 5cec4d4..ce3e6ef 100644 --- a/android_webview/browser/aw_feature_map.cc +++ b/android_webview/browser/aw_feature_map.cc
@@ -55,7 +55,6 @@ &sensitive_content::features::kSensitiveContent, &features::kWebViewWebauthn, &::features::kPrefetchBrowserInitiatedTriggers, - &features::kWebViewAutofillHandleFocusChange, }; // static
diff --git a/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc b/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc index dbe2a99..edf9187 100644 --- a/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc +++ b/android_webview/browser/gfx/viz_compositor_thread_runner_webview.cc
@@ -16,7 +16,6 @@ #include "base/task/thread_pool.h" #include "base/threading/thread_restrictions.h" #include "components/viz/common/features.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/frame_sinks/shared_image_interface_provider.h" #include "components/viz/service/gl/gpu_service_impl.h" @@ -76,16 +75,7 @@ void VizCompositorThreadRunnerWebView::InitFrameSinkManagerOnViz() { DCHECK_CALLED_ON_VALID_THREAD(viz_thread_checker_); - // Android doesn't support software compositing, but in some cases - // unaccelerated canvas can use SharedBitmaps as resource so we create - // SharedBitmapManager anyway. - // TODO(crbug.com/40120216): Stop using SharedBitmapManager after fixing - // fallback to SharedBitmap. - server_shared_bitmap_manager_ = - std::make_unique<viz::ServerSharedBitmapManager>(); - - auto init_params = viz::FrameSinkManagerImpl::InitParams( - server_shared_bitmap_manager_.get()); + auto init_params = viz::FrameSinkManagerImpl::InitParams(); if (features::UseWebViewNewInvalidateHeuristic()) { // HWUI has 2 frames pipelineing and we need another one because we force
diff --git a/android_webview/browser/gfx/viz_compositor_thread_runner_webview.h b/android_webview/browser/gfx/viz_compositor_thread_runner_webview.h index 22aa55f3..3f21a3f9 100644 --- a/android_webview/browser/gfx/viz_compositor_thread_runner_webview.h +++ b/android_webview/browser/gfx/viz_compositor_thread_runner_webview.h
@@ -20,7 +20,6 @@ namespace viz { class FrameSinkManagerImpl; -class ServerSharedBitmapManager; class SharedImageInterfaceProvider; } // namespace viz @@ -95,7 +94,6 @@ // Only accessed on |viz_task_runner_|. THREAD_CHECKER(viz_thread_checker_); - std::unique_ptr<viz::ServerSharedBitmapManager> server_shared_bitmap_manager_; std::unique_ptr<viz::FrameSinkManagerImpl> frame_sink_manager_; raw_ptr<viz::GpuServiceImpl> gpu_service_impl_ = nullptr; base::flat_set<base::PlatformThreadId> thread_ids_;
diff --git a/android_webview/common/aw_features.cc b/android_webview/common/aw_features.cc index 725f34e..2f892a2 100644 --- a/android_webview/common/aw_features.cc +++ b/android_webview/common/aw_features.cc
@@ -249,12 +249,4 @@ BASE_FEATURE(kWebViewInterceptedCookieHeaderReadWrite, "WebViewInterceptedCookieHeaderReadWrite", base::FEATURE_DISABLED_BY_DEFAULT); - -// Kill switch for autofill suggestions to be terminated when they are displayed -// above a soft keyboard and window losses focus. This is to prevent the -// suggestions of one app being shown in another app with active keyboard. -BASE_FEATURE(kWebViewAutofillHandleFocusChange, - "WebViewAutofillHandleFocusChange", - base::FEATURE_ENABLED_BY_DEFAULT); - } // namespace android_webview::features
diff --git a/android_webview/common/aw_features.h b/android_webview/common/aw_features.h index 11c3c674..5f81fd48 100644 --- a/android_webview/common/aw_features.h +++ b/android_webview/common/aw_features.h
@@ -52,7 +52,6 @@ BASE_DECLARE_FEATURE(kWebViewWebauthn); BASE_DECLARE_FEATURE(kWebViewInterceptedCookieHeader); BASE_DECLARE_FEATURE(kWebViewInterceptedCookieHeaderReadWrite); -BASE_DECLARE_FEATURE(kWebViewAutofillHandleFocusChange); } // namespace android_webview::features #endif // ANDROID_WEBVIEW_COMMON_AW_FEATURES_H_
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 223b2f8..1f1321af 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
@@ -160,21 +160,25 @@ void onSuccess(WebViewStartUpDiagnostics result); } - // TODO(gsennton): store aw-objects instead of adapters here - // Initialization guarded by mLock. - private AwBrowserContext mDefaultBrowserContext; - private SharedStatics mSharedStatics; - private GeolocationPermissionsAdapter mDefaultGeolocationPermissions; + @GuardedBy("mLock") private CookieManagerAdapter mDefaultCookieManager; + @GuardedBy("mLock") private WebIconDatabaseAdapter mWebIconDatabase; - private WebStorageAdapter mDefaultWebStorage; + + @GuardedBy("mLock") private WebViewDatabaseAdapter mDefaultWebViewDatabase; - private AwServiceWorkerController mDefaultServiceWorkerController; - private AwTracingController mAwTracingController; + + @GuardedBy("mLock") + private ChromiumStartedGlobals mChromiumStartedGlobals; + + @GuardedBy("mLock") private VariationsSeedLoader mSeedLoader; + + // This is only accessed during WebViewChromiumFactoryProvider.initialize() which is guarded by + // the WebViewFactory lock in the framework, and on the UI thread during startChromiumLocked + // which cannot be called before initialize() has completed. private Thread mSetUpResourcesThread; - private AwProxyController mAwProxyController; // Guards accees to the other members, and is notifyAll() signalled on the UI thread // when the chromium process has been started. @@ -240,20 +244,20 @@ public AwTracingController getAwTracingController() { synchronized (mLock) { - if (mAwTracingController == null) { + if (mChromiumStartedGlobals == null) { ensureChromiumStartedLocked(true, CallSite.GET_AW_TRACING_CONTROLLER); } + return mChromiumStartedGlobals.mAwTracingController; } - return mAwTracingController; } public AwProxyController getAwProxyController() { synchronized (mLock) { - if (mAwProxyController == null) { + if (mChromiumStartedGlobals == null) { ensureChromiumStartedLocked(true, CallSite.GET_AW_PROXY_CONTROLLER); } + return mChromiumStartedGlobals.mAwProxyController; } - return mAwProxyController; } public void setProviderInitOnMainLooperLocation(Throwable t) { @@ -266,7 +270,8 @@ // lives in the ui/ layer. See ui/base/ui_base_paths.h private static final int DIR_RESOURCE_PAKS_ANDROID = 3003; - protected void startChromiumLocked(@CallSite int callSite, boolean triggeredFromUIThread) { + @GuardedBy("mLock") + private void startChromiumLocked(@CallSite int callSite, boolean triggeredFromUIThread) { long startTime = SystemClock.uptimeMillis(); try (ScopedSysTraceEvent event = ScopedSysTraceEvent.scoped("WebViewChromiumAwInit.startChromiumLocked")) { @@ -362,11 +367,6 @@ AwBrowserProcess.loadComponents(); AwBrowserProcess.initializeMetricsLogUploader(); - mSharedStatics = new SharedStatics(); - if (BuildInfo.isDebugAndroidOrApp()) { - mSharedStatics.setWebContentsDebuggingEnabledUnconditionally(true); - } - RecordHistogram.recordSparseHistogram( "Android.WebView.TargetSdkVersion", context.getApplicationInfo().targetSdkVersion); @@ -374,18 +374,12 @@ try (ScopedSysTraceEvent e = ScopedSysTraceEvent.scoped( "WebViewChromiumAwInit.initThreadUnsafeSingletons")) { - // Initialize thread-unsafe singletons. - mDefaultBrowserContext = AwBrowserContext.getDefault(); - mDefaultGeolocationPermissions = - new GeolocationPermissionsAdapter( - mFactory, mDefaultBrowserContext.getGeolocationPermissions()); - mDefaultWebStorage = - new WebStorageAdapter( - mFactory, mDefaultBrowserContext.getQuotaManagerBridge()); - mAwTracingController = new AwTracingController(); - mDefaultServiceWorkerController = - mDefaultBrowserContext.getServiceWorkerController(); - mAwProxyController = new AwProxyController(); + mChromiumStartedGlobals = new ChromiumStartedGlobals(mFactory); + } + + if (BuildInfo.isDebugAndroidOrApp()) { + mChromiumStartedGlobals.mSharedStatics + .setWebContentsDebuggingEnabledUnconditionally(true); } if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) @@ -434,7 +428,7 @@ * * @param context The context. */ - public void setUpResourcesOnBackgroundThread(int packageId, Context context) { + void setUpResourcesOnBackgroundThread(int packageId, Context context) { try (ScopedSysTraceEvent e = ScopedSysTraceEvent.scoped( "WebViewChromiumAwInit.setUpResourcesOnBackgroundThread")) { @@ -486,8 +480,8 @@ // This method is not private only because the downstream subclass needs to access it, // it shouldn't be accessed from anywhere else. // Postcondition: Chromium startup is finished when this method returns. - /* package */ void ensureChromiumStartedLocked( - boolean fromThreadSafeFunction, @CallSite int callSite) { + @GuardedBy("mLock") + void ensureChromiumStartedLocked(boolean fromThreadSafeFunction, @CallSite int callSite) { assert Thread.holdsLock(mLock); ensureChromiumStartupHappensSoon(fromThreadSafeFunction, callSite); if (mInitState.get() == INIT_FINISHED) { // Early-out for the common case. @@ -513,6 +507,7 @@ // Postcondition: Chromium startup will be finished in the near future, but it may or may not be // finished after this method returns. + @GuardedBy("mLock") private void ensureChromiumStartupHappensSoon( boolean fromThreadSafeFunction, @CallSite int callSite) { assert Thread.holdsLock(mLock); @@ -602,14 +597,15 @@ } } - // Only on UI thread. + // This is called only on the same thread that initializes the variable, so + // no need to hold a lock. + @SuppressWarnings("GuardedBy") AwBrowserContext getDefaultBrowserContextOnUiThread() { - assert (mDefaultBrowserContext != null); if (BuildConfig.ENABLE_ASSERTS && !ThreadUtils.runningOnUiThread()) { throw new RuntimeException( "getBrowserContextOnUiThread called on " + Thread.currentThread()); } - return mDefaultBrowserContext; + return mChromiumStartedGlobals.mDefaultBrowserContext; } /** @@ -623,23 +619,23 @@ public SharedStatics getStatics() { synchronized (mLock) { - if (mSharedStatics == null) { + if (mChromiumStartedGlobals == null) { // TODO: Optimization potential: most of the static methods only need the native // library loaded and initialized, not the entire browser process started. ensureChromiumStartedLocked(true, CallSite.GET_STATICS); SharedStatics.setStartupTriggered(); } + return mChromiumStartedGlobals.mSharedStatics; } - return mSharedStatics; } public GeolocationPermissions getDefaultGeolocationPermissions() { synchronized (mLock) { - if (mDefaultGeolocationPermissions == null) { + if (mChromiumStartedGlobals == null) { ensureChromiumStartedLocked(true, CallSite.GET_DEFAULT_GEOLOCATION_PERMISSIONS); } + return mChromiumStartedGlobals.mDefaultGeolocationPermissions; } - return mDefaultGeolocationPermissions; } public CookieManager getDefaultCookieManager() { @@ -648,17 +644,17 @@ mDefaultCookieManager = new CookieManagerAdapter(AwCookieManager.getDefaultCookieManager()); } + return mDefaultCookieManager; } - return mDefaultCookieManager; } public AwServiceWorkerController getDefaultServiceWorkerController() { synchronized (mLock) { - if (mDefaultServiceWorkerController == null) { + if (mChromiumStartedGlobals == null) { ensureChromiumStartedLocked(true, CallSite.GET_DEFAULT_SERVICE_WORKER_CONTROLLER); } + return mChromiumStartedGlobals.mDefaultServiceWorkerController; } - return mDefaultServiceWorkerController; } public android.webkit.WebIconDatabase getWebIconDatabase() { @@ -668,17 +664,17 @@ if (mWebIconDatabase == null) { mWebIconDatabase = new WebIconDatabaseAdapter(); } + return mWebIconDatabase; } - return mWebIconDatabase; } public WebStorage getDefaultWebStorage() { synchronized (mLock) { - if (mDefaultWebStorage == null) { + if (mChromiumStartedGlobals == null) { ensureChromiumStartedLocked(true, CallSite.GET_DEFAULT_WEB_STORAGE); } + return mChromiumStartedGlobals.mDefaultWebStorage; } - return mDefaultWebStorage; } public WebViewDatabase getDefaultWebViewDatabase(final Context context) { @@ -689,10 +685,10 @@ new WebViewDatabaseAdapter( mFactory, HttpAuthDatabase.newInstance(context, HTTP_AUTH_DATABASE_FILE), - mDefaultBrowserContext); + mChromiumStartedGlobals.mDefaultBrowserContext); } + return mDefaultWebViewDatabase; } - return mDefaultWebViewDatabase; } // See comments in VariationsSeedLoader.java on when it's safe to call this. @@ -705,6 +701,7 @@ } } + @GuardedBy("mLock") private void finishVariationsInitLocked() { try (ScopedSysTraceEvent e = ScopedSysTraceEvent.scoped("WebViewChromiumAwInit.finishVariationsInitLocked")) { @@ -760,4 +757,29 @@ ensureChromiumStartupHappensSoon(true, CallSite.ASYNC_WEBVIEW_STARTUP); } } + + // These are objects that need to be created on the UI thread and after chromium has started. + // Thus created during startChromiumLocked for ease. + private static final class ChromiumStartedGlobals { + final AwBrowserContext mDefaultBrowserContext; + final GeolocationPermissionsAdapter mDefaultGeolocationPermissions; + final WebStorageAdapter mDefaultWebStorage; + final AwServiceWorkerController mDefaultServiceWorkerController; + final AwTracingController mAwTracingController; + final AwProxyController mAwProxyController; + final SharedStatics mSharedStatics; + + ChromiumStartedGlobals(WebViewChromiumFactoryProvider factory) { + mSharedStatics = new SharedStatics(); + mDefaultBrowserContext = AwBrowserContext.getDefault(); + mDefaultGeolocationPermissions = + new GeolocationPermissionsAdapter( + factory, mDefaultBrowserContext.getGeolocationPermissions()); + mDefaultWebStorage = + new WebStorageAdapter(factory, mDefaultBrowserContext.getQuotaManagerBridge()); + mAwTracingController = new AwTracingController(); + mDefaultServiceWorkerController = mDefaultBrowserContext.getServiceWorkerController(); + mAwProxyController = new AwProxyController(); + } + } }
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java index 813d087..1b06c23 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -879,7 +879,7 @@ @RequiresApi(Build.VERSION_CODES.P) @Override public TracingController getTracingController() { - synchronized (mAwInit.getLock()) { + synchronized (mAwInit.mLock) { mAwInit.ensureChromiumStartedLocked( true, WebViewChromiumAwInit.CallSite.GET_TRACING_CONTROLLER); // ensureChromiumStartedLocked() can release the lock on first call while
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 1a7e0fe..b7cdeaa5d 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -1673,11 +1673,11 @@ private void installWebContentsObservers() { if (mWebContentsObserver != null) { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); } mWebContentsObserver = new AwWebContentsObserver(mWebContents, this, mContentsClient); if (mAwWebContentsMetricsRecorder != null) { - mAwWebContentsMetricsRecorder.destroy(); + mAwWebContentsMetricsRecorder.observe(null); } mAwWebContentsMetricsRecorder = new AwWebContentsMetricsRecorder(mWebContents, mContext, mSettings); @@ -1909,9 +1909,9 @@ if (mCleanupReference != null) { assert mNativeAwContents != 0; - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; - mAwWebContentsMetricsRecorder.destroy(); + mAwWebContentsMetricsRecorder.observe(null); mAwWebContentsMetricsRecorder = null; mNativeAwContents = 0; mWebContents = null; @@ -4597,10 +4597,6 @@ mViewEventSink.onWindowFocusChanged(hasWindowFocus); mStylusWritingController.onWindowFocusChanged(hasWindowFocus); Clipboard.getInstance().onWindowFocusChanged(hasWindowFocus); - if (AwFeatureMap.isEnabled(AwFeatures.WEBVIEW_AUTOFILL_HANDLE_FOCUS_CHANGE) - && mAutofillProvider != null) { - mAutofillProvider.onWindowFocusChanged(hasWindowFocus); - } } @Override
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 86f8bab..6fe5fef8 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
@@ -1033,11 +1033,6 @@ BlinkFeatures.SPECULATIVE_IMAGE_DECODES, "Start decoding in-viewport images as soon as they have loaded, " + "rather than waiting for them to appear in a raster task."), - Flag.baseFeature( - AwFeatures.WEBVIEW_AUTOFILL_HANDLE_FOCUS_CHANGE, - "When enabled it terminates autofill suggestion after window focus loss"), - Flag.baseFeature( - "LayoutNGShapeCache", "Enables the text shaping cache for the performance."), // 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/CookieManagerTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerTest.java index 25c3559..e27ff1f2 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerTest.java
@@ -95,18 +95,6 @@ private static final String SECURE_COOKIE_HISTOGRAM_NAME = "Android.WebView.SecureCookieAction"; - private static final String ASSET_STATEMENT_TEMPLATE = - """ - [{ - "relation": ["delegate_permission/common.handle_all_urls"], - "target": { - "namespace": "android_app", - "package_name": "%s", - "sha256_cert_fingerprints": ["%s"] - } - }] - """; - public CookieManagerTest(AwSettingsMutation param) { this.mActivityTestRule = new AwActivityTestRule(param.getMutation()); } @@ -1454,15 +1442,7 @@ String unpartitionedCookie = "regular-cookie=456"; TestWebServer webServer = TestWebServer.start(); - // Add an asset statement to test storage access since we can auto grant - // under these circumstances. - webServer.setResponse( - "/.well-known/assetlinks.json", - String.format( - ASSET_STATEMENT_TEMPLATE, - BuildInfo.getInstance().hostPackageName, - BuildInfo.getInstance().getHostSigningCertSha256()), - null); + addServerAssetLinks(webServer); try { // TODO(crbug.com/41496912): The WebView cookie manager API does not currently @@ -1546,13 +1526,7 @@ @Features.EnableFeatures({AwFeatures.WEBVIEW_AUTO_SAA}) public void testAutoStorageAccessNetCookies() throws Throwable { TestWebServer webServer = TestWebServer.start(); - webServer.setResponse( - "/.well-known/assetlinks.json", - String.format( - ASSET_STATEMENT_TEMPLATE, - BuildInfo.getInstance().hostPackageName, - BuildInfo.getInstance().getHostSigningCertSha256()), - null); + addServerAssetLinks(webServer); // This test suite relies on an image to force a network request that has cookies attached. // The AwParameterizedTest will disable this setting so force enabling it again so that @@ -1628,6 +1602,98 @@ @Test @MediumTest @Feature({"AndroidWebView", "Privacy"}) + @Features.EnableFeatures({AwFeatures.WEBVIEW_AUTO_SAA}) + public void testAutoStorageAccessNotAllFrames() throws Throwable { + // This test confirms that when one frame is granted storage access, + // it is not granted to all frames from that site. + // It does this by: + // - loading an iframe + // - requesting storage access in this frame + // - then triggering a new iframe to be loaded at the top level + // - from the new iframe of the same site, try set a 3PC and report it + // + // That 3PC is expected to not be set because the second iframe should + // not have storage access granted. + TestWebServer webServer = TestWebServer.start(); + SettableFuture<Void> storageAccessFuture = SettableFuture.create(); + SettableFuture<String> secondFrameCookieFuture = SettableFuture.create(); + addServerAssetLinks(webServer); + + AwActivityTestRule.addJavascriptInterfaceOnUiThread( + mAwContents, + new Object() { + @JavascriptInterface + public void done() { + storageAccessFuture.set(null); + } + + @JavascriptInterface + public void reportCookies(String cookie) { + secondFrameCookieFuture.set(cookie); + } + }, + "testInterface"); + + try { + String iframeWithNetRequest = + """ + <html><body><script> + document.requestStorageAccess().then(() => { + testInterface.done(); + }); + </script></body></html> + """; + String iframeUrl = + toThirdPartyUrl(webServer.setResponse("/", iframeWithNetRequest, null)); + String url = makeIframeUrl(webServer, "/parent.html", iframeUrl); + + allowFirstPartyCookies(); + blockThirdPartyCookies(mAwContents); + + mActivityTestRule.loadUrlSync( + mAwContents, mContentsClient.getOnPageFinishedHelper(), url); + + // Wait until the first iframe has storage access granted... + AwActivityTestRule.waitForFuture(storageAccessFuture); + + // Once we have granted storage access to one frame, we then load another frame to + // ensure that we don't share storage access across all frames. + // This frame should not have access to unpartitioned cookies + // and so should not report any cookies after attempting to set them. + String reportCookies = + """ + <html><body><script> + document.cookie="blah=hello;"; + testInterface.reportCookies(document.cookie); + </script></body></html> + """; + + String secondFrameUrl = + toThirdPartyUrl(webServer.setResponse("/", reportCookies, null)); + + JavaScriptUtils.executeJavaScript( + mAwContents.getWebContents(), + String.format( + """ + const secondFrame = document.createElement("iframe"); + secondFrame.src="%s"; + document.body.appendChild(secondFrame);""", + secondFrameUrl)); + + String secondFrameCookieString = + AwActivityTestRule.waitForFuture(secondFrameCookieFuture); + Assert.assertEquals( + "Second frame should not have storage access granted.", + "", + secondFrameCookieString); + } finally { + webServer.shutdown(); + } + } + + @Test + @MediumTest + @Feature({"AndroidWebView", "Privacy"}) @CommandLineFlags.Add("disable-partitioned-cookies") @Features.EnableFeatures({AwFeatures.WEBVIEW_AUTO_SAA}) public void testDisabledPartitionedJSCookies() throws Throwable { @@ -1635,15 +1701,7 @@ String unpartitionedCookie = "regular-cookie=456"; TestWebServer webServer = TestWebServer.start(); - // Add an asset statement to test storage access since we can auto grant - // under these circumstances. - webServer.setResponse( - "/.well-known/assetlinks.json", - String.format( - ASSET_STATEMENT_TEMPLATE, - BuildInfo.getInstance().hostPackageName, - BuildInfo.getInstance().getHostSigningCertSha256()), - null); + addServerAssetLinks(webServer); try { // TODO(https://crbug.com/1523964): The WebView cookie manager API does not currently @@ -2401,6 +2459,26 @@ Assert.assertFalse(msg, mCookieManager.acceptCookie()); } + /** Adds an asset links json to allow SAA auto grants. */ + private void addServerAssetLinks(TestWebServer webServer) { + webServer.setResponse( + "/.well-known/assetlinks.json", + String.format( + """ + [{ + "relation": ["delegate_permission/common.handle_all_urls"], + "target": { + "namespace": "android_app", + "package_name": "%s", + "sha256_cert_fingerprints": ["%s"] + } + }] + """, + BuildInfo.getInstance().hostPackageName, + BuildInfo.getInstance().getHostSigningCertSha256()), + null); + } + interface IframeCookieSupplier { String get(boolean requestStorageAccess); }
diff --git a/android_webview/lib/BUILD.gn b/android_webview/lib/BUILD.gn index 0e38f632..127aa56 100644 --- a/android_webview/lib/BUILD.gn +++ b/android_webview/lib/BUILD.gn
@@ -33,6 +33,7 @@ "//components/spellcheck:buildflags", "//components/stylus_handwriting/android:android", "//components/variations", + "//components/variations:variations_associated_data", "//components/version_info", "//components/version_info/android:channel_getter", "//components/viz/common",
diff --git a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt index 8ac3e4f..2dd6f7fc 100644 --- a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt +++ b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
@@ -3412,7 +3412,6 @@ getter hostname getter href getter hreflang - getter interestAction getter interestTargetElement getter name getter origin @@ -3442,7 +3441,6 @@ setter hostname setter href setter hreflang - setter interestAction setter interestTargetElement setter name setter password @@ -3470,7 +3468,6 @@ getter host getter hostname getter href - getter interestAction getter interestTargetElement getter noHref getter origin @@ -3496,7 +3493,6 @@ setter host setter hostname setter href - setter interestAction setter interestTargetElement setter noHref setter password @@ -3602,7 +3598,6 @@ getter formMethod getter formNoValidate getter formTarget - getter interestAction getter interestTargetElement getter labels getter name @@ -3625,7 +3620,6 @@ setter formMethod setter formNoValidate setter formTarget - setter interestAction setter interestTargetElement setter name setter popoverTargetAction @@ -4281,7 +4275,6 @@ getter height getter incremental getter indeterminate - getter interestAction getter interestTargetElement getter labels getter list @@ -4342,7 +4335,6 @@ setter height setter incremental setter indeterminate - setter interestAction setter interestTargetElement setter max setter maxLength @@ -5450,8 +5442,7 @@ method getTargetRanges interface InterestEvent : Event attribute @@toStringTag - getter action - getter invoker + getter source method constructor interface IntersectionObserver attribute @@toStringTag @@ -7673,11 +7664,9 @@ interface SVGAElement : SVGGraphicsElement attribute @@toStringTag getter href - getter interestAction getter interestTargetElement getter target method constructor - setter interestAction setter interestTargetElement interface SVGAngle attribute @@toStringTag
diff --git a/ash/accessibility/magnifier/magnifier_glass.cc b/ash/accessibility/magnifier/magnifier_glass.cc index 3f8dd873..a68634b 100644 --- a/ash/accessibility/magnifier/magnifier_glass.cc +++ b/ash/accessibility/magnifier/magnifier_glass.cc
@@ -196,7 +196,6 @@ zoom_layer_ = std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR); zoom_layer_->SetBounds(window_bounds); zoom_layer_->SetBackgroundZoom(params_.scale, kZoomInset); - zoom_layer_->SetFillsBoundsOpaquely(false); root_layer->Add(zoom_layer_.get()); // Create a rounded rect clip, so that only we see a circle of the zoomed
diff --git a/ash/accessibility/mouse_keys/mouse_keys_controller.cc b/ash/accessibility/mouse_keys/mouse_keys_controller.cc index 34a44e8..650363a 100644 --- a/ash/accessibility/mouse_keys/mouse_keys_controller.cc +++ b/ash/accessibility/mouse_keys/mouse_keys_controller.cc
@@ -162,13 +162,17 @@ } void MouseKeysController::OnMouseEvent(ui::MouseEvent* event) { - bool is_synthesized = event->IsSynthesized() || - event->source_device_id() == ui::ED_UNKNOWN_DEVICE; - if (is_synthesized || event->type() != ui::EventType::kMouseMoved) { + if (event->type() != ui::EventType::kMouseMoved) { return; } + if (event->target()) { last_mouse_position_dips_ = event->target()->GetScreenLocation(*event); + + gfx::Point bubble_position = last_mouse_position_dips_; + bubble_position.Offset(16, 16); + mouse_keys_bubble_controller_->UpdateMouseKeysBubblePosition( + bubble_position); } }
diff --git a/ash/accessibility/mouse_keys/mouse_keys_unittest.cc b/ash/accessibility/mouse_keys/mouse_keys_unittest.cc index 915dda46..a412845 100644 --- a/ash/accessibility/mouse_keys/mouse_keys_unittest.cc +++ b/ash/accessibility/mouse_keys/mouse_keys_unittest.cc
@@ -333,6 +333,19 @@ prefs->SetDouble(prefs::kAccessibilityMouseKeysMaxSpeed, factor); } + gfx::Point GetLastMousePositionFromEvents() { + auto events = CheckForMouseEvents(); + EXPECT_FALSE(events.empty()); + return events.back().location(); + } + + void ShowMouseKeysBubble() { + EXPECT_FALSE(IsBubbleVisible()); + PressAndReleaseKey(ui::VKEY_OEM_COMMA); + EXPECT_TRUE(IsBubbleVisible()); + EXPECT_EQ(GetBubbleText(), u"Right mouse button"); + } + private: base::test::ScopedFeatureList scoped_feature_list_; TestEventCapturer event_capturer_; @@ -525,6 +538,7 @@ ClearEvents(); PressAndReleaseKey(ui::VKEY_W); EXPECT_EQ(0u, CheckForKeyEvents().size()); + LOG(ERROR) << "[LKupo] this is the first click event"; ExpectClick(CheckForMouseEvents(), ui::EF_LEFT_MOUSE_BUTTON, kDefaultPosition); @@ -620,6 +634,37 @@ EXPECT_EQ(mouse_events[0].location(), kDefaultPosition); } +TEST_F(MouseKeysTest, MouseKeysBubbleMovesWithMouse) { + // Initialize mouse and enable Mouse Keys. + GetEventGenerator()->MoveMouseToWithNative(kDefaultPosition, + kDefaultPosition); + SetEnabled(true); + ClearEvents(); + + // Get initial mouse position with a small move up-left. + PressAndReleaseKey(ui::VKEY_7); + gfx::Point initialMousePosition = GetLastMousePositionFromEvents(); + + // Show the bubble and get its initial position. + ShowMouseKeysBubble(); + gfx::Point initialBubblePosition = + GetBubbleView()->GetAnchorRect().CenterPoint(); + + // Simulate mouse movement up-left. + PressAndReleaseKey(ui::VKEY_7); + + // Get the final mouse position. + auto finalMousePosition = GetLastMousePositionFromEvents(); + + // Get the final bubble position. + gfx::Point finalBubblePosition = + GetBubbleView()->GetAnchorRect().CenterPoint(); + + // Verify mouse and bubble movements match. + EXPECT_EQ(finalMousePosition - initialMousePosition, + finalBubblePosition - initialBubblePosition); +} + TEST_F(MouseKeysTest, Move) { GetEventGenerator()->MoveMouseToWithNative(kDefaultPosition, kDefaultPosition);
diff --git a/ash/app_list/views/app_list_bubble_view.cc b/ash/app_list/views/app_list_bubble_view.cc index b01ac85..a15d0a9 100644 --- a/ash/app_list/views/app_list_bubble_view.cc +++ b/ash/app_list/views/app_list_bubble_view.cc
@@ -105,7 +105,6 @@ SeparatorWithLayer() { SetPaintToLayer(ui::LAYER_SOLID_COLOR); // Color is set in OnThemeChanged(). - layer()->SetFillsBoundsOpaquely(false); } SeparatorWithLayer(const SeparatorWithLayer&) = delete; SeparatorWithLayer& operator=(const SeparatorWithLayer&) = delete;
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc index d5aafe2..f93f27bf 100644 --- a/ash/app_list/views/app_list_folder_view.cc +++ b/ash/app_list/views/app_list_folder_view.cc
@@ -692,7 +692,6 @@ ColorProvider::kBackgroundBlurSigma); animating_background_->layer()->SetBackdropFilterQuality( ColorProvider::kBackgroundBlurQuality); - animating_background_->layer()->SetFillsBoundsOpaquely(false); } animating_background_->SetVisible(false);
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc index 5067ac9..c68bc9c2 100644 --- a/ash/app_list/views/app_list_item_view.cc +++ b/ash/app_list/views/app_list_item_view.cc
@@ -663,7 +663,6 @@ icon_background_ = AddChildView(std::make_unique<views::View>()); icon_background_->SetPaintToLayer(ui::LAYER_SOLID_COLOR); - icon_background_->layer()->SetFillsBoundsOpaquely(false); icon_background_->SetCanProcessEventsWithinSubtree(false); icon_background_->SetVisible(is_folder_);
diff --git a/ash/app_list/views/assistant/assistant_page_view.cc b/ash/app_list/views/assistant/assistant_page_view.cc index e9098ed..9e7ee7f 100644 --- a/ash/app_list/views/assistant/assistant_page_view.cc +++ b/ash/app_list/views/assistant/assistant_page_view.cc
@@ -413,7 +413,6 @@ void AssistantPageView::InitLayout() { // Use a solid color layer. The color is set in OnThemeChanged(). SetPaintToLayer(ui::LAYER_SOLID_COLOR); - layer()->SetFillsBoundsOpaquely(!chromeos::features::IsSystemBlurEnabled()); view_shadow_ = std::make_unique<views::ViewShadow>(this, kShadowElevation); view_shadow_->SetRoundedCornerRadius(
diff --git a/ash/app_list/views/top_icon_animation_view.cc b/ash/app_list/views/top_icon_animation_view.cc index 957f4845..1bae598 100644 --- a/ash/app_list/views/top_icon_animation_view.cc +++ b/ash/app_list/views/top_icon_animation_view.cc
@@ -47,7 +47,6 @@ icon_background_ = AddChildView(std::make_unique<views::View>()); if (item_in_folder_icon_) { icon_background_->SetPaintToLayer(ui::LAYER_SOLID_COLOR); - icon_background_->layer()->SetFillsBoundsOpaquely(false); } else { const int background_diameter = app_list_config->GetShortcutBackgroundContainerDimension();
diff --git a/ash/capture_mode/capture_mode_api.cc b/ash/capture_mode/capture_mode_api.cc index 0d7af950..b41b338b 100644 --- a/ash/capture_mode/capture_mode_api.cc +++ b/ash/capture_mode/capture_mode_api.cc
@@ -23,20 +23,36 @@ bool IsSunfishOrScannerEnabled() { // Returns true if sunfish session can be started, which is true if either the - // Sunfish or Scanner feature flag is enabled. Note Scanner operations will - // only be available if the secret key is matched. + // Sunfish or Scanner feature flag is enabled. return features::IsSunfishFeatureEnabled() || features::IsScannerEnabled(); } bool IsSunfishAllowedAndEnabled() { + if (!IsSunfishOrScannerEnabled()) { + return false; + } + Shell* shell = Shell::HasInstance() ? Shell::Get() : nullptr; - return IsSunfishOrScannerEnabled() && - // When `AppListControllerImpl` is initialised and indirectly calls - // this function, the active user session has not been started yet. - // Gracefully handle this case. - shell && shell->session_controller()->IsActiveUserSessionStarted() && - capture_mode_util::GetActiveUserPrefService()->GetBoolean( - prefs::kSunfishEnabled); + if (!shell) { + return false; + } + + // Order here matters: When `AppListControllerImpl` is initialised and + // indirectly calls this function, the active user session has not been + // started yet. Gracefully handle this case. + auto* session_controller = shell->session_controller(); + if (!session_controller || + !session_controller->IsActiveUserSessionStarted()) { + return false; + } + + auto* pref_service = capture_mode_util::GetActiveUserPrefService(); + if (!pref_service || !pref_service->GetBoolean(prefs::kSunfishEnabled)) { + return false; + } + + auto* controller = CaptureModeController::Get(); + return controller && controller->IsSearchAllowedByPolicy(); } } // namespace ash
diff --git a/ash/capture_mode/capture_mode_controller.cc b/ash/capture_mode/capture_mode_controller.cc index 55bad6c..598d98aa 100644 --- a/ash/capture_mode/capture_mode_controller.cc +++ b/ash/capture_mode/capture_mode_controller.cc
@@ -814,6 +814,10 @@ CaptureModeDelegate::CapturePathEnforcement::kManaged; } +bool CaptureModeController::IsSearchAllowedByPolicy() const { + return delegate_->IsSearchAllowedByPolicy(); +} + bool CaptureModeController::IsAudioRecordingInProgress() const { return video_recording_watcher_ && !video_recording_watcher_->is_shutting_down() &&
diff --git a/ash/capture_mode/capture_mode_controller.h b/ash/capture_mode/capture_mode_controller.h index 37a2096..7fc3cec 100644 --- a/ash/capture_mode/capture_mode_controller.h +++ b/ash/capture_mode/capture_mode_controller.h
@@ -171,6 +171,9 @@ // `ScreenCaptureLocation` policy and can't be changed. bool IsCustomFolderManagedByPolicy() const; + // Returns true if Search is allowed. + bool IsSearchAllowedByPolicy() const; + // Returns true if there's an active video recording that is recording audio. bool IsAudioRecordingInProgress() const;
diff --git a/ash/capture_mode/sunfish_unittest.cc b/ash/capture_mode/sunfish_unittest.cc index 28a24f6..bab693a 100644 --- a/ash/capture_mode/sunfish_unittest.cc +++ b/ash/capture_mode/sunfish_unittest.cc
@@ -517,6 +517,23 @@ EXPECT_FALSE(capture_label->GetVisible()); } +// Tests the Search button does not show in default mode. +TEST_F(SunfishTest, CheckSearchPolicy) { + auto* controller = + StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kImage); + auto* test_delegate = + static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing()); + test_delegate->set_is_search_allowed_by_policy(false); + + // Start default session. Test the Search button does not show. + SelectCaptureModeRegion(GetEventGenerator(), gfx::Rect(100, 100, 600, 500), + /*release_mouse=*/true, /*verify_region=*/false); + WaitForCaptureModeWidgetsVisible(); + CaptureModeSessionTestApi session_test_api( + controller->capture_mode_session()); + ASSERT_THAT(session_test_api.GetActionButtons(), IsEmpty()); +} + // Tests that sunfish checks DLP restrictions upon selecting a region. TEST_F(SunfishTest, CheckDlpRestrictions) { auto* controller = CaptureModeController::Get();
diff --git a/ash/capture_mode/test_capture_mode_delegate.cc b/ash/capture_mode/test_capture_mode_delegate.cc index 163176c..30fbef95 100644 --- a/ash/capture_mode/test_capture_mode_delegate.cc +++ b/ash/capture_mode/test_capture_mode_delegate.cc
@@ -110,6 +110,10 @@ return is_allowed_by_policy_; } +bool TestCaptureModeDelegate::IsSearchAllowedByPolicy() const { + return is_search_allowed_by_policy_; +} + void TestCaptureModeDelegate::StartObservingRestrictedContent( const aura::Window* window, const gfx::Rect& bounds,
diff --git a/ash/capture_mode/test_capture_mode_delegate.h b/ash/capture_mode/test_capture_mode_delegate.h index 8f401359..3c9092b 100644 --- a/ash/capture_mode/test_capture_mode_delegate.h +++ b/ash/capture_mode/test_capture_mode_delegate.h
@@ -46,6 +46,9 @@ } void set_is_allowed_by_dlp(bool value) { is_allowed_by_dlp_ = value; } void set_is_allowed_by_policy(bool value) { is_allowed_by_policy_ = value; } + void set_is_search_allowed_by_policy(bool value) { + is_search_allowed_by_policy_ = value; + } void set_should_save_after_dlp_check(bool value) { should_save_after_dlp_check_ = value; } @@ -105,6 +108,7 @@ const gfx::Rect& bounds, OnCaptureModeDlpRestrictionChecked callback) override; bool IsCaptureAllowedByPolicy() const override; + bool IsSearchAllowedByPolicy() const override; void StartObservingRestrictedContent( const aura::Window* window, const gfx::Rect& bounds, @@ -169,6 +173,7 @@ bool is_session_active_ = false; bool is_allowed_by_dlp_ = true; bool is_allowed_by_policy_ = true; + bool is_search_allowed_by_policy_ = true; bool should_save_after_dlp_check_ = true; bool is_camera_disabled_by_policy_ = false; bool is_audio_capture_disabled_by_policy_ = false;
diff --git a/ash/capture_mode/user_nudge_controller.cc b/ash/capture_mode/user_nudge_controller.cc index b69e58a..454bb56 100644 --- a/ash/capture_mode/user_nudge_controller.cc +++ b/ash/capture_mode/user_nudge_controller.cc
@@ -68,10 +68,8 @@ DarkLightModeControllerImpl::Get()->IsDarkModeEnabled() ? SK_ColorWHITE : SK_ColorBLACK; base_ring_.SetColor(ring_color); - base_ring_.SetFillsBoundsOpaquely(false); base_ring_.SetOpacity(0); ripple_ring_.SetColor(ring_color); - ripple_ring_.SetFillsBoundsOpaquely(false); ripple_ring_.SetOpacity(0); Reposition();
diff --git a/ash/public/cpp/capture_mode/capture_mode_delegate.h b/ash/public/cpp/capture_mode/capture_mode_delegate.h index bab33d4d..87efe71 100644 --- a/ash/public/cpp/capture_mode/capture_mode_delegate.h +++ b/ash/public/cpp/capture_mode/capture_mode_delegate.h
@@ -124,6 +124,9 @@ // Returns whether screen capture is allowed by an enterprise policy. virtual bool IsCaptureAllowedByPolicy() const = 0; + // Returns whether search is allowed by the browser enterprise policy. + virtual bool IsSearchAllowedByPolicy() const = 0; + // Called when a video capture for |window| and |bounds| area is started, so // that Data Leak Prevention can start observing the area. // |on_area_restricted_callback| will be called when the area becomes
diff --git a/ash/rotator/screen_rotation_animator.cc b/ash/rotator/screen_rotation_animator.cc index 7d03ac84a..f319849 100644 --- a/ash/rotator/screen_rotation_animator.cc +++ b/ash/rotator/screen_rotation_animator.cc
@@ -29,6 +29,7 @@ #include "ui/compositor/layer_animator.h" #include "ui/compositor/layer_owner.h" #include "ui/compositor/layer_tree_owner.h" +#include "ui/compositor/layer_type.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/display/display.h" #include "ui/display/manager/display_manager.h" @@ -367,12 +368,10 @@ GetScreenRotationContainer(root_window_)->layer()->size(); std::unique_ptr<ui::Layer> copy_layer = CreateLayerFromCopyOutputResult(std::move(result), layer_size); + CHECK_EQ(copy_layer->type(), ui::LAYER_SOLID_COLOR); DCHECK_EQ(copy_layer->size(), GetScreenRotationContainer(root_window_)->layer()->size()); - // TODO(crbug.com/40113966): This is a workaround and should be removed once - // the issue is fixed. - copy_layer->SetFillsBoundsOpaquely(false); return std::make_unique<ui::LayerTreeOwner>(std::move(copy_layer)); }
diff --git a/ash/style/counter_expand_button.cc b/ash/style/counter_expand_button.cc index 69cf4c7e..f7b9c90 100644 --- a/ash/style/counter_expand_button.cc +++ b/ash/style/counter_expand_button.cc
@@ -74,7 +74,6 @@ views::FocusRing::Get(this)->SetOutsetFocusRingDisabled(true); SetPaintToLayer(ui::LAYER_SOLID_COLOR); - layer()->SetFillsBoundsOpaquely(false); layer()->SetRoundedCornerRadius(gfx::RoundedCornersF{kTrayItemCornerRadius}); layer()->SetIsFastRoundedCorner(true); }
diff --git a/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller.cc b/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller.cc index c032fee8..e126f9d 100644 --- a/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller.cc +++ b/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller.cc
@@ -26,21 +26,24 @@ } } +void MouseKeysBubbleController::UpdateMouseKeysBubblePosition( + gfx::Point position) { + if (mouse_keys_bubble_view_) { + mouse_keys_bubble_view_->SetAnchorRect(gfx::Rect(position, gfx::Size())); + } +} + void MouseKeysBubbleController::UpdateBubble( bool visible, MouseKeysBubbleIconType icon, const std::optional<std::u16string>& text) { EnsureInitialize(); - gfx::Point cursor_position = + gfx::Point bubble_position = Shell::Get()->mouse_keys_controller()->GetLastMousePositionDips(); - cursor_position.Offset(16, 16); + bubble_position.Offset(16, 16); - if (mouse_keys_bubble_view_) { - mouse_keys_bubble_view_->SetAnchorRect( - gfx::Rect(cursor_position, gfx::Size())); - } - + UpdateMouseKeysBubblePosition(bubble_position); Update(icon, text); widget_->SetVisible(visible); if (timer_.IsRunning()) {
diff --git a/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller.h b/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller.h index 8ee0c5a..73c1e3b 100644 --- a/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller.h +++ b/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller.h
@@ -33,6 +33,8 @@ delete; ~MouseKeysBubbleController() override; + void UpdateMouseKeysBubblePosition(gfx::Point position); + // Updates the bubble's visibility and text content. void UpdateBubble(bool visible, MouseKeysBubbleIconType icon,
diff --git a/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller_unittest.cc b/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller_unittest.cc index d617130..c5eee49 100644 --- a/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller_unittest.cc +++ b/ash/system/accessibility/mouse_keys/mouse_keys_bubble_controller_unittest.cc
@@ -88,4 +88,4 @@ EXPECT_FALSE(IsBubbleVisible()); } -} // namespace ash +} // namespace ash \ No newline at end of file
diff --git a/ash/system/privacy/privacy_indicators_tray_item_view.cc b/ash/system/privacy/privacy_indicators_tray_item_view.cc index 7927ce7..08d2bd3 100644 --- a/ash/system/privacy/privacy_indicators_tray_item_view.cc +++ b/ash/system/privacy/privacy_indicators_tray_item_view.cc
@@ -165,7 +165,6 @@ // Set up a solid color layer to paint the background color, then add a layer // to each child so that they are visible and can perform layer animation. SetPaintToLayer(ui::LAYER_SOLID_COLOR); - layer()->SetFillsBoundsOpaquely(false); layer()->SetRoundedCornerRadius( gfx::RoundedCornersF{kPrivacyIndicatorsViewExpandedShorterSideSize / 2}); layer()->SetIsFastRoundedCorner(true); @@ -173,7 +172,6 @@ auto add_icon_to_container = [&container_view]() { auto icon = std::make_unique<views::ImageView>(); icon->SetPaintToLayer(); - icon->layer()->SetFillsBoundsOpaquely(false); icon->SetVisible(false); return container_view->AddChildView(std::move(icon)); };
diff --git a/ash/system/privacy/privacy_indicators_tray_item_view_pixeltest.cc b/ash/system/privacy/privacy_indicators_tray_item_view_pixeltest.cc index 131b874..3a5975b 100644 --- a/ash/system/privacy/privacy_indicators_tray_item_view_pixeltest.cc +++ b/ash/system/privacy/privacy_indicators_tray_item_view_pixeltest.cc
@@ -75,7 +75,7 @@ SimulateAnimateToFullyExpandedState(privacy_indicators_view); EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( "full_view" + GetScreenshotNameSuffix(), - /*revision_number=*/1, notification_center_tray)); + /*revision_number=*/2, notification_center_tray)); SimulateAnimationEnded(privacy_indicators_view); EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc index 269b241..dac5365f 100644 --- a/ash/system/tray/tray_background_view.cc +++ b/ash/system/tray/tray_background_view.cc
@@ -298,7 +298,6 @@ // Use layer color to provide background color. Note that children views // need to have their own layers to be visible. SetPaintToLayer(ui::LAYER_SOLID_COLOR); - layer()->SetFillsBoundsOpaquely(!chromeos::features::IsSystemBlurEnabled()); // Start the tray items not visible, because visibility changes are animated. views::View::SetVisible(false);
diff --git a/ash/system/unified/power_button.cc b/ash/system/unified/power_button.cc index 2d0c30d..6a87f7178 100644 --- a/ash/system/unified/power_button.cc +++ b/ash/system/unified/power_button.cc
@@ -398,7 +398,6 @@ background_view_->SetPaintToLayer(ui::LAYER_SOLID_COLOR); auto* background_layer = background_view_->layer(); background_layer->SetRoundedCornerRadius(kAllRoundedCorners); - background_layer->SetFillsBoundsOpaquely(false); background_layer->SetIsFastRoundedCorner(true); set_context_menu_controller(context_menu_.get());
diff --git a/ash/system/video_conference/bubble/title_view.cc b/ash/system/video_conference/bubble/title_view.cc index da69a48..a7957b3 100644 --- a/ash/system/video_conference/bubble/title_view.cc +++ b/ash/system/video_conference/bubble/title_view.cc
@@ -107,7 +107,6 @@ background_view_->SetPaintToLayer(ui::LAYER_SOLID_COLOR); auto* background_layer = background_view_->layer(); background_layer->SetRoundedCornerRadius(gfx::RoundedCornersF(16)); - background_layer->SetFillsBoundsOpaquely(false); button_container_ = AddChildView(std::make_unique<MicTestButtonContainer>(base::BindRepeating(
diff --git a/ash/user_education/welcome_tour/welcome_tour_scrim.cc b/ash/user_education/welcome_tour/welcome_tour_scrim.cc index e03ae7f..4bb3528 100644 --- a/ash/user_education/welcome_tour/welcome_tour_scrim.cc +++ b/ash/user_education/welcome_tour/welcome_tour_scrim.cc
@@ -208,7 +208,6 @@ // Invoked once to initialize `this` scrim. void Init() { // Configure static scrim layer properties. - layer_owner_.layer()->SetFillsBoundsOpaquely(false); layer_owner_.layer()->SetMaskLayer(mask_layer_owner_.layer()); layer_owner_.layer()->SetName(WelcomeTourScrim::kLayerName);
diff --git a/ash/utility/layer_copy_animator.cc b/ash/utility/layer_copy_animator.cc index a3d0eb5..1a14aaf0 100644 --- a/ash/utility/layer_copy_animator.cc +++ b/ash/utility/layer_copy_animator.cc
@@ -10,6 +10,7 @@ #include "ui/base/class_property.h" #include "ui/compositor/layer_animation_sequence.h" #include "ui/compositor/layer_animator.h" +#include "ui/compositor/layer_type.h" DEFINE_UI_CLASS_PROPERTY_TYPE(ash::LayerCopyAnimator*) @@ -114,7 +115,7 @@ } void LayerCopyAnimator::RunAnimation() { - copied_layer_->SetFillsBoundsOpaquely(false); + CHECK_EQ(copied_layer_->type(), ui::LAYER_SOLID_COLOR); auto* parent_layer = window_->layer()->parent(); parent_layer->Add(copied_layer_.get());
diff --git a/ash/webui/common/resources/BUILD.gn b/ash/webui/common/resources/BUILD.gn index d43efa9d..88e345c 100644 --- a/ash/webui/common/resources/BUILD.gn +++ b/ash/webui/common/resources/BUILD.gn
@@ -30,7 +30,6 @@ "multidevice_setup/setup_succeeded_page.js", "multidevice_setup/start_setup_page.js", "multidevice_setup/ui_page.js", - "network/apn_list_item.js", "network/cr_policy_network_indicator_mojo.js", "network/network_config_select.js", "network/network_config_toggle.js", @@ -102,6 +101,7 @@ "bluetooth/bluetooth_pairing_ui.ts", "bluetooth/bluetooth_spinner_page.ts", "network/apn_list.ts", + "network/apn_list_item.ts", "network/apn_selection_dialog.ts", "network/network_apnlist.ts", "network/network_choose_mobile.ts", @@ -451,6 +451,7 @@ "multidevice_setup/ui_page.js", "navigation_shared_vars.css.js", "network/apn_list.html.js", + "network/apn_list_item.html.js", "network/apn_selection_dialog.html.js", "network/cellular_utils.js", "network/cr_policy_network_behavior_mojo.js", @@ -537,7 +538,6 @@ "network/apn_detail_dialog.d.ts", "network/apn_selection_dialog_list_item.d.ts", - "network/apn_list_item.d.ts", "network/cr_policy_network_indicator_mojo.d.ts", "network/network_config_select.d.ts", "network/network_config_toggle.d.ts",
diff --git a/ash/webui/common/resources/network/apn_list.html b/ash/webui/common/resources/network/apn_list.html index 5fdba4b..cf59196 100644 --- a/ash/webui/common/resources/network/apn_list.html +++ b/ash/webui/common/resources/network/apn_list.html
@@ -95,7 +95,7 @@ <template> <apn-list-item apn="[[item]]" - is-connected="[[isApnConnected_(index, managedCellularProperties)]]" + is-apn-connected="[[isApnConnected_(index, managedCellularProperties)]]" should-disallow-disabling-removing="[[shouldDisallowDisablingRemoving_(item)]]" should-disallow-enabling="[[shouldDisallowEnabling_(item)]]" should-disallow-apn-modification="[[shouldDisallowApnModification]]"
diff --git a/ash/webui/common/resources/network/apn_list_item.d.ts b/ash/webui/common/resources/network/apn_list_item.d.ts deleted file mode 100644 index 8e110a25..0000000 --- a/ash/webui/common/resources/network/apn_list_item.d.ts +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {I18nMixin} from '//resources/ash/common/cr_elements/i18n_mixin.js'; -import {ApnProperties} from '//resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; -import {PortalState} from '//resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; -import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -export class ApnListItem extends I18nMixin -(PolymerElement) { -guid: - string; -apn: - ApnProperties; -isConnected: - boolean; -shouldDisallowDisablingRemoving: - boolean; -shouldDisallowEnabling: - boolean; -shouldDisallowApnModification: - boolean; -itemIndex: - number; -listSize: - number; -portalState: - PortalState|null; -private isDisabled_: - boolean; -private isApnRevampAndAllowApnModificationPolicyEnabled_: - boolean; -} - -declare global { - interface HTMLElementTagNameMap { - 'apn-list-item': ApnListItem; - } -}
diff --git a/ash/webui/common/resources/network/apn_list_item.html b/ash/webui/common/resources/network/apn_list_item.html index 7b6350b3..c230193 100644 --- a/ash/webui/common/resources/network/apn_list_item.html +++ b/ash/webui/common/resources/network/apn_list_item.html
@@ -53,16 +53,16 @@ </div> </div> <div id="subLabel" class="cr-secondary-text" aria-hidden="true" - hidden="[[!isConnected]]" + hidden="[[!isApnConnected]]" warning$="[[isPortalStateNoInternet_(portalState)]]"> - [[getSublabel_(isConnected, portalState)]] + [[getSublabel_(isApnConnected, portalState)]] </div> </div> <cr-icon-button id="actionMenuButton" class="icon-more-vert" on-click="onMenuButtonClicked_" title="[[i18n('apnMoreActionsTitle', apn.accessPointName)]]" focus-row-control focus-type="menu" - aria-label="[[getAriaLabel_(apn, itemIndex, listSize, isConnected, + aria-label="[[getAriaLabel_(apn, itemIndex, listSize, isApnConnected, isDisabled_)]]"> </cr-icon-button>
diff --git a/ash/webui/common/resources/network/apn_list_item.js b/ash/webui/common/resources/network/apn_list_item.ts similarity index 72% rename from ash/webui/common/resources/network/apn_list_item.js rename to ash/webui/common/resources/network/apn_list_item.ts index 2494adc..7d72bb85 100644 --- a/ash/webui/common/resources/network/apn_list_item.js +++ b/ash/webui/common/resources/network/apn_list_item.ts
@@ -9,28 +9,23 @@ import './network_shared.css.js'; import '//resources/ash/common/cr_elements/cr_action_menu/cr_action_menu.js'; -import {assert} from '//resources/ash/common/assert.js'; -import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; -import {ApnDetailDialogMode, ApnEventData, getApnDisplayName} from '//resources/ash/common/network/cellular_utils.js'; -import {MojoInterfaceProviderImpl} from '//resources/ash/common/network/mojo_interface_provider.js'; -import {ApnState, ApnType} from '//resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; +import type {CrActionMenuElement} from '//resources/ash/common/cr_elements/cr_action_menu/cr_action_menu.js'; +import {I18nMixin} from '//resources/ash/common/cr_elements/i18n_mixin.js'; +import {assert} from '//resources/js/assert.js'; +import {ApnProperties, ApnState, ApnType, CrosNetworkConfigInterface} from '//resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; import {PortalState} from '//resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; -import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {getTemplate} from './apn_list_item.html.js'; +import {ApnDetailDialogMode, ApnEventData, getApnDisplayName} from './cellular_utils.js'; +import {MojoInterfaceProviderImpl} from './mojo_interface_provider.js'; -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const ApnListItemBase = mixinBehaviors([I18nBehavior], PolymerElement); +const ApnListItemBase = I18nMixin(PolymerElement); -/** @polymer */ -export class ApnListItem extends ApnListItemBase { +export class ApnListItemElement extends ApnListItemBase { static get is() { - return 'apn-list-item'; + return 'apn-list-item' as const; } static get template() { @@ -42,10 +37,9 @@ /** The GUID of the network to display details for. */ guid: String, - /**@type {!ApnProperties}*/ apn: {type: Object}, - isConnected: { + isApnConnected: { type: Boolean, value: false, }, @@ -74,19 +68,16 @@ */ listSize: Number, - /** @type {?PortalState} */ portalState: { type: Object, }, - /** @private */ isDisabled_: { reflectToAttribute: true, type: Boolean, computed: 'computeIsDisabled_(apn)', }, - /** @private */ isApnRevampAndAllowApnModificationPolicyEnabled_: { type: Boolean, value() { @@ -99,77 +90,75 @@ }; } + guid: string; + apn: ApnProperties; + isApnConnected: boolean; + shouldDisallowDisablingRemoving: boolean; + shouldDisallowEnabling: boolean; + shouldDisallowApnModification: boolean; + itemIndex: number; + listSize: number; + portalState: PortalState|null; + private isDisabled_: boolean; + private isApnRevampAndAllowApnModificationPolicyEnabled_: boolean; + private networkConfig_: CrosNetworkConfigInterface; + constructor() { super(); - /** @private {!CrosNetworkConfigInterface} */ + this.networkConfig_ = MojoInterfaceProviderImpl.getInstance().getMojoServiceRemote(); } - /** - * @param {!ApnProperties} apn - * @private - */ - getApnDisplayName_(apn) { + private getApnDisplayName_(apn: ApnProperties): string { return getApnDisplayName(this.i18n.bind(this), apn); } - /** - * @return {string} - * @private - */ - getSublabel_() { + private getSublabel_(): string { if (this.isPortalStateNoInternet_()) { return this.i18n('networkListItemConnectedNoConnectivity'); } return this.i18n('OncConnected'); } - /** - * @return {boolean} - * @private - */ - isPortalStateNoInternet_() { + private isPortalStateNoInternet_(): boolean { return !!this.portalState && this.portalState === PortalState.kNoInternet; } /** * Opens the three dots menu. - * @private */ - onMenuButtonClicked_(event) { - /** @type {!CrActionMenuElement} */ (this.$.dotsMenu) - .showAt(/** @type {!HTMLElement} */ (event.target)); + private onMenuButtonClicked_(event: {target: HTMLElement}): void { + this.shadowRoot!.querySelector<CrActionMenuElement>('#dotsMenu')!.showAt( + event.target); } - /** @private */ - closeMenu_() { - /** @type {!CrActionMenuElement} */ (this.$.dotsMenu).close(); + private closeMenu_(): void { + this.shadowRoot!.querySelector<CrActionMenuElement>('#dotsMenu')!.close(); } /** * Opens APN Details dialog. - * @private */ - onDetailsClicked_() { + private onDetailsClicked_(): void { assert(!!this.apn); this.closeMenu_(); + const apnEventData: ApnEventData = { + apn: this.apn, + // Only allow editing if the APN is a custom APN. + mode: this.getDetailDialogMode_(), + }; this.dispatchEvent(new CustomEvent('show-apn-detail-dialog', { composed: true, bubbles: true, - detail: /** @type {!ApnEventData} */ ({ - apn: this.apn, - // Only allow editing if the APN is a custom APN. - mode: this.getDetailDialogMode_(), - }), + detail: apnEventData, })); } /** * Returns the mode the APN detail dialog should be if opened. - * @private */ - getDetailDialogMode_() { + private getDetailDialogMode_(): ApnDetailDialogMode { if (!this.apn) { return ApnDetailDialogMode.VIEW; } @@ -189,9 +178,8 @@ /** * Disables the selected APN. - * @private */ - onDisableClicked_() { + private onDisableClicked_(): void { assert(this.guid); assert(this.apn); this.closeMenu_(); @@ -214,17 +202,15 @@ return; } - const apn = - /** @type {!ApnProperties} */ (Object.assign({}, this.apn)); + const apn: ApnProperties = Object.assign({}, this.apn); apn.state = ApnState.kDisabled; this.networkConfig_.modifyCustomApn(this.guid, apn); } /** * Enables the selected APN. - * @private */ - onEnableClicked_() { + private onEnableClicked_(): void { assert(this.guid); assert(this.apn); this.closeMenu_(); @@ -247,17 +233,15 @@ return; } - const apn = - /** @type {!ApnProperties} */ (Object.assign({}, this.apn)); + const apn = Object.assign({}, this.apn); apn.state = ApnState.kEnabled; this.networkConfig_.modifyCustomApn(this.guid, apn); } /** * Removes the selected APN. - * @private */ - onRemoveClicked_() { + private onRemoveClicked_(): void { assert(this.guid); assert(this.apn); this.closeMenu_(); @@ -275,52 +259,41 @@ return; } - this.networkConfig_.removeCustomApn( - this.guid, /** @type {string} */ (this.apn.id)); + this.networkConfig_.removeCustomApn(this.guid, this.apn.id); } /** * Returns true if disable menu button should be shown. - * @return {boolean} - * @private */ - shouldShowDisableMenuItem_() { + private shouldShowDisableMenuItem_(): boolean { return !!this.apn.id && this.apn.state === ApnState.kEnabled; } /** * Returns true if enable menu button should be shown. - * @return {boolean} - * @private */ - shouldShowEnableMenuItem_() { + private shouldShowEnableMenuItem_(): boolean { return !!this.apn.id && this.apn.state === ApnState.kDisabled; } /** * Returns true if remove menu button should be shown. - * @return {boolean} - * @private */ - shouldShowRemoveMenuItem_() { + private shouldShowRemoveMenuItem_(): boolean { return !!this.apn.id; } /** * Returns true if the apn is disabled. - * @return {boolean} - * @private */ - computeIsDisabled_() { + private computeIsDisabled_(): boolean { return !!this.apn.id && this.apn.state === ApnState.kDisabled; } /** * Returns the label for the "Details" menu item. - * @return {string} - * @private */ - getDetailsMenuItemLabel_() { + private getDetailsMenuItemLabel_(): string { return this.getDetailDialogMode_() === ApnDetailDialogMode.EDIT ? this.i18n('apnMenuEdit') : this.i18n('apnMenuDetails'); @@ -328,10 +301,8 @@ /** * Returns accessibility label for the item. - * @return {string} - * @private */ - getAriaLabel_() { + private getAriaLabel_(): string { if (!this.apn) { return ''; } @@ -344,7 +315,7 @@ a11yLabel += ' ' + this.i18n('apnA11yAutoDetected'); } - if (this.isConnected) { + if (this.isApnConnected) { a11yLabel += ' ' + this.i18n('apnA11yConnected'); } else if (this.isDisabled_) { a11yLabel += ' ' + this.i18n('apnA11yDisabled'); @@ -374,4 +345,11 @@ } } -customElements.define(ApnListItem.is, ApnListItem); + +declare global { + interface HTMLElementTagNameMap { + [ApnListItemElement.is]: ApnListItemElement; + } +} + +customElements.define(ApnListItemElement.is, ApnListItemElement);
diff --git a/ash/wm/window_mini_view.cc b/ash/wm/window_mini_view.cc index 7e0e5e8..23ed53e 100644 --- a/ash/wm/window_mini_view.cc +++ b/ash/wm/window_mini_view.cc
@@ -136,9 +136,7 @@ backdrop_view_->SetPaintToLayer(ui::LAYER_SOLID_COLOR); ui::Layer* layer = backdrop_view_->layer(); - layer->SetName("BackdropView"); - layer->SetFillsBoundsOpaquely(false); const int corner_radius = window_util::GetMiniWindowRoundedCornerRadius(); layer->SetRoundedCornerRadius(
diff --git a/base/BUILD.gn b/base/BUILD.gn index 914cc1a9..99d5767 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -555,6 +555,8 @@ "profiler/stack_unwind_data.h", "profiler/suspendable_thread_delegate.h", "profiler/thread_delegate.h", + "profiler/thread_group_profiler.cc", + "profiler/thread_group_profiler.h", "profiler/thread_group_profiler_client.h", "profiler/unwinder.cc", "profiler/unwinder.h", @@ -3383,6 +3385,7 @@ "profiler/stack_copier_unittest.cc", "profiler/stack_sampler_unittest.cc", "profiler/stack_sampling_profiler_unittest.cc", + "profiler/thread_group_profiler_unittest.cc", "rand_util_unittest.cc", "ranges/algorithm_unittest.cc", "ranges/functional_unittest.cc", @@ -4429,6 +4432,7 @@ "android/java/src/org/chromium/base/BuildInfo.java", "android/java/src/org/chromium/base/BundleUtils.java", "android/java/src/org/chromium/base/CallbackController.java", + "android/java/src/org/chromium/base/CancelableRunnable.java", "android/java/src/org/chromium/base/CollectionUtil.java", "android/java/src/org/chromium/base/CommandLineInitUtil.java", "android/java/src/org/chromium/base/CpuFeatures.java",
diff --git a/base/android/java/src/org/chromium/base/CancelableRunnable.java b/base/android/java/src/org/chromium/base/CancelableRunnable.java new file mode 100644 index 0000000..72f273c --- /dev/null +++ b/base/android/java/src/org/chromium/base/CancelableRunnable.java
@@ -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. + +package org.chromium.base; + +import org.chromium.build.BuildConfig; + +/** + * CancelableRunnable is a Runnable class that can be canceled. A canceled task is not removed from + * the task queue - it instead becomes a noop. + * + * <p>This class is *not* threadsafe, and is only for canceling tasks from the thread on which it + * would be run. + */ +public class CancelableRunnable implements Runnable { + private Runnable mRunnable; + private Thread mExpectedThread; + + public CancelableRunnable(Runnable runnable) { + mRunnable = runnable; + } + + public void cancel() { + mRunnable = null; + if (BuildConfig.ENABLE_ASSERTS) { + mExpectedThread = Thread.currentThread(); + } + } + + @Override + public void run() { + assert mExpectedThread == null || Thread.currentThread() == mExpectedThread + : "Canceling thread: " + mExpectedThread.getName(); + if (mRunnable != null) mRunnable.run(); + } +}
diff --git a/base/profiler/periodic_sampling_scheduler.h b/base/profiler/periodic_sampling_scheduler.h index 2488490..6e0dd9a3 100644 --- a/base/profiler/periodic_sampling_scheduler.h +++ b/base/profiler/periodic_sampling_scheduler.h
@@ -30,7 +30,8 @@ virtual ~PeriodicSamplingScheduler(); // Returns the amount of time between now and the next collection. - TimeDelta GetTimeToNextCollection(); + // Virtual to provide dependency injection for test use. + virtual TimeDelta GetTimeToNextCollection(); protected: // Virtual to provide seams for test use.
diff --git a/base/profiler/thread_group_profiler.cc b/base/profiler/thread_group_profiler.cc new file mode 100644 index 0000000..ff3f4751 --- /dev/null +++ b/base/profiler/thread_group_profiler.cc
@@ -0,0 +1,407 @@ +// 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/profiler/thread_group_profiler.h" + +#include <memory> + +#include "base/check.h" +#include "base/functional/bind.h" +#include "base/memory/ptr_util.h" +#include "base/numerics/safe_conversions.h" +#include "base/profiler/periodic_sampling_scheduler.h" +#include "base/profiler/sampling_profiler_thread_token.h" +#include "base/profiler/stack_sampling_profiler.h" +#include "base/profiler/thread_group_profiler_client.h" +#include "base/synchronization/waitable_event.h" +#include "base/task/bind_post_task.h" +#include "base/task/sequenced_task_runner.h" +// Required solely to avoid complaints on incomplete type for +// Unretained(worker_thread) invocations. This code otherwise treats +// WorkerThread pointers as opaque. +#include "base/task/thread_pool/worker_thread.h" +#include "base/time/time.h" + +// Periodic sampling collection is done in CollectProfilesTask(). The function +// is scheduled based on PeriodicSamplingScheduler timing and will start +// profiling all active worker threads. +// +// During a sampling session, new worker threads and worker threads that become +// active (being signalled for work while idle) will call OnWorkerThreadActive +// so profiling can be started for them. If at any point the worker thread is +// shutdown (this should only happen in test as we only sample active threads +// and the thread reclaim time after idle is longer than sampling duration), the +// profiler for that thread is stopped and worker thread blocked until profiler +// is destroyed. This should guarantee a uniform sampling for all worker thread +// executions as all the work happening inside a sampling session is collected +// regardless of which thread the work is scheduled. +// +// Thread group shutdown happens after task runner shutdown so no more sampling +// can be scheduled. All existing profilers will be cleared on the main thread +// during shutdown and a profiler shutdown event will signal. Note that after +// ThreadGroup shutdown is started worker threads may still execute +// CONTINUE_ON_SHUTDOWN tasks and these tasks will never be sampled. This is +// acceptable as these profiles are unlikely to be uploaded anyway. + +// ThreadGroupProfiler will only be destructed in test through +// ThreadGroupImpl::JoinForTesting. This also happens after task runner shutdown +// so same logic applies as normal shutdown. In prod the thread pool (which +// holds thread group) is always leaked during shutdown. + +namespace base { +namespace { +// Pointer to the embedder-specific client implementation. +// |g_thread_group_profiler_client| is intentionally leaked on shutdown. +ThreadGroupProfilerClient* g_thread_group_profiler_client = nullptr; + +// Run continuous profiling 2% of the time. +constexpr double kFractionOfExecutionTimeToSample = 0.02; + +// Keep sampling new worker thread until last second of sampling duration. +// This is intended as an performance optimization, i.e. it's not worth it to do +// the whole StackSamplingProfiler set up just to get less than 10 samples. And +// since this treats all threads equally it does not affect the unbiased nature +// of sampling. +const TimeDelta kMinRemainingTimeForNewThreadSampling = Seconds(1); +} // namespace + +// static +void ThreadGroupProfiler::SetClient( + std::unique_ptr<ThreadGroupProfilerClient> client) { + // Generally, the client should only be set once, at process startup. However, + // some test infrastructure causes initialization to happen more than once. + delete g_thread_group_profiler_client; + g_thread_group_profiler_client = client.release(); +} + +// static +bool ThreadGroupProfiler::IsProfilingEnabled() { + // TODO(crbug.com/40226611): Remove GetClient() check once client is set on + // all embedders. This is to temporarily support testing with mock client when + // real clients aren't set on embedders. + return GetClient() && GetClient()->IsProfilerEnabledForCurrentProcess(); +} + +ThreadGroupProfiler::ThreadGroupProfiler( + scoped_refptr<base::SequencedTaskRunner> task_runner, + std::string_view thread_group_label, + std::unique_ptr<PeriodicSamplingScheduler> periodic_sampling_scheduler, + ProfilerFactory profiler_factory) + : thread_group_label_(thread_group_label), + periodic_sampling_scheduler_(std::move(periodic_sampling_scheduler)), + task_runner_(std::move(task_runner)), + stack_sampling_profiler_factory_(std::move(profiler_factory)) { + DETACH_FROM_SEQUENCE(task_runner_sequence_checker_); + if (!periodic_sampling_scheduler_) { + periodic_sampling_scheduler_ = std::make_unique<PeriodicSamplingScheduler>( + GetClient()->GetSamplingParams().sampling_interval * + GetClient()->GetSamplingParams().samples_per_profile, + kFractionOfExecutionTimeToSample, TimeTicks::Now()); + } + task_runner_->PostTask( + FROM_HERE, BindOnce(&ThreadGroupProfiler::StartTask, Unretained(this))); +} + +ThreadGroupProfiler::~ThreadGroupProfiler() { + // Shutdown has been run before destruction. + CHECK(!active_collection_); +} + +void ThreadGroupProfiler::Shutdown() { + // Must be destroyed from the same sequence as constructor. + DCHECK_CALLED_ON_VALID_SEQUENCE(construction_sequence_checker_); + // CHECK that the task runner has actually been shutdown. + CHECK(!task_runner_->PostTask(FROM_HERE, DoNothing())); + + TS_UNCHECKED_READ(active_collection_).reset(); + thread_group_profiler_shutdown_.Signal(); +} + +void ThreadGroupProfiler::OnWorkerThreadStarted( + internal::WorkerThread* worker_thread) { + task_runner_->PostTask( + FROM_HERE, BindOnce(&ThreadGroupProfiler::OnWorkerThreadStartedTask, + Unretained(this), Unretained(worker_thread), + GetSamplingProfilerCurrentThreadToken())); +} + +void ThreadGroupProfiler::OnWorkerThreadActive( + internal::WorkerThread* worker_thread) { + task_runner_->PostTask( + FROM_HERE, BindOnce(&ThreadGroupProfiler::OnWorkerThreadActiveTask, + Unretained(this), Unretained(worker_thread))); +} + +void ThreadGroupProfiler::OnWorkerThreadIdle( + internal::WorkerThread* worker_thread) { + task_runner_->PostTask(FROM_HERE, + BindOnce(&ThreadGroupProfiler::OnWorkerThreadIdleTask, + Unretained(this), Unretained(worker_thread))); +} + +void ThreadGroupProfiler::OnWorkerThreadExiting( + internal::WorkerThread* worker_thread) { + WaitableEvent profiling_has_stopped; + task_runner_->PostTask( + FROM_HERE, BindOnce(&ThreadGroupProfiler::OnWorkerThreadExitingTask, + Unretained(this), Unretained(worker_thread), + Unretained(&profiling_has_stopped))); + base::WaitableEvent* event_array[] = {&profiling_has_stopped, + &thread_group_profiler_shutdown_}; + // During shutdown profiling_has_stopped may not get a chance to signal as + // task runner is stopped, profiler_shutdown event will signal instead + // indicating that clean up has finished and worker thread may safely exit. + WaitableEvent::WaitMany(event_array, std::size(event_array)); +} + +// Production implementation that wraps an actual StackSamplingProfiler. +class ThreadGroupProfiler::ProfilerImpl : public ThreadGroupProfiler::Profiler { + public: + ProfilerImpl(SamplingProfilerThreadToken thread_token, + const StackSamplingProfiler::SamplingParams& params, + std::unique_ptr<ProfileBuilder> profile_builder, + StackSamplingProfiler::UnwindersFactory unwinder_factory) + : sampling_profiler_{thread_token, params, std::move(profile_builder), + std::move(unwinder_factory)} {} + ~ProfilerImpl() override = default; + + // Profiler: + void Start() override { sampling_profiler_.Start(); } + + private: + StackSamplingProfiler sampling_profiler_; +}; + +ThreadGroupProfiler::ActiveCollection::ActiveCollection( + const flat_map<internal::WorkerThread*, WorkerThreadContext>& + worker_thread_context_set, + const TimeDelta& sampling_duration, + SequencedTaskRunner* task_runner, + ProfilerFactory factory, + OnceClosure collection_complete_callback) + : task_runner_(task_runner), + stack_sampling_profiler_factory_(factory), + collection_complete_callback_(std::move(collection_complete_callback)), + sampling_duration_(sampling_duration), + collection_end_time_(TimeTicks::Now() + sampling_duration), + empty_collection_closure_{ + BindOnce(&ActiveCollection::OnEmptyCollectionCompleted, + Unretained(this))} { + decltype(profilers_)::container_type new_profilers; + for (auto& [worker_thread, context] : worker_thread_context_set) { + // Only create profilers for active threads. + if (!context.is_idle) { + std::unique_ptr<Profiler> profiler = CreateSamplingProfilerForThread( + worker_thread, context.token, GetClient()->GetSamplingParams()); + profiler->Start(); + new_profilers.emplace_back(worker_thread, std::move(profiler)); + } + } + // More efficient to construct flat_map from containers then adding each + // profiler in a loop. + profilers_ = flat_map(std::move(new_profilers)); + if (profilers_.empty()) { + // Queue a delayed empty collection callback to run after the sampling + // duration if there are no active threads to sample. + task_runner_->PostDelayedTask( + FROM_HERE, empty_collection_closure_.callback(), sampling_duration_); + } else { + empty_collection_closure_.Cancel(); + } +} + +void ThreadGroupProfiler::ActiveCollection::MaybeAddWorkerThread( + internal::WorkerThread* worker_thread, + const SamplingProfilerThreadToken& token) { + // Skip if the remaining time of current sampling session is less than the + // threshold. + if ((collection_end_time_ - TimeTicks::Now()) < + kMinRemainingTimeForNewThreadSampling) { + return; + } + // Skip if there's already a profiler for this thread. A worker thread can + // flip between idle and active anytime during the collection but profiler + // should only be created for it the first time it becomes active. + if (profilers_.find(worker_thread) != profilers_.end()) { + return; + } + StackSamplingProfiler::SamplingParams sampling_params = + GetClient()->GetSamplingParams(); + // Calculate remaining samples until end of collection period. + sampling_params.samples_per_profile = + ClampFloor((collection_end_time_ - TimeTicks::Now()) / + sampling_params.sampling_interval); + std::unique_ptr<Profiler> profiler = + CreateSamplingProfilerForThread(worker_thread, token, sampling_params); + profiler->Start(); + profilers_.emplace(worker_thread, std::move(profiler)); + // Cancel empty callback since there is a profiler running now. + empty_collection_closure_.Cancel(); +} + +void ThreadGroupProfiler::ActiveCollection::RemoveWorkerThread( + internal::WorkerThread* worker_thread) { + // If there's a profiler associated, remove it. Will block until profiler + // destructor finishes but it should be a rare case (during shutdown or + // ThreadGroup::JoinForTesting) as we only sample active threads; they should + // not get reclaimed during sampling session. + const bool was_present = profilers_.erase(worker_thread) == 1; + if (!was_present || !profilers_.empty()) { + return; + } + // Queue a delayed empty collection callback to run after the sampling + // duration if there are no active threads to sample. + empty_collection_closure_.Reset(BindOnce( + &ActiveCollection::OnEmptyCollectionCompleted, Unretained(this))); + task_runner_->PostDelayedTask(FROM_HERE, empty_collection_closure_.callback(), + collection_end_time_ - TimeTicks::Now()); +} + +std::unique_ptr<ThreadGroupProfiler::Profiler> +ThreadGroupProfiler::ActiveCollection::CreateSamplingProfilerForThread( + internal::WorkerThread* worker_thread, + const SamplingProfilerThreadToken& token, + const StackSamplingProfiler::SamplingParams& sampling_params) { + ThreadGroupProfilerClient* client = ThreadGroupProfiler::GetClient(); + return stack_sampling_profiler_factory_.Run( + token, sampling_params, + client->CreateProfileBuilder(BindPostTask( + task_runner_, + BindOnce(&ActiveCollection::OnProfilerCollectionCompleted, + Unretained(this), Unretained(worker_thread)))), + client->GetUnwindersFactory()); +} + +void ThreadGroupProfiler::ActiveCollection::OnProfilerCollectionCompleted( + internal::WorkerThread* worker_thread) { + DCHECK(!profilers_.empty()); + profilers_.erase(worker_thread); + // Notify the collection is complete when there's no outstanding profilers. + if (profilers_.empty()) { + std::move(collection_complete_callback_).Run(); + } +} + +void ThreadGroupProfiler::ActiveCollection::OnEmptyCollectionCompleted() { + DCHECK(profilers_.empty()); + std::move(collection_complete_callback_).Run(); +} + +ThreadGroupProfiler::ActiveCollection::~ActiveCollection() = default; + +// static +ThreadGroupProfilerClient* ThreadGroupProfiler::GetClient() { + // TODO(crbug.com/40226611): Add check once client is set on all embedders. + // CHECK(g_thread_group_profiler_client); + return g_thread_group_profiler_client; +} + +// static +ThreadGroupProfiler::ProfilerFactory +ThreadGroupProfiler::GetDefaultProfilerFactory() { + return BindRepeating( + [](SamplingProfilerThreadToken thread_token, + const StackSamplingProfiler::SamplingParams& params, + std::unique_ptr<ProfileBuilder> profile_builder, + StackSamplingProfiler::UnwindersFactory unwinder_factory) + -> std::unique_ptr<Profiler> { + return std::make_unique<ProfilerImpl>(thread_token, params, + std::move(profile_builder), + std::move(unwinder_factory)); + }); +} + +// static +TimeDelta ThreadGroupProfiler::GetSamplingDuration() { + StackSamplingProfiler::SamplingParams params = + GetClient()->GetSamplingParams(); + return params.sampling_interval * params.samples_per_profile; +} + +void ThreadGroupProfiler::ThreadGroupProfiler::StartTask() { + DCHECK_CALLED_ON_VALID_SEQUENCE(task_runner_sequence_checker_); + task_runner_->PostDelayedTask( + FROM_HERE, + base::BindOnce(&ThreadGroupProfiler::CollectProfilesTask, + Unretained(this)), + periodic_sampling_scheduler_->GetTimeToNextCollection()); +} + +void ThreadGroupProfiler::OnWorkerThreadStartedTask( + internal::WorkerThread* worker_thread, + SamplingProfilerThreadToken token) { + DCHECK_CALLED_ON_VALID_SEQUENCE(task_runner_sequence_checker_); + const bool inserted = + worker_thread_context_set_ + .emplace(worker_thread, WorkerThreadContext{token, + /*is_idle=*/true}) + .second; + // Worker thread should not be present before this call. + DCHECK(inserted); +} + +// A worker thread starts out on the idle set when it's created. On its +// ThreadMain it will call Delegate::GetWork() and when it does obtain a task +// source it will be removed from idle set and becomes active. +// OnWorkerThreadActive() will be called at that point. When it exhausted the +// task source, it will be placed on idle set and nullptr returned from +// GetWork()/ProcessSwappedTask(). The worker thread will then enter a +// TimedWait until it's either wake up or reaches its reclaim time. +void ThreadGroupProfiler::OnWorkerThreadActiveTask( + internal::WorkerThread* worker_thread) { + DCHECK_CALLED_ON_VALID_SEQUENCE(task_runner_sequence_checker_); + auto it = worker_thread_context_set_.find(worker_thread); + // Profiler token should already be set since OnWorkerThreadActive will + // be called strictly after worker thread creation. + DCHECK(it != worker_thread_context_set_.end()); + // Mark worker thread as active. + it->second.is_idle = false; + if (active_collection_) { + active_collection_->MaybeAddWorkerThread(worker_thread, it->second.token); + } +} + +void ThreadGroupProfiler::OnWorkerThreadIdleTask( + internal::WorkerThread* worker_thread) { + DCHECK_CALLED_ON_VALID_SEQUENCE(task_runner_sequence_checker_); + auto it = worker_thread_context_set_.find(worker_thread); + DCHECK(it != worker_thread_context_set_.end()); + // Mark worker thread as idle. + it->second.is_idle = true; +} + +void ThreadGroupProfiler::OnWorkerThreadExitingTask( + internal::WorkerThread* worker_thread, + WaitableEvent* profiling_has_stopped) { + DCHECK_CALLED_ON_VALID_SEQUENCE(task_runner_sequence_checker_); + if (active_collection_) { + active_collection_->RemoveWorkerThread(worker_thread); + } + worker_thread_context_set_.erase(worker_thread); + profiling_has_stopped->Signal(); +} + +void ThreadGroupProfiler::CollectProfilesTask() { + DCHECK_CALLED_ON_VALID_SEQUENCE(task_runner_sequence_checker_); + DCHECK(!active_collection_); + active_collection_.emplace( + worker_thread_context_set_, GetSamplingDuration(), task_runner_.get(), + stack_sampling_profiler_factory_, + BindOnce(&ThreadGroupProfiler::EndActiveCollectionTask, + Unretained(this))); +} + +void ThreadGroupProfiler::EndActiveCollectionTask() { + DCHECK_CALLED_ON_VALID_SEQUENCE(task_runner_sequence_checker_); + DCHECK(active_collection_); + active_collection_.reset(); + // Schedule the next collection. + task_runner_->PostDelayedTask( + FROM_HERE, + base::BindOnce(&ThreadGroupProfiler::CollectProfilesTask, + Unretained(this)), + periodic_sampling_scheduler_->GetTimeToNextCollection()); +} + +} // namespace base
diff --git a/base/profiler/thread_group_profiler.h b/base/profiler/thread_group_profiler.h new file mode 100644 index 0000000..7fb0261 --- /dev/null +++ b/base/profiler/thread_group_profiler.h
@@ -0,0 +1,254 @@ +// 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 BASE_PROFILER_THREAD_GROUP_PROFILER_H_ +#define BASE_PROFILER_THREAD_GROUP_PROFILER_H_ + +#include <memory> + +#include "base/cancelable_callback.h" +#include "base/containers/flat_map.h" +#include "base/functional/callback.h" +#include "base/memory/scoped_refptr.h" +#include "base/profiler/periodic_sampling_scheduler.h" +#include "base/profiler/sampling_profiler_thread_token.h" +#include "base/profiler/stack_sampling_profiler.h" +#include "base/task/sequenced_task_runner.h" +#include "base/threading/thread_checker.h" +#include "base/time/time.h" + +namespace base { +namespace internal { +class WorkerThread; +} // namespace internal + +class ThreadGroupProfilerClient; + +// ThreadGroupProfiler manages sampling of active worker threads and +// schedules periodic sampling. +// This class will be accessed on +// - Main thread: Construction, shutdown and destruction. +// - Worker thread: Invokes the OnWorkerThread* functions to inform the class +// of their lifetime events. +// - Sequenced task runner: Internal operations of this class are scheduled on +// the task runner. +// Once created, ThreadGroupProfiler will periodically profile active worker +// threads by creating a StackSamplingProfiler for each thread. At the beginning +// of a session, all active worker threads are sampled. During the session, if a +// worker thread becomes active (via OnWorkerThreadActive) it will be sampled +// for the remainder of this session. Once the sampling starts for a thread it +// will continue until either the thread is exiting (via OnWorkerThreadExit) or +// the profile is completed. When a profile completes the associated +// StackSamplingProfiler is destroyed. Worker threads being sampled will be +// blocked on exit until the profiling is stopped. +// +// When shutting down, the class requires that the provided SequencedTaskRunner +// is shutdown prior to invoking Shutdown(). +class BASE_EXPORT ThreadGroupProfiler { + public: + // Interface for profiling stack samples from a specific thread. + // This provides an abstraction over StackSamplingProfiler to enable testing + // of ThreadGroupProfiler without depending on actual profiler implementation. + class Profiler { + public: + virtual ~Profiler() = default; + virtual void Start() = 0; + + protected: + Profiler() = default; + }; + + // Sets the instance of ThreadProfilerClient to provide embedder-specific + // implementation logic. This instance must be set early, before + // CreateThreadGroupProfiler() and IsProfilingEnabled() are called. + static void SetClient(std::unique_ptr<ThreadGroupProfilerClient> client); + + // Must be called after SetClient(). + static bool IsProfilingEnabled(); + + using ProfilerFactory = RepeatingCallback<std::unique_ptr<Profiler>( + SamplingProfilerThreadToken thread_token, + const StackSamplingProfiler::SamplingParams& params, + std::unique_ptr<ProfileBuilder> profile_builder, + StackSamplingProfiler::UnwindersFactory unwinder_factory)>; + + using GetTimeToNextCollectionCallback = RepeatingCallback<TimeDelta()>; + + // ThreadGroupProfiler constructor. |task_runner| will be used to schedule the + // profile collection. |thread_group_label| will used to tag the metadata for + // all samples collected in this profiler. |profiler_factory| is a repeating + // callback that will be used to make Profiler, intended to be used for + // dependency injection for testing. |time_to_next_collection_callback| is a + // repeating callback that will be used to get the next collection time, + // intended to be used for dependency injection for testing. + explicit ThreadGroupProfiler( + scoped_refptr<SequencedTaskRunner> task_runner, + std::string_view thread_group_label, + std::unique_ptr<PeriodicSamplingScheduler> periodic_sampling_scheduler = + nullptr, + ProfilerFactory profiler_factory = GetDefaultProfilerFactory()); + ThreadGroupProfiler(const ThreadGroupProfiler&) = delete; + ThreadGroupProfiler& operator=(const ThreadGroupProfiler&) = delete; + + ~ThreadGroupProfiler(); + + // Shuts down ThreadGroupProfiler instance and stops all current profiling. + // This should only be called after task runner is stopped as it expects + // exclusive access on this instance. No more sampling will happen and worker + // threads are freed to exit after shutdown finishes. + void Shutdown(); + + // Register new worker thread on starting. Must be called on worker + // thread. + void OnWorkerThreadStarted(internal::WorkerThread* worker_thread); + + // Starts profilng on worker that has become active during a sampling + // session. Must be called on worker thread. + void OnWorkerThreadActive(internal::WorkerThread* worker_thread); + + // Must be called on worker thread when it becomes idle, i.e. no more work is + // scheduled to run on this thread. + void OnWorkerThreadIdle(internal::WorkerThread* worker_thread); + + // Clean up on worker thread exiting. Must be called on worker thread. + void OnWorkerThreadExiting(internal::WorkerThread* worker_thread); + + private: + struct WorkerThreadContext { + SamplingProfilerThreadToken token; + bool is_idle; + }; + class ProfilerImpl; + + // Represents an active sample collection phase and is responsible for + // creating profilers for active threads both at the beginning as well as + // during the sampling duration. + class ActiveCollection { + public: + explicit ActiveCollection( + const flat_map<internal::WorkerThread*, WorkerThreadContext>& + worker_thread_context_set, + const TimeDelta& sampling_duration, + SequencedTaskRunner* task_runner, + ProfilerFactory stack_sampling_profiler_factory, + OnceClosure collection_completed_callback); + ~ActiveCollection(); + ActiveCollection(const ActiveCollection&) = delete; + ActiveCollection& operator=(const ActiveCollection&) = delete; + + // Maybe create a new profiler for worker_thread depending on how close + // the collection is to being complete. + void MaybeAddWorkerThread(internal::WorkerThread* worker_thread, + const SamplingProfilerThreadToken& token); + + // Destroy the profiler for worker_thread if it exists. + void RemoveWorkerThread(internal::WorkerThread* worker_thread); + + private: + // Helper function for creating the StackSamplingProfiler. + std::unique_ptr<Profiler> CreateSamplingProfilerForThread( + internal::WorkerThread* worker_thread, + const SamplingProfilerThreadToken& token, + const StackSamplingProfiler::SamplingParams& sampling_params); + + // Remove completed profiler from collection. If this is the last profiler, + // invokes the collection completed callback. + void OnProfilerCollectionCompleted(internal::WorkerThread* worker_thread); + // Invokes collection completed callback to end an empty collection. + void OnEmptyCollectionCompleted(); + + // A map that stores the active `StackSamplingProfiler` instances + // for each worker thread. + flat_map<internal::WorkerThread*, std::unique_ptr<Profiler>> profilers_; + + scoped_refptr<SequencedTaskRunner> task_runner_; + + ProfilerFactory stack_sampling_profiler_factory_; + + // Callback to notify on collection complete. After this callback is run + // there's no guarantee that the instance is still alive. + OnceClosure collection_complete_callback_; + + const TimeDelta sampling_duration_; + + // Tracks the end time (an estimate calculated at start of sampling by + // adding the sampling duration) of the current sampling session. + const TimeTicks collection_end_time_; + + // Used to trigger collection completed when the collection is empty at the + // end of a session. This callback is only alive when there are no profilers + // in this collection and is cancelled immediately when there are active + // profilers. + CancelableOnceClosure empty_collection_closure_; + }; + + // Retrieve the ThreadProfilerClient instance provided via SetClient(). + static ThreadGroupProfilerClient* GetClient(); + + static ProfilerFactory GetDefaultProfilerFactory(); + + static GetTimeToNextCollectionCallback + GetDefaultTimeToNextCollectionCallback(); + + static TimeDelta GetSamplingDuration(); + + // All the private functions below are executed on the task runner to + // ensure proper synchronization. This is enforced through + // DCHECK_CALLED_ON_VALID_SEQUENCE(task_runner_sequence_checker_) for + // functions that are called as PostTask task and + // VALID_CONTEXT_REQUIRED(task_runner_sequence_checker_) for functions that + // are called directly. + + void StartTask(); + + void OnWorkerThreadStartedTask(internal::WorkerThread* worker_thread, + SamplingProfilerThreadToken token); + void OnWorkerThreadActiveTask(internal::WorkerThread* worker_thread); + void OnWorkerThreadIdleTask(internal::WorkerThread* worker_thread); + void OnWorkerThreadExitingTask(internal::WorkerThread* worker_thread, + WaitableEvent* profiling_has_stopped); + + // Starts the thread group profiler collection. This will create stack + // sampling profilers for all active worker threads in the thread group, + // monitor new active worker threads (these include both new worker threads + // that are spawned and idle worker threads becoming active) during sampling + // duration and schedules the next sampling session. + void CollectProfilesTask(); + + void EndActiveCollectionTask(); + + // A map that stores the worker threads, their corresponding profiler + // token and their idle states. + flat_map<internal::WorkerThread*, WorkerThreadContext> + worker_thread_context_set_ + GUARDED_BY_CONTEXT(task_runner_sequence_checker_); + + // This has no value if not in an active collection phase. + std::optional<ActiveCollection> active_collection_ + GUARDED_BY_CONTEXT(task_runner_sequence_checker_); + + // Label to use as metadata for specifying which group (foreground, + // background, utility) the worker thread being sampled belongs to. + const std::string thread_group_label_; + + // Used to block worker threads from exiting during ThreadGroupProfiler + // shutdown. + WaitableEvent thread_group_profiler_shutdown_{ + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED}; + + std::unique_ptr<PeriodicSamplingScheduler> periodic_sampling_scheduler_ + GUARDED_BY_CONTEXT(task_runner_sequence_checker_); + + scoped_refptr<SequencedTaskRunner> task_runner_; + + ProfilerFactory stack_sampling_profiler_factory_; + + SEQUENCE_CHECKER(task_runner_sequence_checker_); + SEQUENCE_CHECKER(construction_sequence_checker_); +}; + +} // namespace base + +#endif // BASE_PROFILER_THREAD_GROUP_PROFILER_H_
diff --git a/base/profiler/thread_group_profiler_unittest.cc b/base/profiler/thread_group_profiler_unittest.cc new file mode 100644 index 0000000..e965e57 --- /dev/null +++ b/base/profiler/thread_group_profiler_unittest.cc
@@ -0,0 +1,868 @@ +// 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/profiler/thread_group_profiler.h" + +#include <map> +#include <memory> + +#include "base/functional/bind.h" +#include "base/functional/function_ref.h" +#include "base/memory/ptr_util.h" +#include "base/memory/raw_ptr.h" +#include "base/profiler/periodic_sampling_scheduler.h" +#include "base/profiler/stack_sampling_profiler.h" +#include "base/profiler/stack_sampling_profiler_test_util.h" +#include "base/profiler/thread_group_profiler_client.h" +#include "base/task/thread_pool.h" +#include "base/test/bind.h" +#include "base/test/gtest_util.h" +#include "base/test/task_environment.h" +#include "base/threading/platform_thread.h" +#include "base/threading/thread.h" +#include "base/time/time.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace base { + +namespace internal { +class WorkerThread; +} + +namespace { +constexpr int kSamplesPerProfile = 20; +constexpr TimeDelta kSamplingInterval = Milliseconds(100); +constexpr TimeDelta kTimeToNextCollection = Hours(1); +} // namespace + +class MockPeriodicSamplingScheduler : public PeriodicSamplingScheduler { + public: + explicit MockPeriodicSamplingScheduler(TimeDelta time_to_next_collection) + : PeriodicSamplingScheduler(Seconds(30), 0.02, TimeTicks::Now()), + time_to_next_collection_(time_to_next_collection) {} + TimeDelta GetTimeToNextCollection() override { + return time_to_next_collection_; + } + + protected: + TimeDelta time_to_next_collection_; +}; + +class MockProfileBuilder : public ProfileBuilder { + public: + explicit MockProfileBuilder(OnceClosure completed_callback) + : completed_callback_(std::move(completed_callback)) {} + void OnProfileCompleted(TimeDelta profile_duration, + TimeDelta sampling_period) override { + std::move(completed_callback_).Run(); + } + ModuleCache* GetModuleCache() override { return &module_cache_; } + MOCK_METHOD2(OnSampleCompleted, + void(std::vector<Frame> frames, TimeTicks sample_timestamp)); + + protected: + ModuleCache module_cache_; + // Callback made when sampling a profile completes. + OnceClosure completed_callback_; +}; + +class MockThreadGroupProfilerClient : public ThreadGroupProfilerClient { + public: + MockThreadGroupProfilerClient() = default; + StackSamplingProfiler::SamplingParams GetSamplingParams() override { + return {.samples_per_profile = kSamplesPerProfile, + .sampling_interval = kSamplingInterval}; + } + std::unique_ptr<ProfileBuilder> CreateProfileBuilder( + OnceClosure callback) override { + return std::make_unique<MockProfileBuilder>(std::move(callback)); + } + bool IsProfilerEnabledForCurrentProcess() override { return true; } + bool IsSingleProcess(const CommandLine& command_line) override { + return false; + } + StackSamplingProfiler::UnwindersFactory GetUnwindersFactory() override { + return CreateCoreUnwindersFactoryForTesting(nullptr); + } +}; + +class MockProfiler : public ThreadGroupProfiler::Profiler { + public: + MockProfiler(std::map<PlatformThreadId, MockProfiler*>& sampling_profilers, + int& sampling_profilers_created, + PlatformThreadId target_thread_id, + const StackSamplingProfiler::SamplingParams& params, + std::unique_ptr<ProfileBuilder> profile_builder) + : sampling_profilers_(sampling_profilers), + sampling_profilers_created_(sampling_profilers_created), + target_thread_id_(target_thread_id), + sampling_params_(params), + profile_builder_(std::move(profile_builder)) { + EXPECT_EQ(sampling_profilers_->count(target_thread_id_), 0); + (*sampling_profilers_)[target_thread_id_] = this; + ++*sampling_profilers_created_; + EXPECT_CALL(*this, Start()); + } + + ~MockProfiler() override { sampling_profilers_->erase(target_thread_id_); } + + // ThreadGroupProfiler::Profiler: + MOCK_METHOD(void, Start, (), (override)); + + const StackSamplingProfiler::SamplingParams& sampling_params() const { + return sampling_params_; + } + + void CompleteProfiling() { + profile_builder_->OnProfileCompleted(TimeDelta(), TimeDelta()); + } + + private: + raw_ref<std::map<PlatformThreadId, MockProfiler*>> sampling_profilers_; + raw_ref<int> sampling_profilers_created_; + PlatformThreadId target_thread_id_; + const StackSamplingProfiler::SamplingParams sampling_params_; + std::unique_ptr<ProfileBuilder> profile_builder_; +}; + +ThreadGroupProfiler::ProfilerFactory GetMockProfilerFactory( + std::map<PlatformThreadId, MockProfiler*>& sampling_profilers, + int& sampling_profilers_created) { + return BindRepeating(BindLambdaForTesting( + [&sampling_profilers, &sampling_profilers_created]( + SamplingProfilerThreadToken thread_token, + const StackSamplingProfiler::SamplingParams& params, + std::unique_ptr<ProfileBuilder> profile_builder, + StackSamplingProfiler::UnwindersFactory unwinder_factory) + -> std::unique_ptr<ThreadGroupProfiler::Profiler> { + return std::make_unique<MockProfiler>( + sampling_profilers, sampling_profilers_created, thread_token.id, + params, std::move(profile_builder)); + })); +} + +class ThreadGroupProfilerTest : public testing::Test { + public: + void SetUp() override { + ThreadGroupProfiler::SetClient( + std::make_unique<MockThreadGroupProfilerClient>()); + profiler_ = std::make_unique<ThreadGroupProfiler>( + ThreadPool::CreateSequencedTaskRunner({}), "Test", + std::make_unique<MockPeriodicSamplingScheduler>(kTimeToNextCollection), + GetMockProfilerFactory(sampling_profilers_, + sampling_profilers_created_)); + } + + void TearDown() override { + task_environment_.reset(); + if (!shutdown_started_) { + profiler_->Shutdown(); + } + ThreadGroupProfiler::SetClient(nullptr); + } + + protected: + class FakeWorkerThread : public Thread { + public: + FakeWorkerThread(internal::WorkerThread* fake_pointer, + test::TaskEnvironment& task_environment) + : Thread("FakeWorkerThread"), + fake_pointer_(fake_pointer), + task_environment_(task_environment) { + Start(); + } + + ~FakeWorkerThread() override { Stop(); } + + void RunOnThread(FunctionRef<void(internal::WorkerThread*)> callable) { + // First, synchronously execute the callable on the Thread's task runner. + WaitableEvent callable_completed{ + WaitableEvent::ResetPolicy::MANUAL, + WaitableEvent::InitialState::NOT_SIGNALED}; + + RunOnThreadAsync(callable, callable_completed); + + callable_completed.Wait(); + + // Then, ensure any thread pool tasks that the profiler posted run to + // completion. The thread pool is configured to run tasks eagerly via + // ThreadPoolExecutionMode::ASYNC, so tasks may already be executing. This + // call ensures they finish. + task_environment_->RunUntilIdle(); + } + + void RunOnThreadAsync(FunctionRef<void(internal::WorkerThread*)> callable, + WaitableEvent& callable_completed) { + task_runner()->PostTask( + FROM_HERE, BindLambdaForTesting([callable, &callable_completed, + fake_pointer = fake_pointer_] { + callable(fake_pointer); + callable_completed.Signal(); + })); + } + + private: + raw_ptr<internal::WorkerThread> const fake_pointer_; + raw_ref<test::TaskEnvironment> task_environment_; + }; + + std::unique_ptr<FakeWorkerThread> CreateFakeWorkerThread() { + return std::make_unique<FakeWorkerThread>( + reinterpret_cast<internal::WorkerThread*>(next_worker_thread_id_++), + *task_environment_); + } + + void InitiateNextCollection() { + task_environment_->FastForwardBy(time_to_next_collection_); + task_environment_->RunUntilIdle(); + time_to_next_collection_ = kTimeToNextCollection; + } + + void AdvanceBySamples(int samples) { + const TimeDelta samples_duration = kSamplingInterval * samples; + task_environment_->FastForwardBy(samples_duration); + task_environment_->RunUntilIdle(); + time_to_next_collection_ -= samples_duration; + } + + void AdvanceToEndOfCollection() { + const TimeDelta duration_already_advanced = + kTimeToNextCollection - time_to_next_collection_; + const TimeDelta collection_duration = + kSamplingInterval * kSamplesPerProfile; + const TimeDelta duration_to_end_of_collection = + collection_duration - duration_already_advanced; + task_environment_->FastForwardBy(duration_to_end_of_collection); + task_environment_->RunUntilIdle(); + time_to_next_collection_ -= duration_to_end_of_collection; + } + + void CompleteProfiling(MockProfiler* profiler) { + profiler->CompleteProfiling(); + task_environment_->RunUntilIdle(); + } + + // Optional to support destruction prior to profiler_. + std::optional<test::TaskEnvironment> task_environment_{ + std::in_place, test::TaskEnvironment::TimeSource::MOCK_TIME, + test::TaskEnvironment::ThreadPoolExecutionMode::ASYNC}; + std::map<PlatformThreadId, MockProfiler*> sampling_profilers_; + int sampling_profilers_created_ = 0; + std::unique_ptr<ThreadGroupProfiler> profiler_; + ModuleCache module_cache_; + int next_worker_thread_id_ = 1; + TimeDelta time_to_next_collection_ = kTimeToNextCollection; + bool shutdown_started_ = false; +}; + +TEST_F(ThreadGroupProfilerTest, Construction) { + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, CollectionInactive_WorkerInactiveLifecycle) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadExiting(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, CollectionInactive_WorkerActiveLifecycle) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadIdle(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadExiting(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, CollectionBecomesActive_NoWorkers) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, CollectionBecomesActive_WorkerExited) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadExiting(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, CollectionBecomesActive_InactiveWorker) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, CollectionBecomesActive_NewlyInactiveWorker) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadIdle(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, CollectionBecomesActive_ActiveWorker) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + InitiateNextCollection(); + EXPECT_EQ(sampling_profilers_.size(), 1); + ASSERT_TRUE(sampling_profilers_.find(worker->GetThreadId()) != + sampling_profilers_.end()); + MockProfiler* const sampling_profiler = + sampling_profilers_[worker->GetThreadId()]; + EXPECT_EQ(sampling_profiler->sampling_params().samples_per_profile, + kSamplesPerProfile); + EXPECT_EQ(sampling_profiler->sampling_params().sampling_interval, + kSamplingInterval); +} + +TEST_F(ThreadGroupProfilerTest, CollectionBecomesActive_ReactivatedWorker) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadIdle(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + InitiateNextCollection(); + EXPECT_EQ(sampling_profilers_.size(), 1); + ASSERT_TRUE(sampling_profilers_.find(worker->GetThreadId()) != + sampling_profilers_.end()); + MockProfiler* const sampling_profiler = + sampling_profilers_[worker->GetThreadId()]; + EXPECT_EQ(sampling_profiler->sampling_params().samples_per_profile, + kSamplesPerProfile); + EXPECT_EQ(sampling_profiler->sampling_params().sampling_interval, + kSamplingInterval); +} + +TEST_F(ThreadGroupProfilerTest, CollectionBecomesActive_MultipleWorkers) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + std::unique_ptr<FakeWorkerThread> worker2 = CreateFakeWorkerThread(); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + worker2->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + worker2->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + InitiateNextCollection(); + EXPECT_EQ(sampling_profilers_.size(), 2); + ASSERT_TRUE(sampling_profilers_.find(worker->GetThreadId()) != + sampling_profilers_.end()); + ASSERT_TRUE(sampling_profilers_.find(worker2->GetThreadId()) != + sampling_profilers_.end()); + MockProfiler* const sampling_profiler = + sampling_profilers_[worker->GetThreadId()]; + EXPECT_EQ(sampling_profiler->sampling_params().samples_per_profile, + kSamplesPerProfile); + EXPECT_EQ(sampling_profiler->sampling_params().sampling_interval, + kSamplingInterval); + MockProfiler* const sampling_profiler2 = + sampling_profilers_[worker2->GetThreadId()]; + EXPECT_EQ(sampling_profiler2->sampling_params().samples_per_profile, + kSamplesPerProfile); + EXPECT_EQ(sampling_profiler2->sampling_params().sampling_interval, + kSamplingInterval); +} + +TEST_F(ThreadGroupProfilerTest, CollectionBecomesActive_WorkerBecomesActive) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + + EXPECT_EQ(sampling_profilers_.size(), 1); + ASSERT_TRUE(sampling_profilers_.find(worker->GetThreadId()) != + sampling_profilers_.end()); + MockProfiler* const sampling_profiler = + sampling_profilers_[worker->GetThreadId()]; + EXPECT_EQ(sampling_profiler->sampling_params().samples_per_profile, + kSamplesPerProfile); + EXPECT_EQ(sampling_profiler->sampling_params().sampling_interval, + kSamplingInterval); +} + +TEST_F(ThreadGroupProfilerTest, CollectionActive_WorkerInactiveLifecycle) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadExiting(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, CollectionActive_WorkerActiveStartsProfiling) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + + EXPECT_EQ(sampling_profilers_.size(), 1); + ASSERT_TRUE(sampling_profilers_.find(worker->GetThreadId()) != + sampling_profilers_.end()); + MockProfiler* const sampling_profiler = + sampling_profilers_[worker->GetThreadId()]; + EXPECT_EQ(sampling_profiler->sampling_params().samples_per_profile, + kSamplesPerProfile); + EXPECT_EQ(sampling_profiler->sampling_params().sampling_interval, + kSamplingInterval); +} + +TEST_F(ThreadGroupProfilerTest, + CollectionActive_WorkerReactivatedContinuesExistingProfiling) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_EQ(sampling_profilers_.size(), 1); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadIdle(worker_thread); + }); + EXPECT_EQ(sampling_profilers_.size(), 1); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + + EXPECT_EQ(sampling_profilers_.size(), 1); + EXPECT_EQ(sampling_profilers_created_, 1); +} + +TEST_F(ThreadGroupProfilerTest, + CollectionActive_WorkerActiveToIdleContinuesProfiling) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_EQ(sampling_profilers_.size(), 1); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadIdle(worker_thread); + }); + + EXPECT_EQ(sampling_profilers_.size(), 1); + EXPECT_EQ(sampling_profilers_created_, 1); + ASSERT_TRUE(sampling_profilers_.find(worker->GetThreadId()) != + sampling_profilers_.end()); +} + +TEST_F(ThreadGroupProfilerTest, + CollectionActive_WorkerActiveToExitStopsProfiling) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_EQ(sampling_profilers_.size(), 1); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadExiting(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, + CollectionActive_CollectionContinuesOnWorkerExit) { + std::unique_ptr<FakeWorkerThread> worker_to_exit = CreateFakeWorkerThread(); + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + // Start a collection and make the worker thread active to start profiling, + // then have the worker exit. + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker_to_exit->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker_to_exit->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_EQ(sampling_profilers_.size(), 1); + + worker_to_exit->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadExiting(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + // Make a new worker thread active. It should start profiling as part of the + // collection. + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_EQ(sampling_profilers_.size(), 1); +} + +TEST_F(ThreadGroupProfilerTest, + CollectionActive_WorkerProfilesOnlyUntilEndOfCollection) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + AdvanceBySamples(5); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + + EXPECT_EQ(sampling_profilers_.size(), 1); + ASSERT_TRUE(sampling_profilers_.find(worker->GetThreadId()) != + sampling_profilers_.end()); + MockProfiler* const sampling_profiler = + sampling_profilers_[worker->GetThreadId()]; + EXPECT_EQ(sampling_profiler->sampling_params().samples_per_profile, + kSamplesPerProfile - 5); + EXPECT_EQ(sampling_profiler->sampling_params().sampling_interval, + kSamplingInterval); +} + +TEST_F(ThreadGroupProfilerTest, + CollectionActive_WorkerDoesNotProfileNearEndOfCollection) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + AdvanceBySamples(kSamplesPerProfile - 5); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, CollectionEnded_NoWorkers) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + AdvanceToEndOfCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + // Making the worker active should not result in any new profiling. + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, + CollectionEnded_ActiveWorker_FinishesBeforeCollection) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + // Start a collection and make the worker thread active to start profiling. + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_EQ(sampling_profilers_.size(), 1); + + // Advance to just before the end of the collection period, and have the + // profiler complete. + AdvanceBySamples(kSamplesPerProfile - 1); + + EXPECT_EQ(sampling_profilers_.size(), 1); + ASSERT_TRUE(sampling_profilers_.find(worker->GetThreadId()) != + sampling_profilers_.end()); + CompleteProfiling(sampling_profilers_[worker->GetThreadId()]); + EXPECT_TRUE(sampling_profilers_.empty()); + + // Complete the collection. + AdvanceToEndOfCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + // Make the thread idle then active again. This should not result in any new + // profiling. + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadIdle(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +TEST_F(ThreadGroupProfilerTest, + CollectionEnded_ActiveWorker_FinishesAfterCollection) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + // Start a collection and make the worker thread active to start profiling. + InitiateNextCollection(); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_EQ(sampling_profilers_.size(), 1); + + // Advance to the end of the collection. The worker profiling should still be + // taking place since it hasn't completed yet. + AdvanceToEndOfCollection(); + EXPECT_EQ(sampling_profilers_.size(), 1); + + // Complete the worker profiling. + EXPECT_EQ(sampling_profilers_.size(), 1); + ASSERT_TRUE(sampling_profilers_.find(worker->GetThreadId()) != + sampling_profilers_.end()); + CompleteProfiling(sampling_profilers_[worker->GetThreadId()]); + EXPECT_TRUE(sampling_profilers_.empty()); + + // Make the thread idle then active again. This should not result in any new + // profiling. + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadIdle(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); + + worker->RunOnThread([this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +// Ensure that worker thread calls post task runner shutdown have no effect. +TEST_F(ThreadGroupProfilerTest, PostTaskRunnerShutdown) { + std::unique_ptr<FakeWorkerThread> worker = CreateFakeWorkerThread(); + + // Shut down the task runner by destroying the TaskEnvironment. + task_environment_.reset(); + + WaitableEvent on_thread_call_completed{ + WaitableEvent::ResetPolicy::AUTOMATIC, + WaitableEvent::InitialState::NOT_SIGNALED}; + + auto worker_started = [this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadStarted(worker_thread); + }; + worker->RunOnThreadAsync(worker_started, on_thread_call_completed); + + on_thread_call_completed.Wait(); + EXPECT_TRUE(sampling_profilers_.empty()); + + auto worker_active = [this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadActive(worker_thread); + }; + worker->RunOnThreadAsync(worker_active, on_thread_call_completed); + + on_thread_call_completed.Wait(); + EXPECT_TRUE(sampling_profilers_.empty()); + + auto worker_idle = [this](internal::WorkerThread* worker_thread) { + profiler_->OnWorkerThreadIdle(worker_thread); + }; + worker->RunOnThreadAsync(worker_idle, on_thread_call_completed); + + on_thread_call_completed.Wait(); + EXPECT_TRUE(sampling_profilers_.empty()); + + // When the task runner has been shut down, OnWorkerThreadExiting depends on + // ThreadGroupProfiler::Shutdown() being invoked to know that the thread's + // profiling has ceased. Choreograph shutdown to mimic those steps. + auto worker_exit = + [profiler = profiler_.get()](internal::WorkerThread* worker_thread) { + profiler->OnWorkerThreadExiting(worker_thread); + }; + worker->RunOnThreadAsync(worker_exit, on_thread_call_completed); + + profiler_->Shutdown(); + shutdown_started_ = true; + on_thread_call_completed.Wait(); + EXPECT_TRUE(sampling_profilers_.empty()); +} + +} // namespace base
diff --git a/base/task/thread_pool/thread_group_impl.cc b/base/task/thread_pool/thread_group_impl.cc index ecb2669..581569f 100644 --- a/base/task/thread_pool/thread_group_impl.cc +++ b/base/task/thread_pool/thread_group_impl.cc
@@ -9,6 +9,7 @@ #include "base/auto_reset.h" #include "base/metrics/histogram_macros.h" +#include "base/profiler/thread_group_profiler.h" #include "base/sequence_token.h" #include "base/strings/stringprintf.h" #include "base/task/common/checked_lock.h" @@ -234,6 +235,13 @@ service_thread_task_runner, worker_thread_observer, worker_environment, synchronous_thread_start_for_testing, may_block_threshold); + // Create thread group profiler if profiling is enabled after the thread group + // start but before worker threads are created. + if (ThreadGroupProfiler::IsProfilingEnabled()) { + thread_group_profiler_.emplace(service_thread_task_runner, + thread_group_label_); + } + ScopedCommandsExecutor executor(this); CheckedAutoLock auto_lock(lock_); DCHECK(workers_.empty()); @@ -330,10 +338,15 @@ worker_only().worker_thread_ = static_cast<WorkerThread*>(worker); SetBlockingObserverForCurrentThread(this); + if (outer_->thread_group_profiler_) { + outer_->thread_group_profiler_->OnWorkerThreadStarted(worker); + } + if (outer_->worker_started_for_testing_) { - // When |worker_started_for_testing_| is set, the thread that starts workers - // should wait for a worker to have started before starting the next one, - // and there should only be one thread that wakes up workers at a time. + // When |worker_started_for_testing_| is set, the thread that starts + // workers should wait for a worker to have started before starting the + // next one, and there should only be one thread that wakes up workers at + // a time. DCHECK(!outer_->worker_started_for_testing_->IsSignaled()); outer_->worker_started_for_testing_->Signal(); } @@ -363,6 +376,10 @@ worker_only().win_thread_environment.reset(); #endif // BUILDFLAG(IS_WIN) + if (outer_->thread_group_profiler_) { + outer_->thread_group_profiler_->OnWorkerThreadExiting(worker_base); + } + // Count cleaned up workers for tests. It's important to do this here // instead of at the end of CleanupLockRequired() because some side-effects // of cleaning up happen outside the lock (e.g. recording histograms) and @@ -413,8 +430,22 @@ DCHECK(!read_worker().current_shutdown_behavior); ScopedCommandsExecutor executor(outer_.get()); - CheckedAutoLock auto_lock(outer_->lock_); - return GetWorkLockRequired(&executor, worker); + RegisteredTaskSource task_source; + { + CheckedAutoLock auto_lock(outer_->lock_); + task_source = GetWorkLockRequired(&executor, worker); + } + // Notify the profiler on the worker thread status when profiling is enabled. + // This must be called without holding lock_ as lock_ is not a universal + // predecessor that does not satisfy OnWorkerThreadIdle's CheckedLock. + if (outer_->thread_group_profiler_) { + // GetWork is only called when waking up, i.e. from an idle state. No need + // to mark it idle again if no task source available. + if (task_source) { + outer_->thread_group_profiler_->OnWorkerThreadActive(worker); + } + } + return task_source; } RegisteredTaskSource ThreadGroupImpl::WorkerDelegate::GetWorkLockRequired( @@ -500,39 +531,47 @@ ScopedCommandsExecutor workers_executor(outer_.get()); ScopedReenqueueExecutor reenqueue_executor; - CheckedAutoLock auto_lock(outer_->lock_); + RegisteredTaskSource next_task_source; + { + CheckedAutoLock auto_lock(outer_->lock_); - // During shutdown, max_tasks may have been incremented in - // OnShutdownStartedLockRequired(). - if (incremented_max_tasks_for_shutdown_) { - DCHECK(outer_->shutdown_started_); - outer_->DecrementMaxTasksLockRequired(); - if (*read_worker().current_task_priority == TaskPriority::BEST_EFFORT) { - outer_->DecrementMaxBestEffortTasksLockRequired(); + // During shutdown, max_tasks may have been incremented in + // OnShutdownStartedLockRequired(). + if (incremented_max_tasks_for_shutdown_) { + DCHECK(outer_->shutdown_started_); + outer_->DecrementMaxTasksLockRequired(); + if (*read_worker().current_task_priority == TaskPriority::BEST_EFFORT) { + outer_->DecrementMaxBestEffortTasksLockRequired(); + } + incremented_max_tasks_since_blocked_ = false; + incremented_max_best_effort_tasks_since_blocked_ = false; + incremented_max_tasks_for_shutdown_ = false; } - incremented_max_tasks_since_blocked_ = false; - incremented_max_best_effort_tasks_since_blocked_ = false; - incremented_max_tasks_for_shutdown_ = false; + + DCHECK(read_worker().blocking_start_time.is_null()); + DCHECK(!incremented_max_tasks_since_blocked_); + DCHECK(!incremented_max_best_effort_tasks_since_blocked_); + + // Running task bookkeeping. + outer_->DecrementTasksRunningLockRequired( + *read_worker().current_task_priority); + write_worker().current_shutdown_behavior = std::nullopt; + write_worker().current_task_priority = std::nullopt; + + if (transaction_with_task_source) { + outer_->ReEnqueueTaskSourceLockRequired( + &workers_executor, &reenqueue_executor, + std::move(transaction_with_task_source.value())); + } + + next_task_source = GetWorkLockRequired(&workers_executor, + static_cast<WorkerThread*>(worker)); } - - DCHECK(read_worker().blocking_start_time.is_null()); - DCHECK(!incremented_max_tasks_since_blocked_); - DCHECK(!incremented_max_best_effort_tasks_since_blocked_); - - // Running task bookkeeping. - outer_->DecrementTasksRunningLockRequired( - *read_worker().current_task_priority); - write_worker().current_shutdown_behavior = std::nullopt; - write_worker().current_task_priority = std::nullopt; - - if (transaction_with_task_source) { - outer_->ReEnqueueTaskSourceLockRequired( - &workers_executor, &reenqueue_executor, - std::move(transaction_with_task_source.value())); + // Must be called without holding a lock. + if (outer_->thread_group_profiler_ && !task_source) { + outer_->thread_group_profiler_->OnWorkerThreadIdle(worker); } - - return GetWorkLockRequired(&workers_executor, - static_cast<WorkerThread*>(worker)); + return next_task_source; } bool ThreadGroupImpl::WorkerDelegate::CanCleanupLockRequired( @@ -755,6 +794,10 @@ } void ThreadGroupImpl::JoinForTesting() { + // profiler needs to shutdown first to not block worker thread joins. + if (thread_group_profiler_) { + thread_group_profiler_->Shutdown(); + } decltype(workers_) workers_copy; { CheckedAutoLock auto_lock(lock_); @@ -859,6 +902,10 @@ return; } + if (thread_group_profiler_) { + thread_group_profiler_->Shutdown(); + } + // Start a MAY_BLOCK scope on each worker that is already running a task. for (scoped_refptr<WorkerThread>& worker : workers_) { // The delegates of workers inside a ThreadGroupImpl should be
diff --git a/base/task/thread_pool/thread_group_impl.h b/base/task/thread_pool/thread_group_impl.h index b015309..da2249f 100644 --- a/base/task/thread_pool/thread_group_impl.h +++ b/base/task/thread_pool/thread_group_impl.h
@@ -11,6 +11,7 @@ #include "base/base_export.h" #include "base/gtest_prod_util.h" +#include "base/profiler/thread_group_profiler.h" #include "base/synchronization/condition_variable.h" #include "base/synchronization/waitable_event.h" #include "base/task/thread_pool/task_source.h" @@ -23,6 +24,7 @@ namespace base { class WorkerThreadObserver; +class ThreadGroupProfiler; namespace internal { @@ -141,6 +143,12 @@ // https://crbug.com/810464. Uses AtomicRefCount to make its only public // method thread-safe. TrackedRefFactory<ThreadGroupImpl> tracked_ref_factory_; + + // This is set in Start() if profiling is enabled, before any worker thread is + // created. If profiling is not enabled, this will remain std::nullopt. If + // created the ThreadGroupProfiler instance will exist until ThreadGroupImpl + // destruction. + std::optional<ThreadGroupProfiler> thread_group_profiler_; }; } // namespace internal
diff --git a/base/task/thread_pool/thread_pool_impl.cc b/base/task/thread_pool/thread_pool_impl.cc index eba8f8cc..66f9dda 100644 --- a/base/task/thread_pool/thread_pool_impl.cc +++ b/base/task/thread_pool/thread_pool_impl.cc
@@ -338,6 +338,8 @@ // Ensures that there are enough background worker to run BLOCK_SHUTDOWN // tasks. + // Shutdown must happen after service thread STOP as ThreadGroupProfiler + // destructor expects exclusive access to the instance during destruction. foreground_thread_group_->OnShutdownStarted(); if (utility_thread_group_) { utility_thread_group_->OnShutdownStarted();
diff --git a/base/test/task_environment.h b/base/test/task_environment.h index 3d46bc8..0fe6347 100644 --- a/base/test/task_environment.h +++ b/base/test/task_environment.h
@@ -126,7 +126,7 @@ // This type will determine what types of messages will get pumped by the main // thread. // Note: If your test needs to use a custom MessagePump you should - // consider using a SingleThreadTaskExecutor instead. + // consider using a SingleThreadTaskEnvironment instead. enum class MainThreadType { // The main thread doesn't pump system messages. DEFAULT,
diff --git a/build/config/mac/rules.gni b/build/config/mac/rules.gni index b69b7b7..b4ee8b8 100644 --- a/build/config/mac/rules.gni +++ b/build/config/mac/rules.gni
@@ -6,6 +6,14 @@ import("//build/config/apple/symbols.gni") import("//build/config/mac/mac_sdk.gni") +_sanitizer_runtime_names = [] +if (is_asan) { + _sanitizer_runtime_names += [ "libclang_rt.asan_osx_dynamic.dylib" ] +} +if (is_ubsan_any) { + _sanitizer_runtime_names += [ "libclang_rt.ubsan_osx_dynamic.dylib" ] +} + # Generates Info.plist files for Mac apps and frameworks. # # Arguments @@ -216,7 +224,8 @@ "Version=" + invoker.framework_version, _output_name, ] + invoker.framework_contents - _framework_contents = [ _output_name ] + invoker.framework_contents + _framework_contents = [ _output_name ] + invoker.sanitizer_runtime_names + + invoker.framework_contents _framework_toc_file = "$target_out_dir/${target_name}.toc" write_file(_framework_toc_file, _framework_toc) @@ -383,6 +392,7 @@ set_defaults("mac_framework_bundle") { configs = default_shared_library_configs + sanitizer_runtime_names = _sanitizer_runtime_names } # Template to create a Mac executable application bundle.
diff --git a/cc/test/test_layer_tree_frame_sink.cc b/cc/test/test_layer_tree_frame_sink.cc index e7348238..f06e2213 100644 --- a/cc/test/test_layer_tree_frame_sink.cc +++ b/cc/test/test_layer_tree_frame_sink.cc
@@ -96,8 +96,7 @@ return false; frame_sink_manager_ = std::make_unique<viz::FrameSinkManagerImpl>( - viz::FrameSinkManagerImpl::InitParams( - /*shared_bitmap_manager_.get()*/ nullptr)); + viz::FrameSinkManagerImpl::InitParams()); frame_sink_manager_->SetSharedImageInterfaceProviderForTest( shared_image_interface_provider_.get()); @@ -187,11 +186,6 @@ } void TestLayerTreeFrameSink::DetachFromClient() { - // This acts like the |shared_bitmap_manager_| is a global object, while - // in fact it is tied to the lifetime of this class and is destroyed below: - // The shared_bitmap_manager_ has ownership of shared memory for each - // SharedBitmapId that has been reported from the client. Since the client is - // gone that memory can be freed. If we don't then it would leak. DebugScopedSetImplThread impl(task_runner_provider_); if (display_begin_frame_source_) {
diff --git a/cc/trees/layer_tree_frame_sink.h b/cc/trees/layer_tree_frame_sink.h index 9844ede..338a3726 100644 --- a/cc/trees/layer_tree_frame_sink.h +++ b/cc/trees/layer_tree_frame_sink.h
@@ -60,9 +60,8 @@ // Optional and won't be used unless |worker_context_provider_wrapper| is // present. // - // |gpu_memory_buffer_manager| and |shared_bitmap_manager| must outlive the - // LayerTreeFrameSink. |shared_bitmap_manager| is optional (won't be used) if - // |context_provider| is present. |gpu_memory_buffer_manager| is optional + // |gpu_memory_buffer_manager| must outlive the + // LayerTreeFrameSink. |gpu_memory_buffer_manager| is optional // (won't be used) unless |context_provider| is present. LayerTreeFrameSink( scoped_refptr<viz::RasterContextProvider> context_provider,
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 4889482..609dfb0 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -2497,6 +2497,10 @@ input_delegate_->IsHandlingTouchSequence(); } + auto active_types = FrameSequenceTrackerActiveTypes(); + metadata.is_handling_animation = HasMainThreadAnimation(active_types) || + HasCompositorThreadAnimation(active_types); + const base::flat_set<viz::SurfaceRange>& referenced_surfaces = active_tree_->SurfaceRanges(); for (auto& surface_range : referenced_surfaces)
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index 7ae2e00..9f046f2c 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -1652,6 +1652,7 @@ deps = [ ":dependencies", + "//chrome/browser/flags:flags_android", "//chrome/browser/ui", "//chrome/child", "//chrome/common", @@ -1659,17 +1660,19 @@ "//chrome/common/profiler", "//chrome/gpu", "//chrome/renderer", + "//components/crash/android:crash_android", "//components/minidump_uploader", "//components/safe_browsing:buildflags", "//components/safe_browsing/android:safe_browsing_api_handler", "//components/safe_browsing/android:safe_browsing_mobile", "//components/stylus_handwriting/android", + "//components/variations:variations_associated_data", "//content/public/app", ] # Explicit dependency required for JNI registration to be able to # find the native side functions. - if (is_android && is_component_build) { + if (is_component_build) { deps += [ "//components/viz/service", "//device/gamepad", @@ -1677,13 +1680,6 @@ ] } - if (is_android) { - deps += [ - "//chrome/browser/flags:flags_android", - "//components/crash/android:crash_android", - ] - } - if (is_chromeos) { public_deps += [ "//ui/lottie" ] deps += [ "//chrome/browser/ash/schedqos" ]
diff --git a/chrome/VERSION b/chrome/VERSION index b54b32c..b3002dcc 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=134 MINOR=0 -BUILD=6964 +BUILD=6965 PATCH=0
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni index 72f4e769..a67b5df 100644 --- a/chrome/android/chrome_junit_test_java_sources.gni +++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -42,6 +42,7 @@ "junit/src/org/chromium/chrome/browser/app/tabmodel/TabPersistentStoreIntegrationTest.java", "junit/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestratorUnitTest.java", "junit/src/org/chromium/chrome/browser/autofill/AutofillImageFetcherTest.java", + "junit/src/org/chromium/chrome/browser/autofill/AutofillImageFetcherUtilsTest.java", "junit/src/org/chromium/chrome/browser/autofill/AutofillSuggestionTest.java", "junit/src/org/chromium/chrome/browser/autofill/AutofillUiUtilsTest.java", "junit/src/org/chromium/chrome/browser/autofill/PlusAddressesHelperTest.java",
diff --git a/chrome/android/features/tab_ui/java/res/layout/dynamic_bottom_tab_strip_toolbar.xml b/chrome/android/features/tab_ui/java/res/layout/dynamic_bottom_tab_strip_toolbar.xml index c7a6fe77..be9c9da8 100644 --- a/chrome/android/features/tab_ui/java/res/layout/dynamic_bottom_tab_strip_toolbar.xml +++ b/chrome/android/features/tab_ui/java/res/layout/dynamic_bottom_tab_strip_toolbar.xml
@@ -106,6 +106,7 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.5" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintEnd_toEndOf="parent" + android:contentDescription="@string/accessibility_bottom_tab_strip_expand_tab_sheet" /> </androidx.constraintlayout.widget.ConstraintLayout> </org.chromium.chrome.browser.tasks.tab_management.TabGroupUiToolbarView>
diff --git a/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_toolbar_two_row.xml b/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_toolbar_two_row.xml index 95ed97b..6f2407a 100644 --- a/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_toolbar_two_row.xml +++ b/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_toolbar_two_row.xml
@@ -66,7 +66,8 @@ android:layout_height="@dimen/min_touch_target_size" android:minWidth="@dimen/min_touch_target_size" android:layout_marginEnd="12dp" - android:visibility="gone"/> + android:visibility="gone" + android:contentDescription="@string/manage_sharing_content_description"/> <include layout="@layout/toolbar_new_tab_and_menu_button"/> </LinearLayout> <LinearLayout
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ActionConfirmationManager.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ActionConfirmationManager.java index 889c0a6..ee238984 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ActionConfirmationManager.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ActionConfirmationManager.java
@@ -92,7 +92,7 @@ R.string.delete_shared_tab_group_dialog_title, R.string.delete_shared_tab_group_description, groupTitle, - R.string.delete_tab_group_menu_item, + R.string.delete_tab_group_action, onResult); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java index 8487f6b..69191b200 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java
@@ -11,6 +11,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import org.chromium.base.Callback; import org.chromium.base.CallbackController; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.OneshotSupplier; @@ -25,6 +26,7 @@ import org.chromium.chrome.browser.hub.ResourceButtonData; import org.chromium.chrome.browser.incognito.reauth.IncognitoReauthController; import org.chromium.chrome.browser.incognito.reauth.IncognitoReauthManager.IncognitoReauthCallback; +import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.IncognitoTabModel; import org.chromium.chrome.browser.tabmodel.IncognitoTabModelObserver; import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter; @@ -35,6 +37,7 @@ import org.chromium.chrome.tab_ui.R; import org.chromium.components.sensitive_content.SensitiveContentFeatures; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.DoubleConsumer; /** A {@link Pane} representing the incognito tab switcher. */ @@ -48,14 +51,50 @@ @Override public void didBecomeEmpty() { - mReferenceButtonDataSupplier.set(null); - if (isFocused()) { - @Nullable PaneHubController controller = getPaneHubController(); - assert controller != null - : "isFocused requires a non-null PaneHubController."; - controller.focusPane(PaneId.TAB_SWITCHER); - } - destroyTabSwitcherPaneCoordinator(); + TabSwitcherPaneCoordinator paneCoordinator = getTabSwitcherPaneCoordinator(); + assert paneCoordinator != null; + + ObservableSupplier<Boolean> isAnimatingSupplier = + paneCoordinator.getIsRecyclerViewAnimatorRunning(); + + AtomicBoolean startedAnimating = new AtomicBoolean(false); + + // Create Callback object to allow us to pass a reference to said callback + // inside the onResult method. + Callback<Boolean> onAnimationStatusChange = + new Callback<>() { + @Override + public void onResult(Boolean isAnimating) { + // This ensures that: + // a) The RecyclerView has started any final + // animation prior to changing tab switcher panes. + // b) The animation only runs when the tab grid dialog is not + // visible. + Supplier<Boolean> dialogShowingOrAnimationSupplier = + paneCoordinator + .getTabGridDialogShowingOrAnimationSupplier(); + boolean isTabGridDialogVisible = + dialogShowingOrAnimationSupplier != null + && dialogShowingOrAnimationSupplier.get(); + if (!isTabGridDialogVisible + && (isAnimating || !startedAnimating.get())) { + startedAnimating.set(isAnimating); + return; + } + mReferenceButtonDataSupplier.set(null); + if (isFocused()) { + @Nullable + PaneHubController controller = getPaneHubController(); + assert controller != null + : "isFocused requires a non-null" + + " PaneHubController."; + controller.focusPane(PaneId.TAB_SWITCHER); + } + destroyTabSwitcherPaneCoordinator(); + isAnimatingSupplier.removeObserver(this); + } + }; + isAnimatingSupplier.addObserver(onAnimationStatusChange); } }; @@ -206,8 +245,8 @@ } @Override - public int getCurrentTabId() { - return TabModelUtils.getCurrentTabId( + public @Nullable Tab getCurrentTab() { + return TabModelUtils.getCurrentTab( mIncognitoTabGroupModelFilterSupplier.get().getTabModel()); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPaneUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPaneUnitTest.java index b0fb910..4bca061 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPaneUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPaneUnitTest.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.tasks.tab_management; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -87,6 +88,8 @@ mIncognitoReauthControllerSupplier = new OneshotSupplierImpl<>(); private final ObservableSupplierImpl<EdgeToEdgeController> mEdgeToEdgeSupplier = new ObservableSupplierImpl<>(); + private final ObservableSupplierImpl<Boolean> mIsRecyclerViewAnimatorRunningSupplier = + new ObservableSupplierImpl<>(false); private Context mContext; private IncognitoTabSwitcherPane mIncognitoTabSwitcherPane; @@ -115,6 +118,8 @@ when(mTabGroupModelFilter.getTabModel()).thenReturn(mIncognitoTabModel); when(mTabGroupModelFilter.isTabModelRestored()).thenReturn(true); + when(mTabSwitcherPaneCoordinator.getIsRecyclerViewAnimatorRunning()) + .thenReturn(mIsRecyclerViewAnimatorRunningSupplier); mIncognitoTabSwitcherPane = new IncognitoTabSwitcherPane( @@ -400,6 +405,10 @@ IncognitoTabModelObserver observer = mIncognitoTabModelObserverCaptor.getValue(); observer.didBecomeEmpty(); + mIsRecyclerViewAnimatorRunningSupplier.set(true); + mIsRecyclerViewAnimatorRunningSupplier.set(false); + ShadowLooper.runUiThreadTasks(); + assertNull(mIncognitoTabSwitcherPane.getReferenceButtonDataSupplier().get()); verify(mPaneHubController).focusPane(PaneId.TAB_SWITCHER); assertNull(mIncognitoTabSwitcherPane.getTabSwitcherPaneCoordinator()); @@ -416,7 +425,12 @@ buttonData.resolveContentDescription(mContext)); assertNotNull(buttonData.resolveIcon(mContext)); + mIncognitoTabSwitcherPane.createTabSwitcherPaneCoordinator(); observer.didBecomeEmpty(); + mIsRecyclerViewAnimatorRunningSupplier.set(true); + mIsRecyclerViewAnimatorRunningSupplier.set(false); + ShadowLooper.runUiThreadTasks(); + assertNull(mIncognitoTabSwitcherPane.getReferenceButtonDataSupplier().get()); verify(mPaneHubController, times(2)).focusPane(PaneId.TAB_SWITCHER); assertNull(mIncognitoTabSwitcherPane.getTabSwitcherPaneCoordinator());
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 dc5de93..f879ed3 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
@@ -1315,7 +1315,15 @@ new CollaborationActivityMessageCardViewModel( mActivity, this::showRecentActivityOrDismissActivityMessageCard, - (unused) -> removeCollaborationActivityMessageCard()); + (unused) -> { + @Nullable Token tabGroupId = getCurrentTabGroupId(); + if (mMessagingBackendService != null && tabGroupId != null) { + mMessagingBackendService.clearDirtyTabMessagesForGroup( + EitherGroupId.createLocalId( + new LocalTabGroupId(tabGroupId))); + } + removeCollaborationActivityMessageCard(); + }); } mCollaborationActivityPropertyModel.updateDescriptionText( mActivity, tabsAdded, tabsChanged, tabsClosed);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListCoordinator.java index eb55bf4..8a46b081 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListCoordinator.java
@@ -185,12 +185,14 @@ Callback<Drawable> callback) { Resources resources = context.getResources(); int faviconSizePixels = resources.getDimensionPixelSize(R.dimen.tab_grid_favicon_size); + FaviconHelper faviconHelper = new FaviconHelper(); FaviconImageCallback faviconImageCallback = - (Bitmap bitmap, GURL ignored) -> - onForeignFavicon(context, fallbackProvider, callback, bitmap); - new FaviconHelper() - .getForeignFaviconImageForURL( - profile, url, faviconSizePixels, faviconImageCallback); + (Bitmap bitmap, GURL ignored) -> { + onForeignFavicon(context, fallbackProvider, callback, bitmap); + faviconHelper.destroy(); + }; + faviconHelper.getForeignFaviconImageForURL( + profile, url, faviconSizePixels, faviconImageCallback); } private static void onForeignFavicon(
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListItemAnimator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListItemAnimator.java index a82665e..e9c962f 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListItemAnimator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListItemAnimator.java
@@ -16,10 +16,13 @@ import android.view.View; import android.view.animation.Interpolator; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.recyclerview.widget.RecyclerView.ViewHolder; import androidx.recyclerview.widget.SimpleItemAnimator; +import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.ui.interpolators.Interpolators; import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter; @@ -133,13 +136,20 @@ } } - private AnimatorHolder mAdds = new AnimatorHolder("Add"); - private AnimatorHolder mChanges = new AnimatorHolder("Change"); - private AnimatorHolder mMoves = new AnimatorHolder("Move"); - private AnimatorHolder mRemovals = new AnimatorHolder("Removal"); + private final AnimatorHolder mAdds = new AnimatorHolder("Add"); + private final AnimatorHolder mChanges = new AnimatorHolder("Change"); + private final AnimatorHolder mMoves = new AnimatorHolder("Move"); + private final AnimatorHolder mRemovals = new AnimatorHolder("Removal"); + private final @NonNull ObservableSupplierImpl<Boolean> mIsAnimatorRunningSupplier; TabListItemAnimator() { + this(new ObservableSupplierImpl<>(false)); + } + + @VisibleForTesting + TabListItemAnimator(@NonNull ObservableSupplierImpl<Boolean> isAnimatorRunningSupplier) { setRemoveDuration(DEFAULT_REMOVE_DURATION); + mIsAnimatorRunningSupplier = isAnimatorRunningSupplier; } @Override @@ -227,6 +237,7 @@ @Override public void onAnimationStart(Animator animator) { dispatchAddStarting(holder); + mIsAnimatorRunningSupplier.set(true); } @Override @@ -310,6 +321,7 @@ @Override public void onAnimationStart(Animator animator) { dispatchChangeStarting(oldHolder, true); + mIsAnimatorRunningSupplier.set(true); } @Override @@ -346,6 +358,7 @@ @Override public void onAnimationStart(Animator animator) { dispatchChangeStarting(newHolder, false); + mIsAnimatorRunningSupplier.set(true); } @Override @@ -397,6 +410,7 @@ @Override public void onAnimationStart(Animator animator) { dispatchMoveStarting(holder); + mIsAnimatorRunningSupplier.set(true); } @Override @@ -454,6 +468,7 @@ @Override public void onAnimationStart(Animator animator) { dispatchRemoveStarting(holder); + mIsAnimatorRunningSupplier.set(true); } @Override @@ -497,6 +512,7 @@ @Override public void onAnimationStart(Animator animator) { dispatchRemoveStarting(holder); + mIsAnimatorRunningSupplier.set(true); } @Override @@ -517,9 +533,14 @@ void dispatchFinishedWhenAllAnimationsDone() { if (!isRunning()) { dispatchAnimationsFinished(); + mIsAnimatorRunningSupplier.set(false); } } + public ObservableSupplier<Boolean> getIsAnimatorRunningSupplier() { + return mIsAnimatorRunningSupplier; + } + private Interpolator getRearrangeInterpolator() { return Interpolators.STANDARD_INTERPOLATOR; }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListItemAnimatorUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListItemAnimatorUnitTest.java index f4f1895..a397ad0 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListItemAnimatorUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListItemAnimatorUnitTest.java
@@ -32,11 +32,13 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.Spy; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.shadows.ShadowLooper; import org.chromium.base.Callback; +import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.tasks.tab_management.TabListModel.CardProperties.ModelType; import org.chromium.ui.modelutil.PropertyKey; @@ -49,12 +51,16 @@ public class TabListItemAnimatorUnitTest { @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Spy + private ObservableSupplierImpl<Boolean> mIsAnimatorRunningSupplier = + new ObservableSupplierImpl<>(false); + @Mock private SimpleRecyclerViewAdapter mAdapter; private TabListItemAnimator mItemAnimator; @Before public void setUp() { - mItemAnimator = spy(new TabListItemAnimator()); + mItemAnimator = spy(new TabListItemAnimator(mIsAnimatorRunningSupplier)); } private static void emptyBind(PropertyModel model, View view, PropertyKey key) {} @@ -442,4 +448,32 @@ verify(mItemAnimator, times(4)).dispatchFinishedWhenAllAnimationsDone(); assertFalse(mItemAnimator.isRunning()); } + + @Test + public void animatorRunningSupplier_RunAnimations() { + var removedHolder = buildViewHolder(TAB, /* useShrinkCloseAnimation= */ true); + mItemAnimator.animateAdd(removedHolder); + + mItemAnimator.runPendingAnimations(); + ShadowLooper.shadowMainLooper().idle(); + + InOrder inOrder = Mockito.inOrder(mIsAnimatorRunningSupplier); + inOrder.verify(mIsAnimatorRunningSupplier).set(true); + inOrder.verify(mIsAnimatorRunningSupplier).set(false); + assertFalse(mIsAnimatorRunningSupplier.get()); + } + + @Test + public void animatorRunningSupplier_EndAnimations() { + var removedHolder = buildViewHolder(TAB, /* useShrinkCloseAnimation= */ true); + mItemAnimator.animateAdd(removedHolder); + + mItemAnimator.endAnimations(); + ShadowLooper.shadowMainLooper().idle(); + + InOrder inOrder = Mockito.inOrder(mIsAnimatorRunningSupplier); + inOrder.verify(mIsAnimatorRunningSupplier).set(true); + inOrder.verify(mIsAnimatorRunningSupplier).set(false); + assertFalse(mIsAnimatorRunningSupplier.get()); + } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java index 13e01d4..f2c90a882 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java
@@ -20,6 +20,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import org.chromium.base.supplier.ObservableSupplier; import org.chromium.chrome.browser.tab_ui.RecyclerViewPosition; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.tab_ui.R; @@ -104,6 +105,14 @@ } /** + * Returns a boolean indicating whether any animator in {@link TabListItemAnimator} is running. + */ + @NonNull + ObservableSupplier<Boolean> getIsAnimatorRunningSupplier() { + return mTabListItemAnimator.getIsAnimatorRunningSupplier(); + } + + /** * @param tabIndex The index in the RecyclerView of the tab. * @param tabId The tab ID of the tab. * @return The {@link Rect} of the thumbnail of the tab in global coordinates.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabModelNotificationDotManager.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabModelNotificationDotManager.java index 872dbcc..8dfb14c1 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabModelNotificationDotManager.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabModelNotificationDotManager.java
@@ -15,7 +15,12 @@ import org.chromium.chrome.browser.collaboration.messaging.MessagingBackendServiceFactory; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab.TabCreationState; +import org.chromium.chrome.browser.tab.TabLaunchType; +import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter; +import org.chromium.chrome.browser.tabmodel.TabGroupModelFilterObserver; import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.components.collaboration.CollaborationService; @@ -57,11 +62,56 @@ } }; + // Any operation aside from grouping a tab for restoring from TabGroupSyncService should "just + // work" via the MessagingBackendService so no need to observe anything else. + private final TabGroupModelFilterObserver mTabGroupModelFilterObserver = + new TabGroupModelFilterObserver() { + @Override + public void didMergeTabToGroup(Tab movedTab) { + maybeUpdateForTab(movedTab, /* mayAddDot= */ true); + } + }; + + // MessagingBackendService and TabGroupSyncService see tabs moving between the hidden and open + // states as essentially no-ops. This observer is necessary to ensure dots are updated + // correctly. + private final TabModelObserver mTabModelObserver = + new TabModelObserver() { + @Override + public void willCloseTab(Tab tab, boolean didCloseAlone) { + maybeUpdateForTab(tab, /* mayAddDot= */ false); + } + + @Override + public void onFinishingTabClosure(Tab tab) { + maybeUpdateForTab(tab, /* mayAddDot= */ false); + } + + @Override + public void tabRemoved(Tab tab) { + maybeUpdateForTab(tab, /* mayAddDot= */ false); + } + + @Override + public void tabClosureUndone(Tab tab) { + maybeUpdateForTab(tab, /* mayAddDot= */ true); + } + + @Override + public void didAddTab( + Tab tab, + @TabLaunchType int type, + @TabCreationState int creationState, + boolean markedForSelection) { + maybeUpdateForTab(tab, /* mayAddDot= */ true); + } + }; + private final ObservableSupplierImpl<Boolean> mNotificationDotObservableSupplier = new ObservableSupplierImpl<>(false); private final CallbackController mCallbackController = new CallbackController(); private @Nullable MessagingBackendService mMessagingBackendService; - private @Nullable TabModel mTabModel; + private @Nullable TabGroupModelFilter mTabGroupModelFilter; private boolean mTabModelSelectorInitialized; private boolean mMessagingBackendServiceInitialized; @@ -72,10 +122,13 @@ * observed. However, the selector is needed to know when the tab model is initialized. */ public void initWithNative(TabModelSelector tabModelSelector) { - mTabModel = tabModelSelector.getModel(/* incognito= */ false); - assert mTabModel != null : "TabModel & native should be initialized."; + mTabGroupModelFilter = + tabModelSelector + .getTabGroupModelFilterProvider() + .getTabGroupModelFilter(/* incognito= */ false); + assert mTabGroupModelFilter != null : "TabModel & native should be initialized."; - Profile profile = mTabModel.getProfile(); + Profile profile = mTabGroupModelFilter.getTabModel().getProfile(); CollaborationService collaborationService = CollaborationServiceFactory.getForProfile(profile); if (!collaborationService.getServiceStatus().isAllowedToJoin()) return; @@ -87,6 +140,9 @@ mCallbackController.makeCancelable( unused -> { mTabModelSelectorInitialized = true; + mTabGroupModelFilter.addTabGroupObserver(mTabGroupModelFilterObserver); + mTabGroupModelFilter.getTabModel().addObserver(mTabModelObserver); + computeUpdate(); })); } @@ -105,6 +161,19 @@ if (mMessagingBackendService != null) { mMessagingBackendService.removePersistentMessageObserver(mPersistentMessageObserver); } + if (mTabGroupModelFilter != null) { + mTabGroupModelFilter.removeTabGroupObserver(mTabGroupModelFilterObserver); + mTabGroupModelFilter.getTabModel().removeObserver(mTabModelObserver); + } + } + + private void maybeUpdateForTab(Tab tab, boolean mayAddDot) { + @Nullable Boolean showingDot = mNotificationDotObservableSupplier.get(); + boolean stateWillBeUnchanged = showingDot != null && showingDot == mayAddDot; + if (tab.getTabGroupId() == null || stateWillBeUnchanged) { + return; + } + computeUpdate(); } private void computeUpdate() { @@ -115,7 +184,9 @@ } private boolean anyTabsInModelHaveDirtyBit() { - assert mTabModel != null && mMessagingBackendService != null; + assert mTabGroupModelFilter != null && mMessagingBackendService != null; + + TabModel tabModel = mTabGroupModelFilter.getTabModel(); List<PersistentMessage> messages = mMessagingBackendService.getMessages( @@ -124,7 +195,8 @@ int tabId = MessageUtils.extractTabId(message); if (tabId == Tab.INVALID_TAB_ID) continue; - if (mTabModel.getTabById(tabId) != null) return true; + @Nullable Tab tab = tabModel.getTabById(tabId); + if (tab != null && !tab.isClosing()) return true; } return false; }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabModelNotificationDotManagerUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabModelNotificationDotManagerUnitTest.java index dc6408d..74ca0ef 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabModelNotificationDotManagerUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabModelNotificationDotManagerUnitTest.java
@@ -21,12 +21,19 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import org.chromium.base.Token; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.collaboration.CollaborationServiceFactory; import org.chromium.chrome.browser.collaboration.messaging.MessagingBackendServiceFactory; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab.TabCreationState; +import org.chromium.chrome.browser.tab.TabLaunchType; +import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter; +import org.chromium.chrome.browser.tabmodel.TabGroupModelFilterObserver; +import org.chromium.chrome.browser.tabmodel.TabGroupModelFilterProvider; import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; import org.chromium.components.collaboration.CollaborationService; @@ -47,11 +54,14 @@ public class TabModelNotificationDotManagerUnitTest { private static final int EXISTING_TAB_ID = 5; private static final int NON_EXISTANT_TAB_ID = 7; + private static final Token TAB_GROUP_ID = new Token(378L, 4378L); @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); @Mock private Profile mProfile; @Mock private TabModelSelector mTabModelSelector; + @Mock private TabGroupModelFilterProvider mTabGroupModelFilterProvider; + @Mock private TabGroupModelFilter mTabGroupModelFilter; @Mock private TabModel mTabModel; @Mock private Tab mTab; @Mock private MessagingBackendService mMessagingBackendService; @@ -60,6 +70,8 @@ @Captor private ArgumentCaptor<PersistentMessageObserver> mPersistentMessageObserverCaptor; @Captor private ArgumentCaptor<TabModelSelectorObserver> mTabModelSelectorObserverCaptor; + @Captor private ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; + @Captor private ArgumentCaptor<TabGroupModelFilterObserver> mTabGroupModelFilterObserverCaptor; private TabModelNotificationDotManager mTabModelNotificationDotManager; private PersistentMessage mDirtyTabMessage = new PersistentMessage(); @@ -76,7 +88,11 @@ MessagingBackendServiceFactory.setForTesting(mMessagingBackendService); when(mTabModelSelector.isTabStateInitialized()).thenReturn(false); - when(mTabModelSelector.getModel(false)).thenReturn(mTabModel); + when(mTabModelSelector.getTabGroupModelFilterProvider()) + .thenReturn(mTabGroupModelFilterProvider); + when(mTabGroupModelFilterProvider.getTabGroupModelFilter(false)) + .thenReturn(mTabGroupModelFilter); + when(mTabGroupModelFilter.getTabModel()).thenReturn(mTabModel); when(mTabModel.getProfile()).thenReturn(mProfile); when(mTabModel.getTabById(EXISTING_TAB_ID)).thenReturn(mTab); @@ -109,6 +125,9 @@ createDirtyTabMessageForIds(List.of(EXISTING_TAB_ID)); mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); + verify(mTabModel).addObserver(mTabModelObserverCaptor.capture()); + verify(mTabGroupModelFilter) + .addTabGroupObserver(mTabGroupModelFilterObserverCaptor.capture()); assertFalse(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); mPersistentMessageObserverCaptor.getValue().onMessagingBackendServiceInitialized(); @@ -123,6 +142,9 @@ assertFalse(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); + verify(mTabModel).addObserver(mTabModelObserverCaptor.capture()); + verify(mTabGroupModelFilter) + .addTabGroupObserver(mTabGroupModelFilterObserverCaptor.capture()); assertTrue(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); } @@ -183,10 +205,68 @@ assertTrue(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); } + @Test + public void testComputeUpdateTabGroupModelFilterObserver() { + initializeBothBackends(); + createDirtyTabMessageForIds(List.of(EXISTING_TAB_ID)); + + mTabGroupModelFilterObserverCaptor.getValue().didMergeTabToGroup(mTab); + assertFalse(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); + } + + @Test + public void testComputeUpdateTabModelObserver() { + initializeBothBackends(); + createDirtyTabMessageForIds(List.of(EXISTING_TAB_ID)); + + mTabModelObserverCaptor + .getValue() + .didAddTab( + mTab, + TabLaunchType.FROM_SYNC_BACKGROUND, + TabCreationState.LIVE_IN_BACKGROUND, + /* markedForSelection= */ false); + assertFalse(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); + + when(mTab.getTabGroupId()).thenReturn(TAB_GROUP_ID); + + mTabModelObserverCaptor + .getValue() + .didAddTab( + mTab, + TabLaunchType.FROM_SYNC_BACKGROUND, + TabCreationState.LIVE_IN_BACKGROUND, + /* markedForSelection= */ false); + assertTrue(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); + + when(mTabModel.getTabById(EXISTING_TAB_ID)).thenReturn(null); + mTabModelObserverCaptor.getValue().tabRemoved(mTab); + assertFalse(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); + + when(mTabModel.getTabById(EXISTING_TAB_ID)).thenReturn(mTab); + mTabModelObserverCaptor.getValue().tabClosureUndone(mTab); + assertTrue(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); + + when(mTabModel.getTabById(EXISTING_TAB_ID)).thenReturn(null); + mTabModelObserverCaptor.getValue().onFinishingTabClosure(mTab); + assertFalse(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); + + when(mTabModel.getTabById(EXISTING_TAB_ID)).thenReturn(mTab); + mTabModelObserverCaptor.getValue().tabClosureUndone(mTab); + assertTrue(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); + + when(mTabModel.getTabById(EXISTING_TAB_ID)).thenReturn(null); + mTabModelObserverCaptor.getValue().willCloseTab(mTab, true); + assertFalse(mTabModelNotificationDotManager.getNotificationDotObservableSupplier().get()); + } + private void initializeBothBackends() { when(mTabModelSelector.isTabStateInitialized()).thenReturn(true); mPersistentMessageObserverCaptor.getValue().onMessagingBackendServiceInitialized(); mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); + verify(mTabModel).addObserver(mTabModelObserverCaptor.capture()); + verify(mTabGroupModelFilter) + .addTabGroupObserver(mTabGroupModelFilterObserverCaptor.capture()); } private void createDirtyTabMessageForIds(List<Integer> ids) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPane.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPane.java index c5580341..f250b19 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPane.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPane.java
@@ -190,8 +190,8 @@ } @Override - public int getCurrentTabId() { - return TabModelUtils.getCurrentTabId(mTabGroupModelFilterSupplier.get().getTabModel()); + public @Nullable Tab getCurrentTab() { + return TabModelUtils.getCurrentTab(mTabGroupModelFilterSupplier.get().getTabModel()); } @Override
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java index cd83457..0b449af 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java
@@ -54,6 +54,7 @@ import org.chromium.chrome.browser.tab_ui.TabSwitcher; import org.chromium.chrome.browser.tab_ui.TabSwitcherCustomViewManager; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; +import org.chromium.chrome.browser.toolbar.ToolbarPositionController; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeUtils; import org.chromium.chrome.browser.user_education.UserEducationHelper; @@ -264,15 +265,15 @@ public @NonNull HubLayoutAnimatorProvider createShowHubLayoutAnimatorProvider( @NonNull HubContainerView hubContainerView) { assert !DeviceFormFactor.isNonMultiDisplayContextOnTablet(hubContainerView.getContext()); - int tabId = getCurrentTabId(); - if (getTabListMode() == TabListMode.LIST || tabId == Tab.INVALID_TAB_ID) { + @Nullable Tab tab = getCurrentTab(); + if (getTabListMode() == TabListMode.LIST || tab == null) { return FadeHubLayoutAnimationFactory.createFadeInAnimatorProvider( hubContainerView, HUB_LAYOUT_FADE_DURATION_MS, mOnToolbarAlphaChange); } @ColorInt int backgroundColor = getAnimationBackgroundColor(); SyncOneshotSupplier<ShrinkExpandAnimationData> animationDataSupplier = - requestAnimationData(hubContainerView, /* isShrink= */ true, tabId); + requestAnimationData(hubContainerView, /* isShrink= */ true, tab); return ShrinkExpandHubLayoutAnimationFactory.createShrinkTabAnimatorProvider( hubContainerView, animationDataSupplier, @@ -285,15 +286,15 @@ public @NonNull HubLayoutAnimatorProvider createHideHubLayoutAnimatorProvider( @NonNull HubContainerView hubContainerView) { assert !DeviceFormFactor.isNonMultiDisplayContextOnTablet(hubContainerView.getContext()); - int tabId = getCurrentTabId(); - if (getTabListMode() == TabListMode.LIST || tabId == Tab.INVALID_TAB_ID) { + Tab tab = getCurrentTab(); + if (getTabListMode() == TabListMode.LIST || tab == null) { return FadeHubLayoutAnimationFactory.createFadeOutAnimatorProvider( hubContainerView, HUB_LAYOUT_FADE_DURATION_MS, mOnToolbarAlphaChange); } @ColorInt int backgroundColor = getAnimationBackgroundColor(); SyncOneshotSupplier<ShrinkExpandAnimationData> animationDataSupplier = - requestAnimationData(hubContainerView, /* isShrink= */ false, tabId); + requestAnimationData(hubContainerView, /* isShrink= */ false, tab); return ShrinkExpandHubLayoutAnimationFactory.createExpandTabAnimatorProvider( hubContainerView, animationDataSupplier, @@ -313,7 +314,7 @@ } private SyncOneshotSupplier<ShrinkExpandAnimationData> requestAnimationData( - @NonNull HubContainerView hubContainerView, boolean isShrink, int tabId) { + @NonNull HubContainerView hubContainerView, boolean isShrink, @NonNull Tab tab) { SyncOneshotSupplierImpl<ShrinkExpandAnimationData> animationDataSupplier = new SyncOneshotSupplierImpl<>(); @Nullable TabSwitcherPaneCoordinator coordinator = getTabSwitcherPaneCoordinator(); @@ -341,6 +342,9 @@ finalBottomCornerRadius = 0; } + int tabId = tab.getId(); + boolean isTopToolbar = ToolbarPositionController.shouldShowToolbarOnTop(tab); + Runnable provideAnimationData = () -> { Rect hubRect = new Rect(); @@ -358,6 +362,7 @@ } int leftOffset = 0; + // Account for the hub's search box container height. int searchBoxHeight = OmniboxFeatures.sAndroidHubSearch.isEnabled() ? HubUtils.getSearchBoxHeight( @@ -365,9 +370,16 @@ R.id.hub_toolbar, R.id.toolbar_action_container) : 0; - // Account for the hub's search box container height. - recyclerViewRect.offset(0, -searchBoxHeight); - recyclerViewRect.bottom += searchBoxHeight; + // If the bottom toolbar will show for the tab we need to offset the + // initial/final location by the height of the toolbar. + int topToolbarOffset = + isTopToolbar + ? 0 + : res.getDimensionPixelSize(R.dimen.toolbar_height_no_shadow); + int topOffset = searchBoxHeight + topToolbarOffset; + + recyclerViewRect.offset(0, -topOffset); + recyclerViewRect.bottom += topOffset; if (isShrink) { initialRect = recyclerViewRect; finalRect = coordinator.getTabThumbnailRect(tabId); @@ -512,8 +524,8 @@ */ protected abstract void showAllTabs(); - /** Returns the current selected tab ID. */ - protected abstract int getCurrentTabId(); + /** Returns the current selected tab. */ + protected abstract @Nullable Tab getCurrentTab(); /** Returns whether to eagerly create the coordinator in the {@link LoadHint.WARM} state. */ protected abstract boolean shouldEagerlyCreateCoordinator();
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java index 58d50098..d13dfd5de 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinator.java
@@ -478,12 +478,24 @@ return mTabGridDialogVisibilitySupplier; } + /** Provides information on whether the tab grid dialog is showing or animating. */ + public @Nullable ObservableSupplier<Boolean> getTabGridDialogShowingOrAnimationSupplier() { + return mTabGridDialogCoordinator != null + ? mTabGridDialogCoordinator.getShowingOrAnimationSupplier() + : null; + } + /** Returns a {@link TabSwitcherCustomViewManager.Delegate} for supplying custom views. */ public @Nullable TabSwitcherCustomViewManager.Delegate getTabSwitcherCustomViewManagerDelegate() { return mMediator; } + /** Indicates whether any animator for the {@link TabListRecyclerView} is running. */ + public ObservableSupplier<Boolean> getIsRecyclerViewAnimatorRunning() { + return mTabListCoordinator.getContainerView().getIsAnimatorRunningSupplier(); + } + /** Returns the number of elements in the tab switcher's tab list model. */ public int getTabSwitcherTabListModelSize() { return mTabListCoordinator.getTabListModelSize();
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java index 59af965c1..be3cb6e9 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java
@@ -193,11 +193,7 @@ // TODO(crbug.com/40067282): Because the show/hide animation already uses the // RootUiCoordinator's ScrimCoordinator, a separate instance is needed. However, the way // this is implemented the status bar color is not updated. This should be fixed. - return new ScrimCoordinator( - activity, - /* systemUiScrimDelegate= */ null, - coordinator, - activity.getColor(R.color.omnibox_focused_fading_background_color)); + return new ScrimCoordinator(activity, /* systemUiScrimDelegate= */ null, coordinator); } @VisibleForTesting
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 9be03f3..02b196b 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
@@ -29,6 +29,7 @@ import org.chromium.chrome.browser.tab_group_sync.TabGroupSyncUtils; import org.chromium.chrome.browser.tabmodel.TabClosureParams; import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter; +import org.chromium.chrome.browser.tabmodel.TabGroupTitleUtils; import org.chromium.chrome.browser.tabmodel.TabList; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelActionListener; @@ -220,12 +221,20 @@ memberRole); } }; + + // The default title is not included in the savedTabGroup data. Use the filter to get the + // last known title for the tab group. + String title = savedTabGroup.title; + @Nullable Tab tab = tabModel.getTabById(tabId); + if (tab != null) { + int rootId = tab.getRootId(); + title = TabGroupTitleUtils.getDisplayableTitle(context, filter, rootId); + } + if (memberRole == MemberRole.OWNER) { - actionConfirmationManager.processDeleteSharedGroupAttempt( - savedTabGroup.title, onActionConfirmation); + actionConfirmationManager.processDeleteSharedGroupAttempt(title, onActionConfirmation); } else if (memberRole == MemberRole.MEMBER) { - actionConfirmationManager.processLeaveGroupAttempt( - savedTabGroup.title, onActionConfirmation); + actionConfirmationManager.processLeaveGroupAttempt(title, onActionConfirmation); } else { showGenericErrorDialog(context, modalDialogManager); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiUtilsUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiUtilsUnitTest.java index dbb2b99..3d8feea 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiUtilsUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiUtilsUnitTest.java
@@ -113,6 +113,8 @@ when(mTabModel.getTabById(TAB_ID)).thenReturn(mTab); when(mTab.getRootId()).thenReturn(ROOT_ID); when(mFilter.getRelatedTabListForRootId(ROOT_ID)).thenReturn(mTabsToClose); + when(mFilter.getRelatedTabCountForRootId(ROOT_ID)).thenReturn(mTabsToClose.size()); + when(mFilter.getTabGroupTitle(ROOT_ID)).thenReturn(GROUP_TITLE); when(mTabModel.getTabById(TAB_ID)).thenReturn(mTab); when(mTab.isClosing()).thenReturn(false); when(mTab.getId()).thenReturn(TAB_ID); @@ -328,7 +330,9 @@ .when(mActionConfirmationManager) .processLeaveGroupAttempt(any(), any()); mockIdentity(EMAIL2, GAIA_ID2); - createSyncGroup(COLLABORATION_ID1); + SavedTabGroup group = createSyncGroup(COLLABORATION_ID1); + group.title = null; + when(mFilter.getTabGroupTitle(ROOT_ID)).thenReturn(null); createSharedGroup(GROUP_MEMBER1, GROUP_MEMBER2); TabUiUtils.exitSharedTabGroupWithDialog( @@ -337,7 +341,7 @@ mActionConfirmationManager, mModalDialogManager, TAB_ID); - verify(mActionConfirmationManager).processLeaveGroupAttempt(eq(GROUP_TITLE), any()); + verify(mActionConfirmationManager).processLeaveGroupAttempt(eq("1 tab"), any()); verify(mDataSharingService, never()).removeMember(any(), any(), any()); }
diff --git a/chrome/android/features/tab_ui/java/strings/android_chrome_tab_ui_strings.grd b/chrome/android/features/tab_ui/java/strings/android_chrome_tab_ui_strings.grd index fcb6fdecd..bf9118f5 100644 --- a/chrome/android/features/tab_ui/java/strings/android_chrome_tab_ui_strings.grd +++ b/chrome/android/features/tab_ui/java/strings/android_chrome_tab_ui_strings.grd
@@ -200,6 +200,9 @@ <message name="IDS_TAB_GRID_MANAGE_BUTTON_TEXT" desc="Text for managing the sharing of the current tab group from the tab group dialog toolbar."> Manage </message> + <message name="IDS_MANAGE_SHARING_CONTENT_DESCRIPTION" desc="Content description for the account avatar button that manages sharing for a shared tab group."> + Manage sharing + </message> <!-- Bottom Tab Strip strings --> <message name="IDS_ACCESSIBILITY_BOTTOM_TAB_STRIP_EXPAND_TAB_SHEET" desc="Accessibility string for BottomTabStripToolbar button indicated visually by the '^' sign.">
diff --git a/chrome/android/features/tab_ui/java/strings/android_chrome_tab_ui_strings_grd/IDS_MANAGE_SHARING_CONTENT_DESCRIPTION.png.sha1 b/chrome/android/features/tab_ui/java/strings/android_chrome_tab_ui_strings_grd/IDS_MANAGE_SHARING_CONTENT_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..0f970288 --- /dev/null +++ b/chrome/android/features/tab_ui/java/strings/android_chrome_tab_ui_strings_grd/IDS_MANAGE_SHARING_CONTENT_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +64ffbe52200268135be8736a81c22e57def4f494 \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java index 2efcfe0..54ac0f2f 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewBinderTest.java
@@ -27,7 +27,6 @@ import android.app.Activity; import android.content.res.ColorStateList; -import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.GradientDrawable; import android.os.Build; @@ -180,8 +179,7 @@ assertNull(mShareButton); assertNull(mImageTilesContainer); } - mScrimCoordinator = - new ScrimCoordinator(sActivity, null, parentView, Color.RED); + mScrimCoordinator = new ScrimCoordinator(sActivity, null, parentView); mTabGridDialogView.setupScrimCoordinator(mScrimCoordinator); mModel =
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewTest.java index 4e1e025e..7f002e2 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogViewTest.java
@@ -20,7 +20,6 @@ import android.app.Activity; import android.content.res.ColorStateList; import android.content.res.Configuration; -import android.graphics.Color; import android.os.SystemClock; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -107,7 +106,7 @@ mTabGridDialogView.findViewById(R.id.dialog_animation_card_view); mBackgroundFrameView = mTabGridDialogView.findViewById(R.id.dialog_frame); ScrimCoordinator scrimCoordinator = - new ScrimCoordinator(sActivity, null, mTestParent, Color.RED); + new ScrimCoordinator(sActivity, null, mTestParent); mTabGridDialogView.setupScrimCoordinator(scrimCoordinator); mTabGridDialogView.setScrimClickRunnable(() -> {});
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 0ef65cb..a16f001 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
@@ -17,6 +17,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.atLeastOnce; @@ -1454,6 +1455,7 @@ public void testDialogToolbarMenu_DeleteSharedGroup() { resetForDataSharing(/* isShared= */ true, GROUP_MEMBER1); + when(mTabGroupModelFilter.getTabGroupTitle(anyInt())).thenReturn(GROUP_TITLE); CoreAccountInfo coreAccountInfo = CoreAccountInfo.createFromEmailAndGaiaId(EMAIL1, GAIA_ID1); when(mIdentityManager.getPrimaryAccountInfo(anyInt())).thenReturn(coreAccountInfo); @@ -1467,6 +1469,7 @@ public void testDialogToolbarMenu_LeaveSharedGroup() { resetForDataSharing(/* isShared= */ true, GROUP_MEMBER1, GROUP_MEMBER2); + when(mTabGroupModelFilter.getTabGroupTitle(anyInt())).thenReturn(GROUP_TITLE); CoreAccountInfo coreAccountInfo = CoreAccountInfo.createFromEmailAndGaiaId(EMAIL2, GAIA_ID2); when(mIdentityManager.getPrimaryAccountInfo(anyInt())).thenReturn(coreAccountInfo); @@ -1712,6 +1715,14 @@ .dismiss(MessageType.COLLABORATION_ACTIVITY); verify(mDialogController).removeMessageCardItem(MessageType.COLLABORATION_ACTIVITY); + verify(mMessagingBackendService) + .clearDirtyTabMessagesForGroup( + argThat( + eitherGroupId -> + eitherGroupId + .getLocalId() + .tabGroupId + .equals(TAB_GROUP_ID))); } @Test
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java index 364867147..972fdf6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java
@@ -122,6 +122,11 @@ /** Destroys the native reference. */ public void shutDown() { + if (mFaviconHelper != null) { + mFaviconHelper.destroy(); + mFaviconHelper = null; + } + if (mNativeLayerTitleCache == 0) return; LayerTitleCacheJni.get().destroy(mNativeLayerTitleCache); mNativeLayerTitleCache = 0; @@ -336,6 +341,13 @@ mSharedAvatarResIds.put(rootId, resId); } + public void transferAvatarToNewRootId(int oldRootId, int newRootId) { + int avatarResId = mSharedAvatarResIds.get(oldRootId, ResourcesCompat.ID_NULL); + if (avatarResId == ResourcesCompat.ID_NULL) return; + mSharedAvatarResIds.delete(oldRootId); + mSharedAvatarResIds.put(newRootId, avatarResId); + } + private void unregisterSharedGroupAvatar(int resId) { DynamicResourceLoader dynamicResourceLoader = mResourceManager.getDynamicResourceLoader(); dynamicResourceLoader.unregisterResource(resId);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java index ed218b19..59de60b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
@@ -475,7 +475,7 @@ OverlayPanelContentJni.get().destroyWebContents(mNativeOverlayPanelContentPtr); mWebContents = null; if (mWebContentsObserver != null) { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java index dd91a73..36c978d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
@@ -205,4 +205,9 @@ public StripLayoutHelperManager getStripLayoutHelperManager() { return mTabStripLayoutHelperManager; } + + @Override + public boolean hasTabletUi() { + return true; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java index 6b8cdb45..a7c090a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java
@@ -613,7 +613,8 @@ selector, mTabContentManagerSupplier.get(), mBrowserControlsStateProvider, - mTopUiThemeColorProvider); + mTopUiThemeColorProvider, + !hasTabletUi()); setNextLayout(null, true); @@ -1414,4 +1415,8 @@ public void removeObserver(LayoutStateObserver listener) { mLayoutObservers.removeObserver(listener); } + + public boolean hasTabletUi() { + return false; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutUpdateHost.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutUpdateHost.java index 8a45f6d..c90751c5f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutUpdateHost.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutUpdateHost.java
@@ -24,8 +24,9 @@ * Requests a next update to refresh the transforms and changing properties. The update occurs * once a frame. This is requesting a new frame to be updated and rendered (no need to call * {@link LayoutRenderHost#requestRender()}). + * * @param onUpdateEffective Callback that will be called when there is a buffer swap for the - * updated frame. + * updated frame. */ default void requestUpdate(Runnable onUpdateEffective) {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java index 3dd1ac4..f29ba94 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java
@@ -123,15 +123,17 @@ /** * Creates an instance of the {@link StaticLayout}. - * @param context The current Android's context. - * @param updateHost The {@link LayoutUpdateHost} view for this layout. - * @param renderHost The {@link LayoutRenderHost} view for this layout. - * @param viewHost The {@link LayoutManagerHost} view for this layout + * + * @param context The current Android's context. + * @param updateHost The {@link LayoutUpdateHost} view for this layout. + * @param renderHost The {@link LayoutRenderHost} view for this layout. + * @param viewHost The {@link LayoutManagerHost} view for this layout. * @param requestSupplier Frame request supplier for Compositor MCP. * @param tabModelSelector {@link TabModelSelector} instance. * @param tabContentManager {@link TabContentsManager} instance. * @param browserControlsStateProvider A {@link BrowserControlsStateProvider}. * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI. + * @param needsOffsetTag Whether or not this layout needs an OffsetTag. */ public StaticLayout( Context context, @@ -142,7 +144,8 @@ TabModelSelector tabModelSelector, TabContentManager tabContentManager, BrowserControlsStateProvider browserControlsStateProvider, - Supplier<TopUiThemeColorProvider> topUiThemeColorProvider) { + Supplier<TopUiThemeColorProvider> topUiThemeColorProvider, + boolean needsOffsetTag) { this( context, updateHost, @@ -153,7 +156,8 @@ tabContentManager, browserControlsStateProvider, topUiThemeColorProvider, - null); + null, + needsOffsetTag); } /** Protected constructor for testing, allows specifying a custom SceneLayer. */ @@ -168,16 +172,18 @@ TabContentManager tabContentManager, BrowserControlsStateProvider browserControlsStateProvider, Supplier<TopUiThemeColorProvider> topUiThemeColorProvider, - StaticTabSceneLayer testSceneLayer) { + StaticTabSceneLayer testSceneLayer, + boolean needsOffsetTag) { super(context, updateHost, renderHost); mContext = context; - boolean isTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(mContext); + // Only handle tab lifecycle on tablets. - mHandlesTabLifecycles = isTablet; - // On tablets, StaticTabSceneLayer is a subtree of TabStripSceneLayer, - // and the tag would have been set on the TabStripSceneLayer already. - mNeedsOffsetTag = !isTablet; + mHandlesTabLifecycles = DeviceFormFactor.isNonMultiDisplayContextOnTablet(mContext); + + // StaticTabSceneLayer is a subtree of TabStripSceneLayer, and the tag would have been set + // on the TabStripSceneLayer already if tablet UI is present. + mNeedsOffsetTag = needsOffsetTag; mViewHost = viewHost; mRequestSupplier = requestSupplier; @@ -219,8 +225,6 @@ BrowserControlsOffsetTagsInfo offsetTagsInfo, @BrowserControlsState int constraints) { if (ChromeFeatureList.sBrowserControlsInViz.isEnabled()) { - // On tablets, StaticTabSceneLayer is a subtree of TabStripSceneLayer, - // and the tag would have been set on the TabStripSceneLayer already. if (mNeedsOffsetTag) { mModel.set( LayoutTab.CONTENT_OFFSET_TAG,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ReorderDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ReorderDelegate.java index b8ef581..02585663 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ReorderDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ReorderDelegate.java
@@ -159,14 +159,10 @@ || mActiveStrategy == mTabStrategy); } - boolean getReorderingForTabDrop() { + private boolean isReorderingForTabDrop() { return getInReorderMode() && mActiveStrategy == mExternalViewDragDropReorderStrategy; } - StripLayoutTab getInteractingTab() { - return (StripLayoutTab) mActiveStrategy.getInteractingView(); - } - private ReorderStrategy getReorderStrategy( StripLayoutView interactingView, @ReorderType int reorderType) { if (mSourceViewDragDropReorderStrategy != null @@ -348,7 +344,7 @@ // added. As such, we need to base this on the most recent x-position of the drag, rather // than the interacting view's drawX. final float x = - getReorderingForTabDrop() + isReorderingForTabDrop() ? adjustXForTabDrop(mLastReorderX) : mActiveStrategy.getInteractingView().getDrawX(); @@ -367,7 +363,7 @@ // Note that we only allow scrolling in each direction if the user has already manually // moved that way. final float width = - getReorderingForTabDrop() + isReorderingForTabDrop() ? mTabWidthSupplier.get() : mActiveStrategy.getInteractingView().getWidth(); float dragSpeedRatio = 0.f; @@ -397,6 +393,13 @@ mInReorderModeSupplier.removeObserver(observer); } + /** Update and animate views for external view drop on strip. */ + void handleTabDropForExternalView( + StripLayoutGroupTitle[] groupTitles, int draggedTabId, int dropIndex) { + assert mExternalViewDragDropReorderStrategy != null; + mExternalViewDragDropReorderStrategy.handleDrop(groupTitles, draggedTabId, dropIndex); + } + // ============================================================================================ // Margin helpers // ============================================================================================ @@ -1348,6 +1351,9 @@ private class ExternalViewDragDropReorderStrategy implements ReorderStrategy { // View on the strip being hovered on by the dragged view. private StripLayoutView mInteractingView; + // View on the strip last hovered on by dragged view. This can be used post stop reorder to + // handle drop event (eg: reparenting dropped tab). + private StripLayoutView mInteractingViewDuringStop; /** Initiate reorder when external view is dragged onto strip. */ @Override @@ -1358,6 +1364,7 @@ PointF startPoint) { // 1. Set initial state and add edge margins. mInteractingView = interactingView; + mInteractingViewDuringStop = null; resetReorderState(startPoint.x); setEdgeMarginsForReorder(stripTabs); @@ -1445,6 +1452,7 @@ StripLayoutGroupTitle[] groupTitles, StripLayoutTab[] stripTabs) { List<Animator> animatorList = new ArrayList<>(); handleStopReorderMode(groupTitles, stripTabs, mInteractingView, animatorList); + mInteractingViewDuringStop = mInteractingView; // Start animations. mAnimationHost.startAnimations( animatorList, @@ -1460,6 +1468,44 @@ public StripLayoutView getInteractingView() { return mInteractingView; } + + /** Merges dropped tab to interacting view's tab group, if one exists. */ + public void handleDrop( + StripLayoutGroupTitle[] groupTitles, int draggedTabId, int dropIndex) { + if (mInteractingViewDuringStop == null) return; + + StripLayoutTab interactingView = (StripLayoutTab) mInteractingViewDuringStop; + Tab interactingTab = mModel.getTabById(interactingView.getTabId()); + + // 1. If hovered on tab is not part of group, no-op. + if (!mTabGroupModelFilter.isTabInTabGroup(interactingTab)) return; + + // 2. Merge dragged tab to hovered tab's group at drop index. + mTabGroupModelFilter.mergeTabsToGroup( + draggedTabId, interactingTab.getId(), /* skipUpdateTabModel= */ true); + mModel.moveTab(draggedTabId, dropIndex); + + // 3. Animate bottom indicator. Done after merging the dragged tab to group, + // so that the calculated bottom indicator width will be correct. + StripLayoutGroupTitle groupTitle = + StripLayoutUtils.findGroupTitle(groupTitles, interactingTab.getRootId()); + List<Animator> animators = new ArrayList<>(); + updateBottomIndicatorWidthForTabReorder( + mAnimationHost.getAnimationHandler(), + mTabGroupModelFilter, + groupTitle, + /* isMovingOutOfGroup= */ false, + /* throughGroupTitle= */ false, + animators); + mAnimationHost.startAnimations( + animators, + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mInteractingViewDuringStop = null; + } + }); + } } float adjustXForTabDrop(float x) { @@ -1615,15 +1661,19 @@ mInReorderModeSupplier.set(inReorderMode); } + float getLastReorderXForTesting() { + return mLastReorderX; + } + + StripLayoutTab getInteractingTabForTesting() { + return (StripLayoutTab) mActiveStrategy.getInteractingView(); + } + float getDragLastOffsetXForTesting() { if (mSourceViewDragDropReorderStrategy == null) return 0f; return mSourceViewDragDropReorderStrategy.mLastOffsetX; } - float getLastReorderXForTesting() { - return mLastReorderX; - } - void setDragLastOffsetXForTesting(float offsetX) { if (mSourceViewDragDropReorderStrategy == null) return; mSourceViewDragDropReorderStrategy.mLastOffsetX = offsetX;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java index 459b7d17..ee99bf2a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -304,6 +304,7 @@ groupTitle.updateRootId(newRootId); // Refresh properties since removing the root tab may have cleared the ones // associated with the oldRootId before updating to the newRootId here. + mLayerTitleCache.transferAvatarToNewRootId(oldRootId, newRootId); updateGroupTextAndSharedState(groupTitle); updateGroupTitleTint(groupTitle); } @@ -1710,10 +1711,6 @@ mTouchableRect.set(touchableRect); } - private boolean isTabDraggingInProgress() { - return mTabDragSource != null && mTabDragSource.isTabDraggingInProgress(); - } - /** * Checks whether a tab at the edge of the strip is partially hidden, in which case the close * button will be hidden to avoid accidental clicks. @@ -1834,12 +1831,6 @@ mUpdateHost.requestUpdate(); } - void dragForTabDrop(long time, float x, float y, float deltaX, boolean draggedTabIncognito) { - if (mIncognito == draggedTabIncognito) { - drag(time, x, y, deltaX); - } - } - private void onStripScrollStart() { long currentTime = SystemClock.elapsedRealtime(); @@ -3734,43 +3725,6 @@ return mStripTabs.length; } - int getTabDropId() { - if (!mReorderDelegate.getReorderingForTabDrop()) { - return Tab.INVALID_TAB_ID; - } - StripLayoutTab interactingTab = mReorderDelegate.getInteractingTab(); - if (interactingTab == null) { - return Tab.INVALID_TAB_ID; - } - - Tab tab = getTabById(interactingTab.getTabId()); - return mTabGroupModelFilter.isTabInTabGroup(tab) ? tab.getId() : Tab.INVALID_TAB_ID; - } - - void mergeToGroupForTabDropIfNeeded(int destTabId, int draggedTabId, int index) { - if (destTabId == Tab.INVALID_TAB_ID) return; - - Tab destTab = getTabById(destTabId); - StripLayoutGroupTitle groupTitle = findGroupTitle(destTab.getRootId()); - - mTabGroupModelFilter.mergeTabsToGroup(draggedTabId, destTabId, true); - mModel.moveTab(draggedTabId, index); - - // Animate bottom indicator. Done after merging the dropped tab into a group, so that the - // calculated bottom indicator width will be correct. - if (groupTitle != null) { - List<Animator> animators = new ArrayList<>(); - mReorderDelegate.updateBottomIndicatorWidthForTabReorder( - mUpdateHost.getAnimationHandler(), - mTabGroupModelFilter, - groupTitle, - /* isMovingOutOfGroup= */ false, - /* throughGroupTitle= */ false, - animators); - startAnimations(animators); - } - } - StripLayoutTab getTabAtPosition(float x) { return (StripLayoutTab) getViewAtPositionX(x, false); } @@ -3797,12 +3751,6 @@ startReorderMode(x, 0, getTabAtPosition(x), ReorderType.DRAG_WITHIN_STRIP); } - void stopReorderMode() { - if (mReorderDelegate.getInReorderMode()) { - mReorderDelegate.stopReorderMode(mStripGroupTitles, mStripTabs); - } - } - private void setCompositorButtonsVisible(boolean visible) { float endOpacity = visible ? 1.f : 0.f; @@ -4181,7 +4129,7 @@ * @return The currently interacting tab. */ StripLayoutTab getInteractingTabForTesting() { - return mReorderDelegate.getInteractingTab(); + return mReorderDelegate.getInteractingTabForTesting(); // IN-TEST } /** @@ -4269,21 +4217,11 @@ stripTab.setAccessibilityDescription(builder.toString(), title, resId); } - void setLastOffsetXForTesting(float lastOffsetX) { - mReorderDelegate.setDragLastOffsetXForTesting(lastOffsetX); // IN-TEST - } + // ============================================================================================ + // Drag and Drop View Delegate. + // ============================================================================================ - float getLastOffsetXForTesting() { - return mReorderDelegate.getDragLastOffsetXForTesting(); // IN-TEST - } - - void startDragAndDropTabForTesting( - @NonNull StripLayoutTab clickedTab, @NonNull PointF dragStartPointF) { - startReorderMode( - dragStartPointF.x, dragStartPointF.y, clickedTab, ReorderType.START_DRAG_DROP); - } - - void prepareForTabDrop( + void handleDragEnter( float currX, float lastX, boolean isSourceStrip, boolean draggedTabIncognito) { if (isSourceStrip) { // Tab drag started reorder - update reorder to handle drag onto strip. @@ -4313,7 +4251,13 @@ } } - void clearForTabDrop(boolean isSourceStrip, boolean draggedTabIncognito) { + void handleDragWithin(long time, float x, float y, float deltaX, boolean draggedTabIncognito) { + if (mIncognito == draggedTabIncognito) { + drag(time, x, y, deltaX); + } + } + + void handleDragExit(boolean isSourceStrip, boolean draggedTabIncognito) { if (isSourceStrip) { // Tab drag started reorder - update reorder to handle drag out of strip. // endX is inaccurate but unused. @@ -4329,7 +4273,21 @@ } } - void sendMoveWindowBroadcast(View view, float startXInView, float startYInView) { + void maybeMergeToGroupOnDrop(int draggedTabId, int index) { + mReorderDelegate.handleTabDropForExternalView(mStripGroupTitles, draggedTabId, index); + } + + void stopReorderMode() { + if (mReorderDelegate.getInReorderMode()) { + mReorderDelegate.stopReorderMode(mStripGroupTitles, mStripTabs); + } + } + + private boolean isTabDraggingInProgress() { + return mTabDragSource != null && mTabDragSource.isTabDraggingInProgress(); + } + + private void sendMoveWindowBroadcast(View view, float startXInView, float startYInView) { if (!TabUiFeatureUtilities.isTabDragAsWindowEnabled()) return; if (mWindowAndroid.getActivity().get() == null) return; @@ -4354,4 +4312,18 @@ intent.putExtra("MOVE_WINDOW_START_Y", startYInScreen); mWindowAndroid.sendBroadcast(intent); } + + void startDragAndDropTabForTesting( + @NonNull StripLayoutTab clickedTab, @NonNull PointF dragStartPointF) { + startReorderMode( + dragStartPointF.x, dragStartPointF.y, clickedTab, ReorderType.START_DRAG_DROP); + } + + void setLastOffsetXForTesting(float lastOffsetX) { + mReorderDelegate.setDragLastOffsetXForTesting(lastOffsetX); // IN-TEST + } + + float getLastOffsetXForTesting() { + return mReorderDelegate.getDragLastOffsetXForTesting(); // IN-TEST + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java index 3f5a4c5d..2e28265 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java
@@ -363,7 +363,7 @@ } mStripLayoutHelperSupplier .get() - .prepareForTabDrop(xPx * mPxToDp, mLastXDp, isDragSource, isDraggedTabIncognito()); + .handleDragEnter(xPx * mPxToDp, mLastXDp, isDragSource, isDraggedTabIncognito()); return true; } @@ -372,7 +372,7 @@ float yDp = yPx * mPxToDp; mStripLayoutHelperSupplier .get() - .dragForTabDrop( + .handleDragWithin( LayoutManagerImpl.time(), xDp, yDp, @@ -383,9 +383,7 @@ private boolean onDrop(DragEvent dropEvent) { StripLayoutHelper helper = mStripLayoutHelperSupplier.get(); - int destinationTabId = helper.getTabDropId(); helper.stopReorderMode(); - if (isDragSource()) { DragDropMetricUtils.recordTabReorderStripWithDragDrop(mUmaState.mDragEverLeftStrip); return true; @@ -413,10 +411,10 @@ mTabModelSelector.getModel(tabBeingDragged.isIncognito()).getCount()); showDroppedDifferentModelToast(mWindowAndroid.getContext().get()); } else { + // Reparent tab at drop index and merge to group on destination if needed. int tabIndex = helper.getTabIndexForTabDrop(dropEvent.getX() * mPxToDp); mMultiInstanceManager.moveTabToWindow(getActivity(), tabBeingDragged, tabIndex); - helper.mergeToGroupForTabDropIfNeeded( - destinationTabId, tabBeingDragged.getId(), tabIndex); + helper.maybeMergeToGroupOnDrop(tabBeingDragged.getId(), tabIndex); } DragDropMetricUtils.recordTabDragDropType( DragDropType.TAB_STRIP_TO_TAB_STRIP, @@ -524,7 +522,7 @@ mShadowView.expand(); } } - mStripLayoutHelperSupplier.get().clearForTabDrop(isDragSource(), isDraggedTabIncognito()); + mStripLayoutHelperSupplier.get().handleDragExit(isDragSource(), isDraggedTabIncognito()); return true; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java index b408e651..eb7813e3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java
@@ -464,7 +464,7 @@ private void dismissDialog() { if (mWebContentsObserver != null) { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); } if (mChipController != null) { mChipController.dismissChipIfShowing();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java index c65281b..b79573c6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
@@ -181,7 +181,7 @@ /** Clear the status map and references to other objects. */ @Override public void destroy() { - if (mWebContentsObserver != null) mWebContentsObserver.destroy(); + if (mWebContentsObserver != null) mWebContentsObserver.observe(null); mIsDestroyed = true; } @@ -294,7 +294,7 @@ /** Clear the reader mode state for this manager. */ private void removeTabState() { - if (mWebContentsObserver != null) mWebContentsObserver.destroy(); + if (mWebContentsObserver != null) mWebContentsObserver.observe(null); mDistillationStatus = DistillationStatus.POSSIBLE; mIsDismissed = false; mMessageRequestedForNavigation = false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ChromeFeedbackCollector.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ChromeFeedbackCollector.java index cc827cd2..0f4a8f3c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ChromeFeedbackCollector.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ChromeFeedbackCollector.java
@@ -62,6 +62,7 @@ sources.add(new DeviceInfoFeedbackSource()); sources.add(new UrlFeedbackSource(initParams.url)); sources.add(new VariationsFeedbackSource(initParams.profile)); + sources.add(new VariationsStateFeedbackSource(initParams.profile)); sources.add(new HistogramFeedbackSource(initParams.profile)); sources.add(new LowEndDeviceFeedbackSource()); sources.add(new IMEFeedbackSource());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryActivity.java index b955a5d..ebaefc9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryActivity.java
@@ -72,11 +72,7 @@ (ViewGroup) LayoutInflater.from(this).inflate(R.layout.bottom_sheet_container, null); ScrimCoordinator scrim = - new ScrimCoordinator( - this, - /* systemUiScrimDelegate= */ null, - contentView, - getColor(R.color.default_scrim_color)); + new ScrimCoordinator(this, /* systemUiScrimDelegate= */ null, contentView); mBottomSheetController = BottomSheetControllerFactory.createBottomSheetController( () -> scrim,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java index 721135f..147af63 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
@@ -359,22 +359,23 @@ public void getFavicon(GURL url, Callback<Drawable> callback) { Resources resources = mContext.getResources(); int size = resources.getDimensionPixelSize(R.dimen.page_info_favicon_size); - new FaviconHelper() - .getLocalFaviconImageForURL( - mProfile, - url, - size, - (image, iconUrl) -> { - if (image != null) { - callback.onResult(new BitmapDrawable(resources, image)); - } else if (UrlUtilities.isInternalScheme(url)) { - callback.onResult( - TintedDrawable.constructTintedDrawable( - mContext, R.drawable.chromelogo16)); - } else { - callback.onResult(null); - } - }); + FaviconHelper faviconHelper = new FaviconHelper(); + faviconHelper.getLocalFaviconImageForURL( + mProfile, + url, + size, + (image, iconUrl) -> { + if (image != null) { + callback.onResult(new BitmapDrawable(resources, image)); + } else if (UrlUtilities.isInternalScheme(url)) { + callback.onResult( + TintedDrawable.constructTintedDrawable( + mContext, R.drawable.chromelogo16)); + } else { + callback.onResult(null); + } + faviconHelper.destroy(); + }); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java index d9450a86..99fe0d7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java
@@ -67,6 +67,8 @@ /** A token held while the payment sheet is obscuring all visible tabs. */ private TabObscuringHandler.Token mTabObscuringToken; + private boolean mIsDestroyed; + @IntDef({ CloseReason.OTHERS, CloseReason.USER, @@ -139,6 +141,48 @@ ApplicationStatus.registerStateListenerForActivity(mActivityStateListener, activity); } + /** Destroy the dependencies of the Mediator. */ + public void destroy() { + if (mIsDestroyed) return; + mIsDestroyed = true; + + observe(null); + + ApplicationStatus.unregisterActivityStateListener(mActivityStateListener); + + switch (mCloseReason) { + case CloseReason.INSECURE_NAVIGATION: + ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow( + mPaymentRequestWebContents, + PaymentEventResponseType.PAYMENT_HANDLER_INSECURE_NAVIGATION); + break; + case CloseReason.USER: + ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow( + mPaymentRequestWebContents, + PaymentEventResponseType.PAYMENT_HANDLER_WINDOW_CLOSING); + break; + case CloseReason.FAIL_LOAD: + ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow( + mPaymentRequestWebContents, + PaymentEventResponseType.PAYMENT_HANDLER_FAIL_TO_LOAD_MAIN_FRAME); + break; + case CloseReason.ACTIVITY_DIED: + ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow( + mPaymentRequestWebContents, + PaymentEventResponseType.PAYMENT_HANDLER_ACTIVITY_DIED); + break; + case CloseReason.OTHERS: + // No need to notify ServiceWorkerPaymentAppBridge when merchant aborts the + // payment request (and thus {@link ChromePaymentRequestService} closes + // PaymentHandlerMediator). "OTHERS" category includes this cases. + // TODO(crbug.com/40134410): we should explicitly list merchant aborting payment + // request as a {@link CloseReason}, renames "OTHERS" as "UNKNOWN" and asserts + // that PaymentHandler wouldn't be closed for unknown reason. + } + mHandler.removeCallbacksAndMessages(null); + hideScrim(); + } + // Implement View.OnLayoutChangeListener: // This is the Tab View's layout change listener, invoked in response to phone rotation. // TODO(crbug.com/40120866): It should listen to the BottomSheet container's layout change @@ -219,44 +263,6 @@ @Override public void onSheetContentChanged(BottomSheetContent newContent) {} - // Implement WebContentsObserver: - @Override - public void onDestroy() { - ApplicationStatus.unregisterActivityStateListener(mActivityStateListener); - - switch (mCloseReason) { - case CloseReason.INSECURE_NAVIGATION: - ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow( - mPaymentRequestWebContents, - PaymentEventResponseType.PAYMENT_HANDLER_INSECURE_NAVIGATION); - break; - case CloseReason.USER: - ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow( - mPaymentRequestWebContents, - PaymentEventResponseType.PAYMENT_HANDLER_WINDOW_CLOSING); - break; - case CloseReason.FAIL_LOAD: - ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow( - mPaymentRequestWebContents, - PaymentEventResponseType.PAYMENT_HANDLER_FAIL_TO_LOAD_MAIN_FRAME); - break; - case CloseReason.ACTIVITY_DIED: - ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow( - mPaymentRequestWebContents, - PaymentEventResponseType.PAYMENT_HANDLER_ACTIVITY_DIED); - break; - case CloseReason.OTHERS: - // No need to notify ServiceWorkerPaymentAppBridge when merchant aborts the - // payment request (and thus {@link ChromePaymentRequestService} closes - // PaymentHandlerMediator). "OTHERS" category includes this cases. - // TODO(crbug.com/40134410): we should explicitly list merchant aborting payment - // request as a {@link CloseReason}, renames "OTHERS" as "UNKNOWN" and asserts - // that PaymentHandler wouldn't be closed for unknown reason. - } - mHandler.removeCallbacksAndMessages(null); - hideScrim(); - } - private void hideScrim() { setObscureState(false); @@ -268,6 +274,12 @@ // Implement WebContentsObserver: @Override + public void webContentsDestroyed() { + destroy(); + } + + // Implement WebContentsObserver: + @Override public void didFinishNavigationInPrimaryMainFrame(NavigationHandle navigationHandle) { // Checking uncommitted navigations (e.g., Network errors) is unnecessary because // they have no chance to be loaded nor rendered.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java index 259b33a..cd4d5675 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
@@ -240,8 +240,7 @@ new ScrimCoordinator( this, /* systemUiScrimDelegate= */ null, - (ViewGroup) sheetContainer.getParent(), - getColor(R.color.default_scrim_color)); + (ViewGroup) sheetContainer.getParent()); mManagedBottomSheetController = BottomSheetControllerFactory.createBottomSheetController(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java index bb02dfb..384de252 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java
@@ -14,11 +14,11 @@ import android.view.View.OnCreateContextMenuListener; import androidx.annotation.IntDef; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import org.chromium.base.Callback; +import org.chromium.base.CancelableRunnable; import org.chromium.base.TimeUtils; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.task.PostTask; @@ -515,31 +515,6 @@ private class TileInteractionDelegateImpl implements TileInteractionDelegate, ContextMenuManager.Delegate, View.OnTouchListener { - - /** - * CancelableRunnable is a Runnable class can be canceled. It is created here instead of - * making CallbackController.CancelableRunnable reusable is that this class is expected to - * be used on UI thread only, so locking mechanism is not required. - */ - private static class CancelableRunnable implements Runnable { - private Runnable mRunnable; - - private CancelableRunnable(@NonNull Runnable runnable) { - mRunnable = runnable; - } - - public void cancel() { - mRunnable = null; - } - - @Override - public void run() { - // This is run on UI thread only, so it is not necessary to guard this against - // another thread. - if (mRunnable != null) mRunnable.run(); - } - } - private final SiteSuggestion mSuggestion; private Runnable mOnClickRunnable; private Runnable mOnRemoveRunnable;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java index e3958f95..5ecd655 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
@@ -55,7 +55,7 @@ private final TabImpl mTab; private final ObserverList<Callback<WebContents>> mInitObservers = new ObserverList<>(); - private WebContentsObserver mObserver; + private Observer mObserver; private GURL mLastUrl; public static TabWebContentsObserver from(Tab tab) { @@ -110,7 +110,8 @@ @Override public void cleanupWebContents(WebContents webContents) { if (mObserver != null) { - mObserver.destroy(); + mObserver.updateNotificationsForTab(); + mObserver.observe(null); mObserver = null; } } @@ -381,7 +382,11 @@ } @Override - public void onDestroy() { + public void webContentsDestroyed() { + updateNotificationsForTab(); + } + + void updateNotificationsForTab() { MediaCaptureNotificationServiceImpl.updateMediaNotificationForTab( ContextUtils.getApplicationContext(), mTab.getId(), null, mLastUrl); BluetoothNotificationManager.updateBluetoothNotificationForTab(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserver.java index ded0b645..31e78ab 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserver.java
@@ -23,6 +23,7 @@ import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator; import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionsVisualState; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeUtils; +import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarStateProvider; import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; @@ -142,7 +143,11 @@ mBottomControlsStacker = bottomControlsStacker; mSnackbarStateProvider = snackbarStateProvider; - mSnackbarStateProvider.addObserver(this); + if (!SnackbarManager.isFloatingSnackbarEnabled()) { + // The floating snackbar appears to hover and isn't anchored to bottom UI, and thus + // should not impact the bottom attached color. + mSnackbarStateProvider.addObserver(this); + } mBottomSheetController = bottomSheetController; mBottomSheetController.addObserver(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java index e8b33a21..886166d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -922,13 +922,7 @@ controller.setNavigationBarScrimFraction(scrimFraction); } }; - return new ScrimCoordinator( - mActivity, - delegate, - mCoordinator, - mCoordinator - .getContext() - .getColor(R.color.omnibox_focused_fading_background_color)); + return new ScrimCoordinator(mActivity, delegate, mCoordinator); } // Package Private class methods
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java index fe4d7b7..59bab65 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -1706,11 +1706,7 @@ RootUiCoordinator.this.setStatusBarScrimFraction(scrimFraction); } }; - return new ScrimCoordinator( - mActivity, - delegate, - coordinator, - coordinator.getContext().getColor(R.color.omnibox_focused_fading_background_color)); + return new ScrimCoordinator(mActivity, delegate, coordinator); } protected void setStatusBarScrimFraction(float scrimFraction) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java index dfd8fca..6459d4ff 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -852,7 +852,7 @@ WebContentsObserver observer = new WebContentsObserver(tab.getWebContents()) { @Override - public void onDestroy() { + public void webContentsDestroyed() { webContentsDestroyed.notifyCalled(); } };
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/save_card/AutofillSaveCardBottomSheetRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/save_card/AutofillSaveCardBottomSheetRenderTest.java index 503cadf..82bef78 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/save_card/AutofillSaveCardBottomSheetRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/save_card/AutofillSaveCardBottomSheetRenderTest.java
@@ -7,7 +7,6 @@ import static org.chromium.base.ThreadUtils.runOnUiThreadBlocking; import android.app.Activity; -import android.graphics.Color; import android.view.ViewGroup; import androidx.test.filters.LargeTest; @@ -58,7 +57,7 @@ @Rule public final RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus() - .setRevision(2) + .setRevision(3) .setBugComponent(Component.UI_BROWSER_AUTOFILL) .build(); @@ -82,8 +81,7 @@ new ScrimCoordinator( mActivity, /* systemUiScrimDelegate= */ null, - activityContentView, - Color.WHITE); + activityContentView); mBottomSheetController = BottomSheetControllerFactory.createFullWidthBottomSheetController( () -> scrimCoordinator,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentlyClosedBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentlyClosedBridgeTest.java index 770a1c1..eba4616 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentlyClosedBridgeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentlyClosedBridgeTest.java
@@ -1605,6 +1605,86 @@ assertTabsAre(recentTabs, titles, urls); } + /** Tests opening the closed tab group when another group is pending closure. */ + @Test + @MediumTest + public void testOpenRecentlyClosedTabGroupEntryWhenHasPendingTabGroupClosure() { + if (mTabGroupModelFilter == null) return; + + // Tab order is inverted in RecentlyClosedEntry as most recent comes first so log data in + // reverse. + final String[] group1Urls = new String[] {getUrl(TEST_PAGE_C), getUrl(TEST_PAGE_B)}; + final String[] group2Urls = new String[] {getUrl(TEST_PAGE_A)}; + final Tab tabA = sActivityTestRule.loadUrlInNewTab(group2Urls[0], /* incognito= */ false); + final Tab tabB = sActivityTestRule.loadUrlInNewTab(group1Urls[1], /* incognito= */ false); + final Tab tabC = sActivityTestRule.loadUrlInNewTab(group1Urls[0], /* incognito= */ false); + + final String[] group1Titles = new String[2]; + final String[] group2Titles = new String[1]; + ThreadUtils.runOnUiThreadBlocking( + () -> { + mTabGroupModelFilter.mergeTabsToGroup(tabC.getId(), tabB.getId()); + mTabGroupModelFilter.setTabGroupTitle(tabB.getId(), "Group 1"); + mTabGroupModelFilter.createSingleTabGroup(tabA, true); + mTabGroupModelFilter.setTabGroupTitle(tabA.getId(), "Group 2"); + group2Titles[0] = tabA.getTitle(); + group1Titles[1] = tabB.getTitle(); + group1Titles[0] = tabC.getTitle(); + closeTabs( + TabClosureParams.closeTabs(List.of(tabB, tabC)) + .hideTabGroups(false) + .build()); + mTabModel.commitAllTabClosures(); + }); + final List<RecentlyClosedEntry> recentEntries = new ArrayList<>(); + int tabCount = getRecentEntriesAndReturnActiveTabCount(recentEntries); + Assert.assertEquals(2, tabCount); + Assert.assertEquals(1, recentEntries.size()); + assertEntryIs( + recentEntries.get(0), + RecentlyClosedGroup.class, + new String[] {"Group 1"}, + group1Titles, + group1Urls); + + // Close Group 2 and restore Group 1. + ThreadUtils.runOnUiThreadBlocking( + () -> { + closeTabs( + TabClosureParams.closeTabs(List.of(tabA)).hideTabGroups(false).build()); + mRecentlyClosedBridge.openMostRecentlyClosedEntry(mTabModel); + }); + + // 1. Blank tab + // 2. Restored tabB + // 3. Restored tabC + final List<Tab> tabs = getAllTabs(); + Assert.assertEquals(3, tabs.size()); + Assert.assertEquals(group1Titles[1], ChromeTabUtils.getTitleOnUiThread(tabs.get(1))); + Assert.assertEquals(group1Urls[1], ChromeTabUtils.getUrlOnUiThread(tabs.get(1)).getSpec()); + Assert.assertEquals(group1Titles[0], ChromeTabUtils.getTitleOnUiThread(tabs.get(2))); + Assert.assertEquals(group1Urls[0], ChromeTabUtils.getUrlOnUiThread(tabs.get(2)).getSpec()); + ThreadUtils.runOnUiThreadBlocking( + () -> { + Assert.assertEquals( + "Group 1", mTabGroupModelFilter.getTabGroupTitle(tabs.get(1).getId())); + Assert.assertTrue(mTabGroupModelFilter.isTabInTabGroup(tabs.get(1))); + Assert.assertEquals( + Arrays.asList(new Tab[] {tabs.get(1), tabs.get(2)}), + mTabGroupModelFilter.getRelatedTabList(tabs.get(1).getId())); + }); + + tabCount = getRecentEntriesAndReturnActiveTabCount(recentEntries); + Assert.assertEquals(3, tabCount); + Assert.assertEquals(1, recentEntries.size()); + assertEntryIs( + recentEntries.get(0), + RecentlyClosedGroup.class, + new String[] {"Group 2"}, + group2Titles, + group2Urls); + } + // TODO(crbug.com/40218713): Add a test a case where bulk closures remain in the native service, // but the flag state is flipped.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/AutofillImageFetcherUtilsTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/AutofillImageFetcherUtilsTest.java new file mode 100644 index 0000000..35e251fc --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/AutofillImageFetcherUtilsTest.java
@@ -0,0 +1,81 @@ +// 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.autofill; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Color; + +import androidx.annotation.Px; +import androidx.core.content.ContextCompat; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; + +import org.chromium.base.test.BaseRobolectricTestRunner; + +/** Unit tests for {@link AutofillImageFetcherUtils}. */ +@RunWith(BaseRobolectricTestRunner.class) +public class AutofillImageFetcherUtilsTest { + private Context mContext; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + } + + @Test + @SmallTest + public void testTreatPixAccountImage_testAllEnhancementsApplied() { + @Px + int logoSize = AutofillImageFetcherUtils.getPixelSize(R.dimen.square_card_icon_side_length); + @Px + int iconCornerRadius = + AutofillImageFetcherUtils.getPixelSize(R.dimen.large_card_icon_corner_radius); + int borderColor = ContextCompat.getColor(mContext, R.color.baseline_neutral_90); + Bitmap testImage = Bitmap.createBitmap(logoSize, logoSize, Bitmap.Config.ARGB_8888); + // Expected treated image according to Pix specifications. + Bitmap expectedTreatedTestImage = + AutofillImageFetcherUtils.addBorder( + AutofillImageFetcherUtils.roundCorners( + AutofillImageFetcherUtils.addCenterAlignedBackground( + AutofillImageFetcherUtils.roundCorners( + testImage, + AutofillImageFetcherUtils.getPixelSize( + R.dimen.square_card_icon_corner_radius)), + AutofillImageFetcherUtils.getPixelSize( + R.dimen.large_card_icon_width), + AutofillImageFetcherUtils.getPixelSize( + R.dimen.large_card_icon_height), + Color.WHITE), + iconCornerRadius), + iconCornerRadius, + AutofillImageFetcherUtils.getPixelSize(R.dimen.card_icon_border_width), + borderColor); + + assertTrue( + AutofillImageFetcherUtils.treatPixAccountImage(testImage) + .sameAs(expectedTreatedTestImage)); + } + + @Test + @SmallTest + public void testTreatPixAccountImage_testOutputImageDimensionsAreConstant() { + @Px int iconWidth = AutofillImageFetcherUtils.getPixelSize(R.dimen.large_card_icon_width); + @Px int iconHeight = AutofillImageFetcherUtils.getPixelSize(R.dimen.large_card_icon_height); + Bitmap testImage = Bitmap.createBitmap(500, 400, Bitmap.Config.ARGB_8888); + + Bitmap treatedImage = AutofillImageFetcherUtils.treatPixAccountImage(testImage); + + assertEquals(iconWidth, treatedImage.getWidth()); + assertEquals(iconHeight, treatedImage.getHeight()); + } +}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/StaticLayoutUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/StaticLayoutUnitTest.java index 46c89f8b..1e91127 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/StaticLayoutUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/StaticLayoutUnitTest.java
@@ -167,7 +167,8 @@ mTabContentManager, mBrowserControlsStateProvider, () -> mTopUiThemeColorProvider, - mStaticTabSceneLayer); + mStaticTabSceneLayer, + false); mModel = mStaticLayout.getModelForTesting(); doReturn(true).when(mUpdateHost).isActiveLayout(mStaticLayout);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java index a0f703fa..474720f 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
@@ -2165,7 +2165,7 @@ StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting(); // Start reorder for tab drop between the 2nd and 3rd tab. - mStripLayoutHelper.prepareForTabDrop(/* currX= */ 300.f, /* lastX= */ 0f, false, false); + mStripLayoutHelper.handleDragEnter(/* currX= */ 300.f, /* lastX= */ 0f, false, false); // Test tab outline should show for the foregrounded tab in destination window during tab // drop. @@ -2746,7 +2746,7 @@ mStripLayoutHelper.updateLayout(TIMESTAMP); // Start reorder for tab drop between the 1st and 2nd tab. - mStripLayoutHelper.prepareForTabDrop(/* currX= */ 150.f, /* lastX= */ 0f, false, false); + mStripLayoutHelper.handleDragEnter(/* currX= */ 150.f, /* lastX= */ 0f, false, false); float expectedEndWidth = expectedStartWidth @@ -2768,7 +2768,7 @@ ReorderDelegate reorderDelegateSpy = spy(mStripLayoutHelper.getReorderDelegateForTesting()); // Start and stop reorder mode for tab drop. - mStripLayoutHelper.prepareForTabDrop(/* currX= */ 10.f, /* lastX= */ 0f, false, false); + mStripLayoutHelper.handleDragEnter(/* currX= */ 10.f, /* lastX= */ 0f, false, false); mStripLayoutHelper.stopReorderMode(); // Verify: folio reattachment animation does not run for tab drop. @@ -3610,8 +3610,8 @@ // Start drag tab out of group or drag off strip. if (draggingTabOffStrip) { // Drag onto strip before dragged off. - mStripLayoutHelper.prepareForTabDrop(0f, 0f, true, false); - mStripLayoutHelper.clearForTabDrop(true, false); + mStripLayoutHelper.handleDragEnter(0f, 0f, true, false); + mStripLayoutHelper.handleDragExit(true, false); } else { float dragDistance = ((tabs[0].getWidth() - TAB_OVERLAP_WIDTH_DP) / 2) @@ -4374,7 +4374,7 @@ mStripLayoutHelper.getInReorderModeForTesting()); assertTrue( "Dragged Tab should match selected tab during drag action.", - mStripLayoutHelper.getReorderDelegateForTesting().getInteractingTab() + mStripLayoutHelper.getReorderDelegateForTesting().getInteractingTabForTesting() == theClickedTab); mStripLayoutHelper.stopReorderMode(); assertFalse( @@ -4432,7 +4432,7 @@ // Drag tab back onto strip. float expectedOffsetX = 123.45f; mStripLayoutHelper.setLastOffsetXForTesting(expectedOffsetX); - mStripLayoutHelper.prepareForTabDrop(0f, 0f, true, false); + mStripLayoutHelper.handleDragEnter(0f, 0f, true, false); // Verify we continue reorder mode with the correct x-offset. assertFalse( @@ -4443,6 +4443,8 @@ expectedOffsetX, mStripLayoutHelper.getInteractingTabForTesting().getOffsetX(), EPSILON); + + // Verify we continue reorder mode. assertTrue( "Should re-enter reorder mode.", mStripLayoutHelper.getInReorderModeForTesting()); } @@ -4460,10 +4462,10 @@ // Drag tab out of strip. float expectedOffsetX = 123.45f; - mStripLayoutHelper.prepareForTabDrop(0f, 0f, true, false); + mStripLayoutHelper.handleDragEnter(0f, 0f, true, false); StripLayoutTab draggedTab = mStripLayoutHelper.getInteractingTabForTesting(); draggedTab.setOffsetX(expectedOffsetX); - mStripLayoutHelper.clearForTabDrop(true, false); + mStripLayoutHelper.handleDragExit(true, false); // Finish animations. assertNotNull( @@ -4499,8 +4501,8 @@ // Drag tab out of strip. mStripLayoutHelper.setTabAtPositionForTesting(draggedTab); - mStripLayoutHelper.prepareForTabDrop(0f, 0f, true, false); - mStripLayoutHelper.clearForTabDrop(true, false); + mStripLayoutHelper.handleDragEnter(0f, 0f, true, false); + mStripLayoutHelper.handleDragExit(true, false); mStripLayoutHelper.updateLayout(TIMESTAMP); // Verify 3rd, 4th and 5th tab's start divider is visible. @@ -4573,7 +4575,7 @@ mStripLayoutHelper.updateLayout(TIMESTAMP); // Prepare for tab drop. - mStripLayoutHelper.prepareForTabDrop(0.f, 0.f, false, false); + mStripLayoutHelper.handleDragEnter(0.f, 0.f, false, false); // Start gap will be tabWidth(265) / 2 = 132.5 mStripLayoutHelper.setScrollOffsetForTesting(-132); @@ -4611,7 +4613,7 @@ } @Test - public void testPrepareForTabDrop() { + public void testHandleDragEnter() { // Setup with 5 tabs. initializeTest(false, false, 1, 5); mStripLayoutHelper.onSizeChanged( @@ -4626,7 +4628,7 @@ groupTabs(1, 3); // Prepare for tab drop. - mStripLayoutHelper.prepareForTabDrop(0.f, 0.f, false, false); + mStripLayoutHelper.handleDragEnter(0.f, 0.f, false, false); // Verify. StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting(); @@ -4662,7 +4664,7 @@ mStripLayoutHelper.updateLayout(TIMESTAMP); // Prepare for tab drop. - mStripLayoutHelper.prepareForTabDrop(0.f, 0.f, false, false); + mStripLayoutHelper.handleDragEnter(0.f, 0.f, false, false); mStripLayoutHelper.finishAnimations(); // Verify initial trailing margins before hover. StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting(); @@ -4705,7 +4707,7 @@ mStripLayoutHelper.updateLayout(TIMESTAMP); // Prepare for tab drop. - mStripLayoutHelper.prepareForTabDrop(0.f, 0.f, false, false); + mStripLayoutHelper.handleDragEnter(0.f, 0.f, false, false); // Start gap will be tabWidth(265) / 2 = 132.5 mStripLayoutHelper.setScrollOffsetForTesting(-132); mStripLayoutHelper.finishAnimations(); @@ -4747,14 +4749,14 @@ SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT); // Prepare and verify no interaction. - mStripLayoutHelper.prepareForTabDrop(0.f, 0.f, false, !isIncognito); + mStripLayoutHelper.handleDragEnter(0.f, 0.f, false, !isIncognito); assertFalse( "Shouldn't start reorder when dragged tab Incognito state is different.", mStripLayoutHelper.getInReorderModeForTesting()); // Drag and verify no interaction. float expectedOffset = mStripLayoutHelper.getScrollOffset(); - mStripLayoutHelper.dragForTabDrop(TIMESTAMP, PADDING_LEFT, 0.f, 50.f, !isIncognito); + mStripLayoutHelper.handleDragWithin(TIMESTAMP, PADDING_LEFT, 0.f, 50.f, !isIncognito); assertEquals( "Shouldn't have scrolled when dragged tab Incognito is different.", expectedOffset, @@ -4763,7 +4765,7 @@ // Set reorder mode for testing, then clear for tab drop and verify no interaction. mStripLayoutHelper.startReorderModeAtIndexForTesting(0); - mStripLayoutHelper.clearForTabDrop(false, !isIncognito); + mStripLayoutHelper.handleDragExit(false, !isIncognito); assertTrue( "Shouldn't stop reorder when dragged tab Incognito state is different.", mStripLayoutHelper.getInReorderModeForTesting());
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java index 6c203f4..da2a9bf 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java
@@ -540,7 +540,7 @@ // Verify appropriate events are generated. // Strip prepares for drop on drag enter. verify(mSourceStripLayoutHelper, times(1)) - .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); + .handleDragEnter(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Stop reorder on drop and drag end. verify(mSourceStripLayoutHelper, times(2)).stopReorderMode(); // Verify tab is not moved. @@ -576,9 +576,9 @@ // Verify appropriate events are generated. // Strip prepares for drop on drag enter. verify(mSourceStripLayoutHelper, times(1)) - .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); + .handleDragEnter(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Strip clears state for drop on drag exit. - verify(mSourceStripLayoutHelper, times(1)).clearForTabDrop(anyBoolean(), anyBoolean()); + verify(mSourceStripLayoutHelper, times(1)).handleDragExit(anyBoolean(), anyBoolean()); // Verify tab is not moved since drop is on source toolbar. verify(mSourceMultiInstanceManager, times(0)).moveTabToNewWindow(mTabBeingDragged); verify(mSourceMultiInstanceManager, times(0)).moveTabToWindow(any(), any(), anyInt()); @@ -606,9 +606,9 @@ // Verify appropriate events are generated. // Strip prepares for drop on drag enter. verify(mSourceStripLayoutHelper, times(1)) - .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); + .handleDragEnter(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Strip clears state for drop on drag exit. - verify(mSourceStripLayoutHelper, times(1)).clearForTabDrop(anyBoolean(), anyBoolean()); + verify(mSourceStripLayoutHelper, times(1)).handleDragExit(anyBoolean(), anyBoolean()); // Verify tab is not moved since drop is outside strip. verify(mSourceMultiInstanceManager, times(0)).moveTabToNewWindow(mTabBeingDragged); verify(mSourceMultiInstanceManager, times(0)).moveTabToWindow(any(), any(), anyInt()); @@ -656,9 +656,9 @@ // Verify appropriate events are generated. // Strip prepares for drop on drag enter. verify(mSourceStripLayoutHelper, times(1)) - .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); + .handleDragEnter(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Strip clears state for drop on drag exit. - verify(mSourceStripLayoutHelper, times(1)).clearForTabDrop(anyBoolean(), anyBoolean()); + verify(mSourceStripLayoutHelper, times(1)).handleDragExit(anyBoolean(), anyBoolean()); // Verify Since the drop is outside the TabToolbar area the tab will be move to a new // Chrome Window. verify(mSourceMultiInstanceManager, times(1)).moveTabToNewWindow(mTabBeingDragged); @@ -810,7 +810,7 @@ verify(mSourceStripLayoutHelper, times(1)).stopReorderMode(); // Verify destination strip calls. verify(mDestStripLayoutHelper) - .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); + .handleDragEnter(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); verify(mDestStripLayoutHelper).stopReorderMode(); assertNull(ShadowToast.getLatestToast()); @@ -896,14 +896,14 @@ // Verify appropriate events are generated. // Source strip prepares for drop on drag enter. verify(mSourceStripLayoutHelper, times(1)) - .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); + .handleDragEnter(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Source strip clears state for drop on drag exit. - verify(mSourceStripLayoutHelper, times(1)).clearForTabDrop(anyBoolean(), anyBoolean()); + verify(mSourceStripLayoutHelper, times(1)).handleDragExit(anyBoolean(), anyBoolean()); // Destination strip prepares for drop on drag enter. verify(mDestStripLayoutHelper, times(1)) - .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); + .handleDragEnter(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Destination strip clears state for drop on drag exit. - verify(mDestStripLayoutHelper, times(1)).clearForTabDrop(anyBoolean(), anyBoolean()); + verify(mDestStripLayoutHelper, times(1)).handleDragExit(anyBoolean(), anyBoolean()); // Verify tab is not moved since drop is on source toolbar. verify(mSourceMultiInstanceManager, times(0)).moveTabToNewWindow(mTabBeingDragged); verify(mSourceMultiInstanceManager, times(0)).moveTabToWindow(any(), any(), anyInt()); @@ -936,7 +936,7 @@ // Verify appropriate events are generated. // Strip prepares for drop on drag enter. Entered twice. verify(mSourceStripLayoutHelper, times(2)) - .prepareForTabDrop(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); + .handleDragEnter(anyFloat(), anyFloat(), anyBoolean(), anyBoolean()); // Stop reorder on drop and drag end. verify(mSourceStripLayoutHelper, times(2)).stopReorderMode(); // Verify tab is not moved.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java index cfb9074..e4c28b4 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java
@@ -6,6 +6,7 @@ import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -350,6 +351,15 @@ mColorChangeObserver.assertState(null, false, false); } + /* + Tests that when floating snackbar is enabled, we do not add BottomAttachedUiObserver. + */ + @Test + @EnableFeatures(ChromeFeatureList.FLOATING_SNACKBAR) + public void testDoesNotAddBottomAttachedUiObserver() { + verify(mSnackbarManager, never()).addObserver(eq(mBottomAttachedUiObserver)); + } + @Test public void testSetOverlayPanelObserver() { verify(mOverlayPanelStateProvider).addObserver(eq(mBottomAttachedUiObserver));
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt index 6a9a44f..537e580 100644 --- a/chrome/android/profiles/arm.newest.txt +++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-134.0.6955.0_rc-r2-merged.afdo.bz2 +chromeos-chrome-arm-134.0.6962.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 01cdc4a..daf0aeb 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -4174,7 +4174,8 @@ "//chrome/browser/apps/link_capturing", "//chrome/browser/apps/link_capturing:features", "//chrome/browser/autofill_ai:util", - "//chrome/browser/contextual_cueing:contextual_cueing", + "//chrome/browser/contextual_cueing", + "//chrome/browser/contextual_cueing:impl", "//chrome/browser/enterprise/signals:utils", "//chrome/browser/error_reporting", "//chrome/browser/feedback:feedback_enum",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 2f9bd12..9a2e723d9 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1800,9 +1800,22 @@ const FeatureEntry::FeatureParam kTabstripComboButtonNoBackground[] = { {"has_background", "false"}}; +const FeatureEntry::FeatureParam kTabstripComboButtonReverseButtonOrder[] = { + {"reverse_button_order", "true"}}; + +const FeatureEntry::FeatureParam + kTabstripComboButtonReverseButtonOrderNoBackground[] = { + {"has_background", "false"}, + {"reverse_button_order", "true"}}; + const FeatureEntry::FeatureVariation kTabstripComboButtonVariations[] = { {" - without background", kTabstripComboButtonNoBackground, std::size(kTabstripComboButtonNoBackground)}, + {" - reverse button order", kTabstripComboButtonReverseButtonOrder, + std::size(kTabstripComboButtonReverseButtonOrder)}, + {" - reverse button order & without background", + kTabstripComboButtonReverseButtonOrderNoBackground, + std::size(kTabstripComboButtonReverseButtonOrderNoBackground)}, }; #endif @@ -4375,7 +4388,7 @@ {"feedback-include-variations", flag_descriptions::kFeedbackIncludeVariationsName, flag_descriptions::kFeedbackIncludeVariationsDescription, - kOsWin | kOsLinux | kOsMac, + kOsWin | kOsLinux | kOsMac | kOsAndroid, FEATURE_VALUE_TYPE(variations::kFeedbackIncludeVariations)}, #endif {"ui-disable-partial-swap", flag_descriptions::kUiPartialSwapName, @@ -7159,6 +7172,11 @@ #endif // BUILDFLAG(ENABLE_PRINTING) #if BUILDFLAG(IS_WIN) + {"enable-windows-gaming-input-data-fetcher", + flag_descriptions::kEnableWindowsGamingInputDataFetcherName, + flag_descriptions::kEnableWindowsGamingInputDataFetcherDescription, kOsWin, + FEATURE_VALUE_TYPE(features::kEnableWindowsGamingInputDataFetcher)}, + {"windows11-mica-titlebar", flag_descriptions::kWindows11MicaTitlebarName, flag_descriptions::kWindows11MicaTitlebarDescription, kOsWin, FEATURE_VALUE_TYPE(kWindows11MicaTitlebar)},
diff --git a/chrome/browser/accessibility/embedded_a11y_extension_loader.cc b/chrome/browser/accessibility/embedded_a11y_extension_loader.cc index 3f97ad7..e2eb44e 100644 --- a/chrome/browser/accessibility/embedded_a11y_extension_loader.cc +++ b/chrome/browser/accessibility/embedded_a11y_extension_loader.cc
@@ -73,7 +73,7 @@ EmbeddedA11yExtensionLoader::ExtensionInfo::ExtensionInfo( const std::string& extension_id, - const std::string& extension_path, + const base::FilePath& extension_path, const base::FilePath::CharType* extension_manifest_file, bool should_localize) : extension_id(extension_id), @@ -119,7 +119,42 @@ void EmbeddedA11yExtensionLoader::InstallExtensionWithId( const std::string& extension_id, - const std::string& extension_path, + const std::string& extension_resource_directory, + const base::FilePath::CharType* manifest_name, + bool should_localize) { + if (extension_map_.contains(extension_id)) { + return; + } + + base::FilePath resources_path; +#if BUILDFLAG(IS_MAC) + base::FilePath root_path; + CHECK(base::PathService::Get(base::DIR_MODULE, &root_path)); + resources_path = root_path.Append("resources"); +#else + if (!base::PathService::Get(chrome::DIR_RESOURCES, &resources_path)) { + NOTREACHED(); + } +#endif + + base::FilePath::StringType common_extension_directory; +#if BUILDFLAG(IS_WIN) + common_extension_directory = base::UTF8ToWide(extension_resource_directory); +#else + common_extension_directory = extension_resource_directory; +#endif + + auto path = resources_path.Append(common_extension_directory); + + ExtensionInfo new_extension = {extension_id, path, manifest_name, + should_localize}; + extension_map_.insert({extension_id, new_extension}); + UpdateAllProfiles(extension_id); +} + +void EmbeddedA11yExtensionLoader::InstallExtensionWithIdAndPath( + const std::string& extension_id, + const base::FilePath& extension_path, const base::FilePath::CharType* manifest_name, bool should_localize) { if (extension_map_.contains(extension_id)) { @@ -214,7 +249,7 @@ void EmbeddedA11yExtensionLoader::MaybeInstallExtension( Profile* profile, const std::string& extension_id, - const std::string& extension_path, + const base::FilePath& extension_path, const base::FilePath::CharType* manifest_name, bool should_localize) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -223,33 +258,13 @@ return; } - base::FilePath resources_path; -#if BUILDFLAG(IS_MAC) - base::FilePath root_path; - CHECK(base::PathService::Get(base::DIR_MODULE, &root_path)); - resources_path = root_path.Append("resources"); -#else - if (!base::PathService::Get(chrome::DIR_RESOURCES, &resources_path)) { - NOTREACHED(); - } -#endif - - base::FilePath::StringType common_path; -#if BUILDFLAG(IS_WIN) - common_path = base::UTF8ToWide(extension_path); -#else - common_path = extension_path; -#endif - - auto path = resources_path.Append(common_path); - extensions::GetExtensionFileTaskRunner()->PostTaskAndReplyWithResult( FROM_HERE, - base::BindOnce(&LoadManifestOnFileThread, path, manifest_name, + base::BindOnce(&LoadManifestOnFileThread, extension_path, manifest_name, /*localize=*/should_localize), base::BindOnce(&EmbeddedA11yExtensionLoader::InstallExtension, - weak_ptr_factory_.GetWeakPtr(), component_loader, path, - extension_id)); + weak_ptr_factory_.GetWeakPtr(), component_loader, + extension_path, extension_id)); } void EmbeddedA11yExtensionLoader::InstallExtension(
diff --git a/chrome/browser/accessibility/embedded_a11y_extension_loader.h b/chrome/browser/accessibility/embedded_a11y_extension_loader.h index b6ffbdd..60a9414 100644 --- a/chrome/browser/accessibility/embedded_a11y_extension_loader.h +++ b/chrome/browser/accessibility/embedded_a11y_extension_loader.h
@@ -35,7 +35,7 @@ // profiles. struct ExtensionInfo { ExtensionInfo(const std::string& extension_id, - const std::string& extension_path, + const base::FilePath& extension_path, const base::FilePath::CharType* extension_manifest_file, bool should_localize); ExtensionInfo(const ExtensionInfo& other); @@ -48,7 +48,7 @@ const std::string extension_id; // The path to the extension manifest file. - const std::string extension_path; + const base::FilePath extension_path; // The name of the extension manifest file. const base::FilePath::CharType* extension_manifest_file; @@ -72,9 +72,14 @@ // `manifest_name` must live for the duration of the program. (e.g. be // statically allocated) void InstallExtensionWithId(const std::string& extension_id, - const std::string& extension_path, + const std::string& extension_resource_directory, const base::FilePath::CharType* manifest_name, bool should_localize); + void InstallExtensionWithIdAndPath( + const std::string& extension_id, + const base::FilePath& extension_path, + const base::FilePath::CharType* manifest_name, + bool should_localize); void RemoveExtensionWithId(const std::string& extension_id); // We can't use extensions::ExtensionHostTestHelper as those require a @@ -104,7 +109,7 @@ // if it isn't yet installed. void MaybeInstallExtension(Profile* profile, const std::string& extension_id, - const std::string& extension_path, + const base::FilePath& extension_path, const base::FilePath::CharType* manifest_name, bool should_localize);
diff --git a/chrome/browser/accessibility/embedded_a11y_extension_loader_browsertest.cc b/chrome/browser/accessibility/embedded_a11y_extension_loader_browsertest.cc index 78b2232..2f15adf 100644 --- a/chrome/browser/accessibility/embedded_a11y_extension_loader_browsertest.cc +++ b/chrome/browser/accessibility/embedded_a11y_extension_loader_browsertest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/accessibility/embedded_a11y_extension_loader.h" +#include "base/path_service.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/component_loader.h" @@ -120,6 +121,30 @@ profile, extension_misc::kReadingModeGDocsHelperExtensionId); } +IN_PROC_BROWSER_TEST_F(EmbeddedA11yExtensionLoaderTest, + InstallExtensionWithIdAndPath) { + ProfileManager* profile_manager = g_browser_process->profile_manager(); + const auto& profiles = profile_manager->GetLoadedProfiles(); + ASSERT_GT(profiles.size(), 0u); + Profile* profile = profiles[0]; + + char manifest_id[] = "cjlaeehoipngghikfjogbdkpbdgebppb"; + base::FilePath source_root_dir; + base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &source_root_dir); + base::FilePath extension_path = source_root_dir.AppendASCII("chrome") + .AppendASCII("test") + .AppendASCII("data") + .AppendASCII("accessibility") + .AppendASCII("extension"); + base::FilePath::CharType manifest_name[] = FILE_PATH_LITERAL("manifest.json"); + auto* embedded_a11y_extension_loader = + EmbeddedA11yExtensionLoader::GetInstance(); + embedded_a11y_extension_loader->InstallExtensionWithIdAndPath( + manifest_id, extension_path, manifest_name, /*should_localize=*/false); + WaitForExtensionLoaded(profile, manifest_id); + RemoveAndWaitForExtensionUnloaded(profile, manifest_id); +} + #if !BUILDFLAG(IS_CHROMEOS) IN_PROC_BROWSER_TEST_F(EmbeddedA11yExtensionLoaderTest, InstallsOnMultipleProfiles) {
diff --git a/chrome/browser/ai/ai_manager.cc b/chrome/browser/ai/ai_manager.cc index b9d33f04..a2f3ec5 100644 --- a/chrome/browser/ai/ai_manager.cc +++ b/chrome/browser/ai/ai_manager.cc
@@ -391,55 +391,41 @@ void AIManager::CanCreateWriter(blink::mojom::AIWriterCreateOptionsPtr options, CanCreateWriterCallback callback) { // TODO(crbug.com/382596381): Check Options. - // TODO(crbug.com/382325795): Use kWritingAssistanceApi instead of kCompose. - CanCreateSession(optimization_guide::ModelBasedCapabilityKey::kCompose, - std::move(callback)); + CanCreateSession( + optimization_guide::ModelBasedCapabilityKey::kWritingAssistanceApi, + std::move(callback)); } void AIManager::CreateWriter( mojo::PendingRemote<blink::mojom::AIManagerCreateWriterClient> client, blink::mojom::AIWriterCreateOptionsPtr options) { - // TODO(crbug.com/382325795): Use kWritingAssistanceApi instead of kCompose. CreateContextBoundObjectTask<AIWriter, blink::mojom::AIWriter, blink::mojom::AIManagerCreateWriterClient, blink::mojom::AIWriterCreateOptionsPtr>:: - CreateAndStart(browser_context_, - optimization_guide::ModelBasedCapabilityKey::kCompose, - context_bound_object_set_, std::move(options), - std::move(client)); + CreateAndStart( + browser_context_, + optimization_guide::ModelBasedCapabilityKey::kWritingAssistanceApi, + context_bound_object_set_, std::move(options), std::move(client)); } void AIManager::CanCreateRewriter( blink::mojom::AIRewriterCreateOptionsPtr options, CanCreateRewriterCallback callback) { - // TODO(crbug.com/382615217): Check Options. - // TODO(crbug.com/382325795): Use kWritingAssistanceApi instead of kCompose. - CanCreateSession(optimization_guide::ModelBasedCapabilityKey::kCompose, - std::move(callback)); + CanCreateSession( + optimization_guide::ModelBasedCapabilityKey::kWritingAssistanceApi, + std::move(callback)); } void AIManager::CreateRewriter( mojo::PendingRemote<blink::mojom::AIManagerCreateRewriterClient> client, blink::mojom::AIRewriterCreateOptionsPtr options) { - if (options->tone != blink::mojom::AIRewriterTone::kAsIs && - options->length != blink::mojom::AIRewriterLength::kAsIs) { - // TODO(crbug.com/358214322): Currently the combination of the tone and the - // length option is not supported. - // TODO(crbug.com/358214322): Return an error enum and throw a clear - // exception from the blink side. - mojo::Remote<blink::mojom::AIManagerCreateRewriterClient> client_remote( - std::move(client)); - client_remote->OnResult(mojo::PendingRemote<blink::mojom::AIRewriter>()); - return; - } - // TODO(crbug.com/382325795): Use kWritingAssistanceApi instead of kCompose. CreateContextBoundObjectTask<AIRewriter, blink::mojom::AIRewriter, blink::mojom::AIManagerCreateRewriterClient, blink::mojom::AIRewriterCreateOptionsPtr>:: - CreateAndStart(browser_context_, - optimization_guide::ModelBasedCapabilityKey::kCompose, - context_bound_object_set_, std::move(options), - std::move(client)); + CreateAndStart( + browser_context_, + optimization_guide::ModelBasedCapabilityKey::kWritingAssistanceApi, + context_bound_object_set_, std::move(options), std::move(client)); } void AIManager::CanCreateSession(
diff --git a/chrome/browser/ai/ai_rewriter.cc b/chrome/browser/ai/ai_rewriter.cc index fb8f13fa..34724b6f 100644 --- a/chrome/browser/ai/ai_rewriter.cc +++ b/chrome/browser/ai/ai_rewriter.cc
@@ -10,9 +10,61 @@ #include "chrome/browser/ai/ai_utils.h" #include "components/optimization_guide/core/optimization_guide_util.h" #include "components/optimization_guide/proto/common_types.pb.h" -#include "components/optimization_guide/proto/features/compose.pb.h" #include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom.h" +namespace { + +optimization_guide::proto::WritingAssistanceApiOutputTone ToProtoTone( + blink::mojom::AIRewriterTone type) { + switch (type) { + case blink::mojom::AIRewriterTone::kAsIs: + // Rewriter config handles neutral tone semantically like "as-is". + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_TONE_NEUTRAL; + case blink::mojom::AIRewriterTone::kMoreFormal: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_TONE_FORMAL; + case blink::mojom::AIRewriterTone::kMoreCasual: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_TONE_CASUAL; + } +} + +optimization_guide::proto::WritingAssistanceApiOutputFormat ToProtoFormat( + blink::mojom::AIRewriterFormat format) { + switch (format) { + case blink::mojom::AIRewriterFormat::kAsIs: + // Rewriter config handles unspecified format by omitting instructions. + NOTIMPLEMENTED() << "TODO: Improve AIRewriterFormat::kAsIs support"; + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_FORMAT_NOT_SPECIFIED; + case blink::mojom::AIRewriterFormat::kPlainText: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_FORMAT_PLAIN_TEXT; + case blink::mojom::AIRewriterFormat::kMarkdown: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_FORMAT_MARKDOWN; + } +} + +optimization_guide::proto::WritingAssistanceApiOutputLength ToProtoLength( + blink::mojom::AIRewriterLength length) { + switch (length) { + case blink::mojom::AIRewriterLength::kAsIs: + // Rewriter config handles medium length semantically like "as-is". + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_LENGTH_MEDIUM; + case blink::mojom::AIRewriterLength::kShorter: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_LENGTH_SHORT; + case blink::mojom::AIRewriterLength::kLonger: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_LENGTH_LONG; + } +} + +} // namespace + AIRewriter::AIRewriter( AIContextBoundObjectSet& context_bound_object_set, std::unique_ptr<optimization_guide::OptimizationGuideModelExecutor::Session> @@ -34,46 +86,31 @@ } } +// static +std::unique_ptr<optimization_guide::proto::WritingAssistanceApiOptions> +AIRewriter::ToProtoOptions( + const blink::mojom::AIRewriterCreateOptionsPtr& options) { + auto proto_options = std::make_unique< + optimization_guide::proto::WritingAssistanceApiOptions>(); + proto_options->set_output_tone(ToProtoTone(options->tone)); + proto_options->set_output_format(ToProtoFormat(options->format)); + proto_options->set_output_length(ToProtoLength(options->length)); + return proto_options; +} + void AIRewriter::Rewrite( const std::string& input, const std::optional<std::string>& context, mojo::PendingRemote<blink::mojom::ModelStreamingResponder> pending_responder) { - optimization_guide::proto::ComposePageMetadata page_metadata; - std::string context_string = base::JoinString( - {options_->shared_context.value_or(""), context.value_or("")}, "\n"); - base::TrimString(context_string, "\n", &context_string); - page_metadata.set_trimmed_page_inner_text( - context_string.substr(0, AIUtils::kTrimmedInnerTextMaxChars)); - page_metadata.set_page_inner_text(context_string); - - optimization_guide::proto::ComposeRequest context_request; - *context_request.mutable_page_metadata() = std::move(page_metadata); - - session_->AddContext(context_request); - - optimization_guide::proto::ComposeRequest execute_request; - // TODO(crbug.com/358214322): We don't support the combination of tone and - // length. - if (options_->tone == blink::mojom::AIRewriterTone::kMoreFormal) { - execute_request.mutable_rewrite_params()->set_tone( - optimization_guide::proto::ComposeTone::COMPOSE_FORMAL); - } else if (options_->tone == blink::mojom::AIRewriterTone::kMoreCasual) { - execute_request.mutable_rewrite_params()->set_tone( - optimization_guide::proto::ComposeTone::COMPOSE_INFORMAL); - } else if (options_->length == blink::mojom::AIRewriterLength::kLonger) { - execute_request.mutable_rewrite_params()->set_length( - optimization_guide::proto::ComposeLength::COMPOSE_LONGER); - } else if (options_->length == blink::mojom::AIRewriterLength::kShorter) { - execute_request.mutable_rewrite_params()->set_length( - optimization_guide::proto::ComposeLength::COMPOSE_SHORTER); - } else { - execute_request.mutable_rewrite_params()->set_regenerate(true); - } - execute_request.mutable_rewrite_params()->set_previous_response(input); - + optimization_guide::proto::WritingAssistanceApiRequest request; + request.set_context(context.value_or(std::string())); + request.set_allocated_options(ToProtoOptions(options_).release()); + request.set_rewrite_text(input); + // TODO(crbug.com/390006887): Pass shared context with session creation. + request.set_shared_context(options_->shared_context.value_or(std::string())); session_->ExecuteModel( - execute_request, + request, base::BindRepeating(&AIRewriter::ModelExecutionCallback, weak_ptr_factory_.GetWeakPtr(), responder_set_.Add(std::move(pending_responder)))); @@ -93,11 +130,12 @@ return; } - auto compose_response = optimization_guide::ParsedAnyMetadata< - optimization_guide::proto::ComposeResponse>(result.response->response); - if (compose_response) { + auto response = optimization_guide::ParsedAnyMetadata< + optimization_guide::proto::WritingAssistanceApiResponse>( + result.response->response); + if (response) { responder->OnStreaming( - compose_response->output(), + response->output(), blink::mojom::ModelStreamingResponderAction::kReplace); } if (result.response->is_complete) {
diff --git a/chrome/browser/ai/ai_rewriter.h b/chrome/browser/ai/ai_rewriter.h index 11b4319..66ff935 100644 --- a/chrome/browser/ai/ai_rewriter.h +++ b/chrome/browser/ai/ai_rewriter.h
@@ -10,6 +10,7 @@ #include "chrome/browser/ai/ai_context_bound_object.h" #include "components/optimization_guide/core/optimization_guide_model_executor.h" +#include "components/optimization_guide/proto/features/writing_assistance_api.pb.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote_set.h" @@ -30,9 +31,11 @@ mojo::PendingReceiver<blink::mojom::AIRewriter> receiver); AIRewriter(const AIRewriter&) = delete; AIRewriter& operator=(const AIRewriter&) = delete; - ~AIRewriter() override; + static std::unique_ptr<optimization_guide::proto::WritingAssistanceApiOptions> + ToProtoOptions(const blink::mojom::AIRewriterCreateOptionsPtr& options); + // `blink::mojom::AIRewriter` implementation. void Rewrite(const std::string& input, const std::optional<std::string>& context,
diff --git a/chrome/browser/ai/ai_rewriter_unittest.cc b/chrome/browser/ai/ai_rewriter_unittest.cc index d3c8b46..593032a 100644 --- a/chrome/browser/ai/ai_rewriter_unittest.cc +++ b/chrome/browser/ai/ai_rewriter_unittest.cc
@@ -14,6 +14,7 @@ #include "components/optimization_guide/core/optimization_guide_proto_util.h" #include "components/optimization_guide/core/optimization_guide_switches.h" #include "components/optimization_guide/core/optimization_guide_util.h" +#include "components/optimization_guide/proto/features/writing_assistance_api.pb.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/mojom/ai/ai_manager.mojom.h" @@ -25,8 +26,6 @@ constexpr char kSharedContextString[] = "test shared context"; constexpr char kContextString[] = "test context"; -constexpr char kConcatenatedContextString[] = - "test shared context\ntest context"; constexpr char kInputString[] = "input string"; class MockCreateRewriterClient @@ -53,7 +52,7 @@ optimization_guide::OptimizationGuideModelStreamingExecutionResult CreateExecutionResult(std::string_view output, bool is_complete) { - optimization_guide::proto::ComposeResponse response; + optimization_guide::proto::WritingAssistanceApiResponse response; *response.mutable_output() = output; return optimization_guide::OptimizationGuideModelStreamingExecutionResult( optimization_guide::StreamingResponse{ @@ -71,169 +70,93 @@ /*provided_by_on_device=*/true); } -void CheckComposeRequestContext( - const google::protobuf::MessageLite& request_metadata, - const std::string& expected_context_string) { - const optimization_guide::proto::ComposeRequest* request = - static_cast<const optimization_guide::proto::ComposeRequest*>( - &request_metadata); - EXPECT_THAT(request->page_metadata().page_inner_text(), - expected_context_string); - EXPECT_THAT(request->page_metadata().trimmed_page_inner_text(), - expected_context_string); +blink::mojom::AIRewriterCreateOptionsPtr GetDefaultOptions() { + return blink::mojom::AIRewriterCreateOptions::New( + kSharedContextString, blink::mojom::AIRewriterTone::kAsIs, + blink::mojom::AIRewriterFormat::kAsIs, + blink::mojom::AIRewriterLength::kAsIs); } -void CheckComposeRequestRewriteParamsPreviousResponse( - const google::protobuf::MessageLite& request_metadata, - const std::string& previous_response) { - const optimization_guide::proto::ComposeRequest* request = - static_cast<const optimization_guide::proto::ComposeRequest*>( - &request_metadata); - EXPECT_THAT(request->rewrite_params().previous_response(), previous_response); -} - -void CheckComposeRequestRewriteParamsTone( - const google::protobuf::MessageLite& request_metadata, - optimization_guide::proto::ComposeTone tone) { - const optimization_guide::proto::ComposeRequest* request = - static_cast<const optimization_guide::proto::ComposeRequest*>( - &request_metadata); - EXPECT_EQ(request->rewrite_params().tone(), tone); -} - -void CheckComposeRequestRewriteParamsLength( - const google::protobuf::MessageLite& request_metadata, - optimization_guide::proto::ComposeLength length) { - const optimization_guide::proto::ComposeRequest* request = - static_cast<const optimization_guide::proto::ComposeRequest*>( - &request_metadata); - EXPECT_EQ(request->rewrite_params().length(), length); -} - -void CheckComposeRequestRewriteParamsRegenerateFlag( - const google::protobuf::MessageLite& request_metadata) { - const optimization_guide::proto::ComposeRequest* request = - static_cast<const optimization_guide::proto::ComposeRequest*>( - &request_metadata); - EXPECT_TRUE(request->rewrite_params().regenerate()); +std::unique_ptr<optimization_guide::proto::WritingAssistanceApiOptions> +GetDefaultExpectedOptions() { + return AIRewriter::ToProtoOptions(GetDefaultOptions()); } } // namespace class AIRewriterTest : public AITestUtils::AITestBase { protected: - void RunSimpleRewriteTest( - blink::mojom::AIRewriterTone tone, - blink::mojom::AIRewriterFormat format, - blink::mojom::AIRewriterLength length, - base::OnceCallback<void(const google::protobuf::MessageLite& - request_metadata)> request_check_callback); - void RunRewriteOptionCombinationFailureTest( - blink::mojom::AIRewriterTone tone, - blink::mojom::AIRewriterFormat format, - blink::mojom::AIRewriterLength length); -}; + void RunSimpleRewriteTest(blink::mojom::AIRewriterTone tone, + blink::mojom::AIRewriterFormat format, + blink::mojom::AIRewriterLength length) { + const auto options = blink::mojom::AIRewriterCreateOptions::New( + kSharedContextString, tone, format, length); -void AIRewriterTest::RunSimpleRewriteTest( - blink::mojom::AIRewriterTone tone, - blink::mojom::AIRewriterFormat format, - blink::mojom::AIRewriterLength length, - base::OnceCallback<void(const google::protobuf::MessageLite& - request_metadata)> request_check_callback) { - SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) - .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey - feature, - const std::optional< - optimization_guide:: - SessionConfigParams>& - config_params) { - auto session = std::make_unique<optimization_guide::MockSession>(); + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) + .WillOnce(testing::Invoke([&](optimization_guide:: + ModelBasedCapabilityKey feature, + const std::optional< + optimization_guide:: + SessionConfigParams>& + config_params) { + auto session = std::make_unique<optimization_guide::MockSession>(); + EXPECT_CALL(*session, ExecuteModel(_, _)) + .WillOnce(testing::Invoke( + [&](const google::protobuf::MessageLite& request_metadata, + optimization_guide:: + OptimizationGuideModelExecutionResultStreamingCallback + callback) { + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *AIRewriter::ToProtoOptions(options), kInputString); + callback.Run(CreateExecutionResult("Result text", + /*is_complete=*/true)); + })); + return session; + })); - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })); - EXPECT_CALL(*session, ExecuteModel(_, _)) - .WillOnce(testing::Invoke( - [&](const google::protobuf::MessageLite& request_metadata, - optimization_guide:: - OptimizationGuideModelExecutionResultStreamingCallback - callback) { - CheckComposeRequestRewriteParamsPreviousResponse( - request_metadata, kInputString); - std::move(request_check_callback).Run(request_metadata); - callback.Run(CreateExecutionResult("Result text", - /*is_complete=*/true)); - })); - return session; - })); + mojo::Remote<blink::mojom::AIRewriter> rewriter_remote; + { + MockCreateRewriterClient mock_create_rewriter_client; + base::RunLoop run_loop; + EXPECT_CALL(mock_create_rewriter_client, OnResult(_)) + .WillOnce(testing::Invoke( + [&](mojo::PendingRemote<::blink::mojom::AIRewriter> rewriter) { + EXPECT_TRUE(rewriter); + rewriter_remote = + mojo::Remote<blink::mojom::AIRewriter>(std::move(rewriter)); + run_loop.Quit(); + })); - mojo::Remote<blink::mojom::AIRewriter> rewriter_remote; - { - MockCreateRewriterClient mock_create_rewriter_client; + mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); + ai_manager->CreateRewriter( + mock_create_rewriter_client.BindNewPipeAndPassRemote(), + options.Clone()); + run_loop.Run(); + } + AITestUtils::MockModelStreamingResponder mock_responder; + base::RunLoop run_loop; - EXPECT_CALL(mock_create_rewriter_client, OnResult(_)) + EXPECT_CALL(mock_responder, OnStreaming(_, _)) .WillOnce(testing::Invoke( - [&](mojo::PendingRemote<::blink::mojom::AIRewriter> rewriter) { - EXPECT_TRUE(rewriter); - rewriter_remote = - mojo::Remote<blink::mojom::AIRewriter>(std::move(rewriter)); + [&](const std::string& text, + blink::mojom::ModelStreamingResponderAction action) { + EXPECT_THAT(text, "Result text"); + EXPECT_EQ(action, + blink::mojom::ModelStreamingResponderAction::kReplace); + })); + + EXPECT_CALL(mock_responder, OnCompletion(_)) + .WillOnce(testing::Invoke( + [&](blink::mojom::ModelExecutionContextInfoPtr context_info) { run_loop.Quit(); })); - mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); - ai_manager->CreateRewriter( - mock_create_rewriter_client.BindNewPipeAndPassRemote(), - blink::mojom::AIRewriterCreateOptions::New(kSharedContextString, tone, - format, length)); + rewriter_remote->Rewrite(kInputString, kContextString, + mock_responder.BindNewPipeAndPassRemote()); run_loop.Run(); } - AITestUtils::MockModelStreamingResponder mock_responder; - - base::RunLoop run_loop; - EXPECT_CALL(mock_responder, OnStreaming(_, _)) - .WillOnce(testing::Invoke( - [&](const std::string& text, - blink::mojom::ModelStreamingResponderAction action) { - EXPECT_THAT(text, "Result text"); - EXPECT_EQ(action, - blink::mojom::ModelStreamingResponderAction::kReplace); - })); - - EXPECT_CALL(mock_responder, OnCompletion(_)) - .WillOnce(testing::Invoke( - [&](blink::mojom::ModelExecutionContextInfoPtr context_info) { - run_loop.Quit(); - })); - - rewriter_remote->Rewrite(kInputString, kContextString, - mock_responder.BindNewPipeAndPassRemote()); - run_loop.Run(); -} - -void AIRewriterTest::RunRewriteOptionCombinationFailureTest( - blink::mojom::AIRewriterTone tone, - blink::mojom::AIRewriterFormat format, - blink::mojom::AIRewriterLength length) { - MockCreateRewriterClient mock_create_rewriter_client; - base::RunLoop run_loop; - EXPECT_CALL(mock_create_rewriter_client, OnResult(_)) - .WillOnce(testing::Invoke( - [&](mojo::PendingRemote<::blink::mojom::AIRewriter> rewriter) { - EXPECT_FALSE(rewriter); - run_loop.Quit(); - })); - - mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); - ai_manager->CreateRewriter( - mock_create_rewriter_client.BindNewPipeAndPassRemote(), - blink::mojom::AIRewriterCreateOptions::New(kSharedContextString, tone, - format, length)); - run_loop.Run(); -} +}; TEST_F(AIRewriterTest, CreateRewriterNoService) { SetupNullOptimizationGuideKeyedService(); @@ -250,10 +173,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateRewriter( mock_create_rewriter_client.BindNewPipeAndPassRemote(), - blink::mojom::AIRewriterCreateOptions::New( - kSharedContextString, blink::mojom::AIRewriterTone::kAsIs, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kAsIs)); + GetDefaultOptions()); run_loop.Run(); } @@ -284,10 +204,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateRewriter( mock_create_rewriter_client.BindNewPipeAndPassRemote(), - blink::mojom::AIRewriterCreateOptions::New( - kSharedContextString, blink::mojom::AIRewriterTone::kAsIs, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kAsIs)); + GetDefaultOptions()); run_loop.Run(); } @@ -346,22 +263,19 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateRewriter( mock_create_rewriter_client.BindNewPipeAndPassRemote(), - blink::mojom::AIRewriterCreateOptions::New( - kSharedContextString, blink::mojom::AIRewriterTone::kAsIs, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kAsIs)); + GetDefaultOptions()); run_loop_for_add_observer.Run(); CHECK(availability_observer); // Send `kConfigNotAvailableForFeature` first to the observer. availability_observer->OnDeviceModelAvailabilityChanged( - optimization_guide::ModelBasedCapabilityKey::kCompose, + optimization_guide::ModelBasedCapabilityKey::kWritingAssistanceApi, optimization_guide::OnDeviceModelEligibilityReason:: kConfigNotAvailableForFeature); // And then send `kConfigNotAvailableForFeature` to the observer. availability_observer->OnDeviceModelAvailabilityChanged( - optimization_guide::ModelBasedCapabilityKey::kCompose, + optimization_guide::ModelBasedCapabilityKey::kWritingAssistanceApi, optimization_guide::OnDeviceModelEligibilityReason::kSuccess); // OnResult() should be called. @@ -412,10 +326,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateRewriter( mock_create_rewriter_client->BindNewPipeAndPassRemote(), - blink::mojom::AIRewriterCreateOptions::New( - kSharedContextString, blink::mojom::AIRewriterTone::kAsIs, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kAsIs)); + GetDefaultOptions()); run_loop_for_add_observer.Run(); CHECK(availability_observer); @@ -427,101 +338,37 @@ run_loop_for_remove_observer.Run(); } -TEST_F(AIRewriterTest, RewriteRegenerate) { - RunSimpleRewriteTest( - blink::mojom::AIRewriterTone::kAsIs, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kAsIs, - base::BindLambdaForTesting( - [&](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestRewriteParamsRegenerateFlag(request_metadata); - })); +TEST_F(AIRewriterTest, RewriteDefault) { + SetupMockOptimizationGuideKeyedService(); + RunSimpleRewriteTest(blink::mojom::AIRewriterTone::kAsIs, + blink::mojom::AIRewriterFormat::kAsIs, + blink::mojom::AIRewriterLength::kAsIs); } -TEST_F(AIRewriterTest, RewriteMoreCasual) { - RunSimpleRewriteTest( - blink::mojom::AIRewriterTone::kMoreCasual, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kAsIs, - base::BindLambdaForTesting( - [&](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestRewriteParamsTone( - request_metadata, - optimization_guide::proto::ComposeTone::COMPOSE_INFORMAL); - })); -} - -TEST_F(AIRewriterTest, RewriteMoreFormal) { - RunSimpleRewriteTest( - blink::mojom::AIRewriterTone::kMoreFormal, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kAsIs, - base::BindLambdaForTesting( - [&](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestRewriteParamsTone( - request_metadata, - optimization_guide::proto::ComposeTone::COMPOSE_FORMAL); - })); -} - -TEST_F(AIRewriterTest, RewriteLonger) { - RunSimpleRewriteTest( - blink::mojom::AIRewriterTone::kAsIs, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kLonger, - base::BindLambdaForTesting( - [&](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestRewriteParamsLength( - request_metadata, - optimization_guide::proto::ComposeLength::COMPOSE_LONGER); - })); -} - -TEST_F(AIRewriterTest, RewriteShorter) { - RunSimpleRewriteTest( - blink::mojom::AIRewriterTone::kAsIs, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kShorter, - base::BindLambdaForTesting( - [&](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestRewriteParamsLength( - request_metadata, - optimization_guide::proto::ComposeLength::COMPOSE_SHORTER); - })); -} - -TEST_F(AIRewriterTest, RewriteOptionCombinationFailureTest) { +TEST_F(AIRewriterTest, RewriteWithOptions) { SetupMockOptimizationGuideKeyedService(); blink::mojom::AIRewriterTone tones[]{ - blink::mojom::AIRewriterTone::kMoreCasual, + blink::mojom::AIRewriterTone::kAsIs, blink::mojom::AIRewriterTone::kMoreFormal, + blink::mojom::AIRewriterTone::kMoreCasual, }; blink::mojom::AIRewriterFormat formats[]{ + blink::mojom::AIRewriterFormat::kAsIs, blink::mojom::AIRewriterFormat::kPlainText, blink::mojom::AIRewriterFormat::kMarkdown, }; blink::mojom::AIRewriterLength lengths[]{ - blink::mojom::AIRewriterLength::kLonger, + blink::mojom::AIRewriterLength::kAsIs, blink::mojom::AIRewriterLength::kShorter, + blink::mojom::AIRewriterLength::kLonger, }; - // Any combination with more than one non-kAsIs value fails. for (const auto& tone : tones) { for (const auto& format : formats) { for (const auto& length : lengths) { - RunRewriteOptionCombinationFailureTest(tone, format, length); + SCOPED_TRACE(testing::Message() + << tone << " " << format << " " << length); + RunSimpleRewriteTest(tone, format, length); } - RunRewriteOptionCombinationFailureTest( - tone, format, blink::mojom::AIRewriterLength::kAsIs); - } - for (const auto& length : lengths) { - RunRewriteOptionCombinationFailureTest( - tone, blink::mojom::AIRewriterFormat::kAsIs, length); - } - } - for (const auto& format : formats) { - for (const auto& length : lengths) { - RunRewriteOptionCombinationFailureTest( - blink::mojom::AIRewriterTone::kAsIs, format, length); } } } @@ -536,20 +383,15 @@ SessionConfigParams>& config_params) { auto session = std::make_unique<optimization_guide::MockSession>(); - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })); EXPECT_CALL(*session, ExecuteModel(_, _)) .WillOnce(testing::Invoke( [](const google::protobuf::MessageLite& request_metadata, optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestRewriteParamsPreviousResponse( - request_metadata, kInputString); + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *GetDefaultExpectedOptions(), kInputString); callback.Run(CreateExecutionErrorResult( optimization_guide::OptimizationGuideModelExecutionError:: FromModelExecutionError( @@ -609,22 +451,15 @@ SessionConfigParams>& config_params) { auto session = std::make_unique<optimization_guide::MockSession>(); - - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })); EXPECT_CALL(*session, ExecuteModel(_, _)) .WillOnce(testing::Invoke( [](const google::protobuf::MessageLite& request_metadata, optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestRewriteParamsPreviousResponse( - request_metadata, kInputString); - + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *GetDefaultExpectedOptions(), kInputString); callback.Run( CreateExecutionResult("Result ", /*is_complete=*/false)); callback.Run(CreateExecutionResult("Result text", @@ -649,10 +484,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateRewriter( mock_create_rewriter_client.BindNewPipeAndPassRemote(), - blink::mojom::AIRewriterCreateOptions::New( - kSharedContextString, blink::mojom::AIRewriterTone::kAsIs, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kAsIs)); + GetDefaultOptions()); run_loop.Run(); } AITestUtils::MockModelStreamingResponder mock_responder; @@ -695,26 +527,15 @@ SessionConfigParams>& config_params) { auto session = std::make_unique<optimization_guide::MockSession>(); - - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext( - request_metadata, "test shared context\ntest context 2"); - })); EXPECT_CALL(*session, ExecuteModel(_, _)) .WillOnce(testing::Invoke( [](const google::protobuf::MessageLite& request_metadata, optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestRewriteParamsPreviousResponse( - request_metadata, kInputString); + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *GetDefaultExpectedOptions(), kInputString); callback.Run(CreateExecutionResult("Result text", /*is_complete=*/true)); })) @@ -723,8 +544,9 @@ optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestRewriteParamsPreviousResponse( - request_metadata, "input string 2"); + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, "test context 2", + *GetDefaultExpectedOptions(), "input string 2"); callback.Run(CreateExecutionResult("Result text 2", /*is_complete=*/true)); })); @@ -747,10 +569,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateRewriter( mock_create_rewriter_client.BindNewPipeAndPassRemote(), - blink::mojom::AIRewriterCreateOptions::New( - kSharedContextString, blink::mojom::AIRewriterTone::kAsIs, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kAsIs)); + GetDefaultOptions()); run_loop.Run(); } { @@ -813,21 +632,15 @@ SessionConfigParams>& config_params) { auto session = std::make_unique<optimization_guide::MockSession>(); - - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })); EXPECT_CALL(*session, ExecuteModel(_, _)) .WillOnce(testing::Invoke( [&](const google::protobuf::MessageLite& request_metadata, optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestRewriteParamsPreviousResponse( - request_metadata, kInputString); + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *GetDefaultExpectedOptions(), kInputString); streaming_callback = std::move(callback); run_loop_for_callback.Quit(); })); @@ -850,10 +663,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateRewriter( mock_create_rewriter_client.BindNewPipeAndPassRemote(), - blink::mojom::AIRewriterCreateOptions::New( - kSharedContextString, blink::mojom::AIRewriterTone::kAsIs, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kAsIs)); + GetDefaultOptions()); run_loop.Run(); } std::unique_ptr<AITestUtils::MockModelStreamingResponder> mock_responder = @@ -886,21 +696,15 @@ SessionConfigParams>& config_params) { auto session = std::make_unique<optimization_guide::MockSession>(); - - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })); EXPECT_CALL(*session, ExecuteModel(_, _)) .WillOnce(testing::Invoke( [&](const google::protobuf::MessageLite& request_metadata, optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestRewriteParamsPreviousResponse( - request_metadata, kInputString); + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *GetDefaultExpectedOptions(), kInputString); streaming_callback = std::move(callback); run_loop_for_callback.Quit(); })); @@ -923,10 +727,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateRewriter( mock_create_rewriter_client.BindNewPipeAndPassRemote(), - blink::mojom::AIRewriterCreateOptions::New( - kSharedContextString, blink::mojom::AIRewriterTone::kAsIs, - blink::mojom::AIRewriterFormat::kAsIs, - blink::mojom::AIRewriterLength::kAsIs)); + GetDefaultOptions()); run_loop.Run(); }
diff --git a/chrome/browser/ai/ai_test_utils.cc b/chrome/browser/ai/ai_test_utils.cc index 074c3db..a414792 100644 --- a/chrome/browser/ai/ai_test_utils.cc +++ b/chrome/browser/ai/ai_test_utils.cc
@@ -110,3 +110,25 @@ static base::NoDestructor<optimization_guide::proto::Any> data; return *data; } + +// static +void AITestUtils::CheckWritingAssistanceApiRequest( + const google::protobuf::MessageLite& request_metadata, + const std::string& expected_shared_context, + const std::string& expected_context, + const optimization_guide::proto::WritingAssistanceApiOptions& + expected_options, + const std::string& expected_input) { + const optimization_guide::proto::WritingAssistanceApiRequest* request = + static_cast< + const optimization_guide::proto::WritingAssistanceApiRequest*>( + &request_metadata); + EXPECT_EQ(request->shared_context(), expected_shared_context); + EXPECT_EQ(request->context(), expected_context); + EXPECT_EQ(request->options().output_tone(), expected_options.output_tone()); + EXPECT_EQ(request->options().output_format(), + expected_options.output_format()); + EXPECT_EQ(request->options().output_length(), + expected_options.output_length()); + EXPECT_EQ(request->rewrite_text(), expected_input); +}
diff --git a/chrome/browser/ai/ai_test_utils.h b/chrome/browser/ai/ai_test_utils.h index e645fa7..102125a 100644 --- a/chrome/browser/ai/ai_test_utils.h +++ b/chrome/browser/ai/ai_test_utils.h
@@ -9,6 +9,7 @@ #include "chrome/browser/ai/ai_manager.h" #include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "components/optimization_guide/proto/features/writing_assistance_api.pb.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "testing/gmock/include/gmock/gmock.h" @@ -131,6 +132,14 @@ static const optimization_guide::TokenLimits& GetFakeTokenLimits(); static const optimization_guide::proto::Any& GetFakeFeatureMetadata(); + + static void CheckWritingAssistanceApiRequest( + const google::protobuf::MessageLite& request_metadata, + const std::string& expected_shared_context, + const std::string& expected_context, + const optimization_guide::proto::WritingAssistanceApiOptions& + expected_options, + const std::string& expected_input); }; #endif // CHROME_BROWSER_AI_AI_TEST_UTILS_H_
diff --git a/chrome/browser/ai/ai_writer.cc b/chrome/browser/ai/ai_writer.cc index 3a9feca5..ebe345ec 100644 --- a/chrome/browser/ai/ai_writer.cc +++ b/chrome/browser/ai/ai_writer.cc
@@ -10,9 +10,54 @@ #include "chrome/browser/ai/ai_utils.h" #include "components/optimization_guide/core/optimization_guide_util.h" #include "components/optimization_guide/proto/common_types.pb.h" -#include "components/optimization_guide/proto/features/compose.pb.h" #include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom.h" +namespace { + +optimization_guide::proto::WritingAssistanceApiOutputTone ToProtoTone( + blink::mojom::AIWriterTone type) { + switch (type) { + case blink::mojom::AIWriterTone::kFormal: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_TONE_FORMAL; + case blink::mojom::AIWriterTone::kNeutral: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_TONE_NEUTRAL; + case blink::mojom::AIWriterTone::kCasual: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_TONE_CASUAL; + } +} + +optimization_guide::proto::WritingAssistanceApiOutputFormat ToProtoFormat( + blink::mojom::AIWriterFormat format) { + switch (format) { + case blink::mojom::AIWriterFormat::kPlainText: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_FORMAT_PLAIN_TEXT; + case blink::mojom::AIWriterFormat::kMarkdown: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_FORMAT_MARKDOWN; + } +} + +optimization_guide::proto::WritingAssistanceApiOutputLength ToProtoLength( + blink::mojom::AIWriterLength length) { + switch (length) { + case blink::mojom::AIWriterLength::kShort: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_LENGTH_SHORT; + case blink::mojom::AIWriterLength::kMedium: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_LENGTH_MEDIUM; + case blink::mojom::AIWriterLength::kLong: + return optimization_guide::proto:: + WRITING_ASSISTANCE_API_OUTPUT_LENGTH_LONG; + } +} + +} // namespace + AIWriter::AIWriter( AIContextBoundObjectSet& context_bound_object_set, std::unique_ptr<optimization_guide::OptimizationGuideModelExecutor::Session> @@ -34,28 +79,30 @@ } } +// static +std::unique_ptr<optimization_guide::proto::WritingAssistanceApiOptions> +AIWriter::ToProtoOptions( + const blink::mojom::AIWriterCreateOptionsPtr& options) { + auto proto_options = std::make_unique< + optimization_guide::proto::WritingAssistanceApiOptions>(); + proto_options->set_output_tone(ToProtoTone(options->tone)); + proto_options->set_output_format(ToProtoFormat(options->format)); + proto_options->set_output_length(ToProtoLength(options->length)); + return proto_options; +} + void AIWriter::Write(const std::string& input, const std::optional<std::string>& context, mojo::PendingRemote<blink::mojom::ModelStreamingResponder> pending_responder) { - optimization_guide::proto::ComposePageMetadata page_metadata; - std::string context_string = base::JoinString( - {options_->shared_context.value_or(""), context.value_or("")}, "\n"); - base::TrimString(context_string, "\n", &context_string); - page_metadata.set_trimmed_page_inner_text( - context_string.substr(0, AIUtils::kTrimmedInnerTextMaxChars)); - page_metadata.set_page_inner_text(context_string); - - optimization_guide::proto::ComposeRequest context_request; - *context_request.mutable_page_metadata() = std::move(page_metadata); - - session_->AddContext(context_request); - - optimization_guide::proto::ComposeRequest execute_request; - execute_request.mutable_generate_params()->set_user_input(input); - + optimization_guide::proto::WritingAssistanceApiRequest request; + request.set_context(context.value_or(std::string())); + request.set_allocated_options(ToProtoOptions(options_).release()); + request.set_rewrite_text(input); + // TODO(crbug.com/390006887): Pass shared context with session creation. + request.set_shared_context(options_->shared_context.value_or(std::string())); session_->ExecuteModel( - execute_request, + request, base::BindRepeating(&AIWriter::ModelExecutionCallback, weak_ptr_factory_.GetWeakPtr(), responder_set_.Add(std::move(pending_responder)))); @@ -75,11 +122,12 @@ return; } - auto compose_response = optimization_guide::ParsedAnyMetadata< - optimization_guide::proto::ComposeResponse>(result.response->response); - if (compose_response) { + auto response = optimization_guide::ParsedAnyMetadata< + optimization_guide::proto::WritingAssistanceApiResponse>( + result.response->response); + if (response) { responder->OnStreaming( - compose_response->output(), + response->output(), blink::mojom::ModelStreamingResponderAction::kReplace); } if (result.response->is_complete) {
diff --git a/chrome/browser/ai/ai_writer.h b/chrome/browser/ai/ai_writer.h index bf3c6624..6766d4ef 100644 --- a/chrome/browser/ai/ai_writer.h +++ b/chrome/browser/ai/ai_writer.h
@@ -10,6 +10,7 @@ #include "chrome/browser/ai/ai_context_bound_object.h" #include "components/optimization_guide/core/optimization_guide_model_executor.h" +#include "components/optimization_guide/proto/features/writing_assistance_api.pb.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote_set.h" @@ -28,9 +29,11 @@ mojo::PendingReceiver<blink::mojom::AIWriter> receiver); AIWriter(const AIWriter&) = delete; AIWriter& operator=(const AIWriter&) = delete; - ~AIWriter() override; + static std::unique_ptr<optimization_guide::proto::WritingAssistanceApiOptions> + ToProtoOptions(const blink::mojom::AIWriterCreateOptionsPtr& options); + // `blink::mojom::AIWriter` implementation. void Write(const std::string& input, const std::optional<std::string>& context,
diff --git a/chrome/browser/ai/ai_writer_unittest.cc b/chrome/browser/ai/ai_writer_unittest.cc index 5c9a8192..e4c31d4 100644 --- a/chrome/browser/ai/ai_writer_unittest.cc +++ b/chrome/browser/ai/ai_writer_unittest.cc
@@ -14,6 +14,7 @@ #include "components/optimization_guide/core/optimization_guide_proto_util.h" #include "components/optimization_guide/core/optimization_guide_switches.h" #include "components/optimization_guide/core/optimization_guide_util.h" +#include "components/optimization_guide/proto/features/writing_assistance_api.pb.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/mojom/ai/ai_manager.mojom.h" @@ -25,8 +26,6 @@ constexpr char kSharedContextString[] = "test shared context"; constexpr char kContextString[] = "test context"; -constexpr char kConcatenatedContextString[] = - "test shared context\ntest context"; constexpr char kInputString[] = "input string"; class MockCreateWriterClient @@ -53,7 +52,7 @@ optimization_guide::OptimizationGuideModelStreamingExecutionResult CreateExecutionResult(std::string_view output, bool is_complete) { - optimization_guide::proto::ComposeResponse response; + optimization_guide::proto::WritingAssistanceApiResponse response; *response.mutable_output() = output; return optimization_guide::OptimizationGuideModelStreamingExecutionResult( optimization_guide::StreamingResponse{ @@ -71,30 +70,93 @@ /*provided_by_on_device=*/true); } -void CheckComposeRequestContext( - const google::protobuf::MessageLite& request_metadata, - const std::string& expected_context_string) { - const optimization_guide::proto::ComposeRequest* request = - static_cast<const optimization_guide::proto::ComposeRequest*>( - &request_metadata); - EXPECT_THAT(request->page_metadata().page_inner_text(), - expected_context_string); - EXPECT_THAT(request->page_metadata().trimmed_page_inner_text(), - expected_context_string); +blink::mojom::AIWriterCreateOptionsPtr GetDefaultOptions() { + return blink::mojom::AIWriterCreateOptions::New( + kSharedContextString, blink::mojom::AIWriterTone::kNeutral, + blink::mojom::AIWriterFormat::kPlainText, + blink::mojom::AIWriterLength::kMedium); } -void CheckComposeRequestUserInput( - const google::protobuf::MessageLite& request_metadata, - const std::string& expected_user_input) { - const optimization_guide::proto::ComposeRequest* request = - static_cast<const optimization_guide::proto::ComposeRequest*>( - &request_metadata); - EXPECT_THAT(request->generate_params().user_input(), expected_user_input); +std::unique_ptr<optimization_guide::proto::WritingAssistanceApiOptions> +GetDefaultExpectedOptions() { + return AIWriter::ToProtoOptions(GetDefaultOptions()); } } // namespace -class AIWriterTest : public AITestUtils::AITestBase {}; +class AIWriterTest : public AITestUtils::AITestBase { + protected: + void RunSimpleWriteTest(blink::mojom::AIWriterTone tone, + blink::mojom::AIWriterFormat format, + blink::mojom::AIWriterLength length) { + const auto options = blink::mojom::AIWriterCreateOptions::New( + kSharedContextString, tone, format, length); + + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) + .WillOnce(testing::Invoke([&](optimization_guide:: + ModelBasedCapabilityKey feature, + const std::optional< + optimization_guide:: + SessionConfigParams>& + config_params) { + auto session = std::make_unique<optimization_guide::MockSession>(); + EXPECT_CALL(*session, ExecuteModel(_, _)) + .WillOnce(testing::Invoke( + [&](const google::protobuf::MessageLite& request_metadata, + optimization_guide:: + OptimizationGuideModelExecutionResultStreamingCallback + callback) { + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *AIWriter::ToProtoOptions(options), kInputString); + callback.Run(CreateExecutionResult("Result text", + /*is_complete=*/true)); + })); + return session; + })); + + mojo::Remote<blink::mojom::AIWriter> writer_remote; + { + MockCreateWriterClient mock_create_writer_client; + base::RunLoop run_loop; + EXPECT_CALL(mock_create_writer_client, OnResult(_)) + .WillOnce(testing::Invoke( + [&](mojo::PendingRemote<::blink::mojom::AIWriter> writer) { + EXPECT_TRUE(writer); + writer_remote = + mojo::Remote<blink::mojom::AIWriter>(std::move(writer)); + run_loop.Quit(); + })); + + mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); + ai_manager->CreateWriter( + mock_create_writer_client.BindNewPipeAndPassRemote(), + options.Clone()); + run_loop.Run(); + } + AITestUtils::MockModelStreamingResponder mock_responder; + + base::RunLoop run_loop; + EXPECT_CALL(mock_responder, OnStreaming(_, _)) + .WillOnce(testing::Invoke( + [&](const std::string& text, + blink::mojom::ModelStreamingResponderAction action) { + EXPECT_THAT(text, "Result text"); + EXPECT_EQ(action, + blink::mojom::ModelStreamingResponderAction::kReplace); + })); + + EXPECT_CALL(mock_responder, OnCompletion(_)) + .WillOnce(testing::Invoke( + [&](blink::mojom::ModelExecutionContextInfoPtr context_info) { + run_loop.Quit(); + })); + + writer_remote->Write(kInputString, kContextString, + mock_responder.BindNewPipeAndPassRemote()); + run_loop.Run(); + } +}; TEST_F(AIWriterTest, CreateWriterNoService) { SetupNullOptimizationGuideKeyedService(); @@ -109,12 +171,8 @@ })); mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); - ai_manager->CreateWriter( - mock_create_writer_client.BindNewPipeAndPassRemote(), - blink::mojom::AIWriterCreateOptions::New( - kSharedContextString, blink::mojom::AIWriterTone::kNeutral, - blink::mojom::AIWriterFormat::kPlainText, - blink::mojom::AIWriterLength::kMedium)); + ai_manager->CreateWriter(mock_create_writer_client.BindNewPipeAndPassRemote(), + GetDefaultOptions()); run_loop.Run(); } @@ -143,12 +201,8 @@ })); mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); - ai_manager->CreateWriter( - mock_create_writer_client.BindNewPipeAndPassRemote(), - blink::mojom::AIWriterCreateOptions::New( - kSharedContextString, blink::mojom::AIWriterTone::kNeutral, - blink::mojom::AIWriterFormat::kPlainText, - blink::mojom::AIWriterLength::kMedium)); + ai_manager->CreateWriter(mock_create_writer_client.BindNewPipeAndPassRemote(), + GetDefaultOptions()); run_loop.Run(); } @@ -205,24 +259,20 @@ })); mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); - ai_manager->CreateWriter( - mock_create_writer_client.BindNewPipeAndPassRemote(), - blink::mojom::AIWriterCreateOptions::New( - kSharedContextString, blink::mojom::AIWriterTone::kNeutral, - blink::mojom::AIWriterFormat::kPlainText, - blink::mojom::AIWriterLength::kMedium)); + ai_manager->CreateWriter(mock_create_writer_client.BindNewPipeAndPassRemote(), + GetDefaultOptions()); run_loop_for_add_observer.Run(); CHECK(availability_observer); // Send `kConfigNotAvailableForFeature` first to the observer. availability_observer->OnDeviceModelAvailabilityChanged( - optimization_guide::ModelBasedCapabilityKey::kCompose, + optimization_guide::ModelBasedCapabilityKey::kWritingAssistanceApi, optimization_guide::OnDeviceModelEligibilityReason:: kConfigNotAvailableForFeature); // And then send `kConfigNotAvailableForFeature` to the observer. availability_observer->OnDeviceModelAvailabilityChanged( - optimization_guide::ModelBasedCapabilityKey::kCompose, + optimization_guide::ModelBasedCapabilityKey::kWritingAssistanceApi, optimization_guide::OnDeviceModelEligibilityReason::kSuccess); // OnResult() should be called. @@ -272,10 +322,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateWriter( mock_create_writer_client->BindNewPipeAndPassRemote(), - blink::mojom::AIWriterCreateOptions::New( - kSharedContextString, blink::mojom::AIWriterTone::kNeutral, - blink::mojom::AIWriterFormat::kPlainText, - blink::mojom::AIWriterLength::kMedium)); + GetDefaultOptions()); run_loop_for_add_observer.Run(); CHECK(availability_observer); @@ -287,80 +334,38 @@ run_loop_for_remove_observer.Run(); } -TEST_F(AIWriterTest, SimpleWrite) { +TEST_F(AIWriterTest, WriteDefault) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) - .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey - feature, - const std::optional< - optimization_guide:: - SessionConfigParams>& - config_params) { - EXPECT_EQ(feature, - optimization_guide::ModelBasedCapabilityKey::kCompose); - auto session = std::make_unique<optimization_guide::MockSession>(); - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })); - EXPECT_CALL(*session, ExecuteModel(_, _)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata, - optimization_guide:: - OptimizationGuideModelExecutionResultStreamingCallback - callback) { - CheckComposeRequestUserInput(request_metadata, kInputString); - callback.Run(CreateExecutionResult("Result text", - /*is_complete=*/true)); - })); - return session; - })); + RunSimpleWriteTest(blink::mojom::AIWriterTone::kNeutral, + blink::mojom::AIWriterFormat::kPlainText, + blink::mojom::AIWriterLength::kMedium); +} - mojo::Remote<blink::mojom::AIWriter> writer_remote; - { - MockCreateWriterClient mock_create_writer_client; - base::RunLoop run_loop; - EXPECT_CALL(mock_create_writer_client, OnResult(_)) - .WillOnce(testing::Invoke( - [&](mojo::PendingRemote<::blink::mojom::AIWriter> writer) { - EXPECT_TRUE(writer); - writer_remote = - mojo::Remote<blink::mojom::AIWriter>(std::move(writer)); - run_loop.Quit(); - })); - - mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); - ai_manager->CreateWriter( - mock_create_writer_client.BindNewPipeAndPassRemote(), - blink::mojom::AIWriterCreateOptions::New( - kSharedContextString, blink::mojom::AIWriterTone::kNeutral, - blink::mojom::AIWriterFormat::kPlainText, - blink::mojom::AIWriterLength::kMedium)); - run_loop.Run(); +TEST_F(AIWriterTest, WriteWithOptions) { + SetupMockOptimizationGuideKeyedService(); + blink::mojom::AIWriterTone tones[]{ + blink::mojom::AIWriterTone::kFormal, + blink::mojom::AIWriterTone::kNeutral, + blink::mojom::AIWriterTone::kCasual, + }; + blink::mojom::AIWriterFormat formats[]{ + blink::mojom::AIWriterFormat::kPlainText, + blink::mojom::AIWriterFormat::kMarkdown, + }; + blink::mojom::AIWriterLength lengths[]{ + blink::mojom::AIWriterLength::kShort, + blink::mojom::AIWriterLength::kMedium, + blink::mojom::AIWriterLength::kLong, + }; + for (const auto& tone : tones) { + for (const auto& format : formats) { + for (const auto& length : lengths) { + SCOPED_TRACE(testing::Message() + << tone << " " << format << " " << length); + RunSimpleWriteTest(tone, format, length); + } + } } - AITestUtils::MockModelStreamingResponder mock_responder; - - base::RunLoop run_loop; - EXPECT_CALL(mock_responder, OnStreaming(_, _)) - .WillOnce(testing::Invoke( - [&](const std::string& text, - blink::mojom::ModelStreamingResponderAction action) { - EXPECT_THAT(text, "Result text"); - EXPECT_EQ(action, - blink::mojom::ModelStreamingResponderAction::kReplace); - })); - - EXPECT_CALL(mock_responder, OnCompletion(_)) - .WillOnce(testing::Invoke( - [&](blink::mojom::ModelExecutionContextInfoPtr context_info) { - run_loop.Quit(); - })); - - writer_remote->Write(kInputString, kContextString, - mock_responder.BindNewPipeAndPassRemote()); - run_loop.Run(); } TEST_F(AIWriterTest, WriteError) { @@ -374,19 +379,15 @@ config_params) { auto session = std::make_unique<optimization_guide::MockSession>(); - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })); EXPECT_CALL(*session, ExecuteModel(_, _)) .WillOnce(testing::Invoke( [](const google::protobuf::MessageLite& request_metadata, optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestUserInput(request_metadata, kInputString); + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *GetDefaultExpectedOptions(), kInputString); callback.Run(CreateExecutionErrorResult( optimization_guide::OptimizationGuideModelExecutionError:: FromModelExecutionError( @@ -413,10 +414,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateWriter( mock_create_writer_client.BindNewPipeAndPassRemote(), - blink::mojom::AIWriterCreateOptions::New( - kSharedContextString, blink::mojom::AIWriterTone::kNeutral, - blink::mojom::AIWriterFormat::kPlainText, - blink::mojom::AIWriterLength::kMedium)); + GetDefaultOptions()); run_loop.Run(); } AITestUtils::MockModelStreamingResponder mock_responder; @@ -447,19 +445,15 @@ config_params) { auto session = std::make_unique<optimization_guide::MockSession>(); - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })); EXPECT_CALL(*session, ExecuteModel(_, _)) .WillOnce(testing::Invoke( [](const google::protobuf::MessageLite& request_metadata, optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestUserInput(request_metadata, kInputString); + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *GetDefaultExpectedOptions(), kInputString); callback.Run( CreateExecutionResult("Result ", /*is_complete=*/false)); @@ -485,10 +479,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateWriter( mock_create_writer_client.BindNewPipeAndPassRemote(), - blink::mojom::AIWriterCreateOptions::New( - kSharedContextString, blink::mojom::AIWriterTone::kNeutral, - blink::mojom::AIWriterFormat::kPlainText, - blink::mojom::AIWriterLength::kMedium)); + GetDefaultOptions()); run_loop.Run(); } AITestUtils::MockModelStreamingResponder mock_responder; @@ -532,24 +523,15 @@ config_params) { auto session = std::make_unique<optimization_guide::MockSession>(); - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext( - request_metadata, "test shared context\ntest context 2"); - })); EXPECT_CALL(*session, ExecuteModel(_, _)) .WillOnce(testing::Invoke( [](const google::protobuf::MessageLite& request_metadata, optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestUserInput(request_metadata, kInputString); + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *GetDefaultExpectedOptions(), kInputString); callback.Run(CreateExecutionResult("Result text", /*is_complete=*/true)); })) @@ -558,8 +540,9 @@ optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestUserInput(request_metadata, - "input string 2"); + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, "test context 2", + *GetDefaultExpectedOptions(), "input string 2"); callback.Run(CreateExecutionResult("Result text 2", /*is_complete=*/true)); })); @@ -582,10 +565,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateWriter( mock_create_writer_client.BindNewPipeAndPassRemote(), - blink::mojom::AIWriterCreateOptions::New( - kSharedContextString, blink::mojom::AIWriterTone::kNeutral, - blink::mojom::AIWriterFormat::kPlainText, - blink::mojom::AIWriterLength::kMedium)); + GetDefaultOptions()); run_loop.Run(); } { @@ -648,20 +628,15 @@ SessionConfigParams>& config_params) { auto session = std::make_unique<optimization_guide::MockSession>(); - - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })); EXPECT_CALL(*session, ExecuteModel(_, _)) .WillOnce(testing::Invoke( [&](const google::protobuf::MessageLite& request_metadata, optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestUserInput(request_metadata, kInputString); + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *GetDefaultExpectedOptions(), kInputString); streaming_callback = std::move(callback); run_loop_for_callback.Quit(); })); @@ -684,10 +659,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateWriter( mock_create_writer_client.BindNewPipeAndPassRemote(), - blink::mojom::AIWriterCreateOptions::New( - kSharedContextString, blink::mojom::AIWriterTone::kNeutral, - blink::mojom::AIWriterFormat::kPlainText, - blink::mojom::AIWriterLength::kMedium)); + GetDefaultOptions()); run_loop.Run(); } std::unique_ptr<AITestUtils::MockModelStreamingResponder> mock_responder = @@ -720,20 +692,15 @@ SessionConfigParams>& config_params) { auto session = std::make_unique<optimization_guide::MockSession>(); - - EXPECT_CALL(*session, AddContext(_)) - .WillOnce(testing::Invoke( - [](const google::protobuf::MessageLite& request_metadata) { - CheckComposeRequestContext(request_metadata, - kConcatenatedContextString); - })); EXPECT_CALL(*session, ExecuteModel(_, _)) .WillOnce(testing::Invoke( [&](const google::protobuf::MessageLite& request_metadata, optimization_guide:: OptimizationGuideModelExecutionResultStreamingCallback callback) { - CheckComposeRequestUserInput(request_metadata, kInputString); + AITestUtils::CheckWritingAssistanceApiRequest( + request_metadata, kSharedContextString, kContextString, + *GetDefaultExpectedOptions(), kInputString); streaming_callback = std::move(callback); run_loop_for_callback.Quit(); })); @@ -756,10 +723,7 @@ mojo::Remote<blink::mojom::AIManager> ai_manager = GetAIManagerRemote(); ai_manager->CreateWriter( mock_create_writer_client.BindNewPipeAndPassRemote(), - blink::mojom::AIWriterCreateOptions::New( - kSharedContextString, blink::mojom::AIWriterTone::kNeutral, - blink::mojom::AIWriterFormat::kPlainText, - blink::mojom::AIWriterLength::kMedium)); + GetDefaultOptions()); run_loop.Run(); }
diff --git a/chrome/browser/ash/apps/apk_web_app_service.cc b/chrome/browser/ash/apps/apk_web_app_service.cc index a36a6f0..6d17042 100644 --- a/chrome/browser/ash/apps/apk_web_app_service.cc +++ b/chrome/browser/ash/apps/apk_web_app_service.cc
@@ -221,15 +221,10 @@ if (!web_app_provider) { return std::nullopt; } - // TODO(crbug.com/340952100): Evaluate call sites of FindBestAppWithUrlInScope - // for correctness. + // Which capability check (if any) would fit best here? std::optional<webapps::AppId> app_id = web_app_provider->registrar_unsafe().FindBestAppWithUrlInScope( - url, - { - web_app::proto::InstallState::INSTALLED_WITH_OS_INTEGRATION, - web_app::proto::InstallState::INSTALLED_WITHOUT_OS_INTEGRATION, - }); + url, web_app::WebAppFilter::InstalledInChrome()); if (!app_id) { return std::nullopt; }
diff --git a/chrome/browser/ash/arc/extensions/arc_support_message_host.cc b/chrome/browser/ash/arc/extensions/arc_support_message_host.cc index b81a569b..03205b3 100644 --- a/chrome/browser/ash/arc/extensions/arc_support_message_host.cc +++ b/chrome/browser/ash/arc/extensions/arc_support_message_host.cc
@@ -15,13 +15,6 @@ namespace arc { // static -const char ArcSupportMessageHost::kHostName[] = "com.google.arc_support"; - -// static -const char* const ArcSupportMessageHost::kHostOrigin[] = { - "chrome-extension://cnbgggchhmkkdmeppjobngjoejnihlei/"}; - -// static std::unique_ptr<extensions::NativeMessageHost> ArcSupportMessageHost::Create( content::BrowserContext* browser_context) { return std::unique_ptr<NativeMessageHost>(new ArcSupportMessageHost());
diff --git a/chrome/browser/ash/arc/extensions/arc_support_message_host.h b/chrome/browser/ash/arc/extensions/arc_support_message_host.h index 519b796f..b6f47983 100644 --- a/chrome/browser/ash/arc/extensions/arc_support_message_host.h +++ b/chrome/browser/ash/arc/extensions/arc_support_message_host.h
@@ -32,8 +32,9 @@ ArcSupportMessageHost(const ArcSupportMessageHost&) = delete; ArcSupportMessageHost& operator=(const ArcSupportMessageHost&) = delete; - static const char kHostName[]; - static const char* const kHostOrigin[]; + static constexpr char kHostName[] = "com.google.arc_support"; + static constexpr const char* kHostOrigin[] = { + "chrome-extension://cnbgggchhmkkdmeppjobngjoejnihlei/"}; // Called when the arc_support connects the "port". Returns the // instance of ArcSupportMessageHost.
diff --git a/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc b/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc index 53bc015b..0533f59 100644 --- a/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc +++ b/chrome/browser/ash/arc/session/arc_session_manager_unittest.cc
@@ -409,6 +409,7 @@ void TearDown() override { resourced_client_ = nullptr; + ash::DlcserviceClient::Shutdown(); ash::ResourcedClient::Shutdown(); ArcSessionManagerTestBase::TearDown(); }
diff --git a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc index 7fc9ce9..64a58b93 100644 --- a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc +++ b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc
@@ -36,25 +36,12 @@ namespace guest_os { // static -const char* const VmSKForwardingNativeMessageHost::kHostName = - "com.google.vm_sk_forwarding"; - -// static -const char* const VmSKForwardingNativeMessageHost::kOrigins[] = { - "chrome-extension://lehkgnicackihfeppclgiffgbgbhmbdp/", - "chrome-extension://lcooaekmckohjjnpaaokodoepajbnill/"}; - -// static const char* const VmSKForwardingNativeMessageHost::kHostCreatedByExtensionNotSupportedError = "{\"error\":\"Communication initiated by extension is not " "supported.\"}"; // static -const size_t VmSKForwardingNativeMessageHost::kOriginCount = - std::size(kOrigins); - -// static std::unique_ptr<extensions::NativeMessageHost> VmSKForwardingNativeMessageHost::CreateFromExtension( content::BrowserContext* browser_context) {
diff --git a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.h b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.h index 115e821e..2869ee1 100644 --- a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.h +++ b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.h
@@ -35,10 +35,11 @@ // opened and closes the channel once a response is received. class VmSKForwardingNativeMessageHost : public extensions::NativeMessageHost { public: - static const char* const kHostName; - static const char* const kOrigins[]; + static constexpr char kHostName[] = "com.google.vm_sk_forwarding"; + static constexpr const char* kOrigins[] = { + "chrome-extension://lehkgnicackihfeppclgiffgbgbhmbdp/", + "chrome-extension://lcooaekmckohjjnpaaokodoepajbnill/"}; static const char* const kHostCreatedByExtensionNotSupportedError; - static const size_t kOriginCount; using ResponseCallback = base::OnceCallback<void(const std::string& response)>;
diff --git a/chrome/browser/ash/mahi/web_contents/mahi_web_contents_manager_impl.cc b/chrome/browser/ash/mahi/web_contents/mahi_web_contents_manager_impl.cc index c91116a..d7af805f 100644 --- a/chrome/browser/ash/mahi/web_contents/mahi_web_contents_manager_impl.cc +++ b/chrome/browser/ash/mahi/web_contents/mahi_web_contents_manager_impl.cc
@@ -111,7 +111,7 @@ // Pick the plugin frame host if `contents` is a PDF viewer guest. If using // OOPIF PDF viewer, pick the PDF extension frame host. content::RenderFrameHost* full_page_pdf_embedder_host = - base::FeatureList::IsEnabled(chrome_pdf::features::kPdfOopif) + chrome_pdf::features::IsOopifPdfEnabled() ? pdf_frame_util::FindFullPagePdfExtensionHost(contents) : printing::GetFullPagePlugin(contents); content::RenderFrameHost* pdf_rfh = pdf_frame_util::FindPdfChildFrame( @@ -418,7 +418,7 @@ // If OOPIF PDF is enabled, we need to observe the focused web contents for // a11y changes. Otherwise, we need to observe the inner web contents. content::WebContents* web_contents_to_observe = focused_web_contents_; - if (!base::FeatureList::IsEnabled(chrome_pdf::features::kPdfOopif)) { + if (!chrome_pdf::features::IsOopifPdfEnabled()) { std::vector<content::WebContents*> inner_contents = focused_web_contents_ ? focused_web_contents_->GetInnerWebContents() : std::vector<content::WebContents*>();
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager.cc b/chrome/browser/ash/system_web_apps/system_web_app_manager.cc index 05a886aa..96f1acac 100644 --- a/chrome/browser/ash/system_web_apps/system_web_app_manager.cc +++ b/chrome/browser/ash/system_web_apps/system_web_app_manager.cc
@@ -546,15 +546,9 @@ return std::nullopt; } - // TODO(crbug.com/379827962): Evaluate call sites of FindBestAppWithUrlInScope - // for correctness. std::optional<webapps::AppId> app_id = provider_->registrar_unsafe().FindBestAppWithUrlInScope( - url, - { - web_app::proto::InstallState::INSTALLED_WITH_OS_INTEGRATION, - web_app::proto::InstallState::INSTALLED_WITHOUT_OS_INTEGRATION, - }); + url, web_app::WebAppFilter::InstalledInChrome()); if (!app_id.has_value()) { return std::nullopt; }
diff --git a/chrome/browser/autocomplete/enterprise_search_aggregator_suggestions_service_factory.cc b/chrome/browser/autocomplete/enterprise_search_aggregator_suggestions_service_factory.cc index 68ee786..e615bd5 100644 --- a/chrome/browser/autocomplete/enterprise_search_aggregator_suggestions_service_factory.cc +++ b/chrome/browser/autocomplete/enterprise_search_aggregator_suggestions_service_factory.cc
@@ -9,6 +9,7 @@ #include "base/no_destructor.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_selections.h" +#include "chrome/browser/signin/identity_manager_factory.h" #include "components/omnibox/browser/enterprise_search_aggregator_suggestions_service.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/storage_partition.h" @@ -36,9 +37,11 @@ content::BrowserContext* context) const { Profile* profile = Profile::FromBrowserContext(context); + signin::IdentityManager* identity_manager = + IdentityManagerFactory::GetForProfile(profile); return std::make_unique<EnterpriseSearchAggregatorSuggestionsService>( - profile->GetDefaultStoragePartition() - ->GetURLLoaderFactoryForBrowserProcess()); + identity_manager, profile->GetDefaultStoragePartition() + ->GetURLLoaderFactoryForBrowserProcess()); } EnterpriseSearchAggregatorSuggestionsServiceFactory:: @@ -51,7 +54,9 @@ // TODO(crbug.com/41488885): Check if this service is needed for // Ash Internals. .WithAshInternals(ProfileSelection::kOriginalOnly) - .Build()) {} + .Build()) { + DependsOn(IdentityManagerFactory::GetInstance()); +} EnterpriseSearchAggregatorSuggestionsServiceFactory:: ~EnterpriseSearchAggregatorSuggestionsServiceFactory() = default;
diff --git a/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.cc b/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.cc index ceb0ec0..5d2da15 100644 --- a/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.cc +++ b/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.cc
@@ -21,9 +21,13 @@ namespace { constexpr auto kReservedGroupIdMap = - base::MakeFixedFlatMap<int, omnibox::GroupId>( + base::MakeFixedFlatMap<size_t, omnibox::GroupId>( {{0, omnibox::GROUP_UNSCOPED_EXTENSION_1}, {1, omnibox::GROUP_UNSCOPED_EXTENSION_2}}); +constexpr auto kReservedSectionMap = + base::MakeFixedFlatMap<size_t, omnibox::GroupSection>( + {{0, omnibox::SECTION_UNSCOPED_EXTENSION_1}, + {1, omnibox::SECTION_UNSCOPED_EXTENSION_2}}); } // namespace UnscopedExtensionProviderDelegateImpl::UnscopedExtensionProviderDelegateImpl( @@ -47,8 +51,9 @@ const AutocompleteInput& input, bool minimal_changes, std::set<std::string> unscoped_mode_extension_ids) { - // Reset last suggest matches. - extension_suggest_matches_.clear(); + CHECK(extension_suggest_matches_.empty()); + CHECK(extension_id_to_group_id_map_.empty()); + provider_->set_done(false); for (const std::string& extension_id : unscoped_mode_extension_ids) { @@ -58,10 +63,11 @@ } } -void UnscopedExtensionProviderDelegateImpl::IncrementRequestId() { +void UnscopedExtensionProviderDelegateImpl::Stop(bool clear_cached_results) { current_request_id_++; - // Reset suggestions grouping map any time a new request is made. - ResetSuggestionGroupsMap(); + if (clear_cached_results) { + ClearSuggestions(); + } } void UnscopedExtensionProviderDelegateImpl::OnOmniboxSuggestionsReady( @@ -69,8 +75,8 @@ const std::string& extension_id) { CHECK(suggestions); + // Discard suggestions with a stale request ID. if (suggestions->request_id != current_request_id_) { - // This is an old result, so just ignore. return; } @@ -78,7 +84,7 @@ const TemplateURL* template_url = turl_service->FindTemplateURLForExtension( extension_id, TemplateURL::OMNIBOX_API_EXTENSION); - if (!base::Contains(extension_id_group_map_, extension_id)) { + if (!base::Contains(extension_id_to_group_id_map_, extension_id)) { if (next_available_group_index_ == kReservedGroupIdMap.size()) { // Reached max number of groups that can be assigned to an extension. // Discard suggestions from this extension. @@ -88,11 +94,19 @@ // next available groupId, and give the group the corresponding header for // the extension. If the max number of extensions have been assigned a // header, don't assign headers to further extensions. - omnibox::GroupId current_group = + const omnibox::GroupId current_group_id = kReservedGroupIdMap.at(next_available_group_index_++); - provider_->AddToSuggestionGroupsMap( - current_group, base::UTF16ToUTF8(template_url->keyword())); - extension_id_group_map_[extension_id] = current_group; + extension_id_to_group_id_map_[extension_id] = current_group_id; + + CHECK_LT(next_available_section_index_, kReservedSectionMap.size()); + const omnibox::GroupSection current_section = + kReservedSectionMap.at(next_available_section_index_++); + + omnibox::GroupConfig group; + group.set_section(current_section); + group.set_render_type(omnibox::GroupConfig_RenderType_DEFAULT_VERTICAL); + group.set_header_text(base::UTF16ToUTF8(template_url->keyword())); + provider_->AddToSuggestionGroupsMap(current_group_id, std::move(group)); } int first_relevance = 10000000; @@ -112,13 +126,11 @@ provider_->NotifyListeners(!extension_suggest_matches_.empty()); } -// Input has been accepted, so we're done with this input session. Ensure -// we don't send the OnInputCancelled event, or handle any more stray -// suggestions_ready events. void UnscopedExtensionProviderDelegateImpl::OnOmniboxInputEntered() { - // TODO(378538411): make sure this called when a match created by this class - // is selected. - IncrementRequestId(); + // Input has been accepted, clear the current list of suggestions and ensure + // any suggestions that may be incoming later with a stale request ID are + // discarded. + Stop(/*clear_cached_results=*/true); } AutocompleteMatch @@ -153,12 +165,13 @@ match.contents_class = extensions::StyleTypesToACMatchClassifications(suggestion); - match.suggestion_group_id = extension_id_group_map_[extension_id]; + match.suggestion_group_id = extension_id_to_group_id_map_[extension_id]; return match; } -void UnscopedExtensionProviderDelegateImpl::ResetSuggestionGroupsMap() { - provider_->ClearSuggestionGroupsMap(); - extension_id_group_map_.clear(); +void UnscopedExtensionProviderDelegateImpl::ClearSuggestions() { + extension_suggest_matches_.clear(); + extension_id_to_group_id_map_.clear(); next_available_group_index_ = 0; + next_available_section_index_ = 0; }
diff --git a/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.h b/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.h index 1b6c4e20..c699b52 100644 --- a/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.h +++ b/chrome/browser/autocomplete/unscoped_extension_provider_delegate_impl.h
@@ -47,7 +47,7 @@ void Start(const AutocompleteInput& input, bool minimal_changes, std::set<std::string> unscoped_mode_extension_ids) override; - void IncrementRequestId() override; + void Stop(bool clear_cached_results) override; // OmniboxInputWatcher::Observer: void OnOmniboxInputEntered() override; @@ -63,26 +63,29 @@ int relevance, const std::string& extension_id); - // Resets all state related to suggestion group mapping. - void ResetSuggestionGroupsMap(); + // Clears the current list of cached matches and suggestion group information. + void ClearSuggestions(); - // Identifies the current input state. This is incremented each time the - // autocomplete edit's input changes in any way. It is used to tell - // whether suggest results from the extension are current. + // Incremented each time a new request for suggestions is sent to extensions + // or when the input is accepted. Used to discard any suggestions that may be + // incoming later with a stale request ID. int current_request_id_ = 0; - // TODO(378538411): populate this once the suggestions logic is implemented. - // Saved suggestions that were received from the extension used - // for resetting matches without asking the extension again. + // Current list of matches received from the extensions. Used to update the + // list of matches in the provider. std::vector<AutocompleteMatch> extension_suggest_matches_; // Next group available to be given to a set of extension suggestions. // Possible groups are defined in `kReservedGroupIdMap`. - int next_available_group_index_ = 0; + size_t next_available_group_index_ = 0; + // Next section available to be given to a set of extension suggestions. + // Possible sections are defined in `kReservedSectionMap`. + size_t next_available_section_index_ = 0; - // Maps extension id to a group. Allows extensions to have distinct headers. + // Maps extension IDs to group IDs. Allows suggestions from different + // extensions to have distinct headers. std::unordered_map<extensions::ExtensionId, omnibox::GroupId> - extension_id_group_map_; + extension_id_to_group_id_map_; raw_ptr<Profile> profile_;
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillImageFetcherUtils.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillImageFetcherUtils.java index d2c19dc..7858279 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillImageFetcherUtils.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillImageFetcherUtils.java
@@ -8,9 +8,9 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; import android.graphics.RectF; import androidx.annotation.Px; @@ -35,6 +35,82 @@ } /** + * Adds corner radius to a bitmap. + * + * @param bitmap The input bitmap whose corners are to be rounded. + * @param cornerRadius Corner radius in Px. + * @return A copy of the input bitmap with rounded corners. + */ + static Bitmap roundCorners(Bitmap bitmap, @Px int cornerRadius) { + Bitmap outputBitmap = + Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(outputBitmap); + Path path = new Path(); + RectF rect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()); + path.addRoundRect(rect, cornerRadius, cornerRadius, Path.Direction.CW); + canvas.clipPath(path); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + canvas.drawBitmap(bitmap, 0, 0, paint); + + return outputBitmap; + } + + /** + * Adds a background and center aligns the input bitmap. + * + * <p>The input bitmap dimensions should not be larger than the background dimensions. If it is + * larger, the input bitmap will be returned without any modifications. + * + * @param bitmap The input bitmap to which the background has to be added. + * @param backgroundWidth Background width in Px. + * @param backgroundHeight Background height in Px. + * @param backgroundColor Background color. + * @return A new bitmap which is a composite of the input bitmap placed on a background. + */ + static Bitmap addCenterAlignedBackground( + Bitmap bitmap, @Px int backgroundWidth, @Px int backgroundHeight, int backgroundColor) { + if (bitmap.getWidth() > backgroundWidth || bitmap.getHeight() > backgroundHeight) { + return bitmap; + } + Bitmap outputBitmap = + Bitmap.createBitmap(backgroundWidth, backgroundHeight, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(outputBitmap); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(backgroundColor); + canvas.drawRect(0, 0, backgroundWidth, backgroundHeight, paint); + float left = (backgroundWidth - bitmap.getWidth()) / 2f; + float top = (backgroundHeight - bitmap.getHeight()) / 2f; + canvas.drawBitmap(bitmap, left, top, /* paint= */ null); + + return outputBitmap; + } + + /** + * Adds border to a bitmap. + * + * @param bitmap The input to which a border is to be added. + * @param cornerRadius Corner radius of the bitmap in Px. The border will be added with the same + * corner radius. + * @param borderThickness Border thickness in Px. + * @param borderColor Border color. + * @return A copy of the input bitmap with border. + */ + static Bitmap addBorder( + Bitmap bitmap, @Px int cornerRadius, @Px int borderThickness, int borderColor) { + Bitmap outputBitmap = bitmap.copy(bitmap.getConfig(), /* isMutable= */ true); + Canvas canvas = new Canvas(outputBitmap); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(borderColor); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(borderThickness); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + RectF rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()); + canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint); + + return outputBitmap; + } + + /** * Treats Pix account image as per specifications: * * <p>Resizes the logo to 18dp x 18dp if the logo is of a different dimension, and adds a corner @@ -52,60 +128,39 @@ */ static Bitmap treatPixAccountImage(Bitmap bitmap) { @Px int logoSize = getPixelSize(R.dimen.square_card_icon_side_length); - @Px int logoCornerRadius = getPixelSize(R.dimen.square_card_icon_corner_radius); - @Px int iconWidth = getPixelSize(R.dimen.large_card_icon_width); - @Px int iconHeight = getPixelSize(R.dimen.large_card_icon_height); @Px int iconCornerRadius = getPixelSize(R.dimen.large_card_icon_corner_radius); - @Px int iconBorderWidth = getPixelSize(R.dimen.card_icon_border_width); if (bitmap.getWidth() != logoSize || bitmap.getHeight() != logoSize) { bitmap = Bitmap.createScaledBitmap(bitmap, logoSize, logoSize, /* filter= */ true); } // Round the corners of the square bitmap. - Bitmap squareBitmap = Bitmap.createBitmap(logoSize, logoSize, Bitmap.Config.ARGB_8888); - Canvas squareCanvas = new Canvas(squareBitmap); - Paint squarePaint = new Paint(); - squarePaint.setAntiAlias(true); - RectF squareRectF = new RectF(0, 0, logoSize, logoSize); - squareCanvas.drawRoundRect(squareRectF, logoCornerRadius, logoCornerRadius, squarePaint); - squarePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); - squareCanvas.drawBitmap(bitmap, 0, 0, squarePaint); + Bitmap logoWithRoundCorners = + roundCorners(bitmap, getPixelSize(R.dimen.square_card_icon_corner_radius)); // Create a white background and place the square logo in the center. - Bitmap backgroundBitmap = - Bitmap.createBitmap(iconWidth, iconHeight, Bitmap.Config.ARGB_8888); - Canvas backgroundCanvas = new Canvas(backgroundBitmap); - Paint backgroundPaint = new Paint(); - backgroundPaint.setColor(Color.WHITE); - backgroundPaint.setAntiAlias(true); - backgroundCanvas.drawRect(0, 0, iconWidth, iconHeight, backgroundPaint); - int left = (iconWidth - logoSize) / 2; - int top = (iconHeight - logoSize) / 2; - backgroundCanvas.drawBitmap(squareBitmap, left, top, null); + Bitmap compositeBitmap = + addCenterAlignedBackground( + logoWithRoundCorners, + getPixelSize(R.dimen.large_card_icon_width), + getPixelSize(R.dimen.large_card_icon_height), + Color.WHITE); - // Round the corners of the composite image. - Bitmap bitmapWithEnhancements = - Bitmap.createBitmap(iconWidth, iconHeight, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmapWithEnhancements); - Paint paint = new Paint(); - paint.setAntiAlias(true); - Rect rect = new Rect(0, 0, iconWidth, iconHeight); - RectF rectF = new RectF(rect); - canvas.drawRoundRect(rectF, iconCornerRadius, iconCornerRadius, paint); - paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); - canvas.drawBitmap(backgroundBitmap, rect, rect, paint); + // Round the corners of the composite bitmap. + Bitmap compositeBitmapWithRoundCorners = roundCorners(compositeBitmap, iconCornerRadius); // Add the grey border. // TODO(crbug.com/389947287): Verify the border color. int greyColor = ContextCompat.getColor( ContextUtils.getApplicationContext(), R.color.baseline_neutral_90); - paint.setColor(greyColor); - paint.setStyle(Paint.Style.STROKE); - paint.setStrokeWidth(iconBorderWidth); - canvas.drawRoundRect(rectF, iconCornerRadius, iconCornerRadius, paint); + Bitmap compositeBitmapWithRoundCornersAndGreyBorder = + addBorder( + compositeBitmapWithRoundCorners, + iconCornerRadius, + getPixelSize(R.dimen.card_icon_border_width), + greyColor); - return bitmapWithEnhancements; + return compositeBitmapWithRoundCornersAndGreyBorder; } }
diff --git a/chrome/browser/auxiliary_search/java/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonor.java b/chrome/browser/auxiliary_search/java/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonor.java index e09d80b..b4483bad 100644 --- a/chrome/browser/auxiliary_search/java/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonor.java +++ b/chrome/browser/auxiliary_search/java/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonor.java
@@ -39,6 +39,7 @@ import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.ResettersForTesting; +import org.chromium.base.shared_preferences.SharedPreferencesManager; import org.chromium.base.task.AsyncTask; import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; @@ -82,6 +83,7 @@ private Callback<Boolean> mPendingCallback; private boolean mSharedTabsWithOsState; private Boolean mIsDeviceCompatible; + private boolean mIsCreatedSessionAndInitForTesting; /** Static class that implements the initialization-on-demand holder idiom. */ private static class LazyHolder { @@ -99,7 +101,9 @@ mSkipSchemaCheck = AuxiliarySearchUtils.SKIP_SCHEMA_CHECK.getValue(); mSharedTabsWithOsState = AuxiliarySearchUtils.isShareTabsWithOsEnabled(); - if (mSharedTabsWithOsState) { + boolean shouldInit = mSharedTabsWithOsState || !isShareTabsWithOsEnabledKeyExist(); + if (shouldInit) { + mIsCreatedSessionAndInitForTesting = true; createSessionAndInit(); } } @@ -671,6 +675,12 @@ UI_THREAD_EXECUTOR); } + @VisibleForTesting + boolean isShareTabsWithOsEnabledKeyExist() { + SharedPreferencesManager prefsManager = ChromeSharedPreferences.getInstance(); + return prefsManager.contains(ChromePreferenceKeys.SHARING_TABS_WITH_OS); + } + public boolean getIsSchemaSetForTesting() { return mIsSchemaSet; } @@ -714,4 +724,12 @@ mAppSearchSession = sessionForTesting; ResettersForTesting.register(() -> mAppSearchSession = oldSession); } + + public static AuxiliarySearchDonor createDonorForTesting() { + return new AuxiliarySearchDonor(); + } + + public boolean getIsCreatedSessionAndInitForTesting() { + return mIsCreatedSessionAndInitForTesting; + } }
diff --git a/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorUnitTest.java b/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorUnitTest.java index 938f143..088cd032 100644 --- a/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorUnitTest.java +++ b/chrome/browser/auxiliary_search/junit/src/org/chromium/chrome/browser/auxiliary_search/AuxiliarySearchDonorUnitTest.java
@@ -72,7 +72,7 @@ assertTrue(AuxiliarySearchUtils.isShareTabsWithOsEnabled()); AuxiliarySearchDonor.setSkipInitializationForTesting(true); - mAuxiliarySearchDonor = AuxiliarySearchDonor.getInstance(); + mAuxiliarySearchDonor = AuxiliarySearchDonor.createDonorForTesting(); try { when(mAppSearchSession.get()).thenReturn(mSession); mAuxiliarySearchDonor.setAppSearchSessionForTesting(mAppSearchSession); @@ -87,6 +87,17 @@ // #createSessionAndInit() has been called in AuxiliarySearchDonor's constructor. // Verifies that calling createSessionAndInit() again will early exit. assertFalse(mAuxiliarySearchDonor.createSessionAndInit()); + assertTrue(mAuxiliarySearchDonor.getIsCreatedSessionAndInitForTesting()); + } + + @Test + @SmallTest + public void testCreateSessionAndInit_DefaultDisabled() { + when(mHooks.isSettingDefaultEnabledByOs()).thenReturn(false); + assertFalse(AuxiliarySearchControllerFactory.getInstance().isSettingDefaultEnabledByOs()); + + mAuxiliarySearchDonor = AuxiliarySearchDonor.createDonorForTesting(); + assertTrue(mAuxiliarySearchDonor.getIsCreatedSessionAndInitForTesting()); } @Test @@ -295,6 +306,21 @@ verify(mCallback).onResult(eq(true)); } + @Test + @SmallTest + public void testIsShareTabsWithOsEnabledKeyExist() { + SharedPreferencesManager prefsManager = ChromeSharedPreferences.getInstance(); + prefsManager.removeKey(ChromePreferenceKeys.SHARING_TABS_WITH_OS); + + assertFalse(mAuxiliarySearchDonor.isShareTabsWithOsEnabledKeyExist()); + + prefsManager.writeBoolean(ChromePreferenceKeys.SHARING_TABS_WITH_OS, true); + assertTrue(mAuxiliarySearchDonor.isShareTabsWithOsEnabledKeyExist()); + + prefsManager.writeBoolean(ChromePreferenceKeys.SHARING_TABS_WITH_OS, false); + assertTrue(mAuxiliarySearchDonor.isShareTabsWithOsEnabledKeyExist()); + } + private SearchResult createSearchResult(int applicationType) { GlobalSearchApplicationInfo appInfo = new GlobalSearchApplicationInfo.Builder("namespace", "id", applicationType)
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc index 6ec4745..e11b774 100644 --- a/chrome/browser/background/background_mode_manager.cc +++ b/chrome/browser/background/background_mode_manager.cc
@@ -988,10 +988,14 @@ } void BackgroundModeManager::RemoveStatusTrayIcon() { - if (status_icon_) - status_tray_->RemoveStatusIcon(status_icon_); - status_icon_ = nullptr; - context_menu_ = nullptr; + if (status_icon_) { + std::unique_ptr<StatusIcon> removed_icon = + status_tray_->RemoveStatusIcon(status_icon_); + context_menu_ = nullptr; + status_icon_ = nullptr; + removed_icon.reset(); + } + status_tray_ = nullptr; } BackgroundModeManager::BackgroundModeData*
diff --git a/chrome/browser/background/background_mode_manager.h b/chrome/browser/background/background_mode_manager.h index ad9b08d..b78f5c7 100644 --- a/chrome/browser/background/background_mode_manager.h +++ b/chrome/browser/background/background_mode_manager.h
@@ -434,14 +434,14 @@ // Reference to our status tray. If null, the platform doesn't support status // icons. - raw_ptr<StatusTray, DanglingUntriaged> status_tray_ = nullptr; + raw_ptr<StatusTray> status_tray_ = nullptr; // Reference to our status icon (if any) - owned by the StatusTray. - raw_ptr<StatusIcon, DanglingUntriaged> status_icon_ = nullptr; + raw_ptr<StatusIcon> status_icon_ = nullptr; // Reference to our status icon's context menu (if any) - owned by the // status_icon_. - raw_ptr<StatusIconMenuModel, DanglingUntriaged> context_menu_ = nullptr; + raw_ptr<StatusIconMenuModel> context_menu_ = nullptr; // Set to true when we are running in background mode. Allows us to track our // current background state so we can take the appropriate action when the
diff --git a/chrome/browser/background/background_mode_manager_unittest.cc b/chrome/browser/background/background_mode_manager_unittest.cc index b76fc50..7d2afac 100644 --- a/chrome/browser/background/background_mode_manager_unittest.cc +++ b/chrome/browser/background/background_mode_manager_unittest.cc
@@ -259,7 +259,6 @@ void TearDown() override { // Clean up the status icon. If this is not done before profile deletes, // the context menu updates will DCHECK with the now deleted profiles. - delete manager_->status_icon_; manager_->status_icon_ = nullptr; // We're getting ready to shutdown the message loop. Clear everything out! @@ -770,7 +769,9 @@ service2->AddExtension(build_regular_extension().get()); service2->AddExtension(build_regular_extension_with_options().get()); - manager_->status_icon_ = new TestStatusIcon(); + std::unique_ptr<StatusIcon> test_status_icon = + std::make_unique<TestStatusIcon>(); + manager_->status_icon_ = test_status_icon.get(); manager_->UpdateStatusTrayIconContextMenu(); StatusIconMenuModel* context_menu = manager_->context_menu_; EXPECT_TRUE(context_menu); @@ -846,6 +847,9 @@ EXPECT_TRUE(IsCommandEnabled(context_menu, 6)); // P2 - RE EXPECT_TRUE(IsCommandEnabled(context_menu, 7)); // P2 - REO EXPECT_TRUE(IsCommandEnabled(context_menu, 8)); // P2 + + manager_->context_menu_ = nullptr; + manager_->status_icon_ = nullptr; } TEST_F(BackgroundModeManagerWithExtensionsTest, BalloonDisplay) { @@ -891,7 +895,9 @@ run_loop.Run(); ASSERT_TRUE(system->is_ready()); - manager_->status_icon_ = new TestStatusIcon(); + std::unique_ptr<StatusIcon> test_status_icon = + std::make_unique<TestStatusIcon>(); + manager_->status_icon_ = test_status_icon.get(); manager_->UpdateStatusTrayIconContextMenu(); // Adding a background extension should show the balloon. @@ -921,6 +927,9 @@ // show the balloon. service->AddExtension(upgraded_no_bg_ext_has_bg.get()); EXPECT_TRUE(manager_->HasShownBalloon()); + + manager_->context_menu_ = nullptr; + manager_->status_icon_ = nullptr; } TEST_F(BackgroundModeManagerTest, TransientBackgroundApp) {
diff --git a/chrome/browser/bookmarks/bookmark_html_writer.cc b/chrome/browser/bookmarks/bookmark_html_writer.cc index 3dcdf595..ab15626 100644 --- a/chrome/browser/bookmarks/bookmark_html_writer.cc +++ b/chrome/browser/bookmarks/bookmark_html_writer.cc
@@ -249,9 +249,7 @@ } // Increments the indent. - void IncrementIndent() { - indent_.resize(indent_.size() + kIndentSize, ' '); - } + void IncrementIndent() { indent_.resize(indent_.size() + kIndentSize, ' '); } // Decrements the indent. void DecrementIndent() { @@ -304,9 +302,7 @@ } // Indents the current line. - bool WriteIndent() { - return Write(indent_); - } + bool WriteIndent() { return Write(indent_); } // Converts a time string written to the JSON codec into a time_t string // (used by bookmarks.html) and writes it. @@ -377,18 +373,15 @@ return false; } if (folder_type == BookmarkNode::BOOKMARK_BAR) { - if (!Write(kBookmarkBar)) + if (!Write(kBookmarkBar)) { return false; + } title = l10n_util::GetStringUTF8(IDS_BOOKMARK_BAR_FOLDER_NAME); } else if (!Write(kFolderAttributeEnd)) { return false; } - if (!Write(title, CONTENT) || - !Write(kFolderEnd) || - !Write(kNewline) || - !WriteIndent() || - !Write(kFolderChildren) || - !Write(kNewline)) { + if (!Write(title, CONTENT) || !Write(kFolderEnd) || !Write(kNewline) || + !WriteIndent() || !Write(kFolderChildren) || !Write(kNewline)) { return false; } IncrementIndent(); @@ -407,9 +400,7 @@ folder_type != BookmarkNode::MOBILE) { // Close out the folder. DecrementIndent(); - if (!WriteIndent() || - !Write(kFolderChildrenEnd) || - !Write(kNewline)) { + if (!WriteIndent() || !Write(kFolderChildrenEnd) || !Write(kNewline)) { return false; } } @@ -443,9 +434,7 @@ Profile* profile, const base::FilePath& path, BookmarksExportObserver* observer) - : profile_(profile), - path_(path), - observer_(observer) { + : profile_(profile), path_(path), observer_(observer) { DCHECK(!profile->IsOffTheRecord()); favicons_map_ = std::make_unique<URLFaviconMap>(); } @@ -457,20 +446,23 @@ BookmarkModelFactory::GetForBrowserContext(profile_)->other_node()); ExtractUrls( BookmarkModelFactory::GetForBrowserContext(profile_)->mobile_node()); - if (!bookmark_urls_.empty()) + if (!bookmark_urls_.empty()) { FetchNextFavicon(); - else + } else { ExecuteWriter(); + } } void BookmarkFaviconFetcher::ExtractUrls(const BookmarkNode* node) { if (node->is_url()) { std::string url = node->url().spec(); - if (!url.empty()) + if (!url.empty()) { bookmark_urls_.push_back(url); + } } else { - for (const auto& child : node->children()) + for (const auto& child : node->children()) { ExtractUrls(child.get()); + } } } @@ -519,8 +511,7 @@ bookmark_urls_.pop_front(); } if (bitmap_result.is_valid() && !url.is_empty()) { - favicons_map_->insert( - make_pair(url.spec(), bitmap_result.bitmap_data)); + favicons_map_->insert(make_pair(url.spec(), bitmap_result.bitmap_data)); } if (FetchNextFavicon()) { @@ -535,8 +526,9 @@ const base::FilePath& path, BookmarksExportObserver* observer) { // We allow only one concurrent bookmark export operation per profile. - if (profile->GetUserData(kBookmarkFaviconFetcherKey)) + if (profile->GetUserData(kBookmarkFaviconFetcherKey)) { return; + } auto fetcher = std::make_unique<BookmarkFaviconFetcher>(profile, path, observer);
diff --git a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc b/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc index 1b310274..797f09a 100644 --- a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc +++ b/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
@@ -75,17 +75,19 @@ std::u16string BookmarkEntryToString(const ImportedBookmarkEntry& entry) { std::u16string result; result.append(u"on_toolbar="); - if (entry.in_toolbar) + if (entry.in_toolbar) { result.append(u"true"); - else + } else { result.append(u"false"); + } result.append(u" url=" + base::UTF8ToUTF16(entry.url.spec())); result.append(u" path="); for (size_t i = 0; i < entry.path.size(); ++i) { - if (i != 0) + if (i != 0) { result.append(u"/"); + } result.append(entry.path[i]); } @@ -112,8 +114,9 @@ entry.path.push_back(f1); if (!f2.empty()) { entry.path.push_back(f2); - if (!f3.empty()) + if (!f3.empty()) { entry.path.push_back(f3); + } } } entry.title = title; @@ -129,8 +132,8 @@ const std::u16string& f1, const std::u16string& f2, const std::u16string& f3) { - EXPECT_EQ(BookmarkValuesToString(on_toolbar, url, title, creation_time, - f1, f2, f3), + EXPECT_EQ(BookmarkValuesToString(on_toolbar, url, title, creation_time, f1, + f2, f3), BookmarkEntryToString(entry)); } @@ -218,8 +221,8 @@ base::Time t2(t1 + base::Hours(1)); base::Time t3(t1 + base::Hours(1)); base::Time t4(t1 + base::Hours(1)); - const BookmarkNode* f1 = model->AddFolder( - model->bookmark_bar_node(), 0, f1_title); + const BookmarkNode* f1 = + model->AddFolder(model->bookmark_bar_node(), 0, f1_title); model->AddURL(f1, 0, url1_title, url1, nullptr, t1); HistoryServiceFactory::GetForProfile(profile.get(), ServiceAccessType::EXPLICIT_ACCESS)
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index dd324aa9..fe7816cc 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2430,15 +2430,9 @@ Profile::FromBrowserContext(web_contents->GetBrowserContext()); auto& registrar = web_app::WebAppProvider::GetForWebApps(profile)->registrar_unsafe(); - // TODO(crbug.com/379916273): Evaluate call sites of FindBestAppWithUrlInScope - // for correctness. std::vector<webapps::AppId> app_ids_for_origin = registrar.FindAllAppsNestedInUrl( - app_origin.GetURL(), - { - web_app::proto::InstallState::INSTALLED_WITH_OS_INTEGRATION, - web_app::proto::InstallState::INSTALLED_WITHOUT_OS_INTEGRATION, - }); + app_origin.GetURL(), web_app::WebAppFilter::InstalledInChrome()); if (app_ids_for_origin.empty()) { return blink::ParsedPermissionsPolicy(); }
diff --git a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationControllerDelegateImpl.java b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationControllerDelegateImpl.java index 1a6bcf4..8716ecf 100644 --- a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationControllerDelegateImpl.java +++ b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationControllerDelegateImpl.java
@@ -228,8 +228,9 @@ */ @CalledByNative void promoteTabGroup(String collaborationId, long resultCallback) { + mDataSharingTabManager.promoteTabGroup(collaborationId); CollaborationControllerDelegateImplJni.get() - .runResultCallback(Outcome.FAILURE, resultCallback); + .runResultCallback(Outcome.SUCCESS, resultCallback); } /** Focus and show the current flow screen. */
diff --git a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationControllerDelegateImplUnitTest.java b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationControllerDelegateImplUnitTest.java index bb7f7c0..8594565 100644 --- a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationControllerDelegateImplUnitTest.java +++ b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationControllerDelegateImplUnitTest.java
@@ -180,4 +180,16 @@ // Exit callback should be ran. verify(mCollaborationControllerDelegateImplNativeMock).runExitCallback(eq(exitCallback)); } + + @Test + public void testPromoteTabGroup() { + createDelegate(FlowType.JOIN); + long resultCallback = 1; + String collaborationId = "collaboration"; + + mCollaborationControllerDelegateImpl.promoteTabGroup(collaborationId, resultCallback); + verify(mDataSharingTabManager).promoteTabGroup(collaborationId); + verify(mCollaborationControllerDelegateImplNativeMock) + .runResultCallback(eq(Outcome.SUCCESS), eq(resultCallback)); + } }
diff --git a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediator.java b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediator.java index ba35d39..dcc9f28 100644 --- a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediator.java +++ b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetMediator.java
@@ -228,7 +228,7 @@ void destroyWebContents() { if (mWebContentsObserver != null) { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; } if (mWebContents != null) {
diff --git a/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediator.java b/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediator.java index 3e8822f7d..c1e5c53 100644 --- a/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediator.java +++ b/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediator.java
@@ -197,6 +197,7 @@ mSharedPreferences.unregisterOnSharedPreferenceChangeListener( mPriceAnnotationsPrefListener); mTabModelSelector.removeObserver(this); + mFaviconHelper.destroy(); } int getModuleType() {
diff --git a/chrome/browser/content_settings/page_specific_content_settings_delegate.cc b/chrome/browser/content_settings/page_specific_content_settings_delegate.cc index b0a5dd53..01ddb8d 100644 --- a/chrome/browser/content_settings/page_specific_content_settings_delegate.cc +++ b/chrome/browser/content_settings/page_specific_content_settings_delegate.cc
@@ -317,15 +317,6 @@ return false; } -bool PageSpecificContentSettingsDelegate::IsPiPWindow( - content::WebContents* web_contents) { - DCHECK(web_contents); - content::WebContents* child_web_contents = - PictureInPictureWindowManager::GetInstance()->GetChildWebContents(); - - return child_web_contents == web_contents; -} - void PageSpecificContentSettingsDelegate::PrimaryPageChanged( content::Page& page) { ClearPendingProtocolHandler();
diff --git a/chrome/browser/content_settings/page_specific_content_settings_delegate.h b/chrome/browser/content_settings/page_specific_content_settings_delegate.h index 674e6ba..3d15a5a 100644 --- a/chrome/browser/content_settings/page_specific_content_settings_delegate.h +++ b/chrome/browser/content_settings/page_specific_content_settings_delegate.h
@@ -93,7 +93,6 @@ bool IsBlockedOnSystemLevel(ContentSettingsType type) override; bool IsFrameAllowlistedForJavaScript( content::RenderFrameHost* render_frame_host) override; - bool IsPiPWindow(content::WebContents* web_contents) override; // content::WebContentsObserver: void PrimaryPageChanged(content::Page& page) override;
diff --git a/chrome/browser/contextual_cueing/BUILD.gn b/chrome/browser/contextual_cueing/BUILD.gn index 3e775cc..6553b039 100644 --- a/chrome/browser/contextual_cueing/BUILD.gn +++ b/chrome/browser/contextual_cueing/BUILD.gn
@@ -2,22 +2,35 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//chrome/common/features.gni") + source_set("contextual_cueing") { sources = [ - "contextual_cueing_features.cc", "contextual_cueing_features.h", - "contextual_cueing_helper.cc", "contextual_cueing_helper.h", ] public_deps = [ "//base", "//content/public/browser", ] +} + +source_set("impl") { + sources = [ + "contextual_cueing_features.cc", + "contextual_cueing_helper.cc", + ] deps = [ + "//chrome/browser/contextual_cueing", "//chrome/browser/optimization_guide", "//chrome/browser/profiles:profile", + "//chrome/browser/ui", + "//chrome/browser/ui/browser_window", "//components/optimization_guide/core:core", "//components/optimization_guide/proto:optimization_guide_proto", "//url", ] + if (enable_glic) { + deps += [ "//chrome/browser/glic:enabling" ] + } }
diff --git a/chrome/browser/contextual_cueing/contextual_cueing_helper.cc b/chrome/browser/contextual_cueing/contextual_cueing_helper.cc index 8b942a3..024f0b2 100644 --- a/chrome/browser/contextual_cueing/contextual_cueing_helper.cc +++ b/chrome/browser/contextual_cueing/contextual_cueing_helper.cc
@@ -9,7 +9,12 @@ #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 "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_window/public/browser_window_features.h" +#include "chrome/browser/ui/tabs/glic_nudge_controller.h" #include "components/optimization_guide/core/model_execution/model_execution_features_controller.h" +#include "components/optimization_guide/core/optimization_guide_decider.h" #include "components/optimization_guide/core/optimization_metadata.h" #include "components/optimization_guide/proto/icon_view_metadata.pb.h" #include "content/public/browser/navigation_handle.h" @@ -17,6 +22,10 @@ #include "url/gurl.h" #include "url/origin.h" +#if BUILDFLAG(ENABLE_GLIC) +#include "chrome/browser/glic/glic_enabling.h" +#endif + namespace contextual_cueing { ContextualCueingHelper::ContextualCueingHelper( @@ -33,40 +42,59 @@ // content::WebContentsObserver void ContextualCueingHelper::DocumentOnLoadCompletedInPrimaryMainFrame() { + last_navigation_cue_label_.clear(); + Browser* browser = chrome::FindBrowserWithTab(web_contents()); + if (!browser) { + return; + } + auto* glic_nudge_controller = + browser->browser_window_features()->glic_nudge_controller(); + if (!glic_nudge_controller) { + return; + } + optimization_guide::OptimizationMetadata metadata; auto decision = optimization_guide_keyed_service_->CanApplyOptimization( web_contents()->GetLastCommittedURL(), optimization_guide::proto::OPTIMIZATION_GUIDE_ICON_VIEW, &metadata); - if (decision != optimization_guide::OptimizationGuideDecision::kTrue || - metadata.empty()) { - return; + if (decision == optimization_guide::OptimizationGuideDecision::kTrue && + !metadata.empty()) { + auto parsed = metadata.ParsedMetadata< + optimization_guide::proto::OptimizationGuideIconViewMetadata>(); + if (parsed->has_cue_label()) { + last_navigation_cue_label_ = parsed->cue_label(); + } } - auto parsed = metadata.ParsedMetadata< - optimization_guide::proto::OptimizationGuideIconViewMetadata>(); - // TODO(crbug.com/388305688): trigger cueing UI. + glic_nudge_controller->UpdateNudgeLabel(web_contents(), + last_navigation_cue_label_); } // static -std::unique_ptr<ContextualCueingHelper> -ContextualCueingHelper::MaybeCreateForWebContents( +void ContextualCueingHelper::MaybeCreateForWebContents( content::WebContents* web_contents) { if (!base::FeatureList::IsEnabled(contextual_cueing::kContextualCueing)) { - return nullptr; + return; } +#if BUILDFLAG(ENABLE_GLIC) Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); - auto* optimization_guide_keyed_service_ = - OptimizationGuideKeyedServiceFactory::GetForProfile(profile); - if (!optimization_guide_keyed_service_ || - !optimization_guide_keyed_service_->GetModelExecutionFeaturesController() - ->ShouldModelExecutionBeAllowedForUser()) { - return nullptr; + if (!GlicEnabling::IsProfileEligible(profile)) { + return; } - return base::WrapUnique<ContextualCueingHelper>(new ContextualCueingHelper( - web_contents, optimization_guide_keyed_service_)); + auto* optimization_guide_keyed_service = + OptimizationGuideKeyedServiceFactory::GetForProfile(profile); + if (!optimization_guide_keyed_service || + !optimization_guide_keyed_service->GetModelExecutionFeaturesController() + ->ShouldModelExecutionBeAllowedForUser()) { + return; + } + + ContextualCueingHelper::CreateForWebContents( + web_contents, optimization_guide_keyed_service); +#endif // BUILDFLAG(ENABLE_GLIC) } WEB_CONTENTS_USER_DATA_KEY_IMPL(ContextualCueingHelper);
diff --git a/chrome/browser/contextual_cueing/contextual_cueing_helper.h b/chrome/browser/contextual_cueing/contextual_cueing_helper.h index 3d83040e..6616261 100644 --- a/chrome/browser/contextual_cueing/contextual_cueing_helper.h +++ b/chrome/browser/contextual_cueing/contextual_cueing_helper.h
@@ -19,8 +19,7 @@ public: // Creates ContextualCueingHelper and attaches it the `web_contents` if // contextual cueing is enabled. - [[nodiscard]] static std::unique_ptr<ContextualCueingHelper> - MaybeCreateForWebContents(content::WebContents* web_contents); + static void MaybeCreateForWebContents(content::WebContents* web_contents); ContextualCueingHelper(const ContextualCueingHelper&) = delete; ContextualCueingHelper& operator=(const ContextualCueingHelper&) = delete; @@ -29,6 +28,10 @@ // content::WebContentsObserver void DocumentOnLoadCompletedInPrimaryMainFrame() override; + const std::string& last_navigation_cue_label() const { + return last_navigation_cue_label_; + } + private: ContextualCueingHelper(content::WebContents* contents, OptimizationGuideKeyedService* ogks); @@ -36,6 +39,9 @@ raw_ptr<OptimizationGuideKeyedService> optimization_guide_keyed_service_ = nullptr; + // Holds the cue label for the last navigation in `this`. + std::string last_navigation_cue_label_; + friend WebContentsUserData<ContextualCueingHelper>; WEB_CONTENTS_USER_DATA_KEY_DECL(); };
diff --git a/chrome/browser/contextual_cueing/contextual_cueing_helper_interactive_uitest.cc b/chrome/browser/contextual_cueing/contextual_cueing_helper_interactive_uitest.cc new file mode 100644 index 0000000..dde800b0 --- /dev/null +++ b/chrome/browser/contextual_cueing/contextual_cueing_helper_interactive_uitest.cc
@@ -0,0 +1,162 @@ +// 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/test/scoped_feature_list.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/contextual_cueing/contextual_cueing_features.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 "chrome/browser/signin/identity_test_environment_profile_adaptor.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_tabstrip.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/browser_window/public/browser_window_features.h" +#include "chrome/browser/ui/tabs/glic_nudge_controller.h" +#include "chrome/browser/ui/tabs/glic_nudge_observer.h" +#include "chrome/common/chrome_features.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/interactive_test_utils.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/optimization_guide/core/optimization_metadata.h" +#include "components/optimization_guide/proto/icon_view_metadata.pb.h" +#include "components/signin/public/identity_manager/account_capabilities_test_mutator.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" + +#if BUILDFLAG(ENABLE_GLIC) + +class FakeGlicNudgeObserver : public GlicNudgeObserver { + public: + void OnTriggerGlicNudgeUI(std::string label) override { + last_nudge_label_ = label; + } + std::string last_nudge_label_; +}; + +class ContextualCueingHelperBrowserTest : public InProcessBrowserTest { + public: + ContextualCueingHelperBrowserTest() { + scoped_feature_list_.InitWithFeatures( + {features::kGlic, features::kTabstripComboButton, + contextual_cueing::kContextualCueing}, + {}); + } + + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + identity_test_env_adaptor_ = + std::make_unique<IdentityTestEnvironmentProfileAdaptor>( + browser()->profile()); + } + + void SetUpInProcessBrowserTestFixture() override { + create_services_subscription_ = + BrowserContextDependencyManager::GetInstance() + ->RegisterCreateServicesCallbackForTesting( + base::BindRepeating(&ContextualCueingHelperBrowserTest:: + OnWillCreateBrowserContextServices, + base::Unretained(this))); + } + + void SetUpEnabledHints() { + optimization_guide::proto::OptimizationGuideIconViewMetadata + icon_view_metadata; + icon_view_metadata.set_cue_label("test label"); + optimization_guide::OptimizationMetadata metadata; + metadata.SetAnyMetadataForTesting(icon_view_metadata); + OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile()) + ->AddHintForTesting( + GURL("https://enabled.com/"), + optimization_guide::proto::OPTIMIZATION_GUIDE_ICON_VIEW, metadata); + } + + void EnableSignIn() { + auto account_info = + identity_test_env_adaptor_->identity_test_env() + ->MakePrimaryAccountAvailable("user@gmail.com", + signin::ConsentLevel::kSignin); + AccountCapabilitiesTestMutator mutator(&account_info.capabilities); + mutator.set_can_use_model_execution_features(true); + identity_test_env_adaptor_->identity_test_env() + ->UpdateAccountInfoForAccount(account_info); + } + + tabs::GlicNudgeController* glic_nudge_controller() { + return browser()->browser_window_features()->glic_nudge_controller(); + } + + private: + void OnWillCreateBrowserContextServices(content::BrowserContext* context) { + IdentityTestEnvironmentProfileAdaptor:: + SetIdentityTestEnvironmentFactoriesOnBrowserContext(context); + } + + base::test::ScopedFeatureList scoped_feature_list_; + + // Identity test support. + std::unique_ptr<IdentityTestEnvironmentProfileAdaptor> + identity_test_env_adaptor_; + base::CallbackListSubscription create_services_subscription_; +}; + +IN_PROC_BROWSER_TEST_F(ContextualCueingHelperBrowserTest, + TestCueLabelDisplayed) { + EnableSignIn(); + SetUpEnabledHints(); + + FakeGlicNudgeObserver nudge_observer; + glic_nudge_controller()->AddObserver(&nudge_observer); + + ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL("https://enabled.com/"), + WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP)); + EXPECT_EQ("test label", nudge_observer.last_nudge_label_); +} + +IN_PROC_BROWSER_TEST_F(ContextualCueingHelperBrowserTest, + TestCueLabelNotDisplayed) { + EnableSignIn(); + SetUpEnabledHints(); + + FakeGlicNudgeObserver nudge_observer; + glic_nudge_controller()->AddObserver(&nudge_observer); + + ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL("https://disabled.com/"), + WindowOpenDisposition::CURRENT_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP)); + EXPECT_TRUE(nudge_observer.last_nudge_label_.empty()); +} + +IN_PROC_BROWSER_TEST_F(ContextualCueingHelperBrowserTest, + TestCueLabelDisplayedForActiveTab) { + EnableSignIn(); + SetUpEnabledHints(); + + FakeGlicNudgeObserver nudge_observer; + glic_nudge_controller()->AddObserver(&nudge_observer); + + ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL("https://enabled.com/"), + WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP)); + EXPECT_EQ("test label", nudge_observer.last_nudge_label_); + + ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL("https://disabled.com/"), + WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP)); + EXPECT_TRUE(nudge_observer.last_nudge_label_.empty()); + + browser()->tab_strip_model()->ActivateTabAt(1); + EXPECT_EQ("test label", nudge_observer.last_nudge_label_); + + browser()->tab_strip_model()->ActivateTabAt(2); + EXPECT_TRUE(nudge_observer.last_nudge_label_.empty()); +} + +#endif
diff --git a/chrome/browser/contextual_cueing/contextual_cueing_helper_unittest.cc b/chrome/browser/contextual_cueing/contextual_cueing_helper_unittest.cc index 31270af..0f55f8254 100644 --- a/chrome/browser/contextual_cueing/contextual_cueing_helper_unittest.cc +++ b/chrome/browser/contextual_cueing/contextual_cueing_helper_unittest.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" +#include "chrome/common/chrome_features.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "components/component_updater/pref_names.h" #include "components/optimization_guide/core/model_execution/model_execution_prefs.h" @@ -47,8 +48,10 @@ class ContextualCueingHelperTest : public ChromeRenderViewHostTestHarness { public: ContextualCueingHelperTest() { - scoped_feature_list_.InitAndEnableFeature( - contextual_cueing::kContextualCueing); + scoped_feature_list_.InitWithFeatures( + {features::kGlic, features::kTabstripComboButton, + contextual_cueing::kContextualCueing}, + {}); } void SetUp() override { @@ -72,11 +75,6 @@ DogfoodStatus::NON_DOGFOOD)); } - void TearDown() override { - contextual_cueing_helper_.reset(); - ChromeRenderViewHostTestHarness::TearDown(); - } - void EnableSignIn() { auto account_info = identity_test_env_.MakePrimaryAccountAvailable( "test_email", signin::ConsentLevel::kSignin); @@ -101,9 +99,6 @@ base::BindRepeating(&CreateOptimizationGuideKeyedService)}}; } - protected: - std::unique_ptr<ContextualCueingHelper> contextual_cueing_helper_; - private: signin::IdentityTestEnvironment identity_test_env_; std::unique_ptr<TestingPrefServiceSimple> pref_service_; @@ -111,24 +106,30 @@ base::test::ScopedFeatureList scoped_feature_list_; }; +#if BUILDFLAG(ENABLE_GLIC) + TEST_F(ContextualCueingHelperTest, NullTabHelperWithoutSignin) { - contextual_cueing_helper_ = - ContextualCueingHelper::MaybeCreateForWebContents(web_contents()); - EXPECT_FALSE(contextual_cueing_helper_); + ContextualCueingHelper::MaybeCreateForWebContents(web_contents()); + auto* contextual_cueing_helper = + ContextualCueingHelper::FromWebContents(web_contents()); + EXPECT_FALSE(contextual_cueing_helper); } TEST_F(ContextualCueingHelperTest, NullTabHelperIfWithoutCapability) { EnableSignInWithoutCapability(); - contextual_cueing_helper_ = - ContextualCueingHelper::MaybeCreateForWebContents(web_contents()); - EXPECT_FALSE(contextual_cueing_helper_); + ContextualCueingHelper::MaybeCreateForWebContents(web_contents()); + auto* contextual_cueing_helper = + ContextualCueingHelper::FromWebContents(web_contents()); + EXPECT_FALSE(contextual_cueing_helper); } TEST_F(ContextualCueingHelperTest, TabHelperStartsUp) { EnableSignIn(); - contextual_cueing_helper_ = - ContextualCueingHelper::MaybeCreateForWebContents(web_contents()); - EXPECT_TRUE(contextual_cueing_helper_); + ContextualCueingHelper::MaybeCreateForWebContents(web_contents()); + auto* contextual_cueing_helper = + ContextualCueingHelper::FromWebContents(web_contents()); + EXPECT_TRUE(contextual_cueing_helper); } +#endif // BUILDFLAG(ENABLE_GLIC) } // namespace contextual_cueing
diff --git a/chrome/browser/controlled_frame/controlled_frame_apitest.cc b/chrome/browser/controlled_frame/controlled_frame_apitest.cc index 4733d916..fa43a44 100644 --- a/chrome/browser/controlled_frame/controlled_frame_apitest.cc +++ b/chrome/browser/controlled_frame/controlled_frame_apitest.cc
@@ -70,90 +70,6 @@ return file_contents; } -const extensions::MenuItem::Id CreateMenuItemId( - const extensions::MenuItem::ExtensionKey& extension_key, - const std::string& string_uid) { - extensions::MenuItem::Id id; - id.extension_key = extension_key; - id.string_uid = string_uid; - return id; -} - -const content::EvalJsResult CreateContextMenuItem( - content::RenderFrameHost* app_frame, - const std::string& id, - const std::string& title) { - return content::EvalJs(app_frame, content::JsReplace(R"( - new Promise(async (resolve, reject) => { - const frame = document.getElementsByTagName('controlledframe')[0]; - if (!frame || !frame.contextMenus || !frame.contextMenus.create) { - reject('FAIL: frame, frame.contextMenus, or ' + - 'frame.contextMenus.create is undefined'); - return; - } - await frame.contextMenus.create({ title: $2, id: $1 }); - resolve('SUCCESS'); - }); - )", - id, title)); -} - -const content::EvalJsResult UpdateContextMenuItemTitle( - content::RenderFrameHost* app_frame, - const std::string& id, - const std::string& new_title) { - return content::EvalJs(app_frame, content::JsReplace(R"( - new Promise(async (resolve, reject) => { - const frame = document.getElementsByTagName('controlledframe')[0]; - if (!frame || !frame.contextMenus || !frame.contextMenus.update) { - reject('FAIL: frame, frame.contextMenus, or ' + - 'frame.contextMenus.update is undefined'); - return; - } - - await frame.contextMenus.update(/*id=*/$1, { title: $2 }); - resolve('SUCCESS'); - }); - )", - id, new_title)); -} - -const content::EvalJsResult RemoveContextMenuItem( - content::RenderFrameHost* app_frame, - const std::string& id) { - return content::EvalJs(app_frame, content::JsReplace(R"( - new Promise(async (resolve, reject) => { - const frame = document.getElementsByTagName('controlledframe')[0]; - if (!frame || !frame.contextMenus || !frame.contextMenus.remove) { - reject('FAIL: frame, frame.contextMenus, or ' + - 'frame.contextMenus.remove is undefined'); - return; - } - - await frame.contextMenus.remove(/*id=*/$1); - resolve('SUCCESS'); - }); - )", - id)); -} - -const content::EvalJsResult RemoveAllContextMenuItems( - content::RenderFrameHost* app_frame) { - return content::EvalJs(app_frame, R"( - new Promise(async (resolve, reject) => { - const frame = document.getElementsByTagName('controlledframe')[0]; - if (!frame || !frame.contextMenus || !frame.contextMenus.removeAll) { - reject('FAIL: frame, frame.contextMenus, or ' + - 'frame.contextMenus.removeAll is undefined'); - return; - } - - await frame.contextMenus.removeAll(); - resolve('SUCCESS'); - }); - )"); -} - const content::EvalJsResult SetBackgroundColorToWhite( extensions::WebViewGuest* guest) { return content::EvalJs(guest->GetGuestMainFrame(), R"( @@ -238,145 +154,8 @@ StartContentServer("web_apps/simple_isolated_app"); } - void ExpectMenuItemWithIdAndTitle( - const extensions::MenuItem::ExtensionKey& extension_key, - const std::string& expected_id, - const std::string& expected_title) { - auto* menu_manager = extensions::MenuManager::Get(profile()); - extensions::MenuItem* menu_item = - menu_manager->GetItemById(CreateMenuItemId(extension_key, expected_id)); - - ASSERT_TRUE(menu_item); - EXPECT_EQ(expected_title, menu_item->title()); - } }; -IN_PROC_BROWSER_TEST_F(ControlledFrameApiTest, ContextMenusCreate) { - web_app::IsolatedWebAppUrlInfo url_info = - CreateAndInstallEmptyApp(web_app::ManifestBuilder()); - content::RenderFrameHost* app_frame = OpenApp(url_info.app_id()); - - ASSERT_TRUE(CreateControlledFrame( - app_frame, embedded_https_test_server().GetURL("/index.html"))); - extensions::WebViewGuest* web_view_guest = GetWebViewGuest(app_frame); - auto* menu_manager = extensions::MenuManager::Get(profile()); - - const extensions::MenuItem::ExtensionKey extension_key( - /*extension_id=*/"", - web_view_guest->owner_rfh()->GetProcess()->GetDeprecatedID(), - web_view_guest->owner_rfh()->GetRoutingID(), - web_view_guest->view_instance_id()); - EXPECT_EQ(0u, menu_manager->MenuItemsSize(extension_key)); - - static constexpr std::string kItem1ID = "1"; - static constexpr std::string kItem1Title = "Test"; - EXPECT_EQ(kEvalSuccessStr, - CreateContextMenuItem(app_frame, kItem1ID, kItem1Title)); - ASSERT_EQ(1u, menu_manager->MenuItemsSize(extension_key)); - ExpectMenuItemWithIdAndTitle(extension_key, kItem1ID, kItem1Title); - - static constexpr std::string kItem2ID = "2"; - static constexpr std::string kItem2Title = "Test2"; - EXPECT_EQ(kEvalSuccessStr, - CreateContextMenuItem(app_frame, kItem2ID, kItem2Title)); - ASSERT_EQ(2u, menu_manager->MenuItemsSize(extension_key)); - ExpectMenuItemWithIdAndTitle(extension_key, kItem2ID, kItem2Title); - - static constexpr std::string kItem3ID = "3"; - static constexpr std::string kItem3Title = "Test3"; - EXPECT_EQ(kEvalSuccessStr, - CreateContextMenuItem(app_frame, kItem3ID, kItem3Title)); - ASSERT_EQ(3u, menu_manager->MenuItemsSize(extension_key)); - ExpectMenuItemWithIdAndTitle(extension_key, kItem3ID, kItem3Title); -} - -IN_PROC_BROWSER_TEST_F(ControlledFrameApiTest, ContextMenusUpdate) { - web_app::IsolatedWebAppUrlInfo url_info = - CreateAndInstallEmptyApp(web_app::ManifestBuilder()); - content::RenderFrameHost* app_frame = OpenApp(url_info.app_id()); - - ASSERT_TRUE(CreateControlledFrame( - app_frame, embedded_https_test_server().GetURL("/index.html"))); - extensions::WebViewGuest* web_view_guest = GetWebViewGuest(app_frame); - auto* menu_manager = extensions::MenuManager::Get(profile()); - - static constexpr std::string kItem1ID = "1"; - static constexpr std::string kItem1Title = "Test"; - EXPECT_EQ(kEvalSuccessStr, - CreateContextMenuItem(app_frame, kItem1ID, kItem1Title)); - - const extensions::MenuItem::ExtensionKey extension_key( - /*extension_id=*/"", - web_view_guest->owner_rfh()->GetProcess()->GetDeprecatedID(), - web_view_guest->owner_rfh()->GetRoutingID(), - web_view_guest->view_instance_id()); - ASSERT_EQ(1u, menu_manager->MenuItemsSize(extension_key)); - ExpectMenuItemWithIdAndTitle(extension_key, kItem1ID, kItem1Title); - - static constexpr std::string kItem1NewTitle = "Test1"; - EXPECT_EQ(kEvalSuccessStr, - UpdateContextMenuItemTitle(app_frame, kItem1ID, kItem1NewTitle)); - - ASSERT_EQ(1u, menu_manager->MenuItemsSize(extension_key)); - ExpectMenuItemWithIdAndTitle(extension_key, kItem1ID, kItem1NewTitle); -} - -IN_PROC_BROWSER_TEST_F(ControlledFrameApiTest, ContextMenusRemove) { - web_app::IsolatedWebAppUrlInfo url_info = - CreateAndInstallEmptyApp(web_app::ManifestBuilder()); - content::RenderFrameHost* app_frame = OpenApp(url_info.app_id()); - - ASSERT_TRUE(CreateControlledFrame( - app_frame, embedded_https_test_server().GetURL("/index.html"))); - extensions::WebViewGuest* web_view_guest = GetWebViewGuest(app_frame); - auto* menu_manager = extensions::MenuManager::Get(profile()); - - static constexpr std::string kItem1ID = "1"; - static constexpr std::string kItem1Title = "Test1"; - EXPECT_EQ(kEvalSuccessStr, - CreateContextMenuItem(app_frame, kItem1ID, kItem1Title)); - EXPECT_EQ(kEvalSuccessStr, CreateContextMenuItem(app_frame, /*id=*/"2", - /*title=*/"Test2")); - - EXPECT_EQ(kEvalSuccessStr, RemoveContextMenuItem(app_frame, kItem1ID)); - - const extensions::MenuItem::ExtensionKey extension_key( - /*extension_id=*/"", - web_view_guest->owner_rfh()->GetProcess()->GetDeprecatedID(), - web_view_guest->owner_rfh()->GetRoutingID(), - web_view_guest->view_instance_id()); - ASSERT_EQ(1u, menu_manager->MenuItemsSize(extension_key)); - - extensions::MenuItem* deleted_item = - menu_manager->GetItemById(CreateMenuItemId(extension_key, kItem1ID)); - EXPECT_FALSE(deleted_item); -} - -IN_PROC_BROWSER_TEST_F(ControlledFrameApiTest, ContextMenusRemoveAll) { - web_app::IsolatedWebAppUrlInfo url_info = - CreateAndInstallEmptyApp(web_app::ManifestBuilder()); - content::RenderFrameHost* app_frame = OpenApp(url_info.app_id()); - - ASSERT_TRUE(CreateControlledFrame( - app_frame, embedded_https_test_server().GetURL("/index.html"))); - extensions::WebViewGuest* web_view_guest = GetWebViewGuest(app_frame); - auto* menu_manager = extensions::MenuManager::Get(profile()); - - EXPECT_EQ(kEvalSuccessStr, CreateContextMenuItem(app_frame, /*id=*/"1", - /*title=*/"Test1")); - EXPECT_EQ(kEvalSuccessStr, CreateContextMenuItem(app_frame, /*id=*/"2", - /*title=*/"Test2")); - - EXPECT_EQ(kEvalSuccessStr, RemoveAllContextMenuItems(app_frame)); - - const extensions::MenuItem::ExtensionKey extension_key( - /*extension_id=*/"", - web_view_guest->owner_rfh()->GetProcess()->GetDeprecatedID(), - web_view_guest->owner_rfh()->GetRoutingID(), - web_view_guest->view_instance_id()); - ASSERT_EQ(0u, menu_manager->MenuItemsSize(extension_key)); -} - // This test checks if the Controlled Frame is able to intercept URL navigation // requests. IN_PROC_BROWSER_TEST_F(ControlledFrameApiTest, URLLoaderIsProxied) {
diff --git a/chrome/browser/controlled_frame/controlled_frame_contextmenus_browsertest.cc b/chrome/browser/controlled_frame/controlled_frame_contextmenus_browsertest.cc new file mode 100644 index 0000000..f93a902 --- /dev/null +++ b/chrome/browser/controlled_frame/controlled_frame_contextmenus_browsertest.cc
@@ -0,0 +1,372 @@ +// 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 <memory> +#include <string> + +#include "chrome/browser/controlled_frame/controlled_frame_test_base.h" +#include "chrome/browser/extensions/menu_manager.h" +#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/context_menu_interceptor.h" +#include "content/public/test/hit_test_region_observer.h" +#include "extensions/browser/guest_view/web_view/web_view_guest.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/input/web_input_event.h" +#include "third_party/blink/public/common/input/web_mouse_event.h" + +namespace controlled_frame { + +constexpr char kEvalSuccessStr[] = "SUCCESS"; + +class ControlledFrameContextMenusTest : public ControlledFrameTestBase { + public: + ControlledFrameContextMenusTest() + : ControlledFrameTestBase( + /*channel=*/version_info::Channel::STABLE, + /*feature_setting=*/FeatureSetting::ENABLED, + /*flag_setting=*/FlagSetting::CONTROLLED_FRAME) {} + + void SetUpOnMainThread() override { + ControlledFrameTestBase::SetUpOnMainThread(); + StartContentServer("web_apps/simple_isolated_app"); + } + + const extensions::MenuItem::Id CreateMenuItemId( + const extensions::MenuItem::ExtensionKey& extension_key, + const std::string& string_uid) { + extensions::MenuItem::Id id; + id.extension_key = extension_key; + id.string_uid = string_uid; + return id; + } + + void ExpectMenuItemWithIdAndTitle( + const extensions::MenuItem::ExtensionKey& extension_key, + const std::string& expected_id, + const std::string& expected_title) { + auto* menu_manager = extensions::MenuManager::Get(profile()); + extensions::MenuItem* menu_item = + menu_manager->GetItemById(CreateMenuItemId(extension_key, expected_id)); + + ASSERT_TRUE(menu_item); + EXPECT_EQ(expected_title, menu_item->title()); + } + + const content::EvalJsResult CreateContextMenuItem( + content::RenderFrameHost* app_frame, + const std::string& id, + const std::string& title) { + return content::EvalJs(app_frame, content::JsReplace(R"( + new Promise(async (resolve, reject) => { + const frame = document.getElementsByTagName('controlledframe')[0]; + if (!frame || !frame.contextMenus || !frame.contextMenus.create) { + reject('FAIL: frame, frame.contextMenus, or ' + + 'frame.contextMenus.create is undefined'); + return; + } + await frame.contextMenus.create({ title: $2, id: $1 }); + resolve('SUCCESS'); + }); + )", + id, title)); + } + + const content::EvalJsResult UpdateContextMenuItemTitle( + content::RenderFrameHost* app_frame, + const std::string& id, + const std::string& new_title) { + return content::EvalJs(app_frame, content::JsReplace(R"( + new Promise(async (resolve, reject) => { + const frame = document.getElementsByTagName('controlledframe')[0]; + if (!frame || !frame.contextMenus || !frame.contextMenus.update) { + reject('FAIL: frame, frame.contextMenus, or ' + + 'frame.contextMenus.update is undefined'); + return; + } + + await frame.contextMenus.update(/*id=*/$1, { title: $2 }); + resolve('SUCCESS'); + }); + )", + id, new_title)); + } + + const content::EvalJsResult RemoveContextMenuItem( + content::RenderFrameHost* app_frame, + const std::string& id) { + return content::EvalJs(app_frame, content::JsReplace(R"( + new Promise(async (resolve, reject) => { + const frame = document.getElementsByTagName('controlledframe')[0]; + if (!frame || !frame.contextMenus || !frame.contextMenus.remove) { + reject('FAIL: frame, frame.contextMenus, or ' + + 'frame.contextMenus.remove is undefined'); + return; + } + + await frame.contextMenus.remove(/*id=*/$1); + resolve('SUCCESS'); + }); + )", + id)); + } + + const content::EvalJsResult RemoveAllContextMenuItems( + content::RenderFrameHost* app_frame) { + return content::EvalJs(app_frame, R"( + new Promise(async (resolve, reject) => { + const frame = document.getElementsByTagName('controlledframe')[0]; + if (!frame || !frame.contextMenus || !frame.contextMenus.removeAll) { + reject('FAIL: frame, frame.contextMenus, or ' + + 'frame.contextMenus.removeAll is undefined'); + return; + } + + await frame.contextMenus.removeAll(); + resolve('SUCCESS'); + }); + )"); + } + + void SimulateOpenContextMenu(content::RenderFrameHost* controlled_frame) { + CHECK(controlled_frame); + content::WaitForHitTestData( + content::WebContents::FromRenderFrameHost(controlled_frame)); + + auto context_menu_interceptor = + std::make_unique<content::ContextMenuInterceptor>(controlled_frame); + gfx::Point click_pos(1, 1); + content::SimulateMouseClickAt( + content::WebContents::FromRenderFrameHost(controlled_frame), + blink::WebInputEvent::kNoModifiers, + blink::WebMouseEvent::Button::kRight, click_pos); + context_menu_interceptor->Wait(); + } +}; + +IN_PROC_BROWSER_TEST_F(ControlledFrameContextMenusTest, Create) { + web_app::IsolatedWebAppUrlInfo url_info = + CreateAndInstallEmptyApp(web_app::ManifestBuilder()); + content::RenderFrameHost* app_frame = OpenApp(url_info.app_id()); + + ASSERT_TRUE(CreateControlledFrame( + app_frame, embedded_https_test_server().GetURL("/index.html"))); + extensions::WebViewGuest* web_view_guest = GetWebViewGuest(app_frame); + auto* menu_manager = extensions::MenuManager::Get(profile()); + + const extensions::MenuItem::ExtensionKey extension_key( + /*extension_id=*/"", + web_view_guest->owner_rfh()->GetProcess()->GetDeprecatedID(), + web_view_guest->owner_rfh()->GetRoutingID(), + web_view_guest->view_instance_id()); + EXPECT_EQ(0u, menu_manager->MenuItemsSize(extension_key)); + + static constexpr std::string kItem1ID = "1"; + static constexpr std::string kItem1Title = "Test"; + EXPECT_EQ(kEvalSuccessStr, + CreateContextMenuItem(app_frame, kItem1ID, kItem1Title)); + ASSERT_EQ(1u, menu_manager->MenuItemsSize(extension_key)); + ExpectMenuItemWithIdAndTitle(extension_key, kItem1ID, kItem1Title); + + static constexpr std::string kItem2ID = "2"; + static constexpr std::string kItem2Title = "Test2"; + EXPECT_EQ(kEvalSuccessStr, + CreateContextMenuItem(app_frame, kItem2ID, kItem2Title)); + ASSERT_EQ(2u, menu_manager->MenuItemsSize(extension_key)); + ExpectMenuItemWithIdAndTitle(extension_key, kItem2ID, kItem2Title); + + static constexpr std::string kItem3ID = "3"; + static constexpr std::string kItem3Title = "Test3"; + EXPECT_EQ(kEvalSuccessStr, + CreateContextMenuItem(app_frame, kItem3ID, kItem3Title)); + ASSERT_EQ(3u, menu_manager->MenuItemsSize(extension_key)); + ExpectMenuItemWithIdAndTitle(extension_key, kItem3ID, kItem3Title); +} + +IN_PROC_BROWSER_TEST_F(ControlledFrameContextMenusTest, Update) { + web_app::IsolatedWebAppUrlInfo url_info = + CreateAndInstallEmptyApp(web_app::ManifestBuilder()); + content::RenderFrameHost* app_frame = OpenApp(url_info.app_id()); + + ASSERT_TRUE(CreateControlledFrame( + app_frame, embedded_https_test_server().GetURL("/index.html"))); + extensions::WebViewGuest* web_view_guest = GetWebViewGuest(app_frame); + auto* menu_manager = extensions::MenuManager::Get(profile()); + + static constexpr std::string kItem1ID = "1"; + static constexpr std::string kItem1Title = "Test"; + EXPECT_EQ(kEvalSuccessStr, + CreateContextMenuItem(app_frame, kItem1ID, kItem1Title)); + + const extensions::MenuItem::ExtensionKey extension_key( + /*extension_id=*/"", + web_view_guest->owner_rfh()->GetProcess()->GetDeprecatedID(), + web_view_guest->owner_rfh()->GetRoutingID(), + web_view_guest->view_instance_id()); + ASSERT_EQ(1u, menu_manager->MenuItemsSize(extension_key)); + ExpectMenuItemWithIdAndTitle(extension_key, kItem1ID, kItem1Title); + + static constexpr std::string kItem1NewTitle = "Test1"; + EXPECT_EQ(kEvalSuccessStr, + UpdateContextMenuItemTitle(app_frame, kItem1ID, kItem1NewTitle)); + + ASSERT_EQ(1u, menu_manager->MenuItemsSize(extension_key)); + ExpectMenuItemWithIdAndTitle(extension_key, kItem1ID, kItem1NewTitle); +} + +IN_PROC_BROWSER_TEST_F(ControlledFrameContextMenusTest, Remove) { + web_app::IsolatedWebAppUrlInfo url_info = + CreateAndInstallEmptyApp(web_app::ManifestBuilder()); + content::RenderFrameHost* app_frame = OpenApp(url_info.app_id()); + + ASSERT_TRUE(CreateControlledFrame( + app_frame, embedded_https_test_server().GetURL("/index.html"))); + extensions::WebViewGuest* web_view_guest = GetWebViewGuest(app_frame); + auto* menu_manager = extensions::MenuManager::Get(profile()); + + static constexpr std::string kItem1ID = "1"; + static constexpr std::string kItem1Title = "Test1"; + EXPECT_EQ(kEvalSuccessStr, + CreateContextMenuItem(app_frame, kItem1ID, kItem1Title)); + EXPECT_EQ(kEvalSuccessStr, CreateContextMenuItem(app_frame, /*id=*/"2", + /*title=*/"Test2")); + + EXPECT_EQ(kEvalSuccessStr, RemoveContextMenuItem(app_frame, kItem1ID)); + + const extensions::MenuItem::ExtensionKey extension_key( + /*extension_id=*/"", + web_view_guest->owner_rfh()->GetProcess()->GetDeprecatedID(), + web_view_guest->owner_rfh()->GetRoutingID(), + web_view_guest->view_instance_id()); + ASSERT_EQ(1u, menu_manager->MenuItemsSize(extension_key)); + + extensions::MenuItem* deleted_item = + menu_manager->GetItemById(CreateMenuItemId(extension_key, kItem1ID)); + EXPECT_FALSE(deleted_item); +} + +IN_PROC_BROWSER_TEST_F(ControlledFrameContextMenusTest, RemoveAll) { + web_app::IsolatedWebAppUrlInfo url_info = + CreateAndInstallEmptyApp(web_app::ManifestBuilder()); + content::RenderFrameHost* app_frame = OpenApp(url_info.app_id()); + + ASSERT_TRUE(CreateControlledFrame( + app_frame, embedded_https_test_server().GetURL("/index.html"))); + extensions::WebViewGuest* web_view_guest = GetWebViewGuest(app_frame); + auto* menu_manager = extensions::MenuManager::Get(profile()); + + EXPECT_EQ(kEvalSuccessStr, CreateContextMenuItem(app_frame, /*id=*/"1", + /*title=*/"Test1")); + EXPECT_EQ(kEvalSuccessStr, CreateContextMenuItem(app_frame, /*id=*/"2", + /*title=*/"Test2")); + + EXPECT_EQ(kEvalSuccessStr, RemoveAllContextMenuItems(app_frame)); + + const extensions::MenuItem::ExtensionKey extension_key( + /*extension_id=*/"", + web_view_guest->owner_rfh()->GetProcess()->GetDeprecatedID(), + web_view_guest->owner_rfh()->GetRoutingID(), + web_view_guest->view_instance_id()); + ASSERT_EQ(0u, menu_manager->MenuItemsSize(extension_key)); +} + +IN_PROC_BROWSER_TEST_F(ControlledFrameContextMenusTest, OnShow) { + web_app::IsolatedWebAppUrlInfo url_info = + CreateAndInstallEmptyApp(web_app::ManifestBuilder()); + content::RenderFrameHost* app_frame = OpenApp(url_info.app_id()); + + ASSERT_TRUE(CreateControlledFrame( + app_frame, embedded_https_test_server().GetURL("/index.html"))); + + auto add_handler_script = content::JsReplace( + R"( +document.onShowHandler = function() { + document.onShowCount = (document.onShowCount ?? 0) + 1; +}; + +(function() { + const frame = document.getElementsByTagName('controlledframe')[0]; + if (!frame || !frame.contextMenus) { + return ('FAIL: frame or frame.contextMenus is undefined'); + } + + if (frame.contextMenus.onShow.hasListeners()) { + return 'FAIL: frame.contextMenus.onShow.hasListeners() \ + returns true before addListener().'; + } + + frame.contextMenus.onShow.addListener(document.onShowHandler); + + if (!frame.contextMenus.onShow.hasListeners()) { + return 'FAIL: frame.contextMenus.hasListeners() \ + returns false after addListener().'; + } + + if (!frame.contextMenus.onShow.hasListener(document.onShowHandler)) { + return 'FAIL: frame.contextMenus.onShow.hasListener() \ + returns false after addListener().'; + } + + return $1; +})(); +)", + kEvalSuccessStr); + + // Add a listener for 'onShow' then simulate right click and expect the + // listener to be triggered. + ASSERT_EQ(content::EvalJs(app_frame, add_handler_script), kEvalSuccessStr); + + extensions::WebViewGuest* web_view_guest = GetWebViewGuest(app_frame); + ASSERT_TRUE(web_view_guest); + content::RenderFrameHost* controlled_frame = + web_view_guest->GetGuestMainFrame(); + ASSERT_TRUE(controlled_frame); + SimulateOpenContextMenu(controlled_frame); + ASSERT_EQ(content::EvalJs(app_frame, + "(function(){return document.onShowCount;})();"), + 1); + + auto remove_handler_script = content::JsReplace( + R"( +(function() { + const frame = document.getElementsByTagName('controlledframe')[0]; + if (!frame || !frame.contextMenus) { + return ('FAIL: frame or frame.contextMenus is undefined'); + } + + if (!frame.contextMenus.onShow.hasListeners()) { + return 'FAIL: frame.contextMenus.onShow.hasListeners() \ + returns false before removeListener().'; + } + + frame.contextMenus.onShow.removeListener(document.onShowHandler); + + if (frame.contextMenus.onShow.hasListeners()) { + return 'FAIL: frame.contextMenus.hasListeners() \ + returns true after removeListener().'; + } + + if (frame.contextMenus.onShow.hasListener(document.onShowHandler)) { + return 'FAIL: frame.contextMenus.onShow.hasListener() \ + returns true after removeListener().'; + } + + return $1; +})(); +)", + kEvalSuccessStr); + + // Remove the listener for 'onShow' then simulate right click and expect the + // listener to not be triggered. + ASSERT_EQ(content::EvalJs(app_frame, remove_handler_script), kEvalSuccessStr); + + SimulateOpenContextMenu(controlled_frame); + ASSERT_EQ(content::EvalJs(app_frame, + "(function(){return document.onShowCount;})();"), + 1); +} +} // namespace controlled_frame
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java index 5e4b7cb..d175865 100644 --- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java +++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java
@@ -396,10 +396,7 @@ private void initBottomSheet() { mScrim = new ScrimCoordinator( - mActivity, - /* systemUiScrimDelegate= */ null, - mCreatorViewGroup, - mActivity.getColor(R.color.default_scrim_color)); + mActivity, /* systemUiScrimDelegate= */ null, mCreatorViewGroup); mBottomSheetContainer = new FrameLayout(mActivity); mBottomSheetContainer.setId(R.id.creator_content_preview_bottom_sheet); @@ -657,6 +654,11 @@ mContext.getResources().getDimensionPixelSize(R.dimen.preview_tab_favicon_size); } + /** Destroys the native favicon helper. */ + public void destroy() { + mFaviconHelper.destroy(); + } + /** * Generates a favicon for a given URL. If no favicon was could be found or generated from * the URL, a default favicon will be shown.
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabMediator.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabMediator.java index fadbff1..1c41cc6 100644 --- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabMediator.java +++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabMediator.java
@@ -224,12 +224,13 @@ /** Destroys the objects used for the current preview tab. */ void destroyContent() { if (mWebContentsObserver != null) { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; } mWebContentsDelegate = null; mWebContents = null; mSheetContent = null; mProfile = null; + mFaviconLoader.destroy(); } }
diff --git a/chrome/browser/data_sharing/BUILD.gn b/chrome/browser/data_sharing/BUILD.gn index 28148d1..c7dae62 100644 --- a/chrome/browser/data_sharing/BUILD.gn +++ b/chrome/browser/data_sharing/BUILD.gn
@@ -100,6 +100,7 @@ "//components/data_sharing/public/protocol:proto_java", "//components/embedder_support/android:util_java", "//components/saved_tab_groups/public:java", + "//components/strings:components_strings_grd", "//content/public/android:content_full_java", "//third_party/android_sdk:android_window_extensions_java", "//ui/android:ui_java",
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 bcb141bf..691fcd66 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
@@ -88,6 +88,9 @@ private static final String LEARN_ABOUT_BLOCKED_ACCOUNTS_URL = "https://support.google.com/chrome/?p=chrome_collaboration"; + // Separator for description and link in share sheet. + private static final String SHARED_TEXT_SEPARATOR = "\n"; + private final ObservableSupplier<TabModelSelector> mTabModelSelectorSupplier; private final DataSharingTabGroupsDelegate mDataSharingTabGroupsDelegate; private final Supplier<BottomSheetController> mBottomSheetControllerSupplier; @@ -394,6 +397,7 @@ || previewData.sharedDataPreview.sharedTabGroupPreview == null) { DataSharingMetrics.recordJoinActionFlowState( DataSharingMetrics.JoinActionStateAndroid.PREVIEW_PERMISSION_DENIED); + showInvitationFailureDialog(); return; } @@ -577,6 +581,22 @@ } /** + * Open and focus on the tab group. + * + * @param collaborationId The collaboration id of the shared tab group. + */ + public void promoteTabGroup(String collaborationId) { + TabGroupSyncService tabGroupSyncService = + TabGroupSyncServiceFactory.getForProfile(mProfile); + SavedTabGroup existingGroup = + DataSharingTabGroupUtils.getTabGroupForCollabIdFromSync( + collaborationId, tabGroupSyncService); + assert existingGroup != null; + + onSavedTabGroupAvailable(existingGroup); + } + + /** * Called when a saved tab group is available. * * @param group The SavedTabGroup that became available. @@ -714,10 +734,12 @@ createGroupFinishedCallback.onResult(true); DataSharingMetrics.recordShareActionFlowState( DataSharingMetrics.ShareActionStateAndroid.GROUP_CREATE_SUCCESS); + // Consider using an utility to convert result to GroupData. showShareSheet( + activity, new GroupData( result.getGroupId(), - tabGroupDisplayName, + /* displayName= */ null, /* members= */ null, result.getAccessToken()), onCreateFinished); @@ -750,17 +772,26 @@ /* maxFaviconsToFetch= */ 4); } - private void showShareSheet(GroupData groupData, Callback<Boolean> onShareSheetShown) { + private void showShareSheet( + Context context, GroupData groupData, Callback<Boolean> onShareSheetShown) { mDataSharingTabGroupsDelegate.getPreviewBitmap( groupData.groupToken.collaborationId, ShareHelper.getTextPreviewImageSizePx(mResources), (preview) -> { - showShareSheetWithPreview(groupData, preview, onShareSheetShown); + showShareSheetWithPreview(context, groupData, preview, onShareSheetShown); }); } private void showShareSheetWithPreview( - GroupData groupData, Bitmap preview, Callback<Boolean> onShareSheetShown) { + Context context, + GroupData groupData, + Bitmap preview, + Callback<Boolean> onShareSheetShown) { + TabGroupSyncService tabGroupSyncService = + TabGroupSyncServiceFactory.getForProfile(mProfile); + SavedTabGroup tabGroup = + DataSharingTabGroupUtils.getTabGroupForCollabIdFromSync( + groupData.groupToken.collaborationId, tabGroupSyncService); GURL url = mDataSharingService.getDataSharingUrl(groupData); if (url == null) { // TODO(ritikagup) : Show error dialog showing fetching URL failed. Contact owner for @@ -777,8 +808,26 @@ .setDetailedContentType(DetailedContentType.TAB_GROUP_LINK) .build(); + String tabGroupName = null; + // TODO(ssid): The tab group should not be null, if we wait for makeTabGroupShared() to + // finish. Remove this check when its integrated. + if (tabGroup != null) { + tabGroupName = tabGroup.title; + } + if (TextUtils.isEmpty(tabGroupName)) { + tabGroupName = + context.getString(R.string.collaboration_share_sheet_tab_group_fallback_name); + } + // TODO(ssid): Share delegate adds another separator, fix the formatting. + String text = + context.getString(R.string.collaboration_share_sheet_message, tabGroupName) + + SHARED_TEXT_SEPARATOR; ShareParams.Builder shareParamsBuilder = - new ShareParams.Builder(mWindowAndroid, groupData.displayName, url.getSpec()); + new ShareParams.Builder( + mWindowAndroid, + context.getString(R.string.collaboration_share_sheet_title), + url.getSpec()) + .setText(text); if (preview != null) { shareParamsBuilder.setPreviewImageBitmap(preview); @@ -853,10 +902,12 @@ @Override public void onShareInviteLinkClickedWithWait( GroupToken groupToken, Callback<Boolean> onFinished) { + // Consider pass GroupData from the UI. showShareSheet( + activity, new GroupData( groupToken.collaborationId, - tabGroupName, + /* displayName= */ null, /* members= */ null, groupToken.accessToken), onFinished);
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 ac35a6b..eeb328af7 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
@@ -468,6 +468,10 @@ mShareParamsCaptor.capture(), any(), eq(ShareDelegate.ShareOrigin.TAB_GROUP)); + ShareParams shareParams = mShareParamsCaptor.getValue(); + assertEquals(shareParams.getText(), "Shared tab group link expires in 48 hours\n"); + assertEquals(shareParams.getUrl(), TEST_URL.getSpec()); + assertEquals(shareParams.getTitle(), "Collaborate on tab group"); } @Test @@ -504,6 +508,11 @@ DataSharingCreateUiConfig uiConfig = uiConfigCaptor.getValue(); + mSavedTabGroup.collaborationId = COLLABORATION_ID1; + mSavedTabGroup.title = "test title"; + doReturn(mSavedTabGroup).when(mTabGroupSyncService).getGroup(SYNC_GROUP_ID1); + doReturn(new String[] {SYNC_GROUP_ID1}).when(mTabGroupSyncService).getAllGroupIds(); + assertNotNull(uiConfig.getCreateCallback()); uiConfig.getCreateCallback() .onGroupCreatedWithWait( @@ -520,7 +529,15 @@ // Verifying DataSharingService createGroup API is called. verify(mTabGroupSyncService).makeTabGroupShared(LOCAL_ID, COLLABORATION_ID1); - verify(mShareDelegate).share(any(), any(), eq(ShareDelegate.ShareOrigin.TAB_GROUP)); + verify(mShareDelegate) + .share( + mShareParamsCaptor.capture(), + any(), + eq(ShareDelegate.ShareOrigin.TAB_GROUP)); + ShareParams shareParams = mShareParamsCaptor.getValue(); + assertEquals(shareParams.getText(), "test title link expires in 48 hours\n"); + assertEquals(shareParams.getUrl(), TEST_URL.getSpec()); + assertEquals(shareParams.getTitle(), "Collaborate on tab group"); } @Test @@ -639,6 +656,16 @@ verify(mMessagingBackendService).getActivityLog(any()); } + @Test + public void testPromoteTabGroup() { + when(mProfile.getOriginalProfile()).thenReturn(mProfile); + + doReturn(mSavedTabGroup).when(mTabGroupSyncService).getGroup(SYNC_GROUP_ID1); + + mDataSharingTabManager.promoteTabGroup(COLLABORATION_ID1); + verify(mDataSharingTabGroupsDelegate).openTabGroupWithTabId(TAB_ID); + } + private void setupActivityLogItemsOnTheBackend() { List<ActivityLogItem> logItems = new ArrayList<>();
diff --git a/chrome/browser/data_sharing/data_sharing_navigation_throttle.cc b/chrome/browser/data_sharing/data_sharing_navigation_throttle.cc index 160ef9d..ff928b7c 100644 --- a/chrome/browser/data_sharing/data_sharing_navigation_throttle.cc +++ b/chrome/browser/data_sharing/data_sharing_navigation_throttle.cc
@@ -20,6 +20,13 @@ return false; } + // If this is a session or tab restore, don't intercept the + // navigation to avoid showing the dialog on each browser + // start. + if (navigation_handle->GetRestoreType() == content::RestoreType::kRestored) { + return false; + } + if (navigation_handle->IsRendererInitiated()) { if (navigation_handle->HasUserGesture()) { return true;
diff --git a/chrome/browser/dbus_memory_pressure_evaluator_linux.cc b/chrome/browser/dbus_memory_pressure_evaluator_linux.cc index 6f7d8f9d..193b4d8 100644 --- a/chrome/browser/dbus_memory_pressure_evaluator_linux.cc +++ b/chrome/browser/dbus_memory_pressure_evaluator_linux.cc
@@ -18,18 +18,6 @@ #include "dbus/object_path.h" #include "dbus/object_proxy.h" -namespace { - -scoped_refptr<dbus::Bus> CreateBusOfType(dbus::Bus::BusType type) { - dbus::Bus::Options options; - options.bus_type = type; - options.connection_type = dbus::Bus::PRIVATE; - options.dbus_task_runner = dbus_thread_linux::GetTaskRunner(); - return base::MakeRefCounted<dbus::Bus>(options); -} - -} // namespace - const char DbusMemoryPressureEvaluatorLinux::kLmmService[] = "org.freedesktop.LowMemoryMonitor"; const char DbusMemoryPressureEvaluatorLinux::kLmmObject[] = @@ -89,8 +77,9 @@ void DbusMemoryPressureEvaluatorLinux::CheckIfLmmIsAvailable() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!system_bus_) - system_bus_ = CreateBusOfType(dbus::Bus::SYSTEM); + if (!system_bus_) { + system_bus_ = dbus_thread_linux::GetSharedSystemBus(); + } dbus_utils::CheckForServiceAndStart( system_bus_, kLmmService, @@ -118,7 +107,7 @@ } else { VLOG(1) << "LMM is not available, checking for portal"; - ResetBus(system_bus_); + system_bus_.reset(); CheckIfPortalIsAvailable(); } } @@ -126,8 +115,9 @@ void DbusMemoryPressureEvaluatorLinux::CheckIfPortalIsAvailable() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!session_bus_) - session_bus_ = CreateBusOfType(dbus::Bus::SESSION); + if (!session_bus_) { + session_bus_ = dbus_thread_linux::GetSharedSessionBus(); + } dbus_utils::CheckForServiceAndStart( session_bus_, kXdgPortalService, @@ -156,19 +146,10 @@ } else { VLOG(1) << "No memory monitor found"; - ResetBus(session_bus_); + session_bus_.reset(); } } -void DbusMemoryPressureEvaluatorLinux::ResetBus(scoped_refptr<dbus::Bus>& bus) { - if (!bus) - return; - - bus->GetDBusTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&dbus::Bus::ShutdownAndBlock, bus)); - bus.reset(); -} - void DbusMemoryPressureEvaluatorLinux::OnSignalConnected( const std::string& interface, const std::string& signal, @@ -178,8 +159,8 @@ if (!connected) { LOG(WARNING) << "Failed to connect to " << interface << '.' << signal; - ResetBus(system_bus_); - ResetBus(session_bus_); + system_bus_.reset(); + session_bus_.reset(); } } @@ -209,10 +190,12 @@ base::MemoryPressureListener::MemoryPressureLevel DbusMemoryPressureEvaluatorLinux::LmmToBasePressureLevel(uint8_t lmm_level) { - if (lmm_level >= critical_level_) + if (lmm_level >= critical_level_) { return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; - if (lmm_level >= moderate_level_) + } + if (lmm_level >= moderate_level_) { return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE; + } return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; }
diff --git a/chrome/browser/dbus_memory_pressure_evaluator_linux.h b/chrome/browser/dbus_memory_pressure_evaluator_linux.h index 53ce09b..c14325a 100644 --- a/chrome/browser/dbus_memory_pressure_evaluator_linux.h +++ b/chrome/browser/dbus_memory_pressure_evaluator_linux.h
@@ -86,9 +86,6 @@ // Handles the availability response from above. void CheckIfPortalIsAvailableResponse(std::optional<bool> is_available); - // Shuts down the given bus on the D-Bus thread and clears the pointer. - void ResetBus(scoped_refptr<dbus::Bus>& bus); - void OnSignalConnected(const std::string& interface, const std::string& signal, bool connected);
diff --git a/chrome/browser/device_notifications/device_status_icon_renderer.cc b/chrome/browser/device_notifications/device_status_icon_renderer.cc index 91a89e3..0ac84bc6 100644 --- a/chrome/browser/device_notifications/device_status_icon_renderer.cc +++ b/chrome/browser/device_notifications/device_status_icon_renderer.cc
@@ -67,7 +67,10 @@ if (status_icon_) { auto* status_tray = g_browser_process->status_tray(); DCHECK(status_tray); - status_tray->RemoveStatusIcon(status_icon_); + std::unique_ptr<StatusIcon> removed_icon = + status_tray->RemoveStatusIcon(status_icon_); + status_icon_ = nullptr; + removed_icon.reset(); } } @@ -136,8 +139,10 @@ DCHECK(status_tray); if (device_system_tray_icon_->profiles().empty()) { if (status_icon_) { - status_tray->RemoveStatusIcon(status_icon_); + std::unique_ptr<StatusIcon> removed_icon = + status_tray->RemoveStatusIcon(status_icon_); status_icon_ = nullptr; + removed_icon.reset(); } return; }
diff --git a/chrome/browser/device_notifications/device_status_icon_renderer.h b/chrome/browser/device_notifications/device_status_icon_renderer.h index ba9c61d..d3a688c5 100644 --- a/chrome/browser/device_notifications/device_status_icon_renderer.h +++ b/chrome/browser/device_notifications/device_status_icon_renderer.h
@@ -62,7 +62,7 @@ int about_device_message_id_; // Reference to our status icon (if any) - owned by the StatusTray. - raw_ptr<StatusIcon, DanglingUntriaged> status_icon_ = nullptr; + raw_ptr<StatusIcon> status_icon_ = nullptr; // The mapping of clickable system tray icon items to their click handlers std::vector<base::RepeatingClosure> command_id_callbacks_;
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc index fab87ae5..232931c 100644 --- a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc +++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc
@@ -683,12 +683,6 @@ ExtensionFunction::ResponseAction EnterpriseReportingPrivateGetFileSystemInfoFunction::Run() { - if (!IsNewFunctionEnabled( - enterprise_signals::features::NewEvFunction::kFileSystemInfo)) { - return RespondNow(Error(device_signals::ErrorToString( - device_signals::SignalCollectionError::kUnsupported))); - } - std::optional<api::enterprise_reporting_private::GetFileSystemInfo::Params> params = api::enterprise_reporting_private::GetFileSystemInfo::Params::Create( @@ -763,12 +757,6 @@ ExtensionFunction::ResponseAction EnterpriseReportingPrivateGetSettingsFunction::Run() { - if (!IsNewFunctionEnabled( - enterprise_signals::features::NewEvFunction::kSettings)) { - return RespondNow(Error(device_signals::ErrorToString( - device_signals::SignalCollectionError::kUnsupported))); - } - std::optional<api::enterprise_reporting_private::GetSettings::Params> params = api::enterprise_reporting_private::GetSettings::Params::Create(args()); EXTENSION_FUNCTION_VALIDATE(params); @@ -840,12 +828,6 @@ ExtensionFunction::ResponseAction EnterpriseReportingPrivateGetAvInfoFunction::Run() { - if (!IsNewFunctionEnabled( - enterprise_signals::features::NewEvFunction::kAntiVirus)) { - return RespondNow(Error(device_signals::ErrorToString( - device_signals::SignalCollectionError::kUnsupported))); - } - std::optional<api::enterprise_reporting_private::GetAvInfo::Params> params = api::enterprise_reporting_private::GetAvInfo::Params::Create(args()); EXTENSION_FUNCTION_VALIDATE(params); @@ -892,12 +874,6 @@ ExtensionFunction::ResponseAction EnterpriseReportingPrivateGetHotfixesFunction::Run() { - if (!IsNewFunctionEnabled( - enterprise_signals::features::NewEvFunction::kHotfix)) { - return RespondNow(Error(device_signals::ErrorToString( - device_signals::SignalCollectionError::kUnsupported))); - } - std::optional<api::enterprise_reporting_private::GetHotfixes::Params> params = api::enterprise_reporting_private::GetHotfixes::Params::Create(args()); EXTENSION_FUNCTION_VALIDATE(params);
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc index 03948c9..be1152b 100644 --- a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc +++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc
@@ -126,7 +126,6 @@ { extensions_features:: kApiEnterpriseReportingPrivateReportDataMaskingEvent, - enterprise_signals::features::kNewEvSignalsEnabled, }, /*disabled_features=*/{}); #else
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc index d239705f..1fc67db 100644 --- a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc +++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc
@@ -62,7 +62,6 @@ #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) #include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_feature_list.h" #include "chrome/browser/enterprise/signals/signals_aggregator_factory.h" #include "components/device_signals/core/browser/mock_signals_aggregator.h" // nogncheck #include "components/device_signals/core/browser/signals_aggregator.h" // nogncheck @@ -70,7 +69,6 @@ #include "components/device_signals/core/browser/user_context.h" // nogncheck #include "components/device_signals/core/common/common_types.h" // nogncheck #include "components/device_signals/core/common/signals_constants.h" // nogncheck -#include "components/device_signals/core/common/signals_features.h" // nogncheck #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) @@ -1320,14 +1318,9 @@ })); } - virtual void SetFeatureFlag() { - scoped_features_.InitAndEnableFeature( - enterprise_signals::features::kNewEvSignalsEnabled); - } raw_ptr<device_signals::MockSignalsAggregator, DanglingUntriaged> mock_aggregator_; - base::test::ScopedFeatureList scoped_features_; base::HistogramTester histogram_tester_; }; @@ -1338,8 +1331,6 @@ void SetUp() override { UserContextGatedTest::SetUp(); - SetFeatureFlag(); - function_ = base::MakeRefCounted< EnterpriseReportingPrivateGetFileSystemInfoFunction>(); } @@ -1497,27 +1488,6 @@ "Enterprise.DeviceSignals.Collection.FileSystemInfo.Delta", 0); } -class EnterpriseReportingPrivateGetFileSystemInfoDisabledTest - : public EnterpriseReportingPrivateGetFileSystemInfoTest { - protected: - // Overwrite this function to disable the feature flag for tests using this - // specific fixture. - void SetFeatureFlag() override { - scoped_features_.InitAndEnableFeatureWithParameters( - enterprise_signals::features::kNewEvSignalsEnabled, - {{"DisableFileSystemInfo", "true"}}); - } -}; - -TEST_F(EnterpriseReportingPrivateGetFileSystemInfoDisabledTest, - FlagDisabled_Test) { - auto error = api_test_utils::RunFunctionAndReturnError( - function_.get(), GetFakeRequest(), profile()); - EXPECT_EQ(error, function_->GetError()); - EXPECT_EQ(error, device_signals::ErrorToString( - device_signals::SignalCollectionError::kUnsupported)); -} - #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) @@ -1528,8 +1498,6 @@ void SetUp() override { UserContextGatedTest::SetUp(); - SetFeatureFlag(); - function_ = base::MakeRefCounted<EnterpriseReportingPrivateGetSettingsFunction>(); } @@ -1700,26 +1668,6 @@ "Enterprise.DeviceSignals.Collection.SystemSettings.Delta", 0); } -class EnterpriseReportingPrivateGetSettingsDisabledTest - : public EnterpriseReportingPrivateGetSettingsTest { - protected: - // Overwrite this function to disable the feature flag for tests using this - // specific fixture. - void SetFeatureFlag() override { - scoped_features_.InitAndEnableFeatureWithParameters( - enterprise_signals::features::kNewEvSignalsEnabled, - {{"DisableSettings", "true"}}); - } -}; - -TEST_F(EnterpriseReportingPrivateGetSettingsDisabledTest, FlagDisabled_Test) { - auto error = api_test_utils::RunFunctionAndReturnError( - function_.get(), GetFakeRequest(), profile()); - EXPECT_EQ(error, function_->GetError()); - EXPECT_EQ(error, device_signals::ErrorToString( - device_signals::SignalCollectionError::kUnsupported)); -} - #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_WIN) @@ -1739,8 +1687,6 @@ void SetUp() override { UserContextGatedTest::SetUp(); - SetFeatureFlag(); - function_ = base::MakeRefCounted<EnterpriseReportingPrivateGetAvInfoFunction>(); } @@ -1865,25 +1811,6 @@ "Enterprise.DeviceSignals.Collection.Success.AntiVirus.Latency", 0); } -class EnterpriseReportingPrivateGetAvInfoDisabledTest - : public EnterpriseReportingPrivateGetAvInfoTest { - protected: - // Overwrite this function to disable the feature flag for tests using this - // specific fixture. - void SetFeatureFlag() override { - scoped_features_.InitAndEnableFeatureWithParameters( - enterprise_signals::features::kNewEvSignalsEnabled, - {{"DisableAntiVirus", "true"}}); - } -}; - -TEST_F(EnterpriseReportingPrivateGetAvInfoDisabledTest, FlagDisabled_Test) { - auto error = api_test_utils::RunFunctionAndReturnError( - function_.get(), GetFakeUserContextJsonParams(), profile()); - EXPECT_EQ(error, function_->GetError()); - EXPECT_EQ(error, device_signals::ErrorToString( - device_signals::SignalCollectionError::kUnsupported)); -} // Tests for API enterprise.reportingPrivate.getHotfixes class EnterpriseReportingPrivateGetHotfixesTest : public UserContextGatedTest { @@ -1891,8 +1818,6 @@ void SetUp() override { UserContextGatedTest::SetUp(); - SetFeatureFlag(); - function_ = base::MakeRefCounted<EnterpriseReportingPrivateGetHotfixesFunction>(); } @@ -2009,27 +1934,6 @@ "Enterprise.DeviceSignals.Collection.Success.Hotfixes.Latency", 0); } -class EnterpriseReportingPrivateGetHotfixesInfoDisabledTest - : public EnterpriseReportingPrivateGetHotfixesTest { - protected: - // Overwrite this function to disable the feature flag for tests using this - // specific fixture. - void SetFeatureFlag() override { - scoped_features_.InitAndEnableFeatureWithParameters( - enterprise_signals::features::kNewEvSignalsEnabled, - {{"DisableHotfix", "true"}}); - } -}; - -TEST_F(EnterpriseReportingPrivateGetHotfixesInfoDisabledTest, - FlagDisabled_Test) { - auto error = api_test_utils::RunFunctionAndReturnError( - function_.get(), GetFakeUserContextJsonParams(), profile()); - EXPECT_EQ(error, function_->GetError()); - EXPECT_EQ(error, device_signals::ErrorToString( - device_signals::SignalCollectionError::kUnsupported)); -} - #endif // BUILDFLAG(IS_WIN) } // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc index a05dac5..efd9e139 100644 --- a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc +++ b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc
@@ -2,11 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/40285824): Remove this and convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - // devguid requires Windows.h be imported first. #include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h" @@ -171,13 +166,13 @@ if (device_descriptor->VendorIdOffset && output_buf[device_descriptor->VendorIdOffset]) { - device.vendor.assign(output_buf.data() + device_descriptor->VendorIdOffset); + device.vendor.assign(&output_buf[device_descriptor->VendorIdOffset]); } std::string product_id; if (device_descriptor->ProductIdOffset && output_buf[device_descriptor->ProductIdOffset]) { - device.model.assign(output_buf.data() + device_descriptor->ProductIdOffset); + device.model.assign(&output_buf[device_descriptor->ProductIdOffset]); } device_list->data.push_back(std::move(device));
diff --git a/chrome/browser/extensions/api/messaging/native_message_built_in_host.cc b/chrome/browser/extensions/api/messaging/native_message_built_in_host.cc index afc16be..b305d95 100644 --- a/chrome/browser/extensions/api/messaging/native_message_built_in_host.cc +++ b/chrome/browser/extensions/api/messaging/native_message_built_in_host.cc
@@ -2,11 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/40285824): Remove this and convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #include "chrome/browser/extensions/api/messaging/native_message_built_in_host.h" #include <string> @@ -26,8 +21,8 @@ bool MatchesSecurityOrigin(const NativeMessageBuiltInHost& host, const ExtensionId& extension_id) { GURL origin(std::string(kExtensionScheme) + "://" + extension_id); - for (size_t i = 0; i < host.allowed_origins_count; i++) { - URLPattern allowed_origin(URLPattern::SCHEME_ALL, host.allowed_origins[i]); + for (const char* host_allowed_origin : host.allowed_origins) { + URLPattern allowed_origin(URLPattern::SCHEME_ALL, host_allowed_origin); if (allowed_origin.MatchesSecurityOrigin(origin)) { return true; } @@ -44,8 +39,7 @@ const std::string& native_host_name, bool allow_user_level, std::string* error) { - for (size_t i = 0; i < kBuiltInHostsCount; i++) { - const auto& host = kBuiltInHosts[i]; + for (const auto& host : kBuiltInHosts) { if (host.name == native_host_name) { if (MatchesSecurityOrigin(host, source_extension_id)) { return (*host.create_function)(browser_context);
diff --git a/chrome/browser/extensions/api/messaging/native_message_built_in_host.h b/chrome/browser/extensions/api/messaging/native_message_built_in_host.h index 08e2ae4..7b19cdb 100644 --- a/chrome/browser/extensions/api/messaging/native_message_built_in_host.h +++ b/chrome/browser/extensions/api/messaging/native_message_built_in_host.h
@@ -5,11 +5,13 @@ #ifndef CHROME_BROWSER_EXTENSIONS_API_MESSAGING_NATIVE_MESSAGE_BUILT_IN_HOST_H_ #define CHROME_BROWSER_EXTENSIONS_API_MESSAGING_NATIVE_MESSAGE_BUILT_IN_HOST_H_ -#include <memory> -#include "base/memory/raw_ptr_exclusion.h" - #include <stddef.h> +#include <memory> + +#include "base/containers/span.h" +#include "base/memory/raw_span.h" + namespace content { class BrowserContext; } @@ -23,24 +25,18 @@ const char* const name; // The extension origins allowed to create the built-in host. - // This field is not a raw_ptr<> because it only ever points at statically- + // This field is a raw_span<> because it only ever points at statically- // allocated memory which is never freed, and hence cannot dangle. - RAW_PTR_EXCLUSION const char* const* const allowed_origins; - - // The count of |allowed_origins|. - size_t allowed_origins_count; + const base::raw_span<const char* const> allowed_origins; // The factory function used to create new instances of this host. - std::unique_ptr<NativeMessageHost> (*create_function)( + std::unique_ptr<NativeMessageHost> (*const create_function)( content::BrowserContext*); }; // The set of built-in hosts that can be instantiated. These are defined in the // platform-specific impl files. -extern const NativeMessageBuiltInHost kBuiltInHosts[]; - -// The count of built-in hosts defined in |kBuiltInHosts|. -extern const size_t kBuiltInHostsCount; +extern const base::span<const NativeMessageBuiltInHost> kBuiltInHosts; } // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/native_message_echo_host.cc b/chrome/browser/extensions/api/messaging/native_message_echo_host.cc index a126d67..30f9687 100644 --- a/chrome/browser/extensions/api/messaging/native_message_echo_host.cc +++ b/chrome/browser/extensions/api/messaging/native_message_echo_host.cc
@@ -16,19 +16,6 @@ namespace extensions { // static -// Must match ScopedTestNativeMessagingHost::kHostName. -const char* const NativeMessageEchoHost::kHostName = - "com.google.chrome.test.echo"; - -// static -// Must match ScopedTestNativeMessagingHost::kExtensionId. -const char* const NativeMessageEchoHost::kOrigins[] = { - "chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"}; - -// static -const size_t NativeMessageEchoHost::kOriginCount = std::size(kOrigins); - -// static std::unique_ptr<NativeMessageHost> NativeMessageEchoHost::Create( content::BrowserContext* browser_context) { return std::make_unique<NativeMessageEchoHost>();
diff --git a/chrome/browser/extensions/api/messaging/native_message_echo_host.h b/chrome/browser/extensions/api/messaging/native_message_echo_host.h index db51ff1..3f39547 100644 --- a/chrome/browser/extensions/api/messaging/native_message_echo_host.h +++ b/chrome/browser/extensions/api/messaging/native_message_echo_host.h
@@ -26,9 +26,12 @@ // used to drive the tests. class NativeMessageEchoHost : public NativeMessageHost { public: - static const char* const kHostName; - static const char* const kOrigins[]; - static const size_t kOriginCount; + // Must match ScopedTestNativeMessagingHost::kHostName. + static constexpr char kHostName[] = "com.google.chrome.test.echo"; + + // Must match ScopedTestNativeMessagingHost::kExtensionId. + static constexpr const char* kOrigins[] = { + "chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"}; static std::unique_ptr<NativeMessageHost> Create( content::BrowserContext* browser_context);
diff --git a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc index 34d4380..4d868d9 100644 --- a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc +++ b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
@@ -26,26 +26,25 @@ return remoting::CreateIt2MeNativeMessagingHostForChromeOS(); } -} // namespace - -const NativeMessageBuiltInHost kBuiltInHosts[] = { +const NativeMessageBuiltInHost kBuiltInHostsArray[] = { {NativeMessageEchoHost::kHostName, NativeMessageEchoHost::kOrigins, - NativeMessageEchoHost::kOriginCount, &NativeMessageEchoHost::Create}, + &NativeMessageEchoHost::Create}, {remoting::kIt2MeNativeMessageHostName, remoting::kIt2MeOrigins, - remoting::kIt2MeOriginsSize, &CreateIt2MeHost}, + &CreateIt2MeHost}, {arc::ArcSupportMessageHost::kHostName, - arc::ArcSupportMessageHost::kHostOrigin, 1, + arc::ArcSupportMessageHost::kHostOrigin, &arc::ArcSupportMessageHost::Create}, {drive::kDriveFsNativeMessageHostName, - drive::kDriveFsNativeMessageHostOrigins.data(), - drive::kDriveFsNativeMessageHostOrigins.size(), + {drive::kDriveFsNativeMessageHostOrigins}, &drive::CreateDriveFsNativeMessageHostAsh}, {ash::guest_os::VmSKForwardingNativeMessageHost::kHostName, - ash::guest_os::VmSKForwardingNativeMessageHost::kOrigins, - ash::guest_os::VmSKForwardingNativeMessageHost::kOriginCount, + {ash::guest_os::VmSKForwardingNativeMessageHost::kOrigins}, &ash::guest_os::VmSKForwardingNativeMessageHost::CreateFromExtension}, }; -const size_t kBuiltInHostsCount = std::size(kBuiltInHosts); +} // namespace + +constexpr base::span<const NativeMessageBuiltInHost> kBuiltInHosts = + kBuiltInHostsArray; } // namespace extensions
diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc b/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc index ee43c8f0..d263a11e 100644 --- a/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc +++ b/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/extensions/api/system_indicator/system_indicator_manager.h" +#include <memory> #include <utility> #include "base/containers/contains.h" @@ -62,7 +63,7 @@ raw_ptr<const Extension> extension_; raw_ptr<StatusTray> status_tray_; - raw_ptr<StatusIcon, DanglingUntriaged> status_icon_; + raw_ptr<StatusIcon> status_icon_; raw_ptr<Profile> profile_; IconImage manifest_icon_; gfx::Image dynamic_icon_; @@ -88,7 +89,10 @@ ExtensionIndicatorIcon::~ExtensionIndicatorIcon() { if (status_icon_) { status_icon_->RemoveObserver(this); - status_tray_->RemoveStatusIcon(status_icon_); + std::unique_ptr<StatusIcon> removed_icon = + status_tray_->RemoveStatusIcon(status_icon_); + status_icon_ = nullptr; + removed_icon.reset(); } }
diff --git a/chrome/browser/extensions/desktop_android/desktop_android_extension_system.cc b/chrome/browser/extensions/desktop_android/desktop_android_extension_system.cc index 7f023db..6f3000f 100644 --- a/chrome/browser/extensions/desktop_android/desktop_android_extension_system.cc +++ b/chrome/browser/extensions/desktop_android/desktop_android_extension_system.cc
@@ -109,7 +109,7 @@ scoped_refptr<const Extension> extension) override {} void ShowExtensionDisabledError(const Extension* extension, bool is_remote_install) override {} - + void FinishDelayedInstallationsIfAny() override {} void LoadExtensionForReload( const ExtensionId& extension_id, const base::FilePath& path,
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 2400563..124cd59 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc
@@ -585,16 +585,7 @@ void ExtensionService::EnabledReloadableExtensions() { TRACE_EVENT0("browser,startup", "ExtensionService::EnabledReloadableExtensions"); - - std::vector<std::string> extensions_to_enable; - for (const auto& e : registry_->disabled_extensions()) { - if (extension_prefs_->GetDisableReasons(e->id()) == - disable_reason::DISABLE_RELOAD) - extensions_to_enable.push_back(e->id()); - } - for (const std::string& extension : extensions_to_enable) { - EnableExtension(extension); - } + extension_registrar_.EnabledReloadableExtensions(); } void ExtensionService::MaybeFinishShutdownDelayed() { @@ -791,6 +782,10 @@ AddExtensionDisabledError(this, extension, is_remote_install); } +void ExtensionService::FinishDelayedInstallationsIfAny() { + MaybeFinishDelayedInstallations(); +} + void ExtensionService::OnUnpackedReloadFailure(const Extension* extension, const base::FilePath& file_path, const std::string& error) { @@ -1384,13 +1379,7 @@ void ExtensionService::RemoveComponentExtension( const std::string& extension_id) { - scoped_refptr<const Extension> extension( - registry_->enabled_extensions().GetByID(extension_id)); - UnloadExtension(extension_id, UnloadedExtensionReason::UNINSTALL); - if (extension.get()) { - ExtensionRegistry::Get(profile_)->TriggerOnUninstalled( - extension.get(), UNINSTALL_REASON_COMPONENT_REMOVED); - } + extension_registrar_.RemoveComponentExtension(extension_id); } void ExtensionService::UnloadAllExtensionsForTest() { @@ -1771,7 +1760,7 @@ if (InstallVerifier::NeedsVerification(*extension, GetBrowserContext())) InstallVerifier::Get(GetBrowserContext())->VerifyExtension(extension->id()); - FinishInstallation(extension); + extension_registrar_.FinishInstallation(extension); } bool ExtensionService::FinishDelayedInstallationIfReady( @@ -1809,39 +1798,10 @@ NOTREACHED(); } - FinishInstallation(delayed_install.get()); + extension_registrar_.FinishInstallation(delayed_install.get()); return true; } -void ExtensionService::FinishInstallation(const Extension* extension) { - const Extension* existing_extension = - registry_->GetInstalledExtension(extension->id()); - bool is_update = false; - std::string old_name; - if (existing_extension) { - is_update = true; - old_name = existing_extension->name(); - } - registry_->TriggerOnWillBeInstalled(extension, is_update, old_name); - - // Unpacked extensions default to allowing file access, but if that has been - // overridden, don't reset the value. - if (Manifest::ShouldAlwaysAllowFileAccess(extension->location()) && - !extension_prefs_->HasAllowFileAccessSetting(extension->id())) { - extension_prefs_->SetAllowFileAccess(extension->id(), true); - } - - AddExtension(extension); - - // Notify observers that need to know when an installation is complete. - registry_->TriggerOnInstalled(extension, is_update); - - // Check extensions that may have been delayed only because this shared module - // was not available. - if (SharedModuleInfo::IsSharedModule(extension)) - MaybeFinishDelayedInstallations(); -} - const Extension* ExtensionService::GetPendingExtensionUpdate( const std::string& id) const { return delayed_installs_.GetByID(id); @@ -2299,17 +2259,8 @@ } void ExtensionService::UninstallMigratedExtensions() { - const ExtensionSet installed_extensions = - registry_->GenerateInstalledExtensionsSet(); - for (const std::string& extension_id : kObsoleteComponentExtensionIds) { - auto* extension = installed_extensions.GetByID(extension_id); - if (extension) { - UninstallExtension(extension_id, UNINSTALL_REASON_COMPONENT_REMOVED, - nullptr); - extension_prefs_->MarkObsoleteComponentExtensionAsRemoved( - extension->id(), extension->location()); - } - } + extension_registrar_.UninstallMigratedExtensions( + kObsoleteComponentExtensionIds); } void ExtensionService::OnDeveloperModePrefChanged() {
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index 8348081..24896cd 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h
@@ -482,7 +482,7 @@ #if defined(UNIT_TEST) void FinishInstallationForTest(const Extension* extension) { - FinishInstallation(extension); + extension_registrar_.FinishInstallation(extension); } void UninstallMigratedExtensionsForTest() { UninstallMigratedExtensions(); } @@ -552,7 +552,7 @@ ExtensionRegistrar::LoadErrorBehavior load_error_behavior) override; void ShowExtensionDisabledError(const Extension* extension, bool is_remote_install) override; - + void FinishDelayedInstallationsIfAny() override; bool CanAddExtension(const Extension* extension) override; bool CanEnableExtension(const Extension* extension) override; bool CanDisableExtension(const Extension* extension) override; @@ -595,9 +595,6 @@ const std::string& install_parameter, base::Value::Dict ruleset_install_prefs); - // Common helper to finish installing the given extension. - void FinishInstallation(const Extension* extension); - // Disables the extension if the privilege level has increased // (e.g., due to an upgrade). void CheckPermissionsIncrease(const Extension* extension,
diff --git a/chrome/browser/extensions/platform_test_extension_loader.cc b/chrome/browser/extensions/platform_test_extension_loader.cc index 21c8212e..747ce8b 100644 --- a/chrome/browser/extensions/platform_test_extension_loader.cc +++ b/chrome/browser/extensions/platform_test_extension_loader.cc
@@ -36,6 +36,9 @@ scoped_refptr<const Extension> PlatformTestExtensionLoader::LoadExtension( const base::FilePath& path) { + // Clean up the kMetadataFolder if necessary. + file_util::MaybeCleanupMetadataFolder(path); + scoped_refptr<const Extension> extension = LoadExtensionFromDirectory(path); if (!extension) { return nullptr;
diff --git a/chrome/browser/extensions/unpacked_installer.cc b/chrome/browser/extensions/unpacked_installer.cc index 32bee75f..dcc3ea2 100644 --- a/chrome/browser/extensions/unpacked_installer.cc +++ b/chrome/browser/extensions/unpacked_installer.cc
@@ -64,19 +64,6 @@ const char kImportMissing[] = "'import' extension is not installed."; const char kImportNotSharedModule[] = "'import' is not a shared module."; -// Deletes files reserved for use by the Extension system in the kMetadataFolder -// and the kMetadataFolder itself if it is empty. -void MaybeCleanupMetadataFolder(const base::FilePath& extension_path) { - const std::vector<base::FilePath> reserved_filepaths = - file_util::GetReservedMetadataFilePaths(extension_path); - for (const auto& file : reserved_filepaths) - base::DeletePathRecursively(file); - - const base::FilePath& metadata_dir = extension_path.Append(kMetadataFolder); - if (base::IsDirectoryEmpty(metadata_dir)) - base::DeletePathRecursively(metadata_dir); -} - } // namespace // static @@ -261,7 +248,7 @@ // Clean up the kMetadataFolder if necessary. This prevents spurious // warnings/errors and ensures we don't treat a user provided file as one by // the Extension system. - MaybeCleanupMetadataFolder(extension_path_); + file_util::MaybeCleanupMetadataFolder(extension_path_); // Treat presence of illegal filenames as a hard error for unpacked // extensions. Don't do so for command line extensions since this breaks
diff --git a/chrome/browser/extensions/web_accessible_resources_browsertest.cc b/chrome/browser/extensions/web_accessible_resources_browsertest.cc index ff94a09..0e3237f 100644 --- a/chrome/browser/extensions/web_accessible_resources_browsertest.cc +++ b/chrome/browser/extensions/web_accessible_resources_browsertest.cc
@@ -6,11 +6,10 @@ #include "base/strings/stringprintf.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" -#include "chrome/browser/extensions/extension_browsertest.h" +#include "build/build_config.h" +#include "chrome/browser/extensions/extension_platform_browsertest.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/test/base/ui_test_utils.h" #include "components/version_info/channel.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" @@ -18,12 +17,19 @@ #include "content/public/test/test_navigation_observer.h" #include "extensions/browser/background_script_executor.h" #include "extensions/common/constants.h" +#include "extensions/common/extension.h" #include "extensions/common/extension_features.h" +#include "extensions/common/features/feature_channel.h" #include "extensions/test/extension_test_message_listener.h" #include "extensions/test/test_extension_dir.h" #include "net/dns/mock_host_resolver.h" #include "testing/gmock/include/gmock/gmock.h" +#if !BUILDFLAG(IS_ANDROID) +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/ui_test_utils.h" +#endif + namespace extensions { namespace { static constexpr char kManifestStub[] = R"({ @@ -73,7 +79,7 @@ )"; // Exercise web accessible resources with experimental extension features. -class WebAccessibleResourcesBrowserTest : public ExtensionBrowserTest { +class WebAccessibleResourcesBrowserTest : public ExtensionPlatformBrowserTest { public: explicit WebAccessibleResourcesBrowserTest(bool enable_feature = true) { feature_list_.InitWithFeatureState( @@ -81,7 +87,7 @@ } void SetUpOnMainThread() override { - ExtensionBrowserTest::SetUpOnMainThread(); + ExtensionPlatformBrowserTest::SetUpOnMainThread(); host_resolver()->AddRule("*", "127.0.0.1"); EXPECT_TRUE(embedded_test_server()->Start()); } @@ -114,8 +120,8 @@ // Navigate to a test page and get the web contents. base::FilePath test_page; GURL gurl = embedded_test_server()->GetURL("example.com", "/simple.html"); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl)); - auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); + auto* web_contents = GetActiveWebContents(); + ASSERT_TRUE(content::NavigateToURL(web_contents, gurl)); std::string script = base::StringPrintf(kFetchResourceScriptTemplate, @@ -128,8 +134,11 @@ ASSERT_TRUE(content::EvalJs(web_contents, script).ExtractBool()); } +#if !BUILDFLAG(IS_ANDROID) // Exercise these resources being used in iframes in a web page. The navigation // flow goes through a different path than resource fetching. +// TODO(crbug.com/390687767): Port to desktop Android. Fails due to a navigation +// to about:blank#blocked. IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesBrowserTest, UseDynamicUrlInIframe) { // Load an extension that has one web accessible resource. @@ -194,6 +203,8 @@ // Tests that navigating a main frame via location.href works if and only if // the target resource is accessible to the main frame. // Regression test for https://crbug.com/374503948. +// TODO(crbug.com/390687767): Port to desktop Android. Fails due to a navigation +// to about:blank#blocked. IN_PROC_BROWSER_TEST_F( WebAccessibleResourcesBrowserTest, MainFrameLocationHrefUpdatesAreSubjectToAccessibleResources) { @@ -285,6 +296,7 @@ } } } +#endif // !BUILDFLAG(IS_ANDROID) // A test suite that will run both with and without the dynamic URL feature // enabled. @@ -300,9 +312,12 @@ ParameterizedWebAccessibleResourcesBrowserTest, testing::Bool()); +#if !BUILDFLAG(IS_ANDROID) // DNR, WAR, and use_dynamic_url with the extension feature. DNR does not // currently succeed when redirecting to a resource using use_dynamic_url with // query parameters. +// TODO(crbug.com/390687767): Port to desktop Android once chrome.runtime is +// fully ported. Right now the ExtensionTestMessageListener times out. IN_PROC_BROWSER_TEST_P(ParameterizedWebAccessibleResourcesBrowserTest, DeclarativeNetRequest) { ExtensionTestMessageListener listener("ready"); @@ -352,6 +367,7 @@ EXPECT_TRUE(navigation_observer.last_navigation_succeeded()); } } +#endif // !BUILDFLAG(IS_ANDROID) // If `use_dynamic_url` is set to true in manifest.json, then the associated web // accessible resource(s) can only be loaded using the dynamic url if using the @@ -369,8 +385,8 @@ // Navigate to a test page and get the web contents. base::FilePath test_page; GURL gurl = embedded_test_server()->GetURL("example.com", "/simple.html"); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl)); - auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); + auto* web_contents = GetActiveWebContents(); + ASSERT_TRUE(content::NavigateToURL(web_contents, gurl)); std::string script = base::StringPrintf(kFetchResourceScriptTemplate, @@ -397,11 +413,10 @@ ASSERT_TRUE(listener.WaitUntilSatisfied()); // Navigate to a non extension page. - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); + content::WebContents* web_contents = GetActiveWebContents(); GURL gurl = embedded_test_server()->GetURL("example.com", "/empty.html"); content::TestNavigationObserver navigation_observer(web_contents); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl)); + ASSERT_TRUE(content::NavigateToURL(web_contents, gurl)); ASSERT_TRUE(navigation_observer.last_navigation_succeeded()); EXPECT_EQ(gurl, web_contents->GetLastCommittedURL()); EXPECT_EQ(net::Error::OK, navigation_observer.last_net_error_code()); @@ -419,12 +434,11 @@ ASSERT_TRUE(listener.WaitUntilSatisfied()); // Navigate to a non extension page. - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); + content::WebContents* web_contents = GetActiveWebContents(); GURL gurl = embedded_test_server()->GetURL( "example.com", "/extensions/api_test/webrequest/script/index.html"); content::TestNavigationObserver navigation_observer(web_contents); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl)); + ASSERT_TRUE(content::NavigateToURL(web_contents, gurl)); ASSERT_TRUE(navigation_observer.last_navigation_succeeded()); EXPECT_EQ(gurl, web_contents->GetLastCommittedURL()); EXPECT_EQ(net::Error::OK, navigation_observer.last_net_error_code()); @@ -439,12 +453,11 @@ ASSERT_TRUE(extension); // Navigate to a non extension page. - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); + content::WebContents* web_contents = GetActiveWebContents(); GURL gurl = embedded_test_server()->GetURL("example.com", "/simple_with_script.html"); content::TestNavigationObserver navigation_observer(web_contents); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl)); + ASSERT_TRUE(content::NavigateToURL(web_contents, gurl)); ASSERT_TRUE(navigation_observer.last_navigation_succeeded()); EXPECT_EQ(gurl, web_contents->GetLastCommittedURL()); EXPECT_EQ(net::Error::OK, navigation_observer.last_net_error_code()); @@ -452,6 +465,9 @@ EXPECT_EQ("dnr redirect success", result.ExtractString()); } +#if !BUILDFLAG(IS_ANDROID) +// TODO(crbug.com/390687767): Port to desktop Android. Currently the redirect +// doesn't happen. class WebAccessibleResourcesBrowserRedirectTest : public WebAccessibleResourcesBrowserTest { protected: @@ -520,6 +536,7 @@ })", "Extensions.WAR.XOriginWebAccessible.MV3"); } +#endif // !BUILDFLAG(IS_ANDROID) } // namespace } // namespace extensions
diff --git a/chrome/browser/feedback/android/BUILD.gn b/chrome/browser/feedback/android/BUILD.gn index 324c3169..2c675b6 100644 --- a/chrome/browser/feedback/android/BUILD.gn +++ b/chrome/browser/feedback/android/BUILD.gn
@@ -68,6 +68,7 @@ "java/src/org/chromium/chrome/browser/feedback/SystemInfoFeedbackSource.java", "java/src/org/chromium/chrome/browser/feedback/UrlFeedbackSource.java", "java/src/org/chromium/chrome/browser/feedback/VariationsFeedbackSource.java", + "java/src/org/chromium/chrome/browser/feedback/VariationsStateFeedbackSource.java", ] deps = [ ":feedback_collector_java",
diff --git a/chrome/browser/feedback/android/java/src/org/chromium/chrome/browser/feedback/VariationsStateFeedbackSource.java b/chrome/browser/feedback/android/java/src/org/chromium/chrome/browser/feedback/VariationsStateFeedbackSource.java new file mode 100644 index 0000000..7c64b7c --- /dev/null +++ b/chrome/browser/feedback/android/java/src/org/chromium/chrome/browser/feedback/VariationsStateFeedbackSource.java
@@ -0,0 +1,25 @@ +// 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.feedback; + +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.components.variations.VariationsAssociatedData; + +import java.util.Map; + +/** Grabs feedback about the current command-line variations. */ +class VariationsStateFeedbackSource implements FeedbackSource { + private final boolean mIsOffTheRecord; + + VariationsStateFeedbackSource(Profile profile) { + mIsOffTheRecord = profile.isOffTheRecord(); + } + + @Override + public Map<String, String> getFeedback() { + if (mIsOffTheRecord) return null; + return VariationsAssociatedData.getVariationsStateFeedbackMap(); + } +}
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 554ce14..c0729644 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -3138,13 +3138,13 @@ { "name": "enable-hardware_mirror-mode", "owners": [ - "gildekel@chromium.org", + "vincentchiang@chromium.org", "//ui/display/OWNERS" ], // A temporary flag to control hardware mirroring until it is decided - // whether to permanently remove hardware mirroring. See crbug.com/1161556 - // for more details. - "expiry_milestone": 134 + // whether to permanently remove hardware mirroring. See b/207072219 for + // more details. + "expiry_milestone": 150 }, { "name": "enable-hardware-secure-decryption",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 4f5f051..5133f1e 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1546,6 +1546,12 @@ "When enabled, Chrome will attempt to connect to the system tracing " "service"; +const char kEnableWindowsGamingInputDataFetcherName[] = + "Enable Windows.Gaming.Input"; +const char kEnableWindowsGamingInputDataFetcherDescription[] = + "Enable Windows.Gaming.Input by default to provide game controller " + "support on Windows 10 desktop."; + const char kBlockInsecurePrivateNetworkRequestsName[] = "Block insecure private network requests."; const char kBlockInsecurePrivateNetworkRequestsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 99aa2c5..91f735e 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -806,6 +806,9 @@ extern const char kEnableNetworkLoggingToFileName[]; extern const char kEnableNetworkLoggingToFileDescription[]; +extern const char kEnableWindowsGamingInputDataFetcherName[]; +extern const char kEnableWindowsGamingInputDataFetcherDescription[]; + extern const char kBlockInsecurePrivateNetworkRequestsName[]; extern const char kBlockInsecurePrivateNetworkRequestsDescription[];
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 39a19b5..f06a78c 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
@@ -586,15 +586,15 @@ public static final CachedFlag sAndroidAppIntegration = newCachedFlag(ANDROID_APP_INTEGRATION, true); public static final CachedFlag sAndroidAppIntegrationModule = - newCachedFlag(ANDROID_APP_INTEGRATION_MODULE, false); + newCachedFlag(ANDROID_APP_INTEGRATION_MODULE, false, true); public static final CachedFlag sAndroidAppIntegrationV2 = - newCachedFlag(ANDROID_APP_INTEGRATION_V2, false); + newCachedFlag(ANDROID_APP_INTEGRATION_V2, false, true); public static final CachedFlag sAndroidTabSkipSaveTabsKillswitch = newCachedFlag(ANDROID_TAB_SKIP_SAVE_TABS_TASK_KILLSWITCH, true, true); public static final CachedFlag sNewTabPageCustomization = newCachedFlag(NEW_TAB_PAGE_CUSTOMIZATION, false); public static final CachedFlag sAndroidAppIntegrationWithFavicon = - newCachedFlag(ANDROID_APP_INTEGRATION_WITH_FAVICON, false); + newCachedFlag(ANDROID_APP_INTEGRATION_WITH_FAVICON, false, true); public static final CachedFlag sAndroidBottomToolbar = newCachedFlag(ANDROID_BOTTOM_TOOLBAR, false, true); public static final CachedFlag sAndroidElegantTextHeight =
diff --git a/chrome/browser/glic/border_view.cc b/chrome/browser/glic/border_view.cc index 2d40493..b008af28 100644 --- a/chrome/browser/glic/border_view.cc +++ b/chrome/browser/glic/border_view.cc
@@ -21,13 +21,8 @@ namespace glic { namespace { -// Note: | | | -// |<-- 5px -->|<-- 5px -->| -// | outside | visible | -// -// So only half of the full width are inside the visible viewport. -constexpr static int kBorderWidthMin = 2; -constexpr static int kBorderWidthMax = 10; +constexpr static int kBorderWidthMin = 1; +constexpr static int kBorderWidthMax = 5; constexpr static base::TimeDelta kAnimationDuration = base::Seconds(2); @@ -36,6 +31,10 @@ return (since_first_frame / kAnimationDuration) * (M_PI / 2); } +SkV4 SkRGBA4fToSkV4(SkRGBA4f<kPremul_SkAlphaType> color) { + return SkV4{color.fR, color.fG, color.fB, color.fA}; +} + } // namespace class BorderView::BorderViewUpdater { @@ -139,15 +138,43 @@ return; } - int border_width = - kBorderWidthMin + ((kBorderWidthMax - kBorderWidthMin) * progress_); + float border_width = + (kBorderWidthMin + ((kBorderWidthMax - kBorderWidthMin) * progress_)); + SkColor4f border_color = + SkColor4f::FromColor(GetColorProvider()->GetColor(ui::kColorSysPrimary)); + border_color.fA = progress_; + + const std::string_view kDrawRect(R"( + const float4 transparent = vec4(0); + uniform float2 u_top_left; + uniform float2 u_btm_right; + uniform float4 u_border_color; + vec4 main(float2 coord) { + if (all(greaterThanEqual(coord, u_top_left)) && + all(lessThan(coord, u_btm_right))) { + return transparent; + } else { + return u_border_color; + } + } + )"); + + std::vector<cc::PaintShader::Float2Uniform> float2_uniforms = { + {.name = SkString("u_top_left"), + .value = SkV2{bounds().origin().x() + border_width, + bounds().origin().y() + border_width}}, + {.name = SkString("u_btm_right"), + .value = SkV2{bounds().bottom_right().x() - border_width, + bounds().bottom_right().y() - border_width}}}; + std::vector<cc::PaintShader::Float4Uniform> float4_uniforms = { + {.name = SkString("u_border_color"), + .value = SkRGBA4fToSkV4(border_color.premul())}}; views::View::OnPaint(canvas); cc::PaintFlags flags; - flags.setStyle(cc::PaintFlags::kStroke_Style); - flags.setColor(GetColorProvider()->GetColor(ui::kColorSysPrimary)); - flags.setStrokeWidth(border_width); - flags.setAlphaf(progress_); + flags.setShader(cc::PaintShader::MakeSkSLCommand( + kDrawRect, /*float_uniforms=*/{}, std::move(float2_uniforms), + std::move(float4_uniforms))); canvas->DrawRect(gfx::RectF(bounds()), flags); }
diff --git a/chrome/browser/glic/border_view_browsertest.cc b/chrome/browser/glic/border_view_browsertest.cc index 320e5ac..61d5c15 100644 --- a/chrome/browser/glic/border_view_browsertest.cc +++ b/chrome/browser/glic/border_view_browsertest.cc
@@ -83,7 +83,7 @@ static SkBitmap ConstructExpectedBitmap(const gfx::Size& size, SkColor border_color, SkColor center_color, - int border_width, + float border_width, float alpha) { SkBitmap bitmap; SkImageInfo info = @@ -188,7 +188,7 @@ SkBitmap expected_bitmap = ConstructExpectedBitmap( capture_rect.size(), /*border_color=*/BorderColor(), - /*center_color=*/kBlack, /*border_width=*/2, /*alpha=*/0.f); + /*center_color=*/kBlack, /*border_width=*/2.f, /*alpha=*/0.f); EXPECT_TRUE(cc::MatchesBitmap( actual_bitmap, expected_bitmap, @@ -210,7 +210,7 @@ // The border width is calculated as: // `kBorderWidthMin` + ((`kBorderWidthMax` - `kBorderWidthMin`) * // `progress`). - int border_width = 2 + (8 * progress); + float border_width = 2 + (8 * progress); SkBitmap expected_bitmap = ConstructExpectedBitmap( capture_rect.size(), /*border_color=*/BorderColor(), @@ -231,7 +231,7 @@ SkBitmap expected_bitmap = ConstructExpectedBitmap(capture_rect.size(), /*border_color=*/BorderColor(), - /*center_color=*/kBlack, /*border_width=*/10, + /*center_color=*/kBlack, /*border_width=*/10.f, /*alpha=*/1.f); EXPECT_TRUE(cc::MatchesBitmap( @@ -248,7 +248,7 @@ SkBitmap expected_bitmap = ConstructExpectedBitmap( capture_rect.size(), /*border_color=*/BorderColor(), - /*center_color=*/kBlack, /*border_width=*/10, /*alpha=*/1.f); + /*center_color=*/kBlack, /*border_width=*/10.f, /*alpha=*/1.f); EXPECT_TRUE(cc::MatchesBitmap( actual_bitmap, expected_bitmap, @@ -297,7 +297,7 @@ SkBitmap expected_bitmap = ConstructExpectedBitmap( capture_rect.size(), /*border_color=*/BorderColor(), - /*center_color=*/kBlack, /*border_width=*/2, /*alpha=*/0.f); + /*center_color=*/kBlack, /*border_width=*/2.f, /*alpha=*/0.f); EXPECT_TRUE(cc::MatchesBitmap( actual_bitmap, expected_bitmap, @@ -311,7 +311,7 @@ SkBitmap actual_bitmap = PaintBorder(border); float progress = sin(0.125 * M_PI); - int border_width = 2 + (8 * progress); + float border_width = 2 + (8 * progress); SkBitmap expected_bitmap = ConstructExpectedBitmap( capture_rect.size(), /*border_color=*/BorderColor(), @@ -339,7 +339,7 @@ SkBitmap expected_bitmap = ConstructExpectedBitmap(capture_rect.size(), /*border_color=*/BorderColor(), - /*center_color=*/kBlack, /*border_width=*/2, + /*center_color=*/kBlack, /*border_width=*/2.f, /*alpha=*/0.f); EXPECT_TRUE(cc::MatchesBitmap( @@ -354,7 +354,7 @@ SkBitmap actual_bitmap = PaintBorder(border); float progress = sin(0.125 * M_PI); - int border_width = 2 + (8 * progress); + float border_width = 2 + (8 * progress); SkBitmap expected_bitmap = ConstructExpectedBitmap( capture_rect.size(), /*border_color=*/BorderColor(), @@ -396,7 +396,7 @@ SkBitmap expected_bitmap = ConstructExpectedBitmap( capture_rect.size(), /*border_color=*/BorderColor(), - /*center_color=*/kBlack, /*border_width=*/2, /*alpha=*/0.f); + /*center_color=*/kBlack, /*border_width=*/2.f, /*alpha=*/0.f); EXPECT_TRUE(cc::MatchesBitmap( actual_bitmap, expected_bitmap, @@ -424,7 +424,7 @@ SkBitmap expected_bitmap = ConstructExpectedBitmap( capture_rect.size(), /*border_color=*/BorderColor(), - /*center_color=*/kBlack, /*border_width=*/2, /*alpha=*/0.f); + /*center_color=*/kBlack, /*border_width=*/2.f, /*alpha=*/0.f); EXPECT_TRUE(cc::MatchesBitmap( actual_bitmap, expected_bitmap, @@ -436,7 +436,7 @@ SkBitmap actual_bitmap = PaintBorder(new_border); float progress = sin(0.25 * M_PI); - int border_width = 2 + (8 * progress); + float border_width = 2 + (8 * progress); SkBitmap expected_bitmap = ConstructExpectedBitmap( capture_rect.size(), /*border_color=*/BorderColor(),
diff --git a/chrome/browser/glic/glic_enabling.cc b/chrome/browser/glic/glic_enabling.cc index cb7da74..1ef9ad7 100644 --- a/chrome/browser/glic/glic_enabling.cc +++ b/chrome/browser/glic/glic_enabling.cc
@@ -27,7 +27,8 @@ return false; } - return profile->GetPrefs()->GetBoolean(glic::prefs::kGlicEnabledByPolicy); + return profile->GetPrefs()->GetInteger(glic::prefs::kGlicEnabledByPolicy) == + static_cast<int>(glic::prefs::EnabledByPolicyState::kEnabled); } glic::GlicEnabledStatus GlicEnabling::CheckEnabling() {
diff --git a/chrome/browser/glic/glic_policy_browsertest.cc b/chrome/browser/glic/glic_policy_browsertest.cc index ca8f56fc7..974fb557 100644 --- a/chrome/browser/glic/glic_policy_browsertest.cc +++ b/chrome/browser/glic/glic_policy_browsertest.cc
@@ -26,6 +26,7 @@ #include "content/public/test/browser_test.h" #include "content/public/test/test_navigation_observer.h" +using glic::prefs::EnabledByPolicyState; using glic::prefs::kGlicEnabledByPolicy; namespace glic { @@ -103,6 +104,11 @@ testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_for_profile_2_; + static constexpr int kEnabledValue = + static_cast<int>(EnabledByPolicyState::kEnabled); + static constexpr int kDisabledValue = + static_cast<int>(EnabledByPolicyState::kDisabled); + private: base::test::ScopedFeatureList scoped_feature_list_; }; @@ -111,19 +117,20 @@ // By default the pref should start off unmanaged and defaulted to enabled. PrefService* prefs = browser()->profile()->GetPrefs(); EXPECT_FALSE(prefs->IsManagedPreference(kGlicEnabledByPolicy)); - EXPECT_TRUE(prefs->GetBoolean(kGlicEnabledByPolicy)); + EXPECT_EQ(kEnabledValue, prefs->GetInteger(kGlicEnabledByPolicy)); // Verify that policy can force-disable Glic. PolicyMap policies; - policies.Set(key::kGlicEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, - POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(false), nullptr); + policies.Set(key::kGlicSettings, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(kDisabledValue), + nullptr); UpdateProviderPolicy(policies); EXPECT_TRUE(prefs->IsManagedPreference(kGlicEnabledByPolicy)); - EXPECT_FALSE(prefs->GetBoolean(kGlicEnabledByPolicy)); + EXPECT_EQ(kDisabledValue, prefs->GetInteger(kGlicEnabledByPolicy)); // Verify the policy value cannot be overridden. - prefs->SetBoolean(kGlicEnabledByPolicy, true); - EXPECT_FALSE(prefs->GetBoolean(kGlicEnabledByPolicy)); + prefs->SetInteger(kGlicEnabledByPolicy, kEnabledValue); + EXPECT_EQ(kDisabledValue, prefs->GetInteger(kGlicEnabledByPolicy)); } // Ensure that when policy disables Glic, a browser window doesn't show the Glic @@ -133,14 +140,17 @@ ASSERT_NE(profile_1_, profile_2_); // The pref defaults to enabled. - ASSERT_TRUE(profile_1_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kEnabledValue, + profile_1_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); // Disable the policy in the default profile. PolicyMap policies; - policies.Set(key::kGlicEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, - POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(false), nullptr); + policies.Set(key::kGlicSettings, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(kDisabledValue), + nullptr); UpdateProviderPolicy(policies); - ASSERT_FALSE(profile_1_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kDisabledValue, + profile_1_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); { // A new window in profile 1 shouldn't have the Glic button. @@ -154,10 +164,12 @@ } // Re-enable the policy. Ensure the button is recreated. - policies.Set(key::kGlicEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, - POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(true), nullptr); + policies.Set(key::kGlicSettings, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(kEnabledValue), + nullptr); UpdateProviderPolicy(policies); - ASSERT_TRUE(profile_1_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kEnabledValue, + profile_1_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); { // A new window in profile 1 should again get the Glic button now that the @@ -180,7 +192,8 @@ Browser* profile_2_window_2 = CreateBrowser(profile_2_); // The pref defaults to enabled. Ensure the button was created in each window. - ASSERT_TRUE(profile_1_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kEnabledValue, + profile_1_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); EXPECT_TRUE(GetGlicButtonForBrowser(profile_1_window_1)); EXPECT_TRUE(GetGlicButtonForBrowser(profile_1_window_2)); EXPECT_TRUE(GetGlicButtonForBrowser(profile_2_window_1)); @@ -188,10 +201,12 @@ // Disable the policy in the first profile. PolicyMap policies; - policies.Set(key::kGlicEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, - POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(false), nullptr); + policies.Set(key::kGlicSettings, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(kDisabledValue), + nullptr); UpdateProviderPolicy(policies); - ASSERT_FALSE(profile_1_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kDisabledValue, + profile_1_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); { // The windows in profile 1 should have lost their Glic button. @@ -204,10 +219,12 @@ } // Re-enable the policy. Ensure the button is recreated. - policies.Set(key::kGlicEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, - POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(true), nullptr); + policies.Set(key::kGlicSettings, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(kEnabledValue), + nullptr); UpdateProviderPolicy(policies); - ASSERT_TRUE(profile_1_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kEnabledValue, + profile_1_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); { // The windows in profile 1 should get back their Glic button. @@ -230,8 +247,10 @@ ASSERT_TRUE(new_window_profile_2); // The pref defaults to enabled. - ASSERT_TRUE(profile_1_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); - ASSERT_TRUE(profile_2_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kEnabledValue, + profile_1_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); + ASSERT_EQ(kEnabledValue, + profile_2_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); glic::GlicBackgroundModeManager* background_mode_manager = g_browser_process->GetFeatures()->glic_background_mode_manager(); @@ -240,11 +259,14 @@ // Disable the policy in the default profile. { PolicyMap policies; - policies.Set(key::kGlicEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, - POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(false), nullptr); + policies.Set(key::kGlicSettings, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(kDisabledValue), + nullptr); UpdateProviderPolicy(policies); - ASSERT_FALSE(profile_1_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); - ASSERT_TRUE(profile_2_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kDisabledValue, + profile_1_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); + ASSERT_EQ(kEnabledValue, + profile_2_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); } // Background mode should remain active since profile_2_ still has it enabled. @@ -253,11 +275,14 @@ // Disable the policy in the second profile. { PolicyMap policies; - policies.Set(key::kGlicEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, - POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(false), nullptr); + policies.Set(key::kGlicSettings, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(kDisabledValue), + nullptr); policy_for_profile_2_.UpdateChromePolicy(policies); - ASSERT_FALSE(profile_1_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); - ASSERT_FALSE(profile_2_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kDisabledValue, + profile_1_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); + ASSERT_EQ(kDisabledValue, + profile_2_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); } // Background mode should be exited since none of the loaded profiles enable @@ -267,11 +292,14 @@ // Enable the policy in the default profile again. { PolicyMap policies; - policies.Set(key::kGlicEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, - POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(true), nullptr); + policies.Set(key::kGlicSettings, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(kEnabledValue), + nullptr); UpdateProviderPolicy(policies); - ASSERT_TRUE(profile_1_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); - ASSERT_FALSE(profile_2_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kEnabledValue, + profile_1_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); + ASSERT_EQ(kDisabledValue, + profile_2_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); } // Background mode should be reentered since the first profile is enabled. @@ -282,11 +310,12 @@ IN_PROC_BROWSER_TEST_F(GlicPolicyTest, PolicyDisablesWebUi) { // Disable the policy. PolicyMap policies; - policies.Set(key::kGlicEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, - POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(false), nullptr); + policies.Set(key::kGlicSettings, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(kDisabledValue), + nullptr); UpdateProviderPolicy(policies); - ASSERT_FALSE( - browser()->profile()->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kDisabledValue, + browser()->profile()->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); GURL glic_url = GURL(chrome::kChromeUIGlicURL); @@ -303,10 +332,12 @@ } // Re-enable the policy. - policies.Set(key::kGlicEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, - POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(true), nullptr); + policies.Set(key::kGlicSettings, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(kEnabledValue), + nullptr); UpdateProviderPolicy(policies); - ASSERT_TRUE(profile_1_->GetPrefs()->GetBoolean(kGlicEnabledByPolicy)); + ASSERT_EQ(kEnabledValue, + profile_1_->GetPrefs()->GetInteger(kGlicEnabledByPolicy)); // Navigating to chrome://glic should now succeed. {
diff --git a/chrome/browser/glic/glic_pref_names.h b/chrome/browser/glic/glic_pref_names.h index 2282877..6a500406 100644 --- a/chrome/browser/glic/glic_pref_names.h +++ b/chrome/browser/glic/glic_pref_names.h
@@ -20,9 +20,17 @@ // ************* PROFILE PREFS *************** // Prefs below are tied to a user profile -// Boolean pref that determines whether Glic is enabled for this user profile. +// Integer pref that determines whether Glic is enabled for this user profile. // This is controlled from enterprise policy. inline constexpr char kGlicEnabledByPolicy[] = "glic.enabled_by_policy"; +enum class EnabledByPolicyState { + kMinValue = 0, + + kEnabled = kMinValue, + kDisabled = 1, + + kMaxValue = kDisabled +}; // Boolean pref that enables or disables geolocation access for Glic. inline constexpr char kGlicGeolocationEnabled[] = "glic.geolocation_enabled";
diff --git a/chrome/browser/glic/glic_profile_configuration.cc b/chrome/browser/glic/glic_profile_configuration.cc index 1585af8..4b918cec 100644 --- a/chrome/browser/glic/glic_profile_configuration.cc +++ b/chrome/browser/glic/glic_profile_configuration.cc
@@ -36,7 +36,9 @@ // static void GlicProfileConfiguration::RegisterProfilePrefs( PrefRegistrySimple* registry) { - registry->RegisterBooleanPref(prefs::kGlicEnabledByPolicy, true); + registry->RegisterIntegerPref( + prefs::kGlicEnabledByPolicy, + static_cast<int>(prefs::EnabledByPolicyState::kEnabled)); registry->RegisterBooleanPref(prefs::kGlicMicrophoneEnabled, false); registry->RegisterBooleanPref(prefs::kGlicGeolocationEnabled, false); registry->RegisterBooleanPref(prefs::kGlicTabContextEnabled, false); @@ -44,12 +46,13 @@ } bool GlicProfileConfiguration::IsEnabledByPolicy() const { - return profile_->GetPrefs()->GetBoolean(prefs::kGlicEnabledByPolicy); + return profile_->GetPrefs()->GetInteger(prefs::kGlicEnabledByPolicy) == + static_cast<int>(prefs::EnabledByPolicyState::kEnabled); } void GlicProfileConfiguration::OnEnabledByPolicyChanged() { // Note: the pref listener can sometimes fire even if the value from - // GetBoolean doesn't change (e.g. value was set from multiple sources). See + // GetInteger doesn't change (e.g. value was set from multiple sources). See // GlicPolicyTest.PrefDisabledByPolicy for an example. for (Browser* const browser : *BrowserList::GetInstance()) { if (browser->profile() == &profile_.get()) {
diff --git a/chrome/browser/glic/glic_view.cc b/chrome/browser/glic/glic_view.cc index bac3c8f..1337bf44 100644 --- a/chrome/browser/glic/glic_view.cc +++ b/chrome/browser/glic/glic_view.cc
@@ -43,7 +43,6 @@ views::Widget::InitParams params( views::Widget::InitParams::CLIENT_OWNS_WIDGET, views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); - params.opacity = views::Widget::InitParams::WindowOpacity::kOpaque; params.remove_standard_frame = true; #if BUILDFLAG(IS_WIN) params.dont_show_in_taskbar = true; @@ -79,4 +78,10 @@ return false; } +void GlicView::AnimateFrameBounds(const gfx::Rect& bounds) { + bounds_change_animation_ = + std::make_unique<BrowserFrameBoundsChangeAnimation>(*GetWidget(), bounds); + bounds_change_animation_->Start(); +} + } // namespace glic
diff --git a/chrome/browser/glic/glic_view.h b/chrome/browser/glic/glic_view.h index 9570bf2..a641d11 100644 --- a/chrome/browser/glic/glic_view.h +++ b/chrome/browser/glic/glic_view.h
@@ -44,6 +44,9 @@ views::WebView* web_view() { return web_view_; } + // Sets the bounds of the widget with animation + void AnimateFrameBounds(const gfx::Rect& bounds); + private: raw_ptr<views::WebView> web_view_;
diff --git a/chrome/browser/glic/glic_window_controller.cc b/chrome/browser/glic/glic_window_controller.cc index 3858a325..27075b7 100644 --- a/chrome/browser/glic/glic_window_controller.cc +++ b/chrome/browser/glic/glic_window_controller.cc
@@ -43,9 +43,9 @@ // to a browser's glic button to attach to said browser. constexpr static int kAttachmentDistanceThreshold = 50; -constexpr static int kWidgetDefaultWidth = 400; +constexpr static int kWidgetWidth = 400; +constexpr static int kWidgetHeight = 800; constexpr static int kWidgetTopBarHeight = 80; -static constexpr int kEntryDurationMs = 300; class ContentsAndProfileKeepAlive : public content::WebContentsDelegate { public: @@ -216,11 +216,7 @@ if (glic_window_widget_ || will_show_) { return; } - - if (!contents_) { - contents_ = std::make_unique<ContentsAndProfileKeepAlive>(profile_, this); - } - + int padding; gfx::Point top_right_point; will_show_ = true; if (!glic_button_view) { @@ -229,6 +225,7 @@ // TODO(crbug.com/384061064): Add more logic for when the glic window should // show up in a detached state. top_right_point = GetTopRightPositionForDetachedGlicWindow(); + padding = 50; button_widget_for_browser_attachment_ = nullptr; } else { // If summoned from the tab strip button. This will always show up attached @@ -236,49 +233,37 @@ // window. top_right_point = GetTopRightPositionForAttachedGlicWindow(glic_button_view); + padding = GetLayoutConstant(TAB_STRIP_PADDING); button_widget_for_browser_attachment_ = glic_button_view->GetWidget()->GetWeakPtr(); } - gfx::Size default_widget_size(kWidgetDefaultWidth, kWidgetTopBarHeight); - if (final_widget_bounds_.IsEmpty()) { - final_widget_bounds_.set_size(default_widget_size); + glic_window_widget_ = glic::GlicView::CreateWidget( + profile_, {top_right_point.x() - kWidgetWidth - padding, + top_right_point.y() + padding, kWidgetWidth, kWidgetHeight}); + + GlicView* glic_view = GlicView::FromWidget(*glic_window_widget_); + if (!contents_) { + contents_ = std::make_unique<ContentsAndProfileKeepAlive>(profile_, this); } - - gfx::Rect glic_window_widget_initial_rect = - glic_button_view->GetBoundsInScreen(); - - glic_window_widget_ = - glic::GlicView::CreateWidget(profile_, glic_window_widget_initial_rect); + glic_view->web_view()->SetWebContents(contents_->web_contents()); glic_window_widget_->AddObserver(this); glic_widget_observer_ = std::make_unique<GlicWidgetObserver>(this, glic_window_widget_.get()); - glic_window_widget_->Show(); - - if (button_widget_for_browser_attachment_) { - Browser* browser = chrome::FindBrowserWithWindow( - button_widget_for_browser_attachment_->GetNativeWindow()); - AttachToBrowser(browser); - // Set target bounds for animation and run the open attached animation. - gfx::Rect target_bounds = glic_window_widget_->GetWindowBoundsInScreen(); - int final_x = top_right_point.x() - kWidgetDefaultWidth; - target_bounds.set_x(final_x); - target_bounds.set_width(kWidgetDefaultWidth); - target_bounds.set_height(final_widget_bounds_.height()); - - // TODO(crbug.com/389982576): Match the background color of the widget with - // the web client background. - GetGlicView()->SetBackground( - views::CreateRoundedRectBackground(SK_ColorBLACK, 12)); - AnimateBounds( - target_bounds, base::Milliseconds(kEntryDurationMs), - base::BindOnce(&GlicWindowController::SetWebContents, GetWeakPtr())); - } else { - SetWebContents(); - MaybeCreateHolderWindowAndReparent(); - } + // This is used to handle the case where the native window is closed + // directly (e.g., Windows context menu close on the title bar). The widget + // can't be deleted by the OnWidgetDestroyed notification because the widget + // code doesn't support that. + glic_window_widget_->widget_delegate()->RegisterDeleteDelegateCallback( + base::BindOnce( + [](const base::WeakPtr<GlicWindowController>& weak_this) { + if (weak_this) { + weak_this->Close(); + } + }, + weak_ptr_factory_.GetWeakPtr())); // If the web client is already initialized, go to phase 2. Otherwise, wait // for the web client to initialize. @@ -306,20 +291,31 @@ void GlicWindowController::ShowFinish() { will_show_ = false; - if (!glic_window_widget_) { + if (!glic_window_widget_ || glic_window_widget_->IsVisible()) { return; } + if (button_widget_for_browser_attachment_) { + glic_window_widget_->Show(); + Browser* browser = chrome::FindBrowserWithWindow( + button_widget_for_browser_attachment_->GetNativeWindow()); + AttachToBrowser(browser); + } else { + // Be sure to reparent the widget and set its state first before showing it. + MaybeCreateHolderWindowAndReparent(); +#if BUILDFLAG(IS_MAC) + // Be careful to not activate, so that in case Chromium isn't the front-most + // app it's not brought to the front. + glic_window_widget_->ShowInactive(); +#else + glic_window_widget_->Show(); +#endif + } + window_event_observer_ = std::make_unique<WindowEventObserver>(this, GetGlicView()); - // Set the draggable area to the top bar of the window, by default. - GetGlicView()->SetDraggableAreas( - {{0, 0, final_widget_bounds_.width(), kWidgetTopBarHeight}}); -} - -void GlicWindowController::SetWebContents() { - GetGlicView()->web_view()->SetWebContents(contents_->web_contents()); + GetGlicView()->SetDraggableAreas({{0, 0, kWidgetWidth, kWidgetTopBarHeight}}); } GlicView* GlicWindowController::GetGlicView() { @@ -376,11 +372,9 @@ // moves to the top right of the display. gfx::Size screen_size = display::Screen::GetScreen()->GetPrimaryDisplay().GetSizeInPixel(); - final_widget_bounds_.set_origin( - gfx::Point(screen_size.width() - final_widget_bounds_.width(), 0)); - AnimateBounds( - final_widget_bounds_, base::Milliseconds(kEntryDurationMs), - base::BindOnce(&GlicWindowController::ResizeFinished, GetWeakPtr())); + gfx::Rect bounds = glic_window_widget_->GetWindowBoundsInScreen(); + bounds.set_origin(gfx::Point(screen_size.width() - bounds.width(), 0)); + GetGlicView()->AnimateFrameBounds(bounds); } void GlicWindowController::AttachToBrowser(Browser* browser) { @@ -414,30 +408,14 @@ } bool GlicWindowController::Resize(const gfx::Size& size) { - final_widget_bounds_.set_size(size); - if (!glic_window_widget_) { return false; } - - AnimateBounds( - final_widget_bounds_, base::Milliseconds(0), - base::BindOnce(&GlicWindowController::ResizeFinished, GetWeakPtr())); - - return true; -} - -void GlicWindowController::AnimateBounds(const gfx::Rect& target_bounds, - base::TimeDelta duration, - base::OnceClosure callback) { - if (!glic_window_widget_) { - return; - } - // TODO(iwells): Set animation duration based on value set by client. window_resize_animation_ = std::make_unique<GlicWindowResizeAnimation>( - glic_window_widget_.get(), target_bounds, - /*duration=*/duration, std::move(callback)); + glic_window_widget_.get(), size, /*duration=*/base::Milliseconds(0), + base::BindOnce(&GlicWindowController::ResizeFinished, GetWeakPtr())); + return true; } gfx::Size GlicWindowController::GetSize() { @@ -592,21 +570,21 @@ CHECK(glic_button); attached_browser_ = browser->AsWeakPtr(); + gfx::Rect glic_rect = glic_window_widget_->GetWindowBoundsInScreen(); // TODO(andreaxg): Fix exact attachment position. gfx::Rect glic_button_rect = glic_button->GetBoundsInScreen(); gfx::Point top_right = glic_button_rect.top_right(); int tab_strip_padding = GetLayoutConstant(TAB_STRIP_PADDING); - final_widget_bounds_.set_x(top_right.x() - final_widget_bounds_.width() - - tab_strip_padding); - final_widget_bounds_.set_y(top_right.y() + tab_strip_padding); + glic_rect.set_x(top_right.x() - glic_rect.width() - tab_strip_padding); + glic_rect.set_y(top_right.y() + tab_strip_padding); // Avoid conversions between pixels and DIP on non 1.0 scale factor displays // changing widget width and height. + glic_rect.set_width(kWidgetWidth); + glic_rect.set_height(kWidgetHeight); if (animate) { - AnimateBounds( - final_widget_bounds_, base::Milliseconds(kEntryDurationMs), - base::BindOnce(&GlicWindowController::SetWebContents, GetWeakPtr())); + GetGlicView()->AnimateFrameBounds(glic_rect); } else { - glic_window_widget_->SetBounds(final_widget_bounds_); + glic_window_widget_->SetBounds(glic_rect); } NotifyIfPanelStateChanged(); }
diff --git a/chrome/browser/glic/glic_window_controller.h b/chrome/browser/glic/glic_window_controller.h index 1078700..77942130 100644 --- a/chrome/browser/glic/glic_window_controller.h +++ b/chrome/browser/glic/glic_window_controller.h
@@ -54,8 +54,6 @@ // shows the glic window. void Show(views::View* glic_button_view); - void OnShowAnimationCompleted(); - // Attaches glic to the last focused Chrome window. void Attach(); @@ -127,8 +125,6 @@ void ShowPhase2(); void ShowFinish(); - void SetWebContents(); - // Determines the correct position for the glic window when attached to a // browser window. gfx::Point GetTopRightPositionForAttachedGlicWindow( @@ -203,13 +199,6 @@ // Called when the programmatic resize has finished. void ResizeFinished(); - // Sets target bounds for the widget and creates a WindowResizeAnimation - // instance to begin a new animation. Blocks any calls to animate if the - // widget it not yet visible. - void AnimateBounds(const gfx::Rect& target_bounds, - base::TimeDelta duration, - base::OnceClosure callback); - AttachedTargetWidgetObserver attached_target_widget_observer_{this}; base::WeakPtr<Browser> attached_browser_; @@ -234,8 +223,6 @@ std::unique_ptr<GlicWindowResizeAnimation> window_resize_animation_; bool glic_window_widget_visible_ = false; - gfx::Rect final_widget_bounds_; - // Indicates `Show()` has been called, but not `FinishShow()`. bool will_show_ = false; // While `will_show_` is true, this is the button widget on the browser window
diff --git a/chrome/browser/glic/glic_window_resize_animation.cc b/chrome/browser/glic/glic_window_resize_animation.cc index e1214d0b..395d859 100644 --- a/chrome/browser/glic/glic_window_resize_animation.cc +++ b/chrome/browser/glic/glic_window_resize_animation.cc
@@ -19,13 +19,13 @@ GlicWindowResizeAnimation::GlicWindowResizeAnimation( views::Widget* widget, - const gfx::Rect& target_bounds, + gfx::Size new_size, base::TimeDelta duration, FinishedCallback finished_callback) : gfx::LinearAnimation(duration, kDefaultFrameRate, this), widget_(widget), - initial_bounds_(widget->GetWindowBoundsInScreen()), - new_bounds_(target_bounds), + initial_size_(widget->GetWindowBoundsInScreen().size()), + new_size_(new_size), finished_callback_(std::move(finished_callback)) { // TODO(crbug.com/389238233): CompositorAnimationRunner does not appear to // be fully functional. @@ -41,9 +41,9 @@ GlicWindowResizeAnimation::~GlicWindowResizeAnimation() = default; void GlicWindowResizeAnimation::AnimateToState(double state) { - widget_->SetBounds(gfx::Tween::RectValueBetween( + widget_->SetSize(gfx::Tween::SizeValueBetween( gfx::Tween::CalculateValue(gfx::Tween::EASE_IN_OUT_EMPHASIZED, state), - initial_bounds_, new_bounds_)); + initial_size_, new_size_)); } void GlicWindowResizeAnimation::AnimationEnded(const Animation* animation) {
diff --git a/chrome/browser/glic/glic_window_resize_animation.h b/chrome/browser/glic/glic_window_resize_animation.h index 8ad2d0b02..5c255fd5 100644 --- a/chrome/browser/glic/glic_window_resize_animation.h +++ b/chrome/browser/glic/glic_window_resize_animation.h
@@ -30,7 +30,7 @@ // FinishedCallback. FinishedCallback is always invoked asynchronously. using FinishedCallback = base::OnceClosure; GlicWindowResizeAnimation(views::Widget* widget, - const gfx::Rect& target_bounds, + gfx::Size new_size, base::TimeDelta duration, FinishedCallback finished_callback); GlicWindowResizeAnimation(const GlicWindowResizeAnimation&) = delete; @@ -43,8 +43,8 @@ private: const raw_ptr<views::Widget> widget_; - const gfx::Rect initial_bounds_; - const gfx::Rect new_bounds_; + const gfx::Size initial_size_; + const gfx::Size new_size_; FinishedCallback finished_callback_; base::WeakPtrFactory<GlicWindowResizeAnimation> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/glic/launcher/OWNERS b/chrome/browser/glic/launcher/OWNERS new file mode 100644 index 0000000..f6b08bc --- /dev/null +++ b/chrome/browser/glic/launcher/OWNERS
@@ -0,0 +1,4 @@ +agale@chromium.org +charlesmeng@chromium.org +estalin@chromium.org +stluong@chromium.org
diff --git a/chrome/browser/glic/launcher/glic_background_mode_manager.cc b/chrome/browser/glic/launcher/glic_background_mode_manager.cc index 254247e9..821114b 100644 --- a/chrome/browser/glic/launcher/glic_background_mode_manager.cc +++ b/chrome/browser/glic/launcher/glic_background_mode_manager.cc
@@ -33,8 +33,9 @@ : configuration_(std::make_unique<GlicLauncherConfiguration>(this)), controller_(std::make_unique<GlicController>()), status_tray_(status_tray), - enabled_pref_(configuration_->IsEnabled()), - expected_registered_hotkey_(configuration_->GetGlobalHotkey()) { + enabled_pref_(GlicLauncherConfiguration::IsEnabled()), + expected_registered_hotkey_( + GlicLauncherConfiguration::GetGlobalHotkey()) { UpdateState(); g_browser_process->profile_manager()->AddObserver(this); }
diff --git a/chrome/browser/glic/launcher/glic_launcher_configuration.cc b/chrome/browser/glic/launcher/glic_launcher_configuration.cc index 5e66fc4e4..ba188673 100644 --- a/chrome/browser/glic/launcher/glic_launcher_configuration.cc +++ b/chrome/browser/glic/launcher/glic_launcher_configuration.cc
@@ -50,11 +50,13 @@ .Set(kHotkeyModifiers, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)); } +// static bool GlicLauncherConfiguration::IsEnabled() { return g_browser_process->local_state()->GetBoolean( prefs::kGlicLauncherEnabled); } +// static ui::Accelerator GlicLauncherConfiguration::GetGlobalHotkey() { const base::Value::Dict& hotkey_dictionary = g_browser_process->local_state()->GetDict(
diff --git a/chrome/browser/glic/launcher/glic_launcher_configuration.h b/chrome/browser/glic/launcher/glic_launcher_configuration.h index d36a98e..653e41b9 100644 --- a/chrome/browser/glic/launcher/glic_launcher_configuration.h +++ b/chrome/browser/glic/launcher/glic_launcher_configuration.h
@@ -32,9 +32,9 @@ static void RegisterLocalStatePrefs(PrefRegistrySimple* registry); - bool IsEnabled(); + static bool IsEnabled(); - ui::Accelerator GetGlobalHotkey(); + static ui::Accelerator GetGlobalHotkey(); private: void OnEnabledPrefChanged();
diff --git a/chrome/browser/glic/launcher/glic_status_icon.cc b/chrome/browser/glic/launcher/glic_status_icon.cc index 2d9398c45..60175c61 100644 --- a/chrome/browser/glic/launcher/glic_status_icon.cc +++ b/chrome/browser/glic/launcher/glic_status_icon.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/glic/launcher/glic_status_icon.h" +#include <memory> #include <optional> #include "chrome/app/chrome_command_ids.h" @@ -90,8 +91,10 @@ context_menu_ = nullptr; if (status_icon_) { status_icon_->RemoveObserver(this); - status_tray_->RemoveStatusIcon(status_icon_); + std::unique_ptr<StatusIcon> removed_icon = + status_tray_->RemoveStatusIcon(status_icon_); status_icon_ = nullptr; + removed_icon.reset(); } status_tray_ = nullptr; }
diff --git a/chrome/browser/glic/launcher/glic_status_icon.h b/chrome/browser/glic/launcher/glic_status_icon.h index bccd32b..a374636 100644 --- a/chrome/browser/glic/launcher/glic_status_icon.h +++ b/chrome/browser/glic/launcher/glic_status_icon.h
@@ -47,8 +47,7 @@ native_theme_observer_{this}; raw_ptr<StatusTray> status_tray_; - // TODO(crbug.com/390463341): Figure out how to not dangle this pointer. - raw_ptr<StatusIcon, DanglingUntriaged> status_icon_; + raw_ptr<StatusIcon> status_icon_; raw_ptr<StatusIconMenuModel> context_menu_; };
diff --git a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterCoordinatorTest.java b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterCoordinatorTest.java index d3a6a3b5..3d4d089 100644 --- a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterCoordinatorTest.java +++ b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterCoordinatorTest.java
@@ -11,7 +11,6 @@ import static org.chromium.chrome.browser.history.AppFilterCoordinator.MAX_VISIBLE_ITEM_COUNT; import android.app.Activity; -import android.graphics.Color; import android.graphics.drawable.Drawable; import android.view.ViewGroup; @@ -98,10 +97,7 @@ ViewGroup activityContentView = getActivity().findViewById(android.R.id.content); ScrimCoordinator scrimCoordinator = new ScrimCoordinator( - getActivity(), - /* systemUiScrimDelegate= */ null, - activityContentView, - Color.WHITE); + getActivity(), /* systemUiScrimDelegate= */ null, activityContentView); return BottomSheetControllerFactory.createBottomSheetController( () -> scrimCoordinator, (unused) -> {},
diff --git a/chrome/browser/hub/BUILD.gn b/chrome/browser/hub/BUILD.gn index 44c772877..5fdef2d6 100644 --- a/chrome/browser/hub/BUILD.gn +++ b/chrome/browser/hub/BUILD.gn
@@ -140,5 +140,6 @@ "//third_party/mockito:mockito_java", "//ui/android:ui_java_test_support", "//ui/android:ui_no_recycler_view_java", + "//ui/android:ui_unit_device_javatests", ] }
diff --git a/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/HubLayoutScrimController.java b/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/HubLayoutScrimController.java index 532b795..206963c 100644 --- a/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/HubLayoutScrimController.java +++ b/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/HubLayoutScrimController.java
@@ -76,7 +76,9 @@ } private void onIncognitoChange(Boolean ignored) { - mPropertyModel.set(ScrimProperties.BACKGROUND_COLOR, calculateScrimColor()); + if (mPropertyModel == null) return; + + mScrimCoordinator.setScrimColor(calculateScrimColor(), mPropertyModel); } private @ColorInt int calculateScrimColor() {
diff --git a/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/HubLayoutScrimControllerUnitTest.java b/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/HubLayoutScrimControllerUnitTest.java index 0490c52..d759f0c 100644 --- a/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/HubLayoutScrimControllerUnitTest.java +++ b/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/HubLayoutScrimControllerUnitTest.java
@@ -13,7 +13,6 @@ import static org.mockito.Mockito.verify; import android.app.Activity; -import android.graphics.Color; import android.view.View; import android.widget.FrameLayout; @@ -73,8 +72,7 @@ mAnchorView = new View(mActivity); rootView.addView(mAnchorView); - mScrimCoordinator = - spy(new ScrimCoordinator(mActivity, mScrimDelegate, rootView, Color.RED)); + mScrimCoordinator = spy(new ScrimCoordinator(mActivity, mScrimDelegate, rootView)); mIsIncognitoSupplier = new ObservableSupplierImpl<>(false);
diff --git a/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/ShrinkExpandAnimatorRenderTest.java b/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/ShrinkExpandAnimatorRenderTest.java index 30408f3..0d138c9 100644 --- a/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/ShrinkExpandAnimatorRenderTest.java +++ b/chrome/browser/hub/android/java/src/org/chromium/chrome/browser/hub/ShrinkExpandAnimatorRenderTest.java
@@ -37,12 +37,11 @@ import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; +import org.chromium.ui.animation.RenderTestAnimationUtils; import org.chromium.ui.test.util.BlankUiTestActivity; import org.chromium.ui.test.util.NightModeTestUtils; import org.chromium.ui.test.util.RenderTestRule; -import java.util.Locale; - /** Render tests for {@link ShrinkExpandAnimator}. */ // TODO(crbug.com/40286625): Move to hub/internal/ once TabSwitcherLayout no longer depends on this. @RunWith(BaseJUnit4ClassRunner.class) @@ -67,6 +66,12 @@ private FrameLayout mRootView; private ShrinkExpandImageView mView; + // Retains a strong reference to the {@link ShrinkExpandAnimator} on the class to prevent it + // from being prematurely GC'd during {@link RenderTestAnimationUtils#stepThroughAnimation}. The + // {@link ObjectAnimator} only retains a {@link java.lang.ref.WeakReference} to the object, + // meaning it could be GC'd anytime after changing stack frames. + private ShrinkExpandAnimator mAnimator; + @BeforeClass public static void setupSuite() { sActivity = sActivityTestRule.launchActivity(null); @@ -121,13 +126,21 @@ startX + thumbnailSize.getWidth(), startY + thumbnailSize.getHeight()); - setupShrinkExpandImageView(startValue); - ShrinkExpandAnimator animator = - createAnimator(startValue, endValue, thumbnailSize, /* searchBoxHeight= */ 0); - Rect startValueCopy = new Rect(startValue); Rect endValueCopy = new Rect(endValue); + setupShrinkExpandImageView(startValue); + mAnimator = createAnimator(startValue, endValue, thumbnailSize, /* searchBoxHeight= */ 0); + ObjectAnimator expandAnimator = + ThreadUtils.runOnUiThreadBlocking( + () -> + ObjectAnimator.ofObject( + mAnimator, + ShrinkExpandAnimator.RECT, + new RectEvaluator(), + startValueCopy, + endValueCopy)); + // Verify changing rects after doesn't cause ShrinkExpandAnimator to behave differently. startValue.left = 0; startValue.right = 10; @@ -138,8 +151,8 @@ endValue.top = 100; endValue.bottom = 200; - stepThroughAnimation( - "expand_rect", animator, startValueCopy, endValueCopy, ANIMATION_STEPS); + RenderTestAnimationUtils.stepThroughAnimation( + "expand_rect", mRenderTestRule, mRootView, expandAnimator, ANIMATION_STEPS); } @Test @@ -162,11 +175,23 @@ Math.round(thumbnailSize.getHeight() / 2.0f)); setupShrinkExpandImageView(startValue); - ShrinkExpandAnimator animator = - createAnimator(startValue, endValue, thumbnailSize, /* searchBoxHeight= */ 0); + mAnimator = createAnimator(startValue, endValue, thumbnailSize, /* searchBoxHeight= */ 0); + ObjectAnimator expandAnimator = + ThreadUtils.runOnUiThreadBlocking( + () -> + ObjectAnimator.ofObject( + mAnimator, + ShrinkExpandAnimator.RECT, + new RectEvaluator(), + startValue, + endValue)); - stepThroughAnimation( - "expand_rect_with_top_clip", animator, startValue, endValue, ANIMATION_STEPS); + RenderTestAnimationUtils.stepThroughAnimation( + "expand_rect_with_top_clip", + mRenderTestRule, + mRootView, + expandAnimator, + ANIMATION_STEPS); } @Test @@ -190,14 +215,22 @@ Math.round(thumbnailSize.getHeight() / 2.0f)); setupShrinkExpandImageView(startValue); - ShrinkExpandAnimator animator = - createAnimator(startValue, endValue, thumbnailSize, SEARCH_BOX_HEIGHT); + mAnimator = createAnimator(startValue, endValue, thumbnailSize, SEARCH_BOX_HEIGHT); + ObjectAnimator expandAnimator = + ThreadUtils.runOnUiThreadBlocking( + () -> + ObjectAnimator.ofObject( + mAnimator, + ShrinkExpandAnimator.RECT, + new RectEvaluator(), + startValue, + endValue)); - stepThroughAnimation( + RenderTestAnimationUtils.stepThroughAnimation( "expand_rect_with_top_clip_hub_search", - animator, - startValue, - endValue, + mRenderTestRule, + mRootView, + expandAnimator, ANIMATION_STEPS); } @@ -222,10 +255,19 @@ endY + thumbnailSize.getHeight()); setupShrinkExpandImageView(startValue); - ShrinkExpandAnimator animator = - createAnimator(startValue, endValue, thumbnailSize, /* searchBoxHeight= */ 0); + mAnimator = createAnimator(startValue, endValue, thumbnailSize, /* searchBoxHeight= */ 0); + ObjectAnimator shrinkAnimator = + ThreadUtils.runOnUiThreadBlocking( + () -> + ObjectAnimator.ofObject( + mAnimator, + ShrinkExpandAnimator.RECT, + new RectEvaluator(), + startValue, + endValue)); - stepThroughAnimation("shrink_rect_rect", animator, startValue, endValue, ANIMATION_STEPS); + RenderTestAnimationUtils.stepThroughAnimation( + "shrink_rect_rect", mRenderTestRule, mRootView, shrinkAnimator, ANIMATION_STEPS); } private ShrinkExpandAnimator createAnimator( @@ -240,59 +282,13 @@ }); } - /** Returns a thumbnail size 1/4 the size of {@link mRootView}. */ + /** Returns a thumbnail size 1/4 the size of {@link #mRootView}. */ private Size getThumbnailSize() { return new Size( Math.round(mRootView.getWidth() / 4.0f), Math.round(mRootView.getHeight() / 4.0f)); } /** - * Steps through an animation. - * - * @param testcaseName The base name for the render test results. - * @param rectAnimator The animator to drive the animation of. - * @param startValue The initial react. - * @param endValue The final rect. - * @param steps The number of steps to take. Must be 2 or more. - */ - private void stepThroughAnimation( - String testcaseName, - ShrinkExpandAnimator rectAnimator, - Rect startValue, - Rect endValue, - int steps) - throws Exception { - assert steps >= 2; - float fractionPerStep = 1.0f / (steps - 1); - - ObjectAnimator animator = - ThreadUtils.runOnUiThreadBlocking( - () -> { - return ObjectAnimator.ofObject( - rectAnimator, - ShrinkExpandAnimator.RECT, - new RectEvaluator(), - startValue, - endValue); - }); - - // Manually drive the animation instead of using an ObjectAnimator for exact control over - // step size and timing. - for (int step = 0; step < steps; step++) { - final float animationFraction = fractionPerStep * step; - ThreadUtils.runOnUiThreadBlocking( - () -> { - animator.setCurrentFraction(animationFraction); - }); - - mRenderTestRule.render( - mRootView, - testcaseName - + String.format(Locale.ENGLISH, "_step_%d_of_%d", step + 1, steps)); - } - } - - /** * Sets the initial position of the image view. * * @param startValue The rect to position the image view at. @@ -321,7 +317,7 @@ onNextLayout.waitForNext(); } - /** Returns a blue checkerboard bitmap the size of {@link mRootView}. */ + /** Returns a blue checkerboard bitmap the size of {@link #mRootView}. */ private Bitmap createBitmap() { int width = mRootView.getWidth(); int height = mRootView.getHeight();
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java index 6b25f3b..2e82cd1 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java
@@ -5,11 +5,14 @@ package org.chromium.chrome.browser.hub; import static org.chromium.chrome.browser.hub.HubAnimationConstants.PANE_COLOR_BLEND_ANIMATION_DURATION_MS; +import static org.chromium.chrome.browser.hub.HubAnimationConstants.PANE_FADE_ANIMATION_DURATION_MS; import static org.chromium.chrome.browser.hub.HubAnimationConstants.getPaneColorBlendInterpolator; import static org.chromium.ui.util.ColorBlendAnimationFactory.createMultiColorBlendAnimation; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.drawable.Drawable; @@ -56,12 +59,14 @@ private OnTabSelectedListener mOnTabSelectedListener; private boolean mBlockTabSelectionCallback; private final AnimationHandler mColorBlendAnimatorHandler; + private final AnimationHandler mHubSearchAnimatorHandler; private final HubColorBlendAnimatorSetHelper mAnimatorSetBuilder; /** Default {@link LinearLayout} constructor called by inflation. */ public HubToolbarView(Context context, AttributeSet attributeSet) { super(context, attributeSet); mColorBlendAnimatorHandler = new AnimationHandler(); + mHubSearchAnimatorHandler = new AnimationHandler(); mAnimatorSetBuilder = new HubColorBlendAnimatorSetHelper(); mToolbarOverviewColorSetter = (color) -> {}; } @@ -209,6 +214,14 @@ ImageViewCompat.setImageTintList(mMenuButton, menuButtonColor); })); + // We don't want to pass a method reference. Lambdas will ensure we run the most recent + // setter. + mAnimatorSetBuilder.registerBlend( + new SingleHubViewColorBlend( + PANE_COLOR_BLEND_ANIMATION_DURATION_MS, + colorScheme -> HubColors.getBackgroundColor(context, colorScheme), + color -> mToolbarOverviewColorSetter.onResult(color))); + // TODO(crbug.com/40948541): Updating the app menu color here is more correct and // should be done for code health. Menu Button Color is also set by // HubToolbarCoordinator. @@ -236,14 +249,6 @@ PANE_COLOR_BLEND_ANIMATION_DURATION_MS, colorScheme -> HubColors.getIconColor(context, colorScheme), this::updateSearchLoupeColor)); - - // We don't want to pass a method reference. Lambdas will ensure we run the most recent - // setter. - mAnimatorSetBuilder.registerBlend( - new SingleHubViewColorBlend( - PANE_COLOR_BLEND_ANIMATION_DURATION_MS, - colorScheme -> HubColors.getBackgroundColor(context, colorScheme), - color -> mToolbarOverviewColorSetter.onResult(color))); } private void updateTabIconTintInternal( @@ -269,7 +274,25 @@ } void setSearchBoxVisible(boolean visible) { - mSearchBoxLayout.setVisibility(visible ? View.VISIBLE : View.GONE); + AnimatorSet hubSearchTransitionAnimation = getHubSearchBoxTransitionAnimation(visible); + AnimatorListenerAdapter animationListener = + new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + if (visible) { + mSearchBoxLayout.setVisibility(View.VISIBLE); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + if (!visible) { + mSearchBoxLayout.setVisibility(View.GONE); + } + } + }; + hubSearchTransitionAnimation.addListener(animationListener); + mHubSearchAnimatorHandler.startAnimation(hubSearchTransitionAnimation); } public void setSearchLoupeVisible(boolean visible) { @@ -324,4 +347,18 @@ : R.string.hub_search_empty_hint; mSearchBoxTextView.setHint(context.getString(emptyHintRes)); } + + private AnimatorSet getHubSearchBoxTransitionAnimation(boolean visible) { + float fadeAlphaFrom = visible ? 0 : 1; + float fadeAlphaTo = visible ? 1 : 0; + float slideTransitionY = visible ? 0 : -mSearchBoxLayout.getHeight(); + Animator fade = + ObjectAnimator.ofFloat(mSearchBoxLayout, View.ALPHA, fadeAlphaFrom, fadeAlphaTo); + Animator slide = + ObjectAnimator.ofFloat(mSearchBoxLayout, View.TRANSLATION_Y, slideTransitionY); + AnimatorSet slideFadeHubSearchBoxAnimator = new AnimatorSet(); + slideFadeHubSearchBoxAnimator.play(slide).with(fade); + slideFadeHubSearchBoxAnimator.setDuration(PANE_FADE_ANIMATION_DURATION_MS); + return slideFadeHubSearchBoxAnimator; + } }
diff --git a/chrome/browser/image_descriptions/android/java/src/org/chromium/chrome/browser/image_descriptions/ImageDescriptionsDialog.java b/chrome/browser/image_descriptions/android/java/src/org/chromium/chrome/browser/image_descriptions/ImageDescriptionsDialog.java index 9f85ba5..99e05c1 100644 --- a/chrome/browser/image_descriptions/android/java/src/org/chromium/chrome/browser/image_descriptions/ImageDescriptionsDialog.java +++ b/chrome/browser/image_descriptions/android/java/src/org/chromium/chrome/browser/image_descriptions/ImageDescriptionsDialog.java
@@ -155,12 +155,9 @@ } @Override - public void onDestroy() { - // If no dismissal cause has been set, web contents were destroyed. - if (mDismissalCause == DialogDismissalCause.UNKNOWN) { - mDismissalCause = DialogDismissalCause.WEB_CONTENTS_DESTROYED; - } - dismiss(); + public void webContentsDestroyed() { + mDismissalCause = DialogDismissalCause.WEB_CONTENTS_DESTROYED; + unregisterObserverAndDismiss(); } }; @@ -273,7 +270,8 @@ * or on user action. The call to #destroy() will also dismiss the dialog. */ private void unregisterObserverAndDismiss() { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); + dismiss(); } /** Helper method to display this dialog. */
diff --git a/chrome/browser/media/webrtc/media_stream_capture_indicator.cc b/chrome/browser/media/webrtc/media_stream_capture_indicator.cc index 961b1a2f..399b290 100644 --- a/chrome/browser/media/webrtc/media_stream_capture_indicator.cc +++ b/chrome/browser/media/webrtc/media_stream_capture_indicator.cc
@@ -675,8 +675,10 @@ StatusTray* status_tray = g_browser_process->status_tray(); if (status_tray != nullptr) { - status_tray->RemoveStatusIcon(status_icon_); + std::unique_ptr<StatusIcon> removed_icon = + status_tray->RemoveStatusIcon(status_icon_); status_icon_ = nullptr; + removed_icon.reset(); } }
diff --git a/chrome/browser/media/webrtc/media_stream_capture_indicator.h b/chrome/browser/media/webrtc/media_stream_capture_indicator.h index 327b5a14..84b8ee0 100644 --- a/chrome/browser/media/webrtc/media_stream_capture_indicator.h +++ b/chrome/browser/media/webrtc/media_stream_capture_indicator.h
@@ -173,7 +173,7 @@ // Reference to our status icon - owned by the StatusTray. If null, // the platform doesn't support status icons. - raw_ptr<StatusIcon, DanglingUntriaged> status_icon_ = nullptr; + raw_ptr<StatusIcon> status_icon_ = nullptr; // A map that contains the usage counts of the opened capture devices for each // WebContents instance.
diff --git a/chrome/browser/nearby_sharing/nearby_share_settings.cc b/chrome/browser/nearby_sharing/nearby_share_settings.cc index cea2bfd9..a0785b6 100644 --- a/chrome/browser/nearby_sharing/nearby_share_settings.cc +++ b/chrome/browser/nearby_sharing/nearby_share_settings.cc
@@ -52,6 +52,14 @@ base::UmaHistogramEnumeration("Nearby.Share.VisibilityChoice", GetVisibility()); } + + // In Quick Share v2, the 'Selected contacts' visibility is deprecated. Set + // user visibility, if in 'Selected contacts', to 'Your devices'. + if (chromeos::features::IsQuickShareV2Enabled()) { + if (GetVisibility() == nearby_share::mojom::Visibility::kSelectedContacts) { + SetVisibility(nearby_share::mojom::Visibility::kYourDevices); + } + } } NearbyShareSettings::~NearbyShareSettings() {
diff --git a/chrome/browser/nearby_sharing/nearby_share_settings_unittest.cc b/chrome/browser/nearby_sharing/nearby_share_settings_unittest.cc index 3b37649..f40d2165 100644 --- a/chrome/browser/nearby_sharing/nearby_share_settings_unittest.cc +++ b/chrome/browser/nearby_sharing/nearby_share_settings_unittest.cc
@@ -10,6 +10,7 @@ #include "base/feature_list.h" #include "base/run_loop.h" #include "base/test/bind.h" +#include "base/test/scoped_feature_list.h" #include "chrome/browser/nearby_sharing/common/nearby_share_features.h" #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h" #include "chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_local_device_data_manager.h" @@ -116,6 +117,7 @@ FakeNearbyShareSettingsObserver observer_; std::unique_ptr<NearbyShareSettings> nearby_share_settings_; std::unique_ptr<NearbyShareSettingsAsyncWaiter> nearby_share_settings_waiter_; + base::test::ScopedFeatureList feature_list_; }; TEST_F(NearbyShareSettingsTest, GetAndSetEnabled) { @@ -343,3 +345,18 @@ settings_waiter()->GetAllowedContacts(&allowed_contacts); EXPECT_EQ(0u, allowed_contacts.size()); } + +TEST_F(NearbyShareSettingsTest, QuickShareV2_SomeContacts_ToYourDevices) { + feature_list_.InitAndEnableFeature(chromeos::features::kQuickShareV2); + pref_service_.SetInteger( + prefs::kNearbySharingBackgroundVisibilityName, + static_cast<int>(nearby_share::mojom::Visibility::kSelectedContacts)); + + // Since some contacts -> your devices occurs in constructor, new + // NearbyShareSettings object must be created after QuickShareV2 is enabled. + NearbyShareSettings nearby_share_settings(&pref_service_, + &local_device_data_manager_); + + EXPECT_EQ(nearby_share_settings.GetVisibility(), + nearby_share::mojom::Visibility::kYourDevices); +}
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc index d9fec9b..37d1787 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
@@ -5461,9 +5461,9 @@ TEST_P( NearbySharingServiceImplTest, - SelfShareEnabled_YourDevicesVisibilityOnScreenLock_DefaultSelectedContactsVisibility) { + SelfShareEnabled_YourDevicesVisibilityOnScreenLock_DefaultAllContactsVisibility) { const std::set<std::string> contacts = {"1", "2"}; - SetVisibility(nearby_share::mojom::Visibility::kSelectedContacts); + SetVisibility(nearby_share::mojom::Visibility::kAllContacts); contact_manager()->SetAllowedContacts(contacts); // Lock screen, expect Your Devices visibility. @@ -5473,8 +5473,7 @@ // Unlock screen, expect visibility to return to All Contacts. session_controller_->SetScreenLocked(false); - EXPECT_EQ(nearby_share::mojom::Visibility::kSelectedContacts, - GetVisibility()); + EXPECT_EQ(nearby_share::mojom::Visibility::kAllContacts, GetVisibility()); EXPECT_EQ(contacts, contact_manager()->GetAllowedContacts()); }
diff --git a/chrome/browser/net/cookie_policy_browsertest.cc b/chrome/browser/net/cookie_policy_browsertest.cc index a47c752c..1e3a0b8e 100644 --- a/chrome/browser/net/cookie_policy_browsertest.cc +++ b/chrome/browser/net/cookie_policy_browsertest.cc
@@ -666,7 +666,8 @@ } IN_PROC_BROWSER_TEST_P(CookiePolicyStorageBrowserTest, - NestedThirdPartyIFrameStorage) { + // TODO(crbug.com/390648566): Re-enable this test + DISABLED_NestedThirdPartyIFrameStorage) { NavigateToPageWithFrame(kHostA); NavigateFrameTo(kHostB, "/iframe.html"); NavigateNestedFrameTo(kHostC, "/browsing_data/site_data.html");
diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc index 8f66c350..467093a 100644 --- a/chrome/browser/notifications/platform_notification_service_impl.cc +++ b/chrome/browser/notifications/platform_notification_service_impl.cc
@@ -679,15 +679,9 @@ #if !BUILDFLAG(IS_ANDROID) web_app::WebAppProvider* web_app_provider = web_app::WebAppProvider::GetForLocalAppsUnchecked(profile_); - // TODO(crbug.com/379827962): Evaluate call sites of FindBestAppWithUrlInScope - // for correctness. if (web_app_provider) { return web_app_provider->registrar_unsafe().FindBestAppWithUrlInScope( - web_app_hint_url, - { - web_app::proto::InstallState::INSTALLED_WITH_OS_INTEGRATION, - web_app::proto::InstallState::INSTALLED_WITHOUT_OS_INTEGRATION, - }); + web_app_hint_url, web_app::WebAppFilter::InstalledInChrome()); } #endif @@ -701,15 +695,19 @@ web_app::WebAppProvider* web_app_provider = web_app::WebAppProvider::GetForLocalAppsUnchecked(profile_); if (web_app_provider) { - // TODO(crbug.com/379827962): Evaluate call sites of - // FindBestAppWithUrlInScope for correctness. +#if BUILDFLAG(IS_CHROMEOS) + // The PlatformNotificationServiceTest FindWebAppIconAndTitle seems to be + // verifying the availability of an icon and a title for notification + // purposes, even though the app is not installed with OS integration, which + // is surprising. + web_app::WebAppFilter filter = web_app::WebAppFilter::InstalledInChrome(); +#else + web_app::WebAppFilter filter = + web_app::WebAppFilter::SupportsOsNotifications(); +#endif const std::optional<webapps::AppId> app_id = web_app_provider->registrar_unsafe().FindBestAppWithUrlInScope( - web_app_hint_url, - { - web_app::proto::InstallState::INSTALLED_WITH_OS_INTEGRATION, - web_app::proto::InstallState::INSTALLED_WITHOUT_OS_INTEGRATION, - }); + web_app_hint_url, filter); if (app_id) { std::optional<WebAppIconAndTitle> icon_and_title; icon_and_title.emplace(); @@ -740,8 +738,7 @@ } const std::optional<webapps::AppId> app_id = web_app_provider->registrar_unsafe().FindBestAppWithUrlInScope( - web_app_url, - {web_app::proto::InstallState::INSTALLED_WITH_OS_INTEGRATION}); + web_app_url, web_app::WebAppFilter::SupportsOsNotifications()); return app_id.has_value(); #endif }
diff --git a/chrome/browser/platform_util_linux.cc b/chrome/browser/platform_util_linux.cc index df221178..5216ab56 100644 --- a/chrome/browser/platform_util_linux.cc +++ b/chrome/browser/platform_util_linux.cc
@@ -31,7 +31,6 @@ #include "base/task/thread_pool.h" #include "base/threading/scoped_blocking_call.h" #include "base/types/expected.h" -#include "chrome/browser/lifetime/termination_notification.h" #include "chrome/browser/platform_util_internal.h" #include "components/dbus/properties/types.h" #include "components/dbus/thread_linux/dbus_thread_linux.h" @@ -66,13 +65,7 @@ return *instance; } - ShowItemHelper() - : browser_shutdown_subscription_( - browser_shutdown::AddAppTerminatingCallback( - base::BindOnce(&ShowItemHelper::OnAppTerminating, - // Unretained is safe, the ShowItemHelper - // instance is never destroyed. - base::Unretained(this)))) {} + ShowItemHelper() = default; ShowItemHelper(const ShowItemHelper&) = delete; ShowItemHelper& operator=(const ShowItemHelper&) = delete; @@ -84,12 +77,7 @@ return; } if (!bus_) { - // Sets up the D-Bus connection. - dbus::Bus::Options bus_options; - bus_options.bus_type = dbus::Bus::SESSION; - bus_options.connection_type = dbus::Bus::PRIVATE; - bus_options.dbus_task_runner = dbus_thread_linux::GetTaskRunner(); - bus_ = base::MakeRefCounted<dbus::Bus>(bus_options); + bus_ = dbus_thread_linux::GetSharedSessionBus(); } if (api_type_.has_value()) { @@ -143,16 +131,6 @@ } } - void OnAppTerminating() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - // The browser process is about to exit. Clean up while we still can. - portal_object_proxy_ = nullptr; - file_manager_object_proxy_ = nullptr; - if (bus_) - bus_->ShutdownOnDBusThreadAndBlock(); - bus_.reset(); - } - void CheckPortalRunningResponse(std::optional<bool> is_running) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (is_running.value_or(false)) { @@ -315,8 +293,6 @@ // Requests that are queued until the API availability is determined. std::queue<base::FilePath> pending_requests_; - - base::CallbackListSubscription browser_shutdown_subscription_; }; void OnLaunchOptionsCreated(const std::string& command, @@ -339,12 +315,14 @@ // applications. See http://crbug.com/24120 char* disable_gnome_bug_buddy = getenv("GNOME_DISABLE_CRASH_DIALOG"); if (disable_gnome_bug_buddy && - disable_gnome_bug_buddy == std::string("SET_BY_GOOGLE_CHROME")) + disable_gnome_bug_buddy == std::string("SET_BY_GOOGLE_CHROME")) { options.environment["GNOME_DISABLE_CRASH_DIALOG"] = std::string(); + } base::Process process = base::LaunchProcess(argv, options); - if (process.IsValid()) + if (process.IsValid()) { base::EnsureProcessGetsReaped(std::move(process)); + } } void RunCommand(const std::string& command, @@ -396,10 +374,11 @@ void OpenExternal(const GURL& url) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (url.SchemeIs("mailto")) + if (url.SchemeIs("mailto")) { XDGEmail(url.spec()); - else + } else { XDGOpen(base::FilePath(), url.spec()); + } } } // namespace platform_util
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 203905ed..77a87976 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -2351,12 +2351,6 @@ { key::kWebAudioOutputBufferingEnabled, prefs::kWebAudioOutputBufferingEnabled, base::Value::Type::BOOLEAN }, - -#if BUILDFLAG(ENABLE_GLIC) - { key::kGlicEnabled, - glic::prefs::kGlicEnabledByPolicy, - base::Value::Type::BOOLEAN }, -#endif // BUILDFLAG(ENABLE_GLIC) }; // clang-format on @@ -3304,6 +3298,13 @@ std::make_unique<PowerBatteryChargingOptimizationPolicyHandler>())); #endif // BUILDFLAG(IS_CHROMEOS) +#if BUILDFLAG(ENABLE_GLIC) + handlers->AddHandler(std::make_unique<IntRangePolicyHandler>( + key::kGlicSettings, glic::prefs::kGlicEnabledByPolicy, + static_cast<int>(glic::prefs::EnabledByPolicyState::kMinValue), + static_cast<int>(glic::prefs::EnabledByPolicyState::kMaxValue), false)); +#endif + return handlers; }
diff --git a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogConsentEEA.java b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogConsentEEA.java index be2005f..4b3356f1 100644 --- a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogConsentEEA.java +++ b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogConsentEEA.java
@@ -366,7 +366,7 @@ if (mThinWebView != null) { mWebContents.destroy(); mWebContents = null; - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; mThinWebView.destroy(); mThinWebView = null;
diff --git a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogNoticeEeaV2.java b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogNoticeEeaV2.java index ec94e596..9662504 100644 --- a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogNoticeEeaV2.java +++ b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogNoticeEeaV2.java
@@ -302,7 +302,7 @@ if (mThinWebView != null) { mWebContents.destroy(); mWebContents = null; - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; mThinWebView.destroy(); mThinWebView = null;
diff --git a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogNoticeROW.java b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogNoticeROW.java index 2947258a..f639511 100644 --- a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogNoticeROW.java +++ b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxDialogNoticeROW.java
@@ -287,7 +287,7 @@ if (mThinWebView != null) { mWebContents.destroy(); mWebContents = null; - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; mThinWebView.destroy(); mThinWebView = null;
diff --git a/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_subpage.ts b/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_subpage.ts index 63498e46..c64ea59 100644 --- a/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_subpage.ts +++ b/chrome/browser/resources/ash/settings/nearby_share_page/nearby_share_subpage.ts
@@ -307,6 +307,22 @@ if (visibility === undefined) { return ''; } + + if (this.isQuickShareV2Enabled_) { + switch (visibility) { + case Visibility.kAllContacts: + return this.i18n('nearbyShareContactVisiblityContactsButton'); + case Visibility.kNoOne: + return this.i18n('nearbyShareContactVisibilityNone'); + case Visibility.kUnknown: + return this.i18n('nearbyShareContactVisibilityUnknown'); + case Visibility.kYourDevices: + return this.i18n('nearbyShareContactVisibilityYourDevices'); + default: + assertNotReached(); + } + } + switch (visibility) { case Visibility.kAllContacts: return this.i18n('nearbyShareContactVisibilityAll');
diff --git a/chrome/browser/resources/chromeos/nearby_share/shared/nearby_contact_visibility.ts b/chrome/browser/resources/chromeos/nearby_share/shared/nearby_contact_visibility.ts index 82712f6..d2a94e5 100644 --- a/chrome/browser/resources/chromeos/nearby_share/shared/nearby_contact_visibility.ts +++ b/chrome/browser/resources/chromeos/nearby_share/shared/nearby_contact_visibility.ts
@@ -146,6 +146,14 @@ type: String, value: '', }, + + /** + * Determines whether the QuickShareV2 flag is enabled. + */ + isQuickShareV2Enabled_: { + type: Boolean, + value: () => loadTimeData.getBoolean('isQuickShareV2Enabled'), + }, }; } @@ -172,6 +180,7 @@ private downloadTimeoutId_: number|null; private isDarkModeActive_: boolean; private isAllContactsToggledOn_: boolean; + private isQuickShareV2Enabled_: boolean; private numUnreachable_: number; private numUnreachableMessage_: string; @@ -226,6 +235,10 @@ |null { switch (visibilityString) { case 'contacts': + if (this.isQuickShareV2Enabled_) { + return Visibility.kAllContacts + } + if (this.isAllContactsToggledOn_) { return Visibility.kAllContacts; } @@ -339,6 +352,10 @@ * @return true when checkboxes should be shown for contacts. */ private showContactCheckBoxes_(): boolean { + if (this.isQuickShareV2Enabled_) { + return false; + } + return this.getSelectedVisibility() === Visibility.kSelectedContacts; } @@ -417,6 +434,10 @@ private showAllContactsToggle_( selectedVisibility: string, contactsState: ContactsState): boolean { + if (this.isQuickShareV2Enabled_) { + return false; + } + return selectedVisibility === 'contacts' && contactsState === ContactsState.HAS_CONTACTS; }
diff --git a/chrome/browser/resources/commerce/product_specifications/app.ts b/chrome/browser/resources/commerce/product_specifications/app.ts index 707e9e3..8562891a 100644 --- a/chrome/browser/resources/commerce/product_specifications/app.ts +++ b/chrome/browser/resources/commerce/product_specifications/app.ts
@@ -887,6 +887,7 @@ } if (urlSetChanged) { + this.closeAllProductSelectionMenus_(); this.populateTable_(set.urls.map(url => url.url)); } else if (orderChanged) { const newCols: TableColumn[] = []; @@ -1051,6 +1052,11 @@ private onHeaderMenuDeleteClick_() { this.deleteSet_(); } + + private closeAllProductSelectionMenus_() { + this.$.summaryTable.closeAllProductSelectionMenus(); + this.$.newColumnSelector.closeMenu(); + } } declare global {
diff --git a/chrome/browser/resources/commerce/product_specifications/comparison_table_list.html.ts b/chrome/browser/resources/commerce/product_specifications/comparison_table_list.html.ts index 140f70d..5028ea65 100644 --- a/chrome/browser/resources/commerce/product_specifications/comparison_table_list.html.ts +++ b/chrome/browser/resources/commerce/product_specifications/comparison_table_list.html.ts
@@ -58,7 +58,11 @@ <cr-action-menu> <button id="menuOpenAll" class="dropdown-item" @click="${this.onOpenAllClick_}"> - ${this.getOpenAllString_(this.numSelected_)} + ${this.getOpenAllString_(this.numSelected_)} + </button> + <button id="menuOpenAllInNewWindow" class="dropdown-item" + @click="${this.onOpenAllInNewWindowClick_}"> + ${this.getOpenAllInNewWindowString_(this.numSelected_)} </button> <hr> <button id="menuDelete" class="dropdown-item"
diff --git a/chrome/browser/resources/commerce/product_specifications/comparison_table_list.ts b/chrome/browser/resources/commerce/product_specifications/comparison_table_list.ts index ba242156..4e4a1ad0 100644 --- a/chrome/browser/resources/commerce/product_specifications/comparison_table_list.ts +++ b/chrome/browser/resources/commerce/product_specifications/comparison_table_list.ts
@@ -9,6 +9,8 @@ import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render_lit.js'; import './images/icons.html.js'; +import {ShowSetDisposition} from '//resources/cr_components/commerce/product_specifications.mojom-webui.js'; +import type {ProductSpecificationsBrowserProxy} from '//resources/cr_components/commerce/product_specifications_browser_proxy.js'; import {ProductSpecificationsBrowserProxyImpl} from '//resources/cr_components/commerce/product_specifications_browser_proxy.js'; import type {ShoppingServiceBrowserProxy} from '//resources/cr_components/commerce/shopping_service_browser_proxy.js'; import {ShoppingServiceBrowserProxyImpl} from '//resources/cr_components/commerce/shopping_service_browser_proxy.js'; @@ -72,6 +74,8 @@ private selectedUuids_: Set<Uuid> = new Set(); private shoppingApi_: ShoppingServiceBrowserProxy = ShoppingServiceBrowserProxyImpl.getInstance(); + private productSpecificationsProxy_: ProductSpecificationsBrowserProxy = + ProductSpecificationsBrowserProxyImpl.getInstance(); protected getSelectionLabel_(numSelected: number): string { return loadTimeData.getStringF('numSelected', numSelected); @@ -81,6 +85,10 @@ return loadTimeData.getStringF('menuOpenAll', numSelected); } + protected getOpenAllInNewWindowString_(numSelected: number): string { + return loadTimeData.getStringF('menuOpenAllInNewWindow', numSelected); + } + protected onEditClick_() { if (!this.isEditing_) { this.isEditing_ = true; @@ -110,17 +118,21 @@ } protected async onOpenAllClick_() { - this.selectedUuids_.forEach(uuid => { - ProductSpecificationsBrowserProxyImpl.getInstance() - .showProductSpecificationsSetForUuid(uuid, true); - }); - + this.productSpecificationsProxy_.showProductSpecificationsSetsForUuids( + Array.from(this.selectedUuids_), ShowSetDisposition.kInNewTabs); this.$.menu.get().close(); - this.stopEditing_(); this.fire('open-all-finished-for-testing'); } + protected async onOpenAllInNewWindowClick_() { + this.productSpecificationsProxy_.showProductSpecificationsSetsForUuids( + Array.from(this.selectedUuids_), ShowSetDisposition.kInNewWindow); + this.$.menu.get().close(); + + this.fire('open-all-in-new-window-finished-for-testing'); + } + protected onCheckboxChange_(event: ComparisonTableListItemCheckboxChangeEvent) { if (event.detail.checked) {
diff --git a/chrome/browser/resources/commerce/product_specifications/comparison_table_list_item.html.ts b/chrome/browser/resources/commerce/product_specifications/comparison_table_list_item.html.ts index 49c0ec9..3a289ed 100644 --- a/chrome/browser/resources/commerce/product_specifications/comparison_table_list_item.html.ts +++ b/chrome/browser/resources/commerce/product_specifications/comparison_table_list_item.html.ts
@@ -51,6 +51,10 @@ @click="${this.onOpenInNewTabClick_}"> $i18n{menuOpenInNewTab} </button> + <button id="openInNewWindow" class="dropdown-item" role="menuitem" + @click="${this.onOpenInNewWindowClick_}"> + $i18n{menuOpenInNewWindow} + </button> <hr> <button id="rename" class="dropdown-item" role="menuitem" @click="${this.onRenameClick_}">
diff --git a/chrome/browser/resources/commerce/product_specifications/comparison_table_list_item.ts b/chrome/browser/resources/commerce/product_specifications/comparison_table_list_item.ts index 382d5c3a..7405c9d 100644 --- a/chrome/browser/resources/commerce/product_specifications/comparison_table_list_item.ts +++ b/chrome/browser/resources/commerce/product_specifications/comparison_table_list_item.ts
@@ -11,6 +11,7 @@ import 'chrome://resources/cr_elements/cr_input/cr_input.js'; import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; +import {ShowSetDisposition} from '//resources/cr_components/commerce/product_specifications.mojom-webui.js'; import type {CrActionMenuElement} from '//resources/cr_elements/cr_action_menu/cr_action_menu.js'; import type {CrIconButtonElement} from '//resources/cr_elements/cr_icon_button/cr_icon_button.js'; import type {CrLazyRenderLitElement} from '//resources/cr_elements/cr_lazy_render/cr_lazy_render_lit.js'; @@ -167,6 +168,12 @@ this.uuid, true); } + protected onOpenInNewWindowClick_() { + this.$.menu.get().close(); + this.productSpecificationsProxy_.showProductSpecificationsSetsForUuids( + [this.uuid], ShowSetDisposition.kInNewWindow); + } + protected async onRenameClick_() { this.$.menu.get().close(); this.isRenaming_ = true;
diff --git a/chrome/browser/resources/commerce/product_specifications/new_column_selector.ts b/chrome/browser/resources/commerce/product_specifications/new_column_selector.ts index 2c671bc7..0439728 100644 --- a/chrome/browser/resources/commerce/product_specifications/new_column_selector.ts +++ b/chrome/browser/resources/commerce/product_specifications/new_column_selector.ts
@@ -47,6 +47,10 @@ return getHtml.bind(this)(); } + closeMenu() { + this.$.productSelectionMenu.close(); + } + protected showMenu_() { this.$.productSelectionMenu.showAt(this.$.button); this.$.button.classList.add('showing-menu');
diff --git a/chrome/browser/resources/commerce/product_specifications/product_selection_menu.ts b/chrome/browser/resources/commerce/product_specifications/product_selection_menu.ts index 6fe46b4b..1299f25 100644 --- a/chrome/browser/resources/commerce/product_specifications/product_selection_menu.ts +++ b/chrome/browser/resources/commerce/product_specifications/product_selection_menu.ts
@@ -135,7 +135,10 @@ } close() { - this.$.menu.get().close(); + const menu = this.$.menu.getIfExists(); + if (menu) { + menu.close(); + } } protected expandedChanged_(
diff --git a/chrome/browser/resources/commerce/product_specifications/product_selector.ts b/chrome/browser/resources/commerce/product_specifications/product_selector.ts index bea6083..1687dd7 100644 --- a/chrome/browser/resources/commerce/product_specifications/product_selector.ts +++ b/chrome/browser/resources/commerce/product_specifications/product_selector.ts
@@ -52,6 +52,10 @@ return getHtml.bind(this)(); } + closeMenu() { + this.$.productSelectionMenu.close(); + } + protected showMenu_() { this.$.productSelectionMenu.showAt(this.$.currentProductContainer); this.$.currentProductContainer.classList.add('showing-menu');
diff --git a/chrome/browser/resources/commerce/product_specifications/table.ts b/chrome/browser/resources/commerce/product_specifications/table.ts index 3d76471..2d4cbb1 100644 --- a/chrome/browser/resources/commerce/product_specifications/table.ts +++ b/chrome/browser/resources/commerce/product_specifications/table.ts
@@ -26,6 +26,7 @@ import type {ProductDescription} from './description_section.js'; import {DragAndDropManager} from './drag_and_drop_manager.js'; import type {SectionType} from './product_selection_menu.js'; +import type {ProductSelectorElement} from './product_selector.js'; import {getTemplate} from './table.html.js'; import {WindowProxy} from './window_proxy.js'; @@ -106,6 +107,13 @@ this.dispatchEvent(new Event('url-order-update')); } + closeAllProductSelectionMenus() { + const productSelectors = + this.shadowRoot!.querySelectorAll<ProductSelectorElement>( + 'product-selector'); + productSelectors.forEach(productSelector => productSelector.closeMenu()); + } + private onColumnsChanged_() { this.style.setProperty('--num-columns', String(this.columns.length)); }
diff --git a/chrome/browser/resources/pdf/elements/viewer_toolbar.html b/chrome/browser/resources/pdf/elements/viewer_toolbar.html index e7ece01a..b7fca01 100644 --- a/chrome/browser/resources/pdf/elements/viewer_toolbar.html +++ b/chrome/browser/resources/pdf/elements/viewer_toolbar.html
@@ -4,7 +4,7 @@ title="$i18n{menu}" aria-label="$i18n{menu}" aria-expanded="${this.getAriaExpanded_()}" <if expr="enable_ink"> - ?disabled="${this.annotationMode}" + ?disabled="${this.isInInk1AnnotationMode_()}" </if> @click="${this.onSidenavToggleClick_}"> </cr-icon-button> @@ -44,7 +44,7 @@ <cr-icon-button id="rotate" .ironIcon="${this.iconsetName_()}:rotate-left" suppress-rtl-flip <if expr="enable_ink"> - ?disabled="${this.annotationMode}" + ?disabled="${this.isInInk1AnnotationMode_()}" </if> aria-label="$i18n{tooltipRotateCCW}" title="$i18n{tooltipRotateCCW}" @click="${this.onRotateClick_}"> @@ -106,7 +106,7 @@ <button id="two-page-view-button" class="dropdown-item" @click="${this.toggleTwoPageViewClick_}" role="checkbox" <if expr="enable_ink"> - ?disabled="${this.annotationMode}" + ?disabled="${this.isInInk1AnnotationMode_()}" </if> aria-checked="${this.getAriaChecked_(this.twoUpViewEnabled)}"> <span class="check-container">
diff --git a/chrome/browser/resources/pdf/elements/viewer_toolbar.ts b/chrome/browser/resources/pdf/elements/viewer_toolbar.ts index 6352275..bd70c85 100644 --- a/chrome/browser/resources/pdf/elements/viewer_toolbar.ts +++ b/chrome/browser/resources/pdf/elements/viewer_toolbar.ts
@@ -44,7 +44,7 @@ export interface ViewerToolbarElement { $: { - sidenavToggle: HTMLElement, + sidenavToggle: HTMLButtonElement, menu: CrActionMenuElement, 'present-button': HTMLButtonElement, 'two-page-view-button': HTMLButtonElement, @@ -268,7 +268,7 @@ this.isInInk1AnnotationMode_(); } - private isInInk1AnnotationMode_(): boolean { + protected isInInk1AnnotationMode_(): boolean { // <if expr="enable_pdf_ink2"> if (this.pdfInk2Enabled) { return false;
diff --git a/chrome/browser/resources/tab_search/auto_tab_groups/auto_tab_groups_group.html.ts b/chrome/browser/resources/tab_search/auto_tab_groups/auto_tab_groups_group.html.ts index 5bcd8c4..e2948c92 100644 --- a/chrome/browser/resources/tab_search/auto_tab_groups/auto_tab_groups_group.html.ts +++ b/chrome/browser/resources/tab_search/auto_tab_groups/auto_tab_groups_group.html.ts
@@ -62,9 +62,6 @@ </tab-search-item> `)} </cr-page-selector> - <auto-tab-groups-results-actions - @create-group-click="${this.onCreateGroupClick_}"> - </auto-tab-groups-results-actions> </div> <!--_html_template_end_-->`; // clang-format on
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h index 169bade..fdd95b9 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h +++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_SAFE_BROWSING_CLOUD_CONTENT_SCANNING_BINARY_UPLOAD_SERVICE_H_ #include "base/functional/bind.h" +#include "base/functional/callback.h" #include "base/memory/read_only_shared_memory_region.h" #include "base/memory/weak_ptr.h" #include "base/types/id_type.h" @@ -13,7 +14,6 @@ #include "components/enterprise/common/proto/connectors.pb.h" #include "components/enterprise/connectors/core/analysis_settings.h" #include "components/keyed_service/core/keyed_service.h" -#include "services/network/public/cpp/resource_request.h" #include "url/gurl.h" class Profile;
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc index 1d9e200..a6bfbe66 100644 --- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc +++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
@@ -34,6 +34,7 @@ #include "net/base/load_flags.h" #include "net/http/http_request_headers.h" #include "net/http/http_status_code.h" +#include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" #include "services/network/public/mojom/url_response_head.mojom.h"
diff --git a/chrome/browser/safe_browsing/download_protection/ppapi_download_request.cc b/chrome/browser/safe_browsing/download_protection/ppapi_download_request.cc index 389121a..0aeea0a 100644 --- a/chrome/browser/safe_browsing/download_protection/ppapi_download_request.cc +++ b/chrome/browser/safe_browsing/download_protection/ppapi_download_request.cc
@@ -28,6 +28,7 @@ #include "net/base/load_flags.h" #include "net/http/http_cache.h" #include "net/http/http_status_code.h" +#include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" #include "services/network/public/mojom/url_response_head.mojom.h"
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidCustomActionProvider.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidCustomActionProvider.java index 08da0137..a819f00 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidCustomActionProvider.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidCustomActionProvider.java
@@ -277,7 +277,7 @@ } // TODO(386833405): Update the text based on UX reviews and icon resolution. return new FirstPartyOptionBuilder(ContentType.LINK_PAGE_VISIBLE) - .setIcon(R.drawable.ic_person_add_40dp, R.string.collaboration_share_group_title) + .setIcon(R.drawable.ic_person_add_40dp, R.string.sharing_tab_group) .setShareActionType(ShareCustomAction.SHARE_AS_TAB_GROUP) .setFeatureNameForMetrics(USER_ACTION_SHARE_AS_TAB_GROUP) .setOnClickCallback(
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java index b8338e8..a179f92e 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java
@@ -269,6 +269,7 @@ size, (Bitmap icon, GURL iconUrl) -> { onFaviconRetrieved(context, icon, size, onUriReady); + faviconHelper.destroy(); }); }
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java index 6e15545f..332adca4 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java
@@ -244,7 +244,7 @@ } else { assertCustomActions( intent, - R.string.collaboration_share_group_title, + R.string.sharing_tab_group, R.string.sharing_long_screenshot, R.string.print_share_activity_title, R.string.sharing_send_tab_to_self, @@ -858,7 +858,7 @@ } else { assertCustomActions( intent, - R.string.collaboration_share_group_title, + R.string.sharing_tab_group, R.string.sharing_long_screenshot, R.string.print_share_activity_title, R.string.sharing_send_tab_to_self,
diff --git a/chrome/browser/status_icons/status_tray.cc b/chrome/browser/status_icons/status_tray.cc index 2756d74..ffa2a09 100644 --- a/chrome/browser/status_icons/status_tray.cc +++ b/chrome/browser/status_icons/status_tray.cc
@@ -23,11 +23,12 @@ return status_icons_.back().icon.get(); } -void StatusTray::RemoveStatusIcon(StatusIcon* icon) { +std::unique_ptr<StatusIcon> StatusTray::RemoveStatusIcon(StatusIcon* icon) { for (auto iter = status_icons_.begin(); iter != status_icons_.end(); ++iter) { if (iter->icon.get() == icon) { + auto removed_icon = std::move(iter->icon); status_icons_.erase(iter); - return; + return removed_icon; } } NOTREACHED();
diff --git a/chrome/browser/status_icons/status_tray.h b/chrome/browser/status_icons/status_tray.h index 0cccc59..4f0af0c 100644 --- a/chrome/browser/status_icons/status_tray.h +++ b/chrome/browser/status_icons/status_tray.h
@@ -44,8 +44,9 @@ const gfx::ImageSkia& image, const std::u16string& tool_tip); - // Removes |icon| from this status tray. - void RemoveStatusIcon(StatusIcon* icon); + // Removes |icon| from this status tray. Returns the `std::unique_ptr` to the + // icon so it can be cleaned up safely. + std::unique_ptr<StatusIcon> RemoveStatusIcon(StatusIcon* icon); // Checks if a status icon of a specific type exists in the status tray. bool HasStatusIconOfTypeForTesting(StatusIconType type) const;
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabStateAttributes.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabStateAttributes.java index 6528c23..4cca70c 100644 --- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabStateAttributes.java +++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabStateAttributes.java
@@ -236,7 +236,7 @@ @Override public void cleanupWebContents(WebContents webContents) { if (mWebContentsObserver != null) { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; } }
diff --git a/chrome/browser/touch_to_fill/password_manager/no_passkeys/internal/android/java/src/org/chromium/chrome/browser/touch_to_fill/no_passkeys/NoPasskeysBottomSheetRenderTest.java b/chrome/browser/touch_to_fill/password_manager/no_passkeys/internal/android/java/src/org/chromium/chrome/browser/touch_to_fill/no_passkeys/NoPasskeysBottomSheetRenderTest.java index 3f820d9..e2da7766a 100644 --- a/chrome/browser/touch_to_fill/password_manager/no_passkeys/internal/android/java/src/org/chromium/chrome/browser/touch_to_fill/no_passkeys/NoPasskeysBottomSheetRenderTest.java +++ b/chrome/browser/touch_to_fill/password_manager/no_passkeys/internal/android/java/src/org/chromium/chrome/browser/touch_to_fill/no_passkeys/NoPasskeysBottomSheetRenderTest.java
@@ -8,7 +8,6 @@ import static org.chromium.base.test.util.ApplicationTestUtils.finishActivity; import static org.chromium.ui.base.LocalizationUtils.setRtlForTesting; -import android.graphics.Color; import android.view.ViewGroup; import androidx.test.filters.MediumTest; @@ -137,10 +136,7 @@ ViewGroup activityContentView = getActivity().findViewById(android.R.id.content); ScrimCoordinator scrimCoordinator = new ScrimCoordinator( - getActivity(), - /* systemUiScrimDelegate= */ null, - activityContentView, - Color.WHITE); + getActivity(), /* systemUiScrimDelegate= */ null, activityContentView); return BottomSheetControllerFactory.createFullWidthBottomSheetController( () -> scrimCoordinator, (unused) -> {},
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 4b71499..b6e4ee5 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1676,6 +1676,7 @@ "//chrome/browser/apps/link_capturing", "//chrome/browser/apps/link_capturing:features", "//chrome/browser/browsing_data:constants", + "//chrome/browser/contextual_cueing", # TODO(crbug.com/370804668i): Remove the dependency when chrome/browser/serial # gets modularized. @@ -3089,7 +3090,6 @@ deps += [ "//chrome/app:generated_resources", - "//chrome/browser/contextual_cueing:contextual_cueing", "//chrome/browser/on_device_translation:language_pack_util", "//chrome/browser/shortcuts", "//components/capture_mode",
diff --git a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java index 4e4d0a30..d4c04b2 100644 --- a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java +++ b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java
@@ -334,7 +334,7 @@ * @param tab The {@link Tab} whose {@link WebContents} we want to observe. */ private void updateWebContentsObserver(Tab tab) { - if (mWebContentsObserver != null) mWebContentsObserver.destroy(); + if (mWebContentsObserver != null) mWebContentsObserver.observe(null); mWebContentsObserver = new WebContentsObserver(tab.getWebContents()) { @Override @@ -564,7 +564,7 @@ @Override public void destroy() { if (mWebContentsObserver != null) { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; } if (mCurrentTab != null) mCurrentTab.removeObserver(mTabObserver);
diff --git a/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabMediator.java b/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabMediator.java index 094bd89..f87622c 100644 --- a/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabMediator.java +++ b/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabMediator.java
@@ -271,7 +271,7 @@ /** Destroys the objects used for the current preview tab. */ void destroyContent() { if (mWebContentsObserver != null) { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; } mWebContentsDelegate = null;
diff --git a/chrome/browser/ui/android/omnibox/java/res/values/colors.xml b/chrome/browser/ui/android/omnibox/java/res/values/colors.xml index ba64843..91d414e 100644 --- a/chrome/browser/ui/android/omnibox/java/res/values/colors.xml +++ b/chrome/browser/ui/android/omnibox/java/res/values/colors.xml
@@ -26,7 +26,6 @@ <color name="locationbar_status_separator_color_light">@color/white_alpha_60</color> <color name="locationbar_status_separator_color_incognito">@color/baseline_neutral_variant_60</color> - <color name="omnibox_focused_fading_background_color">@color/black_alpha_65</color> <color name="omnibox_focused_fading_background_color_light">@color/white_alpha_65</color> <color name="branded_url_text_on_dark_bg">@color/baseline_neutral_100</color>
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtils.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtils.java index 89292af..8eba39d 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtils.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtils.java
@@ -111,6 +111,7 @@ @Override public void destroy() { mTemplateUrlService.removeObserver(this); + mFaviconHelper.destroy(); } @Override
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java index 1ab86fa..5e5f294c 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java
@@ -257,7 +257,7 @@ if (navigation.hasCommitted() && !navigation.isErrorPage()) { setReceivedUserGesture(navigation.getUrl()); } - destroy(); + observe(null); } } @@ -335,7 +335,7 @@ locationBarDataProvider != null ? locationBarDataProvider.getTab() : null; if (currentTab != null) { if (mVoiceSearchWebContentsObserver != null) { - mVoiceSearchWebContentsObserver.destroy(); + mVoiceSearchWebContentsObserver.observe(null); mVoiceSearchWebContentsObserver = null; } if (currentTab.getWebContents() != null) {
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninAccountPickerCoordinator.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninAccountPickerCoordinator.java index 2ca3e24..b8faf28 100644 --- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninAccountPickerCoordinator.java +++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninAccountPickerCoordinator.java
@@ -123,13 +123,16 @@ sheetContainer.setLayoutParams( new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); mContainerView.addView(sheetContainer); - @ColorInt int scrimColor = mActivity.getColor(R.color.default_scrim_color); mScrim = new ScrimCoordinator( mActivity, new ScrimCoordinator.SystemUiScrimDelegate() { @Override public void setStatusBarScrimFraction(float scrimFraction) { + // TODO(skym): Once the ability to get the current scrim color is + // added, this should be updated to use that instead. + @ColorInt int scrimColor = mScrim.getDefaultScrimColor(); + // Update the status bar color to match the currently shown scrim // color when the latter is changed. float alpha = ((float) Color.alpha(scrimColor)) * scrimFraction; @@ -143,8 +146,7 @@ mDelegate.setScrimColor(scrimColor); } }, - (ViewGroup) sheetContainer.getParent(), - scrimColor); + (ViewGroup) sheetContainer.getParent()); mBottomSheetController = BottomSheetControllerFactory.createBottomSheetController(
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index eb450413d..e748024 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -5896,6 +5896,10 @@ Including link: <ph name="ORIGIN">%1$s<ex>https://www.example.com</ex></ph> </message> + <message name="IDS_SHARING_TAB_GROUP" desc="Label for the button in share bottom sheet for sharing a link to collaborate in a shared tab group."> + Tab group + </message> + <message name="IDS_QR_CODE_FILENAME_PREFIX" desc="File name prefix for downloaded qrcode that is followed by timestamp."> chrome_qrcode_<ph name="CURRENT_TIMESTAMP_MS">%1$s<ex>1582667748515</ex></ph> </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SHARING_TAB_GROUP.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SHARING_TAB_GROUP.png.sha1 new file mode 100644 index 0000000..730475e --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SHARING_TAB_GROUP.png.sha1
@@ -0,0 +1 @@ +e9ac74b00007eaff9103105e5fc8d6a9ca0592de \ No newline at end of file
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarPositionController.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarPositionController.java index 73d2fa7..d717bce5 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarPositionController.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarPositionController.java
@@ -402,7 +402,7 @@ } /** Returns whether the toolbar will be shown on top for the supplied tab. */ - static boolean shouldShowToolbarOnTop(Tab tab) { + public static boolean shouldShowToolbarOnTop(Tab tab) { boolean isNtpUrl = (tab != null) && (tab.getUrl() != null) && UrlUtilities.isNtpUrl(tab.getUrl());
diff --git a/chrome/browser/ui/ash/capture_mode/BUILD.gn b/chrome/browser/ui/ash/capture_mode/BUILD.gn index 6a6f10d..bdcc1700 100644 --- a/chrome/browser/ui/ash/capture_mode/BUILD.gn +++ b/chrome/browser/ui/ash/capture_mode/BUILD.gn
@@ -55,6 +55,7 @@ "//components/endpoint_fetcher", "//components/language/core/common:common", "//components/lens", + "//components/lens:enterprise_policy", "//content/public/browser", "//services/screen_ai/public/mojom", "//services/video_capture/public/mojom", @@ -103,6 +104,7 @@ "//chrome/browser/ui/ash/system_web_apps", "//chrome/common", "//chrome/test:test_support", + "//components/lens:enterprise_policy", "//content/test:test_support", "//media", "//media:test_support",
diff --git a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc index d8bf6fa08..3f4b7e48 100644 --- a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc +++ b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
@@ -57,6 +57,7 @@ #include "chromeos/ash/services/recording/public/mojom/recording_service.mojom.h" #include "components/drive/file_errors.h" #include "components/lens/lens_overlay_mime_type.h" +#include "components/lens/lens_overlay_permission_utils.h" #include "components/prefs/pref_service.h" #include "components/services/app_service/public/cpp/app_launch_util.h" #include "content/public/browser/audio_service.h" @@ -143,6 +144,14 @@ return g_instance; } +bool ChromeCaptureModeDelegate::IsSearchAllowedByPolicy() const { + auto* profile = ProfileManager::GetActiveUserProfile(); + return profile && profile->GetPrefs() && + profile->GetPrefs()->GetInteger(lens::prefs::kLensOverlaySettings) == + static_cast<int>( + lens::prefs::LensOverlaySettingsPolicyValue::kEnabled); +} + void ChromeCaptureModeDelegate::SetIsScreenCaptureLocked(bool locked) { is_screen_capture_locked_ = locked; if (is_screen_capture_locked_) {
diff --git a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.h b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.h index e7111b3..cbc370aa 100644 --- a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.h +++ b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.h
@@ -69,6 +69,7 @@ const gfx::Rect& bounds, ash::OnCaptureModeDlpRestrictionChecked callback) override; bool IsCaptureAllowedByPolicy() const override; + bool IsSearchAllowedByPolicy() const override; void StartObservingRestrictedContent( const aura::Window* window, const gfx::Rect& bounds,
diff --git a/chrome/browser/ui/ash/capture_mode/sunfish_browsertest.cc b/chrome/browser/ui/ash/capture_mode/sunfish_browsertest.cc index 5934dba..5028c38 100644 --- a/chrome/browser/ui/ash/capture_mode/sunfish_browsertest.cc +++ b/chrome/browser/ui/ash/capture_mode/sunfish_browsertest.cc
@@ -7,12 +7,14 @@ #include "ash/capture_mode/search_results_panel.h" #include "ash/constants/ash_features.h" #include "ash/constants/ash_switches.h" +#include "ash/public/cpp/capture_mode/capture_mode_api.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.h" #include "chrome/browser/ui/ash/capture_mode/search_results_view.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/test/base/in_process_browser_test.h" +#include "components/lens/lens_overlay_permission_utils.h" #include "content/public/test/browser_test.h" #include "content/public/test/test_navigation_observer.h" #include "ui/views/view_utils.h" @@ -151,4 +153,17 @@ base::BindRepeating([](GURL url) {})); } +// Tests that the policy can be read and set browser-side. +IN_PROC_BROWSER_TEST_F(SunfishBrowserTest, BrowserPolicy) { + ChromeCaptureModeDelegate* delegate = ChromeCaptureModeDelegate::Get(); + EXPECT_TRUE(delegate->IsSearchAllowedByPolicy()); + EXPECT_TRUE(IsSunfishAllowedAndEnabled()); + + browser()->profile()->GetPrefs()->SetInteger( + lens::prefs::kLensOverlaySettings, + static_cast<int>(lens::prefs::LensOverlaySettingsPolicyValue::kDisabled)); + EXPECT_FALSE(delegate->IsSearchAllowedByPolicy()); + EXPECT_FALSE(IsSunfishAllowedAndEnabled()); +} + } // namespace ash
diff --git a/chrome/browser/ui/ash/editor_menu/editor_menu_card_context.cc b/chrome/browser/ui/ash/editor_menu/editor_menu_card_context.cc index 8d5449e..f2c70e99 100644 --- a/chrome/browser/ui/ash/editor_menu/editor_menu_card_context.cc +++ b/chrome/browser/ui/ash/editor_menu/editor_menu_card_context.cc
@@ -4,7 +4,6 @@ #include "chrome/browser/ui/ash/editor_menu/editor_menu_card_context.h" -#include "ash/constants/ash_features.h" #include "chrome/browser/ui/ash/editor_menu/editor_menu_strings.h" #include "chrome/browser/ui/ash/editor_menu/utils/text_and_image_mode.h" @@ -18,38 +17,32 @@ EditorMenuCardContext::~EditorMenuCardContext() = default; TextAndImageMode EditorMenuCardContext::text_and_image_mode() const { - // TODO: b:389553095 - With the introduction of EditorTextSelectionMode, - // merge kRewrite and kWrite into a single enum value. - switch (editor_mode_) { - case EditorMode::kRewrite: - case EditorMode::kWrite: - case EditorMode::kConsentNeeded: - if (editor_mode_ == EditorMode::kConsentNeeded && - !ash::features::IsMagicBoostRevampEnabled()) { - return TextAndImageMode::kPromoCard; - } - if (lobster_mode_ == LobsterMode::kBlocked) { - return text_selection_mode_ == - EditorMenuCardTextSelectionMode::kHasSelection - ? TextAndImageMode::kEditorRewriteOnly - : TextAndImageMode::kEditorWriteOnly; - } - return text_selection_mode_ == - EditorMenuCardTextSelectionMode::kHasSelection - ? TextAndImageMode::kEditorRewriteAndLobster - : TextAndImageMode::kEditorWriteAndLobster; - - case EditorMode::kSoftBlocked: - case EditorMode::kHardBlocked: - if (lobster_mode_ == LobsterMode::kBlocked) { - return TextAndImageMode::kBlocked; - } - - return text_selection_mode_ == - EditorMenuCardTextSelectionMode::kHasSelection - ? TextAndImageMode::kLobsterWithSelectedText - : TextAndImageMode::kLobsterWithNoSelectedText; + if (lobster_mode_ == LobsterMode::kBlocked) { + if (editor_mode_ == EditorMode::kRewrite) { + return TextAndImageMode::kEditorRewriteOnly; + } + if (editor_mode_ == EditorMode::kWrite) { + return TextAndImageMode::kEditorWriteOnly; + } + if (editor_mode_ == EditorMode::kConsentNeeded) { + return TextAndImageMode::kPromoCard; + } + return TextAndImageMode::kBlocked; } + + if (editor_mode_ == EditorMode::kRewrite) { + return TextAndImageMode::kEditorRewriteAndLobster; + } + if (editor_mode_ == EditorMode::kWrite) { + return TextAndImageMode::kEditorWriteAndLobster; + } + if (editor_mode_ == EditorMode::kConsentNeeded) { + return TextAndImageMode::kPromoCard; + } + if (lobster_mode_ == LobsterMode::kNoSelectedText) { + return TextAndImageMode::kLobsterWithNoSelectedText; + } + return TextAndImageMode::kLobsterWithSelectedText; } bool EditorMenuCardContext::consent_status_settled() const {
diff --git a/chrome/browser/ui/ash/editor_menu/editor_menu_card_context_unittest.cc b/chrome/browser/ui/ash/editor_menu/editor_menu_card_context_unittest.cc index b26966f..9e0f71e0 100644 --- a/chrome/browser/ui/ash/editor_menu/editor_menu_card_context_unittest.cc +++ b/chrome/browser/ui/ash/editor_menu/editor_menu_card_context_unittest.cc
@@ -4,8 +4,6 @@ #include "chrome/browser/ui/ash/editor_menu/editor_menu_card_context.h" -#include "ash/constants/ash_features.h" -#include "base/test/scoped_feature_list.h" #include "chrome/browser/ui/ash/editor_menu/editor_menu_strings.h" #include "chrome/browser/ui/ash/editor_menu/utils/text_and_image_mode.h" #include "chromeos/ash/components/editor_menu/public/cpp/preset_text_query.h" @@ -17,375 +15,172 @@ namespace { -struct TextAndImageModeTestCase { - bool magic_boost_revamp_enabled; - EditorMode editor_mode; - LobsterMode lobster_mode; - EditorMenuCardTextSelectionMode text_selection_mode; - TextAndImageMode expected_mode; +using ::testing::ElementsAre; + +class EditorMenuCardContextTest : public testing::Test { + public: + EditorMenuCardContextTest() = default; + + EditorMenuCardContextTest(const EditorMenuCardContextTest&) = delete; + EditorMenuCardContextTest& operator=(const EditorMenuCardContextTest&) = + delete; + + ~EditorMenuCardContextTest() override = default; }; -class EditorMenuCardContextTextAndImageModeTest - : public testing::TestWithParam<TextAndImageModeTestCase> {}; +TEST_F(EditorMenuCardContextTest, BlockedMode) { + EditorMenuCardContext context = EditorMenuCardContext() + .set_editor_mode(EditorMode::kHardBlocked) + .set_lobster_mode(LobsterMode::kBlocked) + .build(); -INSTANTIATE_TEST_SUITE_P( - , - EditorMenuCardContextTextAndImageModeTest, - testing::Values( - // magic_boost_revamp_enabled=false - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kHardBlocked, - LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kNoSelection, - TextAndImageMode::kBlocked}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kConsentNeeded, - LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kNoSelection, - TextAndImageMode::kPromoCard}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kWrite, LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kNoSelection, - TextAndImageMode::kEditorWriteOnly}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kRewrite, LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kHasSelection, - TextAndImageMode::kEditorRewriteOnly}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kHardBlocked, - LobsterMode::kSelectedText, - EditorMenuCardTextSelectionMode::kHasSelection, - TextAndImageMode::kLobsterWithSelectedText}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kWrite, - LobsterMode::kNoSelectedText, - EditorMenuCardTextSelectionMode::kNoSelection, - TextAndImageMode::kEditorWriteAndLobster}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kRewrite, - LobsterMode::kSelectedText, - EditorMenuCardTextSelectionMode::kHasSelection, - TextAndImageMode::kEditorRewriteAndLobster}, - // magic_boost_revamp_enabled=true - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kHardBlocked, - LobsterMode::kNoSelectedText, - EditorMenuCardTextSelectionMode::kNoSelection, - TextAndImageMode::kLobsterWithNoSelectedText}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kHardBlocked, - LobsterMode::kSelectedText, - EditorMenuCardTextSelectionMode::kHasSelection, - TextAndImageMode::kLobsterWithSelectedText}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kConsentNeeded, - LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kHasSelection, - TextAndImageMode::kEditorRewriteOnly}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kConsentNeeded, - LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kNoSelection, - TextAndImageMode::kEditorWriteOnly}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kConsentNeeded, - LobsterMode::kSelectedText, - EditorMenuCardTextSelectionMode::kHasSelection, - TextAndImageMode::kEditorRewriteAndLobster}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kConsentNeeded, - LobsterMode::kNoSelectedText, - EditorMenuCardTextSelectionMode::kNoSelection, - TextAndImageMode::kEditorWriteAndLobster}, - TextAndImageModeTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kWrite, - LobsterMode::kNoSelectedText, - EditorMenuCardTextSelectionMode::kNoSelection, - TextAndImageMode::kEditorWriteAndLobster}, - TextAndImageModeTestCase{ - /*magic_boost_revamp_enabled=*/true, EditorMode::kRewrite, - LobsterMode::kSelectedText, - EditorMenuCardTextSelectionMode::kHasSelection, - TextAndImageMode::kEditorRewriteAndLobster}, )); - -TEST_P(EditorMenuCardContextTextAndImageModeTest, TextAndImageModeIsCorrect) { - base::test::ScopedFeatureList feature_list; - - feature_list.InitWithFeatureState(ash::features::kMagicBoostRevamp, - GetParam().magic_boost_revamp_enabled); - - EditorMenuCardContext context = - EditorMenuCardContext() - .set_editor_mode(GetParam().editor_mode) - .set_lobster_mode(GetParam().lobster_mode) - .set_text_selection_mode(GetParam().text_selection_mode) - .build(); - - EXPECT_EQ(context.text_and_image_mode(), GetParam().expected_mode); + EXPECT_EQ(context.text_and_image_mode(), TextAndImageMode::kBlocked); } -struct PresetQueriesTestCase { - bool magic_boost_revamp_enabled; - EditorMode editor_mode; - LobsterMode lobster_mode; - EditorMenuCardTextSelectionMode text_selection_mode; - std::vector<PresetTextQuery> editor_preset_queries; - std::vector<PresetTextQuery> expected_queries; -}; - -class EditorMenuCardContextPresetQueriesTest - : public testing::TestWithParam<PresetQueriesTestCase> {}; - -INSTANTIATE_TEST_SUITE_P( - , - EditorMenuCardContextPresetQueriesTest, - testing::Values( - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kHardBlocked, LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kConsentNeeded, LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kRewrite, - LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kHasSelection, - /*editor_preset_queries=*/ - {PresetTextQuery(/*preset_text_id=*/"1", - u"Query 1", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"2", - u"Query 2", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"3", - u"Query 3", - PresetQueryCategory::kUnknown)}, - /*expected_queries=*/ - {PresetTextQuery(/*preset_text_id=*/"1", - u"Query 1", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"2", - u"Query 2", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"3", - u"Query 3", - PresetQueryCategory::kUnknown)}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kWrite, LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kHardBlocked, - LobsterMode::kNoSelectedText, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kConsentNeeded, - LobsterMode::kNoSelectedText, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kWrite, LobsterMode::kNoSelectedText, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kHardBlocked, - LobsterMode::kSelectedText, - EditorMenuCardTextSelectionMode::kHasSelection, - /*editor_preset_queries=*/ - {}, - /*expected_queries=*/ - {PresetTextQuery( - /*preset_text_id=*/kLobsterPresetId, - GetEditorMenuLobsterChipLabel(), - PresetQueryCategory::kLobster)}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/false, - EditorMode::kConsentNeeded, - LobsterMode::kSelectedText, - EditorMenuCardTextSelectionMode::kHasSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/ - {}}, - PresetQueriesTestCase{ - /*magic_boost_revamp_enabled=*/false, - EditorMode::kRewrite, - LobsterMode::kSelectedText, - EditorMenuCardTextSelectionMode::kHasSelection, - /*editor_preset_queries=*/ - {PresetTextQuery(/*preset_text_id=*/"1", - u"Query 1", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"2", - u"Query 2", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"3", - u"Query 3", - PresetQueryCategory::kUnknown)}, - /*expected_queries=*/ - {PresetTextQuery(/*preset_text_id=*/"1", - u"Query 1", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"2", - u"Query 2", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"3", - u"Query 3", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/kLobsterPresetId, - GetEditorMenuLobsterChipLabel(), - PresetQueryCategory::kLobster)}}, - - // MagicBoostRevamp enabled - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kHardBlocked, LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kConsentNeeded, LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kRewrite, - LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kHasSelection, - /*editor_preset_queries=*/ - {PresetTextQuery(/*preset_text_id=*/"1", - u"Query 1", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"2", - u"Query 2", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"3", - u"Query 3", - PresetQueryCategory::kUnknown)}, - /*expected_queries=*/ - {PresetTextQuery(/*preset_text_id=*/"1", - u"Query 1", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"2", - u"Query 2", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"3", - u"Query 3", - PresetQueryCategory::kUnknown)}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kWrite, LobsterMode::kBlocked, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kHardBlocked, - LobsterMode::kNoSelectedText, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kConsentNeeded, - LobsterMode::kNoSelectedText, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kWrite, LobsterMode::kNoSelectedText, - EditorMenuCardTextSelectionMode::kNoSelection, - /*editor_preset_queries=*/{}, - /*expected_queries=*/{}}, - PresetQueriesTestCase{/*magic_boost_revamp_enabled=*/true, - EditorMode::kHardBlocked, - LobsterMode::kSelectedText, - EditorMenuCardTextSelectionMode::kHasSelection, - /*editor_preset_queries=*/ - {}, - /*expected_queries=*/ - {PresetTextQuery( - /*preset_text_id=*/kLobsterPresetId, - GetEditorMenuLobsterChipLabel(), - PresetQueryCategory::kLobster)}}, - PresetQueriesTestCase{ - /*magic_boost_revamp_enabled=*/true, - EditorMode::kConsentNeeded, - LobsterMode::kSelectedText, - EditorMenuCardTextSelectionMode::kHasSelection, - /*editor_preset_queries=*/ - {PresetTextQuery(/*preset_text_id=*/"1", - u"Query 1", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"2", - u"Query 2", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"3", - u"Query 3", - PresetQueryCategory::kUnknown)}, - /*expected_queries=*/ - {PresetTextQuery(/*preset_text_id=*/"1", - u"Query 1", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"2", - u"Query 2", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"3", - u"Query 3", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/kLobsterPresetId, - GetEditorMenuLobsterChipLabel(), - PresetQueryCategory::kLobster)}}, - PresetQueriesTestCase{ - /*magic_boost_revamp_enabled=*/true, - EditorMode::kRewrite, - LobsterMode::kSelectedText, - EditorMenuCardTextSelectionMode::kHasSelection, - /*editor_preset_queries=*/ - {PresetTextQuery(/*preset_text_id=*/"1", - u"Query 1", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"2", - u"Query 2", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"3", - u"Query 3", - PresetQueryCategory::kUnknown)}, - /*expected_queries=*/ - {PresetTextQuery(/*preset_text_id=*/"1", - u"Query 1", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"2", - u"Query 2", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/"3", - u"Query 3", - PresetQueryCategory::kUnknown), - PresetTextQuery(/*preset_text_id=*/kLobsterPresetId, - GetEditorMenuLobsterChipLabel(), - PresetQueryCategory::kLobster)}}, ) - -); - -TEST_P(EditorMenuCardContextPresetQueriesTest, PresetQueriesAreCorrect) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatureState( - ash::features::kMagicBoostRevamp, GetParam().magic_boost_revamp_enabled); - +TEST_F(EditorMenuCardContextTest, PromoCardMode) { EditorMenuCardContext context = EditorMenuCardContext() - .set_editor_mode(GetParam().editor_mode) - .set_lobster_mode(GetParam().lobster_mode) - .set_text_selection_mode( - GetParam().text_selection_mode) // Add this line - .set_editor_preset_queries(GetParam().editor_preset_queries) + .set_editor_mode(EditorMode::kConsentNeeded) + .set_lobster_mode(LobsterMode::kBlocked) + .build(); + + EXPECT_EQ(context.text_and_image_mode(), TextAndImageMode::kPromoCard); +} + +TEST_F(EditorMenuCardContextTest, EditorWriteOnly) { + EditorMenuCardContext context = EditorMenuCardContext() + .set_editor_mode(EditorMode::kWrite) + .set_lobster_mode(LobsterMode::kBlocked) + .build(); + + EXPECT_EQ(context.text_and_image_mode(), TextAndImageMode::kEditorWriteOnly); +} + +TEST_F(EditorMenuCardContextTest, EditorRewriteOnly) { + EditorMenuCardContext context = EditorMenuCardContext() + .set_editor_mode(EditorMode::kRewrite) + .set_lobster_mode(LobsterMode::kBlocked) + .build(); + + EXPECT_EQ(context.text_and_image_mode(), + TextAndImageMode::kEditorRewriteOnly); +} + +TEST_F(EditorMenuCardContextTest, LobsterWithSelectedText) { + EditorMenuCardContext context = + EditorMenuCardContext() + .set_editor_mode(EditorMode::kHardBlocked) + .set_lobster_mode(LobsterMode::kSelectedText) + .build(); + + EXPECT_EQ(context.text_and_image_mode(), + TextAndImageMode::kLobsterWithSelectedText); +} + +TEST_F(EditorMenuCardContextTest, EditorWriteAndLobster) { + EditorMenuCardContext context = + EditorMenuCardContext() + .set_editor_mode(EditorMode::kWrite) + .set_lobster_mode(LobsterMode::kNoSelectedText) + .build(); + + EXPECT_EQ(context.text_and_image_mode(), + TextAndImageMode::kEditorWriteAndLobster); +} + +TEST_F(EditorMenuCardContextTest, EditorRewriteAndLobster) { + EditorMenuCardContext context = + EditorMenuCardContext() + .set_editor_mode(EditorMode::kRewrite) + .set_lobster_mode(LobsterMode::kSelectedText) + .build(); + + EXPECT_EQ(context.text_and_image_mode(), + TextAndImageMode::kEditorRewriteAndLobster); +} + +TEST_F(EditorMenuCardContextTest, + ReturnsEditorPresetQueriesWhenLobsterIsBlocked) { + EditorMenuCardContext context = + EditorMenuCardContext() + .set_editor_mode(EditorMode::kRewrite) + .set_lobster_mode(LobsterMode::kBlocked) + .set_editor_preset_queries({ + PresetTextQuery(/*preset_text_id=*/"1", u"Query 1", + PresetQueryCategory::kUnknown), + PresetTextQuery(/*preset_text_id=*/"2", u"Query 2", + PresetQueryCategory::kUnknown), + PresetTextQuery(/*preset_text_id=*/"3", u"Query 3", + PresetQueryCategory::kUnknown), + }) .build(); EXPECT_THAT(context.preset_queries(), - testing::ElementsAreArray(GetParam().expected_queries)); + ElementsAre(PresetTextQuery(/*preset_text_id=*/"1", u"Query 1", + PresetQueryCategory::kUnknown), + PresetTextQuery(/*preset_text_id=*/"2", u"Query 2", + PresetQueryCategory::kUnknown), + PresetTextQuery(/*preset_text_id=*/"3", u"Query 3", + PresetQueryCategory::kUnknown))); +} + +TEST_F(EditorMenuCardContextTest, ReturnsNoChipsWhenBothFeaturesAreBlocked) { + EditorMenuCardContext context = EditorMenuCardContext() + .set_editor_mode(EditorMode::kHardBlocked) + .set_lobster_mode(LobsterMode::kBlocked) + .build(); + + EXPECT_TRUE(context.preset_queries().empty()); +} + +TEST_F(EditorMenuCardContextTest, ReturnsNoChipsInPromoCardMode) { + EditorMenuCardContext context = + EditorMenuCardContext() + .set_editor_mode(EditorMode::kConsentNeeded) + .set_lobster_mode(LobsterMode::kBlocked) + .build(); + + EXPECT_TRUE(context.preset_queries().empty()); +} + +TEST_F(EditorMenuCardContextTest, + ReturnsNoChipsWhenBothFeaturesAreEnabledInWriteMode) { + EditorMenuCardContext context = + EditorMenuCardContext() + .set_editor_mode(EditorMode::kWrite) + .set_lobster_mode(LobsterMode::kNoSelectedText) + .build(); + + EXPECT_TRUE(context.preset_queries().empty()); +} + +TEST_F(EditorMenuCardContextTest, + ReturnsEditorAndLobsterChipWhenBothFeaturesAreEnabledInRewriteMode) { + EditorMenuCardContext context = + EditorMenuCardContext() + .set_editor_mode(EditorMode::kRewrite) + .set_lobster_mode(LobsterMode::kSelectedText) + .set_editor_preset_queries({ + PresetTextQuery(/*preset_text_id=*/"1", u"Query 1", + PresetQueryCategory::kUnknown), + PresetTextQuery(/*preset_text_id=*/"2", u"Query 2", + PresetQueryCategory::kUnknown), + PresetTextQuery(/*preset_text_id=*/"3", u"Query 3", + PresetQueryCategory::kUnknown), + }) + .build(); + + EXPECT_THAT(context.preset_queries(), + ElementsAre(PresetTextQuery(/*preset_text_id=*/"1", u"Query 1", + PresetQueryCategory::kUnknown), + PresetTextQuery(/*preset_text_id=*/"2", u"Query 2", + PresetQueryCategory::kUnknown), + PresetTextQuery(/*preset_text_id=*/"3", u"Query 3", + PresetQueryCategory::kUnknown), + PresetTextQuery( + /*preset_text_id=*/kLobsterPresetId, + GetEditorMenuLobsterChipLabel(), + PresetQueryCategory::kLobster))); } } // namespace
diff --git a/chrome/browser/ui/ash/editor_menu/editor_menu_controller_impl.cc b/chrome/browser/ui/ash/editor_menu/editor_menu_controller_impl.cc index 00f8d8a..8ce920ee 100644 --- a/chrome/browser/ui/ash/editor_menu/editor_menu_controller_impl.cc +++ b/chrome/browser/ui/ash/editor_menu/editor_menu_controller_impl.cc
@@ -15,7 +15,6 @@ #include "ash/webui/settings/public/constants/routes.mojom.h" #include "ash/webui/settings/public/constants/setting.mojom.h" #include "base/feature_list.h" -#include "base/notreached.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" @@ -27,7 +26,6 @@ #include "chrome/browser/ash/lobster/lobster_system_state_provider.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/ash/editor_menu/editor_manager_factory.h" -#include "chrome/browser/ui/ash/editor_menu/editor_menu_card_context.h" #include "chrome/browser/ui/ash/editor_menu/editor_menu_promo_card_view.h" #include "chrome/browser/ui/ash/editor_menu/editor_menu_strings.h" #include "chrome/browser/ui/ash/editor_menu/editor_menu_view.h" @@ -106,9 +104,7 @@ /*text_selection_mode=*/selected_text.length() > 0 ? EditorTextSelectionMode::kHasSelection : EditorTextSelectionMode::kNoSelection, - /*consent_status_settled=*/false, - /*preset_queries=*/{})); - return; + false, {})); } card_session_->editor_manager()->GetEditorPanelContext(base::BindOnce( @@ -282,11 +278,6 @@ .set_editor_preset_queries(editor_context.preset_queries) .set_editor_mode(editor_context.mode) .set_lobster_mode(lobster_mode) - .set_text_selection_mode( - editor_context.text_selection_mode == - EditorTextSelectionMode::kHasSelection - ? EditorMenuCardTextSelectionMode::kHasSelection - : EditorMenuCardTextSelectionMode::kNoSelection) .build()); } @@ -300,11 +291,6 @@ .set_editor_preset_queries(editor_context.preset_queries) .set_editor_mode(editor_context.mode) .set_lobster_mode(lobster_mode) - .set_text_selection_mode( - editor_context.text_selection_mode == - EditorTextSelectionMode::kHasSelection - ? EditorMenuCardTextSelectionMode::kHasSelection - : EditorMenuCardTextSelectionMode::kNoSelection) .build(); TextAndImageMode text_and_image_mode = @@ -314,9 +300,6 @@ case TextAndImageMode::kBlocked: break; case TextAndImageMode::kPromoCard: - if (ash::features::IsMagicBoostRevampEnabled()) { - NOTREACHED(); - } editor_menu_widget_ = EditorMenuPromoCardView::CreateWidget(anchor_bounds, this); editor_menu_widget_->ShowInactive();
diff --git a/chrome/browser/ui/browser_tabrestore.cc b/chrome/browser/ui/browser_tabrestore.cc index f4e0d31..73e9e6c 100644 --- a/chrome/browser/ui/browser_tabrestore.cc +++ b/chrome/browser/ui/browser_tabrestore.cc
@@ -294,7 +294,8 @@ int insertion_index = tab_strip->active_index(); tab_strip->InsertWebContentsAt( insertion_index + 1, std::move(web_contents), - AddTabTypes::ADD_ACTIVE | AddTabTypes::ADD_INHERIT_OPENER); + AddTabTypes::ADD_ACTIVE | AddTabTypes::ADD_INHERIT_OPENER, + tab_strip->GetTabGroupForTab(insertion_index)); tab_strip->CloseWebContentsAt(insertion_index, TabCloseTypes::CLOSE_NONE); LoadRestoredTabIfVisible(browser, raw_web_contents);
diff --git a/chrome/browser/ui/browser_window/browser_window_features.cc b/chrome/browser/ui/browser_window/browser_window_features.cc index e40ffd46..1982aa5e 100644 --- a/chrome/browser/ui/browser_window/browser_window_features.cc +++ b/chrome/browser/ui/browser_window/browser_window_features.cc
@@ -128,7 +128,8 @@ #if BUILDFLAG(ENABLE_GLIC) if (GlicEnabling::IsProfileEligible(browser->GetProfile())) { DCHECK(features::IsTabstripComboButtonEnabled()); - glic_nudge_controller_ = std::make_unique<tabs::GlicNudgeController>(); + glic_nudge_controller_ = + std::make_unique<tabs::GlicNudgeController>(browser); } #endif // BUILDFLAG(ENABLE_GLIC) }
diff --git a/chrome/browser/ui/cookie_controls/cookie_controls_controller_unittest.cc b/chrome/browser/ui/cookie_controls/cookie_controls_controller_unittest.cc index ddcec244..310038d 100644 --- a/chrome/browser/ui/cookie_controls/cookie_controls_controller_unittest.cc +++ b/chrome/browser/ui/cookie_controls/cookie_controls_controller_unittest.cc
@@ -542,8 +542,7 @@ cookie_controls()->Update(web_contents()); testing::Mock::VerifyAndClearExpectations(mock()); - // Create incognito web_contents and - // content_settings::CookieControlsController. + // Create incognito web_contents and CookieControlsController. std::unique_ptr<content::WebContents> incognito_web_contents = content::WebContentsTester::CreateTestWebContents( profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true), nullptr); @@ -552,7 +551,7 @@ std::make_unique<PageSpecificContentSettingsDelegate>( incognito_web_contents.get())); auto* tester = content::WebContentsTester::For(incognito_web_contents.get()); - MockCookieControlsObserver incognito_mock_; + MockCookieControlsObserver incognito_mock; content_settings::CookieControlsController incognito_cookie_controls( CookieSettingsFactory::GetForProfile( profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true)), @@ -560,11 +559,11 @@ HostContentSettingsMapFactory::GetForProfile(profile()), TrackingProtectionSettingsFactory::GetForProfile(profile()), /*is_incognito_profile=*/true); - incognito_cookie_controls.AddObserver(&incognito_mock_); + incognito_cookie_controls.AddObserver(&incognito_mock); // Navigate incognito web_contents to the same URL. tester->NavigateAndCommit(GURL(kUrl)); - EXPECT_CALL(incognito_mock_, + EXPECT_CALL(incognito_mock, OnStatusChanged( /*controls_visible=*/true, /*protections_on=*/true, CookieControlsEnforcement::kNoEnforcement, @@ -574,13 +573,13 @@ BlockingStatus::kBlocked))); EXPECT_CALL( - incognito_mock_, + incognito_mock, OnCookieControlsIconStatusChanged( /*icon_visible=*/false, /*protections_on=*/true, CookieBlocking3pcdStatus::kNotIn3pcd, /*should_highlight=*/false)); incognito_cookie_controls.Update(incognito_web_contents.get()); testing::Mock::VerifyAndClearExpectations(mock()); - testing::Mock::VerifyAndClearExpectations(&incognito_mock_); + testing::Mock::VerifyAndClearExpectations(&incognito_mock); // Allow cookies in regular mode should also allow in incognito but enforced // through regular mode. @@ -597,7 +596,7 @@ CookieBlocking3pcdStatus::kNotIn3pcd, /*should_highlight=*/false)); - EXPECT_CALL(incognito_mock_, + EXPECT_CALL(incognito_mock, OnStatusChanged( /*controls_visible=*/true, /*protections_on=*/false, CookieControlsEnforcement::kEnforcedByCookieSetting, @@ -607,13 +606,13 @@ BlockingStatus::kAllowed))); EXPECT_CALL( - incognito_mock_, + incognito_mock, OnCookieControlsIconStatusChanged( /*icon_visible=*/true, /*protections_on=*/false, CookieBlocking3pcdStatus::kNotIn3pcd, /*should_highlight=*/false)); cookie_controls()->OnCookieBlockingEnabledForSite(false); testing::Mock::VerifyAndClearExpectations(mock()); - testing::Mock::VerifyAndClearExpectations(&incognito_mock_); + testing::Mock::VerifyAndClearExpectations(&incognito_mock); // This should be enforced regardless of the default cookie setting in the // default profile. @@ -633,7 +632,7 @@ CookieBlocking3pcdStatus::kNotIn3pcd, /*should_highlight=*/false)); - EXPECT_CALL(incognito_mock_, + EXPECT_CALL(incognito_mock, OnStatusChanged( /*controls_visible=*/true, /*protections_on=*/false, CookieControlsEnforcement::kEnforcedByCookieSetting, @@ -643,7 +642,7 @@ BlockingStatus::kAllowed))); EXPECT_CALL( - incognito_mock_, + incognito_mock, OnCookieControlsIconStatusChanged( /*icon_visible=*/true, /*protections_on=*/false, CookieBlocking3pcdStatus::kNotIn3pcd, /*should_highlight=*/false)); @@ -652,7 +651,7 @@ static_cast<int>(content_settings::CookieControlsMode::kIncognitoOnly)); incognito_cookie_controls.Update(incognito_web_contents.get()); testing::Mock::VerifyAndClearExpectations(mock()); - testing::Mock::VerifyAndClearExpectations(&incognito_mock_); + testing::Mock::VerifyAndClearExpectations(&incognito_mock); } TEST_F(CookieControlsUserBypassTest, ThirdPartyCookiesException) { @@ -1766,15 +1765,6 @@ void SetUp() override { CookieControlsUserBypassTest::SetUp(); - if (std::get<0>(GetParam())) { - cookie_settings()->SetThirdPartyCookieSetting( - GURL(kUrl), ContentSetting::CONTENT_SETTING_BLOCK); - } else { - tracking_protection_settings()->AddTrackingProtectionException( - GURL(kUrl)); - cookie_settings()->SetThirdPartyCookieSetting( - GURL(kUrl), ContentSetting::CONTENT_SETTING_ALLOW); - } std::vector<base::test::FeatureRef> enabled_features = {}; if (std::get<1>(GetParam())) { @@ -1814,22 +1804,53 @@ return features_list; } + void AddUserBypassException(Profile* profile) { + if (std::get<0>(GetParam())) { + CookieSettingsFactory::GetForProfile(profile)->SetThirdPartyCookieSetting( + GURL(kUrl), ContentSetting::CONTENT_SETTING_BLOCK); + } else { + TrackingProtectionSettingsFactory::GetForProfile(profile) + ->AddTrackingProtectionException(GURL(kUrl)); + CookieSettingsFactory::GetForProfile(profile)->SetThirdPartyCookieSetting( + GURL(kUrl), ContentSetting::CONTENT_SETTING_ALLOW); + } + } + private: base::test::ScopedFeatureList feature_list_; }; TEST_P(CookieControlsUserBypassTrackingProtectionUiTest, - AddsActFeaturesToVectorBasedOnFeatureAndExceptionStatus) { - NavigateAndCommit(GURL(kUrl)); - EXPECT_CALL(*mock(), + AddsActFeaturesToVectorInIncognitoBasedOnFeatureAndExceptionStatus) { + auto* incognito_profile = + profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true); + std::unique_ptr<content::WebContents> incognito_web_contents = + content::WebContentsTester::CreateTestWebContents(incognito_profile, + nullptr); + content_settings::PageSpecificContentSettings::CreateForWebContents( + incognito_web_contents.get(), + std::make_unique<PageSpecificContentSettingsDelegate>( + incognito_web_contents.get())); + content_settings::CookieControlsController incognito_cookie_controls( + CookieSettingsFactory::GetForProfile(incognito_profile), + CookieSettingsFactory::GetForProfile(profile()), + HostContentSettingsMapFactory::GetForProfile(incognito_profile), + TrackingProtectionSettingsFactory::GetForProfile(incognito_profile), + /*is_incognito_profile=*/true); + MockCookieControlsObserver incognito_mock; + incognito_cookie_controls.AddObserver(&incognito_mock); + AddUserBypassException(incognito_profile); + auto* tester = content::WebContentsTester::For(incognito_web_contents.get()); + tester->NavigateAndCommit(GURL(kUrl)); + + EXPECT_CALL(incognito_mock, OnStatusChanged( /*controls_visible=*/true, std::get<0>(GetParam()), CookieControlsEnforcement::kNoEnforcement, CookieBlocking3pcdStatus::kNotIn3pcd, zero_expiration(), GetFeatureVector(CookieControlsEnforcement::kNoEnforcement))); - - cookie_controls()->Update(web_contents()); - testing::Mock::VerifyAndClearExpectations(mock()); + incognito_cookie_controls.Update(incognito_web_contents.get()); + testing::Mock::VerifyAndClearExpectations(&incognito_mock); } INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/ui/performance_controls/memory_saver_opt_in_iph_controller.cc b/chrome/browser/ui/performance_controls/memory_saver_opt_in_iph_controller.cc index 69f46e68..b2f8e2da7 100644 --- a/chrome/browser/ui/performance_controls/memory_saver_opt_in_iph_controller.cc +++ b/chrome/browser/ui/performance_controls/memory_saver_opt_in_iph_controller.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/performance_controls/memory_saver_opt_in_iph_controller.h" +#include "base/system/sys_info.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" @@ -13,6 +14,10 @@ #include "components/performance_manager/public/user_tuning/prefs.h" #include "components/prefs/pref_service.h" +// Devices with at least 16 GB of total memory should never be shown the memory +// saver opt-in IPH. +constexpr int kMemoryCap16GB = 16 * 1024; + MemorySaverOptInIPHController::MemorySaverOptInIPHController( BrowserWindowInterface* interface) : browser_window_interface_(interface) { @@ -39,7 +44,8 @@ auto* const manager = performance_manager::user_tuning:: UserPerformanceTuningManager::GetInstance(); if (manager->IsMemorySaverModeDefault() && - !manager->IsMemorySaverModeActive()) { + !manager->IsMemorySaverModeActive() && + base::SysInfo::AmountOfPhysicalMemoryMB() <= kMemoryCap16GB) { browser_window_interface_->GetUserEducationInterface() ->MaybeShowStartupFeaturePromo( feature_engagement::kIPHMemorySaverModeFeature);
diff --git a/chrome/browser/ui/tabs/glic_nudge_controller.cc b/chrome/browser/ui/tabs/glic_nudge_controller.cc index 69b79fe..1624cec 100644 --- a/chrome/browser/ui/tabs/glic_nudge_controller.cc +++ b/chrome/browser/ui/tabs/glic_nudge_controller.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/tabs/glic_nudge_controller.h" +#include "chrome/browser/contextual_cueing/contextual_cueing_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/views/tabs/tab_strip_action_container.h" @@ -11,7 +12,13 @@ namespace tabs { -GlicNudgeController::GlicNudgeController() = default; +GlicNudgeController::GlicNudgeController( + BrowserWindowInterface* browser_window_interface) + : browser_window_interface_(browser_window_interface) { + browser_subscriptions_.push_back( + browser_window_interface->RegisterActiveTabDidChange(base::BindRepeating( + &GlicNudgeController::OnActiveTabChanged, base::Unretained(this)))); +} GlicNudgeController::~GlicNudgeController() = default; @@ -21,9 +28,29 @@ void GlicNudgeController::UpdateNudgeLabel(content::WebContents* web_contents, const std::string& nudge_label) { + auto* const tab_interface = + browser_window_interface_->GetActiveTabInterface(); + if (tab_interface->GetContents() != web_contents) { + return; + } for (auto& observer : observers_) { observer.OnTriggerGlicNudgeUI(nudge_label); } } +void GlicNudgeController::OnActiveTabChanged( + BrowserWindowInterface* browser_interface) { + auto* const tab_interface = browser_interface->GetActiveTabInterface(); + auto* web_contents = tab_interface->GetContents(); + auto* contextual_cueing_helper = + contextual_cueing::ContextualCueingHelper::FromWebContents(web_contents); + if (!contextual_cueing_helper) { + return; + } + for (auto& observer : observers_) { + observer.OnTriggerGlicNudgeUI( + contextual_cueing_helper->last_navigation_cue_label()); + } +} + } // namespace tabs
diff --git a/chrome/browser/ui/tabs/glic_nudge_controller.h b/chrome/browser/ui/tabs/glic_nudge_controller.h index 7665281..3c94654 100644 --- a/chrome/browser/ui/tabs/glic_nudge_controller.h +++ b/chrome/browser/ui/tabs/glic_nudge_controller.h
@@ -10,9 +10,11 @@ #include "chrome/browser/ui/tabs/glic_nudge_observer.h" #include "components/keyed_service/core/keyed_service.h" +class BrowserWindowInterface; + namespace content { class WebContents; -} +} // namespace content namespace tabs { @@ -20,7 +22,8 @@ // targeted. class GlicNudgeController { public: - GlicNudgeController(); + explicit GlicNudgeController( + BrowserWindowInterface* browser_window_interface); GlicNudgeController(const GlicNudgeController&) = delete; GlicNudgeController& operator=(const GlicNudgeController& other) = delete; virtual ~GlicNudgeController(); @@ -37,14 +40,24 @@ return observers_.HasObserver(observer); } + // Updates the `nudge_label` for `web_contents`, if the WebContents is active. void UpdateNudgeLabel(content::WebContents* web_contents, const std::string& nudge_label); private: + // Called when the active tab changes, to update the nudge UI appropriate for + // the tab. + void OnActiveTabChanged(BrowserWindowInterface* browser_interface); + // Returns whether the nudge should be shown in the tabstrip for glic. bool GlicNudgeCriteriaMet(); + // The BrowserWindowInterface that owns `this`. + const raw_ptr<BrowserWindowInterface> browser_window_interface_; + base::ObserverList<GlicNudgeObserver> observers_; + + std::vector<base::CallbackListSubscription> browser_subscriptions_; }; } // namespace tabs
diff --git a/chrome/browser/ui/tabs/glic_nudge_observer.h b/chrome/browser/ui/tabs/glic_nudge_observer.h index 6e355df..2ae0357 100644 --- a/chrome/browser/ui/tabs/glic_nudge_observer.h +++ b/chrome/browser/ui/tabs/glic_nudge_observer.h
@@ -9,7 +9,9 @@ class GlicNudgeObserver : public base::CheckedObserver { public: - // Called when all checks pass to be able to show the glic nudge UI. + // Called when the glic nudge UI needs to be triggered, or to be turned off. + // When the UI needs to be shown `label' holds the nudge label. When the nudge + // UI should be turned off, `label` is empty. virtual void OnTriggerGlicNudgeUI(std::string label) {} };
diff --git a/chrome/browser/ui/tabs/public/tab_features.h b/chrome/browser/ui/tabs/public/tab_features.h index 23b47c2e..a7f2804 100644 --- a/chrome/browser/ui/tabs/public/tab_features.h +++ b/chrome/browser/ui/tabs/public/tab_features.h
@@ -135,10 +135,6 @@ return commerce_ui_tab_helper_.get(); } - contextual_cueing::ContextualCueingHelper* contextual_cueing_tab_helper() { - return contextual_cueing_helper_.get(); - } - privacy_sandbox::PrivacySandboxTabObserver* privacy_sandbox_tab_observer() { return privacy_sandbox_tab_observer_.get(); } @@ -212,10 +208,6 @@ // Responsible for commerce related features. std::unique_ptr<commerce::CommerceUiTabHelper> commerce_ui_tab_helper_; - // Responsible for contextual cueing features. - std::unique_ptr<contextual_cueing::ContextualCueingHelper> - contextual_cueing_helper_; - // Responsible for updating status indicator of the pinned translate button. std::unique_ptr<PinnedTranslateActionListener> pinned_translate_action_listener_;
diff --git a/chrome/browser/ui/tabs/tab_features.cc b/chrome/browser/ui/tabs/tab_features.cc index 2b5ac6d..b714aede 100644 --- a/chrome/browser/ui/tabs/tab_features.cc +++ b/chrome/browser/ui/tabs/tab_features.cc
@@ -138,11 +138,8 @@ CreateCommerceUiTabHelper(tab.GetContents(), profile); } - if (!profile->IsIncognitoProfile()) { - contextual_cueing_helper_ = - contextual_cueing::ContextualCueingHelper::MaybeCreateForWebContents( - tab.GetContents()); - } + contextual_cueing::ContextualCueingHelper::MaybeCreateForWebContents( + tab.GetContents()); privacy_sandbox_tab_observer_ = std::make_unique<privacy_sandbox::PrivacySandboxTabObserver>(
diff --git a/chrome/browser/ui/views/autofill/popup/popup_cell_utils.cc b/chrome/browser/ui/views/autofill/popup/popup_cell_utils.cc index c14a754..032d3aa4 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_cell_utils.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_cell_utils.cc
@@ -143,6 +143,7 @@ case Suggestion::Icon::kOfferTag: case Suggestion::Icon::kPenSpark: case Suggestion::Icon::kPlusAddress: + case Suggestion::Icon::kSaveAndFill: case Suggestion::Icon::kScanCreditCard: case Suggestion::Icon::kSettings: case Suggestion::Icon::kSettingsAndroid: @@ -317,6 +318,8 @@ #else return ImageModelFromVectorIcon(vector_icons::kEmailIcon, kIconSize); #endif + case Suggestion::Icon::kSaveAndFill: + return ImageModelFromVectorIcon(kCreditCardIcon, kIconSize); case Suggestion::Icon::kSettings: return ImageModelFromVectorIcon(omnibox::kProductIcon, kIconSize); case Suggestion::Icon::kUndo:
diff --git a/chrome/browser/ui/views/dark_mode_manager_linux.cc b/chrome/browser/ui/views/dark_mode_manager_linux.cc index 968be4a..e58b7d3 100644 --- a/chrome/browser/ui/views/dark_mode_manager_linux.cc +++ b/chrome/browser/ui/views/dark_mode_manager_linux.cc
@@ -18,21 +18,9 @@ namespace ui { -namespace { - -scoped_refptr<dbus::Bus> CreateBus() { - dbus::Bus::Options options; - options.bus_type = dbus::Bus::SESSION; - options.connection_type = dbus::Bus::PRIVATE; - options.dbus_task_runner = dbus_thread_linux::GetTaskRunner(); - return base::MakeRefCounted<dbus::Bus>(options); -} - -} // namespace - DarkModeManagerLinux::DarkModeManagerLinux() : DarkModeManagerLinux( - CreateBus(), + dbus_thread_linux::GetSharedSystemBus(), ui::GetDefaultLinuxUiTheme(), &ui::GetLinuxUiThemes(), std::vector<raw_ptr<ui::NativeTheme, VectorExperimental>>{ @@ -96,16 +84,7 @@ } } -DarkModeManagerLinux::~DarkModeManagerLinux() { - settings_proxy_ = nullptr; - dbus::Bus* const bus_ptr = bus_.get(); - // `task_runner` may be nullptr in testing. - if (auto* task_runner = bus_ptr->GetDBusTaskRunner()) { - task_runner->PostTask( - FROM_HERE, - base::BindOnce(&dbus::Bus::ShutdownAndBlock, std::move(bus_))); - } -} +DarkModeManagerLinux::~DarkModeManagerLinux() = default; void DarkModeManagerLinux::OnNativeThemeUpdated( ui::NativeTheme* observed_theme) {
diff --git a/chrome/browser/ui/views/dark_mode_manager_linux_unittest.cc b/chrome/browser/ui/views/dark_mode_manager_linux_unittest.cc index e928a27..313af3a 100644 --- a/chrome/browser/ui/views/dark_mode_manager_linux_unittest.cc +++ b/chrome/browser/ui/views/dark_mode_manager_linux_unittest.cc
@@ -168,7 +168,6 @@ } void TearDown() override { - EXPECT_CALL(*mock_bus_, GetDBusTaskRunner()).WillOnce(Return(nullptr)); manager_.reset(); }
diff --git a/chrome/browser/ui/views/frame/dbus_appmenu_registrar.cc b/chrome/browser/ui/views/frame/dbus_appmenu_registrar.cc index 36466d1..ec58351 100644 --- a/chrome/browser/ui/views/frame/dbus_appmenu_registrar.cc +++ b/chrome/browser/ui/views/frame/dbus_appmenu_registrar.cc
@@ -53,13 +53,8 @@ menus_.erase(menu); } -DbusAppmenuRegistrar::DbusAppmenuRegistrar() { - dbus::Bus::Options bus_options; - bus_options.bus_type = dbus::Bus::SESSION; - bus_options.connection_type = dbus::Bus::PRIVATE; - bus_options.dbus_task_runner = dbus_thread_linux::GetTaskRunner(); - bus_ = base::MakeRefCounted<dbus::Bus>(bus_options); - +DbusAppmenuRegistrar::DbusAppmenuRegistrar() + : bus_(dbus_thread_linux::GetSharedSessionBus()) { registrar_proxy_ = bus_->GetObjectProxy( kAppMenuRegistrarName, dbus::ObjectPath(kAppMenuRegistrarPath));
diff --git a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view_interactive_uitest.cc index 5e31ecc..3971b1c8 100644 --- a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view_interactive_uitest.cc
@@ -16,13 +16,9 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h" -#include "chrome/browser/ui/views/location_bar/location_bar_view.h" -#include "chrome/browser/ui/views/permissions/chip/permission_dashboard_controller.h" -#include "chrome/browser/ui/views/permissions/chip/permission_dashboard_view.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" -#include "components/permissions/permission_request_manager.h" #include "content/public/browser/document_picture_in_picture_window_controller.h" #include "content/public/browser/web_contents.h" #include "content/public/common/isolated_world_ids.h" @@ -110,49 +106,6 @@ std::vector<gfx::Animation*> animations_; }; -class ChipAnimationObserver : PermissionChipView::Observer { - public: - enum class QuitOnEvent { - kExpand, - kCollapse, - kVisibiltyTrue, - kVisibiltyFalse, - }; - - explicit ChipAnimationObserver(PermissionChipView* chip) { - observation_.Observe(chip); - } - - void WaitForChip() { loop_.Run(); } - - void OnExpandAnimationEnded() override { - if (quit_on_event == QuitOnEvent::kExpand) { - loop_.Quit(); - } - } - void OnCollapseAnimationEnded() override { - if (quit_on_event == QuitOnEvent::kCollapse) { - loop_.Quit(); - } - } - - void OnChipVisibilityChanged(bool is_visible) override { - if (quit_on_event == QuitOnEvent::kVisibiltyTrue && is_visible) { - loop_.Quit(); - return; - } - - if (quit_on_event == QuitOnEvent::kVisibiltyFalse && !is_visible) { - loop_.Quit(); - } - } - - base::ScopedObservation<PermissionChipView, PermissionChipView::Observer> - observation_{this}; - base::RunLoop loop_; - QuitOnEvent quit_on_event = QuitOnEvent::kExpand; -}; - class PictureInPictureBrowserFrameViewTest : public WebRtcTestBase, public AnimationTimingTest { public: @@ -726,83 +679,6 @@ } } -IN_PROC_BROWSER_TEST_P(PictureInPictureBrowserFrameViewTest, - TestMediaBlockedIndicators) { - ASSERT_NO_FATAL_FAILURE( - SetUpDocumentPIP({}, kPictureInPictureDocumentPipPage)); - - content::WebContents* pip_web_contents = pip_frame_view() - ->browser_view() - ->browser() - ->tab_strip_model() - ->GetActiveWebContents(); - ASSERT_TRUE(pip_web_contents); - - BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); - ASSERT_TRUE(browser_view); - ASSERT_TRUE(browser_view->GetLocationBarView()); - PermissionDashboardController* permission_dashboard_controller = - browser_view->GetLocationBarView()->permission_dashboard_controller(); - PermissionDashboardView* permission_dashboard_view = - permission_dashboard_controller->permission_dashboard_view(); - - ASSERT_TRUE(permission_dashboard_view); - - permissions::PermissionRequestManager::FromWebContents(pip_web_contents) - ->set_auto_response_for_test( - permissions::PermissionRequestManager::DISMISS); - - // Request microphone permission and wait for the mic indicator to expand. - { - ChipAnimationObserver chip_animation_observer( - permission_dashboard_view->GetIndicatorChip()); - chip_animation_observer.quit_on_event = - ChipAnimationObserver::QuitOnEvent::kExpand; - - constexpr char kRequestMicrophone[] = R"( - new Promise(async resolve => { - var constraints = { audio: true }; - window.focus(); - try { - const stream = await navigator.mediaDevices.getUserMedia(constraints); - resolve('granted'); - } catch(error) { - resolve('denied') - } - }) - )"; - - EXPECT_TRUE(content::ExecJs( - pip_web_contents->GetPrimaryMainFrame(), kRequestMicrophone, - content::EvalJsOptions::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); - - chip_animation_observer.WaitForChip(); - } - - // Blocked LHS indicator should be visible. - EXPECT_TRUE(permission_dashboard_view->GetVisible()); - // Blocked media indicator is not supported by PiP window, hence it should not - // be shown. - EXPECT_FALSE(pip_frame_view()->HasAnyVisibleContentSettingViews()); - - // Wait for the LHS indicator to disappear. - { - ChipAnimationObserver chip_animation_observer( - permission_dashboard_view->GetIndicatorChip()); - chip_animation_observer.quit_on_event = - ChipAnimationObserver::QuitOnEvent::kVisibiltyFalse; - - // Wait until chip hides. - chip_animation_observer.WaitForChip(); - } - - // Blocked LHS indicator is hidden. - EXPECT_FALSE(permission_dashboard_view->GetVisible()); - // Blocked media indicator is not supported by PiP window, hence it should not - // be shown. - EXPECT_FALSE(pip_frame_view()->HasAnyVisibleContentSettingViews()); -} - INSTANTIATE_TEST_SUITE_P( AnimationTimingTestSuiteInstantiation, PictureInPictureBrowserFrameViewTest,
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc index 1d13459..957a14f 100644 --- a/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc
@@ -113,10 +113,18 @@ EXPECT_TRUE(tab_2->HasFocus()); move_forward_over_tab(tab_2); - EXPECT_TRUE(new_tab_button()->HasFocus()); + if (features::HasTabstripComboButtonWithReverseButtonOrder()) { + EXPECT_TRUE(tab_search_button()->HasFocus()); + } else { + EXPECT_TRUE(new_tab_button()->HasFocus()); + } press_right(); - EXPECT_TRUE(tab_search_button()->HasFocus()); + if (features::HasTabstripComboButtonWithReverseButtonOrder()) { + EXPECT_TRUE(new_tab_button()->HasFocus()); + } else { + EXPECT_TRUE(tab_search_button()->HasFocus()); + } // Focus should cycle back around to tab_0. press_right(); @@ -153,10 +161,18 @@ // Pressing left should immediately cycle back around to the last button. press_left(); - EXPECT_TRUE(tab_search_button()->HasFocus()); + if (features::HasTabstripComboButtonWithReverseButtonOrder()) { + EXPECT_TRUE(new_tab_button()->HasFocus()); + } else { + EXPECT_TRUE(tab_search_button()->HasFocus()); + } press_left(); - EXPECT_TRUE(new_tab_button()->HasFocus()); + if (features::HasTabstripComboButtonWithReverseButtonOrder()) { + EXPECT_TRUE(tab_search_button()->HasFocus()); + } else { + EXPECT_TRUE(new_tab_button()->HasFocus()); + } move_back_to_tab(tab_2); EXPECT_TRUE(tab_2->HasFocus()); @@ -186,12 +202,20 @@ #if !BUILDFLAG(IS_WIN) EXPECT_TRUE(tab_strip_region_view()->AcceleratorPressed( tab_strip_region_view()->end_key())); - EXPECT_TRUE(new_tab_button()->HasFocus()); + if (features::HasTabstripComboButtonWithReverseButtonOrder()) { + EXPECT_TRUE(tab_search_button()->HasFocus()); + } else { + EXPECT_TRUE(new_tab_button()->HasFocus()); + } #endif // !BUILDFLAG(IS_WIN) EXPECT_TRUE(tab_strip_region_view()->AcceleratorPressed( tab_strip_region_view()->home_key())); - EXPECT_TRUE(tab_search_button()->HasFocus()); + if (features::HasTabstripComboButtonWithReverseButtonOrder()) { + EXPECT_TRUE(new_tab_button()->HasFocus()); + } else { + EXPECT_TRUE(tab_search_button()->HasFocus()); + } } else { // The first tab should be active. @@ -200,7 +224,11 @@ #if !BUILDFLAG(IS_WIN) EXPECT_TRUE(tab_strip_region_view()->AcceleratorPressed( tab_strip_region_view()->end_key())); - EXPECT_TRUE(tab_search_button()->HasFocus()); + if (features::HasTabstripComboButtonWithReverseButtonOrder()) { + EXPECT_TRUE(new_tab_button()->HasFocus()); + } else { + EXPECT_TRUE(tab_search_button()->HasFocus()); + } #endif // !BUILDFLAG(IS_WIN) EXPECT_TRUE(tab_strip_region_view()->AcceleratorPressed(
diff --git a/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_interactive_uitest.cc b/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_interactive_uitest.cc index aad0726e..e8d9005 100644 --- a/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_interactive_uitest.cc +++ b/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_interactive_uitest.cc
@@ -168,36 +168,42 @@ views::kEyeCrossedRefreshIcon)); } - auto CheckTrackingProtectionAllowedState() { + auto CheckTrackingProtectionAllowedState(bool incognito = false, + bool with_act = false) { return Steps( CheckViewProperty(CookieControlsContentView::kToggleButton, - &views::ToggleButton::GetIsOn, !has_act_features_), + &views::ToggleButton::GetIsOn, !with_act), CheckViewProperty( CookieControlsContentView::kTitle, &views::Label::GetText, - l10n_util::GetPluralStringFUTF16( - browser()->profile()->GetPrefs()->GetBoolean( - prefs::kBlockAll3pcToggleEnabled) - ? IDS_TRACKING_PROTECTION_BUBBLE_BLOCKING_RESTART_TITLE - : IDS_TRACKING_PROTECTION_BUBBLE_LIMITING_RESTART_TITLE, - ExceptionDurationInDays())), + incognito + ? l10n_util::GetStringUTF16( + IDS_TRACKING_PROTECTION_BUBBLE_PERMANENT_ALLOWED_TITLE) + : l10n_util::GetPluralStringFUTF16( + browser()->profile()->GetPrefs()->GetBoolean( + prefs::kBlockAll3pcToggleEnabled) + ? IDS_TRACKING_PROTECTION_BUBBLE_BLOCKING_RESTART_TITLE + : IDS_TRACKING_PROTECTION_BUBBLE_LIMITING_RESTART_TITLE, + ExceptionDurationInDays())), CheckViewProperty( CookieControlsContentView::kDescription, &views::Label::GetText, l10n_util::GetStringUTF16( - IDS_TRACKING_PROTECTION_BUBBLE_BLOCKING_RESTART_DESCRIPTION)), + incognito + ? IDS_TRACKING_PROTECTION_BUBBLE_PERMANENT_ALLOWED_DESCRIPTION + : IDS_TRACKING_PROTECTION_BUBBLE_BLOCKING_RESTART_DESCRIPTION)), CheckViewProperty( - has_act_features_ - ? CookieControlsContentView::kThirdPartyCookiesLabel - : CookieControlsContentView::kToggleLabel, + with_act ? CookieControlsContentView::kThirdPartyCookiesLabel + : CookieControlsContentView::kToggleLabel, &views::Label::GetText, l10n_util::GetStringUTF16( IDS_TRACKING_PROTECTION_BUBBLE_3PC_ALLOWED_SUBTITLE)), CheckIcon(RichControlsContainerView::kIcon, views::kEyeRefreshIcon)); } - auto CheckTrackingProtectionBlockedState() { + auto CheckTrackingProtectionBlockedState(bool incognito = false, + bool with_act = false) { return Steps( CheckViewProperty(CookieControlsContentView::kToggleButton, - &views::ToggleButton::GetIsOn, has_act_features_), + &views::ToggleButton::GetIsOn, with_act), CheckViewProperty( CookieControlsContentView::kTitle, &views::Label::GetText, l10n_util::GetStringUTF16( @@ -207,13 +213,13 @@ l10n_util::GetStringUTF16( IDS_TRACKING_PROTECTION_BUBBLE_SITE_NOT_WORKING_DESCRIPTION)), CheckViewProperty( - has_act_features_ - ? CookieControlsContentView::kThirdPartyCookiesLabel - : CookieControlsContentView::kToggleLabel, + with_act ? CookieControlsContentView::kThirdPartyCookiesLabel + : CookieControlsContentView::kToggleLabel, &views::Label::GetText, l10n_util::GetStringUTF16( browser()->profile()->GetPrefs()->GetBoolean( - prefs::kBlockAll3pcToggleEnabled) + prefs::kBlockAll3pcToggleEnabled) || + incognito ? IDS_TRACKING_PROTECTION_BUBBLE_3PC_BLOCKED_SUBTITLE : IDS_TRACKING_PROTECTION_BUBBLE_3PC_LIMITED_SUBTITLE)), CheckIcon(RichControlsContainerView::kIcon, @@ -293,7 +299,6 @@ &CookieControlsInteractiveTestBase::GetReferenceTime, /*time_ticks_override=*/nullptr, /*thread_ticks_override=*/nullptr}; - bool has_act_features_ = false; base::UserActionTester user_actions_; base::test::ScopedFeatureList disabled_features_; std::unique_ptr<net::EmbeddedTestServer> https_server_; @@ -702,25 +707,23 @@ } }; -IN_PROC_BROWSER_TEST_P(CookieControlsInteractiveUi3pcdTest, CreateException) { +IN_PROC_BROWSER_TEST_P(CookieControlsInteractiveUi3pcdTest, + CreateExceptionIncognito) { BlockThirdPartyCookies(/*use_3pcd=*/true); SetBlockAll3pcToggle(std::get<0>(GetParam())); - profile_metrics::SetBrowserProfileType( - browser()->profile(), profile_metrics::BrowserProfileType::kIncognito); - RunTestSequence( - InstrumentTab(kWebContentsElementId), - NavigateWebContents(kWebContentsElementId, third_party_cookie_page_url()), - PressButton(kCookieControlsIconElementId), - InAnyContext(WaitForShow(CookieControlsBubbleView::kContentView)), - CheckTrackingProtectionBlockedState(), - PressButton(CookieControlsContentView::kToggleButton), - CheckFeedbackButtonVisible(testing::get<1>(GetParam())), - EnsureNotPresent(CookieControlsBubbleView::kReloadingView), - CheckTrackingProtectionAllowedState()); - - // Reset browser profile before teardown to avoid profile_destroyer errors. - profile_metrics::SetBrowserProfileType( - browser()->profile(), profile_metrics::BrowserProfileType::kRegular); + auto* const incognito_browser = CreateIncognitoBrowser(browser()->profile()); + RunTestSequence(InContext( + incognito_browser->window()->GetElementContext(), + Steps(InstrumentTab(kWebContentsElementId), + NavigateWebContents(kWebContentsElementId, + third_party_cookie_page_url()), + PressButton(kCookieControlsIconElementId), + InAnyContext(WaitForShow(CookieControlsBubbleView::kContentView)), + CheckTrackingProtectionBlockedState(/*incognito=*/true), + PressButton(CookieControlsContentView::kToggleButton), + CheckFeedbackButtonVisible(testing::get<1>(GetParam())), + EnsureNotPresent(CookieControlsBubbleView::kReloadingView), + CheckTrackingProtectionAllowedState(/*incognito=*/true)))); } IN_PROC_BROWSER_TEST_P(CookieControlsInteractiveUi3pcdTest, RemoveException) { @@ -752,17 +755,11 @@ /*show_feedback_button*/ testing::Bool())); class CookieControlsInteractiveUiTrackingProtectionTest - : public CookieControlsInteractiveTestBase, - public testing::WithParamInterface<bool> { + : public CookieControlsInteractiveTestBase { public: CookieControlsInteractiveUiTrackingProtectionTest() = default; ~CookieControlsInteractiveUiTrackingProtectionTest() override = default; - privacy_sandbox::TrackingProtectionSettings* tracking_protection_settings() { - return TrackingProtectionSettingsFactory::GetForProfile( - browser()->profile()); - } - protected: std::vector<base::test::FeatureRef> EnabledFeatures() override { return {privacy_sandbox::kActUserBypassUx, @@ -772,47 +769,22 @@ std::vector<base::test::FeatureRef> DisabledFeatures() override { return {}; } }; -IN_PROC_BROWSER_TEST_P(CookieControlsInteractiveUiTrackingProtectionTest, - CreateException) { +IN_PROC_BROWSER_TEST_F(CookieControlsInteractiveUiTrackingProtectionTest, + CreateAndRemoveExceptionIncognitoAct) { BlockThirdPartyCookies(/*use_3pcd=*/true); - has_act_features_ = true; EnableFpProtection(); - SetBlockAll3pcToggle(GetParam()); - RunTestSequence( - InstrumentTab(kWebContentsElementId), - NavigateWebContents(kWebContentsElementId, third_party_cookie_page_url()), - PressButton(kCookieControlsIconElementId), - InAnyContext(WaitForShow(CookieControlsBubbleView::kContentView)), - CheckTrackingProtectionBlockedState(), - PressButton(CookieControlsContentView::kToggleButton), - EnsureNotPresent(CookieControlsBubbleView::kReloadingView), - CheckTrackingProtectionAllowedState()); + auto* const incognito_browser = CreateIncognitoBrowser(browser()->profile()); + RunTestSequence(InContext( + incognito_browser->window()->GetElementContext(), + Steps(InstrumentTab(kWebContentsElementId), + NavigateWebContents(kWebContentsElementId, + third_party_cookie_page_url()), + PressButton(kCookieControlsIconElementId), + InAnyContext(WaitForShow(CookieControlsBubbleView::kContentView)), + CheckTrackingProtectionBlockedState(/*incognito=*/true, + /*with_act=*/true), + PressButton(CookieControlsContentView::kToggleButton), + EnsureNotPresent(CookieControlsBubbleView::kReloadingView), + CheckTrackingProtectionAllowedState(/*incognito=*/true, + /*with_act=*/true)))); } - -IN_PROC_BROWSER_TEST_P(CookieControlsInteractiveUiTrackingProtectionTest, - RemoveException) { - // Open the bubble while 3PC are blocked, but the page already has an - // exception. Disable 3PC for the page, and confirm the exception is removed. - BlockThirdPartyCookies(/*use_3pcd=*/true); - has_act_features_ = true; - EnableFpProtection(); - SetBlockAll3pcToggle(GetParam()); - cookie_settings()->SetCookieSettingForUserBypass( - third_party_cookie_page_url()); - tracking_protection_settings()->AddTrackingProtectionException( - third_party_cookie_page_url()); - RunTestSequence( - InstrumentTab(kWebContentsElementId), - NavigateWebContents(kWebContentsElementId, third_party_cookie_page_url()), - PressButton(kCookieControlsIconElementId), - InAnyContext(WaitForShow(CookieControlsContentView::kToggleButton)), - CheckTrackingProtectionAllowedState(), - PressButton(CookieControlsContentView::kToggleButton), - CheckViewProperty(kCookieControlsIconElementId, - &CookieControlsIconView::is_animating_label, false), - CheckTrackingProtectionBlockedState()); -} - -INSTANTIATE_TEST_SUITE_P(All, - CookieControlsInteractiveUiTrackingProtectionTest, - (/*block_all_third_party_cookies*/ testing::Bool()));
diff --git a/chrome/browser/ui/views/media_picker_utils.cc b/chrome/browser/ui/views/media_picker_utils.cc index 285b366..b94e768 100644 --- a/chrome/browser/ui/views/media_picker_utils.cc +++ b/chrome/browser/ui/views/media_picker_utils.cc
@@ -10,7 +10,6 @@ #include "components/constrained_window/constrained_window_views.h" #include "content/public/browser/web_contents.h" #include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" #include "ui/views/window/dialog_delegate.h" bool IsMediaPickerModalWindow(content::WebContents* web_contents) { @@ -20,7 +19,7 @@ views::Widget* CreateMediaPickerDialogWidget(Browser* browser, content::WebContents* web_contents, - views::WidgetDelegate* delegate, + views::DialogDelegate* delegate, gfx::NativeWindow context, gfx::NativeView parent) { // If |web_contents| is not a background page then the picker will be shown @@ -36,11 +35,12 @@ widget = constrained_window::ShowWebModalDialogViews(delegate, web_contents); } else { -#if BUILDFLAG(IS_MAC) - // On Mac, ModalType::kChild with a null parent isn't allowed - fall back to - // ModalType::kWindow. - delegate->SetModalType(ui::mojom::ModalType::kWindow); -#endif + // This becomes a top-level window if it does not have a parent. + // Top-level windows should usually be draggable. + if (!parent) { + delegate->set_draggable(true); + delegate->SetModalType(ui::mojom::ModalType::kNone); + } widget = views::DialogDelegate::CreateDialogWidget(delegate, context, parent); widget->Show();
diff --git a/chrome/browser/ui/views/media_picker_utils.h b/chrome/browser/ui/views/media_picker_utils.h index 9e4dae387..a5925496 100644 --- a/chrome/browser/ui/views/media_picker_utils.h +++ b/chrome/browser/ui/views/media_picker_utils.h
@@ -12,8 +12,8 @@ } namespace views { +class DialogDelegate; class Widget; -class WidgetDelegate; } // namespace views class Browser; @@ -26,7 +26,7 @@ // window. views::Widget* CreateMediaPickerDialogWidget(Browser* browser, content::WebContents* web_contents, - views::WidgetDelegate* delegate, + views::DialogDelegate* delegate, gfx::NativeWindow context, gfx::NativeView parent);
diff --git a/chrome/browser/ui/views/page_action/OWNERS b/chrome/browser/ui/views/page_action/OWNERS index c54b1d7..35987916 100644 --- a/chrome/browser/ui/views/page_action/OWNERS +++ b/chrome/browser/ui/views/page_action/OWNERS
@@ -1 +1,2 @@ file://chrome/browser/ui/page_action/OWNERS +alsan@chromium.org
diff --git a/chrome/browser/ui/views/performance_controls/memory_saver_iph_interactive_uitest.cc b/chrome/browser/ui/views/performance_controls/memory_saver_iph_interactive_uitest.cc index 42a416a..262fd54 100644 --- a/chrome/browser/ui/views/performance_controls/memory_saver_iph_interactive_uitest.cc +++ b/chrome/browser/ui/views/performance_controls/memory_saver_iph_interactive_uitest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/strings/stringprintf.h" +#include "base/test/scoped_amount_of_physical_memory_override.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h" @@ -62,6 +63,12 @@ AddDescriptionPrefix(steps, "TriggerMemorySaverPromo()"); return steps; } + + private: + // Pretend to have 1GB of memory, to ensure the memory saver promo will + // show. + base::test::ScopedAmountOfPhysicalMemoryOverride + scoped_amount_of_physical_memory_override_{1024}; }; // Check that the memory saver mode in-product help promo is shown when
diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc b/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc index 731be8f..1ab5ed0 100644 --- a/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc +++ b/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc
@@ -216,16 +216,12 @@ } // namespace StatusIconLinuxDbus::StatusIconLinuxDbus() - : should_write_icon_to_file_(ShouldWriteIconToFile()), + : bus_(dbus_thread_linux::GetSharedSessionBus()), + should_write_icon_to_file_(ShouldWriteIconToFile()), icon_task_runner_(base::ThreadPool::CreateSequencedTaskRunner( {base::MayBlock(), base::TaskPriority::USER_VISIBLE, base::TaskShutdownBehavior::BLOCK_SHUTDOWN})) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - dbus::Bus::Options bus_options; - bus_options.bus_type = dbus::Bus::SESSION; - bus_options.connection_type = dbus::Bus::PRIVATE; - bus_options.dbus_task_runner = dbus_thread_linux::GetTaskRunner(); - bus_ = base::MakeRefCounted<dbus::Bus>(bus_options); CheckStatusNotifierWatcherHasOwner(); } @@ -297,8 +293,6 @@ StatusIconLinuxDbus::~StatusIconLinuxDbus() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - bus_->GetDBusTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&dbus::Bus::ShutdownAndBlock, bus_)); CleanupIconFile(); }
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 77e0df5..e8b4a83 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_action_container.cc +++ b/chrome/browser/ui/views/tabs/tab_strip_action_container.cc
@@ -409,7 +409,12 @@ void TabStripActionContainer::OnTriggerGlicNudgeUI(std::string label) { CHECK(glic_nudge_button_); glic_nudge_button_->SetText(base::UTF8ToUTF16(label)); - ShowTabStripNudge(glic_nudge_button_); + + if (!label.empty()) { + ShowTabStripNudge(glic_nudge_button_); + } else { + HideTabStripNudge(glic_nudge_button_); + } } DeclutterTriggerCTRBucket TabStripActionContainer::GetDeclutterTriggerBucket(
diff --git a/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc index 079f9ad7..fcd222e 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc +++ b/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc
@@ -9,6 +9,7 @@ #include "base/test/scoped_feature_list.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h" +#include "chrome/browser/ui/tabs/test/mock_tab_interface.h" #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h" #include "chrome/browser/ui/views/commerce/product_specifications_button.h" #include "chrome/browser/ui/views/frame/tab_strip_region_view.h" @@ -85,6 +86,7 @@ void TearDown() override { ChromeViewsTestBase::TearDown(); tab_strip_action_container_.reset(); + glic_nudge_controller_.reset(); } void BuildGlicContainer(bool use_otr_profile) { @@ -97,17 +99,24 @@ tab_strip_model_ = std::make_unique<TabStripModel>( &tab_strip_model_delegate_, tab_strip_->controller()->GetProfile()); + tab_interface_ = std::make_unique<tabs::MockTabInterface>(); + browser_window_interface_ = std::make_unique<MockBrowserWindowInterface>(); ON_CALL(*browser_window_interface_, GetTabStripModel) .WillByDefault(::testing::Return(tab_strip_model_.get())); ON_CALL(*browser_window_interface_, GetProfile) .WillByDefault( ::testing::Return(tab_strip_->controller()->GetProfile())); + ON_CALL(*browser_window_interface_, GetActiveTabInterface) + .WillByDefault(::testing::Return(tab_interface_.get())); + ON_CALL(*tab_interface_, GetContents) + .WillByDefault(::testing::Return(web_contents_.get())); tab_declutter_controller_ = std::make_unique<tabs::TabDeclutterController>( browser_window_interface_.get()); - glic_nudge_controller_ = std::make_unique<tabs::GlicNudgeController>(); + glic_nudge_controller_ = std::make_unique<tabs::GlicNudgeController>( + browser_window_interface_.get()); locked_expansion_view_ = std::make_unique<views::View>(); @@ -121,6 +130,7 @@ std::unique_ptr<TabStripModel> tab_strip_model_; std::unique_ptr<tabs::TabDeclutterController> tab_declutter_controller_; std::unique_ptr<tabs::GlicNudgeController> glic_nudge_controller_; + std::unique_ptr<tabs::MockTabInterface> tab_interface_; std::unique_ptr<MockBrowserWindowInterface> browser_window_interface_; TestTabStripModelDelegate tab_strip_model_delegate_; base::test::ScopedFeatureList scoped_feature_list_;
diff --git a/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc b/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc index 7414003..613a861 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc +++ b/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc
@@ -49,7 +49,13 @@ TabStrip* tab_strip) { Edge new_tab_button_flat_edge = Edge::kNone; if (features::HasTabstripComboButtonWithBackground()) { - new_tab_button_flat_edge = base::i18n::IsRTL() ? Edge::kLeft : Edge::kRight; + if (features::HasTabstripComboButtonWithReverseButtonOrder()) { + new_tab_button_flat_edge = + base::i18n::IsRTL() ? Edge::kRight : Edge::kLeft; + } else { + new_tab_button_flat_edge = + base::i18n::IsRTL() ? Edge::kLeft : Edge::kRight; + } } std::unique_ptr<TabStripControlButton> new_tab_button = std::make_unique<TabStripControlButton>( @@ -70,9 +76,14 @@ new_tab_button->SetBackgroundFrameInactiveColorId( kColorNewTabButtonCRBackgroundFrameInactive); } else { - // Add a gap between the new tab button and tab search container. - new_tab_button->SetProperty( - views::kMarginsKey, gfx::Insets::TLBR(0, 0, 0, kButtonGapNoBackground)); + // Add a gap between the new tab button and tab search button. + gfx::Insets button_margins; + if (features::HasTabstripComboButtonWithReverseButtonOrder()) { + button_margins = gfx::Insets::TLBR(0, kButtonGapNoBackground, 0, 0); + } else { + button_margins = gfx::Insets::TLBR(0, 0, 0, kButtonGapNoBackground); + } + new_tab_button->SetProperty(views::kMarginsKey, button_margins); } new_tab_button->SetTooltipText( @@ -105,8 +116,13 @@ Edge tab_search_button_flat_edge = Edge::kNone; if (features::HasTabstripComboButtonWithBackground()) { - tab_search_button_flat_edge = - base::i18n::IsRTL() ? Edge::kRight : Edge::kLeft; + if (features::HasTabstripComboButtonWithReverseButtonOrder()) { + tab_search_button_flat_edge = + base::i18n::IsRTL() ? Edge::kLeft : Edge::kRight; + } else { + tab_search_button_flat_edge = + base::i18n::IsRTL() ? Edge::kRight : Edge::kLeft; + } } std::unique_ptr<TabSearchButton> tab_search_button = std::make_unique<TabSearchButton>(tab_strip->controller(), browser, @@ -128,9 +144,15 @@ .SetCrossAxisAlignment(views::LayoutAlignment::kCenter); separator_container->SetCanProcessEventsWithinSubtree(false); - new_tab_button_ = button_container->AddChildView(std::move(new_tab_button)); - tab_search_button_ = - button_container->AddChildView(std::move(tab_search_button)); + if (features::HasTabstripComboButtonWithReverseButtonOrder()) { + tab_search_button_ = + button_container->AddChildView(std::move(tab_search_button)); + new_tab_button_ = button_container->AddChildView(std::move(new_tab_button)); + } else { + new_tab_button_ = button_container->AddChildView(std::move(new_tab_button)); + tab_search_button_ = + button_container->AddChildView(std::move(tab_search_button)); + } separator_ = separator_container->AddChildView(std::move(separator)); SetLayoutManager(std::make_unique<views::FillLayout>());
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler_unittest.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler_unittest.cc index 1327767..fd2bb7f 100644 --- a/chrome/browser/ui/webui/app_management/app_management_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/app_management/app_management_page_handler_unittest.cc
@@ -618,19 +618,23 @@ auto web_app_info = web_app::WebAppInstallInfo::CreateWithStartUrlForTesting( GURL("https://example.com/")); web_app_info->title = u"app_name"; - web_app_info->scope_extensions = web_app::ScopeExtensions( - {web_app::ScopeExtensionInfo::CreateForScope(GURL("https://sitea.com")), - web_app::ScopeExtensionInfo::CreateForScope( - GURL("https://app.siteb.com")), - web_app::ScopeExtensionInfo::CreateForScope( - GURL("https://sitec.com"), - /*has_origin_wildcard=*/true), - web_app::ScopeExtensionInfo::CreateForScope( - GURL("http://☃.net/")) /* Unicode */, - web_app::ScopeExtensionInfo::CreateForScope( - GURL("https://localhost:443")), - web_app::ScopeExtensionInfo::CreateForScope( - GURL("https://localhost:9999"))}); + web_app_info->scope_extensions = web_app::ScopeExtensions({ + web_app::ScopeExtensionInfo::CreateForScope(GURL("https://sitea.com")), + web_app::ScopeExtensionInfo::CreateForScope( + GURL("https://app.siteb.com")), + web_app::ScopeExtensionInfo::CreateForScope(GURL("https://sitec.com"), + /*has_origin_wildcard=*/true), + web_app::ScopeExtensionInfo::CreateForScope( + GURL("http://☃.net/")) /* Unicode */, + web_app::ScopeExtensionInfo::CreateForScope( + GURL("https://localhost:443")), + web_app::ScopeExtensionInfo::CreateForScope( + GURL("https://localhost:9999")), + web_app::ScopeExtensionInfo::CreateForScope( + GURL("https://google.com/search?q=search+query")), + web_app::ScopeExtensionInfo::CreateForScope( + GURL("https://google.com/search?q=search+query#fragment")), + }); web_app::WebAppInstallParams install_params; // Skip origin association validation for testing. @@ -655,6 +659,7 @@ std::vector<std::string> expected_scope_extensions = { "xn--n3h.net" /* Unicode */, "app.siteb.com", + "google.com", "localhost", "sitea.com", "*.sitec.com",
diff --git a/chrome/browser/ui/webui/commerce/product_specifications_ui.cc b/chrome/browser/ui/webui/commerce/product_specifications_ui.cc index 8f81c04..296788b 100644 --- a/chrome/browser/ui/webui/commerce/product_specifications_ui.cc +++ b/chrome/browser/ui/webui/commerce/product_specifications_ui.cc
@@ -104,7 +104,10 @@ {"learnMoreA11yLabel", IDS_COMPARE_LEARN_MORE_A11Y_LABEL}, {"menuDelete", IDS_COMPARE_CONTEXT_MENU_DELETE}, {"menuOpenAll", IDS_COMPARE_CONTEXT_MENU_OPEN_ALL_WITH_COUNT}, + {"menuOpenAllInNewWindow", + IDS_COMPARE_CONTEXT_MENU_OPEN_ALL_IN_NEW_WINDOW_WITH_COUNT}, {"menuOpenInNewTab", IDS_COMPARE_CONTEXT_MENU_OPEN_IN_NEW_TAB}, + {"menuOpenInNewWindow", IDS_COMPARE_CONTEXT_MENU_OPEN_IN_NEW_WINDOW}, {"menuRename", IDS_COMPARE_CONTEXT_MENU_RENAME}, {"menuTooltipMore", IDS_COMPARE_EDIT_MORE}, {"numSelected", IDS_COMPARE_NUM_ITEMS_SELECTED},
diff --git a/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate.cc b/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate.cc index e1a6084..4a2a0c2 100644 --- a/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate.cc +++ b/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate.cc
@@ -42,26 +42,67 @@ void ProductSpecificationsUIHandlerDelegate:: ShowProductSpecificationsSetForUuid(const base::Uuid& uuid, bool in_new_tab) { - const GURL product_spec_url = commerce::GetProductSpecsTabUrlForID(uuid); auto* browser = chrome::FindLastActiveWithProfile(Profile::FromWebUI(web_ui_)); if (!browser) { return; } + if (in_new_tab) { - content::OpenURLParams params(product_spec_url, content::Referrer(), - WindowOpenDisposition::NEW_FOREGROUND_TAB, - ui::PAGE_TRANSITION_LINK, false); - browser->OpenURL(params, /*navigation_handle_callback=*/{}); - } else { - content::WebContents* web_contents = - browser->tab_strip_model()->GetActiveWebContents(); - if (!web_contents) { - return; + OpenProductSpecificationsSetForUuidInBrowser( + uuid, *browser, WindowOpenDisposition::NEW_FOREGROUND_TAB); + return; + } + + const GURL product_spec_url = commerce::GetProductSpecsTabUrlForID(uuid); + content::WebContents* web_contents = + browser->tab_strip_model()->GetActiveWebContents(); + if (!web_contents) { + return; + } + web_contents->GetController().LoadURL(product_spec_url, content::Referrer(), + ui::PAGE_TRANSITION_AUTO_TOPLEVEL, + /*extra_headers=*/std::string()); +} + +void ProductSpecificationsUIHandlerDelegate:: + ShowProductSpecificationsSetsForUuids( + const std::vector<base::Uuid>& uuids, + const product_specifications::mojom::ShowSetDisposition disposition) { + if (uuids.empty()) { + return; + } + + auto* browser = + chrome::FindLastActiveWithProfile(Profile::FromWebUI(web_ui_)); + if (!browser) { + return; + } + + if (disposition == + product_specifications::mojom::ShowSetDisposition::kInNewTabs) { + for (const auto& uuid : uuids) { + OpenProductSpecificationsSetForUuidInBrowser( + uuid, *browser, WindowOpenDisposition::NEW_BACKGROUND_TAB); } - web_contents->GetController().LoadURL(product_spec_url, content::Referrer(), - ui::PAGE_TRANSITION_AUTO_TOPLEVEL, - /*extra_headers=*/std::string()); + } + + if (disposition == + product_specifications::mojom::ShowSetDisposition::kInNewWindow) { + auto tab_disposition = WindowOpenDisposition::NEW_WINDOW; + for (const auto& uuid : uuids) { + const auto* web_contents = OpenProductSpecificationsSetForUuidInBrowser( + uuid, *browser, tab_disposition); + + // Open the rest of the tabs in the same window. + browser = chrome::FindBrowserWithTab(web_contents); + if (!browser) { + LOG(ERROR) << "Failed to open product specifications sets in the same " + "new window."; + return; + } + tab_disposition = WindowOpenDisposition::NEW_BACKGROUND_TAB; + } } } @@ -99,4 +140,15 @@ signin_metrics::AccessPoint::ACCESS_POINT_PRODUCT_SPECIFICATIONS); } +content::WebContents* ProductSpecificationsUIHandlerDelegate:: + OpenProductSpecificationsSetForUuidInBrowser( + const base::Uuid& uuid, + Browser& browser, + const WindowOpenDisposition& disposition) { + const GURL product_spec_url = commerce::GetProductSpecsTabUrlForID(uuid); + content::OpenURLParams params(product_spec_url, content::Referrer(), + disposition, ui::PAGE_TRANSITION_LINK, false); + return browser.OpenURL(params, /*navigation_handle_callback=*/{}); +} + } // namespace commerce
diff --git a/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate.h b/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate.h index 98a276e..63b5292 100644 --- a/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate.h +++ b/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate.h
@@ -7,6 +7,9 @@ #include "components/commerce/core/webui/product_specifications_handler.h" #include "content/public/browser/web_ui.h" +#include "ui/base/window_open_disposition.h" + +class Browser; namespace commerce { @@ -29,9 +32,19 @@ void ShowProductSpecificationsSetForUuid(const base::Uuid& uuid, bool in_new_tab) override; + void ShowProductSpecificationsSetsForUuids( + const std::vector<base::Uuid>& uuids, + const product_specifications::mojom::ShowSetDisposition disposition) + override; + void ShowComparePage(bool in_new_tab) override; private: + content::WebContents* OpenProductSpecificationsSetForUuidInBrowser( + const base::Uuid& uuid, + Browser& browser, + const WindowOpenDisposition& disposition); + raw_ptr<content::WebUI> web_ui_; };
diff --git a/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate_browsertest.cc b/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate_browsertest.cc index ce5f9b7..004b83a 100644 --- a/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate_browsertest.cc +++ b/chrome/browser/ui/webui/commerce/product_specifications_ui_handler_delegate_browsertest.cc
@@ -8,6 +8,8 @@ #include "base/uuid.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_list.h" #include "chrome/browser/ui/webui/commerce/product_specifications_disclosure_dialog.h" #include "chrome/test/base/chrome_test_utils.h" #include "chrome/test/base/in_process_browser_test.h" @@ -18,8 +20,38 @@ #include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_web_ui.h" +namespace commerce { namespace { + const char kExampleUrl[] = "http://example.com/"; + +class NewBrowserObserver : public BrowserListObserver { + public: + NewBrowserObserver() { BrowserList::AddObserver(this); } + NewBrowserObserver(const NewBrowserObserver&) = delete; + NewBrowserObserver& operator=(const NewBrowserObserver&) = delete; + ~NewBrowserObserver() override { BrowserList::RemoveObserver(this); } + + void Wait() { + if (browsers_.size() == 0) { + run_loop_.Run(); + } + } + + std::vector<Browser*>& GetBrowsers() { return browsers_; } + + // BrowserListObserver: + void OnBrowserAdded(Browser* browser) override { + LOG(ERROR) << "browser added"; + browsers_.push_back(browser); + run_loop_.Quit(); + } + + private: + std::vector<Browser*> browsers_; + base::RunLoop run_loop_; +}; + } // namespace class ProductSpecificationsUIHandlerDelegateBrowserTest @@ -45,28 +77,27 @@ std::string name = "test_name"; std::string id = "test_id"; auto delegate = - std::make_unique<commerce::ProductSpecificationsUIHandlerDelegate>( - web_ui_.get()); + std::make_unique<ProductSpecificationsUIHandlerDelegate>(web_ui_.get()); delegate->ShowDisclosureDialog(urls, name, id); - auto* dialog = commerce::ProductSpecificationsDisclosureDialog:: - current_instance_for_testing(); + auto* dialog = + ProductSpecificationsDisclosureDialog::current_instance_for_testing(); ASSERT_TRUE(dialog); // Check dialog args. auto dict = base::JSONReader::ReadDict(dialog->GetDialogArgs()); ASSERT_TRUE(dict.has_value()); - auto* set_name = dict->FindString(commerce::kDialogArgsName); + auto* set_name = dict->FindString(kDialogArgsName); ASSERT_TRUE(set_name); ASSERT_EQ(name, *set_name); - auto* url_list = dict->FindList(commerce::kDialogArgsUrls); + auto* url_list = dict->FindList(kDialogArgsUrls); ASSERT_TRUE(url_list); ASSERT_EQ(1u, url_list->size()); ASSERT_EQ(urls[0].spec(), (*url_list)[0].GetString()); - auto* set_id = dict->FindString(commerce::kDialogArgsSetId); + auto* set_id = dict->FindString(kDialogArgsSetId); ASSERT_TRUE(set_id); ASSERT_EQ(id, *set_id); - auto new_tab = dict->FindBool(commerce::kDialogArgsInNewTab); + auto new_tab = dict->FindBool(kDialogArgsInNewTab); ASSERT_TRUE(new_tab.has_value()); ASSERT_FALSE(new_tab.value()); } @@ -75,47 +106,43 @@ TestShowProductSpecificationsSetForUuid) { const base::Uuid uuid = base::Uuid::GenerateRandomV4(); auto delegate = - std::make_unique<commerce::ProductSpecificationsUIHandlerDelegate>( - web_ui_.get()); + std::make_unique<ProductSpecificationsUIHandlerDelegate>(web_ui_.get()); ASSERT_EQ(1, browser()->tab_strip_model()->count()); content::TestNavigationObserver observer_one( - commerce::GetProductSpecsTabUrlForID(uuid)); + GetProductSpecsTabUrlForID(uuid)); observer_one.WatchExistingWebContents(); delegate->ShowProductSpecificationsSetForUuid(uuid, false); observer_one.Wait(); ASSERT_EQ(1, browser()->tab_strip_model()->count()); - ASSERT_EQ(commerce::GetProductSpecsTabUrlForID(uuid), - browser() - ->tab_strip_model() - ->GetActiveWebContents() - ->GetLastCommittedURL()); + ASSERT_EQ(GetProductSpecsTabUrlForID(uuid), browser() + ->tab_strip_model() + ->GetActiveWebContents() + ->GetLastCommittedURL()); content::TestNavigationObserver observer_two( - commerce::GetProductSpecsTabUrlForID(uuid)); + GetProductSpecsTabUrlForID(uuid)); observer_two.StartWatchingNewWebContents(); delegate->ShowProductSpecificationsSetForUuid(uuid, true); observer_two.WaitForNavigationFinished(); ASSERT_EQ(2, browser()->tab_strip_model()->count()); - ASSERT_EQ(commerce::GetProductSpecsTabUrlForID(uuid), - browser() - ->tab_strip_model() - ->GetActiveWebContents() - ->GetLastCommittedURL()); + ASSERT_EQ(GetProductSpecsTabUrlForID(uuid), browser() + ->tab_strip_model() + ->GetActiveWebContents() + ->GetLastCommittedURL()); } IN_PROC_BROWSER_TEST_F(ProductSpecificationsUIHandlerDelegateBrowserTest, TestShowComparePage_InCurrentTab) { auto delegate = - std::make_unique<commerce::ProductSpecificationsUIHandlerDelegate>( - web_ui_.get()); + std::make_unique<ProductSpecificationsUIHandlerDelegate>(web_ui_.get()); ASSERT_EQ(1, browser()->tab_strip_model()->count()); - const auto compare_url = GURL(commerce::kChromeUICompareUrl); + const auto compare_url = GURL(kChromeUICompareUrl); content::TestNavigationObserver observer(compare_url); observer.WatchExistingWebContents(); @@ -132,10 +159,9 @@ IN_PROC_BROWSER_TEST_F(ProductSpecificationsUIHandlerDelegateBrowserTest, TestShowComparePage_InNewTab) { auto delegate = - std::make_unique<commerce::ProductSpecificationsUIHandlerDelegate>( - web_ui_.get()); + std::make_unique<ProductSpecificationsUIHandlerDelegate>(web_ui_.get()); - const auto compare_url = GURL(commerce::kChromeUICompareUrl); + const auto compare_url = GURL(kChromeUICompareUrl); content::TestNavigationObserver observer(compare_url); observer.StartWatchingNewWebContents(); @@ -148,3 +174,78 @@ ->GetActiveWebContents() ->GetLastCommittedURL()); } + +IN_PROC_BROWSER_TEST_F(ProductSpecificationsUIHandlerDelegateBrowserTest, + TestShowProductSpecificationSetsForUuids_InNewTabs) { + const base::Uuid uuid_one = base::Uuid::GenerateRandomV4(); + const base::Uuid uuid_two = base::Uuid::GenerateRandomV4(); + auto delegate = + std::make_unique<ProductSpecificationsUIHandlerDelegate>(web_ui_.get()); + ASSERT_EQ(1, browser()->tab_strip_model()->count()); + + content::TestNavigationObserver observer_one( + GetProductSpecsTabUrlForID(uuid_one)); + observer_one.StartWatchingNewWebContents(); + content::TestNavigationObserver observer_two( + GetProductSpecsTabUrlForID(uuid_two)); + observer_two.StartWatchingNewWebContents(); + + delegate->ShowProductSpecificationsSetsForUuids( + {uuid_one, uuid_two}, + product_specifications::mojom::ShowSetDisposition::kInNewTabs); + + observer_one.Wait(); + observer_two.Wait(); + + // First tab is the originally open tab. + ASSERT_EQ(3, browser()->tab_strip_model()->count()); + ASSERT_EQ( + GetProductSpecsTabUrlForID(uuid_one), + browser()->tab_strip_model()->GetWebContentsAt(1)->GetLastCommittedURL()); + ASSERT_EQ( + GetProductSpecsTabUrlForID(uuid_two), + browser()->tab_strip_model()->GetWebContentsAt(2)->GetLastCommittedURL()); +} + +IN_PROC_BROWSER_TEST_F(ProductSpecificationsUIHandlerDelegateBrowserTest, + TestShowProductSpecificationSetsForUuids_InNewWindow) { + const base::Uuid uuid_one = base::Uuid::GenerateRandomV4(); + const base::Uuid uuid_two = base::Uuid::GenerateRandomV4(); + auto delegate = + std::make_unique<ProductSpecificationsUIHandlerDelegate>(web_ui_.get()); + ASSERT_EQ(1, browser()->tab_strip_model()->count()); + + NewBrowserObserver browser_observer; + + content::TestNavigationObserver observer_one( + GetProductSpecsTabUrlForID(uuid_one)); + observer_one.StartWatchingNewWebContents(); + content::TestNavigationObserver observer_two( + GetProductSpecsTabUrlForID(uuid_two)); + observer_two.StartWatchingNewWebContents(); + + delegate->ShowProductSpecificationsSetsForUuids( + {uuid_one, uuid_two}, + product_specifications::mojom::ShowSetDisposition::kInNewWindow); + + observer_one.Wait(); + observer_two.Wait(); + browser_observer.Wait(); + + // The original browser window should still only have one tab. + ASSERT_EQ(1, browser()->tab_strip_model()->count()); + + // Only one new browser should have been opened with the new tabs. + const auto& browsers = browser_observer.GetBrowsers(); + ASSERT_EQ(1UL, browsers.size()); + const auto* new_browser = browsers.at(0); + ASSERT_EQ(2, new_browser->tab_strip_model()->count()); + ASSERT_EQ(GetProductSpecsTabUrlForID(uuid_one), new_browser->tab_strip_model() + ->GetWebContentsAt(0) + ->GetLastCommittedURL()); + ASSERT_EQ(GetProductSpecsTabUrlForID(uuid_two), new_browser->tab_strip_model() + ->GetWebContentsAt(1) + ->GetLastCommittedURL()); +} + +} // namespace commerce
diff --git a/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc b/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc index fb55218..d09161f7 100644 --- a/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc +++ b/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc
@@ -29,6 +29,7 @@ #include "chrome/grit/nearby_share_dialog_resources_map.h" #include "chrome/grit/theme_resources.h" #include "chromeos/components/sharesheet/constants.h" +#include "chromeos/constants/chromeos_features.h" #include "content/public/browser/url_data_source.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" @@ -122,6 +123,9 @@ const GURL& url = web_ui->GetWebContents()->GetVisibleURL(); SetAttachmentFromQueryParameter(url); + + html_source->AddBoolean("isQuickShareV2Enabled", + chromeos::features::IsQuickShareV2Enabled()); } NearbyShareDialogUI::~NearbyShareDialogUI() = default;
diff --git a/chrome/browser/ui/webui/new_tab_page/untrusted_source.cc b/chrome/browser/ui/webui/new_tab_page/untrusted_source.cc index 2f5b125..512b72d6 100644 --- a/chrome/browser/ui/webui/new_tab_page/untrusted_source.cc +++ b/chrome/browser/ui/webui/new_tab_page/untrusted_source.cc
@@ -16,6 +16,7 @@ #include "base/memory/ref_counted_memory.h" #include "base/memory/scoped_refptr.h" #include "base/metrics/histogram_macros.h" +#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/task/task_traits.h" @@ -181,7 +182,7 @@ IDR_NEW_TAB_PAGE_UNTRUSTED_BACKGROUND_IMAGE_JS)); return; } - if (base::Contains(path, "background.jpg")) { + if (base::EndsWith(path, "background.jpg")) { base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, base::BindOnce(&ReadBackgroundImageData,
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_uninstall_browsertest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_uninstall_browsertest.cc index 7832c2c..033b96d8 100644 --- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_uninstall_browsertest.cc +++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_uninstall_browsertest.cc
@@ -47,31 +47,8 @@ void SetUp() override { ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); - src_bundle_path_ = scoped_temp_dir_.GetPath().Append( base::FilePath::FromASCII("bundle.swbn")); - switch (mode_and_file_op_) { - case IwaSourceBundleModeAndFileOp::kDevModeCopy: - src_source_ = IsolatedWebAppInstallSource::FromDevUi( - IwaSourceBundleDevModeWithFileOp(src_bundle_path_, - IwaSourceBundleDevFileOp::kCopy)); - break; - case IwaSourceBundleModeAndFileOp::kDevModeMove: - src_source_ = IsolatedWebAppInstallSource::FromDevUi( - IwaSourceBundleDevModeWithFileOp(src_bundle_path_, - IwaSourceBundleDevFileOp::kMove)); - break; - case IwaSourceBundleModeAndFileOp::kProdModeCopy: - src_source_ = IsolatedWebAppInstallSource::FromGraphicalInstaller( - IwaSourceBundleProdModeWithFileOp( - src_bundle_path_, IwaSourceBundleProdFileOp::kCopy)); - break; - case IwaSourceBundleModeAndFileOp::kProdModeMove: - src_source_ = IsolatedWebAppInstallSource::FromGraphicalInstaller( - IwaSourceBundleProdModeWithFileOp( - src_bundle_path_, IwaSourceBundleProdFileOp::kMove)); - break; - } IsolatedWebAppBrowserTestHarness::SetUp(); } @@ -82,9 +59,28 @@ ManifestBuilder().SetName("app-1.0.0").SetVersion("1.0.0")) .BuildBundle(src_bundle_path_, key_pair_); - bundle->TrustSigningKey(); - ASSERT_THAT(bundle->InstallWithSource(profile(), *src_source_), - base::test::HasValue()); + switch (mode_and_file_op_) { + case IwaSourceBundleModeAndFileOp::kDevModeCopy: + ASSERT_THAT(bundle->InstallWithSource( + profile(), &IsolatedWebAppInstallSource::FromDevUi, + IwaSourceBundleDevFileOp::kCopy), + base::test::HasValue()); + break; + case IwaSourceBundleModeAndFileOp::kDevModeMove: + ASSERT_THAT(bundle->InstallWithSource( + profile(), &IsolatedWebAppInstallSource::FromDevUi, + IwaSourceBundleDevFileOp::kMove), + base::test::HasValue()); + break; + case IwaSourceBundleModeAndFileOp::kProdModeCopy: + case IwaSourceBundleModeAndFileOp::kProdModeMove: + ASSERT_THAT( + bundle->InstallWithSource( + profile(), &IsolatedWebAppInstallSource::FromGraphicalInstaller, + mode_and_file_op_), + base::test::HasValue()); + break; + } const WebApp* web_app = provider()->registrar_unsafe().GetAppById(url_info_.app_id()); @@ -129,7 +125,6 @@ test::GetDefaultEd25519WebBundleId()); base::FilePath src_bundle_path_; - std::optional<IsolatedWebAppInstallSource> src_source_; }; IN_PROC_BROWSER_TEST_P(IsolatedWebAppUninstallBrowserTest, Succeeds) {
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc index 2c5cc80..48d0f47 100644 --- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc +++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc
@@ -326,10 +326,7 @@ ASSERT_OK_AND_ASSIGN(IsolatedWebAppUrlInfo url_info, initial_bundle->InstallWithSource( - profile(), IsolatedWebAppInstallSource::FromDevUi( - IwaSourceBundleDevModeWithFileOp( - initial_bundle->path(), - kDefaultBundleDevFileOp)))); + profile(), &IsolatedWebAppInstallSource::FromDevUi)); page_state.manifest_before_default_processing = CreateDefaultManifest( url_info.origin().GetURL(), u"updated iwa", base::Version("2.0.0"));
diff --git a/chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.cc b/chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.cc index 4f7410b2..6cf64cc8 100644 --- a/chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.cc +++ b/chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.cc
@@ -25,6 +25,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/test_future.h" #include "base/threading/thread_restrictions.h" +#include "base/types/optional_ref.h" #include "chrome/browser/web_applications/isolated_web_apps/commands/install_isolated_web_app_command.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_install_source.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_source.h" @@ -121,7 +122,10 @@ base::expected<IsolatedWebAppUrlInfo, std::string> Install( Profile* profile, const web_package::SignedWebBundleId& web_bundle_id, - const IsolatedWebAppInstallSource& install_source) { + const IsolatedWebAppInstallSource& install_source, + const ManifestBuilder& manifest_builder, + bool fake_install_page, + bool trust_key) { auto url_info = IsolatedWebAppUrlInfo::CreateFromSignedWebBundleId(web_bundle_id); if (FakeWebAppProvider* fake_provider = GetFakeWebAppProvider(profile)) { @@ -137,12 +141,22 @@ auto& web_contents_manager = static_cast<FakeWebContentsManager&>( fake_provider->web_contents_manager()); if (!web_contents_manager.HasPageState(install_url)) { - LOG(WARNING) << "The install page for this IWA has not been faked. " - << "You likely need to call FakeInstallPageState before " - << "Install."; + if (fake_install_page) { + FakeInstallPageState( + profile, url_info, + manifest_builder.ToBlinkManifest(url_info.origin())); + } else { + LOG(WARNING) << "The install page for this IWA has not been faked. " + << "You likely need to remove DoNotFakeInstallPage or " + << "manually call FakeInstallPageState before Install."; + } } } + if (trust_key) { + AddTrustedWebBundleIdForTesting(web_bundle_id); + } + base::test::TestFuture<InstallResult> future; WebAppProvider::GetForWebApps(profile)->scheduler().InstallIsolatedWebApp( url_info, install_source, @@ -170,161 +184,6 @@ } // namespace -BundledIsolatedWebApp::BundledIsolatedWebApp( - const web_package::SignedWebBundleId& web_bundle_id, - const std::vector<uint8_t> serialized_bundle, - const base::FilePath path, - ManifestBuilder manifest_builder) - : web_bundle_id_(web_bundle_id), - path_(std::move(path)), - manifest_builder_(manifest_builder) { - base::ScopedAllowBlockingForTesting allow_blocking; - CHECK(base::WriteFile(path_, std::move(serialized_bundle))); -} - -BundledIsolatedWebApp::~BundledIsolatedWebApp() = default; - -void BundledIsolatedWebApp::TrustSigningKey() { - AddTrustedWebBundleIdForTesting(web_bundle_id_); -} - -std::string BundledIsolatedWebApp::GetBundleData() const { - base::ScopedAllowBlockingForTesting allow_blocking; - std::string content; - CHECK(base::ReadFileToString(path_, &content)); - return content; -} - -IsolatedWebAppUrlInfo BundledIsolatedWebApp::InstallChecked(Profile* profile) { - auto result = Install(profile); - CHECK(result.has_value()) << result.error(); - return *result; -} - -base::expected<IsolatedWebAppUrlInfo, std::string> -BundledIsolatedWebApp::TrustBundleAndInstall(Profile* profile) { - TrustSigningKey(); - return Install(profile); -} - -base::expected<IsolatedWebAppUrlInfo, std::string> -BundledIsolatedWebApp::Install(Profile* profile) { - return ::web_app::Install( - profile, web_bundle_id_, - IsolatedWebAppInstallSource::FromGraphicalInstaller( - web_app::IwaSourceBundleProdModeWithFileOp( - path(), web_app::IwaSourceBundleProdFileOp::kCopy))); -} - -base::expected<IsolatedWebAppUrlInfo, std::string> -BundledIsolatedWebApp::InstallWithSource(Profile* profile, - IsolatedWebAppInstallSource source) { - return ::web_app::Install(profile, web_bundle_id_, source); -} - -base::expected<IsolatedWebAppUrlInfo, std::string> -BundledIsolatedWebApp::InstallWithSource( - Profile* profile, - base::FunctionRef<IsolatedWebAppInstallSource(IwaSourceDevModeWithFileOp)> - install_source_provider, - IwaSourceBundleDevFileOp file_op) { - return ::web_app::Install( - profile, web_bundle_id_, - install_source_provider(web_app::IwaSourceDevModeWithFileOp( - web_app::IwaSourceBundleDevModeWithFileOp(path(), file_op)))); -} - -base::expected<IsolatedWebAppUrlInfo, std::string> -BundledIsolatedWebApp::InstallWithSource( - Profile* profile, - base::FunctionRef<IsolatedWebAppInstallSource(IwaSourceProdModeWithFileOp)> - install_source_provider, - IwaSourceBundleProdFileOp file_op) { - return ::web_app::Install( - profile, web_bundle_id_, - install_source_provider(web_app::IwaSourceProdModeWithFileOp( - web_app::IwaSourceBundleProdModeWithFileOp(path(), file_op)))); -} - -FakeWebContentsManager::FakePageState& -BundledIsolatedWebApp::FakeInstallPageState(Profile* profile) { - auto url_info = - IsolatedWebAppUrlInfo::CreateFromSignedWebBundleId(web_bundle_id_); - return ::web_app::FakeInstallPageState( - profile, url_info, manifest_builder_.ToBlinkManifest(url_info.origin())); -} - -// static -std::unique_ptr<ScopedBundledIsolatedWebApp> -ScopedBundledIsolatedWebApp::Create( - const web_package::SignedWebBundleId& web_bundle_id, - const std::vector<uint8_t> serialized_bundle, - ManifestBuilder manifest_builder) { - base::ScopedAllowBlockingForTesting allow_blocking; - base::ScopedTempFile bundle_file; - CHECK(bundle_file.Create()); - - return base::WrapUnique(new ScopedBundledIsolatedWebApp( - web_bundle_id, std::move(serialized_bundle), std::move(bundle_file), - std::move(manifest_builder))); -} - -ScopedBundledIsolatedWebApp::ScopedBundledIsolatedWebApp( - const web_package::SignedWebBundleId& web_bundle_id, - const std::vector<uint8_t> serialized_bundle, - base::ScopedTempFile bundle_file, - ManifestBuilder manifest_builder) - : BundledIsolatedWebApp(web_bundle_id, - std::move(serialized_bundle), - bundle_file.path(), - std::move(manifest_builder)), - bundle_file_(std::move(bundle_file)) {} - -ScopedBundledIsolatedWebApp::~ScopedBundledIsolatedWebApp() { - base::ScopedAllowBlockingForTesting allow_blocking; - bundle_file_.Reset(); -} - -ScopedProxyIsolatedWebApp::ScopedProxyIsolatedWebApp( - std::unique_ptr<net::EmbeddedTestServer> proxy_server, - std::optional<ManifestBuilder> manifest_builder) - : proxy_server_(std::move(proxy_server)), - manifest_builder_(manifest_builder) {} - -ScopedProxyIsolatedWebApp::~ScopedProxyIsolatedWebApp() = default; - -IsolatedWebAppUrlInfo ScopedProxyIsolatedWebApp::InstallChecked( - Profile* profile) { - auto result = Install(profile); - CHECK(result.has_value()) << result.error(); - return *result; -} - -base::expected<IsolatedWebAppUrlInfo, std::string> -ScopedProxyIsolatedWebApp::Install(Profile* profile) { - return Install(profile, - web_package::SignedWebBundleId::CreateRandomForProxyMode()); -} - -base::expected<IsolatedWebAppUrlInfo, std::string> -ScopedProxyIsolatedWebApp::Install( - Profile* profile, - const web_package::SignedWebBundleId& web_bundle_id) { - return ::web_app::Install(profile, web_bundle_id, - IsolatedWebAppInstallSource::FromDevUi( - IwaSourceProxy(proxy_server_->GetOrigin()))); -} - -FakeWebContentsManager::FakePageState& -ScopedProxyIsolatedWebApp::FakeInstallPageState( - Profile* profile, - const web_package::SignedWebBundleId& web_bundle_id) { - auto url_info = - IsolatedWebAppUrlInfo::CreateFromSignedWebBundleId(web_bundle_id); - return ::web_app::FakeInstallPageState( - profile, url_info, manifest_builder_->ToBlinkManifest(url_info.origin())); -} - ManifestBuilder::PermissionsPolicy::PermissionsPolicy( bool wildcard, bool self, @@ -877,4 +736,126 @@ return response; } +BundledIsolatedWebApp::BundledIsolatedWebApp( + const web_package::SignedWebBundleId& web_bundle_id, + const std::vector<uint8_t> serialized_bundle, + const base::FilePath path, + ManifestBuilder manifest_builder) + : web_bundle_id_(web_bundle_id), + path_(std::move(path)), + manifest_builder_(manifest_builder) { + base::ScopedAllowBlockingForTesting allow_blocking; + CHECK(base::WriteFile(path_, std::move(serialized_bundle))); +} + +BundledIsolatedWebApp::~BundledIsolatedWebApp() = default; + +std::string BundledIsolatedWebApp::GetBundleData() const { + base::ScopedAllowBlockingForTesting allow_blocking; + std::string content; + CHECK(base::ReadFileToString(path_, &content)); + return content; +} + +void BundledIsolatedWebApp::TrustSigningKey() { + AddTrustedWebBundleIdForTesting(web_bundle_id_); +} + +FakeWebContentsManager::FakePageState& +BundledIsolatedWebApp::FakeInstallPageState(Profile* profile) { + auto url_info = + IsolatedWebAppUrlInfo::CreateFromSignedWebBundleId(web_bundle_id_); + return ::web_app::FakeInstallPageState( + profile, url_info, manifest_builder_.ToBlinkManifest(url_info.origin())); +} + +base::expected<IsolatedWebAppUrlInfo, std::string> +BundledIsolatedWebApp::TrustBundleAndInstall(Profile* profile) { + TrustSigningKey(); + return Install(profile); +} + +base::expected<IsolatedWebAppUrlInfo, std::string> +BundledIsolatedWebApp::InstallWithSource(Profile* profile, + IsolatedWebAppInstallSource source, + bool fake_install_page, + bool trust_key) { + return ::web_app::Install(profile, web_bundle_id_, source, manifest_builder_, + fake_install_page, trust_key); +} + +// static +std::unique_ptr<ScopedBundledIsolatedWebApp> +ScopedBundledIsolatedWebApp::Create( + const web_package::SignedWebBundleId& web_bundle_id, + const std::vector<uint8_t> serialized_bundle, + ManifestBuilder manifest_builder) { + base::ScopedAllowBlockingForTesting allow_blocking; + base::ScopedTempFile bundle_file; + CHECK(bundle_file.Create()); + + return base::WrapUnique(new ScopedBundledIsolatedWebApp( + web_bundle_id, std::move(serialized_bundle), std::move(bundle_file), + std::move(manifest_builder))); +} + +ScopedBundledIsolatedWebApp::ScopedBundledIsolatedWebApp( + const web_package::SignedWebBundleId& web_bundle_id, + const std::vector<uint8_t> serialized_bundle, + base::ScopedTempFile bundle_file, + ManifestBuilder manifest_builder) + : BundledIsolatedWebApp(web_bundle_id, + std::move(serialized_bundle), + bundle_file.path(), + std::move(manifest_builder)), + bundle_file_(std::move(bundle_file)) {} + +ScopedBundledIsolatedWebApp::~ScopedBundledIsolatedWebApp() { + base::ScopedAllowBlockingForTesting allow_blocking; + bundle_file_.Reset(); +} + +ScopedProxyIsolatedWebApp::ScopedProxyIsolatedWebApp( + std::unique_ptr<net::EmbeddedTestServer> proxy_server, + const ManifestBuilder& manifest_builder) + : proxy_server_(std::move(proxy_server)), + manifest_builder_(manifest_builder) {} + +ScopedProxyIsolatedWebApp::~ScopedProxyIsolatedWebApp() = default; + +IsolatedWebAppUrlInfo ScopedProxyIsolatedWebApp::InstallChecked( + Profile* profile) { + auto result = Install(profile); + CHECK(result.has_value()) << result.error(); + return *result; +} + +base::expected<IsolatedWebAppUrlInfo, std::string> +ScopedProxyIsolatedWebApp::Install(Profile* profile) { + return Install(profile, + web_package::SignedWebBundleId::CreateRandomForProxyMode()); +} + +base::expected<IsolatedWebAppUrlInfo, std::string> +ScopedProxyIsolatedWebApp::Install( + Profile* profile, + const web_package::SignedWebBundleId& web_bundle_id) { + return ::web_app::Install(profile, web_bundle_id, + IsolatedWebAppInstallSource::FromDevUi( + IwaSourceProxy(proxy_server_->GetOrigin())), + manifest_builder_, + /*fake_install_page=*/true, + /*trust_key=*/false); +} + +FakeWebContentsManager::FakePageState& +ScopedProxyIsolatedWebApp::FakeInstallPageState( + Profile* profile, + const web_package::SignedWebBundleId& web_bundle_id) { + auto url_info = + IsolatedWebAppUrlInfo::CreateFromSignedWebBundleId(web_bundle_id); + return ::web_app::FakeInstallPageState( + profile, url_info, manifest_builder_.ToBlinkManifest(url_info.origin())); +} + } // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h b/chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h index 82290141..074464d 100644 --- a/chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h +++ b/chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h
@@ -16,6 +16,7 @@ #include "base/files/scoped_temp_file.h" #include "base/functional/function_ref.h" #include "base/memory/scoped_refptr.h" +#include "base/traits_bag.h" #include "base/types/expected.h" #include "base/version.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_install_source.h" @@ -50,6 +51,10 @@ namespace web_app { +class BundledIsolatedWebApp; +class ScopedBundledIsolatedWebApp; +class ScopedProxyIsolatedWebApp; + // A builder for a subset of the Web Manifest spec. class ManifestBuilder { public: @@ -132,106 +137,6 @@ std::map<std::string, FileHandlerAccept> file_handlers_; }; -class BundledIsolatedWebApp { - public: - BundledIsolatedWebApp(const web_package::SignedWebBundleId& web_bundle_id, - const std::vector<uint8_t> serialized_bundle, - const base::FilePath path, - ManifestBuilder manifest_builder); - - virtual ~BundledIsolatedWebApp(); - - const base::FilePath& path() const { return path_; } - - const web_package::SignedWebBundleId& web_bundle_id() const { - return web_bundle_id_; - } - - base::Version version() const { return manifest_builder_.version(); } - - std::string GetBundleData() const; - - // Saves this app's signing key in Chrome's list of trusted keys, which will - // allow the app to be installed with dev mode disabled. - void TrustSigningKey(); - - web_app::FakeWebContentsManager::FakePageState& FakeInstallPageState( - Profile* profile); - - // uses GraphicalInstaller source - base::expected<IsolatedWebAppUrlInfo, std::string> Install(Profile* profile); - - base::expected<IsolatedWebAppUrlInfo, std::string> InstallWithSource( - Profile* profile, - IsolatedWebAppInstallSource source); - - base::expected<IsolatedWebAppUrlInfo, std::string> InstallWithSource( - Profile* profile, - base::FunctionRef<IsolatedWebAppInstallSource(IwaSourceDevModeWithFileOp)> - install_source_provider, - IwaSourceBundleDevFileOp file_op = IwaSourceBundleDevFileOp::kCopy); - - base::expected<IsolatedWebAppUrlInfo, std::string> InstallWithSource( - Profile* profile, - base::FunctionRef<IsolatedWebAppInstallSource( - IwaSourceProdModeWithFileOp)> install_source_provider, - IwaSourceBundleProdFileOp file_op = IwaSourceBundleProdFileOp::kCopy); - - IsolatedWebAppUrlInfo InstallChecked(Profile* profile); - base::expected<IsolatedWebAppUrlInfo, std::string> TrustBundleAndInstall( - Profile* profile); - - private: - web_package::SignedWebBundleId web_bundle_id_; - base::FilePath path_; - ManifestBuilder manifest_builder_; -}; - -class ScopedBundledIsolatedWebApp : public BundledIsolatedWebApp { - public: - static std::unique_ptr<ScopedBundledIsolatedWebApp> Create( - const web_package::SignedWebBundleId& web_bundle_id, - const std::vector<uint8_t> serialized_bundle, - ManifestBuilder manifest_builder); - - ~ScopedBundledIsolatedWebApp() override; - - private: - ScopedBundledIsolatedWebApp( - const web_package::SignedWebBundleId& web_bundle_id, - const std::vector<uint8_t> serialized_bundle, - base::ScopedTempFile bundle_file, - ManifestBuilder manifest_builder); - - base::ScopedTempFile bundle_file_; -}; - -class ScopedProxyIsolatedWebApp { - public: - explicit ScopedProxyIsolatedWebApp( - std::unique_ptr<net::EmbeddedTestServer> proxy_server, - std::optional<ManifestBuilder> manifest_builder = std::nullopt); - - ~ScopedProxyIsolatedWebApp(); - - net::EmbeddedTestServer& proxy_server() { return *proxy_server_; } - - IsolatedWebAppUrlInfo InstallChecked(Profile* profile); - - base::expected<IsolatedWebAppUrlInfo, std::string> Install(Profile* profile); - base::expected<IsolatedWebAppUrlInfo, std::string> Install( - Profile* profile, - const web_package::SignedWebBundleId& web_bundle_id); - - web_app::FakeWebContentsManager::FakePageState& FakeInstallPageState( - Profile* profile, - const web_package::SignedWebBundleId& web_bundle_id); - - private: - std::unique_ptr<net::EmbeddedTestServer> proxy_server_; - std::optional<ManifestBuilder> manifest_builder_; -}; - // A builder for Isolated Web Apps that supports adding resources from disk // (typically from //chrome/test/data), or from strings provided by the test, // and allows callers to create a dev proxy server or signed web bundle file @@ -397,6 +302,238 @@ std::map<std::string, Resource> resources_; }; +class BundledIsolatedWebApp { + public: +#define WITH_TRAITS(TraitNames) \ + template <typename... TraitNames> \ + requires base::trait_helpers::AreValidTraits< \ + BundledIsolatedWebApp::ValidTraits, TraitNames...> + struct DoNotFakeInstallPage {}; + struct DoNotTrustKey {}; + struct ValidTraits { + explicit ValidTraits(DoNotFakeInstallPage); + explicit ValidTraits(DoNotTrustKey); + }; + + BundledIsolatedWebApp(const web_package::SignedWebBundleId& web_bundle_id, + const std::vector<uint8_t> serialized_bundle, + const base::FilePath path, + ManifestBuilder manifest_builder); + + virtual ~BundledIsolatedWebApp(); + + const base::FilePath& path() const { return path_; } + + const web_package::SignedWebBundleId& web_bundle_id() const { + return web_bundle_id_; + } + + base::Version version() const { return manifest_builder_.version(); } + + std::string GetBundleData() const; + + // Saves this app's signing key in Chrome's list of trusted keys, which will + // allow the app to be installed with dev mode disabled. + void TrustSigningKey(); + + // Configures FakeWebContentsManager with a fake installation page matching + // the data from this bundle. This is necessary for unit tests that can't + // load the auto-generated install page in a real renderer process. + web_app::FakeWebContentsManager::FakePageState& FakeInstallPageState( + Profile* profile); + + // Installs the IWA contained in this bundle with the IWA_GRAPHICAL_INSTALLER + // install source. + // + // The bundle's signing key will be marked as trusted prior to installation + // unless the `DoNotTrustKey` trait is provided. + // A fake installation page will be configured if `FakeWebAppProvider` is + // being used unless the `DoNotFakeInstallPage` trait is provided. + // + // Callers should generally wrap this function in ASSERT_OK_AND_ASSIGN when + // possible: + // ASSERT_OK_AND_ASSIGN(web_app::IsolatedWebAppUrlInfo url_info, + // iwa->Install(profile())); + WITH_TRAITS(InstallationTraits) + base::expected<IsolatedWebAppUrlInfo, std::string> Install( + Profile* profile, + InstallationTraits&&... traits); + + // Like `Install`, but CHECKs that the installation was successful. + // Prefer using `Install` whenever possible for better error messages. + WITH_TRAITS(InstallationTraits) + IsolatedWebAppUrlInfo InstallChecked(Profile* profile, + InstallationTraits&&... traits); + + // Installs the IWA contained in this bundle with the install source + // returned by `install_source_provider`: + // ASSERT_OK_AND_ASSIGN(web_app::IsolatedWebAppUrlInfo url_info, + // iwa->InstallWithSource(profile(), + // &IsolatedWebAppInstallSource::FromExternalPolicy)); + WITH_TRAITS(InstallationTraits) + base::expected<IsolatedWebAppUrlInfo, std::string> InstallWithSource( + Profile* profile, + base::FunctionRef<IsolatedWebAppInstallSource( + IwaSourceProdModeWithFileOp)> install_source_provider, + IwaSourceBundleProdFileOp file_op = IwaSourceBundleProdFileOp::kCopy, + InstallationTraits&&... traits); + + WITH_TRAITS(InstallationTraits) + base::expected<IsolatedWebAppUrlInfo, std::string> InstallWithSource( + Profile* profile, + base::FunctionRef<IsolatedWebAppInstallSource(IwaSourceDevModeWithFileOp)> + install_source_provider, + IwaSourceBundleDevFileOp file_op = kDefaultBundleDevFileOp, + InstallationTraits&&... traits); + + WITH_TRAITS(InstallationTraits) + base::expected<IsolatedWebAppUrlInfo, std::string> InstallWithSource( + Profile* profile, + base::FunctionRef<IsolatedWebAppInstallSource( + IwaSourceBundleWithModeAndFileOp)> install_source_provider, + IwaSourceBundleModeAndFileOp file_op = + IwaSourceBundleModeAndFileOp::kProdModeCopy, + InstallationTraits&&... traits); + + // TODO(crbug.com/390443309): Delete this + base::expected<IsolatedWebAppUrlInfo, std::string> TrustBundleAndInstall( + Profile* profile); + + private: + WITH_TRAITS(InstallationTraits) + base::expected<IsolatedWebAppUrlInfo, std::string> InstallWithSource( + Profile* profile, + IsolatedWebAppInstallSource source, + InstallationTraits&&... traits) { + return InstallWithSource( + profile, source, + /*fake_install_page=*/ + !base::trait_helpers::HasTrait<DoNotFakeInstallPage, + InstallationTraits...>(), + /*trust_key=*/ + !base::trait_helpers::HasTrait<DoNotTrustKey, InstallationTraits...>()); + } + + base::expected<IsolatedWebAppUrlInfo, std::string> InstallWithSource( + Profile* profile, + IsolatedWebAppInstallSource source, + bool fake_install_page, + bool trust_key); + + web_package::SignedWebBundleId web_bundle_id_; + base::FilePath path_; + ManifestBuilder manifest_builder_; +}; + +WITH_TRAITS(InstallationTraits) +base::expected<IsolatedWebAppUrlInfo, std::string> +BundledIsolatedWebApp::Install(Profile* profile, + InstallationTraits&&... traits) { + return InstallWithSource( + profile, &IsolatedWebAppInstallSource::FromGraphicalInstaller, + IwaSourceBundleModeAndFileOp::kProdModeCopy, traits...); +} + +WITH_TRAITS(InstallationTraits) +IsolatedWebAppUrlInfo BundledIsolatedWebApp::InstallChecked( + Profile* profile, + InstallationTraits&&... traits) { + auto result = Install(profile, traits...); + CHECK(result.has_value()) << result.error(); + return *result; +} + +WITH_TRAITS(InstallationTraits) +base::expected<IsolatedWebAppUrlInfo, std::string> +BundledIsolatedWebApp::InstallWithSource( + Profile* profile, + base::FunctionRef<IsolatedWebAppInstallSource(IwaSourceProdModeWithFileOp)> + install_source_provider, + IwaSourceBundleProdFileOp file_op, + InstallationTraits&&... traits) { + return InstallWithSource( + profile, + install_source_provider(IwaSourceProdModeWithFileOp( + IwaSourceBundleProdModeWithFileOp(path(), file_op))), + traits...); +} + +WITH_TRAITS(InstallationTraits) +base::expected<IsolatedWebAppUrlInfo, std::string> +BundledIsolatedWebApp::InstallWithSource( + Profile* profile, + base::FunctionRef<IsolatedWebAppInstallSource(IwaSourceDevModeWithFileOp)> + install_source_provider, + IwaSourceBundleDevFileOp file_op, + InstallationTraits&&... traits) { + return InstallWithSource( + profile, + install_source_provider(IwaSourceDevModeWithFileOp( + IwaSourceBundleDevModeWithFileOp(path(), file_op))), + traits...); +} + +WITH_TRAITS(InstallationTraits) +base::expected<IsolatedWebAppUrlInfo, std::string> +BundledIsolatedWebApp::InstallWithSource( + Profile* profile, + base::FunctionRef<IsolatedWebAppInstallSource( + IwaSourceBundleWithModeAndFileOp)> install_source_provider, + IwaSourceBundleModeAndFileOp file_op, + InstallationTraits&&... traits) { + return InstallWithSource( + profile, + install_source_provider( + IwaSourceBundleWithModeAndFileOp(path(), file_op)), + traits...); +} +#undef WITH_TRAITS + +class ScopedBundledIsolatedWebApp : public BundledIsolatedWebApp { + public: + static std::unique_ptr<ScopedBundledIsolatedWebApp> Create( + const web_package::SignedWebBundleId& web_bundle_id, + const std::vector<uint8_t> serialized_bundle, + ManifestBuilder manifest_builder); + + ~ScopedBundledIsolatedWebApp() override; + + private: + ScopedBundledIsolatedWebApp( + const web_package::SignedWebBundleId& web_bundle_id, + const std::vector<uint8_t> serialized_bundle, + base::ScopedTempFile bundle_file, + ManifestBuilder manifest_builder); + + base::ScopedTempFile bundle_file_; +}; + +class ScopedProxyIsolatedWebApp { + public: + ScopedProxyIsolatedWebApp( + std::unique_ptr<net::EmbeddedTestServer> proxy_server, + const ManifestBuilder& manifest_builder); + + ~ScopedProxyIsolatedWebApp(); + + net::EmbeddedTestServer& proxy_server() { return *proxy_server_; } + + IsolatedWebAppUrlInfo InstallChecked(Profile* profile); + + base::expected<IsolatedWebAppUrlInfo, std::string> Install(Profile* profile); + base::expected<IsolatedWebAppUrlInfo, std::string> Install( + Profile* profile, + const web_package::SignedWebBundleId& web_bundle_id); + + web_app::FakeWebContentsManager::FakePageState& FakeInstallPageState( + Profile* profile, + const web_package::SignedWebBundleId& web_bundle_id); + + private: + std::unique_ptr<net::EmbeddedTestServer> proxy_server_; + ManifestBuilder manifest_builder_; +}; + } // namespace web_app #endif // CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_TEST_ISOLATED_WEB_APP_BUILDER_H_
diff --git a/chrome/browser/web_applications/os_integration/mac/BUILD.gn b/chrome/browser/web_applications/os_integration/mac/BUILD.gn index 44469c3b..a76bf301 100644 --- a/chrome/browser/web_applications/os_integration/mac/BUILD.gn +++ b/chrome/browser/web_applications/os_integration/mac/BUILD.gn
@@ -2,6 +2,7 @@ # Copyright 2018 The Chromium Authors # found in the LICENSE file. +import("//build/config/sanitizers/sanitizers.gni") import("//build/util/branding.gni") import("//chrome/version.gni") @@ -42,5 +43,12 @@ # relative path is correct given the executable's location. "-Wcrl,installnametool,-change,@executable_path/../Frameworks/${chrome_product_full_name} Framework.framework/Versions/${chrome_version_full}/${chrome_product_full_name} Framework,@executable_path/../${chrome_product_full_name} Framework", ] + + if (is_asan || is_ubsan_any) { + # When sanitizers are used their runtime libraries are found in the + # versioned subdirectory of the framework, one level above where the + # helper is installed. + ldflags += [ "-Wl,-rpath,@executable_path/.." ] + } } }
diff --git a/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_copier_mac.mm b/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_copier_mac.mm index dcdbc93d..4d31e20d 100644 --- a/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_copier_mac.mm +++ b/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_copier_mac.mm
@@ -13,6 +13,7 @@ #include "base/apple/mach_port_rendezvous.h" #include "base/base_paths.h" #include "base/command_line.h" +#include "base/debug/leak_annotations.h" #include "base/feature_list.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -90,7 +91,12 @@ const auto& command_line = *base::CommandLine::ForCurrentProcess(); base::HistogramSharedMemory::InitFromLaunchParameters(command_line); - base::FieldTrialList field_trial_list; + // This is intentionally leaked since it needs to live for the duration of + // the process and there's no benefit in cleaning it up at exit. + base::FieldTrialList* leaked_field_trial_list = new base::FieldTrialList(); + ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list); + std::ignore = leaked_field_trial_list; + base::FieldTrialList::CreateTrialsInChildProcess(command_line); auto feature_list = std::make_unique<base::FeatureList>(); base::FieldTrialList::ApplyFeatureOverridesInChildProcess(feature_list.get());
diff --git a/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_creator.mm b/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_creator.mm index baf60f7..8ef2499 100644 --- a/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_creator.mm +++ b/chrome/browser/web_applications/os_integration/mac/web_app_shortcut_creator.mm
@@ -662,9 +662,7 @@ #if defined(ADDRESS_SANITIZER) const base::FilePath asan_library_path = - framework_bundle_path.Append("Versions") - .Append("Current") - .Append("libclang_rt.asan_osx_dynamic.dylib"); + framework_bundle_path.Append("libclang_rt.asan_osx_dynamic.dylib"); if (!base::CopyFile(asan_library_path, destination_executable_path.Append( asan_library_path.BaseName()))) { LOG(ERROR) << "Failed to copy asan library: " << asan_library_path;
diff --git a/chrome/browser/web_applications/scope_extension_info.cc b/chrome/browser/web_applications/scope_extension_info.cc index 4096d10..a3dc600 100644 --- a/chrome/browser/web_applications/scope_extension_info.cc +++ b/chrome/browser/web_applications/scope_extension_info.cc
@@ -50,7 +50,13 @@ ScopeExtensionInfo::ScopeExtensionInfo(url::Origin origin, GURL scope, bool has_origin_wildcard) - : origin(origin), scope(scope), has_origin_wildcard(has_origin_wildcard) {} + : origin(origin), has_origin_wildcard(has_origin_wildcard) { + GURL::Replacements replacements; + replacements.ClearRef(); + replacements.ClearQuery(); + this->scope = scope.ReplaceComponents(replacements); + CHECK(this->scope.is_valid()); +} void ScopeExtensionInfo::Reset() { origin = url::Origin();
diff --git a/chrome/browser/web_applications/scope_extension_info.h b/chrome/browser/web_applications/scope_extension_info.h index 022ed21..a424533 100644 --- a/chrome/browser/web_applications/scope_extension_info.h +++ b/chrome/browser/web_applications/scope_extension_info.h
@@ -43,7 +43,9 @@ url::Origin origin; - // Must be the same origin as `origin` else CHECK-fails + // Must be the same origin as `origin` else CHECK-fails. + // `scope` will also drop any queries or fragments from the URL per manifest + // scope rules: https://w3c.github.io/manifest/#scope-member GURL scope; bool has_origin_wildcard = false;
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc index bd2fc28..df5c202 100644 --- a/chrome/browser/web_applications/web_app_install_finalizer.cc +++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -40,6 +40,7 @@ #include "chrome/browser/web_applications/os_integration/web_app_shortcuts_menu.h" #include "chrome/browser/web_applications/policy/web_app_policy_manager.h" #include "chrome/browser/web_applications/proto/web_app_install_state.pb.h" +#include "chrome/browser/web_applications/scope_extension_info.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app_command_manager.h" #include "chrome/browser/web_applications/web_app_constants.h" @@ -310,6 +311,12 @@ web_app->SetManifestId(web_app_info.manifest_id()); } + for (auto& scope_extension : validated_scope_extensions) { + // This is done to prune any queries or fragments from the scope URL which + // may have been skipped by WebAppOriginAssociationManager validation. + scope_extension = ScopeExtensionInfo::CreateForScope( + scope_extension.scope, scope_extension.has_origin_wildcard); + } web_app->SetValidatedScopeExtensions(validated_scope_extensions); const base::Time now_time = base::Time::Now();
diff --git a/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc b/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc index 2133362..e8a8525 100644 --- a/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc +++ b/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc
@@ -585,4 +585,68 @@ EXPECT_EQ(ScopeExtensions(), installed_app->validated_scope_extensions()); } +class WebAppInstallFinalizerUnitTestQueriesAndFragments + : public WebAppInstallFinalizerUnitTest, + public testing::WithParamInterface<std::tuple<std::string, std::string>> { + public: + WebAppInstallFinalizerUnitTestQueriesAndFragments() = default; + WebAppInstallFinalizerUnitTestQueriesAndFragments( + const WebAppInstallFinalizerUnitTestQueriesAndFragments&) = delete; + WebAppInstallFinalizerUnitTestQueriesAndFragments& operator=( + const WebAppInstallFinalizerUnitTestQueriesAndFragments&) = delete; + ~WebAppInstallFinalizerUnitTestQueriesAndFragments() override = default; +}; + +TEST_P(WebAppInstallFinalizerUnitTestQueriesAndFragments, + ValidateOriginAssociationsDropQueriesAndFragments) { + std::string start_url_str, expected_sanitized_start_url_str; + std::tie(start_url_str, expected_sanitized_start_url_str) = GetParam(); + GURL start_url(start_url_str); + GURL expected_sanitized_start_url(expected_sanitized_start_url_str); + auto info = WebAppInstallInfo::CreateWithStartUrlForTesting(start_url); + info->title = u"Foo Title"; + WebAppInstallFinalizer::FinalizeOptions options( + webapps::WebappInstallSource::INTERNAL_DEFAULT); + + auto scope_extension = + ScopeExtensionInfo::CreateForScope(start_url, + /*has_origin_wildcard=*/true); + CHECK(!scope_extension.origin.opaque()); + info->scope_extensions = {scope_extension}; + + // Set data such that scope_extension will be returned in validated data. + std::map<ScopeExtensionInfo, ScopeExtensionInfo> data = { + {scope_extension, scope_extension}}; + static_cast<FakeWebAppOriginAssociationManager&>( + provider().origin_association_manager()) + .SetData(data); + + FinalizeInstallResult result = AwaitFinalizeInstall(*info, options); + + EXPECT_EQ(webapps::InstallResultCode::kSuccessNewInstall, result.code); + const WebApp* installed_app = registrar().GetAppById(result.installed_app_id); + EXPECT_EQ(installed_app->install_state(), + proto::InstallState::INSTALLED_WITH_OS_INTEGRATION); + EXPECT_EQ(ScopeExtensions({scope_extension}), + installed_app->validated_scope_extensions()); + for (const auto& scope_ext_info : + installed_app->validated_scope_extensions()) { + ASSERT_EQ(expected_sanitized_start_url, scope_ext_info.scope); + } +} + +INSTANTIATE_TEST_SUITE_P( + , + WebAppInstallFinalizerUnitTestQueriesAndFragments, + testing::Values( + std::tuple<std::string, std::string>("https://foo.example/path", + "https://foo.example/path"), + std::tuple<std::string, std::string>( + "https://foo.example/search?q=querystring", + "https://foo.example/search"), + std::tuple<std::string, std::string>("https://foo.example/#hello", + "https://foo.example"), + std::tuple<std::string, std::string>( + "https://foo.example/search?q=querystring#hello", + "https://foo.example/search"))); } // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_install_info.h b/chrome/browser/web_applications/web_app_install_info.h index 42909cf6..c20ad82b 100644 --- a/chrome/browser/web_applications/web_app_install_info.h +++ b/chrome/browser/web_applications/web_app_install_info.h
@@ -389,6 +389,9 @@ // The app intends to have an extended scope containing URLs described by this // information. + // Note: All specified 'scope' members of these extensions will have queries + // and fragments stripped, per specification. + // https://w3c.github.io/manifest/#scope-member base::flat_set<web_app::ScopeExtensionInfo> scope_extensions; // `scope_extensions` after going through validation with associated origins. @@ -396,6 +399,9 @@ // See // https://github.com/WICG/manifest-incubations/blob/gh-pages/scope_extensions-explainer.md // for association requirements. + // Note: All specified 'scope' members of these extensions will have queries + // and fragments stripped, per specification. + // https://w3c.github.io/manifest/#scope-member std::optional<base::flat_set<web_app::ScopeExtensionInfo>> validated_scope_extensions;
diff --git a/chrome/browser/web_applications/web_app_origin_association_manager_browsertest.cc b/chrome/browser/web_applications/web_app_origin_association_manager_browsertest.cc index 9830c773..a309add 100644 --- a/chrome/browser/web_applications/web_app_origin_association_manager_browsertest.cc +++ b/chrome/browser/web_applications/web_app_origin_association_manager_browsertest.cc
@@ -23,7 +23,7 @@ const std::string& kWebAppIdentity = "https://foo.com/index"; const std::string& kInvalidFileUrl = "https://a.com"; const std::string& kValidAppUrl = "https://b.com"; -const std::string& kValidAndInvalidAppsUrl = "https://c.com"; +const std::string& kValidAndInvalidAppsUrl = "https://c.com/search"; constexpr char kInvalidFileContent[] = "invalid"; constexpr char kValidAppFileContent[] = @@ -33,7 +33,7 @@ constexpr char kValidAndInvalidAppsFileContent[] = R"({ // 1st app is valid. - "https://foo.com/index": {}, + "https://foo.com/index": { "scope": "/search?q=some+text#frag"}, // 2nd app is invalid since kWebAppIdentity doesn't match. "https://bar.com/": {} })"; @@ -76,8 +76,7 @@ valid_and_invalid_app_scope_extension_ = std::make_unique<ScopeExtensionInfo>( - ScopeExtensionInfo::CreateForOrigin( - url::Origin::Create(GURL(kValidAndInvalidAppsUrl)))); + ScopeExtensionInfo::CreateForScope(GURL(kValidAndInvalidAppsUrl))); } void VerifyValidAndInvalidAppsResult(int expected_callback_count, @@ -89,8 +88,8 @@ auto valid_app_scope_extension = ScopeExtensionInfo::CreateForOrigin(valid_app_scope_extension_->origin); auto valid_and_invalid_app_scope_extension = - ScopeExtensionInfo::CreateForOrigin( - valid_and_invalid_app_scope_extension_->origin, + ScopeExtensionInfo::CreateForScope( + valid_and_invalid_app_scope_extension_->scope, /*has_origin_wildcard*/ valid_and_invalid_app_scope_extension_ ->has_origin_wildcard);
diff --git a/chrome/browser/web_applications/web_app_origin_association_task.cc b/chrome/browser/web_applications/web_app_origin_association_task.cc index ab5c0ea..5fbaa427 100644 --- a/chrome/browser/web_applications/web_app_origin_association_task.cc +++ b/chrome/browser/web_applications/web_app_origin_association_task.cc
@@ -87,7 +87,13 @@ for (webapps::mojom::AssociatedWebAppPtr& associated_app : association->apps) { if (associated_app->web_app_identity == web_app_identity_) { - scope_extension.scope = associated_app->scope; + // Must drop the fragments and queries per `scope` rules + // https://w3c.github.io/manifest/#scope-member + GURL::Replacements replacements; + replacements.ClearRef(); + replacements.ClearQuery(); + scope_extension.scope = + associated_app->scope.ReplaceComponents(replacements); result_.insert(scope_extension); scope_extension.Reset(); // Only information in the first valid app is saved.
diff --git a/chrome/browser/web_applications/web_app_registrar_unittest.cc b/chrome/browser/web_applications/web_app_registrar_unittest.cc index bab9537..b3074cf 100644 --- a/chrome/browser/web_applications/web_app_registrar_unittest.cc +++ b/chrome/browser/web_applications/web_app_registrar_unittest.cc
@@ -33,6 +33,7 @@ #include "chrome/browser/web_applications/policy/web_app_policy_manager.h" #include "chrome/browser/web_applications/proto/web_app_install_state.pb.h" #include "chrome/browser/web_applications/proto/web_app_proto_package.pb.h" +#include "chrome/browser/web_applications/scope_extension_info.h" #include "chrome/browser/web_applications/test/fake_web_app_database_factory.h" #include "chrome/browser/web_applications/test/fake_web_app_provider.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" @@ -1344,13 +1345,22 @@ // Full scope auto associate_url3 = GURL("https://example.co.uk"); - auto associate_extended_scope3 = GURL(associate_url3.spec()); + + // Scope with query and fragment + auto associate_url4 = + GURL("https://example.com.jp/search?q=asdf+text#fragment"); + auto associate_extended_scope4 = GURL(associate_url4.spec()); + + auto associate_url5 = GURL("https://example.com/index.html/#fragment"); + auto associate_extended_scope5 = GURL(associate_url5.spec()); web_app->SetValidatedScopeExtensions( {ScopeExtensionInfo::CreateForScope(associate_extended_scope), ScopeExtensionInfo::CreateForScope(associate_url2, /*has_origin_wildcard=*/true), - ScopeExtensionInfo::CreateForScope(associate_extended_scope3)}); + ScopeExtensionInfo::CreateForScope(associate_url3), + ScopeExtensionInfo::CreateForScope(associate_extended_scope4), + ScopeExtensionInfo::CreateForScope(associate_extended_scope5)}); RegisterAppUnsafe(std::move(web_app)); EXPECT_EQ( @@ -1379,6 +1389,18 @@ EXPECT_GT(registrar().GetAppExtendedScopeScore(GURL("https://example.co.uk"), app_id), 0); + EXPECT_GT(registrar().GetAppExtendedScopeScore( + GURL("https://example.com.jp/search"), app_id), + 0); + EXPECT_GT(registrar().GetAppExtendedScopeScore( + GURL("https://example.com.jp/search?q=something"), app_id), + 0); + EXPECT_GT(registrar().GetAppExtendedScopeScore( + GURL("https://example.com/index.html"), app_id), + 0); + EXPECT_GT(registrar().GetAppExtendedScopeScore( + GURL("https://example.com/index.html#asdfragment"), app_id), + 0); // Scope is extended to the example.app domain but not to the sub-domain // test.example.app as there was no wildcard prefix.
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index d2630ce..78c4f4f4 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1737115005-482922d9175421026dc3dd21473ffb1d4fb98113-623d6c39e745b0364b5e0878f07acda7defaa7b9.profdata +chrome-android32-main-1737158320-fedaacbe63d5f10467f6a8daeb6b35b0eadfb65b-af448557a34dd74fb5ecff008e7999e0032d502c.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index 47071da..4a55cafe8 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1737128294-a16742f5aada72b0516cd0254efc9628e4323f7f-c6fb21258973e36f73e7a28e5fbce765b0cc8d8f.profdata +chrome-android64-main-1737170057-2dd81d1cf4f2b655382e77fb55984ff716f0dc2b-df6266822515c4ebd6cae97bca7257d72a26dfb6.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index f69c667..a1359ac 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1737115005-dccb6b20b4c7d87c7a0672baf66db81cafd9702a-623d6c39e745b0364b5e0878f07acda7defaa7b9.profdata +chrome-linux-main-1737158320-51227ec4a7ea4a3fcbfe4585edff23ca8f1732db-af448557a34dd74fb5ecff008e7999e0032d502c.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 03ccd5836..28ebeb0 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1737129594-4345a568799efb7b99a130f4db7478c0198e763e-e3cb317bc792776896d9cb072a3f174336d4d405.profdata +chrome-mac-arm-main-1737172188-dca06392eebd4d654067abf45435ee079219e98d-67931b1c9c05ced5e20cfef2de06fb29089603ee.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index c886529..5f08d0f 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1737115005-dd692b949c6b28ad25571111290df5c3159bb2e5-623d6c39e745b0364b5e0878f07acda7defaa7b9.profdata +chrome-mac-main-1737158320-dd36e26034ea2677c08e52381f5271471f93fcc5-af448557a34dd74fb5ecff008e7999e0032d502c.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index 8784040..f30d1d2 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1737115005-27a96aefc900efe8f0fcb81a754e4faa7675a8a2-623d6c39e745b0364b5e0878f07acda7defaa7b9.profdata +chrome-win-arm64-main-1737136754-25e26133ca72705eeeea0b076b82527747fcce10-df4518b150c1be94e9cf81d4cec18313497d1fc0.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 36380ade..ab5ffc91 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1737103675-4468051c31afb340fbe369b56ccd4c70c30fce44-c19fabb3b4ddf650867ee9d59c91fbef047c018a.profdata +chrome-win32-main-1737158320-3e4d855371ca00cb22fdb7c6f16859c279e7cf38-af448557a34dd74fb5ecff008e7999e0032d502c.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index fec2eab..41688ad 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1737103675-37144d3f5279fbc49c2f576567ba1a1f21eaa6cc-c19fabb3b4ddf650867ee9d59c91fbef047c018a.profdata +chrome-win64-main-1737158320-2009e7a28046a0c5772eadbbf60cfccdb952dd01-af448557a34dd74fb5ecff008e7999e0032d502c.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 6c57db8..127f3872 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -333,11 +333,19 @@ const base::FeatureParam<bool> kTabstripComboButtonHasBackground{ &kTabstripComboButton, "has_background", true}; +const base::FeatureParam<bool> kTabstripComboButtonHasReverseButtonOrder{ + &kTabstripComboButton, "reverse_button_order", false}; + bool HasTabstripComboButtonWithBackground() { return IsTabstripComboButtonEnabled() && features::kTabstripComboButtonHasBackground.Get(); } +bool HasTabstripComboButtonWithReverseButtonOrder() { + return IsTabstripComboButtonEnabled() && + features::kTabstripComboButtonHasReverseButtonOrder.Get(); +} + // Force Privacy Guide to be available even if it would be unavailable // otherwise. This is meant for development and test purposes only. BASE_FEATURE(kPrivacyGuideForceAvailable, @@ -757,7 +765,7 @@ // Minimum amount of time allowed between requesting k-anonymity status from the // Query server for a distinct group. constexpr base::FeatureParam<base::TimeDelta> kKAnonymityServiceQueryInterval{ - &kKAnonymityService, "KAnonymityServiceJoinInterval", base::Days(1)}; + &kKAnonymityService, "KAnonymityServiceQueryInterval", base::Days(1)}; // When enabled, the k-Anonymity Service will send requests to the Join and // Query k-anonymity servers.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 988276d..4348c5f 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -216,6 +216,10 @@ COMPONENT_EXPORT(CHROME_FEATURES) extern const base::FeatureParam<bool> kTabstripComboButtonHasBackground; COMPONENT_EXPORT(CHROME_FEATURES) bool HasTabstripComboButtonWithBackground(); +COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::FeatureParam<bool> kTabstripComboButtonHasReverseButtonOrder; +COMPONENT_EXPORT(CHROME_FEATURES) +bool HasTabstripComboButtonWithReverseButtonOrder(); COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kPrivacyGuideForceAvailable);
diff --git a/chrome/common/extensions/api/bookmarks.json b/chrome/common/extensions/api/bookmarks.json index 68525ab..f6581db6 100644 --- a/chrome/common/extensions/api/bookmarks.json +++ b/chrome/common/extensions/api/bookmarks.json
@@ -23,8 +23,6 @@ "id": "FolderType", "type": "string", "enum": ["bookmarks-bar", "other", "mobile", "managed"], - // TODO: crbug.com/383970322 - Remove once API naming is finalized. - "nodoc": true, "description": "Indicates the type of folder. <ul><li>bookmarks-bar: The folder whose contents is displayed at the top of the browser window<li>other: Bookmarks which are displayed in the full list of bookmarks on all platforms<li>mobile: bookmarks generally available on the user's mobile devices, but modifiable by extension or in the bookmarks manager<li>managed: a top-level folder that may be present if the system administrator or the custodian of a supervised user has configured bookmarks.</ul>" }, { @@ -81,8 +79,6 @@ "folderType": { "$ref": "FolderType", "optional": true, - // TODO: crbug.com/383970322 - Remove once API naming is finalized. - "nodoc": true, "description": "If present, this is a folder that is added by the browser and that cannot be modified by the user or the extension. Child nodes may be modified, if this node does not have the <code>unmodifiable</code> property set. Omitted if the node can be modified by the user and the extension (default).<p>There may be zero, one or multiple nodes of each folder type. A folder may be added or removed by the browser, but not via the extensions API." }, "unmodifiable": { @@ -92,8 +88,6 @@ }, "syncing": { "type": "boolean", - // TODO: crbug.com/384024391 - Remove once API naming is finalized. - "nodoc": true, "description": "Whether this node is synced with the user's remote account storage by the browser. This can be used to distinguish between account and local-only versions of the same $(ref:FolderType). The value of this property may change for an existing node, for example as a result of user action.<p>Note: this reflects whether the node is saved to the browser's built-in account provider. It is possible that a node could be synced via a third-party, even if this value is false.</p><p>For managed nodes (nodes where <code>unmodifiable</code> is set to <code>true</code>), this property will always be <code>false</code>.</p>" }, "children": {
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc index ea48951..754a4e6 100644 --- a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc +++ b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
@@ -16,7 +16,6 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "chrome/grit/generated_resources.h" -#include "components/device_signals/core/common/signals_features.h" #include "extensions/common/mojom/api_permission_id.mojom.h" #include "ui/base/l10n/l10n_util.h" @@ -279,10 +278,6 @@ }; int GetEnterpriseReportingPrivatePermissionMessageId() { - if (!base::FeatureList::IsEnabled( - enterprise_signals::features::kNewEvSignalsEnabled)) { - return IDS_EXTENSION_PROMPT_WARNING_ENTERPRISE_REPORTING_PRIVATE; - } #if BUILDFLAG(IS_WIN) return IDS_EXTENSION_PROMPT_WARNING_ENTERPRISE_REPORTING_PRIVATE_ENABLED_WIN; #elif BUILDFLAG(IS_LINUX) or BUILDFLAG(IS_MAC)
diff --git a/chrome/release_scripts b/chrome/release_scripts index b37cf13..cc3ac97 160000 --- a/chrome/release_scripts +++ b/chrome/release_scripts
@@ -1 +1 @@ -Subproject commit b37cf13dae4ea8bdbff22cee2b4820c94c83bab8 +Subproject commit cc3ac97c66a56f4218fee70f28958eaf11ef5d66
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 0d874d4..ed56bd48 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1808,6 +1808,7 @@ "../browser/extensions/system_cpu_apitest.cc", "../browser/extensions/system_memory_apitest.cc", "../browser/extensions/test_resources_browsertest.cc", + "../browser/extensions/web_accessible_resources_browsertest.cc", ] deps += [ @@ -4066,6 +4067,7 @@ "../browser/apps/platform_apps/platform_app_navigation_redirector_browsertest.cc", "../browser/apps/platform_apps/service_worker_browsertest.cc", "../browser/controlled_frame/controlled_frame_apitest.cc", + "../browser/controlled_frame/controlled_frame_contextmenus_browsertest.cc", "../browser/controlled_frame/controlled_frame_dialog_browsertest.cc", "../browser/controlled_frame/controlled_frame_disabled_permission_browsertest.cc", "../browser/controlled_frame/controlled_frame_new_window_browsertest.cc", @@ -5869,7 +5871,6 @@ "../browser/component_updater/subresource_filter_component_installer_unittest.cc", "../browser/component_updater/tpcd_metadata_component_installer_unittest.cc", "../browser/content_index/content_index_provider_unittest.cc", - "../browser/contextual_cueing/contextual_cueing_helper_unittest.cc", "../browser/custom_handlers/chrome_protocol_handler_registry_unittest.cc", "../browser/data_sharing/data_sharing_navigation_throttle_unittest.cc", "../browser/data_sharing/data_sharing_service_factory_unittest.cc", @@ -6389,7 +6390,6 @@ "//chrome/browser/content_extraction", "//chrome/browser/content_settings", "//chrome/browser/content_settings:content_settings_factory", - "//chrome/browser/contextual_cueing", "//chrome/browser/crash_upload_list:unit_tests", "//chrome/browser/data_saver", "//chrome/browser/devtools", @@ -7449,6 +7449,7 @@ "../browser/component_updater/soda_component_installer_unittest.cc", "../browser/component_updater/soda_language_pack_component_installer_unittest.cc", "../browser/component_updater/zxcvbn_data_component_installer_unittest.cc", + "../browser/contextual_cueing/contextual_cueing_helper_unittest.cc", "../browser/data_sharing/desktop/data_sharing_conversion_utils_unittest.cc", "../browser/device_identity/device_oauth2_token_service_unittest.cc", "../browser/device_notifications/device_connection_tracker_unittest.cc", @@ -7850,6 +7851,7 @@ ] deps += [ + "//chrome/browser/contextual_cueing", "//chrome/browser/ui/bookmarks:unit_tests", "//chrome/browser/ui/safety_hub", "//chrome/browser/ui/startup:startup_tab", @@ -9489,9 +9491,6 @@ "//chrome/browser/ui/device_signals_consent:test_support", "//components/device_signals/core/browser", "//components/device_signals/core/browser:test_support", - "//components/device_signals/core/common", - "//components/device_signals/core/common:features", - "//components/device_signals/core/common:unit_tests", "//components/enterprise/device_trust", "//services/data_decoder/public/cpp:test_support", ] @@ -10602,6 +10601,7 @@ "../browser/autofill_ai/autofill_ai_browsertest.cc", "../browser/browser_keyevents_browsertest.cc", "../browser/chrome_render_widget_host_browsertests.cc", + "../browser/contextual_cueing/contextual_cueing_helper_interactive_uitest.cc", "../browser/controlled_frame/controlled_frame_interactive_browsertest.cc", "../browser/devtools/devtools_interactive_browsertest.cc", "../browser/download/download_interactive_uitest.cc", @@ -10758,6 +10758,7 @@ "//chrome/browser/autofill:interactive_ui_tests", "//chrome/browser/autofill:test_support_ui", "//chrome/browser/content_settings:content_settings_factory", + "//chrome/browser/contextual_cueing", "//chrome/browser/devtools", "//chrome/browser/devtools:test_support", "//chrome/browser/file_system_access",
diff --git a/chrome/test/data/accessibility/extension/manifest.json b/chrome/test/data/accessibility/extension/manifest.json new file mode 100644 index 0000000..6156b98 --- /dev/null +++ b/chrome/test/data/accessibility/extension/manifest.json
@@ -0,0 +1,7 @@ +{ + "name": "test extension", + "manifest_version": 3, + "version": "1.0", + "key": "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDCQ+ePDzpLth/ZnUewmbuutBlIOU7RFD27Cy7Z/hFVAGA4wns+Xzj8SJ4YfcQQ1qIH7XfcPe6L+lT+IF8dMwHd5uXIFQWd8gHxeaQoIJcsPjnNgxbVR+TsAuzrgbCWz+gNz0/dDNjqVs+3Dv1QKGf6XE/+iJ4LfkzahIMtsUFp2UaOy+bYT7eh8FGmO8zuQmjAv5gM2I3K3C/8gUBvwm9yhipv/Dn7OtHLcBNHbCq0fbGIHLythTrhBTT81Z+RLAdQy787rS2gQH3IuFqLxuLfXFNBUI30QBdu2c5bL1PbePP+4w+UY8rBQ4ltqO8RDgIJl6zathCsBNtCLt3Yt5hnAgMBAAECggEAMHmkUwjwOYtJOFKsXG+IK0iKlICkX7zGyKE6QDBLX+QXnqI9AaveOund9WuQnMkKJqNFiQI1P92oDr/CLDWZricbSImiXK7SeFCru02im2otn1AqRu9JOvFh8ERs7b0UgTmtipHVoOgnrdzCLhnfFFSrq26ozWJnSBHP7/tuwLwERmBtRldo5HbV7SZWSd54vS2BimijBo4nob7vC+QZf+1p8KEWzi7GvjLxMfpaMMjaC6BcIfvUJPHvPETEMCaLgjb42d4fjr/HECge4elI1dKcXt+IiCJ0pP6Axo1VglIxNqkHbCXlkb/E+F0mST0drYz+Yix4WpxX6eSMg4aEfQKBgQD+E3mFXa3E73Fc5SoZjdvj3KnmEv7CrM3BC79fI9Ljc52PTpp7LKEpl7ywH3vAl06XW0ktwCL+fOth+frgJgRfAMQsq8u8vl9842+yl81i/yoPRRsxM8cri84d3AJRExffY6eddjc6WHqYUauhTz38gUXNvaz+bMNtGXlE2bTBJQKBgQDDvHyhAdWkZa9wTADbmL5UTlVZb/9jS8+ENUpHISqUkOKEwoxvaa071CccurIpxflfP9T+kzdreXGuKHqrziPl4lVfYCDJXo8UmvB9x7/BXvrm0+CGs8rt2i7gL66wVnf9YsGPs5B7KBK/Z8TwS7gie3MNMFLZS8qdcEvc+xzbmwKBgQDRntOlurJBRqOq1s8zIh0HE+mAjq9tghCHct/C6NV3Hs4hi+JcOWgF3tCoJnF9ZdhLe98WRe0ZNYsl3I6lG/iDQSiZCmwfHpm9eg+PszqasJbM3mEe6O8r+D5n2Dp5FV2eyqNhgET0eEc9IDSP88baavViV1lA2A8sFdY9fbhpmQKBgQCjkrDUHKRdblzei6Vr3omwCoZo55+Va5VP9vjL2HutDCdAqxSRRs7uYK0O5TZekoODheSJmp2Fw0etM0bQrMRzKGIQAlVj8xG/NnwjoPouryEeJZJM/5Nmkh76Wt6xnpFHv2/ilzz2rtZ7/kwmRCDtMB1FuEyEK0J3r5C2a2QCYQKBgASVezK2dt9N9kpNxFSJEdW5k7DUZAmAqMVndgIEWWbsurXot5rbgYfhezoST94XVa0K3juIY3lBigvC3ZTafEcLbNEfL8eYmcgb4zK85F2biyIw9Hv5fxqOPsMJ6Ltub3FaORlJGzHPz2783ZTirBsBQgSvQCqKtISVZlwrzXtl", + "description": "A simple extension with a defined id (cjlaeehoipngghikfjogbdkpbdgebppb) for accessibility testing." +}
diff --git a/chrome/test/data/pdf/ink2_viewer_toolbar_test.ts b/chrome/test/data/pdf/ink2_viewer_toolbar_test.ts index 3546423b..201cb24fb 100644 --- a/chrome/test/data/pdf/ink2_viewer_toolbar_test.ts +++ b/chrome/test/data/pdf/ink2_viewer_toolbar_test.ts
@@ -55,6 +55,34 @@ !viewerToolbar.shadowRoot!.querySelector('viewer-annotations-bar')); chrome.test.succeed(); }, + // Ink1 disables some toolbar buttons when in annotation mode, but Ink2 does + // not have the same limitations. Test that these buttons are still enabled in + // Ink2 annotation mode. + async function testInk1DisabledButtonsAreEnabled() { + chrome.test.assertFalse(viewerToolbar.annotationMode); + + viewerToolbar.toggleAnnotation(); + await microtasksFinished(); + + const rotationButton = + getRequiredElement<HTMLButtonElement>(viewerToolbar, '#rotate'); + const twoPageViewButton = getRequiredElement<HTMLButtonElement>( + viewerToolbar, '#two-page-view-button'); + + chrome.test.assertTrue(viewerToolbar.annotationMode); + chrome.test.assertFalse(viewerToolbar.$.sidenavToggle.disabled); + chrome.test.assertFalse(rotationButton.disabled); + chrome.test.assertFalse(twoPageViewButton.disabled); + + viewerToolbar.toggleAnnotation(); + await microtasksFinished(); + + chrome.test.assertFalse(viewerToolbar.annotationMode); + chrome.test.assertFalse(viewerToolbar.$.sidenavToggle.disabled); + chrome.test.assertFalse(rotationButton.disabled); + chrome.test.assertFalse(twoPageViewButton.disabled); + chrome.test.succeed(); + }, // </if> // Test that toggling annotation mode does not affect displaying annotations. async function testTogglingAnnotationModeDoesNotAffectDisplayAnnotations() {
diff --git a/chrome/test/data/webui/chromeos/BUILD.gn b/chrome/test/data/webui/chromeos/BUILD.gn index 6ac5ca85..6bb4ff9 100644 --- a/chrome/test/data/webui/chromeos/BUILD.gn +++ b/chrome/test/data/webui/chromeos/BUILD.gn
@@ -187,7 +187,7 @@ "multidevice_setup/integration_test.js", "multidevice_setup/setup_succeeded_page_test.js", "multidevice_setup/start_setup_page_test.js", - "network/apn_list_item_test.js", + "network/apn_list_item_test.ts", "network/apn_list_test.ts", "network/apn_selection_dialog_list_item_test.js", "network/apn_selection_dialog_test.ts",
diff --git a/chrome/test/data/webui/chromeos/network/apn_list_item_test.js b/chrome/test/data/webui/chromeos/network/apn_list_item_test.js deleted file mode 100644 index 707b4f6..0000000 --- a/chrome/test/data/webui/chromeos/network/apn_list_item_test.js +++ /dev/null
@@ -1,535 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'chrome://os-settings/strings.m.js'; -import 'chrome://resources/ash/common/network/apn_list_item.js'; -import 'chrome://resources/ash/common/cr_elements/cr_action_menu/cr_action_menu.js'; - -import {ApnDetailDialogMode, ApnEventData} from 'chrome://resources/ash/common/network/cellular_utils.js'; -import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js'; -import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js'; -import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {ApnState, ApnType, CrosNetworkConfigRemote} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; -import {NetworkType, PortalState} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; -import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; -import {FakeNetworkConfig} from 'chrome://webui-test/chromeos/fake_network_config_mojom.js'; -import {flushTasks} from 'chrome://webui-test/polymer_test_util.js'; -import {eventToPromise} from 'chrome://webui-test/test_util.js'; - -/** @type {!ApnEventData} */ -const TEST_APN_EVENT_DATA = { - apn: { - name: 'test_apn', - }, - guid: 'test-guid', - mode: ApnDetailDialogMode.VIEW, -}; - -suite('ApnListItemTest', function() { - /** @type {ApnListItemElement} */ - let apnListItem = null; - - /** @type {?CrosNetworkConfigRemote} */ - let mojoApi_ = null; - - setup(async function() { - mojoApi_ = new FakeNetworkConfig(); - MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_; - }); - - async function init() { - apnListItem = document.createElement('apn-list-item'); - apnListItem.apn = { - accessPointName: 'apn1', - }; - apnListItem.guid = 'cellular_guid'; - document.body.appendChild(apnListItem); - return flushTasks(); - } - - function openThreeDotMenu() { - const menuButton = - apnListItem.shadowRoot.querySelector('#actionMenuButton'); - assertTrue(!!menuButton); - assertFalse(apnListItem.$.dotsMenu.open); - - menuButton.click(); - return flushTasks(); - } - - test('Check if APN list item exists', async function() { - await init(); - assertTrue(!!apnListItem); - apnListItem.apn = { - accessPointName: 'apn1', - }; - await flushTasks(); - assertEquals( - apnListItem.$.apnName.innerText, apnListItem.apn.accessPointName); - - apnListItem.apn = { - accessPointName: apnListItem.apn.accessPointName, - name: 'name', - }; - await flushTasks(); - assertEquals(apnListItem.$.apnName.innerText, apnListItem.apn.name); - - apnListItem.apn = {}; - await flushTasks(); - assertEquals( - apnListItem.$.apnName.innerText, apnListItem.i18n('apnNameModem')); - }); - - test('Check if connected sublabel is shown', async function() { - await init(); - apnListItem.isConnected = false; - await flushTasks(); - - const subLabel = apnListItem.shadowRoot.querySelector('#subLabel'); - assertTrue(!!subLabel); - assertTrue(subLabel.hasAttribute('hidden')); - apnListItem.isConnected = true; - await flushTasks(); - - assertFalse(subLabel.hasAttribute('hidden')); - assertFalse(subLabel.hasAttribute('warning')); - assertEquals( - apnListItem.i18n('NetworkHealthStateConnected'), subLabel.innerText); - - apnListItem.portalState = PortalState.kNoInternet; - assertFalse(subLabel.hasAttribute('hidden')); - assertTrue(subLabel.hasAttribute('warning')); - assertEquals( - apnListItem.i18n('networkListItemConnectedNoConnectivity'), - subLabel.innerText); - }); - - test('Check if APN three dot menu shows', async function() { - await init(); - await openThreeDotMenu(); - assertTrue(apnListItem.$.dotsMenu.open); - }); - - test('Check disabled state.', async function() { - await init(); - apnListItem.apn = { - state: ApnState.kDisabled, - accessPointName: 'apn', - }; - await flushTasks(); - assertFalse(apnListItem.hasAttribute('is-disabled_')); - - apnListItem.apn = { - state: ApnState.kEnabled, - accessPointName: 'apn', - id: '1', - }; - await flushTasks(); - assertFalse(apnListItem.hasAttribute('is-disabled_')); - - apnListItem.apn = { - state: ApnState.kDisabled, - accessPointName: 'apn', - id: '1', - }; - await flushTasks(); - assertTrue(apnListItem.hasAttribute('is-disabled_')); - }); - - test('Check if three dot menu remove APN works', async function() { - await init(); - const guid = 'cellular_guid'; - await openThreeDotMenu(); - const getRemoveButton = () => - apnListItem.$.dotsMenu.querySelector('#removeButton'); - assertFalse(!!getRemoveButton()); - - apnListItem.apn = { - accessPointName: 'name1', - id: '1', - }; - await flushTasks(); - assertTrue(!!getRemoveButton()); - assertFalse(!!getRemoveButton().disabled); - - apnListItem.shouldDisallowApnModification = true; - assertTrue(!!getRemoveButton().disabled); - - apnListItem.shouldDisallowApnModification = false; - mojoApi_.setNetworkTypeEnabledState(NetworkType.kCellular, true); - const props = OncMojo.getDefaultManagedProperties( - NetworkType.kCellular, guid, 'cellular'); - - props.typeProperties.cellular = { - customApnList: [{ - accessPointName: 'name1', - id: '1', - }], - }; - mojoApi_.setManagedPropertiesForTest(props); - let managedProps = await mojoApi_.getManagedProperties(guid); - assertEquals( - 1, managedProps.result.typeProperties.cellular.customApnList.length); - getRemoveButton().click(); - await mojoApi_.whenCalled('removeCustomApn'); - - managedProps = await mojoApi_.getManagedProperties(guid); - assertEquals( - 0, managedProps.result.typeProperties.cellular.customApnList.length); - assertFalse(apnListItem.$.dotsMenu.open); - }); - - test('Check if three dot menu disable/enable APN works', async function() { - await init(); - const guid = 'cellular_guid'; - await openThreeDotMenu(); - const getEnableButton = () => - apnListItem.$.dotsMenu.querySelector('#enableButton'); - const getDisableButton = () => - apnListItem.$.dotsMenu.querySelector('#disableButton'); - assertFalse(!!getEnableButton()); - assertFalse(!!getDisableButton()); - - const createApn = (disabled) => { - return { - accessPointName: 'name1', - id: '1', - state: disabled ? ApnState.kDisabled : ApnState.kEnabled, - }; - }; - - mojoApi_.setNetworkTypeEnabledState(NetworkType.kCellular, true); - const props = OncMojo.getDefaultManagedProperties( - NetworkType.kCellular, guid, 'cellular'); - const disabledApn = createApn(/*disabled=*/ true); - props.typeProperties.cellular = { - customApnList: [disabledApn], - }; - mojoApi_.setManagedPropertiesForTest(props); - - apnListItem.apn = disabledApn; - await flushTasks(); - assertTrue(!!getEnableButton()); - assertFalse(!!getEnableButton().disabled); - assertFalse(!!getDisableButton()); - - apnListItem.shouldDisallowApnModification = true; - assertTrue(!!getEnableButton().disabled); - - apnListItem.shouldDisallowApnModification = false; - getEnableButton().click(); - await mojoApi_.whenCalled('modifyCustomApn'); - let managedProps = await mojoApi_.getManagedProperties(guid); - assertEquals( - ApnState.kEnabled, - managedProps.result.typeProperties.cellular.customApnList[0].state); - assertFalse(apnListItem.$.dotsMenu.open); - - apnListItem.apn = createApn(/*disabled=*/ false); - await flushTasks(); - assertTrue(!!getDisableButton()); - assertFalse(!!getDisableButton().disabled); - assertFalse(!!getEnableButton()); - - apnListItem.shouldDisallowApnModification = true; - assertTrue(!!getDisableButton().disabled); - - apnListItem.shouldDisallowApnModification = false; - getDisableButton().click(); - await mojoApi_.whenCalled('modifyCustomApn'); - managedProps = await mojoApi_.getManagedProperties(guid); - assertEquals( - ApnState.kDisabled, - managedProps.result.typeProperties.cellular.customApnList[0].state); - assertFalse(apnListItem.$.dotsMenu.open); - }); - - [true, false].forEach(isApnRevampAndAllowApnModificationPolicyEnabled => { - test( - `Clicking APN details button triggers a show-apn-detail-dialog event - when isApnRevampAndAllowApnModificationPolicyEnabled is ${ - isApnRevampAndAllowApnModificationPolicyEnabled}`, - async function() { - loadTimeData.overrideValues({ - isApnRevampAndAllowApnModificationPolicyEnabled, - }); - await init(); - apnListItem.apn = TEST_APN_EVENT_DATA.apn; - apnListItem.guid = TEST_APN_EVENT_DATA.guid; - - const subLabel = - apnListItem.shadowRoot.querySelector('#autoDetected'); - assertTrue(!!subLabel); - assertFalse(subLabel.hasAttribute('hidden')); - assertEquals(apnListItem.i18n('apnAutoDetected'), subLabel.innerText); - - let apnDetailsClickedEvent = - eventToPromise('show-apn-detail-dialog', window); - assertTrue(!!apnListItem.$.detailsButton); - assertEquals( - apnListItem.i18n('apnMenuDetails'), - apnListItem.$.detailsButton.innerText.trim()); - apnListItem.$.detailsButton.click(); - let eventData = await apnDetailsClickedEvent; - - assertEquals(TEST_APN_EVENT_DATA.apn.name, eventData.detail.apn.name); - assertEquals(TEST_APN_EVENT_DATA.mode, eventData.detail.mode); - assertFalse(apnListItem.$.dotsMenu.open); - - // Case: the apn list item is not auto detected. - apnListItem.apn = { - name: TEST_APN_EVENT_DATA.apn.name, - id: '1', - }; - assertTrue(subLabel.hasAttribute('hidden')); - assertEquals( - apnListItem.i18n('apnMenuEdit'), - apnListItem.$.detailsButton.innerText.trim()); - - apnDetailsClickedEvent = - eventToPromise('show-apn-detail-dialog', window); - apnListItem.$.detailsButton.click(); - eventData = await apnDetailsClickedEvent; - assertEquals(TEST_APN_EVENT_DATA.apn.name, eventData.detail.apn.name); - assertEquals(ApnDetailDialogMode.EDIT, eventData.detail.mode); - assertFalse(apnListItem.$.dotsMenu.open); - - if (isApnRevampAndAllowApnModificationPolicyEnabled) { - // Case: APN modification is disallowed. - apnListItem.shouldDisallowApnModification = true; - await flushTasks(); - - assertEquals( - apnListItem.i18n('apnMenuDetails'), - apnListItem.$.detailsButton.innerText.trim()); - - apnDetailsClickedEvent = - eventToPromise('show-apn-detail-dialog', window); - apnListItem.$.detailsButton.click(); - eventData = await apnDetailsClickedEvent; - assertEquals( - TEST_APN_EVENT_DATA.apn.name, eventData.detail.apn.name); - assertEquals(ApnDetailDialogMode.VIEW, eventData.detail.mode); - assertFalse(apnListItem.$.dotsMenu.open); - } - }); - }); - - test('Test if disable/remove warning event is fired.', async function() { - await init(); - const guid = 'cellular_guid'; - let promptShowEvent = eventToPromise('show-error-toast', window); - await openThreeDotMenu(); - const getDisableButton = () => - apnListItem.$.dotsMenu.querySelector('#disableButton'); - const getRemoveButton = () => - apnListItem.$.dotsMenu.querySelector('#removeButton'); - const createApn = () => { - return { - accessPointName: 'name1', - id: '1', - state: ApnState.kEnabled, - }; - }; - - apnListItem.shouldDisallowDisablingRemoving = true; - apnListItem.apn = createApn(); - mojoApi_.setNetworkTypeEnabledState(NetworkType.kCellular, true); - const props = OncMojo.getDefaultManagedProperties( - NetworkType.kCellular, guid, 'cellular'); - - props.typeProperties.cellular = {customApnList: [createApn()]}; - mojoApi_.setManagedPropertiesForTest(props); - await flushTasks(); - getDisableButton().click(); - let eventData = await promptShowEvent; - let managedProps = await mojoApi_.getManagedProperties(guid); - assertEquals( - ApnState.kEnabled, - managedProps.result.typeProperties.cellular.customApnList[0].state); - assertEquals( - apnListItem.i18n('apnWarningPromptForDisableRemove'), eventData.detail); - assertFalse(apnListItem.$.dotsMenu.open); - - promptShowEvent = eventToPromise('show-error-toast', window); - getRemoveButton().click(); - eventData = await promptShowEvent; - managedProps = await mojoApi_.getManagedProperties(guid); - assertEquals( - 1, managedProps.result.typeProperties.cellular.customApnList.length); - assertEquals( - apnListItem.i18n('apnWarningPromptForDisableRemove'), eventData.detail); - assertFalse(apnListItem.$.dotsMenu.open); - }); - - test('Test if enable warning event is fired.', async function() { - await init(); - const guid = 'cellular_guid'; - const promptShowEvent = eventToPromise('show-error-toast', window); - await openThreeDotMenu(); - const getEnableButton = () => - apnListItem.$.dotsMenu.querySelector('#enableButton'); - const createApn = () => { - return { - accessPointName: 'name1', - id: '1', - state: ApnState.kDisabled, - }; - }; - - apnListItem.shouldDisallowEnabling = true; - apnListItem.apn = createApn(); - mojoApi_.setNetworkTypeEnabledState(NetworkType.kCellular, true); - const props = OncMojo.getDefaultManagedProperties( - NetworkType.kCellular, guid, 'cellular'); - - props.typeProperties.cellular = {customApnList: [createApn()]}; - mojoApi_.setManagedPropertiesForTest(props); - await flushTasks(); - getEnableButton().click(); - const eventData = await promptShowEvent; - const managedProps = await mojoApi_.getManagedProperties(guid); - assertEquals( - ApnState.kDisabled, - managedProps.result.typeProperties.cellular.customApnList[0].state); - assertEquals( - apnListItem.i18n('apnWarningPromptForEnable'), eventData.detail); - assertFalse(apnListItem.$.dotsMenu.open); - }); - - test('Item a11y', async function() { - await init(); - apnListItem.itemIndex = 0; - apnListItem.listSize = 1; - - // Enabled custom APN, non-connected. - const apnName = 'apn1'; - const apnUserFriendlyName = 'userFriendlyNameApn1'; - const apnId = '1'; - const defaultTypeOnly = apnListItem.i18n('apnA11yDefaultApnOnly'); - const attachTypeOnly = apnListItem.i18n('apnA11yAttachApnOnly'); - const defaultAndAttach = apnListItem.i18n('apnA11yDefaultAndAttachApn'); - - // Attach only APN. - apnListItem.apn = { - id: apnId, - accessPointName: apnName, - apnTypes: [ApnType.kAttach], - }; - - const enabledText = apnListItem.i18n('apnA11yEnabled'); - const nameText = apnListItem.i18n( - 'apnA11yName', /*index=*/ 1, /*count=*/ 1, /*name=*/ 'apn1'); - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - nameText + ' ' + enabledText + ' ' + attachTypeOnly); - - // Attach and Default APN. - apnListItem.apn = { - id: apnId, - accessPointName: apnName, - apnTypes: [ApnType.kDefault, ApnType.kAttach], - }; - - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - nameText + ' ' + enabledText + ' ' + defaultAndAttach); - - // Default only APN. - apnListItem.apn = { - id: apnId, - accessPointName: apnName, - apnTypes: [ApnType.kDefault], - }; - - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - nameText + ' ' + enabledText + ' ' + defaultTypeOnly); - - // Enabled custom APN, connected. - apnListItem.isConnected = true; - - const connectedText = apnListItem.i18n('apnA11yConnected'); - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - nameText + ' ' + connectedText + ' ' + defaultTypeOnly); - - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - nameText + ' ' + connectedText + ' ' + defaultTypeOnly); - - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - nameText + ' ' + connectedText + ' ' + defaultTypeOnly); - - // Disabled custom APN, non-connected. - apnListItem.apn = { - id: apnId, - accessPointName: apnName, - state: ApnState.kDisabled, - }; - apnListItem.isConnected = false; - - const disabledText = apnListItem.i18n('apnA11yDisabled'); - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - nameText + ' ' + disabledText); - - // Enabled database APN, non-connected. - apnListItem.apn = { - accessPointName: apnName, - }; - apnListItem.isConnected = false; - const autoDetectedText = apnListItem.i18n('apnA11yAutoDetected'); - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - nameText + ' ' + autoDetectedText + ' ' + enabledText); - - // Enabled database APN, connected. - apnListItem.apn = { - accessPointName: apnName, - }; - apnListItem.isConnected = true; - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - nameText + ' ' + autoDetectedText + ' ' + connectedText); - - // Null APN, connected. - apnListItem.apn = {}; - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - apnListItem.i18n( - 'apnA11yName', /*index=*/ 1, /*count=*/ 1, - apnListItem.i18n('apnNameModem')) + - ' ' + autoDetectedText + ' ' + connectedText); - - // User friendly APN name same as APN has no text indicating as such. - apnListItem.apn = { - id: apnId, - accessPointName: apnName, - name: apnName, - }; - apnListItem.isConnected = true; - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - nameText + ' ' + connectedText); - - // User friendly APN name different from APN has indicating text. - const userFriendlyNameText = apnListItem.i18n( - 'apnA11yName', /*index=*/ 1, /*count=*/ 1, - /*name=*/ 'userFriendlyNameApn1'); - apnListItem.apn = { - id: apnId, - accessPointName: apnName, - name: apnUserFriendlyName, - }; - - const indicateUserFriendlyNameText = apnListItem.i18n( - 'apnA11yUserFriendlyNameIndicator', apnUserFriendlyName, apnName); - assertEquals( - apnListItem.$.actionMenuButton.ariaLabel, - userFriendlyNameText + ' ' + connectedText + ' ' + - indicateUserFriendlyNameText); - }); -});
diff --git a/chrome/test/data/webui/chromeos/network/apn_list_item_test.ts b/chrome/test/data/webui/chromeos/network/apn_list_item_test.ts new file mode 100644 index 0000000..3350c66 --- /dev/null +++ b/chrome/test/data/webui/chromeos/network/apn_list_item_test.ts
@@ -0,0 +1,603 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'chrome://os-settings/strings.m.js'; +import 'chrome://resources/ash/common/network/apn_list_item.js'; +import 'chrome://resources/ash/common/cr_elements/cr_action_menu/cr_action_menu.js'; + +import type {CrActionMenuElement} from 'chrome://resources/ash/common/cr_elements/cr_action_menu/cr_action_menu.js'; +import type {CrIconButtonElement} from 'chrome://resources/ash/common/cr_elements/cr_icon_button/cr_icon_button.js'; +import {ApnListItemElement} from 'chrome://resources/ash/common/network/apn_list_item.js'; +import {ApnDetailDialogMode, ApnEventData} from 'chrome://resources/ash/common/network/cellular_utils.js'; +import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js'; +import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {ApnAuthenticationType, ApnIpType, ApnProperties, ApnSource, ApnState, ApnType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; +import {NetworkType, PortalState} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; +import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {flushTasks} from 'chrome://webui-test/polymer_test_util.js'; +import {eventToPromise} from 'chrome://webui-test/test_util.js'; + +import {FakeNetworkConfig} from '../fake_network_config_mojom.js'; + +const TEST_APN_EVENT_DATA_GUID = 'test_guid' + +const TEST_APN_EVENT_DATA: ApnEventData = { + apn: { + accessPointName: 'test_apn', + username: null, + password: null, + authentication: ApnAuthenticationType.kAutomatic, + ipType: ApnIpType.kAutomatic, + apnTypes: [], + state: ApnState.kEnabled, + id: null, + language: null, + localizedName: null, + name: null, + attach: null, + source: ApnSource.kUi, + }, + mode: ApnDetailDialogMode.VIEW, +}; + +suite('ApnListItemTest', function() { + let apnListItem: ApnListItemElement; + + let mojoApi_: FakeNetworkConfig; + + setup(async () => { + mojoApi_ = new FakeNetworkConfig(); + MojoInterfaceProviderImpl.getInstance().setMojoServiceRemoteForTest( + mojoApi_); + }); + + async function init() { + apnListItem = document.createElement('apn-list-item'); + apnListItem.apn = createTestApnWithOverridenValues({ + accessPointName: 'apn1', + }); + apnListItem.guid = 'cellular_guid'; + document.body.appendChild(apnListItem); + return flushTasks(); + } + + function getThreeDotsMenu(): CrActionMenuElement { + return apnListItem.shadowRoot!.querySelector<CrActionMenuElement>( + '#dotsMenu')!; + } + + async function openThreeDotMenu() { + const menuButton = + apnListItem.shadowRoot!.querySelector<CrIconButtonElement>( + '#actionMenuButton'); + assertTrue(!!menuButton); + assertFalse(getThreeDotsMenu().open); + + menuButton.click(); + return flushTasks(); + } + + function createTestApnWithOverridenValues(overrides: Partial<ApnProperties>): + ApnProperties { + return {...TEST_APN_EVENT_DATA.apn, ...overrides}; + } + + test('Check if APN list item exists', async () => { + await init(); + assertTrue(!!apnListItem); + apnListItem.apn = createTestApnWithOverridenValues({ + accessPointName: 'apn1', + }); + await flushTasks(); + assertEquals( + apnListItem.shadowRoot!.querySelector<HTMLDivElement>( + '#apnName')!.innerText, + apnListItem.apn.accessPointName); + + apnListItem.apn = createTestApnWithOverridenValues({ + accessPointName: apnListItem.apn.accessPointName, + name: 'name', + }); + await flushTasks(); + assertEquals( + apnListItem.shadowRoot!.querySelector<HTMLDivElement>( + '#apnName')!.innerText, + apnListItem.apn.name); + + apnListItem.apn = createTestApnWithOverridenValues({ + accessPointName: '', + }); + await flushTasks(); + assertEquals( + apnListItem.shadowRoot!.querySelector<HTMLDivElement>( + '#apnName')!.innerText, + apnListItem.i18n('apnNameModem')); + }); + + test('Check if connected sublabel is shown', async () => { + await init(); + apnListItem.isApnConnected = false; + await flushTasks(); + + const subLabel = + apnListItem.shadowRoot!.querySelector<HTMLDivElement>('#subLabel'); + assertTrue(!!subLabel); + assertTrue(subLabel.hasAttribute('hidden'), 'fails to hide sublabel'); + apnListItem.isApnConnected = true; + await flushTasks(); + + assertFalse(subLabel.hasAttribute('hidden'), 'fails to show sublabel'); + assertFalse( + subLabel.hasAttribute('warning'), + 'fails to add warning attribute in sublabel'); + assertEquals( + apnListItem.i18n('NetworkHealthStateConnected'), subLabel.innerText); + + apnListItem.portalState = PortalState.kNoInternet; + assertFalse(subLabel.hasAttribute('hidden'), 'fails to hide show'); + assertTrue( + subLabel.hasAttribute('warning'), + 'fails to add warning a11y in sublabel'); + assertEquals( + apnListItem.i18n('networkListItemConnectedNoConnectivity'), + subLabel.innerText); + }); + + test('Check if APN three dot menu shows', async () => { + await init(); + await openThreeDotMenu(); + assertTrue(getThreeDotsMenu().open); + }); + + test('Check disabled state.', async () => { + await init(); + apnListItem.apn = createTestApnWithOverridenValues({ + state: ApnState.kDisabled, + accessPointName: 'apn', + }); + await flushTasks(); + assertFalse(apnListItem.hasAttribute('is-disabled_')); + + apnListItem.apn = createTestApnWithOverridenValues({ + state: ApnState.kEnabled, + accessPointName: 'apn', + id: '1', + }); + await flushTasks(); + assertFalse(apnListItem.hasAttribute('is-disabled_')); + + apnListItem.apn = createTestApnWithOverridenValues({ + state: ApnState.kDisabled, + accessPointName: 'apn', + id: '1', + }); + await flushTasks(); + assertTrue(apnListItem.hasAttribute('is-disabled_')); + }); + + test('Check if three dot menu remove APN works', async () => { + await init(); + const guid = 'cellular_guid'; + await openThreeDotMenu(); + const getRemoveButton = () => + getThreeDotsMenu().querySelector<HTMLButtonElement>('#removeButton')!; + assertFalse(!!getRemoveButton()); + + apnListItem.apn = createTestApnWithOverridenValues({ + accessPointName: 'name1', + id: '1', + }); + await flushTasks(); + assertTrue(!!getRemoveButton()); + assertFalse(!!getRemoveButton().disabled); + + apnListItem.shouldDisallowApnModification = true; + assertTrue(!!getRemoveButton().disabled); + + apnListItem.shouldDisallowApnModification = false; + mojoApi_.setNetworkTypeEnabledState(NetworkType.kCellular, true); + const props = OncMojo.getDefaultManagedProperties( + NetworkType.kCellular, guid, 'cellular'); + + props.typeProperties.cellular = { + customApnList: [{ + accessPointName: 'name1', + id: '1', + }], + }; + mojoApi_.setManagedPropertiesForTest(props); + let managedProps = await mojoApi_.getManagedProperties(guid); + assertEquals( + 1, managedProps.result.typeProperties.cellular.customApnList.length); + getRemoveButton().click(); + await mojoApi_.whenCalled('removeCustomApn'); + + managedProps = await mojoApi_.getManagedProperties(guid); + assertEquals( + 0, managedProps.result.typeProperties.cellular.customApnList.length); + assertFalse(getThreeDotsMenu().open); + }); + + test('Check if three dot menu disable/enable APN works', async () => { + await init(); + const guid = 'cellular_guid'; + await openThreeDotMenu(); + const getEnableButton = () => + getThreeDotsMenu().querySelector<HTMLButtonElement>('#enableButton')!; + const getDisableButton = () => + getThreeDotsMenu().querySelector<HTMLButtonElement>('#disableButton')!; + assertFalse(!!getEnableButton()); + assertFalse(!!getDisableButton()); + + const createApn = (disabled: boolean) => { + return createTestApnWithOverridenValues({ + accessPointName: 'name1', + id: '1', + state: disabled ? ApnState.kDisabled : ApnState.kEnabled, + }); + }; + + mojoApi_.setNetworkTypeEnabledState(NetworkType.kCellular, true); + const props = OncMojo.getDefaultManagedProperties( + NetworkType.kCellular, guid, 'cellular'); + const disabledApn = createApn(/*disabled=*/ true); + props.typeProperties.cellular = { + customApnList: [disabledApn], + }; + mojoApi_.setManagedPropertiesForTest(props); + + apnListItem.apn = disabledApn; + await flushTasks(); + assertTrue(!!getEnableButton()); + assertFalse(!!getEnableButton().disabled); + assertFalse(!!getDisableButton()); + + apnListItem.shouldDisallowApnModification = true; + assertTrue(!!getEnableButton().disabled); + + apnListItem.shouldDisallowApnModification = false; + getEnableButton().click(); + await mojoApi_.whenCalled('modifyCustomApn'); + let managedProps = await mojoApi_.getManagedProperties(guid); + assertEquals( + ApnState.kEnabled, + managedProps.result.typeProperties.cellular.customApnList[0].state); + assertFalse(getThreeDotsMenu().open); + + apnListItem.apn = createApn(/*disabled=*/ false); + await flushTasks(); + assertTrue(!!getDisableButton()); + assertFalse(!!getDisableButton().disabled); + assertFalse(!!getEnableButton()); + + apnListItem.shouldDisallowApnModification = true; + assertTrue(!!getDisableButton().disabled); + + apnListItem.shouldDisallowApnModification = false; + getDisableButton().click(); + await mojoApi_.whenCalled('modifyCustomApn'); + managedProps = await mojoApi_.getManagedProperties(guid); + assertEquals( + ApnState.kDisabled, + managedProps.result.typeProperties.cellular.customApnList[0].state); + assertFalse(getThreeDotsMenu().open); + }); + + [true, false].forEach(isApnRevampAndAllowApnModificationPolicyEnabled => { + test( + `Clicking APN details button triggers a show-apn-detail-dialog event + when isApnRevampAndAllowApnModificationPolicyEnabled is ${ + isApnRevampAndAllowApnModificationPolicyEnabled}`, + async () => { + loadTimeData.overrideValues({ + isApnRevampAndAllowApnModificationPolicyEnabled, + }); + await init(); + apnListItem.apn = TEST_APN_EVENT_DATA.apn; + apnListItem.guid = TEST_APN_EVENT_DATA_GUID; + + const subLabel = + apnListItem.shadowRoot!.querySelector<HTMLDivElement>( + '#autoDetected'); + assertTrue(!!subLabel); + assertFalse(subLabel.hasAttribute('hidden')); + assertEquals(apnListItem.i18n('apnAutoDetected'), subLabel.innerText); + + const getDetailsButton = () => + apnListItem.shadowRoot!.querySelector<HTMLButtonElement>( + '#detailsButton')!; + + let apnDetailsClickedEvent = + eventToPromise('show-apn-detail-dialog', window); + assertTrue(!!getDetailsButton()); + assertEquals( + apnListItem.i18n('apnMenuDetails'), + getDetailsButton().innerText.trim()); + getDetailsButton().click(); + let eventData = await apnDetailsClickedEvent; + + assertEquals(TEST_APN_EVENT_DATA.apn.name, eventData.detail.apn.name); + assertEquals(TEST_APN_EVENT_DATA.mode, eventData.detail.mode); + assertFalse(getThreeDotsMenu().open); + + // Case: the apn list item is not auto detected. + apnListItem.apn = createTestApnWithOverridenValues({ + name: TEST_APN_EVENT_DATA.apn.name, + id: '1', + }); + assertTrue(subLabel.hasAttribute('hidden')); + assertEquals( + apnListItem.i18n('apnMenuEdit'), + getDetailsButton().innerText.trim()); + + apnDetailsClickedEvent = + eventToPromise('show-apn-detail-dialog', window); + getDetailsButton()!.click(); + eventData = await apnDetailsClickedEvent; + assertEquals(TEST_APN_EVENT_DATA.apn.name, eventData.detail.apn.name); + assertEquals(ApnDetailDialogMode.EDIT, eventData.detail.mode); + assertFalse(getThreeDotsMenu().open); + + if (isApnRevampAndAllowApnModificationPolicyEnabled) { + // Case: APN modification is disallowed. + apnListItem.shouldDisallowApnModification = true; + await flushTasks(); + + assertEquals( + apnListItem.i18n('apnMenuDetails'), + getDetailsButton().innerText.trim()); + + apnDetailsClickedEvent = + eventToPromise('show-apn-detail-dialog', window); + getDetailsButton().click(); + eventData = await apnDetailsClickedEvent; + assertEquals( + TEST_APN_EVENT_DATA.apn.name, eventData.detail.apn.name); + assertEquals(ApnDetailDialogMode.VIEW, eventData.detail.mode); + assertFalse(getThreeDotsMenu().open); + } + }); + }); + + test('Test if disable/remove warning event is fired.', async () => { + await init(); + const guid = 'cellular_guid'; + let promptShowEvent = eventToPromise('show-error-toast', window); + await openThreeDotMenu(); + const getDisableButton = () => + getThreeDotsMenu().querySelector<HTMLButtonElement>('#disableButton')!; + const getRemoveButton = () => + getThreeDotsMenu().querySelector<HTMLButtonElement>('#removeButton')!; + const createApn = () => createTestApnWithOverridenValues({ + accessPointName: 'name1', + id: '1', + state: ApnState.kEnabled, + }); + + apnListItem.shouldDisallowDisablingRemoving = true; + apnListItem.apn = createApn(); + mojoApi_.setNetworkTypeEnabledState(NetworkType.kCellular, true); + const props = OncMojo.getDefaultManagedProperties( + NetworkType.kCellular, guid, 'cellular'); + + props.typeProperties.cellular = {customApnList: [createApn()]}; + mojoApi_.setManagedPropertiesForTest(props); + await flushTasks(); + getDisableButton().click(); + let eventData = await promptShowEvent; + let managedProps = await mojoApi_.getManagedProperties(guid); + assertEquals( + ApnState.kEnabled, + managedProps.result.typeProperties.cellular.customApnList[0].state); + assertEquals( + apnListItem.i18n('apnWarningPromptForDisableRemove'), eventData.detail); + assertFalse(getThreeDotsMenu().open); + + promptShowEvent = eventToPromise('show-error-toast', window); + getRemoveButton().click(); + eventData = await promptShowEvent; + managedProps = await mojoApi_.getManagedProperties(guid); + assertEquals( + 1, managedProps.result.typeProperties.cellular.customApnList.length); + assertEquals( + apnListItem.i18n('apnWarningPromptForDisableRemove'), eventData.detail); + assertFalse(getThreeDotsMenu().open); + }); + + test('Test if enable warning event is fired.', async () => { + await init(); + const guid = 'cellular_guid'; + const promptShowEvent = eventToPromise('show-error-toast', window); + await openThreeDotMenu(); + const getEnableButton = () => + getThreeDotsMenu().querySelector<HTMLButtonElement>('#enableButton')!; + const createApn = () => createTestApnWithOverridenValues({ + accessPointName: 'name1', + id: '1', + state: ApnState.kDisabled, + }); + + apnListItem.shouldDisallowEnabling = true; + apnListItem.apn = createApn(); + mojoApi_.setNetworkTypeEnabledState(NetworkType.kCellular, true); + const props = OncMojo.getDefaultManagedProperties( + NetworkType.kCellular, guid, 'cellular'); + + props.typeProperties.cellular = {customApnList: [createApn()]}; + mojoApi_.setManagedPropertiesForTest(props); + await flushTasks(); + getEnableButton().click(); + const eventData = await promptShowEvent; + const managedProps = await mojoApi_.getManagedProperties(guid); + assertEquals( + ApnState.kDisabled, + managedProps.result.typeProperties.cellular.customApnList[0].state); + assertEquals( + apnListItem.i18n('apnWarningPromptForEnable'), eventData.detail); + assertFalse(getThreeDotsMenu().open); + }); + + test('Item a11y', async () => { + await init(); + apnListItem.itemIndex = 0; + apnListItem.listSize = 1; + + // Enabled custom APN, non-connected. + const apnName = 'apn1'; + const apnUserFriendlyName = 'userFriendlyNameApn1'; + const apnId = '1'; + const defaultTypeOnly = apnListItem.i18n('apnA11yDefaultApnOnly'); + const attachTypeOnly = apnListItem.i18n('apnA11yAttachApnOnly'); + const defaultAndAttach = apnListItem.i18n('apnA11yDefaultAndAttachApn'); + + // Attach only APN. + apnListItem.apn = createTestApnWithOverridenValues({ + id: apnId, + accessPointName: apnName, + apnTypes: [ApnType.kAttach], + }); + + const enabledText = apnListItem.i18n('apnA11yEnabled'); + const nameText = apnListItem.i18n( + 'apnA11yName', /*index=*/ 1, /*count=*/ 1, /*name=*/ 'apn1'); + + assertEquals( + apnListItem.shadowRoot! + .querySelector<CrIconButtonElement>( + '#actionMenuButton')!.getAttribute('aria-label'), + nameText + ' ' + enabledText + ' ' + attachTypeOnly, + 'Failed a11y for Attach only APN'); + + // Attach and Default APN. + apnListItem.apn = createTestApnWithOverridenValues({ + id: apnId, + accessPointName: apnName, + apnTypes: [ApnType.kDefault, ApnType.kAttach], + }); + + assertEquals( + apnListItem.shadowRoot! + .querySelector<CrIconButtonElement>( + '#actionMenuButton')!.getAttribute('aria-label'), + nameText + ' ' + enabledText + ' ' + defaultAndAttach, + 'Failed a11y for Attach+Default APN'); + + // Default only APN. + apnListItem.apn = createTestApnWithOverridenValues({ + id: apnId, + accessPointName: apnName, + apnTypes: [ApnType.kDefault], + }); + + assertEquals( + apnListItem.shadowRoot! + .querySelector<CrIconButtonElement>( + '#actionMenuButton')!.getAttribute('aria-label'), + nameText + ' ' + enabledText + ' ' + defaultTypeOnly, + 'Failed a11y for Default only APN'); + + // Enabled custom APN, connected. + apnListItem.isApnConnected = true; + await flushTasks(); + + const connectedText = apnListItem.i18n('apnA11yConnected'); + assertEquals( + nameText + ' ' + connectedText + ' ' + defaultTypeOnly, + apnListItem.shadowRoot! + .querySelector<CrIconButtonElement>( + '#actionMenuButton')!.getAttribute('aria-label'), + 'Failed a11y for connected custom APN'); + + // Disabled custom APN, non-connected. + apnListItem.apn = createTestApnWithOverridenValues({ + id: apnId, + accessPointName: apnName, + state: ApnState.kDisabled, + }); + apnListItem.isApnConnected = false; + + const disabledText = apnListItem.i18n('apnA11yDisabled'); + assertEquals( + apnListItem.shadowRoot! + .querySelector<CrIconButtonElement>( + '#actionMenuButton')!.getAttribute('aria-label'), + nameText + ' ' + disabledText, + 'Failed a11y for disconnected disabled custom APN'); + + // Enabled database APN, non-connected. + apnListItem.apn = createTestApnWithOverridenValues({ + accessPointName: apnName, + }); + apnListItem.isApnConnected = false; + const autoDetectedText = apnListItem.i18n('apnA11yAutoDetected'); + assertEquals( + apnListItem.shadowRoot! + .querySelector<CrIconButtonElement>( + '#actionMenuButton')!.getAttribute('aria-label'), + nameText + ' ' + autoDetectedText + ' ' + enabledText, + 'Failed a11y for disconnected but enabled database APN'); + + // Enabled database APN, connected. + apnListItem.apn = createTestApnWithOverridenValues({ + accessPointName: apnName, + }); + apnListItem.isApnConnected = true; + assertEquals( + apnListItem.shadowRoot! + .querySelector<CrIconButtonElement>( + '#actionMenuButton')!.getAttribute('aria-label'), + nameText + ' ' + autoDetectedText + ' ' + connectedText, + 'Failed a11y for enabled database APN, connected'); + + // Null APN, connected. + apnListItem.apn = createTestApnWithOverridenValues({ + accessPointName: '', + name: null, + }); + assertEquals( + apnListItem.shadowRoot! + .querySelector<CrIconButtonElement>( + '#actionMenuButton')!.getAttribute('aria-label'), + apnListItem.i18n( + 'apnA11yName', /*index=*/ 1, /*count=*/ 1, + apnListItem.i18n('apnNameModem')) + + ' ' + autoDetectedText + ' ' + connectedText, + 'Failed a11y for null APN'); + + // User friendly APN name same as APN has no text indicating as such. + apnListItem.apn = createTestApnWithOverridenValues({ + id: apnId, + accessPointName: apnName, + name: apnName, + }); + apnListItem.isApnConnected = true; + assertEquals( + apnListItem.shadowRoot! + .querySelector<CrIconButtonElement>( + '#actionMenuButton')!.getAttribute('aria-label'), + nameText + ' ' + connectedText, + 'Failed a11y for user friendly APN name same as APN'); + + // User friendly APN name different from APN has indicating text. + const userFriendlyNameText = apnListItem.i18n( + 'apnA11yName', /*index=*/ 1, /*count=*/ 1, + /*name=*/ 'userFriendlyNameApn1'); + apnListItem.apn = createTestApnWithOverridenValues({ + id: apnId, + accessPointName: apnName, + name: apnUserFriendlyName, + }); + + const indicateUserFriendlyNameText = apnListItem.i18n( + 'apnA11yUserFriendlyNameIndicator', apnUserFriendlyName, apnName); + assertEquals( + apnListItem.shadowRoot! + .querySelector<CrIconButtonElement>( + '#actionMenuButton')!.getAttribute('aria-label'), + userFriendlyNameText + ' ' + connectedText + ' ' + + indicateUserFriendlyNameText, + 'Failed a11y for user friendly APN name different from APN'); + }); +});
diff --git a/chrome/test/data/webui/chromeos/network/apn_list_test.ts b/chrome/test/data/webui/chromeos/network/apn_list_test.ts index f76541e7..08d0c763 100644 --- a/chrome/test/data/webui/chromeos/network/apn_list_test.ts +++ b/chrome/test/data/webui/chromeos/network/apn_list_test.ts
@@ -288,7 +288,7 @@ assertEquals(1, apns.length); assertTrue(!!apns[0]); assertTrue(OncMojo.apnMatch(apns[0].apn, connectedApn)); - assertTrue(apns[0].isConnected); + assertTrue(apns[0].isApnConnected); }); test('There is no Connected APN and no custom APNs', async () => { @@ -313,7 +313,7 @@ assertTrue(!!apns[1]); assertTrue(OncMojo.apnMatch(apns[0].apn, customApn1)); assertTrue(OncMojo.apnMatch(apns[1].apn, customApn2)); - assertFalse(apns[0].isConnected); + assertFalse(apns[0].isApnConnected); assertFalse(!!getZeroStateContent()); }); @@ -329,7 +329,7 @@ assertEquals(1, apns.length); assertTrue(!!apns[0]); assertTrue(OncMojo.apnMatch(apns[0].apn, connectedApn)); - assertTrue(apns[0].isConnected); + assertTrue(apns[0].isApnConnected); assertFalse(!!getZeroStateContent()); }); @@ -349,7 +349,7 @@ assertTrue(OncMojo.apnMatch(apns[0].apn, connectedApn)); assertTrue(OncMojo.apnMatch(apns[1].apn, customApn1)); assertTrue(OncMojo.apnMatch(apns[2].apn, customApn2)); - assertTrue(apns[0].isConnected); + assertTrue(apns[0].isApnConnected); assertFalse(!!getZeroStateContent()); }); @@ -367,7 +367,7 @@ assertTrue(OncMojo.apnMatch(apns[0].apn, customApn3)); assertTrue(OncMojo.apnMatch(apns[1].apn, customApn1)); assertTrue(OncMojo.apnMatch(apns[2].apn, customApn2)); - assertTrue(apns[0].isConnected); + assertTrue(apns[0].isApnConnected); assertFalse(!!getZeroStateContent()); }); @@ -380,7 +380,7 @@ assertEquals(1, apns.length); assertTrue(!!apns[0]); assertTrue(OncMojo.apnMatch(apns[0].apn, connectedApn)); - assertTrue(apns[0].isConnected); + assertTrue(apns[0].isApnConnected); assertFalse(!!getZeroStateContent()); // Simulate the APN no longer being connected. @@ -392,7 +392,7 @@ assertEquals(1, apns.length); assertTrue(!!apns[0]); assertTrue(OncMojo.apnMatch(apns[0].apn, connectedApn)); - assertFalse(apns[0].isConnected); + assertFalse(apns[0].isApnConnected); assertFalse(!!getZeroStateContent()); });
diff --git a/chrome/test/data/webui/commerce/product_specifications/app_test.ts b/chrome/test/data/webui/commerce/product_specifications/app_test.ts index b4d2b49..acdfd93 100644 --- a/chrome/test/data/webui/commerce/product_specifications/app_test.ts +++ b/chrome/test/data/webui/commerce/product_specifications/app_test.ts
@@ -2233,6 +2233,95 @@ assertEquals(UserFeedback.kUnspecified, feedbackArgs); }); + test('product selection menus are closed after set updates', async () => { + const exampleUrl = {url: 'https://example.com/'}; + const dimensionValues = { + summary: [], + specificationDescriptions: [ + { + label: '', + altText: '', + options: [], + }, + ], + }; + const dimensionValuesMap = new Map<bigint, ProductSpecificationsValue>( + [[BigInt(2), dimensionValues]]); + const specsProduct = createSpecsProduct({ + productClusterId: BigInt(123), + title: 'Product', + productDimensionValues: dimensionValuesMap, + }); + const info = createProductInfo({ + clusterId: BigInt(123), + title: 'Product', + productUrl: exampleUrl, + imageUrl: {url: `${exampleUrl.url}'/image.png'`}, + }); + const promiseValues = createAppPromiseValues({ + idParam: testId, + specs: createSpecs({ + productDimensionMap: new Map<bigint, string>([[BigInt(2), 'Title']]), + products: [specsProduct], + }), + productInfos: [info], + }); + const specsSet = createSpecsSet({ + name: 'table', + urls: [exampleUrl], + uuid: {value: testId}, + }); + shoppingServiceApi.setResultFor( + 'getProductSpecificationsSetByUuid', Promise.resolve({set: specsSet})); + await createAppElementWithPromiseValues(promiseValues); + + // Populate the product selection menu with options. + const productTabs = [{ + title: 'title', + url: {url: 'https://example2.com/'}, + }]; + shoppingServiceApi.setResultFor( + 'getUrlInfosForProductTabs', Promise.resolve({urlInfos: productTabs})); + shoppingServiceApi.setResultFor( + 'getUrlInfosForRecentlyViewedTabs', Promise.resolve({urlInfos: []})); + + // Open the new column selection menu. + const newColSelector = appElement.$.newColumnSelector; + newColSelector.$.button.click(); + await waitAfterNextRender(appElement); + + let menu = newColSelector.$.productSelectionMenu.$.menu.get(); + assertTrue(menu.open); + + focusWindowAndTriggerSetUpdate(createSpecsSet({ + name: 'table', + urls: [exampleUrl, {url: 'https://example3.com'}], + uuid: {value: testId}, + })); + await waitAfterNextRender(appElement); + + assertFalse(menu.open); + + // Open one of the product selection menus from a selector. + const productSelector = $$<ProductSelectorElement>( + appElement.$.summaryTable, 'product-selector'); + assertTrue(!!productSelector); + productSelector.$.currentProductContainer.click(); + await waitAfterNextRender(appElement); + + menu = productSelector.$.productSelectionMenu.$.menu.get(); + assertTrue(menu.open); + + focusWindowAndTriggerSetUpdate(createSpecsSet({ + name: 'table', + urls: [exampleUrl, {url: 'https://example4.com'}], + uuid: {value: testId}, + })); + await waitAfterNextRender(appElement); + + assertFalse(menu.open); + }); + suite('FeatureState', () => { test('feedback hidden if not allowed', async () => { shoppingServiceApi.setResultFor(
diff --git a/chrome/test/data/webui/commerce/product_specifications/comparison_table_list_item_test.ts b/chrome/test/data/webui/commerce/product_specifications/comparison_table_list_item_test.ts index b1e97844..8994db70 100644 --- a/chrome/test/data/webui/commerce/product_specifications/comparison_table_list_item_test.ts +++ b/chrome/test/data/webui/commerce/product_specifications/comparison_table_list_item_test.ts
@@ -11,8 +11,9 @@ import type {CrInputElement} from '//resources/cr_elements/cr_input/cr_input.js'; import {PluralStringProxyImpl} from '//resources/js/plural_string_proxy.js'; import type {ComparisonTableListItemElement} from 'chrome://compare/comparison_table_list_item.js'; +import {ShowSetDisposition} from 'chrome://compare/product_specifications.mojom-webui.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {assertEquals, assertFalse, assertStringContains, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {assertArrayEquals, assertEquals, assertFalse, assertStringContains, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {TestPluralStringProxy} from 'chrome://webui-test/test_plural_string_proxy.js'; import {$$, eventToPromise, microtasksFinished} from 'chrome://webui-test/test_util.js'; @@ -117,6 +118,24 @@ }); test( + 'open in new window option opens the table in a new window', + async () => { + const openInNewWindowButton = + menu.querySelector<HTMLButtonElement>('#openInNewWindow'); + assertTrue(!!openInNewWindowButton); + openInNewWindowButton.click(); + + assertEquals( + 1, + productSpecsProxy.getCallCount( + 'showProductSpecificationsSetsForUuids')); + const args = productSpecsProxy.getArgs( + 'showProductSpecificationsSetsForUuids')[0]; + assertArrayEquals([TABLE_UUID], args[0]); + assertEquals(ShowSetDisposition.kInNewWindow, args[1]); + }); + + test( 'rename option displays input, and submitting emits event with UUID ' + 'and name', async () => {
diff --git a/chrome/test/data/webui/commerce/product_specifications/comparison_table_list_test.ts b/chrome/test/data/webui/commerce/product_specifications/comparison_table_list_test.ts index d656da9..2bd7ceed 100644 --- a/chrome/test/data/webui/commerce/product_specifications/comparison_table_list_test.ts +++ b/chrome/test/data/webui/commerce/product_specifications/comparison_table_list_test.ts
@@ -10,7 +10,8 @@ import {PluralStringProxyImpl} from '//resources/js/plural_string_proxy.js'; import type {ComparisonTableListElement} from 'chrome://compare/comparison_table_list.js'; import type {ComparisonTableListItemElement} from 'chrome://compare/comparison_table_list_item.js'; -import {assertEquals, assertFalse, assertStringContains, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {ShowSetDisposition} from 'chrome://compare/product_specifications.mojom-webui.js'; +import {assertArrayEquals, assertEquals, assertFalse, assertStringContains, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {TestMock} from 'chrome://webui-test/test_mock.js'; import {TestPluralStringProxy} from 'chrome://webui-test/test_plural_string_proxy.js'; import {$$, eventToPromise, microtasksFinished} from 'chrome://webui-test/test_util.js'; @@ -157,19 +158,32 @@ await openAllFinishedPromise; assertEquals( - 2, + 1, productSpecsProxy.getCallCount( - 'showProductSpecificationsSetForUuid')); - const firstCallArgs = - productSpecsProxy.getArgs('showProductSpecificationsSetForUuid')[0]; - const secondCallArgs = - productSpecsProxy.getArgs('showProductSpecificationsSetForUuid')[1]; - assertEquals(TABLES[0]!.uuid, firstCallArgs[0]); + 'showProductSpecificationsSetsForUuids')); + const args = productSpecsProxy.getArgs( + 'showProductSpecificationsSetsForUuids')[0]; + assertArrayEquals([TABLES[0]!.uuid, TABLES[1]!.uuid], args[0]); + assertEquals(ShowSetDisposition.kInNewTabs, args[1]); + }); + + test('can open multiple comparison tables in a new window', async () => { + const openAllInNewWindowFinishedPromise = eventToPromise( + 'open-all-in-new-window-finished-for-testing', listElement); + const openAllInNewWindowButton = + menu.querySelector<HTMLButtonElement>('#menuOpenAllInNewWindow'); + assertTrue(!!openAllInNewWindowButton); + openAllInNewWindowButton.click(); + await openAllInNewWindowFinishedPromise; + assertEquals( - /*inNewTab=*/ true, firstCallArgs[1]); - assertEquals(TABLES[1]!.uuid, secondCallArgs[0]); - assertEquals( - /*inNewTab=*/ true, secondCallArgs[1]); + 1, + productSpecsProxy.getCallCount( + 'showProductSpecificationsSetsForUuids')); + const args = productSpecsProxy.getArgs( + 'showProductSpecificationsSetsForUuids')[0]; + assertArrayEquals([TABLES[0]!.uuid, TABLES[1]!.uuid], args[0]); + assertEquals(ShowSetDisposition.kInNewWindow, args[1]); }); test('can delete multiple comparison tables', async () => {
diff --git a/chrome/test/data/webui/commerce/product_specifications/new_column_selector_test.ts b/chrome/test/data/webui/commerce/product_specifications/new_column_selector_test.ts index 59cc5f5..261eec8 100644 --- a/chrome/test/data/webui/commerce/product_specifications/new_column_selector_test.ts +++ b/chrome/test/data/webui/commerce/product_specifications/new_column_selector_test.ts
@@ -14,6 +14,7 @@ suite('NewColumnSelectorTest', () => { const shoppingServiceApi = TestMock.fromClass(ShoppingServiceBrowserProxyImpl); + const SHOWING_MENU_CLASS = 'showing-menu'; async function createSelector(): Promise<NewColumnSelectorElement> { const selector = document.createElement('new-column-selector'); @@ -47,35 +48,33 @@ test('menu shown on enter', async () => { initUrlInfos(); const selector = await createSelector(); - const showingMenuClass = 'showing-menu'; const menu = selector.$.productSelectionMenu; assertEquals(menu.$.menu.getIfExists(), null); - assertFalse(selector.$.button.classList.contains(showingMenuClass)); + assertFalse(selector.$.button.classList.contains(SHOWING_MENU_CLASS)); selector.$.button.dispatchEvent( new KeyboardEvent('keydown', {key: 'Enter'})); await microtasksFinished(); assertNotEquals(menu.$.menu.getIfExists(), null); - assertTrue(selector.$.button.classList.contains(showingMenuClass)); + assertTrue(selector.$.button.classList.contains(SHOWING_MENU_CLASS)); }); test('updates showing menu class', async () => { initUrlInfos(); const selector = await createSelector(); - const showingMenuClass = 'showing-menu'; - assertFalse(selector.$.button.classList.contains(showingMenuClass)); + assertFalse(selector.$.button.classList.contains(SHOWING_MENU_CLASS)); selector.$.button.click(); await microtasksFinished(); - assertTrue(selector.$.button.classList.contains(showingMenuClass)); + assertTrue(selector.$.button.classList.contains(SHOWING_MENU_CLASS)); selector.$.productSelectionMenu.close(); await eventToPromise('close', selector.$.productSelectionMenu); - assertFalse(selector.$.button.classList.contains(showingMenuClass)); + assertFalse(selector.$.button.classList.contains(SHOWING_MENU_CLASS)); }); });
diff --git a/chrome/test/data/webui/commerce/product_specifications/test_product_specifications_browser_proxy.ts b/chrome/test/data/webui/commerce/product_specifications/test_product_specifications_browser_proxy.ts index f3adc21..191b7b3 100644 --- a/chrome/test/data/webui/commerce/product_specifications/test_product_specifications_browser_proxy.ts +++ b/chrome/test/data/webui/commerce/product_specifications/test_product_specifications_browser_proxy.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. import {PageCallbackRouter} from '//resources/cr_components/commerce/product_specifications.mojom-webui.js'; -import type {DisclosureVersion, PageRemote} from '//resources/cr_components/commerce/product_specifications.mojom-webui.js'; +import type {DisclosureVersion, PageRemote, ShowSetDisposition} from '//resources/cr_components/commerce/product_specifications.mojom-webui.js'; import type {ProductSpecificationsBrowserProxy} from '//resources/cr_components/commerce/product_specifications_browser_proxy.js'; import type {Uuid} from '//resources/mojo/mojo/public/mojom/base/uuid.mojom-webui.js'; import type {Url} from '//resources/mojo/url/mojom/url.mojom-webui.js'; @@ -17,6 +17,7 @@ constructor() { super([ 'showProductSpecificationsSetForUuid', + 'showProductSpecificationsSetsForUuids', 'showComparePage', 'setAcceptedDisclosureVersion', 'maybeShowDisclosure', @@ -44,6 +45,12 @@ this.methodCalled('showProductSpecificationsSetForUuid', uuid, inNewTab); } + showProductSpecificationsSetsForUuids( + uuids: Uuid[], disposition: ShowSetDisposition): void { + this.methodCalled( + 'showProductSpecificationsSetsForUuids', uuids, disposition); + } + showComparePage(inNewTab: boolean): void { this.methodCalled('showComparePage', inNewTab); }
diff --git a/chrome/test/data/webui/cr_components/chromeos/BUILD.gn b/chrome/test/data/webui/cr_components/chromeos/BUILD.gn index 4f01106..63d42d8 100644 --- a/chrome/test/data/webui/cr_components/chromeos/BUILD.gn +++ b/chrome/test/data/webui/cr_components/chromeos/BUILD.gn
@@ -46,7 +46,7 @@ "cellular_setup/provisioning_page_test.ts", "cellular_setup/psim_flow_ui_test.ts", "cellular_setup/setup_loading_page_test.ts", - "network/apn_list_item_test.js", + "network/apn_list_item_test.ts", "network/apn_list_test.ts", "network/apn_selection_dialog_test.js", "network/apn_selection_dialog_list_item_test.js",
diff --git a/chrome/test/data/webui/glic/BUILD.gn b/chrome/test/data/webui/glic/BUILD.gn index 46c45ec2..00ea75e 100644 --- a/chrome/test/data/webui/glic/BUILD.gn +++ b/chrome/test/data/webui/glic/BUILD.gn
@@ -16,8 +16,15 @@ ts_library("build_ts") { out_dir = out_dir - in_files = [ "api_test.ts" ] - deps = [ "//chrome/browser/resources/glic:build_ts" ] + in_files = [ + "api_test.ts", + "api_boot.ts", + "test_client/test_client.ts", + ] + deps = [ + "//chrome/browser/resources/glic:build_ts", + "//ui/webui/resources/js:build_ts", + ] path_mappings = [ "chrome://glic/*|" + rebase_path( "$root_gen_dir/chrome/browser/resources/glic/tsc/*", @@ -25,6 +32,9 @@ } preprocess_if_expr("move_html") { - in_files = [ "test.html" ] + in_files = [ + "test.html", + "test_client/index.html", + ] out_folder = out_dir }
diff --git a/chrome/test/data/webui/glic/api_boot.ts b/chrome/test/data/webui/glic/api_boot.ts new file mode 100644 index 0000000..e9732af --- /dev/null +++ b/chrome/test/data/webui/glic/api_boot.ts
@@ -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. + +import type {GlicApiBootMessage, GlicHostRegistry, WithGlicApi} from 'chrome://glic/glic_api/glic_api.js'; + +// Note: Although the actual glic client does something similar, this code is +// test-only. + +/** + * Creates a GlicHostRegistry by loading the glic API script from Chrome and + * calling the `internalAutoGlicBoot` function. This should be called on or + * before page load. The returned promise never resolves if a message from + * Chrome is not received. + */ +export function createGlicHostRegistryOnLoad(): Promise<GlicHostRegistry> { + return new Promise<GlicHostRegistry>(resolve => { + function messageHandler(event: MessageEvent) { + // Important: only accept messages from Chrome browser's glic WebUI. + if (event.origin !== 'chrome://glic' || event.source === null) { + return; + } + const bootMessage = event.data as GlicApiBootMessage; + if (bootMessage?.type === 'glic-bootstrap' && bootMessage.glicApiSource) { + window.removeEventListener('message', messageHandler); + const glicApiSource = bootMessage.glicApiSource; + const scriptElement = document.createElement('script'); + scriptElement.textContent = glicApiSource; + document.head.appendChild(scriptElement); + const bootFunc = (window as WithGlicApi).internalAutoGlicBoot; + if (!bootFunc) { + throw new Error('Glic client import failed.'); + } + resolve(bootFunc(event.source as WindowProxy)); + } + } + window.addEventListener('message', messageHandler); + }); +}
diff --git a/chrome/test/data/webui/glic/api_test.ts b/chrome/test/data/webui/glic/api_test.ts index e6b0bc3..28035ca 100644 --- a/chrome/test/data/webui/glic/api_test.ts +++ b/chrome/test/data/webui/glic/api_test.ts
@@ -6,33 +6,9 @@ // ash/webui/personalization_app/tools/gen_tsconfig.py --root_out_dir out/pc \ // --gn_target chrome/test/data/webui/glic:build_ts -import type {GlicApiBootMessage, GlicBrowserHost, GlicHostRegistry, GlicWebClient, PanelState, WithGlicApi} from 'chrome://glic/glic_api/glic_api.js'; +import type {GlicBrowserHost, GlicWebClient, PanelState} from 'chrome://glic/glic_api/glic_api.js'; -// Glic API bootstrap code. -function createGlicHostRegistryOnLoad(): Promise<GlicHostRegistry> { - return new Promise<GlicHostRegistry>(resolve => { - function messageHandler(event: MessageEvent) { - // Important: only accept messages from Chrome browser's glic WebUI. - if (event.origin !== 'chrome://glic' || event.source === null) { - return; - } - const bootMessage = event.data as GlicApiBootMessage; - if (bootMessage?.type === 'glic-bootstrap' && bootMessage.glicApiSource) { - window.removeEventListener('message', messageHandler); - const glicApiSource = bootMessage.glicApiSource; - const scriptElement = document.createElement('script'); - scriptElement.textContent = glicApiSource; - document.head.appendChild(scriptElement); - const bootFunc = (window as WithGlicApi).internalAutoGlicBoot; - if (!bootFunc) { - throw new Error('Glic client import failed.'); - } - resolve(bootFunc(event.source as WindowProxy)); - } - } - window.addEventListener('message', messageHandler); - }); -} +import {createGlicHostRegistryOnLoad} from './api_boot.js'; // A dummy web client. class WebClient implements GlicWebClient {
diff --git a/chrome/test/data/webui/glic/test_client/README.md b/chrome/test/data/webui/glic/test_client/README.md new file mode 100644 index 0000000..0a928e52 --- /dev/null +++ b/chrome/test/data/webui/glic/test_client/README.md
@@ -0,0 +1,20 @@ +# Glic test client + +This is a test page that facilitates testing the API between the host and the web client. + + +## Instructions + +1. Build it + +```bash + autoninja -C out/Default chrome/test/data/webui/glic:generate_test_files +``` + +2. Serve it + +```bash + python3 -m http.server -d out/Default/gen/chrome/test/data/webui/glic +``` + +3. Run Chrome with `--glic-guest-url=http://localhost:8000/glic/test_client/index.html`
diff --git a/chrome/test/data/webui/glic/test_client/index.html b/chrome/test/data/webui/glic/test_client/index.html new file mode 100644 index 0000000..d1f4c91 --- /dev/null +++ b/chrome/test/data/webui/glic/test_client/index.html
@@ -0,0 +1,171 @@ +<!-- +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. +--> +<!doctype html> +<meta charset="utf-8" /> + +<style> + #pageHeader.connected { + background-color: green; + } + #pageHeader { + background-color: blue; + color: white; + display: flex; + justify-content: space-between; + } + .section h1 { + text-align: center; + margin: 0.2em; + font-size: 15pt; + } + .section { + background-color: #eee; + box-shadow: 0 0 0.5em #999; + border: 1px solid black; + padding: 3px; + margin-top: 0.5em; + margin-bottom: 0.5em; + } + body { + background-color: white; + } + .permission-switch { + display: flex; + align-items: center; + margin-bottom: 0.5em; + } + .permission-switch label { + margin-right: 0.5em; + } + input[type="text"] { + width: 400px; + } + img { + border: thick double black; + background-image: linear-gradient(cyan, fuchsia); + } +</style> +<div id="pageHeader"> + <h2>Test Web Client</h2> + <button id="refreshbn">🔄</button> + <button id="closebn">❌</button> +</div> + +<div class="section"> + <h1>Test SetPermissionState() and NotifyPermissionChanged()</h1> + <div class="permission-switches"> + <div class="permission-switch"> + <label for="microphoneSwitch">Microphone:</label> + <input type="checkbox" id="microphoneSwitch" disabled /> + </div> + <div class="permission-switch"> + <label for="geolocationSwitch">Geolocation:</label> + <input type="checkbox" id="geolocationSwitch" disabled /> + </div> + <div class="permission-switch"> + <label for="tabContextSwitch">Tab Context:</label> + <input type="checkbox" id="tabContextSwitch" disabled /> + </div> + </div> + <div> + <select id="permissionSelect"> + <option value="microphone">Microphone</option> + <option value="geolocation">Geolocation</option> + <option value="tab_context">Tab Context</option> + </select> + <select id="enabledSelect"> + <option value="true">True</option> + <option value="false">False</option> + </select> + <button id="testPermissionSwitch">Simulate External Permission + Update</button> + </div> +</div> +<div class="section"> + <h1>Focused Tab</h1> + <label>Focused Tab Url: </label><input id="focusedUrl" type="text" /> <br /> + <label>Favicon: </label><img id="focusedFavicon" /> +</div> +<div class="section"> + <h1>Test createTab()</h1> + <label>Url</label><input id="URL" type="text" + value="https://news.ycombinator.com" /> + <br /> + <button id="newtabbn">Open New Tab!</button> + <br /> +</div> +<div class="section"> + <h1>Test Panel Controls</h1> + <button id="attachpanelbn">Attach Panel</button> + <br /> + <button id="detachpanelbn">Detach Panel</button> + <br /> +</div> +<div class="section"> + <h1>Test getContextFromFocusedTab()</h1> + <div> + <button id="getpagecontext">Get page Context</button> + <label> <input type="checkbox" id="innerTextCheckbox" /> Inner Text </label> + <label> <input type="checkbox" + id="viewportScreenshotCheckbox" /> Viewport Screenshot </label> + <img id="faviconImg" /> + </div> + <div id="screenshot"> + <img /> + </div> +</div> +<div class="section"> + <h1>Test Location Access</h1> + <button id="getlocation">Get Location</button> <br /> + <div id="location"></div> +</div> +<div class="section"> + <h1>Test Link Out Behavior</h1> + <a href="https://www.example.com" id="link" target="_blank" + rel="noopener noreferrer" + >https://www.example.com + </a> +</div> +<div class="section"> + <h1>UserProfile</h1> + <div> + <button id="getUserProfileInfoBn">getUserProfileInfo()</button> Status: + <span id="getUserProfileInfoStatus"></span> + <img id="getUserProfileInfoImg" /> + </div> + <div> + <button id="changeProfileBn">changeProfile()</button> + </div> +</div> +<div class="section"> + <h1>Misc</h1> + <button id="syncCookiesBn">refreshSignInCookies()</button> Status: + <span id="syncCookieStatus"></span> +</div> +<div class="section"> + <h1>Demo Test Utils</h1> + <button id="reloadpage">Reload page</button> + <div> + Navigate webview to <input id="navigateWebviewUrl" type="text" + value="https://www.google.com" /> + </div> +</div> +<div class="section"> + <h1>Audio Capture</h1> + <button id="audioCapStart">START</button> + <button id="audioCapStop">STOP</button> + + After pressing STOP, this will play recorded sound. + <br /> + <audio id="mic" controls></audio><br /> + <div></div> + <div id="audioStatus"></div> +</div> +<br /> +<div id="status"></div> + +<script src="./test_client.js" type="module"> +</script>
diff --git a/chrome/test/data/webui/glic/test_client/test_client.ts b/chrome/test/data/webui/glic/test_client/test_client.ts new file mode 100644 index 0000000..539db7c --- /dev/null +++ b/chrome/test/data/webui/glic/test_client/test_client.ts
@@ -0,0 +1,309 @@ +// 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 type {GlicBrowserHost, GlicWebClient, TabData} from 'chrome://glic/glic_api/glic_api.js'; + +import {createGlicHostRegistryOnLoad} from '../api_boot.js'; + +interface PageElementTypes { + status: HTMLDivElement; + pageHeader: HTMLDivElement; + focusedFavicon: HTMLImageElement; + focusedUrl: HTMLInputElement; + syncCookiesBn: HTMLButtonElement; + syncCookieStatus: HTMLSpanElement; + getUserProfileInfoBn: HTMLButtonElement; + getUserProfileInfoStatus: HTMLSpanElement; + getUserProfileInfoImg: HTMLImageElement; + changeProfileBn: HTMLButtonElement; + testPermissionSwitch: HTMLButtonElement; + microphoneSwitch: HTMLInputElement; + geolocationSwitch: HTMLInputElement; + tabContextSwitch: HTMLInputElement; + newtabbn: HTMLButtonElement; + reloadpage: HTMLButtonElement; + getpagecontext: HTMLButtonElement; + URL: HTMLInputElement; + innerTextCheckbox: HTMLInputElement; + viewportScreenshotCheckbox: HTMLInputElement; + screenshotImg: HTMLImageElement; + faviconImg: HTMLImageElement; + getlocation: HTMLButtonElement; + location: HTMLDivElement; + permissionSelect: HTMLSelectElement; + enabledSelect: HTMLSelectElement; + closebn: HTMLButtonElement; + attachpanelbn: HTMLButtonElement; + detachpanelbn: HTMLButtonElement; + refreshbn: HTMLButtonElement; + navigateWebviewUrl: HTMLInputElement; + audioCapStop: HTMLButtonElement; + audioCapStart: HTMLButtonElement; + audioStatus: HTMLDivElement; + mic: HTMLAudioElement; +} + +const $: PageElementTypes = new Proxy({}, { + get(_target: any, prop: string) { + return document.getElementById(prop); + }, +}); + +function logMessage(message: string) { + $.status.append(message.slice(0, 100000), document.createElement('br')); +} + +class WebClient implements GlicWebClient { + browser: GlicBrowserHost|undefined; + + async initialize(browser: GlicBrowserHost): Promise<void> { + this.browser = browser; + logMessage('initialize called'); + $.pageHeader!.classList.add('connected'); + + const ver = await browser.getChromeVersion(); + logMessage(`Chrome version: ${JSON.stringify(ver)}`); + + const focusedTabState = await this.browser.getFocusedTabState!(); + focusedTabChanged(focusedTabState.getValue()); + focusedTabState.subscribe(focusedTabChanged); + } + + async notifyPanelClosed() { + logMessage('notifyPanelClosed called'); + } +} + +const client = new WebClient(); + +function getBrowser(): GlicBrowserHost|undefined { + return client?.browser; +} + +async function focusedTabChanged(newValue: TabData|undefined) { + $.focusedUrl.value = ''; + $.focusedFavicon.src = ''; + logMessage(`Focused Tab State Changed: ${JSON.stringify(newValue)}`); + if (newValue?.url) { + $.focusedUrl.value = newValue.url; + } + if (newValue?.favicon) { + const fav = await newValue.favicon(); + if (fav) { + $.focusedFavicon.src = URL.createObjectURL(fav); + } + } +} + +createGlicHostRegistryOnLoad().then((registry) => { + logMessage('registring web client'); + registry.registerWebClient(client); +}); + +type PermissionSwitchName = 'microphone'|'geolocation'|'tabContext'; +const permissionSwitches: Record<PermissionSwitchName, HTMLInputElement> = { + microphone: $.microphoneSwitch, + geolocation: $.geolocationSwitch, + tabContext: $.tabContextSwitch, +}; + +function updatePermissionSwitch( + permissionSwitchName: PermissionSwitchName, enabled: boolean, + sendToBackend = true) { + logMessage( + `Setting permission ${permissionSwitchName} to ${enabled} and ${ + sendToBackend ? '' : 'not'} sending to backend.`, + ); + if (!permissionSwitches[permissionSwitchName]) { + console.error('Permission switch not found: ' + permissionSwitchName); + return; + } + permissionSwitches[permissionSwitchName].checked = enabled; +} + +$.syncCookiesBn.addEventListener('click', async () => { + $.syncCookieStatus!.innerText = 'Requesting'; + try { + await getBrowser()!.refreshSignInCookies!(); + $.syncCookieStatus!.innerText = `Done!`; + } catch (e) { + $.syncCookieStatus!.innerText = `Caught error: ${e}`; + } +}); + +$.getUserProfileInfoBn.addEventListener('click', async () => { + $.getUserProfileInfoStatus.innerText = 'Requesting'; + try { + const profile = await getBrowser()!.getUserProfileInfo!(); + $.getUserProfileInfoStatus.innerText = `Done: ${JSON.stringify(profile)}`; + const icon = await profile.avatarIcon(); + if (icon) { + $.getUserProfileInfoImg.src = URL.createObjectURL(icon); + } + } catch (e) { + $.getUserProfileInfoStatus.innerText = `Caught error: ${e}`; + } +}); + +$.changeProfileBn.addEventListener('click', () => { + getBrowser()!.showProfilePicker!(); +}); + +// Listen for switch changes by user in webclient: +for (const key of Object.keys(permissionSwitches) as PermissionSwitchName[]) { + const element = permissionSwitches[key]; + element.addEventListener('change', () => { + updatePermissionSwitch(key, element.checked); + }); +} + +// Add listeners to demo elements: +$.newtabbn.addEventListener('click', async () => { + const url = $.URL.value; + await getBrowser()!.createTab!(url, {}); + logMessage('createTab done'); +}); + +$.reloadpage.addEventListener('click', () => { + location.reload(); +}); + +$.getpagecontext.addEventListener('click', async () => { + logMessage('Starting Get Page Context'); + const options: any = {}; + if ($.innerTextCheckbox.checked) { + options.innerText = true; + } + if ($.viewportScreenshotCheckbox.checked) { + options.viewportScreenshot = {}; + } + try { + const pageContent = + await client!.browser!.getContextFromFocusedTab!(options); + if (pageContent.viewportScreenshot) { + const blob = + new Blob([pageContent.viewportScreenshot.data], {type: 'image/jpeg'}); + $.screenshotImg.src = URL.createObjectURL(blob); + } + if (pageContent.tabData.favicon) { + const favicon = await pageContent.tabData.favicon(); + if (favicon) { + $.faviconImg.src = URL.createObjectURL(favicon); + } + } + logMessage( + `Finished Get Page Context. Returned data: ${ + JSON.stringify(pageContent, null, 2)}`, + ); + } catch (error) { + logMessage(`Error getting page context: ${error}`); + } +}); +$.getlocation.addEventListener('click', async () => { + logMessage('Requesting geolocation...'); + + if (navigator.geolocation) { + try { + const position = + await new Promise<GeolocationPosition>((resolve, reject) => { + navigator.geolocation.getCurrentPosition(resolve, reject); + }); + + const latitude = position.coords.latitude; + const longitude = position.coords.longitude; + const accuracy = position.coords.accuracy; + + $.location.innerHTML = ` + Latitude: ${latitude}<br> + Longitude: ${longitude}<br> + Accuracy: ${accuracy} meters + `; + logMessage( + `Geolocation obtained: Latitude ${latitude}, Longitude ${longitude}`); + } catch (error) { + if (error instanceof Error) { + logMessage(`Error getting geolocation: ${error.message}`); + $.location.innerHTML = `Error: ${error.message}`; + } + } + } else { + logMessage('Geolocation is not supported by this browser.'); + $.location.innerHTML = 'Geolocation is not supported by this browser.'; + } +}); +$.testPermissionSwitch.addEventListener('click', () => { + const selectedPermission = $.permissionSelect.value; + const isEnabled = $.enabledSelect.value === 'true'; + updatePermissionSwitch(selectedPermission as any, isEnabled, false); +}); + +$.closebn.addEventListener('click', () => { + getBrowser()!.closePanel!(); +}); +$.attachpanelbn.addEventListener('click', () => { + getBrowser()!.attachPanel!(); +}); +$.detachpanelbn.addEventListener('click', () => { + getBrowser()!.detachPanel!(); +}); +$.refreshbn.addEventListener('click', () => { + location.reload(); +}); +$.navigateWebviewUrl.addEventListener('keyup', ({key}) => { + if (key === 'Enter') { + window.location.href = $.navigateWebviewUrl.value; + } +}); + + +class AudioCapture { + recordedData: Blob[] = []; + recorder: MediaRecorder|undefined; + constructor() {} + + async start() { + if (this.recorder) { + return; + } + const stream = await navigator.mediaDevices.getUserMedia({audio: true}); + + $.audioStatus.replaceChildren('Recording...'); + this.recorder = new MediaRecorder(stream, {mimeType: 'audio/webm'}); + let stopped = false; + window.setInterval(() => { + if (!stopped) { + this.recorder!.requestData(); + } + }, 100); + this.recorder.addEventListener('dataavailable', (event: BlobEvent) => { + this.recordedData.push(event.data); + }); + this.recorder.addEventListener('stop', () => { + stopped = true; + $.audioStatus.replaceChildren('Playback...'); + const blob = new Blob(this.recordedData, {type: 'audio/webm'}); + $.mic.src = URL.createObjectURL(blob); + }); + this.recorder.start(); + } + + stop() { + if (!this.recorder) { + return; + } + $.mic.play(); + this.recorder.stop(); + this.recorder = undefined; + } +} +const audioCapture = new AudioCapture(); + +window.addEventListener('load', () => { + $.audioCapStop.addEventListener('click', () => { + audioCapture.stop(); + }); + $.audioCapStart.addEventListener('click', () => { + audioCapture.start(); + }); +});
diff --git a/chrome/updater/constants.h b/chrome/updater/constants.h index 5381390..ae94859 100644 --- a/chrome/updater/constants.h +++ b/chrome/updater/constants.h
@@ -270,7 +270,12 @@ "server_keep_alive"; inline constexpr char kDevOverrideKeyCrxVerifierFormat[] = "crx_verifier_format"; +inline constexpr char kDevOverrideKeyDictPolicies[] = "dict_policies"; + +// TODO(crbug.com/389965546): remove this once the checked-in old updater builds +// recognize "dict_policies". inline constexpr char kDevOverrideKeyGroupPolicies[] = "group_policies"; + inline constexpr char kDevOverrideKeyOverinstallTimeout[] = "overinstall_timeout"; inline constexpr char kDevOverrideKeyIdleCheckPeriodSeconds[] = @@ -571,16 +576,30 @@ inline constexpr bool kInstallPolicyDefault = kPolicyEnabled; inline constexpr bool kUpdatePolicyDefault = kPolicyEnabled; -// Policy manager `source()` constants. +// Policy manager constants. inline constexpr char kSourceDMPolicyManager[] = "Device Management"; inline constexpr char kSourceDefaultValuesPolicyManager[] = "Default"; inline constexpr char kSourceDictValuesPolicyManager[] = "DictValuePolicy"; #if BUILDFLAG(IS_WIN) +inline constexpr bool kPlatformPolicyManagerDefined = true; inline constexpr char kSourcePlatformPolicyManager[] = "Group Policy"; + +// On Windows, by default, Group Policy has a higher priority than the +// clould policy. +inline constexpr bool kCloudPolicyOverridesPlatformPolicyDefaultValue = false; #elif BUILDFLAG(IS_MAC) +inline constexpr bool kPlatformPolicyManagerDefined = true; inline constexpr char kSourcePlatformPolicyManager[] = "Managed Preferences"; + +// On macOS, cloud policy has a higher priority than the Managed Preferences. +inline constexpr bool kCloudPolicyOverridesPlatformPolicyDefaultValue = true; #else +inline constexpr bool kPlatformPolicyManagerDefined = false; inline constexpr char kSourcePlatformPolicyManager[] = "not-defined"; + +// On other platforms, there's no platform policy at the moment, the value +// doesn't actually matter. +inline constexpr bool kCloudPolicyOverridesPlatformPolicyDefaultValue = true; #endif // Serializes updater installs. Defined in the .cc file so that the updater
diff --git a/chrome/updater/external_constants.h b/chrome/updater/external_constants.h index 2846fe60d..efd6dfd 100644 --- a/chrome/updater/external_constants.h +++ b/chrome/updater/external_constants.h
@@ -58,8 +58,8 @@ // CRX format verification requirements. virtual crx_file::VerifierFormat CrxVerifierFormat() const = 0; - // Overrides for the `GroupPolicyManager`. - virtual base::Value::Dict GroupPolicies() const = 0; + // Policies for the `PolicyManager` surfaced by external constants. + virtual base::Value::Dict DictPolicies() const = 0; // Overrides the overinstall timeout. virtual base::TimeDelta OverinstallTimeout() const = 0;
diff --git a/chrome/updater/external_constants_builder.cc b/chrome/updater/external_constants_builder.cc index 7683a44b..2f376e6 100644 --- a/chrome/updater/external_constants_builder.cc +++ b/chrome/updater/external_constants_builder.cc
@@ -143,13 +143,15 @@ return *this; } -ExternalConstantsBuilder& ExternalConstantsBuilder::SetGroupPolicies( - const base::Value::Dict& group_policies) { - overrides_.Set(kDevOverrideKeyGroupPolicies, group_policies.Clone()); +ExternalConstantsBuilder& ExternalConstantsBuilder::SetDictPolicies( + const base::Value::Dict& dict_policies) { + overrides_.Set(kDevOverrideKeyDictPolicies, dict_policies.Clone()); + overrides_.Set(kDevOverrideKeyGroupPolicies, dict_policies.Clone()); return *this; } -ExternalConstantsBuilder& ExternalConstantsBuilder::ClearGroupPolicies() { +ExternalConstantsBuilder& ExternalConstantsBuilder::ClearDictPolicies() { + overrides_.Remove(kDevOverrideKeyDictPolicies); overrides_.Remove(kDevOverrideKeyGroupPolicies); return *this; } @@ -266,8 +268,8 @@ if (!overrides_.contains(kDevOverrideKeyCrxVerifierFormat)) { SetCrxVerifierFormat(verifier->CrxVerifierFormat()); } - if (!overrides_.contains(kDevOverrideKeyGroupPolicies)) { - SetGroupPolicies(verifier->GroupPolicies()); + if (!overrides_.contains(kDevOverrideKeyDictPolicies)) { + SetDictPolicies(verifier->DictPolicies()); } if (!overrides_.contains(kDevOverrideKeyOverinstallTimeout)) { SetOverinstallTimeout(verifier->OverinstallTimeout());
diff --git a/chrome/updater/external_constants_builder.h b/chrome/updater/external_constants_builder.h index d868278..a00657d 100644 --- a/chrome/updater/external_constants_builder.h +++ b/chrome/updater/external_constants_builder.h
@@ -65,9 +65,9 @@ crx_file::VerifierFormat crx_verifier_format); ExternalConstantsBuilder& ClearCrxVerifierFormat(); - ExternalConstantsBuilder& SetGroupPolicies( - const base::Value::Dict& group_policies); - ExternalConstantsBuilder& ClearGroupPolicies(); + ExternalConstantsBuilder& SetDictPolicies( + const base::Value::Dict& dict_policies); + ExternalConstantsBuilder& ClearDictPolicies(); ExternalConstantsBuilder& SetOverinstallTimeout( base::TimeDelta overinstall_timeout);
diff --git a/chrome/updater/external_constants_builder_unittest.cc b/chrome/updater/external_constants_builder_unittest.cc index fdb31e9..2e80766 100644 --- a/chrome/updater/external_constants_builder_unittest.cc +++ b/chrome/updater/external_constants_builder_unittest.cc
@@ -58,13 +58,13 @@ EXPECT_EQ(verifier->InitialDelay(), kInitialDelay); EXPECT_EQ(verifier->ServerKeepAliveTime(), kServerKeepAliveTime); - EXPECT_EQ(verifier->GroupPolicies().size(), 0U); + EXPECT_EQ(verifier->DictPolicies().size(), 0U); } TEST_F(ExternalConstantsBuilderTests, TestOverridingEverything) { - base::Value::Dict group_policies; - group_policies.Set("a", 1); - group_policies.Set("b", 2); + base::Value::Dict dict_policies; + dict_policies.Set("a", 1); + dict_policies.Set("b", 2); ExternalConstantsBuilder builder; builder.SetUpdateURL(std::vector<std::string>{"https://www.example.com"}) @@ -74,7 +74,7 @@ .SetUseCUP(false) .SetInitialDelay(base::Seconds(123)) .SetServerKeepAliveTime(base::Seconds(2)) - .SetGroupPolicies(group_policies) + .SetDictPolicies(dict_policies) .SetOverinstallTimeout(base::Seconds(3)) .SetIdleCheckPeriod(base::Seconds(4)) .SetMachineManaged(std::make_optional(true)) @@ -97,7 +97,7 @@ EXPECT_EQ(verifier->AppLogoURL(), GURL("https://applogo.example.com/")); EXPECT_EQ(verifier->InitialDelay(), base::Seconds(123)); EXPECT_EQ(verifier->ServerKeepAliveTime(), base::Seconds(2)); - EXPECT_EQ(verifier->GroupPolicies().size(), 2U); + EXPECT_EQ(verifier->DictPolicies().size(), 2U); EXPECT_EQ(verifier->OverinstallTimeout(), base::Seconds(3)); EXPECT_EQ(verifier->IdleCheckPeriod(), base::Seconds(4)); EXPECT_TRUE(verifier->IsMachineManaged().has_value()); @@ -130,7 +130,7 @@ EXPECT_EQ(verifier->AppLogoURL(), GURL(APP_LOGO_URL)); EXPECT_EQ(verifier->InitialDelay(), kInitialDelay); EXPECT_EQ(verifier->ServerKeepAliveTime(), kServerKeepAliveTime); - EXPECT_EQ(verifier->GroupPolicies().size(), 0U); + EXPECT_EQ(verifier->DictPolicies().size(), 0U); } TEST_F(ExternalConstantsBuilderTests, TestClearedEverything) { @@ -151,7 +151,7 @@ .ClearUseCUP() .ClearInitialDelay() .ClearServerKeepAliveSeconds() - .ClearGroupPolicies() + .ClearDictPolicies() .ClearOverinstallTimeout() .ClearIdleCheckPeriod() .ClearMachineManaged() @@ -174,15 +174,15 @@ EXPECT_EQ(verifier->AppLogoURL(), GURL(APP_LOGO_URL)); EXPECT_EQ(verifier->InitialDelay(), kInitialDelay); EXPECT_EQ(verifier->ServerKeepAliveTime(), kServerKeepAliveTime); - EXPECT_EQ(verifier->GroupPolicies().size(), 0U); + EXPECT_EQ(verifier->DictPolicies().size(), 0U); EXPECT_FALSE(verifier->IsMachineManaged().has_value()); EXPECT_FALSE(verifier->EnableDiffUpdates()); EXPECT_EQ(verifier->CecaConnectionTimeout(), kCecaConnectionTimeout); } TEST_F(ExternalConstantsBuilderTests, TestOverSet) { - base::Value::Dict group_policies; - group_policies.Set("a", 1); + base::Value::Dict dict_policies; + dict_policies.Set("a", 1); EXPECT_TRUE( ExternalConstantsBuilder() @@ -194,7 +194,7 @@ .SetInitialDelay(base::Seconds(123.4)) .SetServerKeepAliveTime(base::Seconds(2)) .SetMachineManaged(std::make_optional(true)) - .SetGroupPolicies(group_policies) + .SetDictPolicies(dict_policies) .SetEnableDiffUpdates(false) .SetUpdateURL(std::vector<std::string>{"https://www.example.com"}) .SetCrashUploadURL("https://crash.example.com") @@ -223,7 +223,7 @@ EXPECT_EQ(verifier->AppLogoURL(), GURL("https://applogo.example.com/")); EXPECT_EQ(verifier->InitialDelay(), base::Seconds(937.6)); EXPECT_EQ(verifier->ServerKeepAliveTime(), base::Seconds(3)); - EXPECT_EQ(verifier->GroupPolicies().size(), 1U); + EXPECT_EQ(verifier->DictPolicies().size(), 1U); EXPECT_TRUE(verifier->IsMachineManaged().has_value()); EXPECT_FALSE(verifier->IsMachineManaged().value()); EXPECT_TRUE(verifier->EnableDiffUpdates()); @@ -233,9 +233,9 @@ TEST_F(ExternalConstantsBuilderTests, TestReuseBuilder) { ExternalConstantsBuilder builder; - base::Value::Dict group_policies; - group_policies.Set("a", 1); - group_policies.Set("b", 2); + base::Value::Dict dict_policies; + dict_policies.Set("a", 1); + dict_policies.Set("b", 2); EXPECT_TRUE( builder.SetUpdateURL(std::vector<std::string>{"https://www.google.com"}) @@ -246,7 +246,7 @@ .SetInitialDelay(base::Seconds(123.4)) .SetServerKeepAliveTime(base::Seconds(3)) .SetUpdateURL(std::vector<std::string>{"https://www.example.com"}) - .SetGroupPolicies(group_policies) + .SetDictPolicies(dict_policies) .SetMachineManaged(std::make_optional(true)) .SetEnableDiffUpdates(true) .SetCecaConnectionTimeout(base::Seconds(5)) @@ -267,14 +267,14 @@ EXPECT_EQ(verifier->AppLogoURL(), GURL("https://applogo.google.com/")); EXPECT_EQ(verifier->InitialDelay(), base::Seconds(123.4)); EXPECT_EQ(verifier->ServerKeepAliveTime(), base::Seconds(3)); - EXPECT_EQ(verifier->GroupPolicies().size(), 2U); + EXPECT_EQ(verifier->DictPolicies().size(), 2U); EXPECT_TRUE(verifier->IsMachineManaged().has_value()); EXPECT_TRUE(verifier->IsMachineManaged().value()); EXPECT_TRUE(verifier->EnableDiffUpdates()); EXPECT_EQ(verifier->CecaConnectionTimeout(), base::Seconds(5)); - base::Value::Dict group_policies2; - group_policies2.Set("b", 2); + base::Value::Dict dict_policies2; + dict_policies2.Set("b", 2); // But now we can use the builder again: EXPECT_TRUE(builder.SetInitialDelay(base::Seconds(92.3)) @@ -283,7 +283,7 @@ .ClearCrashUploadURL() .ClearDeviceManagementURL() .ClearAppLogoURL() - .SetGroupPolicies(group_policies2) + .SetDictPolicies(dict_policies2) .ClearMachineManaged() .SetEnableDiffUpdates(false) .ClearCecaConnectionTimeout() @@ -307,7 +307,7 @@ EXPECT_EQ(verifier2->InitialDelay(), base::Seconds(92.3)); // Updated; update should be seen. EXPECT_EQ(verifier2->ServerKeepAliveTime(), base::Seconds(4)); - EXPECT_EQ(verifier2->GroupPolicies().size(), 1U); + EXPECT_EQ(verifier2->DictPolicies().size(), 1U); EXPECT_FALSE(verifier2->IsMachineManaged().has_value()); EXPECT_FALSE(verifier2->EnableDiffUpdates()); EXPECT_EQ(verifier2->CecaConnectionTimeout(), kCecaConnectionTimeout); @@ -316,9 +316,9 @@ TEST_F(ExternalConstantsBuilderTests, TestModify) { ExternalConstantsBuilder builder; - base::Value::Dict group_policies; - group_policies.Set("a", 1); - group_policies.Set("b", 2); + base::Value::Dict dict_policies; + dict_policies.Set("a", 1); + dict_policies.Set("b", 2); EXPECT_TRUE( builder.SetUpdateURL(std::vector<std::string>{"https://www.google.com"}) @@ -332,7 +332,7 @@ .SetCrashUploadURL("https://crash.example.com") .SetDeviceManagementURL("https://dm.example.com") .SetAppLogoURL("https://applogo.example.com/") - .SetGroupPolicies(group_policies) + .SetDictPolicies(dict_policies) .SetMachineManaged(std::make_optional(false)) .SetEnableDiffUpdates(true) .SetCecaConnectionTimeout(base::Seconds(55)) @@ -353,7 +353,7 @@ EXPECT_EQ(verifier->AppLogoURL(), GURL("https://applogo.example.com/")); EXPECT_EQ(verifier->InitialDelay(), base::Seconds(123.4)); EXPECT_EQ(verifier->ServerKeepAliveTime(), base::Seconds(3)); - EXPECT_EQ(verifier->GroupPolicies().size(), 2U); + EXPECT_EQ(verifier->DictPolicies().size(), 2U); EXPECT_TRUE(verifier->IsMachineManaged().has_value()); EXPECT_FALSE(verifier->IsMachineManaged().value()); EXPECT_TRUE(verifier->EnableDiffUpdates()); @@ -362,10 +362,10 @@ // Now we use a new builder to modify just the group policies. ExternalConstantsBuilder builder2; - base::Value::Dict group_policies2; - group_policies2.Set("b", 2); + base::Value::Dict dict_policies2; + dict_policies2.Set("b", 2); - EXPECT_TRUE(builder2.SetGroupPolicies(group_policies2).Modify()); + EXPECT_TRUE(builder2.SetDictPolicies(dict_policies2).Modify()); // We need a new overrider to verify because it only loads once. scoped_refptr<ExternalConstantsOverrider> verifier2 = @@ -373,7 +373,7 @@ CreateDefaultExternalConstants()); // Only the group policies are different. - EXPECT_EQ(verifier2->GroupPolicies().size(), 1U); + EXPECT_EQ(verifier2->DictPolicies().size(), 1U); // All the values below are unchanged. EXPECT_FALSE(verifier2->UseCUP());
diff --git a/chrome/updater/external_constants_default.cc b/chrome/updater/external_constants_default.cc index 3934b6a0..2bc49d9 100644 --- a/chrome/updater/external_constants_default.cc +++ b/chrome/updater/external_constants_default.cc
@@ -48,7 +48,7 @@ return crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF; } - base::Value::Dict GroupPolicies() const override { + base::Value::Dict DictPolicies() const override { return base::Value::Dict(); }
diff --git a/chrome/updater/external_constants_override.cc b/chrome/updater/external_constants_override.cc index 73f1aca3..4411fe2 100644 --- a/chrome/updater/external_constants_override.cc +++ b/chrome/updater/external_constants_override.cc
@@ -181,17 +181,17 @@ crx_format_verifier_value->GetInt()); } -base::Value::Dict ExternalConstantsOverrider::GroupPolicies() const { - if (!override_values_.contains(kDevOverrideKeyGroupPolicies)) { - return next_provider_->GroupPolicies(); +base::Value::Dict ExternalConstantsOverrider::DictPolicies() const { + if (!override_values_.contains(kDevOverrideKeyDictPolicies)) { + return next_provider_->DictPolicies(); } - const base::Value* group_policies_value = - override_values_.Find(kDevOverrideKeyGroupPolicies); - CHECK(group_policies_value->is_dict()) - << "Unexpected type of override[" << kDevOverrideKeyGroupPolicies - << "]: " << base::Value::GetTypeName(group_policies_value->type()); - return group_policies_value->GetDict().Clone(); + const base::Value* dict_policies_value = + override_values_.Find(kDevOverrideKeyDictPolicies); + CHECK(dict_policies_value->is_dict()) + << "Unexpected type of override[" << kDevOverrideKeyDictPolicies + << "]: " << base::Value::GetTypeName(dict_policies_value->type()); + return dict_policies_value->GetDict().Clone(); } base::TimeDelta ExternalConstantsOverrider::OverinstallTimeout() const {
diff --git a/chrome/updater/external_constants_override.h b/chrome/updater/external_constants_override.h index 77b853c..d70c091 100644 --- a/chrome/updater/external_constants_override.h +++ b/chrome/updater/external_constants_override.h
@@ -55,7 +55,7 @@ base::TimeDelta InitialDelay() const override; base::TimeDelta ServerKeepAliveTime() const override; crx_file::VerifierFormat CrxVerifierFormat() const override; - base::Value::Dict GroupPolicies() const override; + base::Value::Dict DictPolicies() const override; base::TimeDelta OverinstallTimeout() const override; base::TimeDelta IdleCheckPeriod() const override; std::optional<bool> IsMachineManaged() const override;
diff --git a/chrome/updater/external_constants_override_unittest.cc b/chrome/updater/external_constants_override_unittest.cc index e8da374..bc556ad 100644 --- a/chrome/updater/external_constants_override_unittest.cc +++ b/chrome/updater/external_constants_override_unittest.cc
@@ -42,7 +42,7 @@ EXPECT_EQ(overrider->InitialDelay(), kInitialDelay); EXPECT_EQ(overrider->ServerKeepAliveTime(), kServerKeepAliveTime); - EXPECT_EQ(overrider->GroupPolicies().size(), 0U); + EXPECT_EQ(overrider->DictPolicies().size(), 0U); EXPECT_FALSE(overrider->EnableDiffUpdates()); EXPECT_EQ(overrider->CecaConnectionTimeout(), kCecaConnectionTimeout); } @@ -52,9 +52,9 @@ base::Value::List url_list; url_list.Append("https://www.example.com"); url_list.Append("https://www.google.com"); - base::Value::Dict group_policies; - group_policies.Set("a", 1); - group_policies.Set("b", 2); + base::Value::Dict dict_policies; + dict_policies.Set("a", 1); + dict_policies.Set("b", 2); overrides.Set(kDevOverrideKeyUseCUP, false); overrides.Set(kDevOverrideKeyUrl, std::move(url_list)); @@ -63,7 +63,7 @@ overrides.Set(kDevOverrideKeyAppLogoUrl, "https://applogo.google.com/"); overrides.Set(kDevOverrideKeyInitialDelay, 137.1); overrides.Set(kDevOverrideKeyServerKeepAliveSeconds, 1); - overrides.Set(kDevOverrideKeyGroupPolicies, std::move(group_policies)); + overrides.Set(kDevOverrideKeyDictPolicies, std::move(dict_policies)); overrides.Set(kDevOverrideKeyOverinstallTimeout, 3); overrides.Set(kDevOverrideKeyIdleCheckPeriodSeconds, 4); overrides.Set(kDevOverrideKeyEnableDiffUpdates, true); @@ -89,7 +89,7 @@ EXPECT_EQ(overrider->InitialDelay(), base::Seconds(137.1)); EXPECT_EQ(overrider->ServerKeepAliveTime(), base::Seconds(1)); - EXPECT_EQ(overrider->GroupPolicies().size(), 2U); + EXPECT_EQ(overrider->DictPolicies().size(), 2U); EXPECT_EQ(overrider->OverinstallTimeout(), base::Seconds(3)); EXPECT_EQ(overrider->IdleCheckPeriod(), base::Seconds(4)); EXPECT_TRUE(overrider->EnableDiffUpdates()); @@ -111,7 +111,7 @@ EXPECT_TRUE(overrider->UseCUP()); EXPECT_EQ(overrider->InitialDelay(), kInitialDelay); EXPECT_EQ(overrider->ServerKeepAliveTime(), kServerKeepAliveTime); - EXPECT_EQ(overrider->GroupPolicies().size(), 0U); + EXPECT_EQ(overrider->DictPolicies().size(), 0U); EXPECT_EQ(overrider->CecaConnectionTimeout(), kCecaConnectionTimeout); }
diff --git a/chrome/updater/mac/BUILD.gn b/chrome/updater/mac/BUILD.gn index 889bb96c..490ddb6 100644 --- a/chrome/updater/mac/BUILD.gn +++ b/chrome/updater/mac/BUILD.gn
@@ -619,6 +619,7 @@ "$root_out_dir/CRURegistration/CRURegistration.h", "$root_out_dir/CRURegistration/CRURegistration-Private.h", "$root_out_dir/CRURegistration/CRURegistration.m", + "$root_out_dir/CRURegistration/CRURegistrationPaths.m", ] inputs += rebase_path(get_path_info(updater_signing_sources, "file"), "",
diff --git a/chrome/updater/policy/service.cc b/chrome/updater/policy/service.cc index 64bc51e..2bb4944 100644 --- a/chrome/updater/policy/service.cc +++ b/chrome/updater/policy/service.cc
@@ -61,7 +61,7 @@ dm_policy_manager_ = CreateDMPolicyManager(external_constants->IsMachineManaged()); external_constants_policy_manager_ = - base::MakeRefCounted<PolicyManager>(external_constants->GroupPolicies()); + base::MakeRefCounted<PolicyManager>(external_constants->DictPolicies()); platform_policy_manager_ = CreatePlatformPolicyManager(external_constants->IsMachineManaged()); } @@ -111,19 +111,6 @@ bool PolicyService::PolicyManagers::CloudPolicyOverridesPlatformPolicy( const std::vector<scoped_refptr<PolicyManagerInterface>>& providers) { -#if BUILDFLAG(IS_WIN) - // On Windows, by default, Group Policy has a higher priority than the - // clould policy. - constexpr bool kCloudPolicyOverridesPlatformPolicyDefaultValue = false; -#elif BUILDFLAG(IS_MAC) - // On macOS, cloud policy has a higher priority than the Managed Preferences. - constexpr bool kCloudPolicyOverridesPlatformPolicyDefaultValue = true; -#else - // On other platforms, there's no platform policy at the moment, the value - // doesn't actually matter. - constexpr bool kCloudPolicyOverridesPlatformPolicyDefaultValue = true; -#endif - auto it = base::ranges::find_if( providers, [](scoped_refptr<PolicyManagerInterface> p) { return p && (p->CloudPolicyOverridesPlatformPolicy()).has_value();
diff --git a/chrome/updater/policy/service_unittest.cc b/chrome/updater/policy/service_unittest.cc index 5cab969..ea1330da 100644 --- a/chrome/updater/policy/service_unittest.cc +++ b/chrome/updater/policy/service_unittest.cc
@@ -20,21 +20,35 @@ #include "base/values.h" #include "chrome/enterprise_companion/global_constants.h" #include "chrome/updater/external_constants.h" +#include "chrome/updater/external_constants_builder.h" +#include "chrome/updater/external_constants_override.h" #include "chrome/updater/policy/dm_policy_manager.h" #include "chrome/updater/policy/manager.h" #include "chrome/updater/policy/platform_policy_manager.h" #include "chrome/updater/protos/omaha_settings.pb.h" +#include "chrome/updater/test/integration_tests_impl.h" +#include "chrome/updater/test/test_scope.h" +#include "chrome/updater/test/unit_test_util.h" #include "testing/gtest/include/gtest/gtest.h" #if BUILDFLAG(IS_WIN) #include "base/test/test_reg_util_win.h" -#include "base/win/registry.h" #include "chrome/updater/util/win_util.h" #include "chrome/updater/win/win_constants.h" #endif namespace updater { +namespace { + +#if BUILDFLAG(IS_WIN) +constexpr char kGlobalPolicyKey[] = ""; +#elif !BUILDFLAG(IS_MAC) +constexpr char kGlobalPolicyKey[] = "global"; +#endif + +} // namespace + using PolicyManagers = std::vector<scoped_refptr<PolicyManagerInterface>>; void PolicyService::SetManagersForTesting(updater::PolicyManagers managers) { @@ -770,62 +784,6 @@ ->AreUpdatesSuppressedNow(now)); } -#if BUILDFLAG(IS_WIN) -TEST_F(PolicyServiceTest, CreateManagers) { - base::test::TaskEnvironment environment; - registry_util::RegistryOverrideManager registry_overrides; - ASSERT_NO_FATAL_FAILURE( - registry_overrides.OverrideRegistry(HKEY_LOCAL_MACHINE)); - - auto omaha_settings = - std::make_unique<::wireless_android_enterprise_devicemanagement:: - OmahaSettingsClientProto>(); - auto dm_policy = base::MakeRefCounted<DMPolicyManager>(*omaha_settings, true); - PolicyService::PolicyManagers managers(CreateExternalConstants()); - managers.ResetDeviceManagementManager(dm_policy); - EXPECT_EQ(managers.managers().size(), size_t{4}); - EXPECT_EQ(managers.managers()[0]->source(), "Device Management"); - EXPECT_EQ(managers.managers()[1]->source(), "Default"); - EXPECT_EQ(managers.managers()[2]->source(), "DictValuePolicy"); - EXPECT_EQ(managers.managers()[3]->source(), "Group Policy"); - - base::win::RegKey key(HKEY_LOCAL_MACHINE, UPDATER_POLICIES_KEY, - Wow6432(KEY_WRITE)); - EXPECT_EQ(ERROR_SUCCESS, - key.WriteValue(L"CloudPolicyOverridesPlatformPolicy", 1)); - managers.ResetDeviceManagementManager(dm_policy); - EXPECT_EQ(managers.managers().size(), size_t{4}); - EXPECT_EQ(managers.managers()[0]->source(), "Device Management"); - EXPECT_EQ(managers.managers()[1]->source(), "Default"); - EXPECT_EQ(managers.managers()[2]->source(), "DictValuePolicy"); - EXPECT_EQ(managers.managers()[3]->source(), "Group Policy"); -} -#elif BUILDFLAG(IS_MAC) -TEST_F(PolicyServiceTest, CreateManagers) { - auto omaha_settings = - std::make_unique<::wireless_android_enterprise_devicemanagement:: - OmahaSettingsClientProto>(); - auto dm_policy = base::MakeRefCounted<DMPolicyManager>(*omaha_settings, true); - PolicyService::PolicyManagers managers(CreateExternalConstants()); - managers.ResetDeviceManagementManager(dm_policy); - EXPECT_EQ(managers.managers().size(), size_t{4}); - EXPECT_EQ(managers.managers()[0]->source(), "Device Management"); -} -#else -TEST_F(PolicyServiceTest, CreateManagers) { - auto omaha_settings = - std::make_unique<::wireless_android_enterprise_devicemanagement:: - OmahaSettingsClientProto>(); - auto dm_policy = base::MakeRefCounted<DMPolicyManager>(*omaha_settings, true); - PolicyService::PolicyManagers managers(CreateExternalConstants()); - managers.ResetDeviceManagementManager(dm_policy); - EXPECT_EQ(managers.managers().size(), size_t{3}); - EXPECT_EQ(managers.managers()[0]->source(), "Device Management"); - EXPECT_EQ(managers.managers()[1]->source(), "Default"); - EXPECT_EQ(managers.managers()[2]->source(), "DictValuePolicy"); -} -#endif - TEST_F(PolicyServiceTest, PolicyServiceProxyConfiguration_Get) { // Test proxy mode "auto_detect". auto manager = base::MakeRefCounted<FakePolicyManager>(true, "manager"); @@ -879,4 +837,212 @@ ASSERT_FALSE(PolicyServiceProxyConfiguration::Get(policy_service)); } +class PolicyManagersTest : public ::testing::Test { + protected: + void SetUp() override { +#if BUILDFLAG(IS_MAC) + if (IsSystemInstall(GetUpdaterScopeForTesting())) { + GTEST_SKIP(); + } +#endif + + ASSERT_NO_FATAL_FAILURE(DeleteOverridesFile()); + +#if BUILDFLAG(IS_WIN) + ASSERT_NO_FATAL_FAILURE( + registry_overrides_.OverrideRegistry(HKEY_LOCAL_MACHINE)); +#endif + } + + void TearDown() override { +#if BUILDFLAG(IS_MAC) + if (IsSystemInstall(GetUpdaterScopeForTesting())) { + GTEST_SKIP(); + } +#endif + + ASSERT_NO_FATAL_FAILURE(DeleteOverridesFile()); + } + + void DeleteOverridesFile() { + ASSERT_TRUE( + test::DeleteFileAndEmptyParentDirectories(overrides_file_path_)); + } + + private: + const std::optional<base::FilePath> overrides_file_path_ = + GetOverrideFilePath(GetUpdaterScopeForTesting()); + +#if BUILDFLAG(IS_WIN) + registry_util::RegistryOverrideManager registry_overrides_; + base::test::TaskEnvironment environment_; +#endif +}; + +TEST_F(PolicyManagersTest, NullExternalConstants) { + PolicyService::PolicyManagers managers({}); + ASSERT_EQ(managers.managers().size(), size_t{1}); + EXPECT_EQ(managers.managers()[0]->source(), "Default"); +} + +TEST_F(PolicyManagersTest, MachineUnmanaged) { + ASSERT_TRUE(ExternalConstantsBuilder().SetMachineManaged(false).Overwrite()); + PolicyService::PolicyManagers managers(CreateExternalConstants()); + + ASSERT_EQ(managers.managers().size(), + size_t{2 + kPlatformPolicyManagerDefined}); + EXPECT_EQ(managers.managers()[0]->source(), "Default"); + EXPECT_EQ(managers.managers()[1]->source(), "DictValuePolicy"); + if (kPlatformPolicyManagerDefined) { + EXPECT_EQ(managers.managers()[2]->source(), kSourcePlatformPolicyManager); + } +} + +TEST_F(PolicyManagersTest, ValidDeviceManagementManager) { + ASSERT_TRUE(ExternalConstantsBuilder().SetMachineManaged(false).Overwrite()); + auto omaha_settings = + std::make_unique<::wireless_android_enterprise_devicemanagement:: + OmahaSettingsClientProto>(); + auto dm_policy = base::MakeRefCounted<DMPolicyManager>(*omaha_settings, true); + PolicyService::PolicyManagers managers(CreateExternalConstants()); + managers.ResetDeviceManagementManager(dm_policy); + + ASSERT_EQ(managers.managers().size(), + size_t{3 + kPlatformPolicyManagerDefined}); + EXPECT_EQ(managers.managers()[0]->source(), "Device Management"); + EXPECT_EQ(managers.managers()[1]->source(), "Default"); + EXPECT_EQ(managers.managers()[2]->source(), "DictValuePolicy"); + if (kPlatformPolicyManagerDefined) { + EXPECT_EQ(managers.managers()[3]->source(), kSourcePlatformPolicyManager); + } +} + +// TODO(crbug.com/389965546): enable these tests for mac. +#if !BUILDFLAG(IS_MAC) +TEST_F(PolicyManagersTest, ValidDictPlatformPolicies) { + base::Value::Dict dict_policies; + dict_policies.Set("a", 1); + + ASSERT_TRUE(ExternalConstantsBuilder() + .SetMachineManaged(true) + .SetDictPolicies(dict_policies) + .Overwrite()); + + base::Value::Dict policies; + policies.Set(kGlobalPolicyKey, + base::Value::Dict().Set("CloudPolicyOverridesPlatformPolicy", + kPolicyEnabled)); + ASSERT_NO_FATAL_FAILURE(test::SetPlatformPolicies(policies)); + + PolicyService::PolicyManagers managers(CreateExternalConstants()); + + ASSERT_EQ(managers.managers().size(), + size_t{2 + kPlatformPolicyManagerDefined}); + EXPECT_EQ(managers.managers()[0]->source(), "DictValuePolicy"); + if (kPlatformPolicyManagerDefined) { + EXPECT_EQ(managers.managers()[1]->source(), kSourcePlatformPolicyManager); + } + EXPECT_EQ(managers.managers()[1 + kPlatformPolicyManagerDefined]->source(), + "Default"); +} + +TEST_F(PolicyManagersTest, ValidDeviceManagementPlatformPolicyNoCloudOverride) { + ASSERT_TRUE(ExternalConstantsBuilder().SetMachineManaged(true).Overwrite()); + + base::Value::Dict policies; + policies.Set(kGlobalPolicyKey, + base::Value::Dict().Set("CloudPolicyOverridesPlatformPolicy", + kPolicyDisabled)); + ASSERT_NO_FATAL_FAILURE(test::SetPlatformPolicies(policies)); + + auto omaha_settings = + std::make_unique<::wireless_android_enterprise_devicemanagement:: + OmahaSettingsClientProto>(); + auto dm_policy = base::MakeRefCounted<DMPolicyManager>(*omaha_settings, true); + PolicyService::PolicyManagers managers(CreateExternalConstants()); + managers.ResetDeviceManagementManager(dm_policy); + ASSERT_EQ(managers.managers().size(), + size_t{3 + kPlatformPolicyManagerDefined}); + if (kPlatformPolicyManagerDefined) { + EXPECT_EQ(managers.managers()[0]->source(), + kCloudPolicyOverridesPlatformPolicyDefaultValue + ? "Device Management" + : kSourcePlatformPolicyManager); + EXPECT_EQ(managers.managers()[1]->source(), + kCloudPolicyOverridesPlatformPolicyDefaultValue + ? kSourcePlatformPolicyManager + : "Device Management"); + } else { + EXPECT_EQ(managers.managers()[0]->source(), "Device Management"); + } + + EXPECT_EQ(managers.managers()[1 + kPlatformPolicyManagerDefined]->source(), + "Default"); + EXPECT_EQ(managers.managers()[2 + kPlatformPolicyManagerDefined]->source(), + "DictValuePolicy"); +} + +TEST_F(PolicyManagersTest, ValidDeviceManagementPlatformPolicyCloudOverride) { + ASSERT_TRUE(ExternalConstantsBuilder().SetMachineManaged(true).Overwrite()); + + base::Value::Dict policies; + policies.Set(kGlobalPolicyKey, + base::Value::Dict().Set("CloudPolicyOverridesPlatformPolicy", + kPolicyEnabled)); + ASSERT_NO_FATAL_FAILURE(test::SetPlatformPolicies(policies)); + + auto omaha_settings = + std::make_unique<::wireless_android_enterprise_devicemanagement:: + OmahaSettingsClientProto>(); + auto dm_policy = base::MakeRefCounted<DMPolicyManager>(*omaha_settings, true); + PolicyService::PolicyManagers managers(CreateExternalConstants()); + managers.ResetDeviceManagementManager(dm_policy); + + ASSERT_EQ(managers.managers().size(), + size_t{3 + kPlatformPolicyManagerDefined}); + EXPECT_EQ(managers.managers()[0]->source(), "Device Management"); + if (kPlatformPolicyManagerDefined) { + EXPECT_EQ(managers.managers()[1]->source(), kSourcePlatformPolicyManager); + } + EXPECT_EQ(managers.managers()[1 + kPlatformPolicyManagerDefined]->source(), + "Default"); + EXPECT_EQ(managers.managers()[2 + kPlatformPolicyManagerDefined]->source(), + "DictValuePolicy"); +} + +TEST_F(PolicyManagersTest, + ValidDictDeviceManagementPlatformPolicyCloudOverride) { + base::Value::Dict dict_policies; + dict_policies.Set("a", 1); + + ASSERT_TRUE(ExternalConstantsBuilder() + .SetMachineManaged(true) + .SetDictPolicies(dict_policies) + .Overwrite()); + + base::Value::Dict policies; + policies.Set(kGlobalPolicyKey, + base::Value::Dict().Set("CloudPolicyOverridesPlatformPolicy", + kPolicyEnabled)); + ASSERT_NO_FATAL_FAILURE(test::SetPlatformPolicies(policies)); + + auto omaha_settings = + std::make_unique<::wireless_android_enterprise_devicemanagement:: + OmahaSettingsClientProto>(); + auto dm_policy = base::MakeRefCounted<DMPolicyManager>(*omaha_settings, true); + PolicyService::PolicyManagers managers(CreateExternalConstants()); + managers.ResetDeviceManagementManager(dm_policy); + ASSERT_EQ(managers.managers().size(), + size_t{3 + kPlatformPolicyManagerDefined}); + EXPECT_EQ(managers.managers()[0]->source(), "DictValuePolicy"); + EXPECT_EQ(managers.managers()[1]->source(), "Device Management"); + if (kPlatformPolicyManagerDefined) { + EXPECT_EQ(managers.managers()[2]->source(), kSourcePlatformPolicyManager); + } + + EXPECT_EQ(managers.managers()[2 + kPlatformPolicyManagerDefined]->source(), + "Default"); +} +#endif // !BUILDFLAG(IS_MAC) + } // namespace updater
diff --git a/chrome/updater/test/integration_test_commands.h b/chrome/updater/test/integration_test_commands.h index 9a5e6b17..52143c11 100644 --- a/chrome/updater/test/integration_test_commands.h +++ b/chrome/updater/test/integration_test_commands.h
@@ -41,7 +41,7 @@ base::TimeDelta server_keep_alive_time, base::TimeDelta ceca_connection_timeout) const = 0; virtual void ExitTestMode() const = 0; - virtual void SetGroupPolicies(const base::Value::Dict& values) const = 0; + virtual void SetDictPolicies(const base::Value::Dict& values) const = 0; virtual void SetPlatformPolicies(const base::Value::Dict& values) const = 0; virtual void SetMachineManaged(bool is_managed_device) const = 0; virtual void Clean() const = 0;
diff --git a/chrome/updater/test/integration_test_commands_system.cc b/chrome/updater/test/integration_test_commands_system.cc index 263b1d9..e717db9 100644 --- a/chrome/updater/test/integration_test_commands_system.cc +++ b/chrome/updater/test/integration_test_commands_system.cc
@@ -167,8 +167,8 @@ void ExitTestMode() const override { RunCommand("exit_test_mode"); } - void SetGroupPolicies(const base::Value::Dict& values) const override { - RunCommand("set_group_policies", + void SetDictPolicies(const base::Value::Dict& values) const override { + RunCommand("set_dict_policies", {Param("values", StringFromValue(base::Value(values.Clone())))}); }
diff --git a/chrome/updater/test/integration_test_commands_user.cc b/chrome/updater/test/integration_test_commands_user.cc index 1eacf55..af0b4bff 100644 --- a/chrome/updater/test/integration_test_commands_user.cc +++ b/chrome/updater/test/integration_test_commands_user.cc
@@ -103,8 +103,8 @@ updater::test::ExpectSelfUpdateSequence(updater_scope_, test_server); } - void SetGroupPolicies(const base::Value::Dict& values) const override { - updater::test::SetGroupPolicies(values); + void SetDictPolicies(const base::Value::Dict& values) const override { + updater::test::SetDictPolicies(values); } void SetPlatformPolicies(const base::Value::Dict& values) const override {
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc index c344ee0..61c1ba8c 100644 --- a/chrome/updater/test/integration_tests.cc +++ b/chrome/updater/test/integration_tests.cc
@@ -350,8 +350,8 @@ void ExitTestMode() { test_commands_->ExitTestMode(); } - void SetGroupPolicies(const base::Value::Dict& values) { - test_commands_->SetGroupPolicies(values); + void SetDictPolicies(const base::Value::Dict& values) { + test_commands_->SetDictPolicies(values); } void SetPlatformPolicies(const base::Value::Dict& values) { @@ -1476,11 +1476,11 @@ TEST_F(IntegrationTest, NoCheckWhenLastCheckedRecentlyPolicy) { ScopedServer test_server(test_commands_); - base::Value::Dict group_policies; - group_policies.Set("autoupdatecheckperiodminutes", 60 * 18); + base::Value::Dict dict_policies; + dict_policies.Set("autoupdatecheckperiodminutes", 60 * 18); ASSERT_NO_FATAL_FAILURE(SetLastChecked(base::Time::Now() - base::Hours(12))); ASSERT_NO_FATAL_FAILURE(Install()); - ASSERT_NO_FATAL_FAILURE(SetGroupPolicies(group_policies)); + ASSERT_NO_FATAL_FAILURE(SetDictPolicies(dict_policies)); ASSERT_NO_FATAL_FAILURE(InstallApp("test")); ASSERT_NO_FATAL_FAILURE(RunWake(0)); ASSERT_NO_FATAL_FAILURE(ExpectUninstallPing(&test_server)); @@ -1491,12 +1491,12 @@ ScopedServer test_server(test_commands_); base::Time::Exploded now; base::Time::Now().LocalExplode(&now); - base::Value::Dict group_policies; - group_policies.Set("updatessuppressedstarthour", (now.hour - 1 + 24) % 24); - group_policies.Set("updatessuppressedstartmin", 0); - group_policies.Set("updatessuppresseddurationmin", 120); + base::Value::Dict dict_policies; + dict_policies.Set("updatessuppressedstarthour", (now.hour - 1 + 24) % 24); + dict_policies.Set("updatessuppressedstartmin", 0); + dict_policies.Set("updatessuppresseddurationmin", 120); ASSERT_NO_FATAL_FAILURE(Install()); - ASSERT_NO_FATAL_FAILURE(SetGroupPolicies(group_policies)); + ASSERT_NO_FATAL_FAILURE(SetDictPolicies(dict_policies)); ASSERT_NO_FATAL_FAILURE(InstallApp("test")); ASSERT_NO_FATAL_FAILURE(RunWake(0)); ASSERT_NO_FATAL_FAILURE(ExpectUninstallPing(&test_server)); @@ -4188,12 +4188,11 @@ ScopedServer test_server(test_commands_); ASSERT_NO_FATAL_FAILURE(Install()); - base::Value::Dict group_policies; - group_policies.Set("installtest1", - IsSystemInstall(GetUpdaterScopeForTesting()) - ? kPolicyForceInstallMachine - : kPolicyForceInstallUser); - ASSERT_NO_FATAL_FAILURE(SetGroupPolicies(group_policies)); + base::Value::Dict dict_policies; + dict_policies.Set("installtest1", IsSystemInstall(GetUpdaterScopeForTesting()) + ? kPolicyForceInstallMachine + : kPolicyForceInstallUser); + ASSERT_NO_FATAL_FAILURE(SetDictPolicies(dict_policies)); ExpectUpdateCheckRequest(&test_server); @@ -4729,9 +4728,9 @@ TEST_P(IntegrationLegacyUpdate3WebTest, DisabledPolicyManual) { ASSERT_TRUE(WaitForUpdaterExit()); - base::Value::Dict group_policies; - group_policies.Set("updatetest1", kPolicyAutomaticUpdatesOnly); - ASSERT_NO_FATAL_FAILURE(SetGroupPolicies(group_policies)); + base::Value::Dict dict_policies; + dict_policies.Set("updatetest1", kPolicyAutomaticUpdatesOnly); + ASSERT_NO_FATAL_FAILURE(SetDictPolicies(dict_policies)); ASSERT_NO_FATAL_FAILURE(ExpectLegacyUpdate3WebSucceeds( kAppId, AppBundleWebCreateMode::kCreateInstalledApp, STATE_ERROR, GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY_MANUAL)); @@ -4739,9 +4738,9 @@ TEST_P(IntegrationLegacyUpdate3WebTest, DisabledPolicy) { ASSERT_TRUE(WaitForUpdaterExit()); - base::Value::Dict group_policies; - group_policies.Set("updatetest1", kPolicyDisabled); - ASSERT_NO_FATAL_FAILURE(SetGroupPolicies(group_policies)); + base::Value::Dict dict_policies; + dict_policies.Set("updatetest1", kPolicyDisabled); + ASSERT_NO_FATAL_FAILURE(SetDictPolicies(dict_policies)); ExpectLegacyUpdate3WebSucceeds( kAppId, AppBundleWebCreateMode::kCreateInstalledApp, STATE_ERROR, GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY);
diff --git a/chrome/updater/test/integration_tests_helper.cc b/chrome/updater/test/integration_tests_helper.cc index e1db88a..aea6973 100644 --- a/chrome/updater/test/integration_tests_helper.cc +++ b/chrome/updater/test/integration_tests_helper.cc
@@ -301,7 +301,7 @@ WithSwitch("update_url", Wrap(&EnterTestMode))))))))}, {"exit_test_mode", WithSystemScope(Wrap(&ExitTestMode))}, - {"set_group_policies", WithSwitch("values", Wrap(&SetGroupPolicies))}, + {"set_dict_policies", WithSwitch("values", Wrap(&SetDictPolicies))}, {"set_platform_policies", WithSwitch("values", Wrap(&SetPlatformPolicies))}, {"set_machine_managed",
diff --git a/chrome/updater/test/integration_tests_impl.cc b/chrome/updater/test/integration_tests_impl.cc index c659606..c246d24 100644 --- a/chrome/updater/test/integration_tests_impl.cc +++ b/chrome/updater/test/integration_tests_impl.cc
@@ -513,8 +513,8 @@ .Modify()); } -void SetGroupPolicies(const base::Value::Dict& values) { - ASSERT_TRUE(ExternalConstantsBuilder().SetGroupPolicies(values).Modify()); +void SetDictPolicies(const base::Value::Dict& values) { + ASSERT_TRUE(ExternalConstantsBuilder().SetDictPolicies(values).Modify()); } void SetMachineManaged(bool is_managed_device) {
diff --git a/chrome/updater/test/integration_tests_impl.h b/chrome/updater/test/integration_tests_impl.h index f0f1a0a..240d962 100644 --- a/chrome/updater/test/integration_tests_impl.h +++ b/chrome/updater/test/integration_tests_impl.h
@@ -164,8 +164,8 @@ // JSON file. void ExitTestMode(UpdaterScope scope); -// Sets the external constants for group policies. -void SetGroupPolicies(const base::Value::Dict& values); +// Sets the dict policies that are surfaced via external constants. +void SetDictPolicies(const base::Value::Dict& values); // Sets platform policies. Platform policy is group policy on Windows, and // Managed Preferences on macOS.
diff --git a/chrome/updater/test/service/win/run_command_as_standard_user.py b/chrome/updater/test/service/win/run_command_as_standard_user.py index f08caa6..a2116e2 100644 --- a/chrome/updater/test/service/win/run_command_as_standard_user.py +++ b/chrome/updater/test/service/win/run_command_as_standard_user.py
@@ -2,13 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# [VPYTHON:BEGIN] -# python_version: "3.8" -# wheel: < -# name: "infra/python/wheels/pywin32/${vpython_platform}" -# version: "version:300" -# > -# [VPYTHON:END] """Run the given command as the standard user. All arguments provided to this program will be used to reconstruct the command
diff --git a/chrome/updater/test/service/win/updater_test_service.py b/chrome/updater/test/service/win/updater_test_service.py index c321d1e..ee6e301 100644 --- a/chrome/updater/test/service/win/updater_test_service.py +++ b/chrome/updater/test/service/win/updater_test_service.py
@@ -58,6 +58,8 @@ _svc_name_ = 'UpdaterTestService' _svc_display_name_ = 'Updater Test Service' _svc_description_ = 'Service for browser updater tests' + _exe_name_ = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), + 'pythonservice.exe') def SvcStop(self): """Called by service framework to stop this service."""
diff --git a/chrome/updater/test/service/win/updater_test_service_control.py b/chrome/updater/test/service/win/updater_test_service_control.py index 33b38ca1..61bed50 100644 --- a/chrome/updater/test/service/win/updater_test_service_control.py +++ b/chrome/updater/test/service/win/updater_test_service_control.py
@@ -2,14 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# [VPYTHON:BEGIN] -# python_version: "3.8" -# wheel: < -# name: "infra/python/wheels/pywin32/${vpython_platform}" -# version: "version:300" -# > -# [VPYTHON:END] - import contextlib import logging import os @@ -17,6 +9,7 @@ import subprocess import socket import sys +import sysconfig import time import pywintypes @@ -56,6 +49,20 @@ return process.returncode == 0 +def _CopyDLLsInDirectory(source_dir, destination_dir): + """Copies all DLLs in `source_dir` to the `destination_dir`.""" + for filename in os.listdir(source_dir): + source_file = os.path.join(source_dir, filename) + destination_file = os.path.join(destination_dir, filename) + if os.path.isfile(source_file) and source_file.endswith( + '.dll') and not os.path.exists(destination_file): + logging.info(f'Copying {source_file} ===> {destination_file} ...') + try: + shutil.copy(source_file, destination_file) + except PermissionError as err: + logging.exception(err) + + def _SetupEnvironmentForVPython(): """Setup vpython environment.""" # vpython_spec above brings the pywin32 module we need, but it may not be @@ -63,23 +70,32 @@ # https://pypi.org/project/pywin32/. # This script outputs some error messages to stderr if it has run before. # So skip logging to avoid this log pollution. - post_install_script = os.path.join( - os.path.dirname(os.path.abspath(sys.executable)), - 'pywin32_postinstall.py') - _RunCommand( - [sys.executable, post_install_script, '-install', '-silent', '-quiet'], - log_error=False) # Make pythonservice.exe explicit for our service. This is to avoid pickup # an incompatible interpreter accidentally. python_dir = os.path.dirname(os.path.abspath(sys.executable)) - source = os.path.join(os.path.dirname(python_dir), 'Lib', 'site-packages', - 'win32', 'pythonservice.exe') + source = os.path.join(sysconfig.get_paths()['platlib'], 'win32', + 'pythonservice.exe') python_service_path = os.path.join(python_dir, 'pythonservice.exe') if os.path.exists(source) and not os.path.exists(python_service_path): shutil.copyfile(source, python_service_path) os.environ['PYTHON_SERVICE_EXE'] = python_service_path + # Copy the DLLs from `pywin32_system32` folder to the folder that + # `pythonservice.exe` resides. The DLLs are required by `pythonservice.exe`. + # Normally we run the post install scripts as described by + # https://pypi.org/project/pywin32/ to make pywin32 ready. However + # the script copies the DLLs to `%WINDIR%\\system32` which leads to version + # conflict when multiple versions of VPython exists. Hence we + # setup this running environment entirely within current VPython directory. + # This is less robust compared with running `pywin32_postinstall.py`, but + # works good enough for our test. This also avoids the issue that + # `pywin32_postinstall.py` accidentally omits `-silent` switch since + # https://github.com/mhammond/pywin32/commit/c6958cdccb38e5888a5141553dd36a21fa196f53. + _CopyDLLsInDirectory( + os.path.join(sysconfig.get_paths()['platlib'], 'pywin32_system32'), + python_dir) + def _IsServiceInStatus(status): """Returns the if test service is in the given status."""
diff --git a/chrome/updater/win/app_command_runner.cc b/chrome/updater/win/app_command_runner.cc index 1ab6417..1a296dd 100644 --- a/chrome/updater/win/app_command_runner.cc +++ b/chrome/updater/win/app_command_runner.cc
@@ -2,11 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/40285824): Remove this and convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #include "chrome/updater/win/app_command_runner.h" #include <windows.h> @@ -23,6 +18,7 @@ #include "base/containers/span.h" #include "base/files/file_path.h" #include "base/logging.h" +#include "base/numerics/safe_conversions.h" #include "base/path_service.h" #include "base/process/launch.h" #include "base/strings/strcat.h" @@ -258,7 +254,13 @@ return E_INVALIDARG; } - const base::FilePath exe = base::FilePath(argv.get()[0]); + // SAFETY: the unsafe buffer is present due to the ::CommandLineToArgvW call. + // When constructing the span, `num_args` is validated and checked as a valid + // size_t value. + UNSAFE_BUFFERS(const base::span<wchar_t*> safe_args{ + argv.get(), base::checked_cast<size_t>(num_args)}); + + const base::FilePath exe(safe_args[0]); if (!IsSecureAppCommandExePath(scope, exe)) { LOG(WARNING) << __func__ << ": !IsSecureAppCommandExePath(scope, exe): " << exe; @@ -267,8 +269,8 @@ executable = exe; parameters.clear(); - for (int i = 1; i < num_args; ++i) { - parameters.push_back(argv.get()[i]); + for (size_t i = 1; i < safe_args.size(); ++i) { + parameters.push_back(safe_args[i]); } return S_OK;
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn index bee86a9..d2c8f21 100644 --- a/chromecast/browser/BUILD.gn +++ b/chromecast/browser/BUILD.gn
@@ -323,6 +323,7 @@ "//chromecast/browser/android:jni_headers", "//components/android_autofill/browser:android", "//components/embedder_support/android:view", + "//components/variations:variations_associated_data", ] } else { deps += [ ":display_configurator" ]
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 8de6bab..94a05740 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -16163.0.0-1066150 \ No newline at end of file +16164.0.0-1066176 \ No newline at end of file
diff --git a/chromeos/ash/components/network/metrics/cellular_network_metrics_logger.h b/chromeos/ash/components/network/metrics/cellular_network_metrics_logger.h index b30c07f1..3e2a0c3 100644 --- a/chromeos/ash/components/network/metrics/cellular_network_metrics_logger.h +++ b/chromeos/ash/components/network/metrics/cellular_network_metrics_logger.h
@@ -126,7 +126,7 @@ }; static constexpr char kCreateCustomApnResultHistogram[] = - "Network.Ash.Cellular.Apn.CreateCustomApn.Result"; + "Network.Ash.Cellular.Apn.CreateCustomApn.Result2"; static constexpr char kCreateCustomApnShillErrorHistogram[] = "Network.Ash.Cellular.Apn.CreateCustomApn.ShillError"; static constexpr char kCreateCustomApnAuthenticationTypeHistogram[] =
diff --git a/chromeos/ui/frame/frame_header.cc b/chromeos/ui/frame/frame_header.cc index 2f26708..05de497f 100644 --- a/chromeos/ui/frame/frame_header.cc +++ b/chromeos/ui/frame/frame_header.cc
@@ -19,6 +19,7 @@ #include "ui/compositor/layer.h" #include "ui/compositor/layer_animation_observer.h" #include "ui/compositor/layer_tree_owner.h" +#include "ui/compositor/layer_type.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/canvas.h" #include "ui/gfx/color_utils.h" @@ -115,7 +116,9 @@ old_layer->SetTransform(gfx::Transform()); // Layer in maximized / fullscreen / snapped state is set to // opaque, which can prevent resterizing the new layer immediately. - old_layer->SetFillsBoundsOpaquely(false); + if (old_layer->type() != ui::LAYER_SOLID_COLOR) { + old_layer->SetFillsBoundsOpaquely(false); + } layer_owner_ = std::move(old_layer_owner);
diff --git a/clank b/clank index 327a12f..7305a3c6 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 327a12f72fb1020336bddcf8c48c34ca9807eea1 +Subproject commit 7305a3c6540fa265dc3796f66a575054fafab42a
diff --git a/components/BUILD.gn b/components/BUILD.gn index 6c311d6..6e9755d 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -673,6 +673,7 @@ "//components/signin/public/android:signin_java_test_support", "//components/spellcheck/browser/android:java", "//components/translate/content/android:unit_tests", + "//components/variations:variations_associated_data", "//components/variations/android:variations_java", "//components/webapps/browser/android:java", "//components/webapps/browser/android:unit_tests",
diff --git a/components/android_autofill/browser/BUILD.gn b/components/android_autofill/browser/BUILD.gn index 16c6663..5ec70162 100644 --- a/components/android_autofill/browser/BUILD.gn +++ b/components/android_autofill/browser/BUILD.gn
@@ -31,7 +31,6 @@ "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/jni_zero:jni_zero_java", "//ui/android:ui_no_recycler_view_java", - "//ui/android:ui_utils_java", ] sources = [
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 496c636..e64d81e 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
@@ -38,8 +38,6 @@ import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.display.DisplayAndroid; -import java.util.Objects; - /** * This class works with Android autofill service to fill web form, it doesn't use Chrome's autofill * service or suggestion UI. All methods are supposed to be called in UI thread. @@ -84,7 +82,6 @@ // Whether onProvideAutofillVirtualStructure has been called for the current PrefillRequest. // Used solely for metrics. private boolean mStructureProvidedForPrefillRequest; - private boolean mVirtualViewExitedAfterFocusLoss; public AutofillProvider( Context context, @@ -759,45 +756,6 @@ } /** - * Notify autofill provider window focus has changed. - * - * @param hasWindowFocus whether window gained or lost focus. - */ - public void onWindowFocusChanged(boolean hasWindowFocus) { - if (mRequest == null) return; - FocusField focusField = mRequest.getFocusField(); - if (focusField == null) return; - - if (!hasWindowFocus) { - // When physical keyboard is being used, suggestions appear as a popup window anchored - // next to the form. That causes window focus loss, since the popup gains the focus. - // So we only want to send virtualViewExit when suggestions are displayed above - // the soft keyboard. - if (mAutofillManager.isAutofillInputUiShowing() && isSoftKeyboardVisible()) { - notifyVirtualViewExited(mContainerView, focusField.fieldIndex); - mVirtualViewExitedAfterFocusLoss = true; - } else { - mVirtualViewExitedAfterFocusLoss = false; - } - } - - if (hasWindowFocus && mVirtualViewExitedAfterFocusLoss) { - notifyVirtualViewEntered(mContainerView, focusField.fieldIndex, focusField.absBound); - } - } - - /** - * Checks if the soft keyboard is currently visible on the screen. - * - * @return {@code true} if the soft keyboard is visible, {@code false} otherwise. - */ - private boolean isSoftKeyboardVisible() { - return Objects.requireNonNull(mWebContents.getTopLevelNativeWindow()) - .getKeyboardDelegate() - .isKeyboardShowing(mContext, mContainerView); - } - - /** * Inform native provider to autofill. * * @param nativeAutofillProvider the native autofill provider.
diff --git a/components/autofill/core/browser/data_model/credit_card.cc b/components/autofill/core/browser/data_model/credit_card.cc index 0d7c812..74ebfdf 100644 --- a/components/autofill/core/browser/data_model/credit_card.cc +++ b/components/autofill/core/browser/data_model/credit_card.cc
@@ -318,12 +318,12 @@ case Suggestion::Icon::kOfferTag: case Suggestion::Icon::kPenSpark: case Suggestion::Icon::kPlusAddress: + case Suggestion::Icon::kSaveAndFill: case Suggestion::Icon::kScanCreditCard: case Suggestion::Icon::kSettings: case Suggestion::Icon::kSettingsAndroid: case Suggestion::Icon::kUndo: case Suggestion::Icon::kBnpl: - NOTREACHED(); } NOTREACHED();
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc index f87c0e3..0bfcfc0 100644 --- a/components/autofill/core/browser/form_structure.cc +++ b/components/autofill/core/browser/form_structure.cc
@@ -359,20 +359,33 @@ return ShouldBeParsed(); } -bool FormStructure::IsCompleteCreditCardForm() const { - bool found_cc_number = false; - bool found_cc_expiration = false; - for (const auto& field : fields_) { - FieldType type = field->Type().GetStorableType(); - if (!found_cc_expiration && data_util::IsCreditCardExpirationType(type)) { - found_cc_expiration = true; - } else if (!found_cc_number && type == CREDIT_CARD_NUMBER) { - found_cc_number = true; +bool FormStructure::IsCompleteCreditCardForm( + CreditCardFormCompleteness credit_card_form_completeness) const { + bool found_cc_expiration = + std::ranges::any_of(fields_, [](const auto& field) { + return data_util::IsCreditCardExpirationType( + field->Type().GetStorableType()); + }); + auto has_type = [&](FieldType type) { + return std::ranges::any_of(fields_, [&](const auto& field) { + return field->Type().GetStorableType() == type; + }); + }; + bool found_cc_number = has_type(CREDIT_CARD_NUMBER); + + switch (credit_card_form_completeness) { + case CreditCardFormCompleteness::kCompleteCreditCardForm: + return found_cc_expiration && found_cc_number; + case CreditCardFormCompleteness:: + kCompleteCreditCardFormIncludingCvcAndName: { + bool found_cc_cvc = has_type(CREDIT_CARD_VERIFICATION_CODE); + bool found_cc_name = + has_type(CREDIT_CARD_NAME_FULL) || + (has_type(CREDIT_CARD_NAME_FIRST) && has_type(CREDIT_CARD_NAME_LAST)); + return found_cc_expiration && found_cc_number && found_cc_cvc && + found_cc_name; } - if (found_cc_expiration && found_cc_number) - return true; } - return false; } void FormStructure::UpdateAutofillCount() {
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h index c0cc28e..a67d414 100644 --- a/components/autofill/core/browser/form_structure.h +++ b/components/autofill/core/browser/form_structure.h
@@ -93,10 +93,24 @@ // auto-fillable, like google/yahoo/msn search, etc. bool IsAutofillable() const; - // Returns whether |this| form represents a complete Credit Card form, which - // consists in having at least a credit card number field and an expiration - // field. - bool IsCompleteCreditCardForm() const; + // This enum defines two different states of completeness for a credit card + // form, each used for a distinct purpose to check if the required credit card + // fields exist. + enum class CreditCardFormCompleteness { + // This represents a minimal complete credit card form which has at least a + // credit card number field and an expiration date field. + kCompleteCreditCardForm, + // This represents a credit card form which has a CVC field and a cardholder + // name field in addition to the credit card number field and the expiration + // date field. For example, this level is required for offering `Save and + // Fill`. + kCompleteCreditCardFormIncludingCvcAndName, + }; + + // Returns whether |this| form represents a complete Credit Card form, as + // defined by the given CreditCardFormCompleteness level. + bool IsCompleteCreditCardForm( + CreditCardFormCompleteness credit_card_form_completeness) const; // Resets |autofill_count_| and counts the number of auto-fillable fields. // This is used when we receive server data for form fields. At that time,
diff --git a/components/autofill/core/browser/form_structure_fuzzer.cc b/components/autofill/core/browser/form_structure_fuzzer.cc index 1838574..c641af1 100644 --- a/components/autofill/core/browser/form_structure_fuzzer.cc +++ b/components/autofill/core/browser/form_structure_fuzzer.cc
@@ -74,7 +74,8 @@ GenerateGeoIpCountryCode(data_provider), /*log_manager=*/nullptr); std::ignore = form_structure.IsAutofillable(); - std::ignore = form_structure.IsCompleteCreditCardForm(); + std::ignore = form_structure.IsCompleteCreditCardForm( + FormStructure::CreditCardFormCompleteness::kCompleteCreditCardForm); std::ignore = form_structure.ShouldBeParsed(); std::ignore = form_structure.ShouldRunHeuristics(); std::ignore = form_structure.ShouldRunHeuristicsForSingleFields();
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc index 70e744d..9ce16a8 100644 --- a/components/autofill/core/browser/form_structure_unittest.cc +++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -636,56 +636,126 @@ TEST_F(FormStructureTestImpl, IsCompleteCreditCardForm_Minimal) { CheckFormStructureTestData( {{{.description_for_logging = "IsCompleteCreditCardForm_Minimal", - .fields = {{.role = FieldType::CREDIT_CARD_NUMBER}, - {.label = u"Expiration", .name = u"cc_exp"}, - {.role = FieldType::ADDRESS_HOME_ZIP}}}, + .fields = {{.role = CREDIT_CARD_NUMBER}, + {.label = u"Expiration"}, + {.role = ADDRESS_HOME_ZIP}}}, {.determine_heuristic_type = true, - .is_complete_credit_card_form = true}, + .is_complete_credit_card_form = std::make_pair( + FormStructure::CreditCardFormCompleteness::kCompleteCreditCardForm, + true)}, {}}}); } TEST_F(FormStructureTestImpl, IsCompleteCreditCardForm_Full) { CheckFormStructureTestData( {{{.description_for_logging = "IsCompleteCreditCardForm_Full", - .fields = {{.label = u"Name on Card", .name = u"name_on_card"}, - {.role = FieldType::CREDIT_CARD_NUMBER}, - {.label = u"Exp Month", .name = u"ccmonth"}, - {.label = u"Exp Year", .name = u"ccyear"}, - {.label = u"Verification", .name = u"verification"}, - {.label = u"Submit", - .name = u"submit", - .form_control_type = FormControlType::kInputText}}}, + .fields = {{.label = u"Name on Card"}, + {.role = CREDIT_CARD_NUMBER}, + {.label = u"Exp Month"}, + {.label = u"Exp Year"}, + {.label = u"Verification"}}}, {.determine_heuristic_type = true, - .is_complete_credit_card_form = true}, - {}}}); + .is_complete_credit_card_form = std::make_pair( + FormStructure::CreditCardFormCompleteness::kCompleteCreditCardForm, + true)}}}); } // A form with only the credit card number is not considered sufficient. TEST_F(FormStructureTestImpl, IsCompleteCreditCardForm_OnlyCCNumber) { CheckFormStructureTestData( {{{.description_for_logging = "IsCompleteCreditCardForm_OnlyCCNumber", - .fields = {{.role = FieldType::CREDIT_CARD_NUMBER}}}, + .fields = {{.role = CREDIT_CARD_NUMBER}}}, {.determine_heuristic_type = true, - .is_complete_credit_card_form = false}, + .is_complete_credit_card_form = std::make_pair( + FormStructure::CreditCardFormCompleteness::kCompleteCreditCardForm, + false)}, {}}}); } -// A form with only the credit card number is not considered sufficient. TEST_F(FormStructureTestImpl, IsCompleteCreditCardForm_AddressForm) { CheckFormStructureTestData( {{{.description_for_logging = "IsCompleteCreditCardForm_AddressForm", - .fields = {{.role = FieldType::NAME_FIRST, .name = u""}, - {.role = FieldType::NAME_LAST, .name = u""}, - {.role = FieldType::EMAIL_ADDRESS, .name = u""}, - {.role = FieldType::PHONE_HOME_NUMBER, .name = u""}, - {.label = u"Address", .name = u""}, - {.label = u"Address", .name = u""}, - {.role = FieldType::ADDRESS_HOME_ZIP, .name = u""}}}, + .fields = {{.role = FieldType::NAME_FIRST}, + {.role = FieldType::NAME_LAST}, + {.role = FieldType::EMAIL_ADDRESS}, + {.role = FieldType::PHONE_HOME_NUMBER}, + {.label = u"Address"}, + {.label = u"Address"}, + {.role = FieldType::ADDRESS_HOME_ZIP}}}, {.determine_heuristic_type = true, - .is_complete_credit_card_form = false}, + .is_complete_credit_card_form = std::make_pair( + FormStructure::CreditCardFormCompleteness::kCompleteCreditCardForm, + false)}, {}}}); } +TEST_F(FormStructureTestImpl, + IsCompleteCreditCardFormIncludingCvcAndName_CvcAndNameExist) { + CheckFormStructureTestData({{ + {.description_for_logging = + "IsCompleteCreditCardFormIncludingCvcAndName_CvcAndNameExist", + .fields = {{.role = CREDIT_CARD_NUMBER}, + {.label = u"Expiration"}, + {.label = u"Verification"}, + {.label = u"Name on Card"}}}, + {.determine_heuristic_type = true, + .is_complete_credit_card_form = + std::make_pair(FormStructure::CreditCardFormCompleteness:: + kCompleteCreditCardFormIncludingCvcAndName, + true)}, + }}); +} + +TEST_F(FormStructureTestImpl, + IsCompleteCreditCardFormIncludingCvcAndName_MissingCvc) { + CheckFormStructureTestData({{ + {.description_for_logging = + "IsCompleteCreditCardFormIncludingCvcAndName_MissingCvc", + .fields = {{.role = CREDIT_CARD_NUMBER}, + {.label = u"Expiration"}, + {.label = u"Name on Card"}}}, + {.determine_heuristic_type = true, + .is_complete_credit_card_form = + std::make_pair(FormStructure::CreditCardFormCompleteness:: + kCompleteCreditCardFormIncludingCvcAndName, + false)}, + }}); +} + +TEST_F(FormStructureTestImpl, + IsCompleteCreditCardFormIncludingCvcAndName_MissingName) { + CheckFormStructureTestData({{ + {.description_for_logging = + "IsCompleteCreditCardFormIncludingCvcAndName_MissingName", + .fields = {{.role = CREDIT_CARD_NUMBER}, + {.label = u"Expiration"}, + {.label = u"Verification"}}}, + {.determine_heuristic_type = true, + .is_complete_credit_card_form = + std::make_pair(FormStructure::CreditCardFormCompleteness:: + kCompleteCreditCardFormIncludingCvcAndName, + false)}, + }}); +} + +TEST_F(FormStructureTestImpl, + IsCompleteCreditCardFormIncludingCvcAndName_FirstAndLastNames) { + CheckFormStructureTestData({{ + {.description_for_logging = + "IsCompleteCreditCardFormIncludingCvcAndName_FirstAndLastNames", + .fields = {{.role = CREDIT_CARD_NUMBER}, + {.label = u"Expiration"}, + {.label = u"Verification"}, + {.label = u"first name"}, + {.label = u"last name"}}}, + {.determine_heuristic_type = true, + .is_complete_credit_card_form = + std::make_pair(FormStructure::CreditCardFormCompleteness:: + kCompleteCreditCardFormIncludingCvcAndName, + true)}, + }}); +} + // Verify that we can correctly process the 'autocomplete' attribute for phone // number types (especially phone prefixes and suffixes). TEST_F(FormStructureTestImpl, HeuristicsAutocompleteAttributePhoneTypes) {
diff --git a/components/autofill/core/browser/foundations/autofill_client.cc b/components/autofill/core/browser/foundations/autofill_client.cc index 403d535c7..7b00f7363d 100644 --- a/components/autofill/core/browser/foundations/autofill_client.cc +++ b/components/autofill/core/browser/foundations/autofill_client.cc
@@ -210,4 +210,9 @@ void AutofillClient::TriggerPlusAddressUserPerceptionSurvey( plus_addresses::hats::SurveyType survey_type) {} +const syncer::SyncService* AutofillClient::GetSyncService() const { + return const_cast<const syncer::SyncService*>( + const_cast<AutofillClient*>(this)->GetSyncService()); +} + } // namespace autofill
diff --git a/components/autofill/core/browser/foundations/autofill_client.h b/components/autofill/core/browser/foundations/autofill_client.h index 4ed72c0..6258e50 100644 --- a/components/autofill/core/browser/foundations/autofill_client.h +++ b/components/autofill/core/browser/foundations/autofill_client.h
@@ -327,6 +327,7 @@ // Gets the sync service associated with the client. virtual syncer::SyncService* GetSyncService() = 0; + const syncer::SyncService* GetSyncService() const; // Gets the IdentityManager associated with the client. virtual signin::IdentityManager* GetIdentityManager() = 0;
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.cc b/components/autofill/core/browser/foundations/browser_autofill_manager.cc index c63d5d5..20ebd71 100644 --- a/components/autofill/core/browser/foundations/browser_autofill_manager.cc +++ b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
@@ -179,7 +179,8 @@ if (form_structure.developer_engagement_metrics()) { AutofillMetrics::LogDeveloperEngagementUkm( ukm_recorder, source_id, form_structure.main_frame_origin().GetURL(), - form_structure.IsCompleteCreditCardForm(), + form_structure.IsCompleteCreditCardForm( + FormStructure::CreditCardFormCompleteness::kCompleteCreditCardForm), autofill_metrics::GetFormTypesForLogging(form_structure), form_structure.developer_engagement_metrics(), form_structure.form_signature());
diff --git a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.cc b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.cc index e07f86a..c6a8164 100644 --- a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.cc +++ b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.cc
@@ -907,6 +907,9 @@ return bnpl_suggestion; } +// Used to manually enable credit card upload in tests. +std::optional<bool> credit_card_upload_enabled_test_; + } // namespace std::vector<Suggestion> GetSuggestionsForCreditCards( @@ -918,6 +921,22 @@ bool should_show_cards_from_account, const std::vector<std::string>& four_digit_combinations_in_dom, const std::u16string& autofilled_last_four_digits_in_form_for_filtering) { + std::vector<Suggestion> suggestions; + if (client.GetPersonalDataManager() + .payments_data_manager() + .GetCreditCards() + .empty() && + base::FeatureList::IsEnabled(features::kAutofillEnableSaveAndFill)) { + bool display_gpay_logo = false; + suggestions.push_back( + CreateSaveAndFillSuggestion(client, display_gpay_logo)); + base::ranges::move( + GetCreditCardFooterSuggestions( + should_show_scan_credit_card, should_show_cards_from_account, + trigger_field.is_autofilled(), display_gpay_logo), + std::back_inserter(suggestions)); + return suggestions; + } // Only trigger GetVirtualCreditCardsForStandaloneCvcField if it's standalone // CVC field. base::flat_map<std::string, VirtualCardUsageData::VirtualCardLastFour> @@ -931,7 +950,6 @@ // Non-empty virtual_card_guid_to_last_four_map indicates this is standalone // CVC form AND there is matched VCN (based on the VCN usages and last four // from the DOM). - std::vector<Suggestion> suggestions; if (!virtual_card_guid_to_last_four_map.empty()) { suggestions = GetVirtualCardStandaloneCvcFieldSuggestions( client, trigger_field, summary.metadata_logging_context, @@ -1257,6 +1275,23 @@ /*with_gpay_logo=*/false); } +Suggestion CreateSaveAndFillSuggestion(const AutofillClient& client, + bool& display_gpay_logo) { + Suggestion save_and_fill( + l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_AND_FILL_SUGGESTION_TITLE), + SuggestionType::kSaveAndFillCreditCardEntry); + if (IsCreditCardUploadEnabled(client)) { + save_and_fill.labels = {{Suggestion::Text(l10n_util::GetStringUTF16( + IDS_AUTOFILL_SERVER_SAVE_AND_FILL_SUGGESTION_DESCRIPTION))}}; + display_gpay_logo = true; + } else { + save_and_fill.labels = {{Suggestion::Text(l10n_util::GetStringUTF16( + IDS_AUTOFILL_LOCAL_SAVE_AND_FILL_SUGGESTION_DESCRIPTION))}}; + } + save_and_fill.icon = Suggestion::Icon::kSaveAndFill; + return save_and_fill; +} + std::vector<Suggestion> GetSuggestionsForIbans(const std::vector<Iban>& ibans) { if (ibans.empty()) { return {}; @@ -1360,6 +1395,21 @@ return suggestions; } +bool IsCreditCardUploadEnabled(const AutofillClient& client) { + if (credit_card_upload_enabled_test_.has_value()) { + return credit_card_upload_enabled_test_.value(); + } + return ::autofill::IsCreditCardUploadEnabled( + client.GetSyncService(), *client.GetPrefs(), + client.GetPersonalDataManager() + .payments_data_manager() + .GetCountryCodeForExperimentGroup(), + client.GetPersonalDataManager() + .payments_data_manager() + .GetPaymentsSigninStateForMetrics(), + const_cast<AutofillClient*>(&client)->GetCurrentLogManager()); +} + bool IsCardSuggestionAcceptable(const CreditCard& card, const AutofillClient& client) { if (card.record_type() == CreditCard::RecordType::kVirtualCard) { @@ -1482,6 +1532,10 @@ is_autofilled, with_gpay_logo); } +void SetCreditCardUploadEnabledForTest(bool credit_card_upload_enabled) { + credit_card_upload_enabled_test_ = credit_card_upload_enabled; +} + bool ShouldShowVirtualCardOptionForTest(const CreditCard* candidate_card, const AutofillClient& client) { return ShouldShowVirtualCardOption(candidate_card, client);
diff --git a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.h b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.h index 3babbe3..b6c1ad21 100644 --- a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.h +++ b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator.h
@@ -133,6 +133,14 @@ // `SuggestionType`. This distinction is needed for metrics recording. Suggestion CreateManageIbansSuggestion(); +// Generates a "Save and Fill" suggestion for users who don't have any cards +// saved in Autofill. This suggestion is shown above the footer. +// `display_gpay_logo` is an output parameter that is set to true if credit +// card upload is enabled, indicating that the GPay logo should be displayed +// with the suggestion. +Suggestion CreateSaveAndFillSuggestion(const AutofillClient& client, + bool& display_gpay_logo); + // Generates suggestions for all available IBANs. std::vector<Suggestion> GetSuggestionsForIbans(const std::vector<Iban>& ibans); @@ -141,6 +149,10 @@ std::vector<Suggestion> GetPromoCodeSuggestionsFromPromoCodeOffers( const std::vector<const AutofillOfferData*>& promo_code_offers); +// Returns true if all the conditions for enabling the upload of credit card +// are satisfied. +bool IsCreditCardUploadEnabled(const AutofillClient& client); + // Returns true if the suggestion created from the card can be accepted by the // user. Returns false when merchant does not accept the given card for example // when merchants opt-out of VCNs. @@ -181,6 +193,8 @@ bool is_autofilled, bool with_gpay_logo); +void SetCreditCardUploadEnabledForTest(bool credit_card_upload_enabled); + // Exposes `ShouldShowVirtualCardOption` in tests. bool ShouldShowVirtualCardOptionForTest(const CreditCard* candidate_card, const AutofillClient& client);
diff --git a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc index 06732d5..9b7508c 100644 --- a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc +++ b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc
@@ -1722,6 +1722,101 @@ SuggestionType::kMerchantPromoCodeEntry); } +TEST_F(PaymentsSuggestionGeneratorTest, + GenerateLocalSaveAndFillSuggestion_CreditCardUploadDisabled) { + base::test::ScopedFeatureList scoped_feature_list( + features::kAutofillEnableSaveAndFill); + SetCreditCardUploadEnabledForTest(/*credit_card_upload_enabled=*/false); + + CreditCardSuggestionSummary summary; + std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards( + *autofill_client(), FormFieldData(), CREDIT_CARD_NUMBER, summary, + /*should_show_scan_credit_card=*/false, + /*should_show_cards_from_account=*/false, + /*four_digit_combinations_in_dom=*/{}, + /*autofilled_last_four_digits_in_form_for_filtering=*/u""); + + // `suggestions` should contain 3 suggestions which are save and fill + // suggestion, separator, and manage cards footer. + ASSERT_GE(suggestions.size(), 3ul); + EXPECT_THAT( + suggestions[0], + EqualsSuggestion( + SuggestionType::kSaveAndFillCreditCardEntry, + l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_AND_FILL_SUGGESTION_TITLE), + Suggestion::Icon::kSaveAndFill, + {{Suggestion::Text(l10n_util::GetStringUTF16( + IDS_AUTOFILL_LOCAL_SAVE_AND_FILL_SUGGESTION_DESCRIPTION))}})); + EXPECT_THAT(suggestions, + ContainsCreditCardFooterSuggestions(/*with_gpay_logo=*/false)); +} + +TEST_F(PaymentsSuggestionGeneratorTest, + GenerateServerSaveAndFillSuggestion_CreditCardUploadEnabled) { + base::test::ScopedFeatureList scoped_feature_list( + features::kAutofillEnableSaveAndFill); + SetCreditCardUploadEnabledForTest(/*credit_card_upload_enabled=*/true); + + CreditCardSuggestionSummary summary; + std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards( + *autofill_client(), FormFieldData(), CREDIT_CARD_NUMBER, summary, + /*should_show_scan_credit_card=*/false, + /*should_show_cards_from_account=*/false, + /*four_digit_combinations_in_dom=*/{}, + /*autofilled_last_four_digits_in_form_for_filtering=*/u""); + + // `suggestions` should contain 3 suggestions which are save and fill + // suggestion, separator, and manage cards footer. + ASSERT_GE(suggestions.size(), 3ul); + EXPECT_THAT( + suggestions[0], + EqualsSuggestion( + SuggestionType::kSaveAndFillCreditCardEntry, + l10n_util::GetStringUTF16( + IDS_AUTOFILL_SAVE_AND_FILL_SUGGESTION_TITLE), + Suggestion::Icon::kSaveAndFill, + {{Suggestion::Text(l10n_util::GetStringUTF16( + IDS_AUTOFILL_SERVER_SAVE_AND_FILL_SUGGESTION_DESCRIPTION))}})); + EXPECT_THAT(suggestions, + ContainsCreditCardFooterSuggestions(/*with_gpay_logo=*/true)); +} + +TEST_F(PaymentsSuggestionGeneratorTest, + GenerateLocalSaveAndFillSuggestion_FlagDisabled) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature( + features::kAutofillEnableSaveAndFill); + + CreditCardSuggestionSummary summary; + std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards( + *autofill_client(), FormFieldData(), CREDIT_CARD_NUMBER, summary, + /*should_show_scan_credit_card=*/false, + /*should_show_cards_from_account=*/false, + /*four_digit_combinations_in_dom=*/{}, + /*autofilled_last_four_digits_in_form_for_filtering=*/u""); + + ASSERT_GE(suggestions.size(), 0ul); +} + +TEST_F(PaymentsSuggestionGeneratorTest, + SaveAndFillSuggestion_NotOfferedWhenCreditCardIsSavedInProfile) { + base::test::ScopedFeatureList scoped_feature_list( + features::kAutofillEnableSaveAndFill); + + payments_data().AddCreditCard(test::GetCreditCard()); + CreditCardSuggestionSummary summary; + std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards( + *autofill_client(), FormFieldData(), CREDIT_CARD_NUMBER, summary, + /*should_show_scan_credit_card=*/false, + /*should_show_cards_from_account=*/false, + /*four_digit_combinations_in_dom=*/{}, + /*autofilled_last_four_digits_in_form_for_filtering=*/u""); + + EXPECT_EQ(suggestions.size(), 3ul); + EXPECT_THAT(suggestions[0], + EqualsSuggestion(SuggestionType::kCreditCardEntry)); +} // This class helps test the credit card contents that are displayed in // Autofill suggestions. It covers suggestions on Desktop/Android dropdown, // and on Android keyboard accessory.
diff --git a/components/autofill/core/browser/suggestions/suggestion.cc b/components/autofill/core/browser/suggestions/suggestion.cc index 932e891..27f90a6d 100644 --- a/components/autofill/core/browser/suggestions/suggestion.cc +++ b/components/autofill/core/browser/suggestions/suggestion.cc
@@ -116,6 +116,8 @@ return "kNoIcon"; case Suggestion::Icon::kBnpl: return "kBnpl"; + case Suggestion::Icon::kSaveAndFill: + return "kSaveAndFill"; } NOTREACHED(); }
diff --git a/components/autofill/core/browser/suggestions/suggestion.h b/components/autofill/core/browser/suggestions/suggestion.h index 73ace513..d0566088 100644 --- a/components/autofill/core/browser/suggestions/suggestion.h +++ b/components/autofill/core/browser/suggestions/suggestion.h
@@ -275,6 +275,7 @@ kIban, kBnpl, kAutofillAi, + kSaveAndFill, }; // This enum is used to control filtration of suggestions (see it's used in
diff --git a/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc b/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc index 31d106f..46c3300 100644 --- a/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc +++ b/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc
@@ -217,8 +217,10 @@ } if (test_case.form_flags.is_complete_credit_card_form.has_value()) { - EXPECT_EQ(form_structure->IsCompleteCreditCardForm(), - *test_case.form_flags.is_complete_credit_card_form); + auto [completeness, expected_result] = + *test_case.form_flags.is_complete_credit_card_form; + EXPECT_EQ(form_structure->IsCompleteCreditCardForm(completeness), + expected_result); } if (test_case.form_flags.field_count) { ASSERT_EQ(*test_case.form_flags.field_count,
diff --git a/components/autofill/core/browser/test_utils/autofill_form_test_utils.h b/components/autofill/core/browser/test_utils/autofill_form_test_utils.h index ee15e80..efb8681 100644 --- a/components/autofill/core/browser/test_utils/autofill_form_test_utils.h +++ b/components/autofill/core/browser/test_utils/autofill_form_test_utils.h
@@ -6,10 +6,12 @@ #define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_UTILS_AUTOFILL_FORM_TEST_UTILS_H_ #include <optional> +#include <utility> #include <vector> #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/common/autocomplete_parsing_util.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" @@ -92,8 +94,12 @@ bool should_be_queried = false; bool should_be_uploaded = false; bool has_author_specified_types = false; - // The implicit default value `std::nullopt` means no checking. - std::optional<bool> is_complete_credit_card_form; + // The implicit default value `std::nullopt` means no checking. The first + // value is the argument for `IsCompleteCreditCardForm()` specifying the + // required completeness level of the credit card form. The second value is + // the expected result of `IsCompleteCreditCardForm()`. + std::optional<std::pair<FormStructure::CreditCardFormCompleteness, bool>> + is_complete_credit_card_form; std::optional<int> field_count; std::optional<int> autofill_count; std::optional<int> section_count;
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp index 68d639f..343e406 100644 --- a/components/autofill_strings.grdp +++ b/components/autofill_strings.grdp
@@ -223,6 +223,18 @@ Show cards from your Google Account </message> + <message name="IDS_AUTOFILL_SAVE_AND_FILL_SUGGESTION_TITLE" desc="Title for the `Save and Fill` suggestion shown in the Autofill dropdown for users who don't have any cards saved in Autofill. When the suggestion is clicked, users are offered to save and fill a credit card with a single click."> + Save card for faster checkout + </message> + + <message name="IDS_AUTOFILL_LOCAL_SAVE_AND_FILL_SUGGESTION_DESCRIPTION" desc="Description for the local `Save and Fill` suggestion shown in the Autofill dropdown for users who don't have any cards saved in Autofill. When the suggestion is clicked, users are offered to save and fill a credit card with a single click"> + Autofill next time. Card is saved on your device. + </message> + + <message name="IDS_AUTOFILL_SERVER_SAVE_AND_FILL_SUGGESTION_DESCRIPTION" desc="Description for the server `Save and Fill` suggestion shown in the Autofill dropdown for users who don't have any cards saved in Autofill. When the suggestion is clicked, users are offered to save and fill a credit card with a single click"> + Autofill next time. Card is encrypted when saved. + </message> + <if expr="not is_android"> <message name="IDS_AUTOFILL_POPUP_ACCESSIBLE_NODE_DATA" desc="The accessibility text to speak when we display an autofill popup."> Autofill
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_LOCAL_SAVE_AND_FILL_SUGGESTION_DESCRIPTION.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_LOCAL_SAVE_AND_FILL_SUGGESTION_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..8fe81c0 --- /dev/null +++ b/components/autofill_strings_grdp/IDS_AUTOFILL_LOCAL_SAVE_AND_FILL_SUGGESTION_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +097afa3b0efd3962a6363120266ee65ec1e6b845 \ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_SUGGESTION_TITLE.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_SUGGESTION_TITLE.png.sha1 new file mode 100644 index 0000000..29f1e386 --- /dev/null +++ b/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_AND_FILL_SUGGESTION_TITLE.png.sha1
@@ -0,0 +1 @@ +5b9ede374f6c0ecd633d0f6d62b5fed894bf8137 \ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_SERVER_SAVE_AND_FILL_SUGGESTION_DESCRIPTION.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_SERVER_SAVE_AND_FILL_SUGGESTION_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..8ca44ec --- /dev/null +++ b/components/autofill_strings_grdp/IDS_AUTOFILL_SERVER_SAVE_AND_FILL_SUGGESTION_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +e5c91ec05258e56ea4bdbaaf8a71fa6cf5101360 \ No newline at end of file
diff --git a/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomCoordinator.java b/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomCoordinator.java index b32ced3e..5be5d3d 100644 --- a/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomCoordinator.java +++ b/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomCoordinator.java
@@ -162,7 +162,7 @@ /** Clean-up views and children during destruction. */ public void destroy() { if (mWebContentsObserver != null) { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); } if (mView != null) {
diff --git a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetObserverTest.java b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetObserverTest.java index ed8e0bf..26c6a410 100644 --- a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetObserverTest.java +++ b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetObserverTest.java
@@ -9,7 +9,6 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; -import android.graphics.Color; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -130,8 +129,7 @@ new ScrimCoordinator( sTestRule.getActivity(), /* systemUiScrimDelegate= */ null, - rootView, - Color.WHITE); + rootView); Supplier<ScrimCoordinator> scrimSupplier = () -> mScrimCoordinator; Callback<View> initializedCallback = (v) -> {}; return new BottomSheetControllerImpl(
diff --git a/components/browser_ui/display_cutout/android/java/src/org/chromium/components/browser_ui/display_cutout/DisplayCutoutController.java b/components/browser_ui/display_cutout/android/java/src/org/chromium/components/browser_ui/display_cutout/DisplayCutoutController.java index 33ea65fb..09521f8 100644 --- a/components/browser_ui/display_cutout/android/java/src/org/chromium/components/browser_ui/display_cutout/DisplayCutoutController.java +++ b/components/browser_ui/display_cutout/android/java/src/org/chromium/components/browser_ui/display_cutout/DisplayCutoutController.java
@@ -223,7 +223,7 @@ updateInsetObserver(null); updateBrowserCutoutObserver(null); if (mWebContentsObserver != null) { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; } mWindow = null; @@ -271,7 +271,7 @@ } if (mWebContentsObserver != null) { - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; }
diff --git a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java index 4512c08..6b1211b 100644 --- a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java +++ b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java
@@ -289,7 +289,7 @@ mWebContents = webContents; - if (mWebContentsObserver != null) mWebContentsObserver.destroy(); + if (mWebContentsObserver != null) mWebContentsObserver.observe(null); mMediaImageManager.setWebContents(mWebContents); @@ -428,7 +428,7 @@ public void destroy() { cleanupMediaSessionObserver(); hideNotificationImmediately(); - if (mWebContentsObserver != null) mWebContentsObserver.destroy(); + if (mWebContentsObserver != null) mWebContentsObserver.observe(null); mWebContentsObserver = null; if (mLargeIconBridge != null) mLargeIconBridge.destroy(); mLargeIconBridge = null;
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimCoordinator.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimCoordinator.java index 6e68395..6bd009f 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimCoordinator.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimCoordinator.java
@@ -10,9 +10,11 @@ import androidx.annotation.ColorInt; import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; import org.chromium.base.ObserverList; import org.chromium.base.supplier.Supplier; +import org.chromium.components.browser_ui.widget.R; import org.chromium.ui.UiUtils; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModelChangeProcessor; @@ -99,13 +101,13 @@ * @param context An Android {@link Context} for creating the view. * @param systemUiScrimDelegate A means of changing the scrim over the system UI. * @param parent The {@link ViewGroup} the scrim should exist in. - * @param defaultColor The default color of the scrim. */ public ScrimCoordinator( Context context, @Nullable SystemUiScrimDelegate systemUiScrimDelegate, - ViewGroup parent, - @ColorInt int defaultColor) { + ViewGroup parent) { + @ColorInt + int defaultScrimColor = ContextCompat.getColor(context, R.color.default_scrim_color); mMediator = new ScrimMediator( () -> { @@ -114,14 +116,20 @@ mView = null; mChangeProcessor = null; }, - systemUiScrimDelegate); + systemUiScrimDelegate, + defaultScrimColor); mScrimViewBuilder = () -> { - ScrimView view = new ScrimView(context, parent, defaultColor); + ScrimView view = new ScrimView(context, parent); return view; }; } + /** Returns the default scrim color, not the currently shown color. */ + public @ColorInt int getDefaultScrimColor() { + return mMediator.getDefaultScrimColor(); + } + /** * Show the scrim. * @@ -198,12 +206,18 @@ /** * Manually set the alpha for the scrim. + * * @param alpha The alpha in range [0, 1]. */ public void setAlpha(float alpha) { + // TODO(skym): This method should take a PropertyModel as well. mMediator.setAlpha(alpha); } + public void setScrimColor(@ColorInt int scrimColor, PropertyModel propertyModel) { + mMediator.setScrimColor(scrimColor, propertyModel); + } + /** Clean up this coordinator. */ public void destroy() { mMediator.destroy();
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimMediator.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimMediator.java index ba8514f..7bdb34fb 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimMediator.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimMediator.java
@@ -18,10 +18,9 @@ import org.chromium.base.MathUtils; import org.chromium.components.browser_ui.widget.animation.CancelAwareAnimatorListener; import org.chromium.ui.interpolators.Interpolators; -import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; -import org.chromium.ui.modelutil.PropertyObservable; -import org.chromium.ui.modelutil.PropertyObservable.PropertyObserver; + +import java.util.Objects; /** This class holds the animation and related business logic for the scrim. */ class ScrimMediator implements ScrimCoordinator.TouchEventDelegate { @@ -31,7 +30,7 @@ /** A means of changing the system UI color. */ private final @Nullable ScrimCoordinator.SystemUiScrimDelegate mSystemUiScrimDelegate; - private final PropertyObserver<PropertyKey> mOnModelChange = this::onModelChange; + private final @ColorInt int mDefaultScrimColor; /** The animator for fading the view in. */ private ValueAnimator mOverlayFadeInAnimator; @@ -59,12 +58,20 @@ /** * @param scrimHiddenRunnable A mechanism for hiding the scrim. * @param systemUiScrimDelegate A means of changing the scrim over the system UI. + * @param defaultScrimColor The color of the scrim when not explicitly set. */ ScrimMediator( @NonNull Runnable scrimHiddenRunnable, - @Nullable ScrimCoordinator.SystemUiScrimDelegate systemUiScrimDelegate) { + @Nullable ScrimCoordinator.SystemUiScrimDelegate systemUiScrimDelegate, + @ColorInt int defaultScrimColor) { mScrimHiddenRunnable = scrimHiddenRunnable; mSystemUiScrimDelegate = systemUiScrimDelegate; + mDefaultScrimColor = defaultScrimColor; + } + + /* package */ @ColorInt + int getDefaultScrimColor() { + return mDefaultScrimColor; } /** Triggers a fade in of the scrim creating a new animation if necessary. */ @@ -79,21 +86,28 @@ assert model.get(ScrimProperties.ANCHOR_VIEW) != null : "The anchor for the scrim cannot be null."; - if (mModel != null && mSystemUiScrimDelegate != null) { - mModel.removeObserver(mOnModelChange); - } mModel = model; - if (mModel != null) { - mModel.set(ScrimProperties.TOUCH_EVENT_DELEGATE, this); - } + mModel.set(ScrimProperties.TOUCH_EVENT_DELEGATE, this); mIsHidingOrHidden = false; - // Pass the current scrim color to the SystemUiScrimDelegate. - if (mSystemUiScrimDelegate != null - && model.getAllSetProperties().contains(ScrimProperties.BACKGROUND_COLOR)) { - @ColorInt int color = model.get(ScrimProperties.BACKGROUND_COLOR); - mSystemUiScrimDelegate.setScrimColor(color); - mModel.addObserver(mOnModelChange); + // TODO(crbug.com/371034867): This flag and the usage of it should be deleted. This is + // currently needed because SigninAccountPickerCoordinator incorrectly consumes the color in + // its #setScrimColor() observer method. Once the scrim logic publishes more easily consumed + // color + alpha values things can be cleaned up. + boolean colorIsDefault = false; + + // When clients do not specify a background color, use the default. + if (mModel.get(ScrimProperties.BACKGROUND_COLOR) == ScrimProperties.INVALID_COLOR) { + mModel.set(ScrimProperties.BACKGROUND_COLOR, mDefaultScrimColor); + colorIsDefault = true; + } + + if (mSystemUiScrimDelegate != null) { + if (!colorIsDefault) { + // Pass the current scrim color to the SystemUiScrimDelegate. + @ColorInt int currentScrimColor = model.get(ScrimProperties.BACKGROUND_COLOR); + mSystemUiScrimDelegate.setScrimColor(currentScrimColor); + } } // Make sure alpha is reset to 0 since the model may be reused. @@ -128,15 +142,6 @@ runFadeAnimation(mOverlayFadeInAnimator); } - private void onModelChange( - PropertyObservable<PropertyKey> source, @Nullable PropertyKey propertyKey) { - assert mSystemUiScrimDelegate != null; - if (propertyKey == ScrimProperties.BACKGROUND_COLOR) { - @ColorInt int color = mModel.get(ScrimProperties.BACKGROUND_COLOR); - mSystemUiScrimDelegate.setScrimColor(color); - } - } - private int getAnimationDuration(int animDurationMs) { return mDisableAnimationForTesting ? 0 : animDurationMs; } @@ -229,16 +234,20 @@ mCurrentVisibility = isVisible; if (mIsHidingOrHidden && !isVisible && mModel != null) { - if (mSystemUiScrimDelegate != null) { - mModel.removeObserver(mOnModelChange); - } mModel = null; mScrimHiddenRunnable.run(); } } + /*package */ void setScrimColor(@ColorInt int scrimColor, PropertyModel propertyModel) { + if (!Objects.equals(mModel, propertyModel)) return; + mModel.set(ScrimProperties.BACKGROUND_COLOR, scrimColor); + mSystemUiScrimDelegate.setScrimColor(scrimColor); + } + /** * Runs an animation for this view. If one is running, the existing one will be canceled. + * * @param fadeAnimation The animation to run. */ private void runFadeAnimation(Animator fadeAnimation) {
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimProperties.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimProperties.java index 1b97c1b..ebf44fc 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimProperties.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimProperties.java
@@ -60,7 +60,7 @@ /* package */ static final WritableFloatPropertyKey ALPHA = new WritableFloatPropertyKey(); /** - * The background color for the scrim. If null, a default color will be set as the background. + * The background color for the scrim. If not set a default color will be set as the background. */ public static final WritableIntPropertyKey BACKGROUND_COLOR = new WritableIntPropertyKey();
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimTest.java index 45a90a7..52d305eeb 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimTest.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimTest.java
@@ -128,8 +128,7 @@ mAnchorView = new View(sActivity); sParent.addView(mAnchorView); - mScrimCoordinator = - new ScrimCoordinator(sActivity, mScrimDelegate, sParent, Color.RED); + mScrimCoordinator = new ScrimCoordinator(sActivity, mScrimDelegate, sParent); mDelegatedEventHelper = new CallbackHelper(); mCustomGestureDetector = @@ -233,7 +232,7 @@ assertScrimColor(Color.GREEN); assertEquals(Color.GREEN, mScrimColorCallbackHelper.getOnlyPayloadBlocking().intValue()); - ThreadUtils.runOnUiThreadBlocking(() -> model.set(BACKGROUND_COLOR, Color.RED)); + ThreadUtils.runOnUiThreadBlocking(() -> mScrimCoordinator.setScrimColor(Color.RED, model)); assertScrimColor(Color.RED); assertEquals(Color.RED, mScrimColorCallbackHelper.getPayloadByIndexBlocking(1).intValue()); }
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimView.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimView.java index 50544b4..8a49470 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimView.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimView.java
@@ -9,7 +9,6 @@ import android.view.View; import android.view.ViewGroup; -import androidx.annotation.ColorInt; import androidx.annotation.VisibleForTesting; import org.chromium.ui.UiUtils; @@ -23,9 +22,6 @@ /** The view that the scrim should exist in. */ private final ViewGroup mParent; - /** The default background color. */ - private final int mDefaultBackgroundColor; - /** A means of passing all touch events to an external handler. */ private ScrimCoordinator.TouchEventDelegate mEventDelegate; @@ -33,16 +29,14 @@ * @param context An Android {@link Context} for creating the view. * @param parent The {@link ViewGroup} the scrim should exist in. */ - public ScrimView(Context context, ViewGroup parent, @ColorInt int defaultColor) { + public ScrimView(Context context, ViewGroup parent) { super(context); mParent = parent; setFocusable(false); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); - mDefaultBackgroundColor = defaultColor; setAlpha(0.0f); setVisibility(View.GONE); - setBackgroundColor(mDefaultBackgroundColor); setLayoutParams( new ViewGroup.MarginLayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); @@ -79,12 +73,6 @@ } @Override - public void setBackgroundColor(@ColorInt int color) { - super.setBackgroundColor( - color == ScrimProperties.INVALID_COLOR ? mDefaultBackgroundColor : color); - } - - @Override public boolean onTouchEvent(MotionEvent e) { if (mEventDelegate != null && mEventDelegate.onTouchEvent(e)) return true; return super.onTouchEvent(e);
diff --git a/components/collaboration_strings.grdp b/components/collaboration_strings.grdp index 86bfd9d0..3bb01e7 100644 --- a/components/collaboration_strings.grdp +++ b/components/collaboration_strings.grdp
@@ -33,6 +33,15 @@ <message name ="IDS_COLLABORATION_SOMETHING_WENT_WRONG_BODY" desc="The body of of the error dialog something went wrong." formatter_data="android_java"> There was an error. Try again. </message> + <message name ="IDS_COLLABORATION_SHARE_SHEET_TITLE" desc="The title of the share sheet when sharing a tab group." formatter_data="android_java"> + Collaborate on tab group + </message> + <message name ="IDS_COLLABORATION_SHARE_SHEET_MESSAGE" desc="The contents of the message when sharing a tab group." formatter_data="android_java"> + <ph name="TAB_GROUP_DISPLAY_NAME">%1$s<ex>Vacation plan</ex></ph> link expires in 48 hours + </message> + <message name ="IDS_COLLABORATION_SHARE_SHEET_TAB_GROUP_FALLBACK_NAME" desc="Fallback name if the tab group was not named by the user." formatter_data="android_java"> + Shared tab group + </message> </if> <!-- Error Messages --> <!-- /Data Sharing -->
diff --git a/components/collaboration_strings_grdp/IDS_COLLABORATION_SHARE_SHEET_MESSAGE.png.sha1 b/components/collaboration_strings_grdp/IDS_COLLABORATION_SHARE_SHEET_MESSAGE.png.sha1 new file mode 100644 index 0000000..17b451e --- /dev/null +++ b/components/collaboration_strings_grdp/IDS_COLLABORATION_SHARE_SHEET_MESSAGE.png.sha1
@@ -0,0 +1 @@ +1d88990072450331fdf41d795b37e1144804c5d1 \ No newline at end of file
diff --git a/components/collaboration_strings_grdp/IDS_COLLABORATION_SHARE_SHEET_TAB_GROUP_FALLBACK_NAME.png.sha1 b/components/collaboration_strings_grdp/IDS_COLLABORATION_SHARE_SHEET_TAB_GROUP_FALLBACK_NAME.png.sha1 new file mode 100644 index 0000000..a1b0c239 --- /dev/null +++ b/components/collaboration_strings_grdp/IDS_COLLABORATION_SHARE_SHEET_TAB_GROUP_FALLBACK_NAME.png.sha1
@@ -0,0 +1 @@ +68a75e77993440ebe9f98e1a7afbc94c0c2eac8e \ No newline at end of file
diff --git a/components/collaboration_strings_grdp/IDS_COLLABORATION_SHARE_SHEET_TITLE.png.sha1 b/components/collaboration_strings_grdp/IDS_COLLABORATION_SHARE_SHEET_TITLE.png.sha1 new file mode 100644 index 0000000..17b451e --- /dev/null +++ b/components/collaboration_strings_grdp/IDS_COLLABORATION_SHARE_SHEET_TITLE.png.sha1
@@ -0,0 +1 @@ +1d88990072450331fdf41d795b37e1144804c5d1 \ No newline at end of file
diff --git a/components/commerce/core/mojom/product_specifications.mojom b/components/commerce/core/mojom/product_specifications.mojom index aac8d54d..e4643c1 100644 --- a/components/commerce/core/mojom/product_specifications.mojom +++ b/components/commerce/core/mojom/product_specifications.mojom
@@ -13,6 +13,11 @@ kV1 = 1, }; +enum ShowSetDisposition { + kInNewTabs = 0, + kInNewWindow = 1, +}; + // Browser-side handler for Compare-related requests from a WebUI page. interface ProductSpecificationsHandler { // Updates the user's accepted disclosure version for product specifications. @@ -39,10 +44,16 @@ // Show the product specifications set based on the uuid, `in_new_tab` // indicates whether the browser should open the set in a new tab or - // current tab. + // current tab. If in a new tab, the new tab will be focused. ShowProductSpecificationsSetForUuid(mojo_base.mojom.Uuid uuid, bool in_new_tab); + // Show the product specifications sets for the given uuids in either new tabs + // or a new browser window. If in new tabs, the tabs will be opened in the + // background. If in a new window, the window will be focused. + ShowProductSpecificationsSetsForUuids( + array<mojo_base.mojom.Uuid> uuids, ShowSetDisposition disposition); + // Show the chrome://compare page either in the current tab or a new tab. ShowComparePage(bool in_new_tab);
diff --git a/components/commerce/core/webui/product_specifications_handler.cc b/components/commerce/core/webui/product_specifications_handler.cc index b8b4006..0360287 100644 --- a/components/commerce/core/webui/product_specifications_handler.cc +++ b/components/commerce/core/webui/product_specifications_handler.cc
@@ -64,6 +64,16 @@ delegate_->ShowProductSpecificationsSetForUuid(uuid, in_new_tab); } +void ProductSpecificationsHandler::ShowProductSpecificationsSetsForUuids( + const std::vector<base::Uuid>& uuids, + const product_specifications::mojom::ShowSetDisposition disposition) { + if (!delegate_) { + return; + } + + delegate_->ShowProductSpecificationsSetsForUuids(uuids, disposition); +} + void ProductSpecificationsHandler::ShowComparePage(bool in_new_tab) { if (!delegate_) { return;
diff --git a/components/commerce/core/webui/product_specifications_handler.h b/components/commerce/core/webui/product_specifications_handler.h index 8543ebb..2158d626 100644 --- a/components/commerce/core/webui/product_specifications_handler.h +++ b/components/commerce/core/webui/product_specifications_handler.h
@@ -41,6 +41,14 @@ virtual void ShowProductSpecificationsSetForUuid(const base::Uuid& uuid, bool in_new_tab) = 0; + // Show the product specifications sets for the given UUIDs. The disposition + // indicates how the sets should be opened (i.e. in new tabs or in a new + // window). + virtual void ShowProductSpecificationsSetsForUuids( + const std::vector<base::Uuid>& uuids, + const product_specifications::mojom::ShowSetDisposition + disposition) = 0; + // Show the sync setup flow for Compare. virtual void ShowSyncSetupFlow() = 0; @@ -72,6 +80,10 @@ void ShowSyncSetupFlow() override; void ShowProductSpecificationsSetForUuid(const base::Uuid& uuid, bool in_new_tab) override; + void ShowProductSpecificationsSetsForUuids( + const std::vector<base::Uuid>& uuids, + const product_specifications::mojom::ShowSetDisposition disposition) + override; void ShowComparePage(bool in_new_tab) override; void GetPageTitleFromHistory( const GURL& url,
diff --git a/components/commerce/core/webui/product_specifications_handler_unittest.cc b/components/commerce/core/webui/product_specifications_handler_unittest.cc index f9fd1f1..c7fca15 100644 --- a/components/commerce/core/webui/product_specifications_handler_unittest.cc +++ b/components/commerce/core/webui/product_specifications_handler_unittest.cc
@@ -79,6 +79,12 @@ ShowProductSpecificationsSetForUuid, (const base::Uuid& uuid, bool in_new_tab), (override)); + MOCK_METHOD( + void, + ShowProductSpecificationsSetsForUuids, + (const std::vector<base::Uuid>& uuids, + const product_specifications::mojom::ShowSetDisposition disposition), + (override)); MOCK_METHOD(void, ShowSyncSetupFlow, (), (override)); MOCK_METHOD(void, ShowComparePage, (bool in_new_tab), (override)); }; @@ -290,4 +296,19 @@ handler_->ShowComparePage(true); } +TEST_F(ProductSpecificationsHandlerTest, + TestShowProductSpecificationsSetsForUuids) { + base::Uuid uuid_one = base::Uuid::GenerateRandomV4(); + base::Uuid uuid_two = base::Uuid::GenerateRandomV4(); + const auto disposition = + product_specifications::mojom::ShowSetDisposition::kInNewTabs; + + EXPECT_CALL(*delegate_, + ShowProductSpecificationsSetsForUuids( + testing::ElementsAre(uuid_one, uuid_two), disposition)) + .Times(1); + handler_->ShowProductSpecificationsSetsForUuids({uuid_one, uuid_two}, + disposition); +} + } // namespace commerce
diff --git a/components/commerce_strings.grdp b/components/commerce_strings.grdp index b85a46f..c4806d9 100644 --- a/components/commerce_strings.grdp +++ b/components/commerce_strings.grdp
@@ -688,9 +688,15 @@ <message name="IDS_COMPARE_CONTEXT_MENU_OPEN_IN_NEW_TAB" desc="The label for the comparison table list dropdown menu item for opening a comparison table in a new tab."> Open in new tab </message> + <message name="IDS_COMPARE_CONTEXT_MENU_OPEN_IN_NEW_WINDOW" desc="The label for the comparison table list dropdown menu item for opening a comparison table in a new window."> + Open in new window + </message> <message name="IDS_COMPARE_CONTEXT_MENU_OPEN_ALL_WITH_COUNT" desc="The label for the comparison table list dropdown menu item for opening comparison table(s) in new tab(s)."> Open all (<ph name="ITEMS">$1<ex>3</ex></ph>) </message> + <message name="IDS_COMPARE_CONTEXT_MENU_OPEN_ALL_IN_NEW_WINDOW_WITH_COUNT" desc="The label for the comparison table list dropdown menu item for opening comparison table(s) in a new window."> + Open all (<ph name="ITEMS">$1<ex>3</ex></ph>) in new window + </message> <message name="IDS_COMPARE_CONTEXT_MENU_RENAME" desc="The label for the comparison table list dropdown menu item for renaming a comparison table."> Rename </message>
diff --git a/components/commerce_strings_grdp/IDS_COMPARE_CONTEXT_MENU_OPEN_ALL_IN_NEW_WINDOW_WITH_COUNT.png.sha1 b/components/commerce_strings_grdp/IDS_COMPARE_CONTEXT_MENU_OPEN_ALL_IN_NEW_WINDOW_WITH_COUNT.png.sha1 new file mode 100644 index 0000000..c5d0559 --- /dev/null +++ b/components/commerce_strings_grdp/IDS_COMPARE_CONTEXT_MENU_OPEN_ALL_IN_NEW_WINDOW_WITH_COUNT.png.sha1
@@ -0,0 +1 @@ +4ff8f1b65813a85488a4c7e08f971ccd6ce2f508 \ No newline at end of file
diff --git a/components/commerce_strings_grdp/IDS_COMPARE_CONTEXT_MENU_OPEN_IN_NEW_WINDOW.png.sha1 b/components/commerce_strings_grdp/IDS_COMPARE_CONTEXT_MENU_OPEN_IN_NEW_WINDOW.png.sha1 new file mode 100644 index 0000000..9f19681 --- /dev/null +++ b/components/commerce_strings_grdp/IDS_COMPARE_CONTEXT_MENU_OPEN_IN_NEW_WINDOW.png.sha1
@@ -0,0 +1 @@ +898d972c5351959d96987d4d467dba68ce6f1a04 \ No newline at end of file
diff --git a/components/content_settings/browser/page_specific_content_settings.cc b/components/content_settings/browser/page_specific_content_settings.cc index f233b27..74c4992 100644 --- a/components/content_settings/browser/page_specific_content_settings.cc +++ b/components/content_settings/browser/page_specific_content_settings.cc
@@ -1290,9 +1290,6 @@ MaybeUpdateLocationBar(); } - // The PiP window does not support blocked indicators, hence there is no need - // to start a timer to display it. - if (!delegate_->IsPiPWindow(GetWebContents())) { // Camera and/or Mic is blocked, start a blocked indicator's dismiss timer. if (microphone_camera_state_.Has(kMicrophoneBlocked)) { StartBlockedIndicatorTimer(ContentSettingsType::MEDIASTREAM_MIC); @@ -1300,7 +1297,6 @@ if (microphone_camera_state_.Has(kCameraBlocked)) { StartBlockedIndicatorTimer(ContentSettingsType::MEDIASTREAM_CAMERA); } - } } void PageSpecificContentSettings::AddPermissionUsageObserver(
diff --git a/components/content_settings/browser/page_specific_content_settings.h b/components/content_settings/browser/page_specific_content_settings.h index c2eed88d..cbe284c1 100644 --- a/components/content_settings/browser/page_specific_content_settings.h +++ b/components/content_settings/browser/page_specific_content_settings.h
@@ -168,10 +168,6 @@ virtual content::WebContents* MaybeGetSyncedWebContentsForPictureInPicture( content::WebContents* web_contents) = 0; - // Returns `true` if `web_contents` represents a PiP window. Returns `false` - // otherwise. - virtual bool IsPiPWindow(content::WebContents* web_contents) = 0; - // Notifies the delegate a particular content settings type was allowed for // the first time on this page. virtual void OnContentAllowed(ContentSettingsType type) = 0;
diff --git a/components/content_settings/browser/test_page_specific_content_settings_delegate.cc b/components/content_settings/browser/test_page_specific_content_settings_delegate.cc index 2af19c5..22d4a20 100644 --- a/components/content_settings/browser/test_page_specific_content_settings_delegate.cc +++ b/components/content_settings/browser/test_page_specific_content_settings_delegate.cc
@@ -63,9 +63,4 @@ return false; } -bool TestPageSpecificContentSettingsDelegate::IsPiPWindow( - content::WebContents* web_contents) { - return false; -} - } // namespace content_settings
diff --git a/components/content_settings/browser/test_page_specific_content_settings_delegate.h b/components/content_settings/browser/test_page_specific_content_settings_delegate.h index 0b3d6c8c..6a01631 100644 --- a/components/content_settings/browser/test_page_specific_content_settings_delegate.h +++ b/components/content_settings/browser/test_page_specific_content_settings_delegate.h
@@ -36,7 +36,6 @@ bool IsBlockedOnSystemLevel(ContentSettingsType type) override; bool IsFrameAllowlistedForJavaScript( content::RenderFrameHost* render_frame_host) override; - bool IsPiPWindow(content::WebContents* web_contents) override; private: raw_ptr<PrefService> prefs_;
diff --git a/components/cronet/gn2bp/gen_android_bp.py b/components/cronet/gn2bp/gen_android_bp.py index 6d62750..6e06316 100755 --- a/components/cronet/gn2bp/gen_android_bp.py +++ b/components/cronet/gn2bp/gen_android_bp.py
@@ -2042,7 +2042,14 @@ module.handle_static_inline = True module.bindgen_flags = get_bindgen_flags(target.args) - module.header_libs = ["fake_header_libs"] + # This ensures that any CC file that is being processed through the + # rust_bindgen module is able to #include files relative to the root of the + # repository. + # + # Note: this module is not part of the generated build rules; it is expected + # to already be present in AOSP (currently, in Android.extras.bp). See + # https://r.android.com/3413202. + module.header_libs = ["cronet_repository_root_include_dirs_anchor"] module.min_sdk_version = 31 module.apex_available = [tethering_apex] blueprint.add_module(module)
diff --git a/components/cronet/tools/utils.py b/components/cronet/tools/utils.py index 48112591..a09dd7c9 100755 --- a/components/cronet/tools/utils.py +++ b/components/cronet/tools/utils.py
@@ -22,7 +22,7 @@ GN_PATH = os.path.join(REPOSITORY_ROOT, 'buildtools/linux64/gn') NINJA_PATH = os.path.join(REPOSITORY_ROOT, 'third_party/ninja/ninja') ARCHS = ['x86', 'x64', 'arm', 'arm64', 'riscv64'] -AOSP_EXTRA_ARGS = ('is_cronet_for_aosp_build=true', 'use_nss_certs=false') +AOSP_EXTRA_ARGS = ('is_cronet_for_aosp_build=true', 'use_nss_certs=false', 'use_allocator_shim=false') _GN_ARG_MATCHER = re.compile("^.*=.*$")
diff --git a/components/dbus/thread_linux/dbus_thread_linux.cc b/components/dbus/thread_linux/dbus_thread_linux.cc index 7bdd83c..c53eeca 100644 --- a/components/dbus/thread_linux/dbus_thread_linux.cc +++ b/components/dbus/thread_linux/dbus_thread_linux.cc
@@ -4,8 +4,10 @@ #include "components/dbus/thread_linux/dbus_thread_linux.h" +#include "base/no_destructor.h" #include "base/task/lazy_thread_pool_task_runner.h" #include "base/task/single_thread_task_runner.h" +#include "dbus/bus.h" namespace dbus_thread_linux { @@ -21,10 +23,38 @@ base::TaskTraits(base::MayBlock(), base::TaskPriority::USER_BLOCKING), base::SingleThreadTaskRunnerThreadMode::SHARED); +scoped_refptr<dbus::Bus> CreateSharedSessionBus() { + dbus::Bus::Options options; + options.bus_type = dbus::Bus::SESSION; + options.connection_type = dbus::Bus::PRIVATE; + options.dbus_task_runner = GetTaskRunner(); + return base::MakeRefCounted<dbus::Bus>(options); +} + +scoped_refptr<dbus::Bus> CreateSharedSystemBus() { + dbus::Bus::Options options; + options.bus_type = dbus::Bus::SYSTEM; + options.connection_type = dbus::Bus::PRIVATE; + options.dbus_task_runner = GetTaskRunner(); + return base::MakeRefCounted<dbus::Bus>(options); +} + } // namespace scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() { return g_dbus_thread_task_runner.Get(); } +scoped_refptr<dbus::Bus> GetSharedSessionBus() { + static base::NoDestructor<scoped_refptr<dbus::Bus>> bus( + CreateSharedSessionBus()); + return *bus; +} + +scoped_refptr<dbus::Bus> GetSharedSystemBus() { + static base::NoDestructor<scoped_refptr<dbus::Bus>> bus( + CreateSharedSystemBus()); + return *bus; +} + } // namespace dbus_thread_linux
diff --git a/components/dbus/thread_linux/dbus_thread_linux.h b/components/dbus/thread_linux/dbus_thread_linux.h index b5f849b..ed6d513 100644 --- a/components/dbus/thread_linux/dbus_thread_linux.h +++ b/components/dbus/thread_linux/dbus_thread_linux.h
@@ -19,12 +19,27 @@ #error On ChromeOS, use DBusThreadManager instead. #endif +namespace dbus { +class Bus; +} + namespace dbus_thread_linux { // Obtains a task runner to handle DBus IO for usage on desktop Linux. COMPONENT_EXPORT(COMPONENTS_DBUS) scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(); +// Obtains a shared session bus for usage on desktop Linux. The task runner is +// the same as the one obtained from GetTaskRunner(). This should be used for +// all session bus operations except for those that require a named connection +// (currently MPRIS is the only one). Must be called on the UI thread. +COMPONENT_EXPORT(COMPONENTS_DBUS) +scoped_refptr<dbus::Bus> GetSharedSessionBus(); + +// The same as GetSharedSessionBus(), but for the system bus. +COMPONENT_EXPORT(COMPONENTS_DBUS) +scoped_refptr<dbus::Bus> GetSharedSystemBus(); + } // namespace dbus_thread_linux #endif // COMPONENTS_DBUS_THREAD_LINUX_DBUS_THREAD_LINUX_H_
diff --git a/components/device_signals/core/BUILD.gn b/components/device_signals/core/BUILD.gn index 9b0b4db..ec43529 100644 --- a/components/device_signals/core/BUILD.gn +++ b/components/device_signals/core/BUILD.gn
@@ -6,7 +6,6 @@ testonly = true deps = [ "//components/device_signals/core/browser:unit_tests", - "//components/device_signals/core/common:unit_tests", "//components/device_signals/core/system_signals:unit_tests", ] }
diff --git a/components/device_signals/core/common/BUILD.gn b/components/device_signals/core/common/BUILD.gn index a92d72b..6a4e099f 100644 --- a/components/device_signals/core/common/BUILD.gn +++ b/components/device_signals/core/common/BUILD.gn
@@ -39,20 +39,3 @@ public_deps = [ "//base" ] } - -source_set("unit_tests") { - testonly = true - sources = [ "signals_features_unittest.cc" ] - - deps = [ - ":common", - ":features", - "//base", - "//base/test:test_support", - "//testing/gmock", - "//testing/gtest", - ] - if (is_win) { - deps += [ "//components/device_signals/core/common/win:unit_tests" ] - } -}
diff --git a/components/device_signals/core/common/signals_features.cc b/components/device_signals/core/common/signals_features.cc index f40e632..7a18aec 100644 --- a/components/device_signals/core/common/signals_features.cc +++ b/components/device_signals/core/common/signals_features.cc
@@ -10,45 +10,6 @@ "AllowClientCertificateReportingForUsers", base::FEATURE_ENABLED_BY_DEFAULT); -BASE_FEATURE(kNewEvSignalsEnabled, - "NewEvSignalsEnabled", - base::FEATURE_ENABLED_BY_DEFAULT); - -const base::FeatureParam<bool> kDisableFileSystemInfo{ - &kNewEvSignalsEnabled, "DisableFileSystemInfo", false}; -const base::FeatureParam<bool> kDisableSettings{&kNewEvSignalsEnabled, - "DisableSettings", false}; -const base::FeatureParam<bool> kDisableAntiVirus{&kNewEvSignalsEnabled, - "DisableAntiVirus", false}; -const base::FeatureParam<bool> kDisableHotfix{&kNewEvSignalsEnabled, - "DisableHotfix", false}; - -bool IsNewFunctionEnabled(NewEvFunction new_ev_function) { - // AntiVirus and Hotfix are considered "Launched". So only rely on the value - // of the kill-switch to control the feature's behavior. - bool disable_function = false; - switch (new_ev_function) { - case NewEvFunction::kFileSystemInfo: - disable_function = kDisableFileSystemInfo.Get(); - break; - case NewEvFunction::kSettings: - disable_function = kDisableSettings.Get(); - break; - case NewEvFunction::kAntiVirus: - disable_function = kDisableAntiVirus.Get(); - break; - case NewEvFunction::kHotfix: - disable_function = kDisableHotfix.Get(); - break; - } - - if (!base::FeatureList::IsEnabled(kNewEvSignalsEnabled)) { - return false; - } - - return !disable_function; -} - #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \ BUILDFLAG(IS_CHROMEOS) // Enables the triggering of device signals consent dialog when conditions met
diff --git a/components/device_signals/core/common/signals_features.h b/components/device_signals/core/common/signals_features.h index 53eaa28..1f87333 100644 --- a/components/device_signals/core/common/signals_features.h +++ b/components/device_signals/core/common/signals_features.h
@@ -13,23 +13,6 @@ // Allows the reporting of client certificates for managed users. BASE_DECLARE_FEATURE(kAllowClientCertificateReportingForUsers); -// Feature flag for new private SecureConnect functions exposing additional -// device signals. -BASE_DECLARE_FEATURE(kNewEvSignalsEnabled); - -// Feature parameters that can be used to turn off individual functions. -extern const base::FeatureParam<bool> kDisableFileSystemInfo; -extern const base::FeatureParam<bool> kDisableSettings; -extern const base::FeatureParam<bool> kDisableAntiVirus; -extern const base::FeatureParam<bool> kDisableHotfix; - -// Enum used to map a given function to its kill switch. -enum class NewEvFunction { kFileSystemInfo, kSettings, kAntiVirus, kHotfix }; - -// Returns true if the function pointed at by `new_ev_function` is considered -// to be enabled based on the feature flag and its parameters. -bool IsNewFunctionEnabled(NewEvFunction new_ev_function); - #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \ BUILDFLAG(IS_CHROMEOS) BASE_DECLARE_FEATURE(kDeviceSignalsConsentDialog);
diff --git a/components/device_signals/core/common/signals_features_unittest.cc b/components/device_signals/core/common/signals_features_unittest.cc deleted file mode 100644 index 82b26b4..0000000 --- a/components/device_signals/core/common/signals_features_unittest.cc +++ /dev/null
@@ -1,89 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/device_signals/core/common/signals_features.h" - -#include "base/test/scoped_feature_list.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace enterprise_signals::features { - -class SignalsFeaturesTest : public testing::Test { - protected: - const int min_enum_value_ = static_cast<int>(NewEvFunction::kFileSystemInfo); - const int max_enum_value_ = static_cast<int>(NewEvFunction::kHotfix); - base::test::ScopedFeatureList scoped_features_; -}; - -// Tests that IsNewFunctionEnabled will return false when the feature flag is -// disabled. -TEST_F(SignalsFeaturesTest, DisabledFeature) { - scoped_features_.InitAndDisableFeature(kNewEvSignalsEnabled); - for (int i = min_enum_value_; i <= max_enum_value_; i++) { - EXPECT_FALSE(IsNewFunctionEnabled(static_cast<NewEvFunction>(i))); - } -} - -// Tests that IsNewFunctionEnabled will return true when the feature flag is -// enabled, and no specific function is disabled. -TEST_F(SignalsFeaturesTest, EnabledFeature) { - scoped_features_.InitAndEnableFeature(kNewEvSignalsEnabled); - for (int i = min_enum_value_; i <= max_enum_value_; i++) { - EXPECT_TRUE(IsNewFunctionEnabled(static_cast<NewEvFunction>(i))); - } -} - -// Tests how IsNewFunctionEnabled behaves when the feature flag is enabled, but -// the FileSystemInfo function is disabled. -TEST_F(SignalsFeaturesTest, Enabled_DisableFileSystemInfo) { - scoped_features_.InitAndEnableFeatureWithParameters( - kNewEvSignalsEnabled, {{"DisableFileSystemInfo", "true"}}); - - for (int i = min_enum_value_; i <= max_enum_value_; i++) { - NewEvFunction current_function = static_cast<NewEvFunction>(i); - EXPECT_EQ(IsNewFunctionEnabled(current_function), - current_function != NewEvFunction::kFileSystemInfo); - } -} - -// Tests how IsNewFunctionEnabled behaves when the feature flag is enabled, but -// the Settings function is disabled. -TEST_F(SignalsFeaturesTest, Enabled_DisableSetting) { - scoped_features_.InitAndEnableFeatureWithParameters( - kNewEvSignalsEnabled, {{"DisableSettings", "true"}}); - - for (int i = min_enum_value_; i <= max_enum_value_; i++) { - NewEvFunction current_function = static_cast<NewEvFunction>(i); - EXPECT_EQ(IsNewFunctionEnabled(current_function), - current_function != NewEvFunction::kSettings); - } -} - -// Tests how IsNewFunctionEnabled behaves when the feature flag is enabled, but -// the Antivirus function is disabled. -TEST_F(SignalsFeaturesTest, Enabled_DisableAntiVirus) { - scoped_features_.InitAndEnableFeatureWithParameters( - kNewEvSignalsEnabled, {{"DisableAntiVirus", "true"}}); - - for (int i = min_enum_value_; i <= max_enum_value_; i++) { - NewEvFunction current_function = static_cast<NewEvFunction>(i); - EXPECT_EQ(IsNewFunctionEnabled(current_function), - current_function != NewEvFunction::kAntiVirus); - } -} - -// Tests how IsNewFunctionEnabled behaves when the feature flag is enabled, but -// the Hotfix function is disabled. -TEST_F(SignalsFeaturesTest, Enabled_DisableHotfix) { - scoped_features_.InitAndEnableFeatureWithParameters( - kNewEvSignalsEnabled, {{"DisableHotfix", "true"}}); - - for (int i = min_enum_value_; i <= max_enum_value_; i++) { - NewEvFunction current_function = static_cast<NewEvFunction>(i); - EXPECT_EQ(IsNewFunctionEnabled(current_function), - current_function != NewEvFunction::kHotfix); - } -} - -} // namespace enterprise_signals::features
diff --git a/components/enterprise/watermarking/BUILD.gn b/components/enterprise/watermarking/BUILD.gn index 659a9eb..3283fdd8 100644 --- a/components/enterprise/watermarking/BUILD.gn +++ b/components/enterprise/watermarking/BUILD.gn
@@ -32,3 +32,19 @@ "//testing/gtest", ] } + +source_set("watermark_test_utils") { + testonly = true + + sources = [ + "watermark_test_utils.cc", + "watermark_test_utils.h", + ] + + deps = [ "//components/enterprise/watermarking" ] + + public_deps = [ + "//components/enterprise/watermarking/mojom", + "//skia", + ] +}
diff --git a/components/enterprise/watermarking/DEPS b/components/enterprise/watermarking/DEPS index 5e835e2..3eac807 100644 --- a/components/enterprise/watermarking/DEPS +++ b/components/enterprise/watermarking/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+cc/paint", "+cc/test", + "+skia/ext", "+third_party/skia", "+ui/gfx" ]
diff --git a/components/enterprise/watermarking/watermark_test_utils.cc b/components/enterprise/watermarking/watermark_test_utils.cc new file mode 100644 index 0000000..9959aaea --- /dev/null +++ b/components/enterprise/watermarking/watermark_test_utils.cc
@@ -0,0 +1,61 @@ +// 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/enterprise/watermarking/watermark_test_utils.h" + +#include <utility> + +#include "base/memory/shared_memory_mapping.h" +#include "components/enterprise/watermarking/mojom/watermark.mojom.h" +#include "components/enterprise/watermarking/watermark.h" +#include "skia/ext/font_utils.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" +#include "third_party/skia/include/core/SkSerialProcs.h" +#include "third_party/skia/include/core/SkStream.h" +#include "third_party/skia/include/core/SkTextBlob.h" + +namespace enterprise_watermark { + +watermark::mojom::WatermarkBlockPtr MakeTestWatermarkBlock( + const std::string& watermark_text, + const SkSize watermark_size) { + // Initialize text blob + static constexpr SkScalar kTextSize = 30.0f; + SkFont font(skia::DefaultTypeface(), kTextSize, 1.0f, 0.0f); + sk_sp<SkTextBlob> blob = + SkTextBlob::MakeFromString(watermark_text.c_str(), font); + + // Draw onto SkPicture-backed SkCanvas + SkPictureRecorder recorder; + SkCanvas* canvas = recorder.beginRecording( + SkRect{SkRect::MakeWH(watermark_size.fWidth, watermark_size.fHeight)}); + SkPaint paint; + paint.setColor(SK_ColorWHITE); + canvas->drawTextBlob(blob.get(), 0.0f, 0.0f, paint); + sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); + + // Serialize SkPicture + SkDynamicMemoryWStream stream; + SkSerialProcs procs; + picture->serialize(&stream, &procs); + base::MappedReadOnlyRegion region_mapping = + base::ReadOnlySharedMemoryRegion::Create(stream.bytesWritten()); + if (!region_mapping.IsValid()) { + return nullptr; + } + stream.copyTo(region_mapping.mapping.memory()); + + // Measure string dimensions + SkScalar text_width = font.measureText( + watermark_text.c_str(), watermark_text.size(), SkTextEncoding::kUTF8); + + // Construct test data + return watermark::mojom::WatermarkBlockPtr( + std::in_place, std::move(region_mapping.region), text_width, kTextSize); +} + +} // namespace enterprise_watermark
diff --git a/components/enterprise/watermarking/watermark_test_utils.h b/components/enterprise/watermarking/watermark_test_utils.h new file mode 100644 index 0000000..384905d9 --- /dev/null +++ b/components/enterprise/watermarking/watermark_test_utils.h
@@ -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. + +#ifndef COMPONENTS_ENTERPRISE_WATERMARKING_WATERMARK_TEST_UTILS_H_ +#define COMPONENTS_ENTERPRISE_WATERMARKING_WATERMARK_TEST_UTILS_H_ + +#include "components/enterprise/watermarking/mojom/watermark.mojom-forward.h" +#include "third_party/skia/include/core/SkSize.h" + +namespace enterprise_watermark { + +watermark::mojom::WatermarkBlockPtr MakeTestWatermarkBlock( + const std::string& watermark_text, + const SkSize watermark_size); + +} // namespace enterprise_watermark + +#endif // COMPONENTS_ENTERPRISE_WATERMARKING_WATERMARK_TEST_UTILS_H_
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc index e47ead8..53d4059 100644 --- a/components/exo/surface_tree_host.cc +++ b/components/exo/surface_tree_host.cc
@@ -380,9 +380,6 @@ : std::make_optional(GetScaleFactor()), &frame); - // Update after resource is updated. - UpdateHostLayerOpacity(); - std::vector<GLbyte*> sync_tokens; // We track previously verified tokens and set them to be verified to avoid // the considerable overhead of flush verification in @@ -493,17 +490,8 @@ root_surface_->window()->SetBounds(updated_bounds); } - UpdateHostWindowOpaqueRegion(); -} - -void SurfaceTreeHost::UpdateHostLayerOpacity() { - ui::Layer* commit_target_layer = GetCommitTargetLayer(); - if (commit_target_layer == host_window_->layer()) { UpdateHostWindowOpaqueRegion(); - } else if (commit_target_layer) { - commit_target_layer->SetFillsBoundsOpaquely( - ContentsFillsHostWindowOpaquely()); } }
diff --git a/components/exo/surface_tree_host.h b/components/exo/surface_tree_host.h index c7935fc..24004cc 100644 --- a/components/exo/surface_tree_host.h +++ b/components/exo/surface_tree_host.h
@@ -210,10 +210,6 @@ // It also updates `root_surface_origin_` accordingly to the origin. void UpdateSurfaceLayerSizeAndRootSurfaceOrigin(); - // Updates the host layer's opacity. This has to be called after root - // surface's resource is updated. - void UpdateHostLayerOpacity(); - void UpdateHostWindowOpaqueRegion(); bool client_submits_surfaces_in_pixel_coordinates() const {
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java index 9932818..c734b5c7 100644 --- a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java +++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java
@@ -522,13 +522,23 @@ .getLastCommittedEntryIndexBeforeStartingNavigation(); if (getLastCommittedEntryIndex() <= lastCommittedEntryIndexBeforeNavigation) return; - // http://crbug/426679 : we want to go back to the last committed entry index which - // was saved before this navigation, and remove the empty entries from the - // navigation history. - mClearAllForwardHistoryRequired = true; - mClient.getWebContents() - .getNavigationController() - .goToNavigationIndex(lastCommittedEntryIndexBeforeNavigation); + // Like clobbering below, changing navigation index could cancel the current navigation and + // delete the NavigationThrottle calling this code, leading to UAFs. Do the navigation + // asynchronously to avoid that. + PostTask.postTask( + TaskTraits.UI_DEFAULT, + new Runnable() { + @Override + public void run() { + // http://crbug.com/426679 : we want to go back to the last committed entry + // index which was saved before this navigation, and remove the empty + // entries from the navigation history. + mClearAllForwardHistoryRequired = true; + mClient.getWebContents() + .getNavigationController() + .goToNavigationIndex(lastCommittedEntryIndexBeforeNavigation); + } + }); } private void clobberMainFrame(GURL targetUrl, ExternalNavigationParams params) {
diff --git a/components/facilitated_payments/android/BUILD.gn b/components/facilitated_payments/android/BUILD.gn index 6d6a9aac..90f89b6 100644 --- a/components/facilitated_payments/android/BUILD.gn +++ b/components/facilitated_payments/android/BUILD.gn
@@ -8,6 +8,8 @@ sources = [ "facilitated_payments_api_client_android.cc", "facilitated_payments_api_client_android.h", + "secure_payload_android.cc", + "secure_payload_android.h", ] deps = [ @@ -22,7 +24,10 @@ source_set("unit_tests") { testonly = true - sources = [ "facilitated_payments_api_client_android_unittest.cc" ] + sources = [ + "facilitated_payments_api_client_android_unittest.cc", + "secure_payload_android_unittest.cc", + ] deps = [ ":android", "//components/facilitated_payments/core/browser",
diff --git a/components/facilitated_payments/android/java/BUILD.gn b/components/facilitated_payments/android/java/BUILD.gn index b513444..d94cec0 100644 --- a/components/facilitated_payments/android/java/BUILD.gn +++ b/components/facilitated_payments/android/java/BUILD.gn
@@ -10,6 +10,8 @@ sources = [ "src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClient.java", "src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClientBridge.java", + "src/org/chromium/components/facilitated_payments/SecureData.java", + "src/org/chromium/components/facilitated_payments/SecurePayload.java", ] deps = [ "//base:base_java", @@ -24,5 +26,9 @@ } generate_jni("jni_headers") { - sources = [ "src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClientBridge.java" ] + sources = [ + "src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClientBridge.java", + "src/org/chromium/components/facilitated_payments/SecureData.java", + "src/org/chromium/components/facilitated_payments/SecurePayload.java", + ] }
diff --git a/components/facilitated_payments/android/java/src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClient.java b/components/facilitated_payments/android/java/src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClient.java index ea268f92..16d351d0 100644 --- a/components/facilitated_payments/android/java/src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClient.java +++ b/components/facilitated_payments/android/java/src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClient.java
@@ -9,12 +9,13 @@ /** * Client for facilitated payment APIs, such as PIX. The default implementation cannot invoke - * payments. An implementing subclass must provide a factory that builds its instances. - * Example usage: + * payments. An implementing subclass must provide a factory that builds its instances. Example + * usage: * - * FacilitatedPaymentsApiClient apiClient = - * FacilitatedPaymentsApiClient.create(renderFrameHost, delegate); - * apiClient.isAvailable(); + * <pre> + * FacilitatedPaymentsApiClient apiClient = + * FacilitatedPaymentsApiClient.create(renderFrameHost,delegate); apiClient.isAvailable(); + * </pre> */ public class FacilitatedPaymentsApiClient { private static Factory sFactory; @@ -152,7 +153,19 @@ * Initiates the payment flow UI. Will invoke a delegate callback with the result. * * @param primaryAccount User's signed in account. + * @param securePayload The secure payload received from Payments backend that is required for + * invoking the purchase action in Google Play Services. + */ + public void invokePurchaseAction(CoreAccountInfo primaryAccount, SecurePayload securePayload) { + mDelegate.onPurchaseActionResultEnum(PurchaseActionResult.COULD_NOT_INVOKE); + } + + /** + * Initiates the payment flow UI. Will invoke a delegate callback with the result. + * + * @param primaryAccount User's signed in account. * @param actionToken An opaque token used for invoking the purchase action. + * @deprecated TODO(https://crbug.com/329108444): Remove this method. */ public void invokePurchaseAction(CoreAccountInfo primaryAccount, byte[] actionToken) { mDelegate.onPurchaseActionResultEnum(PurchaseActionResult.COULD_NOT_INVOKE);
diff --git a/components/facilitated_payments/android/java/src/org/chromium/components/facilitated_payments/SecureData.java b/components/facilitated_payments/android/java/src/org/chromium/components/facilitated_payments/SecureData.java new file mode 100644 index 0000000..b7840910 --- /dev/null +++ b/components/facilitated_payments/android/java/src/org/chromium/components/facilitated_payments/SecureData.java
@@ -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. + +package org.chromium.components.facilitated_payments; + +import org.jni_zero.CalledByNative; +import org.jni_zero.JNINamespace; + +/** Class containing the key value pairs for the secure data returned from Payments backend. */ +@JNINamespace("payments::facilitated") +public class SecureData { + private final int mKey; + private final String mValue; + + @CalledByNative + public SecureData(int key, String value) { + this.mKey = key; + this.mValue = value; + } + + /** Returns the key for the SecureData. */ + public int getKey() { + return mKey; + } + + /** Returns the value for the SecureData. */ + public String getValue() { + return mValue; + } +}
diff --git a/components/facilitated_payments/android/java/src/org/chromium/components/facilitated_payments/SecurePayload.java b/components/facilitated_payments/android/java/src/org/chromium/components/facilitated_payments/SecurePayload.java new file mode 100644 index 0000000..439800d --- /dev/null +++ b/components/facilitated_payments/android/java/src/org/chromium/components/facilitated_payments/SecurePayload.java
@@ -0,0 +1,41 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.facilitated_payments; + +import org.jni_zero.CalledByNative; +import org.jni_zero.JNINamespace; +import org.jni_zero.JniType; + +import java.util.Arrays; +import java.util.List; + +/** + * Class containing the action token and the decrypted secure data returned from payments backend. + * Both are used to trigger a UI flow within Google Play Services. + */ +@JNINamespace("payments::facilitated") +class SecurePayload { + private final byte[] mActionToken; + private final List<SecureData> mSecureData; + + @CalledByNative + public SecurePayload(byte[] actionToken, @JniType("std::vector") Object[] secureData) { + this.mActionToken = actionToken; + this.mSecureData = (List<SecureData>) (List<?>) Arrays.asList(secureData); + } + + /** Returns an action token that can be used to trigger a UI flow in Google Play Services. */ + public byte[] getActionToken() { + return mActionToken; + } + + /** + * Returns a list of {@link SecureData} that can be passed in conjunction to the action token + * while triggering a UI flow in Google Play Services. + */ + public List<SecureData> getSecureData() { + return mSecureData; + } +}
diff --git a/components/facilitated_payments/android/junit/src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClientUnitTest.java b/components/facilitated_payments/android/junit/src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClientUnitTest.java index b26791e2..e71f268 100644 --- a/components/facilitated_payments/android/junit/src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClientUnitTest.java +++ b/components/facilitated_payments/android/junit/src/org/chromium/components/facilitated_payments/FacilitatedPaymentsApiClientUnitTest.java
@@ -89,7 +89,8 @@ FacilitatedPaymentsApiClient.create(/* renderFrameHost= */ null, delegate); apiClient.invokePurchaseAction( - /* primaryAccount= */ null, new byte[] {'A', 'c', 't', 'i', 'o', 'n'}); + /* primaryAccount= */ null, + new SecurePayload(new byte[] {'A', 'c', 't', 'i', 'o', 'n'}, new SecureData[0])); Assert.assertTrue(delegate.mIsPurchaseActionInvoked); Assert.assertEquals(PurchaseActionResult.COULD_NOT_INVOKE, delegate.mPurchaseActionResult); @@ -113,7 +114,8 @@ } @Override - public void invokePurchaseAction(CoreAccountInfo primaryAccount, byte[] actionToken) { + public void invokePurchaseAction( + CoreAccountInfo primaryAccount, SecurePayload securePayload) { mDelegate.onPurchaseActionResultEnum(PurchaseActionResult.RESULT_OK); } } @@ -161,7 +163,8 @@ FacilitatedPaymentsApiClient.create(/* renderFrameHost= */ null, delegate); apiClient.invokePurchaseAction( - /* primaryAccount= */ null, new byte[] {'A', 'c', 't', 'i', 'o', 'n'}); + /* primaryAccount= */ null, + new SecurePayload(new byte[] {'A', 'c', 't', 'i', 'o', 'n'}, new SecureData[0])); Assert.assertTrue(delegate.mIsPurchaseActionInvoked); Assert.assertEquals(PurchaseActionResult.RESULT_OK, delegate.mPurchaseActionResult);
diff --git a/components/facilitated_payments/android/secure_payload_android.cc b/components/facilitated_payments/android/secure_payload_android.cc new file mode 100644 index 0000000..1adcf7a --- /dev/null +++ b/components/facilitated_payments/android/secure_payload_android.cc
@@ -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. + +#include "components/facilitated_payments/android/secure_payload_android.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" + +// Must come after all headers that specialize FromJniType() / ToJniType(). +#include "components/facilitated_payments/android/java/jni_headers/SecureData_jni.h" +#include "components/facilitated_payments/android/java/jni_headers/SecurePayload_jni.h" + +namespace payments::facilitated { + +namespace { + +using base::android::AttachCurrentThread; +using base::android::ConvertUTF8ToJavaString; +using base::android::ScopedJavaLocalRef; + +} // namespace + +ScopedJavaLocalRef<jobject> ConvertSecurePayloadToJavaObject( + const SecurePayload& secure_payload) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jbyteArray> action_token = + base::android::ToJavaByteArray(env, secure_payload.action_token); + std::vector<base::android::ScopedJavaLocalRef<jobject>> secure_data_array; + for (const SecureData& secure_data : secure_payload.secure_data) { + secure_data_array.push_back(Java_SecureData_Constructor( + env, secure_data.key, ConvertUTF8ToJavaString(env, secure_data.value))); + } + return Java_SecurePayload_Constructor(env, action_token, + std::move(secure_data_array)); +} + +} // namespace payments::facilitated
diff --git a/components/facilitated_payments/android/secure_payload_android.h b/components/facilitated_payments/android/secure_payload_android.h new file mode 100644 index 0000000..63d6348 --- /dev/null +++ b/components/facilitated_payments/android/secure_payload_android.h
@@ -0,0 +1,20 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_FACILITATED_PAYMENTS_ANDROID_SECURE_PAYLOAD_ANDROID_H_ +#define COMPONENTS_FACILITATED_PAYMENTS_ANDROID_SECURE_PAYLOAD_ANDROID_H_ + +#include <jni.h> + +#include "base/android/scoped_java_ref.h" +#include "components/facilitated_payments/core/browser/model/secure_payload.h" + +namespace payments::facilitated { + +base::android::ScopedJavaLocalRef<jobject> ConvertSecurePayloadToJavaObject( + const SecurePayload& secure_payload); + +} // namespace payments::facilitated + +#endif // COMPONENTS_FACILITATED_PAYMENTS_ANDROID_SECURE_PAYLOAD_ANDROID_H_
diff --git a/components/facilitated_payments/android/secure_payload_android_unittest.cc b/components/facilitated_payments/android/secure_payload_android_unittest.cc new file mode 100644 index 0000000..2381a6f --- /dev/null +++ b/components/facilitated_payments/android/secure_payload_android_unittest.cc
@@ -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. + +#include "components/facilitated_payments/android/secure_payload_android.h" + +#include <utility> + +#include "base/android/jni_android.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace payments::facilitated { + +using SecurePayloadAndroidJniTest = testing::Test; + +TEST_F(SecurePayloadAndroidJniTest, SecurePayloadJavaObjectCreated) { + SecurePayload secure_payload; + secure_payload.action_token = {1, 2, 3}; + secure_payload.secure_data.emplace_back(1, "value_1"); + secure_payload.secure_data.emplace_back(2, "value_2"); + + base::android::ScopedJavaLocalRef<jobject> java_secure_payload = + ConvertSecurePayloadToJavaObject(std::move(secure_payload)); + + // Verify that the java object is created. + EXPECT_TRUE(java_secure_payload.obj()); +} + +} // namespace payments::facilitated
diff --git a/components/facilitated_payments/core/browser/ewallet_manager.cc b/components/facilitated_payments/core/browser/ewallet_manager.cc index 90311b3..9dbaa6c6 100644 --- a/components/facilitated_payments/core/browser/ewallet_manager.cc +++ b/components/facilitated_payments/core/browser/ewallet_manager.cc
@@ -9,6 +9,7 @@ #include "base/check_deref.h" #include "base/containers/span.h" #include "base/functional/callback_helpers.h" +#include "base/time/time.h" #include "components/autofill/core/browser/data_manager/payments/payments_data_manager.h" #include "components/autofill/core/browser/data_model/ewallet.h" #include "components/autofill/core/browser/payments/payments_autofill_client.h" @@ -32,6 +33,8 @@ static constexpr FacilitatedPaymentsType kPaymentsType = FacilitatedPaymentsType::kEwallet; +static constexpr base::TimeDelta kProgressScreenDismissDelay = base::Seconds(1); + } // namespace EwalletManager::EwalletManager( @@ -283,6 +286,11 @@ account_info.value(), response_details->secure_payload_.action_token, base::BindOnce(&EwalletManager::OnTransactionResult, weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now())); + + // Close the progress screen just after the platform screen appears. + ui_timer_.Start(FROM_HERE, kProgressScreenDismissDelay, + base::BindOnce(&EwalletManager::DismissProgressScreen, + weak_ptr_factory_.GetWeakPtr())); } void EwalletManager::OnTransactionResult(base::TimeTicks start_time, @@ -371,4 +379,10 @@ return AvailableEwalletsConfiguration::kMultipleEwallets; } +void EwalletManager::DismissProgressScreen() { + if (ui_state_ == UiState::kProgressScreen) { + DismissPrompt(); + } +} + } // namespace payments::facilitated
diff --git a/components/facilitated_payments/core/browser/ewallet_manager.h b/components/facilitated_payments/core/browser/ewallet_manager.h index 2196cd4e..7ced5d4f 100644 --- a/components/facilitated_payments/core/browser/ewallet_manager.h +++ b/components/facilitated_payments/core/browser/ewallet_manager.h
@@ -13,6 +13,7 @@ #include "base/memory/raw_ref.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" +#include "base/timer/timer.h" #include "components/autofill/core/browser/payments/payments_autofill_client.h" #include "components/facilitated_payments/core/browser/facilitated_payments_api_client.h" #include "components/facilitated_payments/core/browser/network_api/facilitated_payments_initiate_payment_request_details.h" @@ -134,6 +135,10 @@ // Returns the `AvailableEwalletsConfiguration` for this user profile. AvailableEwalletsConfiguration GetAvailableEwalletsConfiguration(); + // Dismisses the FacilitatedPayments bottom sheet if the progress screen is + // being shown. + void DismissProgressScreen(); + // A list of eWallets that support the payment link provided in // TriggerEwalletPushPayment(). // @@ -187,6 +192,9 @@ // device. This field is used for logging purposes. bool is_device_bound_for_logging_ = false; + // A timer to make UI changes. + base::OneShotTimer ui_timer_; + base::WeakPtrFactory<EwalletManager> weak_ptr_factory_{this}; };
diff --git a/components/facilitated_payments/core/browser/ewallet_manager_unittest.cc b/components/facilitated_payments/core/browser/ewallet_manager_unittest.cc index b0ed9a1..e18fbf8a 100644 --- a/components/facilitated_payments/core/browser/ewallet_manager_unittest.cc +++ b/components/facilitated_payments/core/browser/ewallet_manager_unittest.cc
@@ -1349,4 +1349,61 @@ EXPECT_EQ(ukm_entries[0].metrics.at("Scheme"), 2); } +TEST_F(EwalletManagerTest, + ProgressScreenAutoDismissedAfterInvokingPurchaseAction) { + // When purchase action is invoked, the progress screen would be showing. + test_api(*ewallet_manager_).ShowProgressScreen(); + + EXPECT_CALL(GetApiClient(), InvokePurchaseAction); + + auto response_details = + std::make_unique<FacilitatedPaymentsInitiatePaymentResponseDetails>(); + response_details->secure_payload_.action_token = + std::vector<uint8_t>{'t', 'o', 'k', 'e', 'n'}; + test_api(*ewallet_manager_) + .OnInitiatePaymentResponseReceived( + base::TimeTicks::Now() - base::Seconds(2), + autofill::payments::PaymentsAutofillClient::PaymentsRpcResult:: + kSuccess, + std::move(response_details)); + + // The progress screen is persisted for a short duration after invoking the + // purchase action for a smooth transition to the platform screen. + EXPECT_EQ(test_api(*ewallet_manager_).ui_state(), UiState::kProgressScreen); + + FastForwardBy(base::Seconds(1)); + + // The progress screen should be dismissed after a short delay. + EXPECT_EQ(test_api(*ewallet_manager_).ui_state(), UiState::kHidden); +} + +TEST_F(EwalletManagerTest, + ErrorScreenNotAutoDismissedAfterInvokingPurchaseAction) { + // When purchase action is invoked, the progress screen would be showing. + test_api(*ewallet_manager_).ShowProgressScreen(); + + EXPECT_CALL(GetApiClient(), InvokePurchaseAction); + + auto response_details = + std::make_unique<FacilitatedPaymentsInitiatePaymentResponseDetails>(); + response_details->secure_payload_.action_token = + std::vector<uint8_t>{'t', 'o', 'k', 'e', 'n'}; + test_api(*ewallet_manager_) + .OnInitiatePaymentResponseReceived( + base::TimeTicks::Now() - base::Seconds(2), + autofill::payments::PaymentsAutofillClient::PaymentsRpcResult:: + kSuccess, + std::move(response_details)); + + // If the purchase action could not be invoked, the `PurchaseActionResult` is + // returned immediately. The error screen is shown. + test_api(*ewallet_manager_) + .OnTransactionResult(base::TimeTicks::Now() - base::Seconds(2), + PurchaseActionResult::kCouldNotInvoke); + FastForwardBy(base::Seconds(1)); + + // The error screen shouldn't be auto-dismissed. + EXPECT_EQ(test_api(*ewallet_manager_).ui_state(), UiState::kErrorScreen); +} + } // namespace payments::facilitated
diff --git a/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc b/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc index 66067b8..4d71fd43 100644 --- a/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc +++ b/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc
@@ -320,6 +320,78 @@ surface.reliability_logging_bridge.GetEventsString()); } +TEST_F(FeedApiReliabilityLoggingTest, LoadStreamComplete_InternetDisconnected) { + network_.error = net::ERR_INTERNET_DISCONNECTED; + TestForYouSurface surface(stream_.get()); + WaitForIdleTaskQueue(); + + EXPECT_EQ( + "LogFeedLaunchOtherStart\n" + "LogLoadingIndicatorShown\n" + + "LogCacheReadStart\n" + "LogCacheReadEnd result=EMPTY_SESSION\n" + + "LogFeedRequestStart id=1\n" + "LogRequestSent id=1\n" + // Should not call LogResponseReceived. + "LogRequestFinished result=-106 id=1\n" + + "LogLaunchFinishedAfterStreamUpdate " + "result=NO_CARDS_REQUEST_ERROR_NO_INTERNET\n" + + "LogAboveTheFoldRender result=FULL_FEED_ERROR\n", + surface.reliability_logging_bridge.GetEventsString()); +} + +TEST_F(FeedApiReliabilityLoggingTest, LoadStreamComplete_NameNotResolved) { + network_.error = net::ERR_NAME_NOT_RESOLVED; + TestForYouSurface surface(stream_.get()); + WaitForIdleTaskQueue(); + + EXPECT_EQ( + "LogFeedLaunchOtherStart\n" + "LogLoadingIndicatorShown\n" + + "LogCacheReadStart\n" + "LogCacheReadEnd result=EMPTY_SESSION\n" + + "LogFeedRequestStart id=1\n" + "LogRequestSent id=1\n" + // Should not call LogResponseReceived. + "LogRequestFinished result=-105 id=1\n" + + "LogLaunchFinishedAfterStreamUpdate " + "result=NO_CARDS_REQUEST_ERROR_NO_INTERNET\n" + + "LogAboveTheFoldRender result=FULL_FEED_ERROR\n", + surface.reliability_logging_bridge.GetEventsString()); +} + +TEST_F(FeedApiReliabilityLoggingTest, LoadStreamComplete_AddressUnreachable) { + network_.error = net::ERR_ADDRESS_UNREACHABLE; + TestForYouSurface surface(stream_.get()); + WaitForIdleTaskQueue(); + + EXPECT_EQ( + "LogFeedLaunchOtherStart\n" + "LogLoadingIndicatorShown\n" + + "LogCacheReadStart\n" + "LogCacheReadEnd result=EMPTY_SESSION\n" + + "LogFeedRequestStart id=1\n" + "LogRequestSent id=1\n" + // Should not call LogResponseReceived. + "LogRequestFinished result=-109 id=1\n" + + "LogLaunchFinishedAfterStreamUpdate " + "result=NO_CARDS_REQUEST_ERROR_NO_INTERNET\n" + + "LogAboveTheFoldRender result=FULL_FEED_ERROR\n", + surface.reliability_logging_bridge.GetEventsString()); +} + TEST_F(FeedApiReliabilityLoggingTest, LoadStreamComplete_ResponseReceivedWithHttpError) { network_.http_status_code = net::HttpStatusCode::HTTP_FORBIDDEN;
diff --git a/components/feed/core/v2/tasks/load_stream_task.cc b/components/feed/core/v2/tasks/load_stream_task.cc index 6d0e569f..05729a8 100644 --- a/components/feed/core/v2/tasks/load_stream_task.cc +++ b/components/feed/core/v2/tasks/load_stream_task.cc
@@ -73,7 +73,8 @@ LaunchResult LoadStreamTask::LaunchResultFromNetworkInfo( const NetworkResponseInfo& response_info, bool has_parsed_body) { - if (response_info.status_code == 200) { + int status_code = response_info.status_code; + if (status_code == 200) { if (has_parsed_body) { // Success. return {LoadStreamStatus::kNoStatus, @@ -106,6 +107,13 @@ LoadStreamStatus::kAccountTokenFetchTimedOut, feedwire::DiscoverLaunchResult::NO_CARDS_FAILED_TO_GET_AUTH_TOKEN}; } + if (status_code == net::ERR_INTERNET_DISCONNECTED || + status_code == net::ERR_NAME_NOT_RESOLVED || + status_code == net::ERR_ADDRESS_UNREACHABLE || + status_code == net::ERR_PROXY_CONNECTION_FAILED) { + return {LoadStreamStatus::kCannotLoadFromNetworkOffline, + feedwire::DiscoverLaunchResult::NO_CARDS_REQUEST_ERROR_NO_INTERNET}; + } return {LoadStreamStatus::kNetworkFetchFailed, feedwire::DiscoverLaunchResult::NO_CARDS_RESPONSE_ERROR_NON_200}; }
diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/ScopeChangeController.java b/components/messages/android/internal/java/src/org/chromium/components/messages/ScopeChangeController.java index 1df37ba..93fed62b 100644 --- a/components/messages/android/internal/java/src/org/chromium/components/messages/ScopeChangeController.java +++ b/components/messages/android/internal/java/src/org/chromium/components/messages/ScopeChangeController.java
@@ -84,6 +84,7 @@ // TODO(crbug.com/40230391): Replace GURL with Origin. private GURL mLastVisitedUrl; private boolean mIsActive; + private boolean mIsDestroyed; public NavigationWebContentsScopeObserver(Delegate delegate, ScopeKey scopeKey) { super(scopeKey.webContents); @@ -134,10 +135,19 @@ } @Override - public void onDestroy() { + public void webContentsDestroyed() { + destroy(); + } + + @Override + public void destroy() { + if (mIsDestroyed) return; + mIsDestroyed = true; + mDelegate.onScopeChange( new MessageScopeChange(mScopeKey.scopeType, mScopeKey, ChangeType.DESTROY)); mIsActive = false; + observe(null); } @Override
diff --git a/components/navigation_interception/intercept_navigation_throttle.cc b/components/navigation_interception/intercept_navigation_throttle.cc index 111ab866..9dd5458 100644 --- a/components/navigation_interception/intercept_navigation_throttle.cc +++ b/components/navigation_interception/intercept_navigation_throttle.cc
@@ -70,12 +70,14 @@ weak_factory_.GetWeakPtr())); return content::NavigationThrottle::PROCEED; } + auto weak_this = weak_factory_.GetWeakPtr(); // No need to set |should_ignore_| since if it is true, we'll cancel the // navigation immediately. return should_ignore_callback_.Run(navigation_handle()) ? content::NavigationThrottle::CANCEL_AND_IGNORE : content::NavigationThrottle::PROCEED; - // Careful, |this| can be deleted at this point. + // Clients should not synchronously cause the navigation to be deleted. + CHECK(weak_this); } void InterceptNavigationThrottle::RunCheckAsync() { @@ -85,8 +87,8 @@ bool final_deferred_check = deferring_ && pending_checks_ == 0; auto weak_this = weak_factory_.GetWeakPtr(); bool should_ignore = should_ignore_callback_.Run(navigation_handle()); - if (!weak_this) - return; + // Clients should not synchronously cause the navigation to be deleted. + CHECK(weak_this); should_ignore_ |= should_ignore; if (!final_deferred_check)
diff --git a/components/navigation_interception/intercept_navigation_throttle_unittest.cc b/components/navigation_interception/intercept_navigation_throttle_unittest.cc index c1f462d..1c418f1 100644 --- a/components/navigation_interception/intercept_navigation_throttle_unittest.cc +++ b/components/navigation_interception/intercept_navigation_throttle_unittest.cc
@@ -199,34 +199,6 @@ EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, result); } -// Regression test for https://crbug.com/856737. There is some java code that -// runs in the CheckCallback that can synchronously tear down the navigation -// while the throttle is running. -// TODO(csharrison): We should probably make that code async to avoid these -// sorts of situations. However, it might not be possible if we implement -// WebViewClient#shouldOverrideUrlLoading with this class which can end up -// calling loadUrl() within the callback. See https://crbug.com/794020 for more -// details. -TEST_P(InterceptNavigationThrottleTest, IgnoreCallbackDeletesNavigation) { - NavigateAndCommit(GURL("about:blank")); - - auto ignore_callback = [](content::NavigationHandle* handle) { - handle->GetWebContents()->GetController().GoToIndex(0); - return true; - }; - auto inserter = std::make_unique<content::TestNavigationThrottleInserter>( - web_contents(), - base::BindRepeating(&InterceptNavigationThrottleTest::CreateThrottle, - base::BindRepeating(ignore_callback))); - - // Intercepting a navigation and forcing a synchronous re-navigation should - // not crash. - auto navigation = content::NavigationSimulator::CreateBrowserInitiated( - GURL("https://intercept.test/"), web_contents()); - navigation->Start(); - base::RunLoop().RunUntilIdle(); -} - INSTANTIATE_TEST_SUITE_P(All, InterceptNavigationThrottleTest, testing::Values(true, false));
diff --git a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc index db779e2..35cac99 100644 --- a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc +++ b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc
@@ -9,6 +9,10 @@ #include <utility> #include "base/functional/bind.h" +#include "base/strings/stringprintf.h" +#include "components/signin/public/identity_manager/identity_manager.h" +#include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h" +#include "components/signin/public/identity_manager/scope_set.h" #include "components/variations/net/variations_http_headers.h" #include "net/base/load_flags.h" #include "net/cookies/site_for_cookies.h" @@ -20,10 +24,11 @@ EnterpriseSearchAggregatorSuggestionsService:: EnterpriseSearchAggregatorSuggestionsService( + signin::IdentityManager* identity_manager, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) - : url_loader_factory_(url_loader_factory) { - DCHECK(url_loader_factory); -} + : url_loader_factory_(url_loader_factory), + identity_manager_(identity_manager), + token_fetcher_(nullptr) {} EnterpriseSearchAggregatorSuggestionsService:: ~EnterpriseSearchAggregatorSuggestionsService() = default; @@ -85,6 +90,40 @@ } })"); + // Create and fetch an OAuth2 token. + signin::ScopeSet scopes; + // TODO(crbug.com/380631529): Add scope once access is provided. + token_fetcher_ = std::make_unique<signin::PrimaryAccountAccessTokenFetcher>( + "enterprise_search_aggregator_suggestions_service", identity_manager_, + scopes, + base::BindOnce( + &EnterpriseSearchAggregatorSuggestionsService::AccessTokenAvailable, + base::Unretained(this), std::move(request), std::move(request_body), + traffic_annotation, std::move(start_callback), + std::move(completion_callback)), + signin::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable, + signin::ConsentLevel::kSignin); +} + +void EnterpriseSearchAggregatorSuggestionsService::AccessTokenAvailable( + std::unique_ptr<network::ResourceRequest> request, + std::string request_body, + net::NetworkTrafficAnnotationTag traffic_annotation, + StartCallback start_callback, + CompletionCallback completion_callback, + GoogleServiceAuthError error, + signin::AccessTokenInfo access_token_info) { + DCHECK(token_fetcher_); + token_fetcher_.reset(); + // If there were no errors obtaining the access token, append it to the + // request as a header. + if (error.state() == GoogleServiceAuthError::NONE) { + DCHECK(!access_token_info.token.empty()); + request->headers.SetHeader( + "Authorization", + base::StringPrintf("Bearer %s", access_token_info.token.c_str())); + } + StartDownloadAndTransferLoader(std::move(request), std::move(request_body), traffic_annotation, std::move(start_callback), std::move(completion_callback));
diff --git a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.h b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.h index 6cae54b..f4377fc 100644 --- a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.h +++ b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.h
@@ -11,11 +11,20 @@ #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" +#include "base/scoped_observation.h" #include "components/keyed_service/core/keyed_service.h" +#include "components/signin/public/identity_manager/access_token_info.h" +#include "components/signin/public/identity_manager/identity_manager.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/cpp/simple_url_loader.h" #include "url/gurl.h" +namespace signin { +class PrimaryAccountAccessTokenFetcher; +} // namespace signin + +class GoogleServiceAuthError; + namespace network { struct ResourceRequest; class SharedURLLoaderFactory; @@ -25,7 +34,8 @@ // A service to fetch suggestions from the search aggregator endpoint URL. class EnterpriseSearchAggregatorSuggestionsService : public KeyedService { public: - explicit EnterpriseSearchAggregatorSuggestionsService( + EnterpriseSearchAggregatorSuggestionsService( + signin::IdentityManager* identity_manager, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); ~EnterpriseSearchAggregatorSuggestionsService() override; @@ -54,6 +64,15 @@ CompletionCallback completion_callback); private: + // Called when an access token request completes (successfully or not). + void AccessTokenAvailable(std::unique_ptr<network::ResourceRequest> request, + std::string request_body, + net::NetworkTrafficAnnotationTag traffic_annotation, + StartCallback start_callback, + CompletionCallback completion_callback, + GoogleServiceAuthError error, + signin::AccessTokenInfo access_token_info); + // TODO(crbug.com/385756623): Factor out this method so it can be used across // document_suggestions_service and // enterprise_search_aggregator_suggestions_service. @@ -65,6 +84,13 @@ CompletionCallback completion_callback); scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; + + // This will outlive this instance because of the factory dependencies. + raw_ptr<signin::IdentityManager> identity_manager_; + + // Helper for fetching OAuth2 access tokens. Non-null when we have a token + // available, or while a token fetch is in progress. + std::unique_ptr<signin::PrimaryAccountAccessTokenFetcher> token_fetcher_; }; #endif // COMPONENTS_OMNIBOX_BROWSER_ENTERPRISE_SEARCH_AGGREGATOR_SUGGESTIONS_SERVICE_H_
diff --git a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service_unittest.cc b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service_unittest.cc index 18bcca7..0407fe1 100644 --- a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service_unittest.cc +++ b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service_unittest.cc
@@ -8,13 +8,13 @@ #include "base/json/json_parser.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" -#include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" +#include "base/test/test_future.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "components/variations/net/variations_http_headers.h" @@ -59,16 +59,6 @@ "dataStore" : "" } ] })"}); -void OnEnterpriseSearchAggregatorSuggestionsRequestAvailable( - network::ResourceRequest* request) {} - -void OnEnterpriseSearchAggregatorSuggestionsLoaderAvailable( - std::unique_ptr<network::SimpleURLLoader> loader, - const std::string& request_body) {} - -void OnURLLoadComplete(const network::SimpleURLLoader* source, - std::unique_ptr<std::string> response_body) {} - class EnterpriseSearchAggregatorSuggestionsServiceTest : public testing::Test { public: EnterpriseSearchAggregatorSuggestionsServiceTest() @@ -76,8 +66,10 @@ shared_url_loader_factory_( base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( &test_url_loader_factory_)), + identity_test_env_(&test_url_loader_factory_, &prefs_), enterprise_search_aggregator_suggestions_service_( new EnterpriseSearchAggregatorSuggestionsService( + identity_test_env_.identity_manager(), shared_url_loader_factory_)) { // Set up a variation. variations::AssociateGoogleVariationID( @@ -126,16 +118,25 @@ base::JSONWriter::Write(root, &test_request_body); const GURL test_endpoint = GURL("https://fake_url.com"); + base::test::TestFuture<network::ResourceRequest*> request_future; + base::test::TestFuture<std::unique_ptr<network::SimpleURLLoader>, + const std::string&> + loader_future; + base::test::TestFuture<const network::SimpleURLLoader*, + std::unique_ptr<std::string>> + complete_future; + enterprise_search_aggregator_suggestions_service_ ->CreateEnterpriseSearchAggregatorSuggestionsRequest( - test_endpoint, test_request_body, - base::BindOnce( - OnEnterpriseSearchAggregatorSuggestionsRequestAvailable), - base::BindOnce( - OnEnterpriseSearchAggregatorSuggestionsLoaderAvailable), - base::BindOnce(OnURLLoadComplete)); + test_endpoint, test_request_body, request_future.GetCallback(), + loader_future.GetCallback(), complete_future.GetCallback()); - base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(request_future.Wait()); + ASSERT_TRUE(loader_future.Wait()); + + complete_future.SetValue(nullptr, + std::make_unique<std::string>(mock_response)); + ASSERT_TRUE(complete_future.Wait()); EXPECT_TRUE(resource_request.site_for_cookies.IsEquivalent( net::SiteForCookies::FromUrl(GURL(test_endpoint))))
diff --git a/components/omnibox/browser/unscoped_extension_provider.cc b/components/omnibox/browser/unscoped_extension_provider.cc index e6aadfe..bd8ed5e 100644 --- a/components/omnibox/browser/unscoped_extension_provider.cc +++ b/components/omnibox/browser/unscoped_extension_provider.cc
@@ -7,24 +7,12 @@ #include <string> #include "base/check_is_test.h" -#include "base/containers/fixed_flat_map.h" #include "base/memory/raw_ptr.h" -#include "build/build_config.h" #include "components/omnibox/browser/autocomplete_provider.h" #include "components/omnibox/browser/autocomplete_provider_client.h" #include "components/omnibox/browser/autocomplete_provider_listener.h" #include "components/omnibox/browser/unscoped_extension_provider_delegate.h" #include "components/search_engines/template_url_service.h" -#include "components/strings/grit/components_strings.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/page_transition_types.h" - -namespace { -constexpr auto kReservedSectionMap = - base::MakeFixedFlatMap<int, omnibox::GroupSection>( - {{0, omnibox::SECTION_UNSCOPED_EXTENSION_1}, - {1, omnibox::SECTION_UNSCOPED_EXTENSION_2}}); -} // namespace UnscopedExtensionProvider::UnscopedExtensionProvider( AutocompleteProviderClient* client, @@ -40,42 +28,51 @@ void UnscopedExtensionProvider::Start(const AutocompleteInput& input, bool minimal_changes) { + // If the changes to the input are not minimal, clear the current list of + // matches and suggestion group information and increment the current request + // ID to discard any suggestions that may be incoming later with a stale + // request ID. + Stop(/*clear_cached_results=*/!minimal_changes, + /*due_to_user_inactivity=*/false); + + // Extension suggestions are not allowed in keyword mode. + if (input.InKeywordMode()) { + return; + } + + // Extension suggestions are not allowed for zero-suggest or empty inputs. + if (input.IsZeroSuggest() || + input.type() == metrics::OmniboxInputType::EMPTY) { + return; + } + + // Extension suggestions are always provided asynchronously. + if (input.omit_asynchronous_matches()) { + return; + } + + // Do not forward the input to the extensions delegate if the changes to the + // input are minimal. if (minimal_changes) { - // Return early and maintain the current matches list. return; } - // Reset done and increment the input ID to discard any stale extension - // suggestions that may be incoming later if the current request id and - // incoming request ids do not match. - Stop(true, false); - - // Do not forward the event to unscoped extensions delegate if: - // 1. there are no unscoped extensions - // 2. in zero-suggest mode - // 3. only synchronous matches are needed and the changes are not - // minimal. Minimal changes will not need an async call. - // 4. in keyword mode. - std::set<std::string> unscoped_extensions = GetUnscopedModeExtensionIds(); - bool skip_unscoped_extensions_matches = - unscoped_extensions.empty() || input.IsZeroSuggest() || - (input.omit_asynchronous_matches()) || input.InKeywordMode(); - - if (skip_unscoped_extensions_matches) { - ClearSuggestionGroupsMap(); + // Do not forward the input to the extensions delegate if there are no + // unscoped extensions. + std::set<std::string> unscoped_extensions = + GetTemplateURLService()->GetUnscopedModeExtensionIds(); + if (unscoped_extensions.empty()) { return; } - delegate_->IncrementRequestId(); + // Forward the input to the extensions delegate. delegate_->Start(input, minimal_changes, unscoped_extensions); } void UnscopedExtensionProvider::Stop(bool clear_cached_results, bool due_to_user_inactivity) { AutocompleteProvider::Stop(clear_cached_results, due_to_user_inactivity); - if (due_to_user_inactivity) { - delegate_->IncrementRequestId(); - } + delegate_->Stop(clear_cached_results); } TemplateURLService* UnscopedExtensionProvider::GetTemplateURLService() const { @@ -86,24 +83,7 @@ } void UnscopedExtensionProvider::AddToSuggestionGroupsMap( - omnibox::GroupId groupId, - const std::string& header_text) { - // Should never be adding to suggestion groups map beyond max extension - // limit. - DCHECK_LT(next_available_section_index_, kReservedSectionMap.size()); - omnibox::GroupConfig group; - group.set_section(kReservedSectionMap.at(next_available_section_index_++)); - group.set_render_type(omnibox::GroupConfig_RenderType_DEFAULT_VERTICAL); - group.set_header_text(header_text); - suggestion_groups_map_[groupId].MergeFrom(group); -} - -void UnscopedExtensionProvider::ClearSuggestionGroupsMap() { - suggestion_groups_map_.clear(); - next_available_section_index_ = 0; -} - -std::set<std::string> UnscopedExtensionProvider::GetUnscopedModeExtensionIds() - const { - return GetTemplateURLService()->GetUnscopedModeExtensionIds(); + omnibox::GroupId group_id, + omnibox::GroupConfig group_config) { + suggestion_groups_map_[group_id].MergeFrom(group_config); }
diff --git a/components/omnibox/browser/unscoped_extension_provider.h b/components/omnibox/browser/unscoped_extension_provider.h index b21651d..3a3b374 100644 --- a/components/omnibox/browser/unscoped_extension_provider.h +++ b/components/omnibox/browser/unscoped_extension_provider.h
@@ -12,12 +12,13 @@ #include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/autocomplete_provider.h" #include "components/omnibox/browser/omnibox_suggestions_watcher.h" -#include "components/omnibox/browser/unscoped_extension_provider_delegate.h" +#include "third_party/omnibox_proto/groups.pb.h" class AutocompleteInput; class AutocompleteProviderClient; class AutocompleteProviderListener; class TemplateURLService; +class UnscopedExtensionProviderDelegate; // Provides suggestions from extension that are allowed to run in unscoped mode // (i.e. without requiring keyword mode). @@ -29,29 +30,21 @@ UnscopedExtensionProvider& operator=(const UnscopedExtensionProvider&) = delete; - void AddToSuggestionGroupsMap(omnibox::GroupId groupId, - const std::string& header_text); - void ClearSuggestionGroupsMap(); - // AutocompleteProvider: void Start(const AutocompleteInput& input, bool minimal_changes) override; void Stop(bool clear_cached_results, bool due_to_user_inactivity) override; + // Used by UnscopedExtensionProviderDelegateImpl. + TemplateURLService* GetTemplateURLService() const; + void AddToSuggestionGroupsMap(omnibox::GroupId group_id, + omnibox::GroupConfig group_config); void set_done(bool done) { done_ = done; } bool done() const { return done_; } ACMatches* matches() { return &matches_; } - TemplateURLService* GetTemplateURLService() const; - private: ~UnscopedExtensionProvider() override; - // Next section available to be given to an extension groupId. Possible - // sections are defined in `kReservedSectionMap`. - size_t next_available_section_index_ = 0; - - std::set<std::string> GetUnscopedModeExtensionIds() const; - raw_ptr<AutocompleteProviderClient> client_; raw_ptr<TemplateURLService> template_url_service_; std::unique_ptr<UnscopedExtensionProviderDelegate> delegate_;
diff --git a/components/omnibox/browser/unscoped_extension_provider_delegate.h b/components/omnibox/browser/unscoped_extension_provider_delegate.h index 460b866e4..bef3ddc 100644 --- a/components/omnibox/browser/unscoped_extension_provider_delegate.h +++ b/components/omnibox/browser/unscoped_extension_provider_delegate.h
@@ -10,8 +10,6 @@ #include "components/omnibox/browser/autocomplete_input.h" -class AutocompleteInput; - class UnscopedExtensionProviderDelegate { public: UnscopedExtensionProviderDelegate(); @@ -26,8 +24,11 @@ bool minimal_changes, std::set<std::string> unscoped_mode_extension_ids) = 0; - // Increments the id of the request sent to the extension. - virtual void IncrementRequestId() = 0; + // Stops the current request to the extension by incrementing the current + // request ID which effectively discards any suggestions that may be incoming + // later with a stale request ID. if `clear_cached_results` is true, it also + // clears the current list of cached matches and suggestion group information. + virtual void Stop(bool clear_cached_results) = 0; }; #endif // COMPONENTS_OMNIBOX_BROWSER_UNSCOPED_EXTENSION_PROVIDER_DELEGATE_H_
diff --git a/components/omnibox/browser/unscoped_extension_provider_unittest.cc b/components/omnibox/browser/unscoped_extension_provider_unittest.cc index e9dbc2ff..2a8d632 100644 --- a/components/omnibox/browser/unscoped_extension_provider_unittest.cc +++ b/components/omnibox/browser/unscoped_extension_provider_unittest.cc
@@ -48,7 +48,7 @@ Start, (const AutocompleteInput&, bool, std::set<std::string>), (override)); - MOCK_METHOD(void, IncrementRequestId, (), (override)); + MOCK_METHOD(void, Stop, (bool clear_cached_suggestions), (override)); }; protected: @@ -87,7 +87,7 @@ input.set_focus_type(metrics::OmniboxFocusType::INTERACTION_DEFAULT); input.set_omit_asynchronous_matches(false); - EXPECT_CALL(*mock_delegate, IncrementRequestId); + EXPECT_CALL(*mock_delegate, Stop); EXPECT_CALL(*mock_delegate, Start); InitProvider(std::move(mock_delegate)); @@ -104,7 +104,7 @@ TestSchemeClassifier()); input.set_focus_type(metrics::OmniboxFocusType::INTERACTION_DEFAULT); - EXPECT_CALL(*mock_delegate, IncrementRequestId).Times(0); + EXPECT_CALL(*mock_delegate, Stop); EXPECT_CALL(*mock_delegate, Start).Times(0); InitProvider(std::move(mock_delegate)); @@ -122,7 +122,7 @@ input.set_focus_type(metrics::OmniboxFocusType::INTERACTION_DEFAULT); input.set_omit_asynchronous_matches(true); - EXPECT_CALL(*mock_delegate, IncrementRequestId).Times(0); + EXPECT_CALL(*mock_delegate, Stop); EXPECT_CALL(*mock_delegate, Start).Times(0); InitProvider(std::move(mock_delegate)); @@ -138,7 +138,7 @@ TestSchemeClassifier()); input.set_focus_type(metrics::OmniboxFocusType::INTERACTION_FOCUS); - EXPECT_CALL(*mock_delegate, IncrementRequestId).Times(0); + EXPECT_CALL(*mock_delegate, Stop); EXPECT_CALL(*mock_delegate, Start).Times(0); InitProvider(std::move(mock_delegate)); @@ -152,7 +152,7 @@ TestSchemeClassifier()); input.set_focus_type(metrics::OmniboxFocusType::INTERACTION_DEFAULT); - EXPECT_CALL(*mock_delegate, IncrementRequestId).Times(0); + EXPECT_CALL(*mock_delegate, Stop); EXPECT_CALL(*mock_delegate, Start).Times(0); InitProvider(std::move(mock_delegate));
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 e84715c7..ceb3152a 100644 --- a/components/optimization_guide/core/model_execution/on_device_execution.cc +++ b/components/optimization_guide/core/model_execution/on_device_execution.cc
@@ -360,6 +360,11 @@ return; } if (safety_result.is_unsafe || safety_result.is_unsupported_language) { + if (opts_.safety_checker->safety_cfg() + .OnlyCancelUnsafeResponseOnComplete() && + completeness != ResponseCompleteness::kComplete) { + return; + } if (histogram_logger_) { histogram_logger_->set_result(Result::kUsedOnDeviceOutputUnsafe); } @@ -439,6 +444,11 @@ AddModelExecutionLogs(std::move(safety_result.logs)); } if (safety_result.is_unsafe || safety_result.is_unsupported_language) { + if (opts_.safety_checker->safety_cfg() + .OnlyCancelUnsafeResponseOnComplete() && + completeness != ResponseCompleteness::kComplete) { + return; + } if (histogram_logger_) { histogram_logger_->set_result(Result::kUsedOnDeviceOutputUnsafe); }
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 a4219efe..4ed25dc 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
@@ -3094,6 +3094,53 @@ EXPECT_THAT(response_.partials(), ElementsAreArray(expected_responses)); } +TEST_F(OnDeviceModelServiceControllerTest, WaitUntilCompleteToCancel) { + FakeSafetyModelAsset safety_asset([]() { + auto safety_config = ComposeSafetyConfig(); + safety_config.set_only_cancel_unsafe_response_on_complete(true); + safety_config.mutable_safety_category_thresholds()->Add(ForbidUnsafe()); + safety_config.add_allowed_languages("en"); + return safety_config; + }()); + Initialize({ + .base_model = &standard_assets_.base_model, + .safety = &safety_asset, + .language = &standard_assets_.language, + .adaptations = {&standard_assets_.compose}, + }); + auto session = CreateSession(); + EXPECT_TRUE(session); + + fake_settings_.set_execute_result( + {"safe", " safe", " lang:en=1.0", " safe", " unsafe"}); + session->ExecuteModel(PageUrlRequest("foo"), + response_.GetStreamingCallback()); + + // The full output was unsafe so it resulted it in it being filtered. + EXPECT_FALSE(response_.GetFinalStatus()); + EXPECT_EQ( + response_.error(), + OptimizationGuideModelExecutionError::ModelExecutionError::kFiltered); + + const std::vector<std::string> expected_responses = { + // The first two responses are filtered because their language hasn't been + // detected yet. Because `only_cancel_unsafe_response_on_complete` is + // true, this doesn't cause the input to be cancelled. + // + // "safe", "safe safe", + + // The next two responses are not filtered because the language has been + // reliably detected as a supported language. + "safe safe lang:en=1.0", "safe safe lang:en=1.0 safe", + + // The last response is unsafe so it is filtered. Since the output is + // complete the response is cancelled. + // + // "safe safe lang:en=1.0 safe unsafe", + }; + EXPECT_THAT(response_.partials(), ElementsAreArray(expected_responses)); +} + // Validate chunk-by-chunk streaming mode works correctly. TEST_F(OnDeviceModelServiceControllerTest, TsInterval1_ChunkByChunk) { // Configure a token interval to enable streaming responses.
diff --git a/components/optimization_guide/core/model_execution/safety_config.cc b/components/optimization_guide/core/model_execution/safety_config.cc index b5e471c..8b991e6 100644 --- a/components/optimization_guide/core/model_execution/safety_config.cc +++ b/components/optimization_guide/core/model_execution/safety_config.cc
@@ -277,4 +277,8 @@ return result; } +bool SafetyConfig::OnlyCancelUnsafeResponseOnComplete() const { + return proto_ && proto_->only_cancel_unsafe_response_on_complete(); +} + } // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_execution/safety_config.h b/components/optimization_guide/core/model_execution/safety_config.h index b11dde3..3fafe384 100644 --- a/components/optimization_guide/core/model_execution/safety_config.h +++ b/components/optimization_guide/core/model_execution/safety_config.h
@@ -89,6 +89,10 @@ ResponseCompleteness completeness, const on_device_model::mojom::SafetyInfoPtr& safety_info) const; + // Whether this config waits until a unsafe response is complete before + // canceling. + bool OnlyCancelUnsafeResponseOnComplete() const; + private: // Whether the text is in a language not supported by the safety classifier, // or the language could not be detected despite the classifier requiring one
diff --git a/components/optimization_guide/proto/BUILD.gn b/components/optimization_guide/proto/BUILD.gn index f188937..32812a3 100644 --- a/components/optimization_guide/proto/BUILD.gn +++ b/components/optimization_guide/proto/BUILD.gn
@@ -15,6 +15,7 @@ "autofill_field_classification_model_metadata.proto", "client_side_phishing_model_metadata.proto", "common_types.proto", + "contextual_cueing_metadata.proto", "descriptors.proto", "features/bling_prototyping.proto", "features/common_quality_data.proto",
diff --git a/components/optimization_guide/proto/contextual_cueing_metadata.proto b/components/optimization_guide/proto/contextual_cueing_metadata.proto new file mode 100644 index 0000000..f3991d7 --- /dev/null +++ b/components/optimization_guide/proto/contextual_cueing_metadata.proto
@@ -0,0 +1,61 @@ +// 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. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; +option java_package = "org.chromium.components.optimization_guide.proto"; +option java_outer_classname = "ContextualCueingMetadataProto"; + +package optimization_guide.proto; + +enum ContextualCueingClientSignal { + CONTEXTUAL_CUEING_CLIENT_SIGNAL_UNSPECIFIED = 0; + // The number of pages in the PDF, if the page being viewed is a PDF. + CONTEXTUAL_CUEING_CLIENT_SIGNAL_PDF_PAGE_COUNT = 1; + // The number of words in the page being viewed if not a PDF. + CONTEXTUAL_CUEING_CLIENT_SIGNAL_CONTENT_LENGTH_WORD_COUNT = 2; +} + +enum ContextualCueingOperator { + CONTEXTUAL_CUEING_OPERATOR_UNSPECIFIED = 0; + CONTEXTUAL_CUEING_OPERATOR_GREATER_THAN_OR_EQUAL_TO = 1; + CONTEXTUAL_CUEING_OPERATOR_LESS_THAN_OR_EQUAL_TO = 2; +} + +message ContextualCueingConditions { + // The signal to check. + optional ContextualCueingClientSignal signal = 1; + + // The operator to use when comparing the signal to the threshold. + optional ContextualCueingOperator cueing_operator = 2; + + oneof threshold { + // The int64 threshold value to compare the signal to. + int64 int64_threshold = 3; + } +} + +message GlicContextualCueingMetadata { + // Cueing configurations supported for this page. + // + // Take the first one that matches something the current client state and + // capabilities. + // + // If there is no match, then the client should not show any cues. + repeated GlicCueingConfiguration cueing_configurations = 1; +} + +message GlicCueingConfiguration { + // The cue label to show in the tab strip. + // + // This will always be non-empty. + optional string cue_label = 1; + + // The conditions that must be met for this cueing configuration to be + // eligible. This should be treated as an AND operation. + // + // If this list is empty, this cueing configuration is always eligible. + repeated ContextualCueingConditions conditions = 2; +}
diff --git a/components/optimization_guide/proto/text_safety_model_metadata.proto b/components/optimization_guide/proto/text_safety_model_metadata.proto index e602f8b..96bcc2c 100644 --- a/components/optimization_guide/proto/text_safety_model_metadata.proto +++ b/components/optimization_guide/proto/text_safety_model_metadata.proto
@@ -140,4 +140,9 @@ // Configures check that run on parsed model output, with request as context. repeated ResponseSafetyCheck response_check = 6; + + // When enabled, the unsafe text does not cancel a pending response, but + // instead just doesn't send it until it is safe again. If the text is still + // unsafe on complete, then it cancels the pending response. + optional bool only_cancel_unsafe_response_on_complete = 7; }
diff --git a/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc b/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc index e42e545..fd9313c 100644 --- a/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc +++ b/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc
@@ -87,14 +87,6 @@ interface_name, method_name, std::move(callback))); } -scoped_refptr<dbus::Bus> CreateBus() { - dbus::Bus::Options options; - options.bus_type = dbus::Bus::SESSION; - options.connection_type = dbus::Bus::PRIVATE; - options.dbus_task_runner = dbus_thread_linux::GetTaskRunner(); - return base::MakeRefCounted<dbus::Bus>(options); -} - const char* InitStatusToString( FreedesktopSecretKeyProvider::InitStatus status) { switch (status) { @@ -255,7 +247,7 @@ product_name_(product_name), bus_(std::move(bus)) { if (!bus_) { - bus_ = CreateBus(); + bus_ = dbus_thread_linux::GetSharedSessionBus(); } }
diff --git a/components/os_crypt/async/browser/secret_portal_key_provider.cc b/components/os_crypt/async/browser/secret_portal_key_provider.cc index 818f4e3..ad5fcca 100644 --- a/components/os_crypt/async/browser/secret_portal_key_provider.cc +++ b/components/os_crypt/async/browser/secret_portal_key_provider.cc
@@ -40,14 +40,6 @@ constexpr char kSaltForHkdf[] = "fdo_portal_secret_salt"; constexpr char kInfoForHkdf[] = "HKDF-SHA-256 AES-256-GCM"; -scoped_refptr<dbus::Bus> CreateBus() { - dbus::Bus::Options options; - options.bus_type = dbus::Bus::SESSION; - options.connection_type = dbus::Bus::PRIVATE; - options.dbus_task_runner = dbus_thread_linux::GetTaskRunner(); - return base::MakeRefCounted<dbus::Bus>(options); -} - } // namespace // static @@ -59,12 +51,12 @@ SecretPortalKeyProvider::SecretPortalKeyProvider(PrefService* local_state, bool use_for_encryption) - : SecretPortalKeyProvider(local_state, CreateBus(), use_for_encryption) {} + : SecretPortalKeyProvider(local_state, + dbus_thread_linux::GetSharedSessionBus(), + use_for_encryption) {} SecretPortalKeyProvider::~SecretPortalKeyProvider() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - bus_->GetDBusTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&dbus::Bus::ShutdownAndBlock, bus_)); } SecretPortalKeyProvider::SecretPortalKeyProvider(PrefService* local_state,
diff --git a/components/os_crypt/async/browser/secret_portal_key_provider_unittest.cc b/components/os_crypt/async/browser/secret_portal_key_provider_unittest.cc index ef25f690..c3d7f777 100644 --- a/components/os_crypt/async/browser/secret_portal_key_provider_unittest.cc +++ b/components/os_crypt/async/browser/secret_portal_key_provider_unittest.cc
@@ -122,8 +122,6 @@ } void TearDown() override { - EXPECT_CALL(*mock_bus_, ShutdownAndBlock()); - // Shutdown the bus to ensure clean-up key_provider_.reset();
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/ConnectionInfoView.java b/components/page_info/android/java/src/org/chromium/components/page_info/ConnectionInfoView.java index 96d0823..d0c079d 100644 --- a/components/page_info/android/java/src/org/chromium/components/page_info/ConnectionInfoView.java +++ b/components/page_info/android/java/src/org/chromium/components/page_info/ConnectionInfoView.java
@@ -246,7 +246,7 @@ } @Override - public void onDestroy() { + public void webContentsDestroyed() { dismiss(DialogDismissalCause.UNKNOWN); } }; @@ -263,7 +263,7 @@ @Override public void onDismiss(PropertyModel model, @DialogDismissalCause int dismissalCause) { mPopup.onDismiss(); - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mDialogModel = null; }
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java index 41cabf3..440557c 100644 --- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java +++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
@@ -324,9 +324,7 @@ } @Override - public void onDestroy() { - // Force the dialog to close immediately in case the destroy was from Chrome - // quitting. + public void webContentsDestroyed() { PageInfoController.this.destroy(); } @@ -351,6 +349,11 @@ } private void destroy() { + if (mWebContentsObserver != null) { + mWebContentsObserver.observe(null); + mWebContentsObserver = null; + } + if (mDialog != null) { mDialog.destroy(); mDialog = null; @@ -457,8 +460,9 @@ mCurrentSubpageController.onSubpageRemoved(); mCurrentSubpageController = null; } - mWebContentsObserver.destroy(); - mWebContentsObserver = null; + + destroy(); + PageInfoControllerJni.get().destroy(mNativePageInfoController, PageInfoController.this); mNativePageInfoController = 0; mContext = null;
diff --git a/components/policy/resources/templates/policies.yaml b/components/policy/resources/templates/policies.yaml index 3352ed9..82ce65f 100644 --- a/components/policy/resources/templates/policies.yaml +++ b/components/policy/resources/templates/policies.yaml
@@ -1325,7 +1325,7 @@ 1324: WebRtcIPHandlingUrl 1325: GenAIPhotoEditingSettings 1326: PartitionedBlobUrlUsage - 1327: GlicEnabled + 1327: GlicSettings 1328: DefaultControlledFrameSetting 1329: ControlledFrameAllowedForUrls 1330: ControlledFrameBlockedForUrls
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/GlicEnabled.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/GlicSettings.yaml similarity index 77% rename from components/policy/resources/templates/policy_definitions/Miscellaneous/GlicEnabled.yaml rename to components/policy/resources/templates/policy_definitions/Miscellaneous/GlicSettings.yaml index 59c4652..40b2530 100644 --- a/components/policy/resources/templates/policy_definitions/Miscellaneous/GlicEnabled.yaml +++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/GlicSettings.yaml
@@ -1,4 +1,4 @@ -caption: Enable <ph name="GLIC">Glic</ph> +caption: Control <ph name="GLIC">Glic</ph> access desc: |- If this policy is Enabled or not set, users are able to use the <ph name="GLIC">Glic</ph> feature. Setting this policy to Disabled prevents @@ -8,20 +8,25 @@ owners: - bokan@chromium.org - file://chrome/browser/glic/OWNERS -example_value: true +example_value: 0 future_on: - chrome.* features: dynamic_refresh: true per_profile: true -type: main +type: int-enum schema: - type: boolean + type: integer + enum: + - 0 + - 1 items: - caption: Enable use of <ph name="GLIC">Glic</ph> - value: true + name: Enabled + value: 0 - caption: Disable use of <ph name="GLIC">Glic</ph>. - value: false -default: true + name: Disabled + value: 1 +default: 0 tags: - google-sharing
diff --git a/components/policy/test/data/pref_mapping/GlicEnabled.json b/components/policy/test/data/pref_mapping/GlicSettings.json similarity index 77% rename from components/policy/test/data/pref_mapping/GlicEnabled.json rename to components/policy/test/data/pref_mapping/GlicSettings.json index adefe72..feebfdd 100644 --- a/components/policy/test/data/pref_mapping/GlicEnabled.json +++ b/components/policy/test/data/pref_mapping/GlicSettings.json
@@ -7,10 +7,10 @@ ], "simple_policy_pref_mapping_test": { "pref_name": "glic.enabled_by_policy", - "default_value": true, + "default_value": 0, "values_to_test": [ - true, - false + 0, + 1 ] } }
diff --git a/components/power_monitor/power_monitor_device_source_linux.cc b/components/power_monitor/power_monitor_device_source_linux.cc index 96800ac8..42901c0 100644 --- a/components/power_monitor/power_monitor_device_source_linux.cc +++ b/components/power_monitor/power_monitor_device_source_linux.cc
@@ -18,20 +18,8 @@ #include "dbus/object_path.h" #include "dbus/object_proxy.h" -namespace { - -scoped_refptr<dbus::Bus> CreateBus() { - dbus::Bus::Options options; - options.bus_type = dbus::Bus::SYSTEM; - options.connection_type = dbus::Bus::PRIVATE; - options.dbus_task_runner = dbus_thread_linux::GetTaskRunner(); - return base::MakeRefCounted<dbus::Bus>(options); -} - -} // namespace - PowerMonitorDeviceSourceLinux::PowerMonitorDeviceSourceLinux() - : bus_(CreateBus()) { + : bus_(dbus_thread_linux::GetSharedSystemBus()) { bus_->GetObjectProxy("org.freedesktop.login1", dbus::ObjectPath("/org/freedesktop/login1")) ->ConnectToSignal( @@ -42,10 +30,7 @@ weak_ptr_factory_.GetWeakPtr())); } -PowerMonitorDeviceSourceLinux::~PowerMonitorDeviceSourceLinux() { - if (bus_) - ShutdownBus(); -} +PowerMonitorDeviceSourceLinux::~PowerMonitorDeviceSourceLinux() = default; base::PowerStateObserver::BatteryPowerStatus PowerMonitorDeviceSourceLinux::GetBatteryPowerStatus() const { @@ -55,24 +40,16 @@ return base::PowerStateObserver::BatteryPowerStatus::kUnknown; } -void PowerMonitorDeviceSourceLinux::ShutdownBus() { - DCHECK(bus_); - dbus::Bus* const bus_ptr = bus_.get(); - bus_ptr->GetDBusTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&dbus::Bus::ShutdownAndBlock, std::move(bus_))); -} - void PowerMonitorDeviceSourceLinux::OnSignalConnected( const std::string& interface_name, const std::string& signal_name, bool connected) { - if (connected) + if (connected) { return; + } DLOG(ERROR) << "Failed to connect to " << interface_name << " for signal " << signal_name; - if (bus_) - ShutdownBus(); } void PowerMonitorDeviceSourceLinux::OnPrepareForSleep(dbus::Signal* signal) {
diff --git a/components/power_monitor/power_monitor_device_source_linux.h b/components/power_monitor/power_monitor_device_source_linux.h index 0306b73..061b089 100644 --- a/components/power_monitor/power_monitor_device_source_linux.h +++ b/components/power_monitor/power_monitor_device_source_linux.h
@@ -31,7 +31,6 @@ const override; private: - void ShutdownBus(); void OnSignalConnected(const std::string& interface_name, const std::string& signal_name, bool connected);
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc index 2927842e..2930f74 100644 --- a/components/printing/renderer/print_render_frame_helper.cc +++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -1528,11 +1528,14 @@ return; ContentProxySet typeface_content_info; + ContentProxySet image_content_info; MetafileSkia metafile(mojom::SkiaDocumentType::kMSKP, params->document_cookie); - // Provide a typeface context to use with serializing to the print compositor. + // Provide typeface and image contexts to use with serializing to the print + // compositor. metafile.UtilizeTypefaceContext(&typeface_content_info); + metafile.UtilizeImageContext(&image_content_info); gfx::Size area_size = params->printable_area.size(); // Since GetVectorCanvasForNewPage() starts a new recording, it will return @@ -1834,6 +1837,8 @@ } render_metafile->UtilizeTypefaceContext( print_preview_context_.typeface_content_info()); + render_metafile->UtilizeImageContext( + print_preview_context_.image_content_info()); base::TimeTicks begin_time = base::TimeTicks::Now(); PrintPageInternalResult result = PrintPageInternal( print_params, page_index, print_preview_context_.total_page_count(), @@ -2242,12 +2247,15 @@ const mojom::PrintPagesParams& params = *print_pages_params_; const mojom::PrintParams& print_params = *params.params; - // Provide a typeface context to use with serializing to the print compositor. + // Provide typeface and image context to use with serializing to the print + // compositor. ContentProxySet typeface_content_info; + ContentProxySet image_content_info; MetafileSkia metafile(print_params.printed_doc_type, print_params.document_cookie); CHECK(metafile.Init()); metafile.UtilizeTypefaceContext(&typeface_content_info); + metafile.UtilizeImageContext(&image_content_info); bool generate_tagged_pdf = print_params.generate_tagged_pdf.value_or( delegate_->ShouldGenerateTaggedPDF()); @@ -3038,10 +3046,17 @@ return &typeface_content_info_; } +ContentProxySet* +PrintRenderFrameHelper::PrintPreviewContext::image_content_info() { + DCHECK(IsRendering()); + return &image_content_info_; +} + void PrintRenderFrameHelper::PrintPreviewContext::ClearContext() { prep_frame_view_.reset(); metafile_.reset(); typeface_content_info_.clear(); + image_content_info_.clear(); pages_to_render_.clear(); error_ = PrintPreviewErrorBuckets::kNone; }
diff --git a/components/printing/renderer/print_render_frame_helper.h b/components/printing/renderer/print_render_frame_helper.h index ce8ac0a..97cb6458 100644 --- a/components/printing/renderer/print_render_frame_helper.h +++ b/components/printing/renderer/print_render_frame_helper.h
@@ -557,6 +557,7 @@ size_t pages_rendered_count() const; MetafileSkia* metafile(); ContentProxySet* typeface_content_info(); + ContentProxySet* image_content_info(); private: enum class State { @@ -580,6 +581,9 @@ // The typefaces encountered in the content during document serialization. ContentProxySet typeface_content_info_; + // The images encountered in the content during document serialization. + ContentProxySet image_content_info_; + // A document metafile is needed when not using the print compositor. std::unique_ptr<MetafileSkia> metafile_;
diff --git a/components/privacy_sandbox/tracking_protection_settings.cc b/components/privacy_sandbox/tracking_protection_settings.cc index 6265222..6671c3a5 100644 --- a/components/privacy_sandbox/tracking_protection_settings.cc +++ b/components/privacy_sandbox/tracking_protection_settings.cc
@@ -118,7 +118,8 @@ bool TrackingProtectionSettings::IsFpProtectionEnabled() const { return pref_service_->GetBoolean(prefs::kFingerprintingProtectionEnabled) && - base::FeatureList::IsEnabled(kFingerprintingProtectionUx); + base::FeatureList::IsEnabled(kFingerprintingProtectionUx) && + is_incognito_; } bool TrackingProtectionSettings::IsDoNotTrackEnabled() const {
diff --git a/components/privacy_sandbox/tracking_protection_settings_unittest.cc b/components/privacy_sandbox/tracking_protection_settings_unittest.cc index a50d6fa0..874c14d 100644 --- a/components/privacy_sandbox/tracking_protection_settings_unittest.cc +++ b/components/privacy_sandbox/tracking_protection_settings_unittest.cc
@@ -104,11 +104,15 @@ EXPECT_TRUE(tracking_protection_settings()->IsIpProtectionEnabled()); } -TEST_F(TrackingProtectionSettingsTest, ReturnsFpProtectionStatus) { - EXPECT_FALSE(prefs()->GetBoolean(prefs::kFingerprintingProtectionEnabled)); - EXPECT_FALSE(tracking_protection_settings()->IsFpProtectionEnabled()); +TEST_F(TrackingProtectionSettingsTest, + IsFpProtectionEnabledOnlyReturnsTrueInIncognito) { prefs()->SetBoolean(prefs::kFingerprintingProtectionEnabled, true); - EXPECT_TRUE(tracking_protection_settings()->IsFpProtectionEnabled()); + EXPECT_TRUE(TrackingProtectionSettings(prefs(), host_content_settings_map(), + /*is_incognito=*/true) + .IsFpProtectionEnabled()); + EXPECT_FALSE(TrackingProtectionSettings(prefs(), host_content_settings_map(), + /*is_incognito=*/false) + .IsFpProtectionEnabled()); } TEST_F(TrackingProtectionSettingsTest, ReturnsTrackingProtection3pcdStatus) {
diff --git a/components/search_engines/template_url_parser.cc b/components/search_engines/template_url_parser.cc index 3a7f7e5..4482e7ad 100644 --- a/components/search_engines/template_url_parser.cc +++ b/components/search_engines/template_url_parser.cc
@@ -55,6 +55,9 @@ // Mime type for as you type suggestions. const char kSuggestionType[] = "application/x-suggestions+json"; +// Short name and keyword string lengths are capped for security. +constexpr size_t kMaxNameLength = 1024; + // Returns true if input_encoding contains a valid input encoding string. This // doesn't verify that we have a valid encoding for the string, just that the // string contains characters that constitute a valid input encoding. @@ -413,6 +416,14 @@ return nullptr; } + // To avoid potential downstream issues when using the data (for example + // crossing IPC for presentation in search engines UI), data that exceeds + // the limit is not finalized and accepted. + if (template_url->data().short_name().length() > kMaxNameLength || + template_url->data().keyword().length() > kMaxNameLength) { + return nullptr; + } + return template_url; }
diff --git a/components/services/print_compositor/BUILD.gn b/components/services/print_compositor/BUILD.gn index ee69dc2..b2e2c8a 100644 --- a/components/services/print_compositor/BUILD.gn +++ b/components/services/print_compositor/BUILD.gn
@@ -66,9 +66,8 @@ deps += [ "//cc:test_support", "//components/enterprise/watermarking", + "//components/enterprise/watermarking:watermark_test_utils", ] - - public_deps = [ "//components/enterprise/watermarking/mojom" ] } } }
diff --git a/components/services/print_compositor/print_compositor_impl.cc b/components/services/print_compositor/print_compositor_impl.cc index 45ea749..33dadae 100644 --- a/components/services/print_compositor/print_compositor_impl.cc +++ b/components/services/print_compositor/print_compositor_impl.cc
@@ -440,7 +440,8 @@ } std::vector<SkDocumentPage> pages(page_count); - SkDeserialProcs procs = DeserializationProcs(&subframes, &typefaces_); + SkDeserialProcs procs = + DeserializationProcs(&subframes, &typefaces_, &images_); if (!SkMultiPictureDocument::Read(&stream, pages.data(), page_count, &procs)) { DLOG(ERROR) << "CompositePages: Page reading failed."; @@ -499,8 +500,8 @@ // Composite the entire frame. SkMemoryStream stream(frame_info->serialized_content.data(), frame_info->serialized_content.size()); - SkDeserialProcs procs = - DeserializationProcs(&subframes, &frame_info->typefaces); + SkDeserialProcs procs = DeserializationProcs( + &subframes, &frame_info->typefaces, &frame_info->images); frame_info->content = SkPicture::MakeFromStream(&stream, &procs); }
diff --git a/components/services/print_compositor/print_compositor_impl.h b/components/services/print_compositor/print_compositor_impl.h index f0c67514..7b850b60 100644 --- a/components/services/print_compositor/print_compositor_impl.h +++ b/components/services/print_compositor/print_compositor_impl.h
@@ -24,6 +24,7 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" #include "printing/buildflags/buildflags.h" +#include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkStream.h" @@ -158,6 +159,7 @@ base::flat_map<uint32_t, sk_sp<SkPicture>>; using TypefaceDeserializationContext = base::flat_map<uint32_t, sk_sp<SkTypeface>>; + using ImageDeserializationContext = base::flat_map<uint32_t, sk_sp<SkImage>>; // Base structure to store a frame's content and its subframe // content information. @@ -178,6 +180,9 @@ // Typefaces used within scope of this frame. TypefaceDeserializationContext typefaces; + + // Images used within scope of this frame. + ImageDeserializationContext images; }; // Other than content, it also stores the status during frame composition. @@ -285,6 +290,9 @@ // Context for dealing with all typefaces encountered across multiple pages. TypefaceDeserializationContext typefaces_; + // Context for dealing with all images encountered across multiple pages. + ImageDeserializationContext images_; + std::vector<std::unique_ptr<RequestInfo>> requests_; std::unique_ptr<DocumentInfo> doc_info_;
diff --git a/components/services/print_compositor/print_compositor_impl_unittest.cc b/components/services/print_compositor/print_compositor_impl_unittest.cc index bf70a4d..2c322a0d 100644 --- a/components/services/print_compositor/print_compositor_impl_unittest.cc +++ b/components/services/print_compositor/print_compositor_impl_unittest.cc
@@ -21,19 +21,14 @@ #include "testing/gtest/include/gtest/gtest.h" #if BUILDFLAG(ENTERPRISE_WATERMARK) -#include "base/memory/shared_memory_mapping.h" #include "base/test/scoped_feature_list.h" #include "cc/test/pixel_test_utils.h" // nogncheck #include "components/enterprise/watermarking/features.h" // nogncheck #include "components/enterprise/watermarking/mojom/watermark.mojom.h" // nogncheck #include "components/enterprise/watermarking/watermark.h" // nogncheck -#include "skia/ext/font_utils.h" +#include "components/enterprise/watermarking/watermark_test_utils.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkColor.h" -#include "third_party/skia/include/core/SkPictureRecorder.h" -#include "third_party/skia/include/core/SkSerialProcs.h" -#include "third_party/skia/include/core/SkTextBlob.h" #include "third_party/skia/include/docs/SkMultiPictureDocument.h" #endif @@ -111,51 +106,14 @@ }; #if BUILDFLAG(ENTERPRISE_WATERMARK) - -watermark::mojom::WatermarkBlockPtr MakeTestWatermarkBlock( - const std::string& watermark_text) { - // Initialize text blob - static constexpr SkScalar kTextSize = 30.0f; - SkFont font(skia::DefaultTypeface(), kTextSize, 1.0f, 0.0f); - sk_sp<SkTextBlob> blob = - SkTextBlob::MakeFromString(watermark_text.c_str(), font); - - // Draw onto SkPicture-backed SkCanvas - SkPictureRecorder recorder; - SkCanvas* canvas = recorder.beginRecording( - SkRect{SkRect::MakeWH(kWatermarkSize.fWidth, kWatermarkSize.fHeight)}); - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas->drawTextBlob(blob.get(), 0.0f, 0.0f, paint); - sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); - - // Serialize SkPicture - SkDynamicMemoryWStream stream; - SkSerialProcs procs; - picture->serialize(&stream, &procs); - base::MappedReadOnlyRegion region_mapping = - base::ReadOnlySharedMemoryRegion::Create(stream.bytesWritten()); - if (!region_mapping.IsValid()) { - return nullptr; - } - stream.copyTo(region_mapping.mapping.memory()); - - // Measure string dimensions - SkScalar text_width = font.measureText( - watermark_text.c_str(), watermark_text.size(), SkTextEncoding::kUTF8); - - // Construct test data - return watermark::mojom::WatermarkBlockPtr( - std::in_place, std::move(region_mapping.region), text_width, kTextSize); -} - class MockPrintCompositorImplEnterpriseWatermark : public PrintCompositorImpl { public: MockPrintCompositorImplEnterpriseWatermark() : PrintCompositorImpl(mojo::NullReceiver(), /*initialize_environment=*/false, /*io_task_runner=*/nullptr) { - SetWatermarkBlock(MakeTestWatermarkBlock(kWatermarkText)); + SetWatermarkBlock(enterprise_watermark::MakeTestWatermarkBlock( + kWatermarkText, kWatermarkSize)); } ~MockPrintCompositorImplEnterpriseWatermark() override = default; @@ -250,7 +208,8 @@ kWatermarkSize.fHeight); SkCanvas canvas(reference_watermark_); canvas.clear(SK_ColorBLACK); - const auto watermark_block = MakeTestWatermarkBlock(kWatermarkText); + const auto watermark_block = enterprise_watermark::MakeTestWatermarkBlock( + kWatermarkText, kWatermarkSize); DrawWatermarkBlockForTesting(&canvas, kWatermarkSize, watermark_block); }
diff --git a/components/sessions/core/tab_restore_service_helper.cc b/components/sessions/core/tab_restore_service_helper.cc index 668c5ed..84d2238 100644 --- a/components/sessions/core/tab_restore_service_helper.cc +++ b/components/sessions/core/tab_restore_service_helper.cc
@@ -692,7 +692,10 @@ if (window.tabs.empty()) { // Remove the entry if there is nothing left to restore. - entries_.erase(entry_iterator); + // The entries_ may by changed after the tabs restored and the + // entry_iterator may be no longer valid. So call RemoveEntryById here + // instead of entries_.erase(entry_iterator). + RemoveEntryById(id); } } @@ -745,7 +748,10 @@ CHECK(ValidateGroup(group)); group.tabs.erase(group.tabs.begin() + i); if (group.tabs.empty()) { - entries_.erase(entry_iterator); + // The entries_ may by changed after the tabs restored and the + // entry_iterator may be no longer valid. So call RemoveEntryById + // here instead of entries_.erase(entry_iterator). + RemoveEntryById(id); } break; @@ -759,7 +765,10 @@ } if (entry_id_matches_restore_id) { - entries_.erase(entry_iterator); + // The entries_ may by changed after the tabs restored and the + // entry_iterator may be no longer valid. So call RemoveEntryById here + // instead of entries_.erase(entry_iterator). + RemoveEntryById(id); } restoring_ = false;
diff --git a/components/variations/BUILD.gn b/components/variations/BUILD.gn index 2eb17c3..6e23d913 100644 --- a/components/variations/BUILD.gn +++ b/components/variations/BUILD.gn
@@ -114,14 +114,6 @@ ] } - if (is_android) { - sources += [ - "android/variations_associated_data_android.cc", - "android/variations_seed_bridge.cc", - "android/variations_seed_bridge.h", - ] - } - if (is_chromeos) { sources += [ "variations_crash_keys_chromeos.cc", @@ -148,7 +140,11 @@ ] if (is_android) { - deps += [ "//components/variations/android:variations_jni" ] + sources += [ + "android/variations_seed_bridge.cc", + "android/variations_seed_bridge.h", + ] + deps += [ "//components/variations/android:variations_seed_jni" ] } if (is_chromeos) { @@ -160,6 +156,15 @@ } if (is_android) { + static_library("variations_associated_data") { + sources = [ "android/variations_associated_data_android.cc" ] + deps = [ + ":variations", + "//components/variations/android:variations_data_jni", + "//components/variations/net", + ] + } + java_cpp_strings("java_switches_srcjar") { # External code should depend on ":variations_java" instead. visibility = [ ":*" ]
diff --git a/components/variations/android/BUILD.gn b/components/variations/android/BUILD.gn index 8fb1ab1..6dbdd640 100644 --- a/components/variations/android/BUILD.gn +++ b/components/variations/android/BUILD.gn
@@ -5,10 +5,13 @@ import("//build/config/android/rules.gni") import("//third_party/jni_zero/jni_zero.gni") -generate_jni("variations_jni") { +generate_jni("variations_seed_jni") { + sources = [ "java/src/org/chromium/components/variations/firstrun/VariationsSeedBridge.java" ] +} + +generate_jni("variations_data_jni") { sources = [ "java/src/org/chromium/components/variations/VariationsAssociatedData.java", - "java/src/org/chromium/components/variations/firstrun/VariationsSeedBridge.java", ] } @@ -24,7 +27,10 @@ "//third_party/jni_zero:jni_zero_java", ] - srcjar_deps = [ ":variations_jni" ] + srcjar_deps = [ + ":variations_data_jni", + ":variations_seed_jni", + ] sources = [ "java/src/org/chromium/components/variations/NormalizedMurmurHashEntropyProvider.java", "java/src/org/chromium/components/variations/VariationsAssociatedData.java",
diff --git a/components/variations/android/java/src/org/chromium/components/variations/VariationsAssociatedData.java b/components/variations/android/java/src/org/chromium/components/variations/VariationsAssociatedData.java index fdbd299d..bfbb226 100644 --- a/components/variations/android/java/src/org/chromium/components/variations/VariationsAssociatedData.java +++ b/components/variations/android/java/src/org/chromium/components/variations/VariationsAssociatedData.java
@@ -28,6 +28,14 @@ return VariationsAssociatedDataJni.get().getVariationParamValue(trialName, paramName); } + /** + * Get a HashMap with the value of a space-separated string containing the list of current + * active variations (as would be reported in the |variation_id| repeated field of the + * ClientVariations proto) for a given ID collection. See more at + * `VariationsIdsProvider::GetVariationsString()`. + * + * @return A HashMap with value containing the current active variations. + */ public static HashMap<String, String> getFeedbackMap() { HashMap<String, String> map = new HashMap<String, String>(); map.put("Chrome Variations", VariationsAssociatedDataJni.get().getFeedbackVariations()); @@ -35,11 +43,24 @@ } /** + * Get the encrypted variations state. Variations state is the commandline variations that a + * person can pass in to Chrome, which specifies Chrome features' on or off states. See more at + * `VariationsCommandLine::EncryptToString()` + * + * @return A HashMap with value containing the encrypted variations state. + */ + public static HashMap<String, String> getVariationsStateFeedbackMap() { + HashMap<String, String> map = new HashMap<String, String>(); + map.put("Chrome Variations State", VariationsAssociatedDataJni.get().getVariationsState()); + return map; + } + + /** * Returns the list of Google App variations from active finch field trials. - * @return A space separated list of ids with leading and trailing space. - * For example, " 123 456 ". - * IMPORTANT: This string is only approved for integrations with the Android - * Google App and must receive a privacy review before extending to other apps. + * + * @return A space separated list of ids with leading and trailing space. e.g. " 123 456 ". + * IMPORTANT: This string is only approved for integrations with the Android Google App and + * must receive a privacy review before extending to other apps. */ public static String getGoogleAppVariations() { String variations = VariationsAssociatedDataJni.get().getGoogleAppVariations(); @@ -52,6 +73,8 @@ String getFeedbackVariations(); + String getVariationsState(); + String getGoogleAppVariations(); } }
diff --git a/components/variations/android/variations_associated_data_android.cc b/components/variations/android/variations_associated_data_android.cc index 3b81de1..f9ce88e3 100644 --- a/components/variations/android/variations_associated_data_android.cc +++ b/components/variations/android/variations_associated_data_android.cc
@@ -5,12 +5,14 @@ #include <string> #include "base/android/jni_string.h" +#include "base/base64.h" #include "base/metrics/field_trial_params.h" -#include "components/variations/variations_associated_data.h" +#include "base/metrics/histogram_functions.h" +#include "components/variations/net/variations_command_line.h" #include "components/variations/variations_ids_provider.h" // Must come after all headers that specialize FromJniType() / ToJniType(). -#include "components/variations/android/variations_jni/VariationsAssociatedData_jni.h" +#include "components/variations/android/variations_data_jni/VariationsAssociatedData_jni.h" using base::android::ConvertJavaStringToUTF8; using base::android::ConvertUTF8ToJavaString; @@ -38,6 +40,24 @@ return ConvertUTF8ToJavaString(env, values); } +ScopedJavaLocalRef<jstring> JNI_VariationsAssociatedData_GetVariationsState( + JNIEnv* env) { + if (!base::FeatureList::IsEnabled(variations::kFeedbackIncludeVariations)) { + return nullptr; + } + std::vector<uint8_t> ciphertext; + const auto status = + variations::VariationsCommandLine::GetForCurrentProcess().EncryptToString( + &ciphertext); + base::UmaHistogramEnumeration("Variations.VariationsStateEncryptionStatus", + status); + if (status != variations::VariationsStateEncryptionStatus::kSuccess) { + return nullptr; + } + std::string value = base::Base64Encode(ciphertext); + return ConvertUTF8ToJavaString(env, value); +} + ScopedJavaLocalRef<jstring> JNI_VariationsAssociatedData_GetGoogleAppVariations( JNIEnv* env) { const std::string values =
diff --git a/components/variations/android/variations_seed_bridge.cc b/components/variations/android/variations_seed_bridge.cc index 39db2c3..9240ddd 100644 --- a/components/variations/android/variations_seed_bridge.cc +++ b/components/variations/android/variations_seed_bridge.cc
@@ -14,7 +14,7 @@ #include "base/time/time.h" // Must come after all headers that specialize FromJniType() / ToJniType(). -#include "components/variations/android/variations_jni/VariationsSeedBridge_jni.h" +#include "components/variations/android/variations_seed_jni/VariationsSeedBridge_jni.h" using base::android::AttachCurrentThread; using base::android::ConvertJavaStringToUTF8;
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc index c9f75e4..83bfa29 100644 --- a/components/viz/common/features.cc +++ b/components/viz/common/features.cc
@@ -264,14 +264,6 @@ BASE_FEATURE(kVSyncAlignedPresent, "VSyncAlignedPresent", base::FEATURE_DISABLED_BY_DEFAULT); - -// The paramters for the number of supported pending Frames. -// 1: Support one pending frame. This is the old default. -// 2: Support two pending frames. New. This is the number of max pending -// swap in the scheduler. -// Others: Error! It will be overwritten to 2 pending frames. -const base::FeatureParam<int> kNumPendingFrames{&kVSyncAlignedPresent, - "PendingFrames", 2}; #endif BASE_FEATURE(kAllowUndamagedNonrootRenderPassToSkip, @@ -633,18 +625,6 @@ bool IsVSyncAlignedPresentEnabled() { return base::FeatureList::IsEnabled(features::kVSyncAlignedPresent); } - -int NumPendingFrameSupported() { - // Return the old default if this feature is not enabled. - if (!base::FeatureList::IsEnabled(kVSyncAlignedPresent)) { - return 1; - } - - // Unless 1 pending frame is specified, overwrite all other params to the new - // default, 2 pending frames. - int num = kNumPendingFrames.Get() == 1 ? 1 : 2; - return num; -} #endif #if BUILDFLAG(IS_CHROMEOS)
diff --git a/components/viz/common/features.h b/components/viz/common/features.h index 82d6a04..a5042a0 100644 --- a/components/viz/common/features.h +++ b/components/viz/common/features.h
@@ -168,7 +168,6 @@ VIZ_COMMON_EXPORT std::optional<double> SnapshotEvictedRootSurfaceScale(); VIZ_COMMON_EXPORT bool IsCVDisplayLinkBeginFrameSourceEnabled(); VIZ_COMMON_EXPORT bool IsVSyncAlignedPresentEnabled(); -VIZ_COMMON_EXPORT int NumPendingFrameSupported(); VIZ_COMMON_EXPORT bool ShouldLogFrameQuadInfo(); VIZ_COMMON_EXPORT bool IsUsingFrameIntervalDecider(); VIZ_COMMON_EXPORT std::optional<uint64_t>
diff --git a/components/viz/common/quads/compositor_frame_metadata.cc b/components/viz/common/quads/compositor_frame_metadata.cc index ecdeeca..104c8b2 100644 --- a/components/viz/common/quads/compositor_frame_metadata.cc +++ b/components/viz/common/quads/compositor_frame_metadata.cc
@@ -31,6 +31,7 @@ content_color_usage(other.content_color_usage), may_contain_video(other.may_contain_video), is_handling_interaction(other.is_handling_interaction), + is_handling_animation(other.is_handling_animation), root_background_color(other.root_background_color), latency_info(other.latency_info), referenced_surfaces(other.referenced_surfaces),
diff --git a/components/viz/common/quads/compositor_frame_metadata.h b/components/viz/common/quads/compositor_frame_metadata.h index 306d16f..09e9c03d 100644 --- a/components/viz/common/quads/compositor_frame_metadata.h +++ b/components/viz/common/quads/compositor_frame_metadata.h
@@ -112,6 +112,9 @@ // gesture scroll events. bool is_handling_interaction = false; + // True if this compositor frame contains animations. + bool is_handling_animation = false; + // This color is usually obtained from the background color of the <body> // element. It can be used for filling in gutter areas around the frame when // it's too small to fill the box the parent reserved for it.
diff --git a/components/viz/common/quads/compositor_frame_metadata_unittest.cc b/components/viz/common/quads/compositor_frame_metadata_unittest.cc index 90609c62d..c0cddaa 100644 --- a/components/viz/common/quads/compositor_frame_metadata_unittest.cc +++ b/components/viz/common/quads/compositor_frame_metadata_unittest.cc
@@ -62,6 +62,7 @@ metadata.content_color_usage = gfx::ContentColorUsage::kHDR; metadata.may_contain_video = true; metadata.is_handling_interaction = true; + metadata.is_handling_animation = true; metadata.root_background_color = SkColors::kBlue; metadata.latency_info.emplace_back(); metadata.referenced_surfaces.emplace_back( @@ -94,6 +95,7 @@ EXPECT_EQ(clone.content_color_usage, metadata.content_color_usage); EXPECT_EQ(clone.may_contain_video, metadata.may_contain_video); EXPECT_EQ(clone.is_handling_interaction, metadata.is_handling_interaction); + EXPECT_EQ(clone.is_handling_animation, metadata.is_handling_animation); EXPECT_EQ(clone.root_background_color, metadata.root_background_color); EXPECT_EQ(clone.latency_info.size(), metadata.latency_info.size());
diff --git a/components/viz/common/resources/transferable_resource.cc b/components/viz/common/resources/transferable_resource.cc index ba098e9..7eb9b09 100644 --- a/components/viz/common/resources/transferable_resource.cc +++ b/components/viz/common/resources/transferable_resource.cc
@@ -9,23 +9,6 @@ namespace viz { // static -TransferableResource TransferableResource::MakeSoftwareSharedBitmap( - const SharedBitmapId& id, - const gpu::SyncToken& sync_token, - const gfx::Size& size, - SharedImageFormat format, - ResourceSource source) { - TransferableResource r; - r.is_software = true; - r.memory_buffer_id_ = id; - r.sync_token_ = sync_token; - r.size = size; - r.format = format; - r.resource_source = source; - return r; -} - -// static TransferableResource TransferableResource::MakeSoftwareSharedImage( const scoped_refptr<gpu::ClientSharedImage>& client_shared_image, const gpu::SyncToken& sync_token, @@ -127,9 +110,4 @@ return out; } -bool TransferableResource::IsSoftwareSharedImage() const { - CHECK(is_software); - return absl::holds_alternative<gpu::Mailbox>(memory_buffer_id_); -} - } // namespace viz
diff --git a/components/viz/common/resources/transferable_resource.h b/components/viz/common/resources/transferable_resource.h index e738d2b2..83527e5 100644 --- a/components/viz/common/resources/transferable_resource.h +++ b/components/viz/common/resources/transferable_resource.h
@@ -30,8 +30,6 @@ namespace viz { -using MemoryBufferId = absl::variant<gpu::Mailbox, SharedBitmapId>; - struct ReturnedResource; struct VIZ_COMMON_EXPORT TransferableResource { @@ -95,12 +93,6 @@ const MetadataOverride& override = {}); // Following Make* functions are deprecated. Please use the one above. - static TransferableResource MakeSoftwareSharedBitmap( - const SharedBitmapId& id, - const gpu::SyncToken& sync_token, - const gfx::Size& size, - SharedImageFormat format, - ResourceSource source = ResourceSource::kUnknown); static TransferableResource MakeSoftwareSharedImage( const scoped_refptr<gpu::ClientSharedImage>& client_shared_image, const gpu::SyncToken& sync_token, @@ -133,16 +125,7 @@ ReturnedResource ToReturnedResource() const; static std::vector<ReturnedResource> ReturnResources( const std::vector<TransferableResource>& input); - bool is_empty() const { - return (absl::holds_alternative<gpu::Mailbox>(memory_buffer_id_) && - mailbox().IsZero()) || - (absl::holds_alternative<SharedBitmapId>(memory_buffer_id_) && - shared_bitmap_id().IsZero()); - } - - // Returns true if this resource (which must be software) is holding a - // SharedImage ID rather than a SharedBitmapId. - bool IsSoftwareSharedImage() const; + bool is_empty() const { return mailbox().IsZero(); } // 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). @@ -167,9 +150,6 @@ void set_mailbox(const gpu::Mailbox& mailbox) { memory_buffer_id_ = mailbox; } - void set_shared_bitmap_id(const SharedBitmapId& shared_bitmap_id) { - memory_buffer_id_ = shared_bitmap_id; - } void set_sync_token(const gpu::SyncToken& sync_token) { sync_token_ = sync_token; } @@ -179,14 +159,8 @@ // Returns the Mailbox that this instance is storing. Valid to call only if // this instance has been created via MakeSoftwareSharedImage() or MakeGpu(). - const gpu::Mailbox& mailbox() const { - return absl::get<gpu::Mailbox>(memory_buffer_id_); - } - // Returns the SharedBitmapId that this instance is storing. Valid to call - // only if this instance has been created via MakeSoftwareSharedBitmap(). - const SharedBitmapId& shared_bitmap_id() const { - return absl::get<SharedBitmapId>(memory_buffer_id_); - } + const gpu::Mailbox& mailbox() const { return memory_buffer_id_; } + const gpu::SyncToken& sync_token() const { return sync_token_; } gpu::SyncToken& mutable_sync_token() { return sync_token_; } uint32_t texture_target() const { return texture_target_; } @@ -266,13 +240,13 @@ bool operator!=(const TransferableResource& o) const { return !(*this == o); } // For usage only in Mojo serialization/deserialization. - const MemoryBufferId& memory_buffer_id() const { return memory_buffer_id_; } - void set_memory_buffer_id(MemoryBufferId memory_buffer_id) { + const gpu::Mailbox& memory_buffer_id() const { return memory_buffer_id_; } + void set_memory_buffer_id(gpu::Mailbox memory_buffer_id) { memory_buffer_id_ = memory_buffer_id; } private: - MemoryBufferId memory_buffer_id_; + gpu::Mailbox memory_buffer_id_; // TODO(crbug.com/337538024): Remove once DUMP_WILL_BE_CHECK() in // TransferableResource::mailbox() has safely rolled out.
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn index 556c719..f43d8a8 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn
@@ -123,7 +123,6 @@ "display/resolved_frame_data.h", "display/resource_fence.cc", "display/resource_fence.h", - "display/shared_bitmap_manager.h", "display/skia_output_surface.cc", "display/skia_output_surface.h", "display/skia_renderer.cc", @@ -148,8 +147,6 @@ "display_embedder/output_surface_provider.h", "display_embedder/output_surface_provider_impl.cc", "display_embedder/output_surface_provider_impl.h", - "display_embedder/server_shared_bitmap_manager.cc", - "display_embedder/server_shared_bitmap_manager.h", "display_embedder/skia_output_device.cc", "display_embedder/skia_output_device.h", "display_embedder/skia_output_device_buffer_queue.cc", @@ -598,7 +595,6 @@ "display/viz_pixel_test.cc", "display/viz_pixel_test.h", "display_embedder/buffer_queue_unittest.cc", - "display_embedder/server_shared_bitmap_manager_unittest.cc", "display_embedder/skia_output_device_buffer_queue_unittest.cc", "display_embedder/skia_output_surface_impl_unittest.cc", "display_embedder/software_output_surface_unittest.cc",
diff --git a/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc b/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc index f9e832e1..c0bb6af 100644 --- a/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc +++ b/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc
@@ -36,8 +36,7 @@ : root_local_surface_id_(1, 1, base::UnguessableToken::Create()), output_surface_provider_(std::move(png_dir_path)), frame_sink_manager_( - FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_, - &output_surface_provider_)) { + FrameSinkManagerImpl::InitParams(&output_surface_provider_)) { frame_sink_manager_.RegisterFrameSinkId(kEmbeddedFrameSinkId, /*report_activation=*/false); frame_sink_manager_.RegisterFrameSinkId(kRootFrameSinkId,
diff --git a/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.h b/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.h index 80927d7..bb45d64 100644 --- a/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.h +++ b/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.h
@@ -12,7 +12,6 @@ #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.h" #include "components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/test/fake_compositor_frame_sink_client.h" #include "components/viz/test/fake_display_client.h" @@ -52,7 +51,6 @@ const LocalSurfaceId root_local_surface_id_; - ServerSharedBitmapManager shared_bitmap_manager_; FuzzerSoftwareOutputSurfaceProvider output_surface_provider_; FrameSinkManagerImpl frame_sink_manager_;
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h index 1995936..472906e 100644 --- a/components/viz/service/display/direct_renderer.h +++ b/components/viz/service/display/direct_renderer.h
@@ -120,6 +120,9 @@ // integration testing. gfx::CALayerResult ca_layer_error_code = gfx::kCALayerSuccess; #endif + + bool is_handling_interaction_or_animation = false; + std::optional<int64_t> choreographer_vsync_id; int64_t swap_trace_id = -1; };
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index 4efa0584..80fcf23 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -1107,6 +1107,7 @@ std::move(animation_thread_ids), std::move(renderer_main_thread_ids), boost_type); + bool has_interactive_or_animated_frame = false; for (const auto& surface_id : aggregator_->previous_contained_surfaces()) { surface = surface_manager_->GetSurfaceForId(surface_id); if (surface) { @@ -1115,6 +1116,11 @@ if (helper) { presentation_group_timing.AddPresentationHelper(std::move(helper)); } + + has_interactive_or_animated_frame |= + surface->HasActiveFrame() && + (surface->GetActiveFrameMetadata().is_handling_interaction || + surface->GetActiveFrameMetadata().is_handling_animation); } } @@ -1150,11 +1156,14 @@ swap_frame_data.ca_layer_error_code = overlay_processor_->GetCALayerErrorCode(); #endif + swap_frame_data.is_handling_interaction_or_animation = + has_interactive_or_animated_frame; // We must notify scheduler and increase |pending_swaps_| before calling // SwapBuffers() as it can call DidReceiveSwapBuffersAck synchronously. - if (scheduler_) + if (scheduler_) { scheduler_->DidSwapBuffers(); + } pending_swaps_++; UMA_HISTOGRAM_COUNTS_100("Compositing.Display.PendingSwaps",
diff --git a/components/viz/service/display/display_damage_tracker_unittest.cc b/components/viz/service/display/display_damage_tracker_unittest.cc index eaeb166..cbfed845 100644 --- a/components/viz/service/display/display_damage_tracker_unittest.cc +++ b/components/viz/service/display/display_damage_tracker_unittest.cc
@@ -13,7 +13,6 @@ #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/service/display/display_resource_provider_software.h" #include "components/viz/service/display/surface_aggregator.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/test/compositor_frame_helpers.h" @@ -33,7 +32,7 @@ class DisplayDamageTrackerTest : public testing::Test { public: DisplayDamageTrackerTest() - : manager_(FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)), + : manager_(FrameSinkManagerImpl::InitParams()), resource_provider_(&shared_image_manager_, &gpu_scheduler_), aggregator_(manager_.surface_manager(), &resource_provider_, false), root_client_(&manager_, kRootFrameSinkId), @@ -117,7 +116,6 @@ fake_begin_frame_source_.TestOnBeginFrame(last_begin_frame_args_); } - ServerSharedBitmapManager shared_bitmap_manager_; gpu::SharedImageManager shared_image_manager_; gpu::SyncPointManager sync_point_manager_; gpu::Scheduler gpu_scheduler_{&sync_point_manager_};
diff --git a/components/viz/service/display/display_resource_provider.cc b/components/viz/service/display/display_resource_provider.cc index 27196bfb..ed19cd98 100644 --- a/components/viz/service/display/display_resource_provider.cc +++ b/components/viz/service/display/display_resource_provider.cc
@@ -244,12 +244,6 @@ } ResourceId local_id = resource_id_generator_.GenerateNextId(); - - // If using legacy shared bitmaps, verify that the format is supported. - DCHECK(!transferable_resource.is_software || - transferable_resource.IsSoftwareSharedImage() || - (!transferable_resource.IsSoftwareSharedImage() && - transferable_resource.format.IsBitmapFormatSupported())); resources_.emplace(local_id, ChildResource(child_id, transferable_resource)); child_info.child_to_parent_map[transferable_resource.id] = local_id;
diff --git a/components/viz/service/display/display_resource_provider_software.cc b/components/viz/service/display/display_resource_provider_software.cc index 58fcc6e..dd89a31b 100644 --- a/components/viz/service/display/display_resource_provider_software.cc +++ b/components/viz/service/display/display_resource_provider_software.cc
@@ -50,7 +50,6 @@ // Determine whether this resource is using a software SharedImage or a legacy // shared bitmap. - DCHECK(resource->transferable.IsSoftwareSharedImage()); DCHECK(shared_image_manager_); auto it = resource_shared_images_.find(id); if (it == resource_shared_images_.end()) {
diff --git a/components/viz/service/display/display_resource_provider_software.h b/components/viz/service/display/display_resource_provider_software.h index ef84dff..e954260 100644 --- a/components/viz/service/display/display_resource_provider_software.h +++ b/components/viz/service/display/display_resource_provider_software.h
@@ -24,7 +24,6 @@ namespace viz { - // DisplayResourceProvider implementation used with SoftwareRenderer. class VIZ_SERVICE_EXPORT DisplayResourceProviderSoftware : public DisplayResourceProvider {
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc index 295e8ba..3fc965c 100644 --- a/components/viz/service/display/display_unittest.cc +++ b/components/viz/service/display/display_unittest.cc
@@ -55,7 +55,6 @@ #include "components/viz/service/display/display_client.h" #include "components/viz/service/display/display_scheduler.h" #include "components/viz/service/display/overlay_processor_stub.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/surface.h" @@ -169,7 +168,7 @@ class DisplayTest : public testing::Test { public: DisplayTest() - : manager_(FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)), + : manager_(FrameSinkManagerImpl::InitParams()), support_( std::make_unique<CompositorFrameSinkSupport>(nullptr, &manager_, @@ -277,7 +276,6 @@ } DebugRendererSettings debug_settings_; - ServerSharedBitmapManager shared_bitmap_manager_; gpu::SharedImageManager shared_image_manager_; gpu::SyncPointManager sync_point_manager_; gpu::Scheduler gpu_scheduler_{&sync_point_manager_};
diff --git a/components/viz/service/display/renderer_perftest.cc b/components/viz/service/display/renderer_perftest.cc index ad4a350..dd1d166 100644 --- a/components/viz/service/display/renderer_perftest.cc +++ b/components/viz/service/display/renderer_perftest.cc
@@ -39,7 +39,6 @@ #include "components/viz/service/display/overlay_processor_stub.h" #include "components/viz/service/display/skia_renderer.h" #include "components/viz/service/display/viz_perftest.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h" #include "components/viz/service/display_embedder/skia_output_surface_impl.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" @@ -233,7 +232,7 @@ class RendererPerfTest : public VizPerfTest { public: RendererPerfTest() - : manager_(FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)), + : manager_(FrameSinkManagerImpl::InitParams()), support_( std::make_unique<CompositorFrameSinkSupport>(nullptr, &manager_, @@ -605,7 +604,6 @@ WaitForSwapDisplayClient client_; ParentLocalSurfaceIdAllocator id_allocator_; std::unique_ptr<BeginFrameSource> begin_frame_source_; - ServerSharedBitmapManager shared_bitmap_manager_; FrameSinkManagerImpl manager_; std::unique_ptr<CompositorFrameSinkSupport> support_; RendererSettings renderer_settings_;
diff --git a/components/viz/service/display/resolved_frame_data_unittest.cc b/components/viz/service/display/resolved_frame_data_unittest.cc index cabccef..a95faf6fb 100644 --- a/components/viz/service/display/resolved_frame_data_unittest.cc +++ b/components/viz/service/display/resolved_frame_data_unittest.cc
@@ -11,7 +11,6 @@ #include "components/viz/common/quads/offset_tag.h" #include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/service/display/display_resource_provider_software.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/surface.h" @@ -117,15 +116,13 @@ return surface; } - ServerSharedBitmapManager shared_bitmap_manager_; gpu::SharedImageManager shared_image_manager_; gpu::SyncPointManager sync_point_manager_; gpu::Scheduler gpu_scheduler_{&sync_point_manager_}; DisplayResourceProviderSoftware resource_provider_{&shared_image_manager_, &gpu_scheduler_}; - FrameSinkManagerImpl frame_sink_manager_{ - FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)}; + FrameSinkManagerImpl frame_sink_manager_{FrameSinkManagerImpl::InitParams()}; TestSurfaceIdAllocator surface_id_{FrameSinkId(1, 1)}; std::unique_ptr<CompositorFrameSinkSupport> support_;
diff --git a/components/viz/service/display/shared_bitmap_manager.h b/components/viz/service/display/shared_bitmap_manager.h deleted file mode 100644 index f69435e..0000000 --- a/components/viz/service/display/shared_bitmap_manager.h +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2013 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_VIZ_SERVICE_DISPLAY_SHARED_BITMAP_MANAGER_H_ -#define COMPONENTS_VIZ_SERVICE_DISPLAY_SHARED_BITMAP_MANAGER_H_ - -#include <memory> - -#include "base/memory/shared_memory_mapping.h" -#include "components/viz/common/resources/shared_bitmap.h" -#include "components/viz/common/resources/shared_image_format.h" -#include "third_party/skia/include/core/SkBitmap.h" - -namespace gfx { -class Size; -} - -namespace viz { - -class SharedBitmapManager { - public: - SharedBitmapManager() = default; - - SharedBitmapManager(const SharedBitmapManager&) = delete; - SharedBitmapManager& operator=(const SharedBitmapManager&) = delete; - - virtual ~SharedBitmapManager() = default; - - // Used in the display compositor to find the bitmap associated with an id. - virtual std::unique_ptr<SharedBitmap> GetSharedBitmapFromId( - const gfx::Size& size, - SharedImageFormat format, - const SharedBitmapId& id) = 0; - virtual base::UnguessableToken GetSharedBitmapTracingGUIDFromId( - const SharedBitmapId& id) = 0; - // Used for locally allocated bitmaps that are not in shared memory. - virtual bool LocalAllocatedSharedBitmap(SkBitmap bitmap, - const SharedBitmapId& id) = 0; - // Used in the display compositor to associate an id to a shm mapping. - virtual bool ChildAllocatedSharedBitmap( - base::ReadOnlySharedMemoryMapping mapping, - const SharedBitmapId& id) = 0; - // Used in the display compositor to break an association of an id to a shm - // handle. - virtual void ChildDeletedSharedBitmap(const SharedBitmapId& id) = 0; -}; - -} // namespace viz - -#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SHARED_BITMAP_MANAGER_H_
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 2f69c38..40b3dd3 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -1181,6 +1181,11 @@ output_frame.data.ca_layer_error_code = swap_frame_data.ca_layer_error_code; #endif +#if BUILDFLAG(IS_MAC) + output_frame.data.is_handling_interaction_or_animation = + swap_frame_data.is_handling_interaction_or_animation; +#endif + if (buffer_queue_) { gfx::Rect damage_rect = output_frame.sub_buffer_rect.value_or( gfx::Rect(surface_size_for_swap_buffers()));
diff --git a/components/viz/service/display/surface_aggregator_perftest.cc b/components/viz/service/display/surface_aggregator_perftest.cc index a3918e1..26511be5b 100644 --- a/components/viz/service/display/surface_aggregator_perftest.cc +++ b/components/viz/service/display/surface_aggregator_perftest.cc
@@ -27,7 +27,6 @@ #include "components/viz/service/display/aggregated_frame.h" #include "components/viz/service/display/display_resource_provider_software.h" #include "components/viz/service/display/viz_perftest.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/surface_manager.h" @@ -80,11 +79,9 @@ class SurfaceAggregatorPerfTest : public VizPerfTest { public: - SurfaceAggregatorPerfTest() - : manager_(FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)) { + SurfaceAggregatorPerfTest() : manager_(FrameSinkManagerImpl::InitParams()) { resource_provider_ = std::make_unique<DisplayResourceProviderSoftware>( - /*shared_image_manager=*/nullptr, - /*gpu_scheduler=*/nullptr); + /*shared_image_manager=*/nullptr, /*gpu_scheduler=*/nullptr); } void RunTest(int num_surfaces, @@ -522,7 +519,6 @@ std::map<ResourceId, TransferableResource> created_resources; }; - ServerSharedBitmapManager shared_bitmap_manager_; FrameSinkManagerImpl manager_; std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<SurfaceAggregator> aggregator_;
diff --git a/components/viz/service/display/surface_aggregator_pixeltest.cc b/components/viz/service/display/surface_aggregator_pixeltest.cc index 6e115fe..7f968de 100644 --- a/components/viz/service/display/surface_aggregator_pixeltest.cc +++ b/components/viz/service/display/surface_aggregator_pixeltest.cc
@@ -15,7 +15,6 @@ #include "components/viz/service/display/delegated_ink_point_pixel_test_helper.h" #include "components/viz/service/display/surface_aggregator.h" #include "components/viz/service/display/viz_pixel_test.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/surface.h" @@ -38,7 +37,7 @@ class SurfaceAggregatorPixelTest : public VizPixelTestWithParam { public: SurfaceAggregatorPixelTest() - : manager_(FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)), + : manager_(FrameSinkManagerImpl::InitParams()), support_(std::make_unique<CompositorFrameSinkSupport>( nullptr, &manager_, @@ -53,7 +52,6 @@ } protected: - ServerSharedBitmapManager shared_bitmap_manager_; FrameSinkManagerImpl manager_; ParentLocalSurfaceIdAllocator root_allocator_; std::unique_ptr<CompositorFrameSinkSupport> support_;
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc index deb975d..f03efd31 100644 --- a/components/viz/service/display/surface_aggregator_unittest.cc +++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -41,7 +41,6 @@ #include "components/viz/common/surfaces/subtree_capture_id.h" #include "components/viz/service/display/aggregated_frame.h" #include "components/viz/service/display/display_resource_provider_software.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/pending_copy_output_request.h" @@ -480,13 +479,11 @@ return shared_image_interface_provider_.GetSharedImageInterface(); } - ServerSharedBitmapManager shared_bitmap_manager_; gpu::SharedImageManager shared_image_manager_; gpu::SyncPointManager sync_point_manager_; gpu::Scheduler gpu_scheduler_{&sync_point_manager_}; - FrameSinkManagerImpl manager_{ - FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)}; + FrameSinkManagerImpl manager_{FrameSinkManagerImpl::InitParams()}; DisplayResourceProviderSoftware resource_provider_{&shared_image_manager_, &gpu_scheduler_}; FakeSurfaceObserver observer_{manager_.surface_manager(), false};
diff --git a/components/viz/service/display_embedder/DEPS b/components/viz/service/display_embedder/DEPS index c950c21..25b0ca6 100644 --- a/components/viz/service/display_embedder/DEPS +++ b/components/viz/service/display_embedder/DEPS
@@ -16,7 +16,6 @@ "+components/viz/service/display/render_pass_alpha_type.h", "+components/viz/service/display/renderer_utils.h", "+components/viz/service/display/resource_metadata.h", - "+components/viz/service/display/shared_bitmap_manager.h", "+components/viz/service/display/skia_output_surface.h", "+components/viz/service/display/software_output_device.h", "+components/viz/service/gl/gpu_service_impl.h",
diff --git a/components/viz/service/display_embedder/image_context_impl.cc b/components/viz/service/display_embedder/image_context_impl.cc index 26789296..8b5e36631 100644 --- a/components/viz/service/display_embedder/image_context_impl.cc +++ b/components/viz/service/display_embedder/image_context_impl.cc
@@ -9,6 +9,7 @@ #include "base/check.h" #include "base/check_op.h" #include "base/metrics/histogram_functions.h" +#include "base/trace_event/trace_event.h" #include "components/viz/common/resources/shared_image_format_utils.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/command_buffer/service/shared_context_state.h"
diff --git a/components/viz/service/display_embedder/output_surface_provider_impl.cc b/components/viz/service/display_embedder/output_surface_provider_impl.cc index 9186701..07502f4 100644 --- a/components/viz/service/display_embedder/output_surface_provider_impl.cc +++ b/components/viz/service/display_embedder/output_surface_provider_impl.cc
@@ -21,7 +21,6 @@ #include "components/viz/common/features.h" #include "components/viz/common/frame_sinks/begin_frame_source.h" #include "components/viz/service/display/display_compositor_memory_and_task_controller.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h" #include "components/viz/service/display_embedder/skia_output_surface_impl.h" #include "components/viz/service/display_embedder/software_output_surface.h"
diff --git a/components/viz/service/display_embedder/server_shared_bitmap_manager.cc b/components/viz/service/display_embedder/server_shared_bitmap_manager.cc deleted file mode 100644 index e66c6d5..0000000 --- a/components/viz/service/display_embedder/server_shared_bitmap_manager.cc +++ /dev/null
@@ -1,220 +0,0 @@ -// Copyright 2013 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/viz/service/display_embedder/server_shared_bitmap_manager.h" - -#include <stdint.h> - -#include <string> -#include <utility> - -#include "base/containers/contains.h" -#include "base/lazy_instance.h" -#include "base/memory/read_only_shared_memory_region.h" -#include "base/memory/ref_counted.h" -#include "base/memory/shared_memory_mapping.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "base/trace_event/process_memory_dump.h" -#include "components/viz/common/resources/bitmap_allocation.h" -#include "components/viz/common/resources/resource_sizes.h" -#include "mojo/public/cpp/system/platform_handle.h" -#include "ui/gfx/geometry/size.h" - -namespace viz { - -class BitmapData : public base::RefCounted<BitmapData> { - public: - BitmapData() = default; - BitmapData(const BitmapData& other) = delete; - BitmapData& operator=(const BitmapData& other) = delete; - - virtual const void* GetMemory() const = 0; - virtual size_t GetSize() const = 0; - virtual const base::UnguessableToken& GetGUID() const = 0; - - protected: - friend class base::RefCounted<BitmapData>; - virtual ~BitmapData() = default; -}; - -// Holds a bitmap stored in local memory. -class LocalBitmapData : public BitmapData { - public: - explicit LocalBitmapData(SkBitmap bitmap) - : bitmap_(std::move(bitmap)), guid_(base::UnguessableToken::Create()) {} - - const void* GetMemory() const override { return bitmap_.getPixels(); } - size_t GetSize() const override { return bitmap_.computeByteSize(); } - const base::UnguessableToken& GetGUID() const override { return guid_; } - - private: - ~LocalBitmapData() override = default; - - SkBitmap bitmap_; - // GUID to identify this bitmap in memory dumps. - base::UnguessableToken guid_; -}; - -// Holds a bitmap stored in shared memory. -class SharedMemoryBitmapData : public BitmapData { - public: - explicit SharedMemoryBitmapData(base::ReadOnlySharedMemoryMapping mapping) - : mapping_(std::move(mapping)) {} - - const void* GetMemory() const override { return mapping_.memory(); } - size_t GetSize() const override { return mapping_.size(); } - const base::UnguessableToken& GetGUID() const override { - return mapping_.guid(); - } - - private: - ~SharedMemoryBitmapData() override = default; - - base::ReadOnlySharedMemoryMapping mapping_; -}; - -namespace { - -// Holds a reference on the BitmapData so that the WritableSharedMemoryMapping -// can outlive the SharedBitmapId registration as long as this SharedBitmap -// object is held alive. -class ServerSharedBitmap : public SharedBitmap { - public: - // NOTE: bitmap_data->GetMemory() is read-only but SharedBitmap expects a - // uint8_t* pointer, even though all instances returned by a - // SharedBitmapManager will be used read-only. - explicit ServerSharedBitmap(scoped_refptr<BitmapData> bitmap_data) - : SharedBitmap( - static_cast<uint8_t*>(const_cast<void*>(bitmap_data->GetMemory()))), - bitmap_data_(std::move(bitmap_data)) {} - - ~ServerSharedBitmap() override { - // Drop unowned reference before destroying `bitmap_data_`. - pixels_ = nullptr; - } - - private: - scoped_refptr<BitmapData> bitmap_data_; -}; - -} // namespace - -ServerSharedBitmapManager::ServerSharedBitmapManager() = default; - -ServerSharedBitmapManager::~ServerSharedBitmapManager() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(handle_map_.empty()); -} - -std::unique_ptr<SharedBitmap> ServerSharedBitmapManager::GetSharedBitmapFromId( - const gfx::Size& size, - SharedImageFormat format, - const SharedBitmapId& id) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - auto it = handle_map_.find(id); - if (it == handle_map_.end()) { - return nullptr; - } - - BitmapData* data = it->second.get(); - - size_t bitmap_size; - if (!ResourceSizes::MaybeSizeInBytes(size, format, &bitmap_size) || - bitmap_size > data->GetSize()) { - return nullptr; - } - - if (!data->GetMemory()) { - return nullptr; - } - - return std::make_unique<ServerSharedBitmap>(data); -} - -base::UnguessableToken -ServerSharedBitmapManager::GetSharedBitmapTracingGUIDFromId( - const SharedBitmapId& id) { - auto it = handle_map_.find(id); - if (it == handle_map_.end()) - return {}; - BitmapData* data = it->second.get(); - return data->GetGUID(); -} - -bool ServerSharedBitmapManager::LocalAllocatedSharedBitmap( - SkBitmap bitmap, - const SharedBitmapId& id) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!bitmap.drawsNothing()); - - // Duplicate ids are not allowed. - if (base::Contains(handle_map_, id)) - return false; - - handle_map_[id] = base::MakeRefCounted<LocalBitmapData>(std::move(bitmap)); - - return true; -} - -bool ServerSharedBitmapManager::ChildAllocatedSharedBitmap( - base::ReadOnlySharedMemoryMapping mapping, - const SharedBitmapId& id) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - // Duplicate ids are not allowed. - if (base::Contains(handle_map_, id)) - return false; - - // This function handles public API requests, so verify we unwrapped a shared - // memory handle before trying to use the handle. - if (!mapping.IsValid()) - return false; - - handle_map_[id] = - base::MakeRefCounted<SharedMemoryBitmapData>(std::move(mapping)); - - // Note: |region| will be destroyed at scope exit, releasing the fd. - return true; -} - -void ServerSharedBitmapManager::ChildDeletedSharedBitmap( - const SharedBitmapId& id) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - handle_map_.erase(id); -} - -bool ServerSharedBitmapManager::OnMemoryDump( - const base::trace_event::MemoryDumpArgs& args, - base::trace_event::ProcessMemoryDump* pmd) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - for (const auto& pair : handle_map_) { - const SharedBitmapId& id = pair.first; - BitmapData* data = pair.second.get(); - - std::string dump_str = base::StringPrintf( - "sharedbitmap/%s", - base::HexEncode(base::as_byte_span(id.name)).c_str()); - base::trace_event::MemoryAllocatorDump* dump = - pmd->CreateAllocatorDump(dump_str); - if (!dump) - return false; - - dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, - base::trace_event::MemoryAllocatorDump::kUnitsBytes, - data->GetSize()); - - // This GUID is the same returned by GetSharedBitmapTracingGUIDFromId() so - // other components use a consistent GUID for a given SharedBitmapId. - base::UnguessableToken bitmap_guid = data->GetGUID(); - DCHECK(!bitmap_guid.is_empty()); - pmd->CreateSharedMemoryOwnershipEdge(dump->guid(), bitmap_guid, - /*importance=*/0); - } - - return true; -} - -} // namespace viz
diff --git a/components/viz/service/display_embedder/server_shared_bitmap_manager.h b/components/viz/service/display_embedder/server_shared_bitmap_manager.h deleted file mode 100644 index 48b7ad0..0000000 --- a/components/viz/service/display_embedder/server_shared_bitmap_manager.h +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2013 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_VIZ_SERVICE_DISPLAY_EMBEDDER_SERVER_SHARED_BITMAP_MANAGER_H_ -#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SERVER_SHARED_BITMAP_MANAGER_H_ - -#include <memory> -#include <unordered_map> - -#include "base/compiler_specific.h" -#include "base/memory/ref_counted.h" -#include "base/trace_event/memory_dump_provider.h" -#include "base/unguessable_token.h" -#include "components/viz/service/display/shared_bitmap_manager.h" -#include "components/viz/service/viz_service_export.h" - -namespace viz { -class BitmapData; - -// A SharedBitmapManager implementation that lives in-process with the -// display compositor. It manages mappings from SharedBitmapId to -// SharedMemory segments. While the returned SharedBitmap is kept alive -// for a given SharedBitmapId, the backing pixels are guaranteed to remain -// valid. -class VIZ_SERVICE_EXPORT ServerSharedBitmapManager - : public SharedBitmapManager, - public base::trace_event::MemoryDumpProvider { - public: - ServerSharedBitmapManager(); - - ServerSharedBitmapManager(const ServerSharedBitmapManager&) = delete; - ServerSharedBitmapManager& operator=(const ServerSharedBitmapManager&) = - delete; - - ~ServerSharedBitmapManager() override; - - // SharedBitmapManager implementation. - std::unique_ptr<SharedBitmap> GetSharedBitmapFromId( - const gfx::Size& size, - SharedImageFormat format, - const SharedBitmapId& id) override; - base::UnguessableToken GetSharedBitmapTracingGUIDFromId( - const SharedBitmapId& id) override; - bool LocalAllocatedSharedBitmap(SkBitmap bitmap, - const SharedBitmapId& id) override; - bool ChildAllocatedSharedBitmap(base::ReadOnlySharedMemoryMapping mapping, - const SharedBitmapId& id) override; - void ChildDeletedSharedBitmap(const SharedBitmapId& id) override; - - // base::trace_event::MemoryDumpProvider implementation. - bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, - base::trace_event::ProcessMemoryDump* pmd) override; - - private: - SEQUENCE_CHECKER(sequence_checker_); - - std::unordered_map<SharedBitmapId, - scoped_refptr<BitmapData>, - SharedBitmapIdHash> - handle_map_; -}; - -} // namespace viz - -#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SERVER_SHARED_BITMAP_MANAGER_H_
diff --git a/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc b/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc deleted file mode 100644 index 5fa87d0c4..0000000 --- a/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc +++ /dev/null
@@ -1,186 +0,0 @@ -// Copyright 2013 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/viz/service/display_embedder/server_shared_bitmap_manager.h" - -#include <algorithm> -#include <utility> - -#include "base/containers/span.h" -#include "components/viz/common/resources/bitmap_allocation.h" -#include "components/viz/common/resources/resource_sizes.h" -#include "mojo/public/cpp/system/platform_handle.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkColor.h" -#include "third_party/skia/include/core/SkImageInfo.h" - -namespace viz { -namespace { - -class ServerSharedBitmapManagerTest : public testing::Test { - protected: - void SetUp() override { - manager_ = std::make_unique<ServerSharedBitmapManager>(); - } - - void TearDown() override { manager_.reset(); } - - ServerSharedBitmapManager* manager() const { return manager_.get(); } - - private: - std::unique_ptr<ServerSharedBitmapManager> manager_; -}; - -TEST_F(ServerSharedBitmapManagerTest, TestCreate) { - gfx::Size bitmap_size(1, 1); - base::MappedReadOnlyRegion shm = bitmap_allocation::AllocateSharedBitmap( - bitmap_size, SinglePlaneFormat::kRGBA_8888); - EXPECT_TRUE(shm.IsValid()); - base::span<uint8_t> span = shm.mapping.GetMemoryAsSpan<uint8_t>(); - std::fill(span.begin(), span.end(), 0xff); - - SharedBitmapId id = SharedBitmap::GenerateId(); - manager()->ChildAllocatedSharedBitmap(shm.region.Map(), id); - - std::unique_ptr<SharedBitmap> large_bitmap; - large_bitmap = manager()->GetSharedBitmapFromId( - gfx::Size(1024, 1024), SinglePlaneFormat::kRGBA_8888, id); - EXPECT_FALSE(large_bitmap); - - std::unique_ptr<SharedBitmap> very_large_bitmap; - very_large_bitmap = manager()->GetSharedBitmapFromId( - gfx::Size(1, (1 << 30) | 1), SinglePlaneFormat::kRGBA_8888, id); - EXPECT_FALSE(very_large_bitmap); - - std::unique_ptr<SharedBitmap> negative_size_bitmap; - negative_size_bitmap = manager()->GetSharedBitmapFromId( - gfx::Size(-1, 1024), SinglePlaneFormat::kRGBA_8888, id); - EXPECT_FALSE(negative_size_bitmap); - - SharedBitmapId id2 = SharedBitmap::GenerateId(); - std::unique_ptr<SharedBitmap> invalid_bitmap; - invalid_bitmap = manager()->GetSharedBitmapFromId( - bitmap_size, SinglePlaneFormat::kRGBA_8888, id2); - EXPECT_FALSE(invalid_bitmap); - - std::unique_ptr<SharedBitmap> shared_bitmap; - shared_bitmap = manager()->GetSharedBitmapFromId( - bitmap_size, SinglePlaneFormat::kRGBA_8888, id); - ASSERT_TRUE(shared_bitmap); - EXPECT_TRUE( - std::equal(span.begin(), span.begin() + 4, shared_bitmap->pixels())); - - std::unique_ptr<SharedBitmap> large_bitmap2; - large_bitmap2 = manager()->GetSharedBitmapFromId( - gfx::Size(1024, 1024), SinglePlaneFormat::kRGBA_8888, id); - EXPECT_FALSE(large_bitmap2); - - std::unique_ptr<SharedBitmap> shared_bitmap2; - shared_bitmap2 = manager()->GetSharedBitmapFromId( - bitmap_size, SinglePlaneFormat::kRGBA_8888, id); - EXPECT_TRUE(shared_bitmap2->pixels() == shared_bitmap->pixels()); - shared_bitmap2.reset(); - EXPECT_TRUE(std::equal(span.begin(), span.end(), shared_bitmap->pixels())); - - manager()->ChildDeletedSharedBitmap(id); - - std::fill(span.begin(), span.end(), 0); - - EXPECT_TRUE(std::equal(span.begin(), span.end(), shared_bitmap->pixels())); - shared_bitmap.reset(); -} - -TEST_F(ServerSharedBitmapManagerTest, TestLocalCreate) { - constexpr gfx::Size bitmap_size(100, 100); - SharedBitmapId id = SharedBitmap::GenerateId(); - void* pixels = nullptr; - - { - // Allocate a local bitmap and fill it with red. - SkImageInfo info = - SkImageInfo::MakeN32Premul(bitmap_size.width(), bitmap_size.height()); - SkBitmap bitmap; - bitmap.allocPixels(info); - bitmap.eraseColor(SK_ColorRED); - - pixels = bitmap.getPixels(); - EXPECT_TRUE(pixels); - - manager()->LocalAllocatedSharedBitmap(std::move(bitmap), id); - } - - std::unique_ptr<SharedBitmap> returned_bitmap = - manager()->GetSharedBitmapFromId(bitmap_size, - SinglePlaneFormat::kRGBA_8888, id); - - // Check the shared bitmap returns the address of pixmap allocated earlier. - ASSERT_TRUE(returned_bitmap); - EXPECT_EQ(pixels, returned_bitmap->pixels()); - - manager()->ChildDeletedSharedBitmap(id); -} - -TEST_F(ServerSharedBitmapManagerTest, AddDuplicate) { - gfx::Size bitmap_size(1, 1); - base::MappedReadOnlyRegion shm = bitmap_allocation::AllocateSharedBitmap( - bitmap_size, SinglePlaneFormat::kRGBA_8888); - EXPECT_TRUE(shm.IsValid()); - base::span<uint8_t> span = shm.mapping.GetMemoryAsSpan<uint8_t>(); - std::fill(span.begin(), span.end(), 0xff); - SharedBitmapId id = SharedBitmap::GenerateId(); - - // NOTE: Duplicate the mapping to compare its content later. - manager()->ChildAllocatedSharedBitmap(shm.region.Map(), id); - - base::MappedReadOnlyRegion shm2 = bitmap_allocation::AllocateSharedBitmap( - bitmap_size, SinglePlaneFormat::kRGBA_8888); - EXPECT_TRUE(shm2.IsValid()); - base::span<uint8_t> span2 = shm.mapping.GetMemoryAsSpan<uint8_t>(); - std::fill(span2.begin(), span2.end(), 0x00); - - manager()->ChildAllocatedSharedBitmap(shm2.region.Map(), id); - - std::unique_ptr<SharedBitmap> shared_bitmap; - shared_bitmap = manager()->GetSharedBitmapFromId( - bitmap_size, SinglePlaneFormat::kRGBA_8888, id); - ASSERT_TRUE(shared_bitmap); - EXPECT_TRUE(std::equal(span.begin(), span.end(), shared_bitmap->pixels())); - manager()->ChildDeletedSharedBitmap(id); -} - -TEST_F(ServerSharedBitmapManagerTest, SharedMemoryHandle) { - gfx::Size bitmap_size(1, 1); - base::MappedReadOnlyRegion shm = bitmap_allocation::AllocateSharedBitmap( - bitmap_size, SinglePlaneFormat::kRGBA_8888); - EXPECT_TRUE(shm.IsValid()); - base::span<uint8_t> span = shm.mapping.GetMemoryAsSpan<uint8_t>(); - std::fill(span.begin(), span.end(), 0xff); - base::UnguessableToken shared_memory_guid = shm.mapping.guid(); - EXPECT_FALSE(shared_memory_guid.is_empty()); - - SharedBitmapId id = SharedBitmap::GenerateId(); - manager()->ChildAllocatedSharedBitmap(shm.region.Map(), id); - - base::UnguessableToken tracing_guid = - manager()->GetSharedBitmapTracingGUIDFromId(id); - EXPECT_EQ(tracing_guid, shared_memory_guid); - - manager()->ChildDeletedSharedBitmap(id); -} - -TEST_F(ServerSharedBitmapManagerTest, InvalidScopedSharedBufferHandle) { - SharedBitmapId id = SharedBitmap::GenerateId(); - base::ReadOnlySharedMemoryMapping invalid_mapping; - EXPECT_FALSE(invalid_mapping.IsValid()); - EXPECT_FALSE( - manager()->ChildAllocatedSharedBitmap(std::move(invalid_mapping), id)); - - // The client could still send an IPC to say it deleted the shared bitmap, - // even though it wasn't valid, which should be ignored. - manager()->ChildDeletedSharedBitmap(id); -} - -} // namespace -} // namespace viz
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc index 30a207b..e820b27 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc +++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -18,6 +18,7 @@ #include "base/system/sys_info.h" #include "base/task/sequenced_task_runner.h" #include "base/time/time.h" +#include "base/trace_event/trace_id_helper.h" #include "base/trace_event/typed_macros.h" #include "build/build_config.h" #include "cc/base/features.h" @@ -33,7 +34,6 @@ #include "components/viz/common/surfaces/video_capture_target.h" #include "components/viz/common/viz_utils.h" #include "components/viz/service/display/display.h" -#include "components/viz/service/display/shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_counter.h" #include "components/viz/service/frame_sinks/frame_sink_bundle_impl.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" @@ -1168,7 +1168,7 @@ } void CompositorFrameSinkSupport::OnBeginFrame(const BeginFrameArgs& args) { - int64_t trace_id = ComputeTraceId(); + int64_t trace_id = base::trace_event::GetNextGlobalTraceId(); TRACE_EVENT( "viz,benchmark,graphics.pipeline", "Graphics.Pipeline", perfetto::Flow::Global(trace_id), [trace_id](perfetto::EventContext ctx) { @@ -1509,15 +1509,6 @@ NOTREACHED(); } -int64_t CompositorFrameSinkSupport::ComputeTraceId() { - // This is losing some info, but should normally be sufficient to avoid - // collisions. - ++trace_sequence_; - uint64_t client = (frame_sink_id_.client_id() & 0xffff); - uint64_t sink = (frame_sink_id_.sink_id() & 0xffff); - return (client << 48) | (sink << 32) | trace_sequence_; -} - bool CompositorFrameSinkSupport::ShouldSendBeginFrame( base::TimeTicks frame_time, base::TimeDelta vsync_interval) { @@ -1666,7 +1657,7 @@ view_transition_token_to_animation_manager_[transition_token] = SurfaceAnimationManager::CreateWithSave( - directive, surface, frame_sink_manager_->shared_bitmap_manager(), + directive, surface, frame_sink_manager_->GetSharedImageInterface(), frame_sink_manager_->reserved_resource_id_tracker(), base::BindOnce(&CompositorFrameSinkSupport::
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/components/viz/service/frame_sinks/compositor_frame_sink_support.h index 4bc5e62..a852c540 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_support.h +++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -316,8 +316,6 @@ // BeginFrame and FrameAck are done. void HandleCallback(); - int64_t ComputeTraceId(); - void MaybeEvictSurfaces(); void EvictLastActiveSurface(); bool ShouldSendBeginFrame(base::TimeTicks timestamp,
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc index 54d0f69..e77db9d 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc +++ b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
@@ -34,7 +34,6 @@ #include "components/viz/common/surfaces/subtree_capture_id.h" #include "components/viz/common/surfaces/surface_id.h" #include "components/viz/common/surfaces/surface_info.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/surface.h" #include "components/viz/test/begin_frame_args_test.h" @@ -155,7 +154,7 @@ // testing::Test void SetUp() override { manager_ = std::make_unique<FrameSinkManagerImpl>( - FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)); + FrameSinkManagerImpl::InitParams()); surface_observer_ = std::make_unique<FakeSurfaceObserver>(manager_->surface_manager()); manager_->SetLocalClient(&frame_sink_manager_client_); @@ -316,7 +315,6 @@ protected: TestSharedImageInterfaceProvider shared_image_interface_provider_; std::unique_ptr<base::SimpleTestTickClock> now_src_; - ServerSharedBitmapManager shared_bitmap_manager_; std::unique_ptr<FrameSinkManagerImpl> manager_; testing::NiceMock<MockFrameSinkManagerClient> frame_sink_manager_client_; FakeCompositorFrameSinkClient fake_support_client_; @@ -2199,8 +2197,7 @@ CompositorFrameTransitionDirective::CreateSave( transition_token, maybe_cross_frame_sink, /*sequence_id=*/1, {}, {}), - surface, &shared_bitmap_manager_, sii, &id_tracker, - base::DoNothing()); + surface, sii, &id_tracker, base::DoNothing()); ASSERT_TRUE(animation_manager); EXPECT_FALSE(HasAnimationManagerForToken(transition_token));
diff --git a/components/viz/service/frame_sinks/fling_scheduler_android_unittest.cc b/components/viz/service/frame_sinks/fling_scheduler_android_unittest.cc index 13a3469..ca4eea3 100644 --- a/components/viz/service/frame_sinks/fling_scheduler_android_unittest.cc +++ b/components/viz/service/frame_sinks/fling_scheduler_android_unittest.cc
@@ -7,7 +7,6 @@ #include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "components/input/features.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/external_begin_frame_source_android.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/input/input_manager.h" @@ -52,8 +51,7 @@ public: FlingSchedulerTest() : frame_sink_manager_( - FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_, - &output_surface_provider_)) { + FrameSinkManagerImpl::InitParams(&output_surface_provider_)) { scoped_feature_list_.InitWithFeatures( /* enabled_features */ {input::features::kInputOnViz}, /* disabled_features */ {}); @@ -167,7 +165,6 @@ } std::unique_ptr<input::FlingController> fling_controller_; - ServerSharedBitmapManager shared_bitmap_manager_; TestOutputSurfaceProvider output_surface_provider_; FrameSinkManagerImpl frame_sink_manager_; base::test::ScopedFeatureList scoped_feature_list_;
diff --git a/components/viz/service/frame_sinks/frame_sink_bundle_impl_unittest.cc b/components/viz/service/frame_sinks/frame_sink_bundle_impl_unittest.cc index 7e17d24..707e83f90 100644 --- a/components/viz/service/frame_sinks/frame_sink_bundle_impl_unittest.cc +++ b/components/viz/service/frame_sinks/frame_sink_bundle_impl_unittest.cc
@@ -28,7 +28,6 @@ #include "components/viz/common/surfaces/frame_sink_bundle_id.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/local_surface_id.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/test/compositor_frame_helpers.h" #include "components/viz/test/fake_external_begin_frame_source.h" @@ -282,11 +281,9 @@ base::SimpleTestTickClock test_clock_; DebugRendererSettings debug_settings_; - ServerSharedBitmapManager shared_bitmap_manager_; TestOutputSurfaceProvider output_surface_provider_; FrameSinkManagerImpl manager_{ - FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_, - &output_surface_provider_)}; + FrameSinkManagerImpl::InitParams(&output_surface_provider_)}; FakeExternalBeginFrameSource begin_frame_source_{0.0f, false}; TestBundleClient test_client_;
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc index 4f4d2308..3a92074 100644 --- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc +++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -29,7 +29,6 @@ #include "components/viz/common/surfaces/subtree_capture_id.h" #include "components/viz/common/surfaces/video_capture_target.h" #include "components/viz/service/display/overdraw_tracker.h" -#include "components/viz/service/display/shared_bitmap_manager.h" #include "components/viz/service/display_embedder/output_surface_provider.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_bundle_impl.h" @@ -43,13 +42,10 @@ namespace viz { -FrameSinkManagerImpl::InitParams::InitParams() = default; FrameSinkManagerImpl::InitParams::InitParams( - SharedBitmapManager* shared_bitmap_manager, OutputSurfaceProvider* output_surface_provider, GmbVideoFramePoolContextProvider* gmb_context_provider) - : shared_bitmap_manager(shared_bitmap_manager), - output_surface_provider(output_surface_provider), + : output_surface_provider(output_surface_provider), gmb_context_provider(gmb_context_provider) {} FrameSinkManagerImpl::InitParams::InitParams(InitParams&& other) = default; FrameSinkManagerImpl::InitParams::~InitParams() = default; @@ -79,8 +75,7 @@ operator=(FrameSinkData&& other) = default; FrameSinkManagerImpl::FrameSinkManagerImpl(const InitParams& params) - : shared_bitmap_manager_(params.shared_bitmap_manager), - output_surface_provider_(params.output_surface_provider), + : output_surface_provider_(params.output_surface_provider), gpu_service_(params.gpu_service), gmb_context_provider_(params.gmb_context_provider), surface_manager_(this,
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/components/viz/service/frame_sinks/frame_sink_manager_impl.h index d29f933b..078b0e9 100644 --- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h +++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -64,7 +64,6 @@ class HintSessionFactory; class InputManager; class OutputSurfaceProvider; -class SharedBitmapManager; class SharedImageInterfaceProvider; struct VideoCaptureTarget; @@ -81,16 +80,13 @@ public HitTestDataProvider { public: struct VIZ_SERVICE_EXPORT InitParams { - InitParams(); explicit InitParams( - SharedBitmapManager* shared_bitmap_manager, OutputSurfaceProvider* output_surface_provider = nullptr, GmbVideoFramePoolContextProvider* gmb_context_provider = nullptr); InitParams(InitParams&& other); ~InitParams(); InitParams& operator=(InitParams&& other); - raw_ptr<SharedBitmapManager> shared_bitmap_manager = nullptr; std::optional<uint32_t> activation_deadline_in_frames = kDefaultActivationDeadlineInFrames; raw_ptr<OutputSurfaceProvider> output_surface_provider = nullptr; @@ -268,9 +264,6 @@ SurfaceManager* surface_manager() { return &surface_manager_; } const HitTestManager* hit_test_manager() { return &hit_test_manager_; } - SharedBitmapManager* shared_bitmap_manager() { - return shared_bitmap_manager_; - } virtual InputManager* GetInputManager(); // virtual for testing. @@ -481,10 +474,6 @@ void MaybeEraseHitTestQuery(const FrameSinkId& frame_sink_id); void MaybeAddHitTestQuery(const FrameSinkId& frame_sink_id); - // SharedBitmapManager for the viz display service for receiving software - // resources in CompositorFrameSinks. - const raw_ptr<SharedBitmapManager> shared_bitmap_manager_; - // Provides an output surface for CreateRootCompositorFrameSink(). const raw_ptr<OutputSurfaceProvider> output_surface_provider_;
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc b/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc index 06026f14..edf9ed5 100644 --- a/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc +++ b/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
@@ -15,7 +15,6 @@ #include "components/viz/common/constants.h" #include "components/viz/common/frame_sinks/begin_frame_source.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/input/mock_input_manager.h" #include "components/viz/service/input/render_input_router_iterator_impl.h" @@ -72,8 +71,7 @@ class FrameSinkManagerTest : public testing::Test { public: FrameSinkManagerTest() - : manager_(FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_, - &output_surface_provider_)) {} + : manager_(FrameSinkManagerImpl::InitParams(&output_surface_provider_)) {} ~FrameSinkManagerTest() override = default; RootCompositorFrameSinkImpl* GetRootCompositorFrameSinkImpl() { @@ -180,7 +178,6 @@ protected: DebugRendererSettings debug_settings_; - ServerSharedBitmapManager shared_bitmap_manager_; TestOutputSurfaceProvider output_surface_provider_; FrameSinkManagerImpl manager_; FakeSurfaceObserver surface_observer_{manager_.surface_manager()};
diff --git a/components/viz/service/frame_sinks/surface_references_unittest.cc b/components/viz/service/frame_sinks/surface_references_unittest.cc index 6be787b..1c3cbaff6 100644 --- a/components/viz/service/frame_sinks/surface_references_unittest.cc +++ b/components/viz/service/frame_sinks/surface_references_unittest.cc
@@ -10,7 +10,6 @@ #include "base/containers/flat_set.h" #include "base/test/test_mock_time_task_runner.h" #include "components/viz/common/surfaces/surface_id.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/surface.h" @@ -125,7 +124,7 @@ void SetUp() override { // Start each test with a fresh SurfaceManager instance. manager_ = std::make_unique<FrameSinkManagerImpl>( - FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)); + FrameSinkManagerImpl::InitParams()); } void TearDown() override { supports_.clear(); @@ -136,7 +135,6 @@ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; base::TestMockTimeTaskRunner::ScopedContext scoped_context_; - ServerSharedBitmapManager shared_bitmap_manager_; std::unique_ptr<FrameSinkManagerImpl> manager_; std::unordered_map<FrameSinkId, std::unique_ptr<CompositorFrameSinkSupport>,
diff --git a/components/viz/service/frame_sinks/surface_synchronization_unittest.cc b/components/viz/service/frame_sinks/surface_synchronization_unittest.cc index 9bcee58a..ca2ce8f 100644 --- a/components/viz/service/frame_sinks/surface_synchronization_unittest.cc +++ b/components/viz/service/frame_sinks/surface_synchronization_unittest.cc
@@ -7,7 +7,6 @@ #include "base/test/simple_test_tick_clock.h" #include "components/viz/common/features.h" #include "components/viz/common/surfaces/surface_id.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/frame_index_constants.h" @@ -193,7 +192,7 @@ void SetUp() override { testing::Test::SetUp(); frame_sink_manager_ = std::make_unique<FrameSinkManagerImpl>( - FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)); + FrameSinkManagerImpl::InitParams()); surface_observer_ = std::make_unique<FakeSurfaceObserver>(surface_manager(), false); begin_frame_source_ = @@ -268,7 +267,6 @@ private: std::unique_ptr<base::SimpleTestTickClock> now_src_; - ServerSharedBitmapManager shared_bitmap_manager_; std::unique_ptr<FrameSinkManagerImpl> frame_sink_manager_; std::unique_ptr<FakeSurfaceObserver> surface_observer_; std::unique_ptr<FakeExternalBeginFrameSource> begin_frame_source_;
diff --git a/components/viz/service/frame_sinks/video_detector_unittest.cc b/components/viz/service/frame_sinks/video_detector_unittest.cc index 0c3b77a8..c8dfedc 100644 --- a/components/viz/service/frame_sinks/video_detector_unittest.cc +++ b/components/viz/service/frame_sinks/video_detector_unittest.cc
@@ -24,7 +24,6 @@ #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/service/display/display_resource_provider_software.h" #include "components/viz/service/display/surface_aggregator.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/test/compositor_frame_helpers.h" @@ -243,12 +242,10 @@ } base::test::ScopedFeatureList scoped_feature_list_; - ServerSharedBitmapManager shared_bitmap_manager_; gpu::SharedImageManager shared_image_manager_; gpu::SyncPointManager sync_point_manager_; gpu::Scheduler gpu_scheduler_{&sync_point_manager_}; - FrameSinkManagerImpl frame_sink_manager_{ - FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)}; + FrameSinkManagerImpl frame_sink_manager_{FrameSinkManagerImpl::InitParams()}; DisplayResourceProviderSoftware resource_provider_{&shared_image_manager_, &gpu_scheduler_}; FakeCompositorFrameSinkClient frame_sink_client_;
diff --git a/components/viz/service/hit_test/hit_test_aggregator_unittest.cc b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc index fa94b079..f1924f61 100644 --- a/components/viz/service/hit_test/hit_test_aggregator_unittest.cc +++ b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
@@ -14,7 +14,6 @@ #include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/surface_id.h" #include "components/viz/host/host_frame_sink_manager.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/hit_test/hit_test_aggregator_delegate.h" @@ -57,9 +56,8 @@ class TestFrameSinkManagerImpl : public FrameSinkManagerImpl { public: - explicit TestFrameSinkManagerImpl(SharedBitmapManager* shared_bitmap_manager) - : FrameSinkManagerImpl( - FrameSinkManagerImpl::InitParams(shared_bitmap_manager)) {} + TestFrameSinkManagerImpl() + : FrameSinkManagerImpl(FrameSinkManagerImpl::InitParams()) {} TestFrameSinkManagerImpl(const TestFrameSinkManagerImpl&) = delete; TestFrameSinkManagerImpl& operator=(const TestFrameSinkManagerImpl&) = delete; @@ -121,8 +119,7 @@ // testing::Test: void SetUp() override { - frame_sink_manager_ = - std::make_unique<TestFrameSinkManagerImpl>(&shared_bitmap_manager_); + frame_sink_manager_ = std::make_unique<TestFrameSinkManagerImpl>(); host_frame_sink_manager_ = std::make_unique<TestHostFrameSinkManager>(); local_surface_id_lookup_delegate_ = std::make_unique<TestLatestLocalSurfaceIdLookupDelegate>(); @@ -230,7 +227,6 @@ } private: - ServerSharedBitmapManager shared_bitmap_manager_; std::unique_ptr<TestHitTestAggregator> hit_test_aggregator_; std::unique_ptr<TestFrameSinkManagerImpl> frame_sink_manager_; std::unique_ptr<TestHostFrameSinkManager> host_frame_sink_manager_;
diff --git a/components/viz/service/hit_test/hit_test_manager_fuzzer.cc b/components/viz/service/hit_test/hit_test_manager_fuzzer.cc index 753fa73..7f4426a 100644 --- a/components/viz/service/hit_test/hit_test_manager_fuzzer.cc +++ b/components/viz/service/hit_test/hit_test_manager_fuzzer.cc
@@ -11,7 +11,6 @@ #include <vector> #include "base/command_line.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/hit_test/hit_test_aggregator.h" @@ -132,9 +131,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t num_bytes) { FuzzedDataProvider fuzz(data, num_bytes); - viz::ServerSharedBitmapManager shared_bitmap_manager; viz::FrameSinkManagerImpl frame_sink_manager{ - viz::FrameSinkManagerImpl::InitParams(&shared_bitmap_manager)}; + viz::FrameSinkManagerImpl::InitParams()}; viz::TestLatestLocalSurfaceIdLookupDelegate delegate; viz::TestLatestLocalSurfaceIdLookupDelegate* lsi_delegate = fuzz.ConsumeBool() ? &delegate : nullptr;
diff --git a/components/viz/service/main/viz_compositor_thread_runner_impl.cc b/components/viz/service/main/viz_compositor_thread_runner_impl.cc index 4cde07e5..2ff7fe1c 100644 --- a/components/viz/service/main/viz_compositor_thread_runner_impl.cc +++ b/components/viz/service/main/viz_compositor_thread_runner_impl.cc
@@ -21,7 +21,6 @@ #include "components/viz/common/switches.h" #include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h" #include "components/viz/service/display_embedder/output_surface_provider_impl.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h" #include "components/viz/service/frame_sinks/shared_image_interface_provider.h" @@ -159,11 +158,6 @@ DCHECK(!frame_sink_manager_); gpu::SchedulerSequence::DefaultDisallowScheduleTaskOnCurrentThread(); - server_shared_bitmap_manager_ = std::make_unique<ServerSharedBitmapManager>(); - base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( - server_shared_bitmap_manager_.get(), "ServerSharedBitmapManager", - task_runner_); - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); const bool headless = command_line->HasSwitch(switches::kHeadless); const bool run_all_compositor_stages_before_draw = @@ -192,7 +186,7 @@ // Create FrameSinkManagerImpl. FrameSinkManagerImpl::InitParams init_params; - init_params.shared_bitmap_manager = server_shared_bitmap_manager_.get(); + // Set default activation deadline to infinite if client doesn't provide one. init_params.activation_deadline_in_frames = std::nullopt; if (params->use_activation_deadline) { @@ -241,17 +235,11 @@ weak_factory_.InvalidateWeakPtrs(); - if (server_shared_bitmap_manager_) { - base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( - server_shared_bitmap_manager_.get()); - } - frame_sink_manager_.reset(); hint_session_factory_.reset(); output_surface_provider_.reset(); gmb_video_frame_pool_context_provider_.reset(); gpu_memory_buffer_manager_.reset(); - server_shared_bitmap_manager_.reset(); } } // namespace viz
diff --git a/components/viz/service/main/viz_compositor_thread_runner_impl.h b/components/viz/service/main/viz_compositor_thread_runner_impl.h index 8ae6f4e..3610ef8 100644 --- a/components/viz/service/main/viz_compositor_thread_runner_impl.h +++ b/components/viz/service/main/viz_compositor_thread_runner_impl.h
@@ -29,7 +29,6 @@ class HintSessionFactory; class InProcessGpuMemoryBufferManager; class OutputSurfaceProvider; -class ServerSharedBitmapManager; class SharedImageInterfaceProvider; #if BUILDFLAG(IS_ANDROID) @@ -83,7 +82,6 @@ // Start variables to be accessed only on |task_runner_|. std::unique_ptr<HintSessionFactory> hint_session_factory_; - std::unique_ptr<ServerSharedBitmapManager> server_shared_bitmap_manager_; std::unique_ptr<InProcessGpuMemoryBufferManager> gpu_memory_buffer_manager_; std::unique_ptr<OutputSurfaceProvider> output_surface_provider_; // `gmb_video_frame_pool_context_provider_` depends on
diff --git a/components/viz/service/surfaces/surface_unittest.cc b/components/viz/service/surfaces/surface_unittest.cc index 5ddfda42..f5bc156d 100644 --- a/components/viz/service/surfaces/surface_unittest.cc +++ b/components/viz/service/surfaces/surface_unittest.cc
@@ -13,7 +13,6 @@ #include "components/viz/common/frame_sinks/copy_output_result.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/common/surfaces/subtree_capture_id.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/pending_copy_output_request.h" @@ -36,13 +35,10 @@ class SurfaceTest : public testing::Test { public: - SurfaceTest() - : frame_sink_manager_( - FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)) {} + SurfaceTest() : frame_sink_manager_(FrameSinkManagerImpl::InitParams()) {} protected: std::unique_ptr<base::SimpleTestTickClock> now_src_; - ServerSharedBitmapManager shared_bitmap_manager_; FrameSinkManagerImpl frame_sink_manager_; };
diff --git a/components/viz/service/transitions/DEPS b/components/viz/service/transitions/DEPS index 6b47897..673c020b 100644 --- a/components/viz/service/transitions/DEPS +++ b/components/viz/service/transitions/DEPS
@@ -1,7 +1,6 @@ # Please consult components/viz/README.md about allowable dependencies. include_rules = [ - "+components/viz/service/display/shared_bitmap_manager.h", "+components/viz/service/frame_sinks", "+components/viz/service/surfaces", "+gpu/command_buffer/common",
diff --git a/components/viz/service/transitions/surface_animation_manager.cc b/components/viz/service/transitions/surface_animation_manager.cc index f0903f03c..590206d 100644 --- a/components/viz/service/transitions/surface_animation_manager.cc +++ b/components/viz/service/transitions/surface_animation_manager.cc
@@ -133,19 +133,17 @@ SurfaceAnimationManager::CreateWithSave( const CompositorFrameTransitionDirective& directive, Surface* surface, - SharedBitmapManager* shared_bitmap_manager, gpu::SharedImageInterface* shared_image_interface, ReservedResourceIdTracker* id_tracker, SaveDirectiveCompleteCallback sequence_id_finished_callback) { return base::WrapUnique(new SurfaceAnimationManager( - directive, surface, shared_bitmap_manager, shared_image_interface, - id_tracker, std::move(sequence_id_finished_callback))); + directive, surface, shared_image_interface, id_tracker, + std::move(sequence_id_finished_callback))); } SurfaceAnimationManager::SurfaceAnimationManager( const CompositorFrameTransitionDirective& directive, Surface* surface, - SharedBitmapManager* shared_bitmap_manager, gpu::SharedImageInterface* shared_image_interface, ReservedResourceIdTracker* id_tracker, SaveDirectiveCompleteCallback sequence_id_finished_callback)
diff --git a/components/viz/service/transitions/surface_animation_manager.h b/components/viz/service/transitions/surface_animation_manager.h index df7c02b4..ffcf14df 100644 --- a/components/viz/service/transitions/surface_animation_manager.h +++ b/components/viz/service/transitions/surface_animation_manager.h
@@ -16,7 +16,6 @@ #include "components/viz/common/quads/compositor_render_pass.h" #include "components/viz/common/quads/compositor_render_pass_draw_quad.h" #include "components/viz/common/resources/resource_id.h" -#include "components/viz/service/display/shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/surface_resource_holder.h" #include "components/viz/service/surfaces/surface_saved_frame.h" #include "components/viz/service/transitions/transferable_resource_tracker.h" @@ -50,7 +49,6 @@ static std::unique_ptr<SurfaceAnimationManager> CreateWithSave( const CompositorFrameTransitionDirective& directive, Surface* surface, - SharedBitmapManager* shared_bitmap_manager, gpu::SharedImageInterface* shared_image_interface, ReservedResourceIdTracker* id_tracker, SaveDirectiveCompleteCallback sequence_id_finished_callback); @@ -91,7 +89,6 @@ SurfaceAnimationManager( const CompositorFrameTransitionDirective& directive, Surface* surface, - SharedBitmapManager* shared_bitmap_manager, gpu::SharedImageInterface* shared_image_interface, ReservedResourceIdTracker* id_tracker, SaveDirectiveCompleteCallback sequence_id_finished_callback);
diff --git a/components/viz/test/BUILD.gn b/components/viz/test/BUILD.gn index f86f32b..2eae54e 100644 --- a/components/viz/test/BUILD.gn +++ b/components/viz/test/BUILD.gn
@@ -89,8 +89,6 @@ "test_output_surface_provider.h", "test_raster_interface.cc", "test_raster_interface.h", - "test_shared_bitmap_manager.cc", - "test_shared_bitmap_manager.h", "test_shared_image_interface_provider.cc", "test_shared_image_interface_provider.h", "test_surface_id_allocator.cc",
diff --git a/components/viz/test/test_shared_bitmap_manager.cc b/components/viz/test/test_shared_bitmap_manager.cc deleted file mode 100644 index 025ce2db..0000000 --- a/components/viz/test/test_shared_bitmap_manager.cc +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2014 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/viz/test/test_shared_bitmap_manager.h" - -#include <stdint.h> - -#include <utility> - -#include "base/memory/read_only_shared_memory_region.h" -#include "base/notreached.h" -#include "components/viz/common/resources/bitmap_allocation.h" -#include "mojo/public/cpp/system/platform_handle.h" - -namespace viz { - -TestSharedBitmapManager::TestSharedBitmapManager() = default; - -TestSharedBitmapManager::~TestSharedBitmapManager() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); -} - -std::unique_ptr<SharedBitmap> TestSharedBitmapManager::GetSharedBitmapFromId( - const gfx::Size&, - SharedImageFormat, - const SharedBitmapId& id) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - const auto it = mapping_map_.find(id); - if (it == mapping_map_.end()) - return nullptr; - // NOTE: pixels needs to be writable for legacy reasons, but SharedBitmap - // instances returned by a SharedBitmapManager are always read-only. - auto* pixels = static_cast<uint8_t*>(const_cast<void*>(it->second.memory())); - return std::make_unique<SharedBitmap>(pixels); -} - -base::UnguessableToken -TestSharedBitmapManager::GetSharedBitmapTracingGUIDFromId( - const SharedBitmapId& id) { - const auto it = mapping_map_.find(id); - if (it == mapping_map_.end()) - return {}; - return it->second.guid(); -} - -bool TestSharedBitmapManager::ChildAllocatedSharedBitmap( - base::ReadOnlySharedMemoryMapping mapping, - const SharedBitmapId& id) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - // TestSharedBitmapManager is both the client and service side. So the - // notification here should be about a bitmap that was previously allocated - // with AllocateSharedBitmap(). - if (mapping_map_.find(id) == mapping_map_.end()) { - mapping_map_.emplace(id, std::move(mapping)); - } - - // The same bitmap id should not be notified more than once. - DCHECK_EQ(notified_set_.count(id), 0u); - notified_set_.insert(id); - return true; -} - -bool TestSharedBitmapManager::LocalAllocatedSharedBitmap( - SkBitmap bitmap, - const SharedBitmapId& id) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - NOTIMPLEMENTED(); - return false; -} - -void TestSharedBitmapManager::ChildDeletedSharedBitmap( - const SharedBitmapId& id) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - notified_set_.erase(id); - mapping_map_.erase(id); -} - -} // namespace viz
diff --git a/components/viz/test/test_shared_bitmap_manager.h b/components/viz/test/test_shared_bitmap_manager.h deleted file mode 100644 index 3807ff7..0000000 --- a/components/viz/test/test_shared_bitmap_manager.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2014 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_VIZ_TEST_TEST_SHARED_BITMAP_MANAGER_H_ -#define COMPONENTS_VIZ_TEST_TEST_SHARED_BITMAP_MANAGER_H_ - -#include <map> -#include <memory> -#include <set> - -#include "base/memory/shared_memory_mapping.h" -#include "base/sequence_checker.h" -#include "components/viz/service/display/shared_bitmap_manager.h" - -namespace viz { - -class TestSharedBitmapManager : public SharedBitmapManager { - public: - TestSharedBitmapManager(); - ~TestSharedBitmapManager() override; - - // SharedBitmapManager implementation. - std::unique_ptr<SharedBitmap> GetSharedBitmapFromId( - const gfx::Size& size, - SharedImageFormat format, - const SharedBitmapId& id) override; - base::UnguessableToken GetSharedBitmapTracingGUIDFromId( - const SharedBitmapId& id) override; - bool ChildAllocatedSharedBitmap(base::ReadOnlySharedMemoryMapping mapping, - const SharedBitmapId& id) override; - bool LocalAllocatedSharedBitmap(SkBitmap bitmap, - const SharedBitmapId& id) override; - void ChildDeletedSharedBitmap(const SharedBitmapId& id) override; - - private: - SEQUENCE_CHECKER(sequence_checker_); - - std::map<SharedBitmapId, base::ReadOnlySharedMemoryMapping> mapping_map_; - std::set<SharedBitmapId> notified_set_; -}; - -} // namespace viz - -#endif // COMPONENTS_VIZ_TEST_TEST_SHARED_BITMAP_MANAGER_H_
diff --git a/content/browser/preloading/prefetch/prefetch_container.cc b/content/browser/preloading/prefetch/prefetch_container.cc index 0faadd4..5e0ce60 100644 --- a/content/browser/preloading/prefetch/prefetch_container.cc +++ b/content/browser/preloading/prefetch/prefetch_container.cc
@@ -1199,9 +1199,7 @@ const PrefetchResponseReader* PrefetchContainer::GetNonRedirectResponseReader() const { - if (redirect_chain_.empty()) { - return nullptr; - } + CHECK(!redirect_chain_.empty()); if (!redirect_chain_.back()->response_reader_->GetHead()) { // Either the last PrefetchResponseReader is for a redirect response, or for // a final response not yet receiving its header. @@ -1486,11 +1484,11 @@ } DVLOG(1) << *this << "(GetServableState)" - << "(streaming_loader=" << streaming_loader_.get() << ")" - << "(redirect_chain.empty=" << redirect_chain_.empty() << ")"; + << "(streaming_loader=" << streaming_loader_.get() + << ", LoadState=" << load_state_ << ")"; // Can only block until head if the request has been started using a // streaming URL loader and head/failure/redirect hasn't been received yet. - if (streaming_loader_ && !redirect_chain_.empty() && + if (streaming_loader_ && redirect_chain_.back()->response_reader_->IsWaitingForResponse()) { return ServableState::kShouldBlockUntilHeadReceived; }
diff --git a/content/browser/renderer_host/embedded_frame_sink_provider_impl_unittest.cc b/content/browser/renderer_host/embedded_frame_sink_provider_impl_unittest.cc index 48de9e1f..b71b88e 100644 --- a/content/browser/renderer_host/embedded_frame_sink_provider_impl_unittest.cc +++ b/content/browser/renderer_host/embedded_frame_sink_provider_impl_unittest.cc
@@ -15,7 +15,6 @@ #include "build/build_config.h" #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/host/host_frame_sink_manager.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/test/compositor_frame_helpers.h" #include "components/viz/test/fake_host_frame_sink_client.h" @@ -146,7 +145,7 @@ // The FrameSinkManagerImpl implementation is in-process here for tests. frame_sink_manager_ = std::make_unique<viz::FrameSinkManagerImpl>( - viz::FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)); + viz::FrameSinkManagerImpl::InitParams()); host_frame_sink_manager_->SetLocalManager(frame_sink_manager_.get()); frame_sink_manager_->SetLocalClient(host_frame_sink_manager_.get()); @@ -169,7 +168,6 @@ // A MessageLoop is required for mojo bindings which are used to // connect to graphics services. base::test::SingleThreadTaskEnvironment task_environment_; - viz::ServerSharedBitmapManager shared_bitmap_manager_; viz::FakeHostFrameSinkClient host_frame_sink_client_; std::unique_ptr<viz::HostFrameSinkManager> host_frame_sink_manager_; std::unique_ptr<viz::FrameSinkManagerImpl> frame_sink_manager_;
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index 344d6a2..27c692d5 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc
@@ -5867,9 +5867,52 @@ // Cases with a UrlLoader are handled in OnStartChecksComplete. MaybeDispatchNavigateEventForCrossDocumentTraversal(); + InheritServiceWorkerControllerFromParentIfNeeded(); + CommitNavigation(); } +void NavigationRequest::InheritServiceWorkerControllerFromParentIfNeeded() { + if (!base::FeatureList::IsEnabled(features::kServiceWorkerSrcdocSupport)) { + return; + } + + CHECK(!loader_); + CHECK(!service_worker_handle_); + RenderFrameHostImpl* parent = frame_tree_node()->parent(); + if (!parent || !GetURL().IsAboutSrcdoc()) { + return; + } + base::WeakPtr<ServiceWorkerClient> parent_service_worker_client = + parent->GetLastCommittedServiceWorkerClient(); + if (!parent_service_worker_client) { + return; + } + + if ((frame_tree_node_->pending_frame_policy().sandbox_flags & + network::mojom::WebSandboxFlags::kOrigin) == + network::mojom::WebSandboxFlags::kOrigin) { + return; + } + StoragePartition* partition = GetStoragePartitionWithCurrentSiteInfo(); + auto* service_worker_context = static_cast<ServiceWorkerContextWrapper*>( + partition->GetServiceWorkerContext()); + // As ServiceWorkerMainResourceHandle is not used for intercepting the srcdoc + // iframe main resource, the fetch event client id is not used. Use empty + // string as fetch_event_client_id when creating it. + service_worker_handle_ = std::make_unique<ServiceWorkerMainResourceHandle>( + service_worker_context, base::DoNothing(), + /*fetch_event_client_id=*/std::string(), parent_service_worker_client); + service_worker_handle_->set_service_worker_client( + service_worker_context->context() + ->service_worker_client_owner() + .CreateServiceWorkerClientForWindow( + IsSecureFrame(frame_tree_node_->parent()), + frame_tree_node_->frame_tree_node_id())); + service_worker_handle_->service_worker_client()->InheritControllerFrom( + *parent_service_worker_client, net::SimplifyUrlForRequest(GetURL())); +} + void NavigationRequest::RunCommitDeferringConditions() { commit_deferrer_->RegisterDeferringConditions(*this); commit_deferrer_->ProcessChecks();
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h index 097243b..befaf810 100644 --- a/content/browser/renderer_host/navigation_request.h +++ b/content/browser/renderer_host/navigation_request.h
@@ -2148,6 +2148,13 @@ // contexts or if DocumentIsolationPolicy is not supported. void SanitizeDocumentIsolationPolicyHeader(); + // Sets up service worker client info to inherit controller from the parent + // frame if it is a same origin srcdoc iframe. + // This method creates a ServiceWorkerClient associated with the navigating + // frame. It should not be called when NavigationURLLoader is used as that + // would also create ServiceWorkerClient and cause conflict. + void InheritServiceWorkerControllerFromParentIfNeeded(); + // Never null. The pointee node owns this navigation request instance. // This field is not a raw_ptr because of incompatibilities with tracing // (TRACE_EVENT*), perfetto::TracedDictionary::Add and gmock/EXPECT_THAT.
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index a8d867c1..2f95024 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -754,8 +754,6 @@ CHECK(GetBackgroundColor()); SkColor color = *GetBackgroundColor(); - bool opaque = SkColorGetA(color) == SK_AlphaOPAQUE; - window_->layer()->SetFillsBoundsOpaquely(opaque); window_->layer()->SetColor(color); }
diff --git a/content/browser/service_worker/service_worker_client.cc b/content/browser/service_worker/service_worker_client.cc index 3f4d8071..0beb070 100644 --- a/content/browser/service_worker/service_worker_client.cc +++ b/content/browser/service_worker/service_worker_client.cc
@@ -400,7 +400,6 @@ blink::mojom::ServiceWorkerClientType ServiceWorkerClient::GetClientType() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(client_info_); return absl::visit( base::Overloaded( [](GlobalRenderFrameHostId render_frame_host_id) { @@ -412,30 +411,24 @@ [](blink::SharedWorkerToken shared_worker_token) { return blink::mojom::ServiceWorkerClientType::kSharedWorker; }), - *client_info_); + client_info_); } bool ServiceWorkerClient::IsContainerForWindowClient() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return client_info_ && - absl::holds_alternative<GlobalRenderFrameHostId>(*client_info_); + return absl::holds_alternative<GlobalRenderFrameHostId>(client_info_); } bool ServiceWorkerClient::IsContainerForWorkerClient() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - using blink::mojom::ServiceWorkerClientType; - if (!client_info_) { - return false; - } - - return absl::holds_alternative<blink::DedicatedWorkerToken>(*client_info_) || - absl::holds_alternative<blink::SharedWorkerToken>(*client_info_); + return absl::holds_alternative<blink::DedicatedWorkerToken>(client_info_) || + absl::holds_alternative<blink::SharedWorkerToken>(client_info_); } ServiceWorkerClientInfo ServiceWorkerClient::GetServiceWorkerClientInfo() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return *client_info_; + return client_info_; } blink::mojom::ServiceWorkerContainerInfoForClientPtr @@ -629,7 +622,7 @@ shared_worker_token, origin) : std::nullopt; }), - *client_info_); + client_info_); if (storage_key) { return *storage_key; @@ -752,7 +745,7 @@ GlobalRenderFrameHostId ServiceWorkerClient::GetRenderFrameHostId() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(IsContainerForWindowClient()); - return absl::get<GlobalRenderFrameHostId>(*client_info_); + return absl::get<GlobalRenderFrameHostId>(client_info_); } int ServiceWorkerClient::GetProcessId() const { @@ -849,7 +842,7 @@ static_cast<int32_t>(GetClientType())); SCOPED_CRASH_KEY_BOOL("SWC_OnEBFC", "is_execution_ready", is_execution_ready()); - SCOPED_CRASH_KEY_BOOL("SWC_OnEBFC", "is_blob_url", + SCOPED_CRASH_KEY_BOOL("SWC_OnEBFC", "is_blob_or_about_url", url() != GetUrlForScopeMatch()); SCOPED_CRASH_KEY_BOOL("SWC_OnEBFC", "is_inherited", is_inherited()); CHECK(!controller_->BFCacheContainsControllee(client_uuid())); @@ -864,7 +857,7 @@ // TODO(crbug.com/330928087): remove check when this issue resolved. SCOPED_CRASH_KEY_BOOL("SWC_OnRFBFC", "is_in_bfcache", is_in_back_forward_cache_); - SCOPED_CRASH_KEY_BOOL("SWC_OnRFBFC", "is_blob_url", + SCOPED_CRASH_KEY_BOOL("SWC_OnRFBFC", "is_blob_or_about_url", url() != GetUrlForScopeMatch()); SCOPED_CRASH_KEY_BOOL("SWC_OnRFBFC", "is_inherited", is_inherited()); if (controller_) { @@ -1007,7 +1000,7 @@ static_cast<int32_t>(GetClientType())); SCOPED_CRASH_KEY_BOOL("SWV_RCFBCM", "is_execution_ready", is_execution_ready()); - SCOPED_CRASH_KEY_BOOL("SWV_RCFBCM", "is_blob_url", + SCOPED_CRASH_KEY_BOOL("SWV_RCFBCM", "is_blob_or_about_url", url() != GetUrlForScopeMatch()); SCOPED_CRASH_KEY_BOOL("SWV_RCFBCM", "is_inherited", is_inherited()); CHECK(!version->BFCacheContainsControllee(client_uuid())); @@ -1082,26 +1075,39 @@ #endif // DCHECK_IS_ON() const GURL& ServiceWorkerClient::GetUrlForScopeMatch() const { - if (!scope_match_url_for_blob_client_.is_empty()) { - return scope_match_url_for_blob_client_; + if (!scope_match_url_for_client_.is_empty()) { + return scope_match_url_for_client_; } return url_; } void ServiceWorkerClient::InheritControllerFrom( ServiceWorkerClient& creator_host, - const GURL& blob_url) { + const GURL& client_url) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(base::FeatureList::IsEnabled(kSharedWorkerBlobURLFix) || - blink::mojom::ServiceWorkerClientType::kDedicatedWorker == - GetClientType()); - DCHECK(blob_url.SchemeIsBlob()); + DCHECK(GetClientType() == + blink::mojom::ServiceWorkerClientType::kDedicatedWorker || + (base::FeatureList::IsEnabled(kSharedWorkerBlobURLFix) && + GetClientType() == + blink::mojom::ServiceWorkerClientType::kSharedWorker) || + (base::FeatureList::IsEnabled(features::kServiceWorkerSrcdocSupport) && + GetClientType() == blink::mojom::ServiceWorkerClientType::kWindow && + client_url.IsAboutSrcdoc())); + // Only expect srcdoc url or blob url of same origin as creator for + // client_url. + DCHECK((client_url.SchemeIsBlob() && + url::Origin::Create(client_url) + .IsSameOriginWith(creator_host.key().origin())) || + (base::FeatureList::IsEnabled(features::kServiceWorkerSrcdocSupport) && + client_url.IsAboutSrcdoc())); - UpdateUrls(blob_url, creator_host.top_frame_origin(), creator_host.key()); - - // Let `scope_match_url_for_blob_client_` be the creator's url for scope match + // Let `scope_match_url_for_client_` be the creator's url for scope match // because a client should be handled by the service worker of its creator. - scope_match_url_for_blob_client_ = creator_host.GetUrlForScopeMatch(); + // Update it before UpdateUrls so that CheckOnUpdateUrls inside UpdateUrls + // checks with the updated GetUrlForScopeMatch(). + scope_match_url_for_client_ = creator_host.GetUrlForScopeMatch(); + + UpdateUrls(client_url, creator_host.top_frame_origin(), creator_host.key()); // Inherit the controller of the creator. if (creator_host.controller_registration()) {
diff --git a/content/browser/service_worker/service_worker_client.h b/content/browser/service_worker/service_worker_client.h index d1cb7a1eb..4f428fb 100644 --- a/content/browser/service_worker/service_worker_client.h +++ b/content/browser/service_worker/service_worker_client.h
@@ -312,16 +312,16 @@ // For service worker clients. Returns the URL that is used for scope matching // algorithm. This can be different from url() in the case of blob URL - // workers. In that case, url() may be like "blob://https://a.test" and the - // scope matching URL is "https://a.test", inherited from the parent container - // host. + // workers or srcdoc/about:blank iframes. In that case, url() may be like + // "blob://https://a.test" or "about:srcdoc" and the scope matching URL is + // "https://a.test", inherited from the parent container host. const GURL& GetUrlForScopeMatch() const; - // For service worker clients that are dedicated workers. Inherits the - // controller of the creator document or worker. Used when the client was - // created with a blob URL. + // For service worker clients that are dedicated workers and srcdoc iframe. + // Inherits the controller of the creator document or worker. Used when the + // client was created with a blob, about:srcdoc or about:blank URL. void InheritControllerFrom(ServiceWorkerClient& creator_host, - const GURL& blob_url); + const GURL& client_url); void SetContainerReady(); @@ -501,11 +501,12 @@ base::flat_set<PendingUpdateVersion> versions_to_update_; // The type of client. - std::optional<ServiceWorkerClientInfo> client_info_; + ServiceWorkerClientInfo client_info_; // The URL used for service worker scope matching. It is empty except in the - // case of a service worker client with a blob URL. - GURL scope_match_url_for_blob_client_; + // case of a service worker client with a blob, about:blank or about:srcdoc + // URL. + GURL scope_match_url_for_client_; // Become true if the container is inherited by other container. bool is_inherited_ = false;
diff --git a/content/browser/service_worker/service_worker_client_utils.cc b/content/browser/service_worker/service_worker_client_utils.cc index 89e844e..5a9147c 100644 --- a/content/browser/service_worker/service_worker_client_utils.cc +++ b/content/browser/service_worker/service_worker_client_utils.cc
@@ -335,6 +335,8 @@ return; } + const url::Origin controller_origin = + url::Origin::Create(controller->script_url()); for (const auto& it : clients_info) { blink::mojom::ServiceWorkerClientInfoPtr info = GetWindowClientInfo(std::get<0>(it), std::get<1>(it), std::get<2>(it)); @@ -347,12 +349,15 @@ continue; DCHECK(!info->client_uuid.empty()); - // We can get info for a frame that was navigating end ended up with a + // TODO(crbug.com/385901567): Investigate/clarify the intention of this + // check. + // We can get info for a frame that was navigating and ended up with a // different URL than expected. In such case, we should make sure to not // expose cross-origin WindowClient. - if (info->url.DeprecatedGetOriginAsURL() != - controller->script_url().DeprecatedGetOriginAsURL()) + auto* rfh = RenderFrameHostImpl::FromID(std::get<0>(it)); + if (!controller_origin.IsSameOriginWith(rfh->GetLastCommittedOrigin())) { continue; + } clients.push_back(std::move(info)); }
diff --git a/content/browser/service_worker/service_worker_container_host.cc b/content/browser/service_worker/service_worker_container_host.cc index bd5b9f3..7e72fd314 100644 --- a/content/browser/service_worker/service_worker_container_host.cc +++ b/content/browser/service_worker/service_worker_container_host.cc
@@ -122,7 +122,7 @@ return; } - std::vector<GURL> urls = {url(), options->scope, script_url}; + std::vector<GURL> urls = {url_for_access_check(), options->scope, script_url}; if (!service_worker_security_utils::AllOriginsMatchAndCanAccessServiceWorkers( urls)) { mojo::ReportBadMessage(ServiceWorkerConsts::kBadMessageImproperOrigins); @@ -135,7 +135,8 @@ } if (!service_worker_security_utils:: - OriginCanRegisterServiceWorkerFromJavascript(url())) { + OriginCanRegisterServiceWorkerFromJavascript( + url_for_access_check())) { mojo::ReportBadMessage(ServiceWorkerConsts::kBadMessageImproperOrigins); // ReportBadMessage() will terminate the renderer process, but Mojo // complains if the callback is not run. Just run it with nonsense @@ -197,7 +198,7 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!CanServeContainerHostMethods( - &callback, url(), GURL(), + &callback, url_for_access_check(), GURL(), ServiceWorkerConsts::kServiceWorkerGetRegistrationErrorPrefix, nullptr)) { return; @@ -238,7 +239,7 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!CanServeContainerHostMethods( - &callback, url(), GURL(), + &callback, url_for_access_check(), GURL(), ServiceWorkerConsts::kServiceWorkerGetRegistrationsErrorPrefix, std::nullopt)) { return; @@ -770,6 +771,11 @@ return service_worker_client().url(); } +const GURL& ServiceWorkerContainerHostForClient::url_for_access_check() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return service_worker_client().GetUrlForScopeMatch(); +} + const base::WeakPtr<ServiceWorkerContextCore>& ServiceWorkerContainerHostForServiceWorker::context() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -787,6 +793,12 @@ return url_; } +const GURL& ServiceWorkerContainerHostForServiceWorker::url_for_access_check() + const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return url_; +} + ServiceWorkerHost* ServiceWorkerContainerHostForServiceWorker::service_worker_host() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -1027,7 +1039,7 @@ *out_error = ServiceWorkerConsts::kBadMessageInvalidURL; return false; } - std::vector<GURL> urls = {url(), client_url}; + std::vector<GURL> urls = {url_for_access_check(), client_url}; if (!service_worker_security_utils::AllOriginsMatchAndCanAccessServiceWorkers( urls)) { *out_error = ServiceWorkerConsts::kBadMessageImproperOrigins; @@ -1044,7 +1056,7 @@ *out_error = ServiceWorkerConsts::kBadMessageFromNonWindow; return false; } - if (!OriginCanAccessServiceWorkers(url())) { + if (!OriginCanAccessServiceWorkers(url_for_access_check())) { *out_error = ServiceWorkerConsts::kBadMessageImproperOrigins; return false; }
diff --git a/content/browser/service_worker/service_worker_container_host.h b/content/browser/service_worker/service_worker_container_host.h index 432a38c..719147c 100644 --- a/content/browser/service_worker/service_worker_container_host.h +++ b/content/browser/service_worker/service_worker_container_host.h
@@ -175,6 +175,11 @@ // The URL of this context. virtual const GURL& url() const = 0; + // The url to use for access check, the same url as the one used for scope + // match. This is needed for srcdoc iframes where url() is "about:srcdoc" and + // url_for_access_check() is the parent client's URL that matches the service + // worker's origin. + virtual const GURL& url_for_access_check() const = 0; // Calls ContentBrowserClient::AllowServiceWorker(). Returns true if content // settings allows service workers to run at |scope|. If this container is for @@ -304,6 +309,7 @@ const base::WeakPtr<ServiceWorkerContextCore>& context() const override; base::WeakPtr<ServiceWorkerContainerHost> AsWeakPtr() override; const GURL& url() const override; + const GURL& url_for_access_check() const override; bool AllowServiceWorker(const GURL& scope, const GURL& script_url) override; void DispatchExtendableMessageEvent( scoped_refptr<ServiceWorkerVersion> version, @@ -470,6 +476,7 @@ const base::WeakPtr<ServiceWorkerContextCore>& context() const override; base::WeakPtr<ServiceWorkerContainerHost> AsWeakPtr() override; const GURL& url() const override; + const GURL& url_for_access_check() const override; bool AllowServiceWorker(const GURL& scope, const GURL& script_url) override; void DispatchExtendableMessageEvent( scoped_refptr<ServiceWorkerVersion> version,
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc index 907f55f..a1696fbd 100644 --- a/content/browser/service_worker/service_worker_context_core.cc +++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -520,7 +520,8 @@ service_worker_client.container_host() ? service_worker_client.container_host()->ukm_source_id() : ukm::kInvalidSourceId, - service_worker_client.url(), service_worker_client.GetClientType()); + service_worker_client.GetUrlForScopeMatch(), + service_worker_client.GetClientType()); } void ServiceWorkerClientOwner::DestroyServiceWorkerClient( @@ -698,7 +699,8 @@ observer_list_->Notify( FROM_HERE, &ServiceWorkerContextCoreObserver::OnClientIsExecutionReady, service_worker_client.container_host()->ukm_source_id(), - service_worker_client.url(), service_worker_client.GetClientType()); + service_worker_client.GetUrlForScopeMatch(), + service_worker_client.GetClientType()); } bool ServiceWorkerContextCore::MaybeHasRegistrationForStorageKey(
diff --git a/content/browser/service_worker/service_worker_object_host.cc b/content/browser/service_worker/service_worker_object_host.cc index be6642f9..836c424 100644 --- a/content/browser/service_worker/service_worker_object_host.cc +++ b/content/browser/service_worker/service_worker_object_host.cc
@@ -21,7 +21,8 @@ scoped_refptr<ServiceWorkerVersion> version) : context_(context), container_host_(container_host), - container_origin_(url::Origin::Create(container_host_->url())), + container_origin_( + url::Origin::Create(container_host_->url_for_access_check())), version_(std::move(version)) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(context_ && container_host_ && version_); @@ -88,7 +89,8 @@ std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort); return; } - DCHECK_EQ(container_origin_, url::Origin::Create(container_host_->url())); + DCHECK_EQ(container_origin_, + url::Origin::Create(container_host_->url_for_access_check())); // As we don't track tasks between workers and renderers, we can nullify the // message's parent task ID.
diff --git a/content/browser/service_worker/service_worker_registration_object_host.cc b/content/browser/service_worker/service_worker_registration_object_host.cc index 2da8e04..a1dffc8 100644 --- a/content/browser/service_worker/service_worker_registration_object_host.cc +++ b/content/browser/service_worker/service_worker_registration_object_host.cc
@@ -347,11 +347,12 @@ return false; } - std::vector<GURL> urls = {container_host_->url(), registration_->scope()}; + std::vector<GURL> urls = {container_host_->url_for_access_check(), + registration_->scope()}; if (!service_worker_security_utils::AllOriginsMatchAndCanAccessServiceWorkers( urls)) { SCOPED_CRASH_KEY_STRING256("SWROH_CSROHM", "host_url", - container_host_->url().spec()); + container_host_->url_for_access_check().spec()); SCOPED_CRASH_KEY_STRING256("SWROH_CSROHM", "reg_scope", registration_->scope().spec()); receivers_.ReportBadMessage(
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index f204b28..5fb02d4 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -1695,7 +1695,7 @@ context_->service_worker_client_owner().GetServiceWorkerClientByClientID( client_uuid); if (!service_worker_client || - service_worker_client->url().DeprecatedGetOriginAsURL() != + service_worker_client->GetUrlForScopeMatch().DeprecatedGetOriginAsURL() != script_url_.DeprecatedGetOriginAsURL()) { // The promise will be resolved to 'undefined'. // Note that we don't BadMessage here since Clients#get() can be passed an @@ -1795,7 +1795,7 @@ } } - if (service_worker_client->url().DeprecatedGetOriginAsURL() != + if (service_worker_client->GetUrlForScopeMatch().DeprecatedGetOriginAsURL() != script_url_.DeprecatedGetOriginAsURL()) { associated_interface_receiver_.ReportBadMessage( "Received Client#postMessage() request for a cross-origin client."); @@ -1851,7 +1851,7 @@ std::move(callback).Run(nullptr /* client */); return; } - if (service_worker_client->url().DeprecatedGetOriginAsURL() != + if (service_worker_client->GetUrlForScopeMatch().DeprecatedGetOriginAsURL() != script_url_.DeprecatedGetOriginAsURL()) { associated_interface_receiver_.ReportBadMessage( "Received WindowClient#focus() request for a cross-origin client."); @@ -1908,7 +1908,7 @@ std::string("The client was not found.")); return; } - if (service_worker_client->url().DeprecatedGetOriginAsURL() != + if (service_worker_client->GetUrlForScopeMatch().DeprecatedGetOriginAsURL() != script_url_.DeprecatedGetOriginAsURL()) { associated_interface_receiver_.ReportBadMessage( "Received WindowClient#navigate() request for a cross-origin client.");
diff --git a/content/browser/webid/federated_auth_disconnect_request.cc b/content/browser/webid/federated_auth_disconnect_request.cc index dd70424..0002aeb 100644 --- a/content/browser/webid/federated_auth_disconnect_request.cc +++ b/content/browser/webid/federated_auth_disconnect_request.cc
@@ -5,6 +5,7 @@ #include "content/browser/webid/federated_auth_disconnect_request.h" #include "base/notreached.h" +#include "content/browser/webid/flags.h" #include "content/browser/webid/webid_utils.h" #include "content/public/browser/federated_identity_api_permission_context_delegate.h" #include "content/public/browser/federated_identity_permission_context_delegate.h" @@ -109,8 +110,13 @@ provider_fetcher_ = std::make_unique<FederatedProviderFetcher>( *render_frame_host_, network_manager_.get()); GURL config_url = options_->config->config_url; + // TODO(crbug.com/390626180): It seems ok to ignore the well-known checks in + // all cases here. However, keeping this unchanged for now when the IDP + // registration API is not enabled since we only really need this for that + // case. provider_fetcher_->Start( - {GURL(config_url)}, blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, + {{config_url, IsFedCmIdPRegistrationEnabled()}}, + blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, /*icon_minimum_size=*/0, base::BindOnce( &FederatedAuthDisconnectRequest::OnAllConfigAndWellKnownFetched,
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc index fbada39c..e597b24 100644 --- a/content/browser/webid/federated_auth_request_impl.cc +++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -1215,10 +1215,18 @@ fetch_data_.pending_idps = std::move(pending_idps); } + std::vector<FederatedProviderFetcher::FetchRequest> idps; + for (const auto& idp : fetch_data_.pending_idps) { + auto idp_get = token_request_get_infos_.find(idp); + CHECK(idp_get != token_request_get_infos_.end()); + idps.emplace_back( + idp, idp_get->second.provider->config->from_idp_registration_api); + } + provider_fetcher_ = std::make_unique<FederatedProviderFetcher>( render_frame_host(), network_manager_.get()); provider_fetcher_->Start( - fetch_data_.pending_idps, rp_mode_, icon_ideal_size, icon_minimum_size, + idps, rp_mode_, icon_ideal_size, icon_minimum_size, base::BindOnce(&FederatedAuthRequestImpl::OnAllConfigAndWellKnownFetched, weak_ptr_factory_.GetWeakPtr())); }
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc index ba03272d..b310b43 100644 --- a/content/browser/webid/federated_auth_request_impl_unittest.cc +++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -151,6 +151,7 @@ std::optional<std::vector<std::string>> fields; const char* params_json; std::optional<std::string> type; + bool from_idp_registration_api = false; }; // Parameters for a call to RequestToken. @@ -1136,6 +1137,8 @@ options->config = blink::mojom::IdentityProviderConfig::New(); options->config->config_url = GURL(identity_provider.provider); options->config->client_id = identity_provider.client_id; + options->config->from_idp_registration_api = + identity_provider.from_idp_registration_api; options->nonce = identity_provider.nonce; options->login_hint = identity_provider.login_hint; options->domain_hint = identity_provider.domain_hint; @@ -1814,6 +1817,32 @@ EXPECT_FALSE(DidFetch(FetchedEndpoint::ACCOUNTS)); } +// Test that when the provider url is not in the well-known, it succeeds when it +// is registered. +TEST_F(FederatedAuthRequestImplTest, WellKnownNotInListButRegistered) { + base::test::ScopedFeatureList list; + list.InitAndEnableFeature(features::kFedCmIdPRegistration); + + const char* idp_config_url = + kDefaultRequestParameters.identity_providers[0].provider; + const char* kWellKnownMismatchConfigUrl = "https://mismatch.example"; + EXPECT_NE(std::string(idp_config_url), kWellKnownMismatchConfigUrl); + + MockConfiguration config = kConfigurationValid; + config.idp_info[idp_config_url].well_known = { + {kWellKnownMismatchConfigUrl}, {ParseStatus::kSuccess, net::HTTP_OK}}; + RequestParameters requestParameters = kDefaultRequestParameters; + requestParameters.identity_providers[0].from_idp_registration_api = true; + + // Need to simulate there is actually a registered IdP, or the call will fail. + std::vector<GURL> registry; + registry.emplace_back(kProviderUrlFull); + EXPECT_CALL(*test_permission_delegate_, GetRegisteredIdPs()) + .WillOnce(Return(registry)); + + RunAuthTest(requestParameters, kExpectationSuccess, config); +} + // Test that the well-known file has too many provider urls. TEST_F(FederatedAuthRequestImplTest, WellKnownHasTooManyProviderUrls) { RequestExpectations expectation = {
diff --git a/content/browser/webid/federated_auth_user_info_request.cc b/content/browser/webid/federated_auth_user_info_request.cc index 523a49dc..5abd838 100644 --- a/content/browser/webid/federated_auth_user_info_request.cc +++ b/content/browser/webid/federated_auth_user_info_request.cc
@@ -165,8 +165,13 @@ // destroyed. provider_fetcher_ = std::make_unique<FederatedProviderFetcher>( *render_frame_host_, network_manager_.get()); + // TODO(crbug.com/390626180): It seems ok to ignore the well-known checks in + // all cases here. However, keeping this unchanged for now when the IDP + // registration API is not enabled since we only really need this for that + // case. provider_fetcher_->Start( - {idp_config_url_}, blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, + {{idp_config_url_, IsFedCmIdPRegistrationEnabled()}}, + blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, /*icon_minimum_size=*/0, base::BindOnce( &FederatedAuthUserInfoRequest::OnAllConfigAndWellKnownFetched,
diff --git a/content/browser/webid/federated_provider_fetcher.cc b/content/browser/webid/federated_provider_fetcher.cc index ac42508..e8879626 100644 --- a/content/browser/webid/federated_provider_fetcher.cc +++ b/content/browser/webid/federated_provider_fetcher.cc
@@ -56,21 +56,23 @@ FederatedProviderFetcher::~FederatedProviderFetcher() = default; void FederatedProviderFetcher::Start( - const std::set<GURL>& identity_provider_config_urls, + const std::vector<FetchRequest>& requested_providers, blink::mojom::RpMode rp_mode, int icon_ideal_size, int icon_minimum_size, RequesterCallback callback) { callback_ = std::move(callback); - for (const GURL& identity_provider_config_url : - identity_provider_config_urls) { + for (const auto& request : requested_providers) { FetchResult fetch_result; - fetch_result.identity_provider_config_url = identity_provider_config_url; + fetch_result.identity_provider_config_url = + request.identity_provider_config_url; + fetch_result.force_skip_well_known_enforcement = + request.force_skip_well_known_enforcement; fetch_results_.push_back(std::move(fetch_result)); - pending_well_known_fetches_.insert(identity_provider_config_url); - pending_config_fetches_.insert(identity_provider_config_url); + pending_well_known_fetches_.insert(request.identity_provider_config_url); + pending_config_fetches_.insert(request.identity_provider_config_url); } // In a separate loop to avoid invalidating references when adding elements to @@ -97,8 +99,7 @@ constexpr char kWellKnownFileStr[] = "well-known file"; if (status.parse_status != IdpNetworkRequestManager::ParseStatus::kSuccess && - !ShouldSkipWellKnownEnforcementForIdp( - fetch_result.identity_provider_config_url)) { + !ShouldSkipWellKnownEnforcementForIdp(fetch_result)) { std::optional<std::string> additional_console_error_message = webid::ComputeConsoleMessageForHttpResponseCode(kWellKnownFileStr, status.response_code); @@ -275,8 +276,7 @@ // contains the config url passed in the JS call // (a) - if (ShouldSkipWellKnownEnforcementForIdp( - result.identity_provider_config_url)) { + if (ShouldSkipWellKnownEnforcementForIdp(result)) { return; } @@ -353,14 +353,18 @@ } bool FederatedProviderFetcher::ShouldSkipWellKnownEnforcementForIdp( - const GURL& idp_url) { + const FetchResult& fetch_result) { if (IsFedCmWithoutWellKnownEnforcementEnabled()) { return true; } + if (fetch_result.force_skip_well_known_enforcement) { + return true; + } // Skip if RP and IDP are same-site. - return webid::IsSameSite(render_frame_host_->GetLastCommittedOrigin(), - url::Origin::Create(idp_url)); + return webid::IsSameSite( + render_frame_host_->GetLastCommittedOrigin(), + url::Origin::Create(fetch_result.identity_provider_config_url)); } } // namespace content
diff --git a/content/browser/webid/federated_provider_fetcher.h b/content/browser/webid/federated_provider_fetcher.h index b2c1a4b..d6c9546 100644 --- a/content/browser/webid/federated_provider_fetcher.h +++ b/content/browser/webid/federated_provider_fetcher.h
@@ -42,12 +42,22 @@ FetchResult(const FetchResult&); ~FetchResult(); GURL identity_provider_config_url; + bool force_skip_well_known_enforcement = false; IdpNetworkRequestManager::WellKnown wellknown; IdpNetworkRequestManager::Endpoints endpoints; std::optional<IdentityProviderMetadata> metadata; std::optional<FetchError> error; }; + struct FetchRequest { + GURL identity_provider_config_url; + bool force_skip_well_known_enforcement = false; + FetchRequest(const GURL& url, bool force_skip_well_known_enforcement) + : identity_provider_config_url(url), + force_skip_well_known_enforcement(force_skip_well_known_enforcement) { + } + }; + using RequesterCallback = base::OnceCallback<void(std::vector<FetchResult>)>; // TODO(crbug.com/40283354): Remove |render_frame_host| when the IDP signin @@ -61,7 +71,7 @@ // Starts fetch of config and well-known files. Start() should be called at // most once per FederatedProviderFetcher instance. - void Start(const std::set<GURL>& identity_provider_config_urls, + void Start(const std::vector<FetchRequest>& requested_providers, blink::mojom::RpMode rp_mode, int icon_ideal_size, int icon_minimum_size, @@ -91,7 +101,7 @@ void RunCallbackIfDone(); - bool ShouldSkipWellKnownEnforcementForIdp(const GURL& idp_url); + bool ShouldSkipWellKnownEnforcementForIdp(const FetchResult& fetch_result); raw_ref<RenderFrameHost> render_frame_host_;
diff --git a/content/browser/webid/federated_provider_fetcher_unittest.cc b/content/browser/webid/federated_provider_fetcher_unittest.cc index 7b03525a..0780245 100644 --- a/content/browser/webid/federated_provider_fetcher_unittest.cc +++ b/content/browser/webid/federated_provider_fetcher_unittest.cc
@@ -38,7 +38,7 @@ std::make_unique<StrictMock<MockIdpNetworkRequestManager>>(); FederatedProviderFetcher fetcher(*main_rfh(), network_manager.get()); - EXPECT_CALL(*network_manager, FetchConfig(_, _, _, _, _)) + EXPECT_CALL(*network_manager, FetchConfig) .WillOnce(WithArg<4>( [](IdpNetworkRequestManager::FetchConfigCallback callback) { IdpNetworkRequestManager::Endpoints endpoints; @@ -53,7 +53,7 @@ })); // Returns a 404 for the fetch of the well-known file. - EXPECT_CALL(*network_manager, FetchWellKnown(_, _)) + EXPECT_CALL(*network_manager, FetchWellKnown) .WillOnce(WithArg<1>( [](IdpNetworkRequestManager::FetchWellKnownCallback callback) { IdpNetworkRequestManager::WellKnown well_known; @@ -66,7 +66,9 @@ // Asserts that we get a kWellKnownHttpNotFound. fetcher.Start( - {GURL("https://idp.example/fedcm.json")}, blink::mojom::RpMode::kPassive, + {{GURL("https://idp.example/fedcm.json"), + /*force_skip_well_known_enforcement=*/false}}, + blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, /*icon_minimum_size=*/0, base::BindLambdaForTesting( @@ -90,7 +92,7 @@ std::make_unique<StrictMock<MockIdpNetworkRequestManager>>(); FederatedProviderFetcher fetcher(*main_rfh(), network_manager.get()); - EXPECT_CALL(*network_manager, FetchConfig(_, _, _, _, _)) + EXPECT_CALL(*network_manager, FetchConfig) .WillOnce(WithArg<4>( [](IdpNetworkRequestManager::FetchConfigCallback callback) { IdpNetworkRequestManager::Endpoints endpoints; @@ -105,7 +107,7 @@ })); // Returns a 404 for the fetch of the well-known file. - EXPECT_CALL(*network_manager, FetchWellKnown(_, _)) + EXPECT_CALL(*network_manager, FetchWellKnown) .WillOnce(WithArg<1>( [](IdpNetworkRequestManager::FetchWellKnownCallback callback) { IdpNetworkRequestManager::WellKnown well_known; @@ -118,7 +120,9 @@ // Asserts that we get no error in the result. fetcher.Start( - {GURL("https://idp.example/fedcm.json")}, blink::mojom::RpMode::kPassive, + {{GURL("https://idp.example/fedcm.json"), + /*force_skip_well_known_enforcement=*/false}}, + blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, /*icon_minimum_size=*/0, base::BindLambdaForTesting( @@ -140,7 +144,7 @@ FederatedProviderFetcher fetcher(*main_rfh(), network_manager.get()); // Returns a 404 for the fetch of the config file. - EXPECT_CALL(*network_manager, FetchConfig(_, _, _, _, _)) + EXPECT_CALL(*network_manager, FetchConfig) .WillOnce(WithArg<4>( [](IdpNetworkRequestManager::FetchConfigCallback callback) { std::move(callback).Run( @@ -148,7 +152,7 @@ /*endpoints=*/{}, /*metadata=*/{}); })); - EXPECT_CALL(*network_manager, FetchWellKnown(_, _)) + EXPECT_CALL(*network_manager, FetchWellKnown) .WillOnce(WithArg<1>( [](IdpNetworkRequestManager::FetchWellKnownCallback callback) { IdpNetworkRequestManager::WellKnown well_known; @@ -161,7 +165,9 @@ // Asserts that we get a kConfigHttpNotFound. fetcher.Start( - {GURL("https://idp.example/fedcm.json")}, blink::mojom::RpMode::kPassive, + {{GURL("https://idp.example/fedcm.json"), + /*force_skip_well_known_enforcement=*/false}}, + blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, /*icon_minimum_size=*/0, base::BindLambdaForTesting( @@ -183,14 +189,14 @@ FederatedProviderFetcher fetcher(*main_rfh(), network_manager.get()); // Returns a 200 but with an empty and invalid response. - EXPECT_CALL(*network_manager, FetchConfig(_, _, _, _, _)) + EXPECT_CALL(*network_manager, FetchConfig) .WillOnce(WithArg<4>( [](IdpNetworkRequestManager::FetchConfigCallback callback) { std::move(callback).Run({ParseStatus::kSuccess, net::HTTP_OK}, /*endpoints=*/{}, /*metadata=*/{}); })); - EXPECT_CALL(*network_manager, FetchWellKnown(_, _)) + EXPECT_CALL(*network_manager, FetchWellKnown) .WillOnce(WithArg<1>( [](IdpNetworkRequestManager::FetchWellKnownCallback callback) { IdpNetworkRequestManager::WellKnown well_known; @@ -203,7 +209,9 @@ // Asserts that we get a kConfigHttpNotFound. fetcher.Start( - {GURL("https://idp.example/fedcm.json")}, blink::mojom::RpMode::kPassive, + {{GURL("https://idp.example/fedcm.json"), + /*force_skip_well_known_enforcement=*/false}}, + blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, /*icon_minimum_size=*/0, base::BindLambdaForTesting( @@ -225,7 +233,7 @@ FederatedProviderFetcher fetcher(*main_rfh(), network_manager.get()); // Returns a 200 but with an empty and invalid response. - EXPECT_CALL(*network_manager, FetchConfig(_, _, _, _, _)) + EXPECT_CALL(*network_manager, FetchConfig) .WillOnce(WithArg<4>( [](IdpNetworkRequestManager::FetchConfigCallback callback) { IdpNetworkRequestManager::Endpoints endpoints; @@ -239,7 +247,7 @@ endpoints, metadata); })); - EXPECT_CALL(*network_manager, FetchWellKnown(_, _)) + EXPECT_CALL(*network_manager, FetchWellKnown) .WillOnce(WithArg<1>( [](IdpNetworkRequestManager::FetchWellKnownCallback callback) { IdpNetworkRequestManager::WellKnown well_known; @@ -252,7 +260,9 @@ // Asserts that we get a kConfigHttpNotFound. fetcher.Start( - {GURL("https://idp.example/fedcm.json")}, blink::mojom::RpMode::kPassive, + {{GURL("https://idp.example/fedcm.json"), + /*force_skip_well_known_enforcement=*/false}}, + blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, /*icon_minimum_size=*/0, base::BindLambdaForTesting( @@ -272,7 +282,7 @@ FederatedProviderFetcher fetcher(*main_rfh(), network_manager.get()); // Returns a 200 but with an empty and invalid response. - EXPECT_CALL(*network_manager, FetchConfig(_, _, _, _, _)) + EXPECT_CALL(*network_manager, FetchConfig) .WillOnce(WithArg<4>( [](IdpNetworkRequestManager::FetchConfigCallback callback) { IdpNetworkRequestManager::Endpoints endpoints; @@ -286,7 +296,7 @@ endpoints, metadata); })); - EXPECT_CALL(*network_manager, FetchWellKnown(_, _)) + EXPECT_CALL(*network_manager, FetchWellKnown) .WillOnce(WithArg<1>( [](IdpNetworkRequestManager::FetchWellKnownCallback callback) { IdpNetworkRequestManager::WellKnown well_known; @@ -301,7 +311,9 @@ // Asserts that we get a kConfigHttpNotFound. fetcher.Start( - {GURL("https://idp.example/fedcm.json")}, blink::mojom::RpMode::kPassive, + {{GURL("https://idp.example/fedcm.json"), + /*force_skip_well_known_enforcement=*/false}}, + blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, /*icon_minimum_size=*/0, base::BindLambdaForTesting( @@ -328,7 +340,7 @@ FederatedProviderFetcher fetcher(*main_rfh(), network_manager.get()); // Returns a 200 but with an empty and invalid response. - EXPECT_CALL(*network_manager, FetchConfig(_, _, _, _, _)) + EXPECT_CALL(*network_manager, FetchConfig) .WillOnce(WithArg<4>( [](IdpNetworkRequestManager::FetchConfigCallback callback) { IdpNetworkRequestManager::Endpoints endpoints; @@ -342,7 +354,7 @@ endpoints, metadata); })); - EXPECT_CALL(*network_manager, FetchWellKnown(_, _)) + EXPECT_CALL(*network_manager, FetchWellKnown) .WillOnce(WithArg<1>( [](IdpNetworkRequestManager::FetchWellKnownCallback callback) { IdpNetworkRequestManager::WellKnown well_known; @@ -358,7 +370,9 @@ // Asserts that we get no error in the result. fetcher.Start( - {GURL("https://idp.example/fedcm.json")}, blink::mojom::RpMode::kPassive, + {{GURL("https://idp.example/fedcm.json"), + /*force_skip_well_known_enforcement=*/false}}, + blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, /*icon_minimum_size=*/0, base::BindLambdaForTesting( @@ -382,7 +396,7 @@ FederatedProviderFetcher fetcher(*main_rfh(), network_manager.get()); // Returns a 200 but with an empty and invalid response. - EXPECT_CALL(*network_manager, FetchConfig(_, _, _, _, _)) + EXPECT_CALL(*network_manager, FetchConfig) .WillOnce(WithArg<4>( [](IdpNetworkRequestManager::FetchConfigCallback callback) { IdpNetworkRequestManager::Endpoints endpoints; @@ -396,7 +410,7 @@ endpoints, metadata); })); - EXPECT_CALL(*network_manager, FetchWellKnown(_, _)) + EXPECT_CALL(*network_manager, FetchWellKnown) .WillOnce(WithArg<1>( [](IdpNetworkRequestManager::FetchWellKnownCallback callback) { IdpNetworkRequestManager::WellKnown well_known; @@ -411,7 +425,9 @@ // Asserts that we get no error in the result. fetcher.Start( - {GURL("https://idp.example/fedcm.json")}, blink::mojom::RpMode::kPassive, + {{GURL("https://idp.example/fedcm.json"), + /*force_skip_well_known_enforcement=*/false}}, + blink::mojom::RpMode::kPassive, /*icon_ideal_size=*/0, /*icon_minimum_size=*/0, base::BindLambdaForTesting( @@ -755,4 +771,54 @@ blink::mojom::FederatedAuthRequestResult::kConfigHttpNotFound); } +TEST_F(FederatedProviderFetcherTest, RegisteredIdpSkipsWellKnownCheck) { + base::test::ScopedFeatureList list; + list.InitAndEnableFeature(features::kFedCmIdPRegistration); + auto network_manager = + std::make_unique<StrictMock<MockIdpNetworkRequestManager>>(); + FederatedProviderFetcher fetcher(*main_rfh(), network_manager.get()); + + EXPECT_CALL(*network_manager, FetchConfig) + .WillOnce(WithArg<4>( + [](IdpNetworkRequestManager::FetchConfigCallback callback) { + IdpNetworkRequestManager::Endpoints endpoints; + endpoints.token = GURL("https://idp.example/token.php"); + endpoints.accounts = GURL("https://idp.example/accounts.php"); + + IdentityProviderMetadata metadata; + metadata.idp_login_url = + GURL("https://idp.example/idp_login_url.php"); + std::move(callback).Run({ParseStatus::kSuccess, net::HTTP_OK}, + endpoints, metadata); + })); + + // Returns a 404 for the fetch of the well-known file. + EXPECT_CALL(*network_manager, FetchWellKnown) + .WillOnce(WithArg<1>( + [](IdpNetworkRequestManager::FetchWellKnownCallback callback) { + IdpNetworkRequestManager::WellKnown well_known; + std::move(callback).Run( + {ParseStatus::kHttpNotFoundError, net::HTTP_NOT_FOUND}, + well_known); + })); + + base::RunLoop loop; + + // Asserts that we get success despite well-known failing. + fetcher.Start( + {{GURL("https://idp.example/fedcm.json"), + /*force_skip_well_known_enforcement=*/true}}, + blink::mojom::RpMode::kPassive, + /*icon_ideal_size=*/0, + /*icon_minimum_size=*/0, + base::BindLambdaForTesting( + [&loop](std::vector<FederatedProviderFetcher::FetchResult> result) { + EXPECT_EQ(result.size(), 1ul); + EXPECT_FALSE(result[0].error); + loop.Quit(); + })); + + loop.Run(); +} + } // namespace content
diff --git a/content/common/features.cc b/content/common/features.cc index 6c1142b..5323e486 100644 --- a/content/common/features.cc +++ b/content/common/features.cc
@@ -379,20 +379,6 @@ #endif ); -// (crbug.com/1371756): When enabled, the static routing API starts -// ServiceWorker when the routing result of a main resource request was network -// fallback. -BASE_FEATURE(kServiceWorkerStaticRouterStartServiceWorker, - "ServiceWorkerStaticRouterStartServiceWorker", - base::FEATURE_ENABLED_BY_DEFAULT); - -// (crbug.com/340949948): Killswitch for the fix to address the ServiceWorker -// main and subreosurce loader lifetime issue, which introduces fetch() failure -// in the sw fetch handler. -BASE_FEATURE(kServiceWorkerStaticRouterRaceRequestFix, - "kServiceWorkerStaticRouterRaceRequestFix", - base::FEATURE_ENABLED_BY_DEFAULT); - // The set of ServiceWorker to bypass while making navigation request. // They are represented by a comma separated list of HEX encoded SHA256 hash of // the ServiceWorker's scripts. @@ -407,6 +393,26 @@ &kServiceWorkerBypassFetchHandlerHashStrings, "script_checksum_to_bypass", ""}; +// (crbug.com/41411856): When enabled, the srcdoc iframes are controlled by the +// same service worker that controls their parent. +BASE_FEATURE(kServiceWorkerSrcdocSupport, + "ServiceWorkerSrcdocSupport", + base::FEATURE_DISABLED_BY_DEFAULT); + +// (crbug.com/340949948): Killswitch for the fix to address the ServiceWorker +// main and subreosurce loader lifetime issue, which introduces fetch() failure +// in the sw fetch handler. +BASE_FEATURE(kServiceWorkerStaticRouterRaceRequestFix, + "kServiceWorkerStaticRouterRaceRequestFix", + base::FEATURE_ENABLED_BY_DEFAULT); + +// (crbug.com/1371756): When enabled, the static routing API starts +// ServiceWorker when the routing result of a main resource request was network +// fallback. +BASE_FEATURE(kServiceWorkerStaticRouterStartServiceWorker, + "ServiceWorkerStaticRouterStartServiceWorker", + base::FEATURE_ENABLED_BY_DEFAULT); + // Enables skipping the early call to CommitPending when navigating away from a // crashed frame. BASE_FEATURE(kSkipEarlyCommitPendingForCrashedFrame,
diff --git a/content/common/features.h b/content/common/features.h index e1f2f46..0f9451f 100644 --- a/content/common/features.h +++ b/content/common/features.h
@@ -89,12 +89,13 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE( kServiceWorkerAvoidMainThreadForInitialization); CONTENT_EXPORT BASE_DECLARE_FEATURE( - kServiceWorkerStaticRouterStartServiceWorker); -CONTENT_EXPORT BASE_DECLARE_FEATURE(kServiceWorkerStaticRouterRaceRequestFix); -CONTENT_EXPORT BASE_DECLARE_FEATURE( kServiceWorkerBypassFetchHandlerHashStrings); CONTENT_EXPORT extern const base::FeatureParam<std::string> kServiceWorkerBypassFetchHandlerBypassedHashStrings; +CONTENT_EXPORT BASE_DECLARE_FEATURE(kServiceWorkerSrcdocSupport); +CONTENT_EXPORT BASE_DECLARE_FEATURE(kServiceWorkerStaticRouterRaceRequestFix); +CONTENT_EXPORT BASE_DECLARE_FEATURE( + kServiceWorkerStaticRouterStartServiceWorker); CONTENT_EXPORT BASE_DECLARE_FEATURE(kSkipEarlyCommitPendingForCrashedFrame); #if BUILDFLAG(IS_MAC) CONTENT_EXPORT BASE_DECLARE_FEATURE(kTextInputClient);
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java index e3ce5415..dfb135b 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
@@ -666,7 +666,7 @@ // opening the Tab Switcher. Timers will restart during the next onAttach. if (mWebContentsObserver != null) { mHistogramRecorder.recordAccessibilityUsageHistograms(); - mWebContentsObserver.destroy(); + mWebContentsObserver.observe(null); mWebContentsObserver = null; } @@ -781,7 +781,7 @@ if (mDelegate.getWebContents() == null) { deleteEarly(); } else { - if (mWebContentsObserver != null) mWebContentsObserver.destroy(); + if (mWebContentsObserver != null) mWebContentsObserver.observe(null); WindowEventObserverManager.from(mDelegate.getWebContents()).removeObserver(this); ((WebContentsImpl) mDelegate.getWebContents()) .removeUserData(WebContentsAccessibilityImpl.class);
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java index ff4ac77c..783df3d22 100644 --- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -310,7 +310,7 @@ mNativeWebContentsAndroid = 0; mNavigationController = null; if (mObserverProxy != null) { - mObserverProxy.destroy(); + mObserverProxy.webContentsDestroyed(); mObserverProxy = null; } }
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java index 8a692f5..f461adc 100644 --- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java +++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java
@@ -505,15 +505,17 @@ finishObserverCall(); } + @Override @CalledByNative - protected void webContentsDestroyed() { + public void webContentsDestroyed() { ThreadUtils.assertOnUiThread(); RewindableIterator<WebContentsObserver> observersIterator = mObservers.rewindableIterator(); for (; observersIterator.hasNext(); ) { - observersIterator.next().destroy(); + WebContentsObserver observer = observersIterator.next(); + observer.webContentsDestroyed(); + observer.observe(null); } - // All observer destroy() implementations should result in their removal - // from the proxy. + // All observer observe(null) implementations should result in their removal from the proxy. String remainingObservers = "These observers were not removed: "; if (!mObservers.isEmpty()) { for (observersIterator.rewind(); observersIterator.hasNext(); ) {
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java index 7ccf89e..600897c 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java
@@ -245,30 +245,12 @@ public void mediaSessionCreated(MediaSession mediaSession) {} /** - * Notified when {@link #destroy()} has been triggered. This can be the result of the {@link - * #getWebContents()} being destroyed, or because an embedder has triggered {@link #onDestroy()} - * manually. + * Called when {@link #getWebContents()} is being destroyed. * - * <p>As an embedder, this method should be overridden and not called directly. + * <p>After this call, clients should assume that {@link #getWebContents()} will be imminently + * destroyed and the C++ counterpart deleted. */ - protected void onDestroy() {} - - /** - * To be called when this object should no longer observe any WebContents and also to carry out - * any cleanup handled in {@link #onDestroy}. - * - * <p>Only the first call to {@link #destroy()}} will trigger {@link #onDestroy()} and - * unregister this observer from the linked {@link #getWebContents()} (if one had been - * registered). - */ - public final void destroy() { - if (mHasBeenDestroyed) return; - mHasBeenDestroyed = true; - - onDestroy(); - - observe(null); - } + public void webContentsDestroyed() {} /** * Updates the {@link WebContents} that this class is observing, and if null, stops observing
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VSyncPausedTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VSyncPausedTest.java index fbc07f14..8625217 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/VSyncPausedTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/VSyncPausedTest.java
@@ -63,7 +63,7 @@ @After public void tearDown() { - ThreadUtils.runOnUiThreadBlocking(() -> mObserver.destroy()); + ThreadUtils.runOnUiThreadBlocking(() -> mObserver.observe(null)); } @Test
diff --git a/content/test/data/gpu/webcodecs/copyTo.html b/content/test/data/gpu/webcodecs/copyTo.html index d802f29..af001e9f 100644 --- a/content/test/data/gpu/webcodecs/copyTo.html +++ b/content/test/data/gpu/webcodecs/copyTo.html
@@ -21,6 +21,23 @@ return { r: r, g: g, b: b }; } + function compareArrayBuffers(buffer1, buffer2) { + const view1 = new DataView(buffer1); + const view2 = new DataView(buffer2); + + if (view1.byteLength !== view2.byteLength) { + return false; + } + + for (let i = 0; i < view1.byteLength; i++) { + if (view1.getUint8(i) !== view2.getUint8(i)) { + return false; + } + } + + return true; + } + async function validateFourColorsBytes(frame) { const m = 4; const tolerance = 8; @@ -42,7 +59,11 @@ } let size = frame.allocationSize(options); let buffer = new ArrayBuffer(size); + let shared_buffer = new SharedArrayBuffer(size); let layout = await frame.copyTo(buffer, options); + await frame.copyTo(shared_buffer, options); + TEST.assert(compareArrayBuffers(buffer, shared_buffer), + 'Readback mismatch between shared and non-shared buffers'); let view = new DataView(buffer); let rgb = null;
diff --git a/content/test/gpu/gpu_tests/common_browser_args.py b/content/test/gpu/gpu_tests/common_browser_args.py index 97d0b7f0..c8910c69 100644 --- a/content/test/gpu/gpu_tests/common_browser_args.py +++ b/content/test/gpu/gpu_tests/common_browser_args.py
@@ -25,8 +25,6 @@ '--enable-direct-composition-video-overlays' ENABLE_DIRECT_COMPOSITION_VP_SCALING = '--disable_vp_scaling=0' ENABLE_DXVA_VIDEO_DECODER = '--enable-features=DXVAVideoDecoding' -ENABLE_PLATFORM_HEVC_ENCODER_SUPPORT =\ - '--enable-features=PlatformHEVCEncoderSupport' ENABLE_EXPERIMENTAL_WEB_PLATFORM_FEATURES =\ '--enable-experimental-web-platform-features' ENABLE_GPU_BENCHMARKING = '--enable-gpu-benchmarking'
diff --git a/content/test/gpu/gpu_tests/webcodecs_integration_test.py b/content/test/gpu/gpu_tests/webcodecs_integration_test.py index 2571ed1..c8041bf 100644 --- a/content/test/gpu/gpu_tests/webcodecs_integration_test.py +++ b/content/test/gpu/gpu_tests/webcodecs_integration_test.py
@@ -322,7 +322,7 @@ '--use-fake-device-for-media-stream', '--use-fake-ui-for-media-stream', '--enable-blink-features=SharedArrayBuffer', - cba.ENABLE_PLATFORM_HEVC_ENCODER_SUPPORT, + '--enable-features=VideoFrameAsyncCopyTo', cba.ENABLE_EXPERIMENTAL_WEB_PLATFORM_FEATURES, ] + cba.ENABLE_WEBGPU_FOR_TESTING
diff --git a/device/gamepad/gamepad_platform_data_fetcher.h b/device/gamepad/gamepad_platform_data_fetcher.h index 2e32c0f..e1039f55 100644 --- a/device/gamepad/gamepad_platform_data_fetcher.h +++ b/device/gamepad/gamepad_platform_data_fetcher.h
@@ -43,7 +43,13 @@ #elif BUILDFLAG(IS_WIN) - manager->AddFactory(new WgiDataFetcherWin::Factory()); + // Windows.Gaming.Input is available in Windows 10.0.10240.0 and later. + if (base::FeatureList::IsEnabled( + features::kEnableWindowsGamingInputDataFetcher)) { + manager->AddFactory(new WgiDataFetcherWin::Factory()); + } else { + manager->AddFactory(new XInputDataFetcherWin::Factory()); + } manager->AddFactory(new NintendoDataFetcher::Factory()); manager->AddFactory(new RawInputDataFetcher::Factory());
diff --git a/device/gamepad/public/cpp/gamepad_features.cc b/device/gamepad/public/cpp/gamepad_features.cc index e725297..7aeb1a9f 100644 --- a/device/gamepad/public/cpp/gamepad_features.cc +++ b/device/gamepad/public/cpp/gamepad_features.cc
@@ -14,6 +14,15 @@ namespace features { +// Enables the Windows.Gaming.Input data fetcher. +// +// Note: This feature is used by the "never expire" flag +// chrome://flags/#enable-windows-gaming-input-data-fetcher and should not be +// removed. See crbug.com/40287784. +BASE_FEATURE(kEnableWindowsGamingInputDataFetcher, + "EnableWindowsGamingInputDataFetcher", + base::FEATURE_ENABLED_BY_DEFAULT); + // Enables gamepad multitouch BASE_FEATURE(kEnableGamepadMultitouch, "EnableGamepadMultitouch",
diff --git a/device/gamepad/public/cpp/gamepad_features.h b/device/gamepad/public/cpp/gamepad_features.h index e817ee80..4a5bb760 100644 --- a/device/gamepad/public/cpp/gamepad_features.h +++ b/device/gamepad/public/cpp/gamepad_features.h
@@ -10,6 +10,8 @@ namespace features { +GAMEPAD_FEATURES_EXPORT BASE_DECLARE_FEATURE( + kEnableWindowsGamingInputDataFetcher); GAMEPAD_FEATURES_EXPORT BASE_DECLARE_FEATURE(kEnableGamepadMultitouch); GAMEPAD_FEATURES_EXPORT bool IsGamepadMultitouchEnabled();
diff --git a/extensions/browser/api/webcam_private/visca_webcam.cc b/extensions/browser/api/webcam_private/visca_webcam.cc index ef66d74..99174b46 100644 --- a/extensions/browser/api/webcam_private/visca_webcam.cc +++ b/extensions/browser/api/webcam_private/visca_webcam.cc
@@ -2,11 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/351564777): Remove this and convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #include "extensions/browser/api/webcam_private/visca_webcam.h" #include <stddef.h>
diff --git a/extensions/browser/extension_registrar.cc b/extensions/browser/extension_registrar.cc index 1559ee2..286071d 100644 --- a/extensions/browser/extension_registrar.cc +++ b/extensions/browser/extension_registrar.cc
@@ -31,6 +31,7 @@ #include "extensions/browser/task_queue_util.h" #include "extensions/common/manifest.h" #include "extensions/common/manifest_handlers/background_info.h" +#include "extensions/common/manifest_handlers/shared_module_info.h" #include "extensions/common/permissions/permissions_data.h" #include "third_party/blink/public/common/service_worker/service_worker_status_code.h" @@ -347,6 +348,30 @@ DisableExtension(extension_id, disable_reasons); } +void ExtensionRegistrar::EnabledReloadableExtensions() { + std::vector<std::string> extensions_to_enable; + for (const auto& e : registry_->disabled_extensions()) { + if (extension_prefs_->GetDisableReasons(e->id()) == + disable_reason::DISABLE_RELOAD) { + extensions_to_enable.push_back(e->id()); + } + } + for (const std::string& extension : extensions_to_enable) { + EnableExtension(extension); + } +} + +void ExtensionRegistrar::RemoveComponentExtension( + const std::string& extension_id) { + scoped_refptr<const Extension> extension( + registry_->enabled_extensions().GetByID(extension_id)); + RemoveExtension(extension_id, UnloadedExtensionReason::UNINSTALL); + if (extension.get()) { + registry_->TriggerOnUninstalled(extension.get(), + UNINSTALL_REASON_COMPONENT_REMOVED); + } +} + void ExtensionRegistrar::RemoveDisableReasonAndMaybeEnable( const std::string& extension_id, disable_reason::DisableReason reason_to_remove) { @@ -543,6 +568,51 @@ return true; } +void ExtensionRegistrar::UninstallMigratedExtensions( + base::span<const char* const> migrated_ids) { + const ExtensionSet installed_extensions = + registry_->GenerateInstalledExtensionsSet(); + for (const auto* extension_id : migrated_ids) { + auto* extension = installed_extensions.GetByID(extension_id); + if (extension) { + UninstallExtension(extension_id, UNINSTALL_REASON_COMPONENT_REMOVED, + nullptr); + extension_prefs_->MarkObsoleteComponentExtensionAsRemoved( + extension->id(), extension->location()); + } + } +} + +void ExtensionRegistrar::FinishInstallation(const Extension* extension) { + const Extension* existing_extension = + registry_->GetInstalledExtension(extension->id()); + bool is_update = false; + std::string old_name; + if (existing_extension) { + is_update = true; + old_name = existing_extension->name(); + } + registry_->TriggerOnWillBeInstalled(extension, is_update, old_name); + + // Unpacked extensions default to allowing file access, but if that has been + // overridden, don't reset the value. + if (Manifest::ShouldAlwaysAllowFileAccess(extension->location()) && + !extension_prefs_->HasAllowFileAccessSetting(extension->id())) { + extension_prefs_->SetAllowFileAccess(extension->id(), true); + } + + AddExtension(extension); + + // Notify observers that need to know when an installation is complete. + registry_->TriggerOnInstalled(extension, is_update); + + // Check extensions that may have been delayed only because this shared module + // was not available. + if (SharedModuleInfo::IsSharedModule(extension)) { + delegate_->FinishDelayedInstallationsIfAny(); + } +} + bool ExtensionRegistrar::CanBlockExtension(const Extension* extension) const { DCHECK(extension); return extension->location() != ManifestLocation::kComponent &&
diff --git a/extensions/browser/extension_registrar.h b/extensions/browser/extension_registrar.h index 0960ab6..ce6bf41e 100644 --- a/extensions/browser/extension_registrar.h +++ b/extensions/browser/extension_registrar.h
@@ -7,6 +7,7 @@ #include <memory> +#include "base/containers/span.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" @@ -104,6 +105,10 @@ virtual void ShowExtensionDisabledError(const Extension* extension, bool is_remote_install) = 0; + // Finishes the deplayed installations if there are any delayed + // extensions ready to be installed. + virtual void FinishDelayedInstallationsIfAny() = 0; + // Returns true if |extension| can be added. virtual bool CanAddExtension(const Extension* extension) = 0; @@ -139,7 +144,7 @@ // Note: Extensions will not be removed from other sets (blocklisted or // blocked). ExtensionService handles that, since it also adds it to those // sets. TODO(michaelpg): Make ExtensionRegistrar the sole mutator of - // ExtensionRegsitry to simplify this usage. + // ExtensionRegistry to simplify this usage. void RemoveExtension(const ExtensionId& extension_id, UnloadedExtensionReason reason); @@ -161,6 +166,13 @@ const std::string& extension_id, disable_reason::DisableReason disable_reasons); + // Attempts to enable all disabled extensions which the only disabled reason + // is reloading. + void EnabledReloadableExtensions(); + + // Removes the specified component extension. + void RemoveComponentExtension(const std::string& extension_id); + // Removes the disable reason and enable the extension if there are no disable // reasons left and is not blocked for another reason. void RemoveDisableReasonAndMaybeEnable(const std::string& extension_id, @@ -192,6 +204,12 @@ std::u16string* error, base::OnceClosure done_callback = base::NullCallback()); + // Uninstalls extensions that have been migrated to component extensions. + void UninstallMigratedExtensions(base::span<const char* const> migrated_ids); + + // Finishes installing |extension| and notifying the observers. + void FinishInstallation(const Extension* extension); + // TODO(michaelpg): Add methods for blocklisting and blocking extensions. // Helper method to determine if an extension can be blocked.
diff --git a/extensions/browser/extension_registrar_unittest.cc b/extensions/browser/extension_registrar_unittest.cc index dfd7d09..151dcb86 100644 --- a/extensions/browser/extension_registrar_unittest.cc +++ b/extensions/browser/extension_registrar_unittest.cc
@@ -85,6 +85,7 @@ const base::FilePath& path, LoadErrorBehavior load_error_behavior)); MOCK_METHOD2(ShowExtensionDisabledError, void(const Extension*, bool)); + MOCK_METHOD0(FinishDelayedInstallationsIfAny, void()); MOCK_METHOD1(CanEnableExtension, bool(const Extension* extension)); MOCK_METHOD1(CanDisableExtension, bool(const Extension* extension)); MOCK_METHOD1(ShouldBlockExtension, bool(const Extension* extension));
diff --git a/extensions/common/file_util.cc b/extensions/common/file_util.cc index 7d98410..f677967 100644 --- a/extensions/common/file_util.cc +++ b/extensions/common/file_util.cc
@@ -601,4 +601,17 @@ extension_path.Append(GetIndexedRulesetDirectoryRelativePath())}; } +void MaybeCleanupMetadataFolder(const base::FilePath& extension_path) { + const std::vector<base::FilePath> reserved_filepaths = + GetReservedMetadataFilePaths(extension_path); + for (const auto& file : reserved_filepaths) { + base::DeletePathRecursively(file); + } + + const base::FilePath& metadata_dir = extension_path.Append(kMetadataFolder); + if (base::IsDirectoryEmpty(metadata_dir)) { + base::DeletePathRecursively(metadata_dir); + } +} + } // namespace extensions::file_util
diff --git a/extensions/common/file_util.h b/extensions/common/file_util.h index 713efeb..fd36e007 100644 --- a/extensions/common/file_util.h +++ b/extensions/common/file_util.h
@@ -177,6 +177,10 @@ std::vector<base::FilePath> GetReservedMetadataFilePaths( const base::FilePath& extension_path); +// Deletes files reserved for use by the Extension system in the kMetadataFolder +// and the kMetadataFolder itself if it is empty. +void MaybeCleanupMetadataFolder(const base::FilePath& extension_path); + } // namespace file_util } // namespace extensions
diff --git a/extensions/shell/browser/shell_extension_loader.cc b/extensions/shell/browser/shell_extension_loader.cc index 6d212b2..887447a 100644 --- a/extensions/shell/browser/shell_extension_loader.cc +++ b/extensions/shell/browser/shell_extension_loader.cc
@@ -175,6 +175,8 @@ const Extension* extension, bool is_remote_install) {} +void ShellExtensionLoader::FinishDelayedInstallationsIfAny() {} + bool ShellExtensionLoader::CanEnableExtension(const Extension* extension) { return true; }
diff --git a/extensions/shell/browser/shell_extension_loader.h b/extensions/shell/browser/shell_extension_loader.h index 3c3a70b..665420e 100644 --- a/extensions/shell/browser/shell_extension_loader.h +++ b/extensions/shell/browser/shell_extension_loader.h
@@ -69,6 +69,7 @@ ExtensionRegistrar::LoadErrorBehavior load_error_behavior) override; void ShowExtensionDisabledError(const Extension* extension, bool is_remote_install) override; + void FinishDelayedInstallationsIfAny() override; bool CanEnableExtension(const Extension* extension) override; bool CanDisableExtension(const Extension* extension) override; bool ShouldBlockExtension(const Extension* extension) override;
diff --git a/gpu/command_buffer/client/query_tracker.h b/gpu/command_buffer/client/query_tracker.h index fc0090e1..b31e5d87 100644 --- a/gpu/command_buffer/client/query_tracker.h +++ b/gpu/command_buffer/client/query_tracker.h
@@ -18,6 +18,7 @@ #include "base/atomicops.h" #include "base/containers/circular_deque.h" #include "base/containers/flat_map.h" +#include "base/functional/callback.h" #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "gles2_impl_export.h"
diff --git a/gpu/command_buffer/client/shared_image_pool.h b/gpu/command_buffer/client/shared_image_pool.h index d43207a..8180021 100644 --- a/gpu/command_buffer/client/shared_image_pool.h +++ b/gpu/command_buffer/client/shared_image_pool.h
@@ -197,8 +197,13 @@ std::move(unused_resource_expiration_time))); } - // Clears the pool, deleting all contained images. - ~SharedImagePool() override = default; + // Clears the pool, deleting all contained images. Also sends an IPC to + // destroy the corresponding service side pool. + ~SharedImagePool() override { + if (sii_) { + sii_->DestroySharedImagePool(pool_id_); + } + } // Retrieves an image from the pool or creates a new one if the pool is empty. scoped_refptr<ClientImageType> GetImage() { @@ -260,9 +265,20 @@ std::optional<base::TimeDelta> unused_resource_expiration_time) : SharedImagePoolBase(SharedImagePoolId::Create(), image_info, - std::move(sii), + sii, std::move(max_pool_size), - std::move(unused_resource_expiration_time)) {} + std::move(unused_resource_expiration_time)) { + mojo::PendingReceiver<gpu::mojom::SharedImagePoolClientInterface> + client_receiver; + auto client_remote = client_receiver.InitWithNewPipeAndPassRemote(); + receiver_.Bind(std::move(client_receiver)); + receiver_.set_disconnect_handler(base::BindOnce( + &SharedImagePool::OnDisconnectedSharedImagePoolClientInterface, + base::Unretained(this))); + sii->CreateSharedImagePool(pool_id_, std::move(client_remote)); + } + + void OnDisconnectedSharedImagePoolClientInterface() { ClearInternal(); } mojo::Receiver<mojom::SharedImagePoolClientInterface> receiver_{this};
diff --git a/gpu/command_buffer/client/test_shared_image_interface.h b/gpu/command_buffer/client/test_shared_image_interface.h index 1e9a877..44219d4 100644 --- a/gpu/command_buffer/client/test_shared_image_interface.h +++ b/gpu/command_buffer/client/test_shared_image_interface.h
@@ -7,6 +7,7 @@ #include <memory> +#include "base/containers/flat_map.h" #include "base/containers/flat_set.h" #include "base/synchronization/lock.h" #include "build/build_config.h" @@ -15,6 +16,8 @@ #include "gpu/command_buffer/common/shared_image_capabilities.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/ipc/client/shared_image_interface_proxy.h" +#include "gpu/ipc/common/shared_image_pool_client_interface.mojom.h" +#include "mojo/public/cpp/bindings/remote.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -106,8 +109,23 @@ void CreateSharedImagePool( const SharedImagePoolId& pool_id, mojo::PendingRemote<mojom::SharedImagePoolClientInterface> client_remote) - override {} - void DestroySharedImagePool(const SharedImagePoolId& pool_id) override {} + override { + auto it = remote_map_.find(pool_id); + CHECK(it == remote_map_.end()); + + mojo::Remote<mojom::SharedImagePoolClientInterface> remote; + remote.Bind(std::move(client_remote)); + remote_map_.emplace(pool_id, std::move(remote)); + } + + void DestroySharedImagePool(const SharedImagePoolId& pool_id) override { + auto it = remote_map_.find(pool_id); + if (it != remote_map_.end()) { + // Disconnect the remote and remove the entry. + it->second.reset(); + remote_map_.erase(it); + } + } size_t shared_image_count() const { return shared_images_.size(); } const gfx::Size& MostRecentSize() const { return most_recent_size_; } @@ -168,6 +186,13 @@ // If non-null, this will be used to back mappable SharedImages with test // GpuMemoryBuffers. std::unique_ptr<TestGpuMemoryBufferManager> test_gmb_manager_; + + // This is used to simply keep the SharedImagePoolClientInterface alive for + // the duration of the SharedImagePool. Not keeping it alive and bound + // triggers diconnect_handlers causing unexpected behaviour in the test. + base::flat_map<SharedImagePoolId, + mojo::Remote<mojom::SharedImagePoolClientInterface>> + remote_map_; }; } // namespace gpu
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h index a393b1972b..13f6648b 100644 --- a/gpu/command_buffer/common/gles2_cmd_format.h +++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -14,7 +14,6 @@ #include "base/atomicops.h" #include "base/check_op.h" #include "base/rand_util.h" -#include "base/trace_event/trace_event.h" #include "gpu/command_buffer/common/cmd_buffer_common.h" #include "gpu/command_buffer/common/common_cmd_format.h" #include "gpu/command_buffer/common/constants.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc index 6cb728ca..309cf1d 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -19,6 +19,7 @@ #include "base/memory/raw_ptr.h" #include "base/ranges/algorithm.h" #include "base/strings/string_split.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "gpu/command_buffer/service/command_buffer_service.h" #include "gpu/command_buffer/service/decoder_client.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc index 18699a3..243ca357 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -19,6 +19,7 @@ #include "base/numerics/checked_math.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "components/viz/common/resources/shared_image_format_utils.h" #include "gpu/command_buffer/common/discardable_handle.h"
diff --git a/gpu/command_buffer/service/service_utils.cc b/gpu/command_buffer/service/service_utils.cc index 13fce38..d653f60 100644 --- a/gpu/command_buffer/service/service_utils.cc +++ b/gpu/command_buffer/service/service_utils.cc
@@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" +#include "base/strings/string_util.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h"
diff --git a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc index cd75cc9..41fead8 100644 --- a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc +++ b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc
@@ -18,6 +18,7 @@ #include "gpu/vulkan/vulkan_image.h" #include "gpu/vulkan/vulkan_implementation.h" #include "gpu/vulkan/vulkan_util.h" +#include "third_party/abseil-cpp/absl/cleanup/cleanup.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkColorSpace.h" #include "third_party/skia/include/gpu/MutableTextureState.h" @@ -701,6 +702,31 @@ return true; } +bool AngleVulkanImageBacking::ReadbackToMemory( + const std::vector<SkPixmap>& pixmaps) { + if (!BeginAccessSkia(/*read_only=*/true)) { + return false; + } + + absl::Cleanup cleanup = [&]() { EndAccessSkia(); }; + + CHECK_EQ(pixmaps.size(), vk_textures_.size()); + for (int i = 0; i < format().NumberOfPlanes(); i++) { + const auto color_type = viz::ToClosestSkColorType(format(), i); + const gfx::Size plane_size = format().GetPlaneSize(i, size()); + + CHECK_EQ(color_type, pixmaps[i].colorType()); + CHECK_EQ(plane_size.width(), pixmaps[i].width()); + CHECK_EQ(plane_size.height(), pixmaps[i].height()); + + if (!vk_textures_[i].Readback(gr_context(), pixmaps[i])) { + return false; + } + } + + return true; +} + AngleVulkanImageBacking::TextureHolderGL::TextureHolderGL() = default; AngleVulkanImageBacking::TextureHolderGL::TextureHolderGL( TextureHolderGL&& other) = default;
diff --git a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.h b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.h index 90faeaa8..f18c6e6 100644 --- a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.h +++ b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.h
@@ -38,6 +38,7 @@ // SharedImageBacking implementation. SharedImageBackingType GetType() const override; bool UploadFromMemory(const std::vector<SkPixmap>& pixmaps) override; + bool ReadbackToMemory(const std::vector<SkPixmap>& pixmaps) override; void Update(std::unique_ptr<gfx::GpuFence> in_fence) override; std::unique_ptr<GLTexturePassthroughImageRepresentation> ProduceGLTexturePassthrough(SharedImageManager* manager,
diff --git a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing_factory_unittest.cc index be82739..a24885d 100644 --- a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing_factory_unittest.cc
@@ -6,6 +6,7 @@ #include "base/no_destructor.h" #include "base/test/scoped_feature_list.h" +#include "cc/test/pixel_test_utils.h" #include "components/viz/common/resources/shared_image_format.h" #include "gpu/command_buffer/common/mailbox.h" #include "gpu/command_buffer/common/shared_image_usage.h" @@ -182,6 +183,54 @@ VerifyPixelsWithReadbackGanesh(mailbox, bitmaps); } +TEST_P(AngleVulkanImageBackingFactoryTest, ReadbackToMemory) { + viz::SharedImageFormat format = GetFormat(); + + auto mailbox = Mailbox::Generate(); + gfx::Size size(9, 9); + auto color_space = gfx::ColorSpace::CreateSRGB(); + GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin; + SkAlphaType alpha_type = kPremul_SkAlphaType; + gpu::SharedImageUsageSet usage = kUsage; + gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle; + + bool supported = backing_factory_->CanCreateSharedImage( + usage, format, size, /*thread_safe=*/false, gfx::EMPTY_BUFFER, + GrContextType::kVulkan, {}); + ASSERT_TRUE(supported); + + auto backing = backing_factory_->CreateSharedImage( + mailbox, format, surface_handle, size, color_space, surface_origin, + alpha_type, usage, "TestLabel", /*is_thread_safe=*/false); + ASSERT_TRUE(backing); + + std::vector<SkBitmap> src_bitmaps = + AllocateRedBitmaps(format, size, /*added_stride=*/0); + + // Upload from bitmap with expected stride. + ASSERT_TRUE(backing->UploadFromMemory(GetSkPixmaps(src_bitmaps))); + + const int num_planes = format.NumberOfPlanes(); + + // Do readback into bitmap with same stride and validate pixels match what + // was uploaded. + std::vector<SkBitmap> readback_bitmaps(num_planes); + for (int plane = 0; plane < num_planes; ++plane) { + auto& info = src_bitmaps[plane].info(); + size_t stride = info.minRowBytes(); + readback_bitmaps[plane].allocPixels(info, stride); + } + + std::vector<SkPixmap> pixmaps = GetSkPixmaps(readback_bitmaps); + ASSERT_TRUE(backing->ReadbackToMemory(pixmaps)); + + for (int plane = 0; plane < num_planes; ++plane) { + EXPECT_TRUE(cc::MatchesBitmap(readback_bitmaps[plane], src_bitmaps[plane], + cc::ExactPixelComparator())) + << "plane_index=" << plane; + } +} + std::string TestParamToString( const testing::TestParamInfo<viz::SharedImageFormat>& param_info) { return param_info.param.ToTestParamString();
diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing.cc b/gpu/command_buffer/service/shared_image/d3d_image_backing.cc index 9f349418..902e4901 100644 --- a/gpu/command_buffer/service/shared_image/d3d_image_backing.cc +++ b/gpu/command_buffer/service/shared_image/d3d_image_backing.cc
@@ -25,6 +25,7 @@ #include "base/memory/raw_ptr.h" #include "base/strings/strcat.h" #include "base/synchronization/waitable_event.h" +#include "base/trace_event/trace_event.h" #include "gpu/command_buffer/common/shared_image_trace_utils.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/command_buffer/service/dxgi_shared_handle_manager.h"
diff --git a/gpu/command_buffer/service/shared_image/egl_image_backing_factory.cc b/gpu/command_buffer/service/shared_image/egl_image_backing_factory.cc index 5f43307..076eedb 100644 --- a/gpu/command_buffer/service/shared_image/egl_image_backing_factory.cc +++ b/gpu/command_buffer/service/shared_image/egl_image_backing_factory.cc
@@ -116,7 +116,9 @@ if ((usage.HasAny(SHARED_IMAGE_USAGE_WEBGPU_READ | SHARED_IMAGE_USAGE_WEBGPU_WRITE)) && - (use_webgpu_adapter_ != WebGPUAdapterName::kOpenGLES)) { + (gr_context_type != GrContextType::kGL || + gl::GetGLImplementation() != gl::kGLImplementationEGLANGLE || + gl::GetANGLEImplementation() != gl::ANGLEImplementation::kOpenGL)) { return false; }
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc b/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc index cda93bb..dce70da 100644 --- a/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc +++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
@@ -1274,6 +1274,60 @@ return success; } +bool ExternalVkImageBacking::ReadbackToMemory( + const std::vector<SkPixmap>& pixmaps) { + DCHECK_EQ(pixmaps.size(), vk_textures_.size()); + + std::vector<ExternalSemaphore> external_semaphores; + if (!BeginAccess(/*readonly=*/true, &external_semaphores, /*is_gl=*/false)) { + DLOG(ERROR) << "BeginAccess() failed."; + return false; + } + auto* gr_context = context_state_->gr_context(); + WaitSemaphoresOnGrContext(gr_context, &external_semaphores); + + bool success = true; + for (size_t plane = 0; plane < vk_textures_.size(); ++plane) { + if (!vk_textures_[plane].Readback(gr_context, pixmaps[plane])) { + success = false; + } + } + + if (!need_synchronization()) { + DCHECK(external_semaphores.empty()); + EndAccess(/*readonly=*/true, ExternalSemaphore(), /*is_gl=*/false); + return success; + } + + for (auto& vk_texture : vk_textures_) { + gr_context->setBackendTextureState( + vk_texture.backend_texture, + skgpu::MutableTextureStates::MakeVulkan(VK_IMAGE_LAYOUT_UNDEFINED, + VK_QUEUE_FAMILY_EXTERNAL)); + } + + auto end_access_semaphore = external_semaphore_pool()->GetOrCreateSemaphore(); + VkSemaphore vk_end_access_semaphore = end_access_semaphore.GetVkSemaphore(); + GrBackendSemaphore end_access_backend_semaphore = + GrBackendSemaphores::MakeVk(vk_end_access_semaphore); + GrFlushInfo flush_info = { + .fNumSemaphores = 1, + .fSignalSemaphores = &end_access_backend_semaphore, + }; + gr_context->flush(flush_info); + + // Submit so the |end_access_semaphore| is ready for waiting. + gr_context->submit(); + + EndAccess(/*readonly=*/true, std::move(end_access_semaphore), + /*is_gl=*/false); + + // |external_semaphores| have been waited on and can be reused when submitted + // GPU work is done. + ReturnPendingSemaphoresWithFenceHelper(std::move(external_semaphores)); + return success; +} + bool ExternalVkImageBacking::UploadToGLTexture( const std::vector<SkPixmap>& pixmaps) { DCHECK(use_separate_gl_texture());
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing.h b/gpu/command_buffer/service/shared_image/external_vk_image_backing.h index 0894bde..c2b27fd 100644 --- a/gpu/command_buffer/service/shared_image/external_vk_image_backing.h +++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing.h
@@ -161,6 +161,7 @@ SharedImageBackingType GetType() const override; void Update(std::unique_ptr<gfx::GpuFence> in_fence) override; bool UploadFromMemory(const std::vector<SkPixmap>& pixmaps) override; + bool ReadbackToMemory(const std::vector<SkPixmap>& pixmaps) override; scoped_refptr<gfx::NativePixmap> GetNativePixmap() override; gfx::GpuMemoryBufferHandle GetGpuMemoryBufferHandle() override;
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc index 31cb18a8..792fef4 100644 --- a/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory_unittest.cc
@@ -15,6 +15,7 @@ #include "base/functional/callback_helpers.h" #include "base/ranges/algorithm.h" #include "build/build_config.h" +#include "cc/test/pixel_test_utils.h" #include "components/viz/common/gpu/vulkan_in_process_context_provider.h" #include "components/viz/common/resources/shared_image_format.h" #include "gpu/command_buffer/service/service_utils.h" @@ -530,6 +531,54 @@ VerifyPixelsWithReadbackGanesh(mailbox, bitmaps); } +TEST_P(ExternalVkImageBackingFactoryWithFormatTest, ReadbackToMemory) { + viz::SharedImageFormat format = get_format(); + + auto mailbox = Mailbox::Generate(); + gfx::Size size(9, 9); + auto color_space = gfx::ColorSpace::CreateSRGB(); + GrSurfaceOrigin surface_origin = kTopLeft_GrSurfaceOrigin; + SkAlphaType alpha_type = kPremul_SkAlphaType; + gpu::SharedImageUsageSet usage = + SHARED_IMAGE_USAGE_DISPLAY_READ | SHARED_IMAGE_USAGE_CPU_UPLOAD; + gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle; + + bool supported = backing_factory_->CanCreateSharedImage( + usage, format, size, /*thread_safe=*/false, gfx::EMPTY_BUFFER, + GrContextType::kVulkan, {}); + ASSERT_TRUE(supported); + + auto backing = backing_factory_->CreateSharedImage( + mailbox, format, surface_handle, size, color_space, surface_origin, + alpha_type, usage, "TestLabel", /*is_thread_safe=*/false); + ASSERT_TRUE(backing); + + std::vector<SkBitmap> src_bitmaps = + AllocateRedBitmaps(format, size, /*added_stride=*/0); + + // Upload from bitmap with expected stride. + ASSERT_TRUE(backing->UploadFromMemory(GetSkPixmaps(src_bitmaps))); + + const int num_planes = format.NumberOfPlanes(); + // Do readback into bitmap with same stride and validate pixels match what + // was uploaded. + std::vector<SkBitmap> readback_bitmaps(num_planes); + for (int plane = 0; plane < num_planes; ++plane) { + auto& info = src_bitmaps[plane].info(); + size_t stride = info.minRowBytes(); + readback_bitmaps[plane].allocPixels(info, stride); + } + + std::vector<SkPixmap> pixmaps = GetSkPixmaps(readback_bitmaps); + ASSERT_TRUE(backing->ReadbackToMemory(pixmaps)); + + for (int plane = 0; plane < num_planes; ++plane) { + EXPECT_TRUE(cc::MatchesBitmap(readback_bitmaps[plane], src_bitmaps[plane], + cc::ExactPixelComparator())) + << "plane_index=" << plane; + } +} + std::string TestParamToString( const testing::TestParamInfo<viz::SharedImageFormat>& param_info) { return param_info.param.ToTestParamString();
diff --git a/gpu/command_buffer/service/shared_image/shared_image_factory.cc b/gpu/command_buffer/service/shared_image/shared_image_factory.cc index e33b70e3e..b138a07 100644 --- a/gpu/command_buffer/service/shared_image/shared_image_factory.cc +++ b/gpu/command_buffer/service/shared_image/shared_image_factory.cc
@@ -730,6 +730,26 @@ return true; } +bool SharedImageFactory::CreateSharedImagePool( + const SharedImagePoolId& pool_id, + mojo::PendingRemote<mojom::SharedImagePoolClientInterface> client_remote) { + auto it = shared_image_pool_map_.find(pool_id); + // Ensure that there is no pool already corresponding to the |pool_id|. + if (it != shared_image_pool_map_.end()) { + return false; + } + auto pool = std::make_unique<SharedImagePoolService>( + pool_id, std::move(client_remote), this); + shared_image_pool_map_.emplace(pool_id, std::move(pool)); + return true; +} + +bool SharedImageFactory::DestroySharedImagePool( + const SharedImagePoolId& pool_id) { + // Ensure that there is a pool corresponding to the |pool_id|. + return shared_image_pool_map_.erase(pool_id); +} + void SharedImageFactory::RegisterSharedImageBackingFactoryForTesting( SharedImageBackingFactory* factory) { backing_factory_for_testing_ = factory;
diff --git a/gpu/command_buffer/service/shared_image/shared_image_factory.h b/gpu/command_buffer/service/shared_image/shared_image_factory.h index c66367d7..e3097afb 100644 --- a/gpu/command_buffer/service/shared_image/shared_image_factory.h +++ b/gpu/command_buffer/service/shared_image/shared_image_factory.h
@@ -10,6 +10,7 @@ #include <unordered_set> #include <vector> +#include "base/containers/flat_map.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "build/build_config.h" @@ -18,10 +19,12 @@ #include "gpu/command_buffer/common/shared_image_capabilities.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/command_buffer/service/shared_image/shared_image_manager.h" +#include "gpu/command_buffer/service/shared_image/shared_image_pool_service.h" #include "gpu/config/gpu_driver_bug_workarounds.h" #include "gpu/config/gpu_preferences.h" #include "gpu/gpu_gles2_export.h" #include "gpu/ipc/common/gpu_memory_buffer_support.h" +#include "gpu/ipc/common/shared_image_pool_client_interface.mojom.h" #include "gpu/ipc/common/surface_handle.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/gpu_extra_info.h" @@ -141,6 +144,11 @@ gfx::Size& size, gfx::BufferUsage& buffer_usage); + bool CreateSharedImagePool( + const SharedImagePoolId& pool_id, + mojo::PendingRemote<mojom::SharedImagePoolClientInterface> client_remote); + bool DestroySharedImagePool(const SharedImagePoolId& pool_id); + void RegisterSharedImageBackingFactoryForTesting( SharedImageBackingFactory* factory); @@ -203,6 +211,11 @@ SharedImageRepresentationFactoryRefKeyEqual> shared_images_; + // Map of all the SharedImagePoolService objects corresponding to its unique + // pool id. + base::flat_map<SharedImagePoolId, std::unique_ptr<SharedImagePoolService>> + shared_image_pool_map_; + // Array of all the backing factories to choose from for creating shared // images. std::vector<std::unique_ptr<SharedImageBackingFactory>> factories_;
diff --git a/gpu/command_buffer/service/shared_image/texture_holder_vk.cc b/gpu/command_buffer/service/shared_image/texture_holder_vk.cc index 43c52d0..6157b7c 100644 --- a/gpu/command_buffer/service/shared_image/texture_holder_vk.cc +++ b/gpu/command_buffer/service/shared_image/texture_holder_vk.cc
@@ -7,6 +7,9 @@ #include "base/check.h" #include "gpu/command_buffer/service/skia_utils.h" #include "gpu/vulkan/vulkan_image.h" +#include "third_party/skia/include/core/SkColorSpace.h" +#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h" +#include "third_party/skia/include/gpu/ganesh/SkImageGanesh.h" #include "third_party/skia/include/gpu/ganesh/vk/GrVkBackendSurface.h" namespace gpu { @@ -34,4 +37,18 @@ return info; } +bool TextureHolderVk::Readback(GrDirectContext* context, + const SkPixmap& destination) { + CHECK(context); + auto sk_image = SkImages::BorrowTextureFrom( + context, backend_texture, kTopLeft_GrSurfaceOrigin, + destination.colorType(), SkAlphaType::kOpaque_SkAlphaType, + /*sk_color_space=*/nullptr); + if (!sk_image) { + return false; + } + + return sk_image->readPixels(context, destination, 0, 0); +} + } // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image/texture_holder_vk.h b/gpu/command_buffer/service/shared_image/texture_holder_vk.h index c38a3d59..0bfc8aa 100644 --- a/gpu/command_buffer/service/shared_image/texture_holder_vk.h +++ b/gpu/command_buffer/service/shared_image/texture_holder_vk.h
@@ -7,10 +7,13 @@ #include <memory> +#include "third_party/skia/include/core/SkPixmap.h" #include "third_party/skia/include/gpu/ganesh/GrBackendSurface.h" #include "third_party/skia/include/gpu/ganesh/vk/GrVkTypes.h" #include "third_party/skia/include/private/chromium/GrPromiseImageTexture.h" +class GrDirectContext; + namespace gfx { class ColorSpace; } // namespace gfx @@ -34,6 +37,8 @@ GrVkImageInfo GetGrVkImageInfo() const; + bool Readback(GrDirectContext* context, const SkPixmap& destination); + std::unique_ptr<VulkanImage> vulkan_image; GrBackendTexture backend_texture; sk_sp<GrPromiseImageTexture> promise_texture;
diff --git a/gpu/ipc/service/image_transport_surface_overlay_mac.mm b/gpu/ipc/service/image_transport_surface_overlay_mac.mm index 08f7955..6bff6b1 100644 --- a/gpu/ipc/service/image_transport_surface_overlay_mac.mm +++ b/gpu/ipc/service/image_transport_surface_overlay_mac.mm
@@ -52,6 +52,10 @@ "NewPresentationFeedbackTimeStamps", base::FEATURE_ENABLED_BY_DEFAULT); +BASE_FEATURE(kPresentationDelayForInteractiveFrames, + "PresentationDelayForInteractiveFrames", + base::FEATURE_ENABLED_BY_DEFAULT); + // Record the delay from the system CVDisplayLink or CADisplaylink source to // CrGpuMain OnVSyncPresentation(). void RecordVSyncCallbackDelay(base::TimeDelta delay) { @@ -162,6 +166,12 @@ bool delay_presenetation_until_next_vsync = features::IsVSyncAlignedPresentEnabled(); + if (base::FeatureList::IsEnabled(kPresentationDelayForInteractiveFrames) && + !ca_layer_tree_coordinator_->NumPendingSwaps() && + !data.is_handling_interaction_or_animation) { + delay_presenetation_until_next_vsync = false; + } + if (vsync_callback_mac_) { vsync_callback_mac_keep_alive_counter_ = kMaxKeepAliveCounter; if (delay_presenetation_until_next_vsync) { @@ -260,8 +270,8 @@ void ImageTransportSurfaceOverlayMacEGL::SetMaxPendingSwaps( int max_pending_swaps) { #if BUILDFLAG(IS_MAC) - cap_max_pending_swaps_ = - std::min(max_pending_swaps, features::NumPendingFrameSupported()); + cap_max_pending_swaps_ = max_pending_swaps; + // MaxCALayerTrees is equal to the number of max_pending_swaps + one // that has been displayed. ca_layer_tree_coordinator_->SetMaxCALayerTrees(cap_max_pending_swaps_ + 1);
diff --git a/gpu/ipc/service/shared_image_stub.cc b/gpu/ipc/service/shared_image_stub.cc index 76ffd5e..91caf7f 100644 --- a/gpu/ipc/service/shared_image_stub.cc +++ b/gpu/ipc/service/shared_image_stub.cc
@@ -151,13 +151,13 @@ } case mojom::DeferredSharedImageRequest::Tag::kCreateSharedImagePool: - // Future CLs will add implementation. - NOTIMPLEMENTED(); + OnCreateSharedImagePool( + std::move(request->get_create_shared_image_pool())); break; case mojom::DeferredSharedImageRequest::Tag::kDestroySharedImagePool: - // Future CLs will add implementation. - NOTIMPLEMENTED(); + OnDestroySharedImagePool( + std::move(request->get_destroy_shared_image_pool())); break; #if BUILDFLAG(IS_WIN) @@ -291,6 +291,31 @@ } } +void SharedImageStub::OnCreateSharedImagePool( + mojom::CreateSharedImagePoolParamsPtr params) { + TRACE_EVENT1("gpu", "SharedImageStub::OnCreateSharedImagePool", "pool_id", + params->pool_id.ToString()); + + if (!factory_->CreateSharedImagePool(params->pool_id, + std::move(params->client_remote))) { + LOG(ERROR) << "Unable to create SharedImagePool."; + OnError(); + return; + } +} + +void SharedImageStub::OnDestroySharedImagePool( + mojom::DestroySharedImagePoolParamsPtr params) { + TRACE_EVENT1("gpu", "SharedImageStub::OnDestroySharedImagePool", "pool_id", + params->pool_id.ToString()); + + if (!factory_->DestroySharedImagePool(params->pool_id)) { + LOG(ERROR) << "Unable to destroy SharedImagePool."; + OnError(); + return; + } +} + void SharedImageStub::OnCreateSharedImageWithData( mojom::CreateSharedImageWithDataParamsPtr params) { TRACE_EVENT2("gpu", "SharedImageStub::OnCreateSharedImageWithData", "width",
diff --git a/gpu/ipc/service/shared_image_stub.h b/gpu/ipc/service/shared_image_stub.h index ac10b9d..6b0e287 100644 --- a/gpu/ipc/service/shared_image_stub.h +++ b/gpu/ipc/service/shared_image_stub.h
@@ -130,6 +130,9 @@ gfx::DXGIHandleToken dxgi_token); #endif // BUILDFLAG(IS_WIN) + void OnCreateSharedImagePool(mojom::CreateSharedImagePoolParamsPtr params); + void OnDestroySharedImagePool(mojom::DestroySharedImagePoolParamsPtr params); + ContextResult Initialize(); void OnError();
diff --git a/infra/config/generated/builder-owners/chrome-sanitizer-builder-owners@google.com.txt b/infra/config/generated/builder-owners/chrome-sanitizer-builder-owners@google.com.txt index cb372159..06f3371e 100644 --- a/infra/config/generated/builder-owners/chrome-sanitizer-builder-owners@google.com.txt +++ b/infra/config/generated/builder-owners/chrome-sanitizer-builder-owners@google.com.txt
@@ -28,7 +28,6 @@ ci/WebKit Linux MSAN ci/Win ASan Release ci/Win ASan Release Media -ci/android-asan ci/chromeos-amd64-generic-asan-rel ci/ios-asan ci/win-asan
diff --git a/infra/config/generated/builders/ci/android-10-x86-fyi-rel/targets/chromium.android.fyi.json b/infra/config/generated/builders/ci/android-10-x86-fyi-rel/targets/chromium.android.fyi.json index 68bfe4b..3ed70b5 100644 --- a/infra/config/generated/builders/ci/android-10-x86-fyi-rel/targets/chromium.android.fyi.json +++ b/infra/config/generated/builders/ci/android-10-x86-fyi-rel/targets/chromium.android.fyi.json
@@ -1017,6 +1017,7 @@ "args": [ "--use-persistent-shell", "--avd-config=../../tools/android/avd/proto/android_29_google_apis_x86.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_10.content_unittests.filter", "--gs-results-bucket=chromium-result-details", "--recover-devices" ], @@ -2244,6 +2245,7 @@ "args": [ "--use-persistent-shell", "--avd-config=../../tools/android/avd/proto/android_29_google_apis_x86.textpb", + "--gtest_filter=-ScopedDirTest.CloseOutOfScope", "--gs-results-bucket=chromium-result-details", "--recover-devices" ], @@ -2574,6 +2576,7 @@ "args": [ "--use-persistent-shell", "--avd-config=../../tools/android/avd/proto/android_29_google_apis_x86.textpb", + "--gtest_filter=-org.chromium.webview_shell.test.WebViewLayoutTest.*", "--gs-results-bucket=chromium-result-details", "--recover-devices" ], @@ -3863,7 +3866,8 @@ "args": [ "--extra-browser-args=--enable-crashpad", "--use-persistent-shell", - "--avd-config=../../tools/android/avd/proto/android_29_google_apis_x86.textpb" + "--avd-config=../../tools/android/avd/proto/android_29_google_apis_x86.textpb", + "--browser=android-chromium" ], "isolate_profile_data": true, "merge": {
diff --git a/infra/config/generated/builders/ci/android-asan/gn-args.json b/infra/config/generated/builders/ci/android-asan/gn-args.json deleted file mode 100644 index df5c21d..0000000 --- a/infra/config/generated/builders/ci/android-asan/gn-args.json +++ /dev/null
@@ -1,18 +0,0 @@ -{ - "gn_args": { - "dcheck_always_on": false, - "debuggable_apks": false, - "ffmpeg_branding": "Chrome", - "is_asan": true, - "is_clang": true, - "is_component_build": false, - "is_debug": false, - "proprietary_codecs": true, - "strip_debug_info": true, - "symbol_level": 1, - "target_cpu": "arm", - "target_os": "android", - "use_remoteexec": true, - "use_siso": true - } -} \ No newline at end of file
diff --git a/infra/config/generated/builders/ci/android-asan/properties.json b/infra/config/generated/builders/ci/android-asan/properties.json deleted file mode 100644 index 25f9b5a..0000000 --- a/infra/config/generated/builders/ci/android-asan/properties.json +++ /dev/null
@@ -1,76 +0,0 @@ -{ - "$build/chromium_tests_builder_config": { - "builder_config": { - "additional_exclusions": [ - "infra/config/generated/builders/ci/android-asan/gn-args.json" - ], - "builder_db": { - "entries": [ - { - "builder_id": { - "bucket": "ci", - "builder": "android-asan", - "project": "chromium" - }, - "builder_spec": { - "build_gs_bucket": "chromium-memory-archive", - "builder_group": "chromium.memory", - "execution_mode": "COMPILE_AND_TEST", - "legacy_android_config": { - "config": "main_builder" - }, - "legacy_chromium_config": { - "apply_configs": [ - "mb" - ], - "build_config": "Release", - "config": "android_asan", - "target_bits": 64, - "target_platform": "android" - }, - "legacy_gclient_config": { - "apply_configs": [ - "android" - ], - "config": "chromium" - } - } - } - ] - }, - "builder_ids": [ - { - "bucket": "ci", - "builder": "android-asan", - "project": "chromium" - } - ], - "retry_failed_shards": true, - "targets_spec_directory": "src/infra/config/generated/builders/ci/android-asan/targets" - } - }, - "$build/reclient": { - "instance": "rbe-chromium-trusted", - "metrics_project": "chromium-reclient-metrics", - "scandeps_server": true - }, - "$build/siso": { - "configs": [ - "builder" - ], - "enable_cloud_profiler": true, - "enable_cloud_trace": true, - "experiments": [], - "project": "rbe-chromium-trusted", - "remote_jobs": 500 - }, - "$recipe_engine/resultdb/test_presentation": { - "column_keys": [], - "grouping_keys": [ - "status", - "v.test_suite" - ] - }, - "builder_group": "chromium.memory", - "recipe": "chromium" -} \ No newline at end of file
diff --git a/infra/config/generated/builders/ci/android-asan/shadow-properties.json b/infra/config/generated/builders/ci/android-asan/shadow-properties.json deleted file mode 100644 index 4325ef4..0000000 --- a/infra/config/generated/builders/ci/android-asan/shadow-properties.json +++ /dev/null
@@ -1,17 +0,0 @@ -{ - "$build/reclient": { - "instance": "rbe-chromium-untrusted", - "metrics_project": "chromium-reclient-metrics", - "scandeps_server": true - }, - "$build/siso": { - "configs": [ - "builder" - ], - "enable_cloud_profiler": true, - "enable_cloud_trace": true, - "experiments": [], - "project": "rbe-chromium-untrusted", - "remote_jobs": 500 - } -} \ No newline at end of file
diff --git a/infra/config/generated/builders/ci/android-asan/targets/chromium.memory.json b/infra/config/generated/builders/ci/android-asan/targets/chromium.memory.json deleted file mode 100644 index 8901822..0000000 --- a/infra/config/generated/builders/ci/android-asan/targets/chromium.memory.json +++ /dev/null
@@ -1,1891 +0,0 @@ -{ - "android-asan": { - "gtest_tests": [ - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "absl_hardening_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "absl_hardening_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "absl_hardening_tests", - "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "android_browsertests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "android_browsertests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 - }, - "test": "android_browsertests", - "test_id_prefix": "ninja://chrome/test:android_browsertests/" - }, - { - "args": [ - "--test-launcher-batch-limit=1", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "android_sync_integration_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "android_sync_integration_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "android_sync_integration_tests", - "test_id_prefix": "ninja://chrome/test:android_sync_integration_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "android_webview_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "android_webview_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "android_webview_unittests", - "test_id_prefix": "ninja://android_webview/test:android_webview_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "base_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "base_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "base_unittests", - "test_id_prefix": "ninja://base:base_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "blink_common_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "blink_common_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "blink_common_unittests", - "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "blink_heap_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "blink_heap_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "blink_heap_unittests", - "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/" - }, - { - "args": [ - "--git-revision=${got_revision}", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "blink_platform_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "blink_platform_unittests", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "blink_platform_unittests", - "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "boringssl_crypto_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "boringssl_crypto_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "boringssl_crypto_tests", - "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "boringssl_ssl_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "boringssl_ssl_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "boringssl_ssl_tests", - "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/" - }, - { - "args": [ - "--gtest_filter=-*UsingRealWebcam*", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "capture_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "capture_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "capture_unittests", - "test_id_prefix": "ninja://media/capture:capture_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "cast_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "cast_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "cast_unittests", - "test_id_prefix": "ninja://media/cast:cast_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "cc_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "cc_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "cc_unittests", - "test_id_prefix": "ninja://cc:cc_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_smoke_test" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "chrome_public_smoke_test", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "chrome_public_smoke_test", - "test_id_prefix": "ninja://chrome/android:chrome_public_smoke_test/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "components_browsertests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "components_browsertests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 3 - }, - "test": "components_browsertests", - "test_id_prefix": "ninja://components:components_browsertests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "components_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "components_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 6 - }, - "test": "components_unittests", - "test_id_prefix": "ninja://components:components_unittests/" - }, - { - "args": [ - "--test-launcher-filter-file=../../testing/buildbot/filters/android.asan.content_browsertests.filter", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "content_browsertests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "content_browsertests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 25 - }, - "test": "content_browsertests", - "test_id_prefix": "ninja://content/test:content_browsertests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "content_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "content_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 3 - }, - "test": "content_unittests", - "test_id_prefix": "ninja://content/test:content_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "crashpad_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "crashpad_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "crashpad_tests", - "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "crypto_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "crypto_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "crypto_unittests", - "test_id_prefix": "ninja://crypto:crypto_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "device_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "device_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "device_unittests", - "test_id_prefix": "ninja://device:device_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "display_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "display_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "display_unittests", - "test_id_prefix": "ninja://ui/display:display_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "ci_only": true, - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "env_chromium_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "env_chromium_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "env_chromium_unittests", - "test_id_prefix": "ninja://third_party/leveldatabase:env_chromium_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "events_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "events_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "events_unittests", - "test_id_prefix": "ninja://ui/events:events_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "fuzzing_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "fuzzing_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "fuzzing_unittests", - "test_id_prefix": "ninja://testing/libfuzzer/tests:fuzzing_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gcm_unit_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "gcm_unit_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gcm_unit_tests", - "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gfx_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "gfx_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gfx_unittests", - "test_id_prefix": "ninja://ui/gfx:gfx_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gin_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "gin_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gin_unittests", - "test_id_prefix": "ninja://gin:gin_unittests/" - }, - { - "args": [ - "--use-cmd-decoder=validating", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gl_tests_validating" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "gl_tests_validating", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gl_tests", - "test_id_prefix": "ninja://gpu:gl_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gl_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "gl_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gl_unittests", - "test_id_prefix": "ninja://ui/gl:gl_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "google_apis_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "google_apis_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "google_apis_unittests", - "test_id_prefix": "ninja://google_apis:google_apis_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gpu_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "gpu_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gpu_unittests", - "test_id_prefix": "ninja://gpu:gpu_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gwp_asan_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "gwp_asan_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gwp_asan_unittests", - "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "ipc_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "ipc_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 - }, - "test": "ipc_tests", - "test_id_prefix": "ninja://ipc:ipc_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "latency_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "latency_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "latency_unittests", - "test_id_prefix": "ninja://ui/latency:latency_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "ci_only": true, - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "leveldb_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "leveldb_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "leveldb_unittests", - "test_id_prefix": "ninja://third_party/leveldatabase:leveldb_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "libjingle_xmpp_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "libjingle_xmpp_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "libjingle_xmpp_unittests", - "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "liburlpattern_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "liburlpattern_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "liburlpattern_unittests", - "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "media_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "media_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "media_unittests", - "test_id_prefix": "ninja://media:media_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "midi_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "midi_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "midi_unittests", - "test_id_prefix": "ninja://media/midi:midi_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "mojo_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "mojo_test_apk", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "mojo_test_apk", - "test_id_prefix": "ninja://mojo/public/java/system:mojo_test_apk/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "mojo_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "mojo_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 5 - }, - "test": "mojo_unittests", - "test_id_prefix": "ninja://mojo:mojo_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "net_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "net_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 3 - }, - "test": "net_unittests", - "test_id_prefix": "ninja://net:net_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "services_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "services_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "services_unittests", - "test_id_prefix": "ninja://services:services_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "shell_dialogs_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "shell_dialogs_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "shell_dialogs_unittests", - "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "skia_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "skia_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "skia_unittests", - "test_id_prefix": "ninja://skia:skia_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "sql_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "sql_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "sql_unittests", - "test_id_prefix": "ninja://sql:sql_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "storage_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "storage_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "storage_unittests", - "test_id_prefix": "ninja://storage:storage_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "ui_android_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "ui_android_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "ui_android_unittests", - "test_id_prefix": "ninja://ui/android:ui_android_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "ui_base_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "ui_base_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "ui_base_unittests", - "test_id_prefix": "ninja://ui/base:ui_base_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "ui_touch_selection_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "ui_touch_selection_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "ui_touch_selection_unittests", - "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/" - }, - { - "args": [ - "--test-launcher-filter-file=../../testing/buildbot/filters/android.asan.unit_tests.filter", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "unit_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "unit_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 - }, - "test": "unit_tests", - "test_id_prefix": "ninja://chrome/test:unit_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "url_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "url_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "url_unittests", - "test_id_prefix": "ninja://url:url_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "viz_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "viz_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "viz_unittests", - "test_id_prefix": "ninja://components/viz:viz_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "vr_android_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "vr_android_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "vr_android_unittests", - "test_id_prefix": "ninja://chrome/browser/android/vr:vr_android_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "vr_common_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "vr_common_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "vr_common_unittests", - "test_id_prefix": "ninja://chrome/browser/vr:vr_common_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webkit_unit_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "webkit_unit_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 6 - }, - "test": "blink_unittests", - "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/" - }, - { - "args": [ - "--webview-process-mode=single", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_instrumentation_test_apk_single_process_mode" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "webview_instrumentation_test_apk_single_process_mode", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 3 - }, - "test": "webview_instrumentation_test_apk", - "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "wtf_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "wtf_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "wtf_unittests", - "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "zlib_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "zlib_unittests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "N2G48C", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "zlib_unittests", - "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/" - } - ] - } -} \ No newline at end of file
diff --git a/infra/config/generated/builders/gn_args_locations.json b/infra/config/generated/builders/gn_args_locations.json index e6ce5cd1..7f65fe5 100644 --- a/infra/config/generated/builders/gn_args_locations.json +++ b/infra/config/generated/builders/gn_args_locations.json
@@ -418,7 +418,6 @@ "WebKit Linux ASAN": "ci/WebKit Linux ASAN/gn-args.json", "WebKit Linux Leak": "ci/WebKit Linux Leak/gn-args.json", "WebKit Linux MSAN": "ci/WebKit Linux MSAN/gn-args.json", - "android-asan": "ci/android-asan/gn-args.json", "ios-asan": "ci/ios-asan/gn-args.json", "win-asan": "ci/win-asan/gn-args.json" },
diff --git a/infra/config/generated/builders/try/android-10-x86-fyi-rel/targets/chromium.android.fyi.json b/infra/config/generated/builders/try/android-10-x86-fyi-rel/targets/chromium.android.fyi.json index 68bfe4b..3ed70b5 100644 --- a/infra/config/generated/builders/try/android-10-x86-fyi-rel/targets/chromium.android.fyi.json +++ b/infra/config/generated/builders/try/android-10-x86-fyi-rel/targets/chromium.android.fyi.json
@@ -1017,6 +1017,7 @@ "args": [ "--use-persistent-shell", "--avd-config=../../tools/android/avd/proto/android_29_google_apis_x86.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_10.content_unittests.filter", "--gs-results-bucket=chromium-result-details", "--recover-devices" ], @@ -2244,6 +2245,7 @@ "args": [ "--use-persistent-shell", "--avd-config=../../tools/android/avd/proto/android_29_google_apis_x86.textpb", + "--gtest_filter=-ScopedDirTest.CloseOutOfScope", "--gs-results-bucket=chromium-result-details", "--recover-devices" ], @@ -2574,6 +2576,7 @@ "args": [ "--use-persistent-shell", "--avd-config=../../tools/android/avd/proto/android_29_google_apis_x86.textpb", + "--gtest_filter=-org.chromium.webview_shell.test.WebViewLayoutTest.*", "--gs-results-bucket=chromium-result-details", "--recover-devices" ], @@ -3863,7 +3866,8 @@ "args": [ "--extra-browser-args=--enable-crashpad", "--use-persistent-shell", - "--avd-config=../../tools/android/avd/proto/android_29_google_apis_x86.textpb" + "--avd-config=../../tools/android/avd/proto/android_29_google_apis_x86.textpb", + "--browser=android-chromium" ], "isolate_profile_data": true, "merge": {
diff --git a/infra/config/generated/health-specs/health-specs.json b/infra/config/generated/health-specs/health-specs.json index 90c7620..01649866 100644 --- a/infra/config/generated/health-specs/health-specs.json +++ b/infra/config/generated/health-specs/health-specs.json
@@ -6974,27 +6974,6 @@ } ] }, - "android-asan": { - "contact_team_email": "chrome-sanitizer-builder-owners@google.com", - "problem_specs": [ - { - "name": "Unhealthy", - "period_days": 7, - "score": 5, - "thresholds": { - "_default": "_default" - } - }, - { - "name": "Low Value", - "period_days": 90, - "score": 1, - "thresholds": { - "_default": "_default" - } - } - ] - }, "android-avd-packager": { "problem_specs": [ {
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index b72a993..e4fb002 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -39916,116 +39916,6 @@ } } builders { - name: "android-asan" - swarming_host: "chromium-swarm.appspot.com" - dimensions: "builderless:1" - dimensions: "cores:8" - dimensions: "cpu:x86-64" - dimensions: "free_space:standard" - dimensions: "os:Ubuntu-22.04" - dimensions: "pool:luci.chromium.ci" - dimensions: "ssd:0" - exe { - cipd_package: "infra/chromium/bootstrapper/${platform}" - cipd_version: "latest" - cmd: "bootstrapper" - } - properties: - '{' - ' "$bootstrap/exe": {' - ' "exe": {' - ' "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",' - ' "cipd_version": "refs/heads/main",' - ' "cmd": [' - ' "luciexe"' - ' ]' - ' }' - ' },' - ' "$bootstrap/properties": {' - ' "properties_file": "infra/config/generated/builders/ci/android-asan/properties.json",' - ' "shadow_properties_file": "infra/config/generated/builders/ci/android-asan/shadow-properties.json",' - ' "top_level_project": {' - ' "ref": "refs/heads/main",' - ' "repo": {' - ' "host": "chromium.googlesource.com",' - ' "project": "chromium/src"' - ' }' - ' }' - ' },' - ' "builder_group": "chromium.memory",' - ' "led_builder_is_bootstrapped": true,' - ' "recipe": "chromium"' - '}' - execution_timeout_secs: 10800 - build_numbers: YES - service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" - experiments { - key: "chromium.use_per_builder_build_dir_name" - value: 100 - } - experiments { - key: "luci.recipes.use_python3" - value: 100 - } - resultdb { - enable: true - bq_exports { - project: "chrome-luci-data" - dataset: "chromium" - table: "ci_test_results" - test_results {} - } - bq_exports { - project: "chrome-luci-data" - dataset: "chromium" - table: "gpu_ci_test_results" - test_results { - predicate { - test_id_regexp: "ninja://(chrome|content)/test:telemetry_gpu_integration_test[^/]*/.+" - } - } - } - bq_exports { - project: "chrome-luci-data" - dataset: "chromium" - table: "blink_web_tests_ci_test_results" - test_results { - predicate { - test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)|(ninja://[^/]*headless_shell_wpt/.+)" - } - } - } - history_options { - use_invocation_timestamp: true - } - } - shadow_builder_adjustments { - service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com" - pool: "luci.chromium.try" - dimensions: "free_space:" - dimensions: "pool:luci.chromium.try" - } - contact_team_email: "chrome-sanitizer-builder-owners@google.com" - custom_metric_definitions { - name: "/chrome/infra/browser/builds/cached_count" - predicates: "has(build.output.properties.is_cached)" - predicates: "string(build.output.properties.is_cached) == \"true\"" - } - custom_metric_definitions { - name: "/chrome/infra/browser/builds/ran_tests_retry_shard_count" - predicates: "has(build.output.properties.ran_tests_retry_shard)" - } - custom_metric_definitions { - name: "/chrome/infra/browser/builds/ran_tests_without_patch_count" - predicates: "has(build.output.properties.ran_tests_without_patch)" - } - custom_metric_definitions { - name: "/chrome/infra/browser/builds/uncached_count" - predicates: "has(build.output.properties.is_cached)" - predicates: "string(build.output.properties.is_cached) == \"false\"" - } - } - builders { name: "android-avd-packager" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index 48e7493..f3d2987 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -988,11 +988,6 @@ short_name: "tst" } builders { - name: "buildbucket/luci.chromium.ci/android-asan" - category: "chromium.memory|android" - short_name: "asn" - } - builders { name: "buildbucket/luci.chromium.ci/Linux CFI" category: "chromium.memory|cfi" short_name: "lnx" @@ -13137,11 +13132,6 @@ short_name: "tst" } builders { - name: "buildbucket/luci.chromium.ci/android-asan" - category: "android" - short_name: "asn" - } - builders { name: "buildbucket/luci.chromium.ci/Linux CFI" category: "cfi" short_name: "lnx"
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg index 5ed3972a..17c96766 100644 --- a/infra/config/generated/luci/luci-scheduler.cfg +++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -3492,15 +3492,6 @@ } } job { - id: "android-asan" - realm: "ci" - buildbucket { - server: "cr-buildbucket.appspot.com" - bucket: "ci" - builder: "android-asan" - } -} -job { id: "android-avd-packager" realm: "ci" schedule: "triggered" @@ -6733,7 +6724,6 @@ triggers: "android-archive-rel" triggers: "android-arm64-archive-rel" triggers: "android-arm64-proguard-rel" - triggers: "android-asan" triggers: "android-bfcache-rel" triggers: "android-binary-size-generator" triggers: "android-cast-arm-dbg"
diff --git a/infra/config/lib/builder_exemptions.star b/infra/config/lib/builder_exemptions.star index 129633c..8d102c6 100644 --- a/infra/config/lib/builder_exemptions.star +++ b/infra/config/lib/builder_exemptions.star
@@ -275,7 +275,6 @@ "android-archive-rel", "android-arm64-archive-rel", "android-arm64-proguard-rel", - "android-asan", "android-avd-packager", "android-bfcache-rel", "android-binary-size-generator", @@ -519,7 +518,6 @@ "android-arm-compile-dbg", "android-arm64-all-targets-dbg", "android-arm64-rel-compilator", - "android-asan-compile-dbg", "android-bfcache-rel", "android-binary-size", "android-chrome-pie-x86-wpt-fyi-rel", @@ -1067,7 +1065,6 @@ "android-arm64-all-targets-dbg", "android-arm64-rel", "android-arm64-rel-compilator", - "android-asan-compile-dbg", "android-bfcache-rel", "android-binary-size", "android-chrome-pie-x86-wpt-fyi-rel",
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.fyi.star b/infra/config/subprojects/chromium/ci/chromium.android.fyi.star index 3f11d58..e4f67d3c 100644 --- a/infra/config/subprojects/chromium/ci/chromium.android.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.android.fyi.star
@@ -555,11 +555,35 @@ shards = 6, ), ), + "content_unittests": targets.mixin( + args = [ + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_10.content_unittests.filter", + ], + ), + "perfetto_unittests": targets.mixin( + args = [ + # TODO(crbug.com/40201873): Fix the failed test + "--gtest_filter=-ScopedDirTest.CloseOutOfScope", + ], + ), "services_unittests": targets.mixin( swarming = targets.swarming( shards = 3, ), ), + "system_webview_shell_layout_test_apk": targets.mixin( + args = [ + # TODO(crbug.com/390676579): Fix the failed test + "--gtest_filter=-org.chromium.webview_shell.test.WebViewLayoutTest.*", + ], + ), + "telemetry_perf_unittests_android_chrome": targets.mixin( + # For whatever reason, automatic browser selection on this bot chooses + # webview instead of the full browser, so explicitly specify it here. + args = [ + "--browser=android-chromium", + ], + ), }, ), targets_settings = targets.settings(
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.star b/infra/config/subprojects/chromium/ci/chromium.memory.star index 02858cb2..1a9ebc5 100644 --- a/infra/config/subprojects/chromium/ci/chromium.memory.star +++ b/infra/config/subprojects/chromium/ci/chromium.memory.star
@@ -1266,116 +1266,6 @@ ) ci.builder( - name = "android-asan", - builder_spec = builder_config.builder_spec( - gclient_config = builder_config.gclient_config( - config = "chromium", - apply_configs = ["android"], - ), - chromium_config = builder_config.chromium_config( - config = "android_asan", - apply_configs = ["mb"], - build_config = builder_config.build_config.RELEASE, - target_bits = 64, - target_platform = builder_config.target_platform.ANDROID, - ), - android_config = builder_config.android_config(config = "main_builder"), - build_gs_bucket = "chromium-memory-archive", - ), - gn_args = gn_args.config( - configs = [ - "android_builder", - "clang", - "asan", - "release_builder", - "remoteexec", - "strip_debug_info", - "minimal_symbols", - "arm", - ], - ), - targets = targets.bundle( - targets = [ - "chromium_android_gtests", - ], - mixins = [ - "has_native_resultdb_integration", - "bullhead", - "nougat", - ], - per_test_modifications = { - "android_browsertests": targets.mixin( - swarming = targets.swarming( - shards = 2, - ), - ), - "angle_unittests": targets.remove( - reason = "Times out listing tests crbug.com/1167314", - ), - "chrome_public_test_apk": targets.remove( - reason = "https://crbug.com/964562", - ), - "chrome_public_test_vr_apk": targets.remove( - reason = "https://crbug.com/964562", - ), - "chrome_public_unit_test_apk": targets.remove( - reason = "https://crbug.com/964562", - ), - "components_browsertests": targets.mixin( - swarming = targets.swarming( - shards = 3, - ), - ), - "content_browsertests": targets.mixin( - args = [ - "--test-launcher-filter-file=../../testing/buildbot/filters/android.asan.content_browsertests.filter", - ], - swarming = targets.swarming( - shards = 25, - ), - ), - "content_shell_test_apk": targets.remove( - reason = "https://crbug.com/964562", - ), - "ipc_tests": targets.mixin( - swarming = targets.swarming( - shards = 2, - ), - ), - "mojo_unittests": targets.mixin( - swarming = targets.swarming( - shards = 5, - ), - ), - "perfetto_unittests": targets.remove( - reason = "TODO(crbug.com/41440830): Fix permission issue when creating tmp files", - ), - "sandbox_linux_unittests": targets.remove( - reason = "https://crbug.com/962650", - ), - "unit_tests": targets.mixin( - args = [ - "--test-launcher-filter-file=../../testing/buildbot/filters/android.asan.unit_tests.filter", - ], - ), - "webview_instrumentation_test_apk_multiple_process_mode": targets.remove( - reason = "https://crbug.com/964562", - ), - }, - ), - targets_settings = targets.settings( - os_type = targets.os_type.ANDROID, - ), - os = os.LINUX_DEFAULT, - gardener_rotations = args.ignore_default(None), - tree_closing = False, - console_view_entry = consoles.console_view_entry( - category = "android", - short_name = "asn", - ), -) - -ci.builder( name = "win-asan", builder_spec = builder_config.builder_spec( gclient_config = builder_config.gclient_config(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star index 3797aa8..1e93334a 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
@@ -421,20 +421,6 @@ siso_remote_jobs = siso.remote_jobs.LOW_JOBS_FOR_CQ, ) -# TODO(crbug.com/40240078): Reenable this builder once the reboot issue is resolved. -# try_.builder( -# name = "android-asan", -# mirrors = ["ci/android-asan"], -# gn_args = gn_args.config( -# configs = [ -# "ci/android-asan", -# "release_try_builder", -# "minimal_symbols", -# ], -# ), -# siso_remote_jobs = siso.remote_jobs.LOW_JOBS_FOR_CQ, -# ) - try_.builder( name = "android-bfcache-rel", mirrors = [
diff --git a/internal b/internal index 7f38ae2..014be7b 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit 7f38ae2436442ada9c5c9c059547f64e6961de04 +Subproject commit 014be7b57c088d653120c5997fea33b52107a768
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index d3f7bf10..fdf06e4 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1201,8 +1201,14 @@ <message name="IDS_IOS_CONTENT_SUGGESTIONS_HISTORY" desc="The History title on the new tab page [Length: 10em]"> History </message> + <message name="IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_CONTEXT_MENU_DESCRIPTION" desc="Descripiton for the long-press context menu of the module that presents the most visite sites."> + This card shows your most visited sites. + </message> + <message name="IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_HIDE_CARD" desc="Button text indicating most visited sites module can be removed"> + Hide "Your Top Sites" + </message> <message name="IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_TITLE" desc="The Most Visited module title on the new tab page [Length: 10em]"> - Most visited sites + Your Top Sites </message> <message name="IDS_IOS_CONTENT_SUGGESTIONS_PARCEL_TRACKING_MODULE_PACKAGE_ARRIVING_STATUS" desc="The Parcel Tracking module package arriving status description on the Home surface [Length: 10em]"> Arriving <ph name="Date"><ex>Monday, September 13</ex>$1</ph>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_CONTEXT_MENU_DESCRIPTION.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_CONTEXT_MENU_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..2e77b10 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_CONTEXT_MENU_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +470616ac06e7e3c8729c85a70a61c8804dd0942c \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_HIDE_CARD.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_HIDE_CARD.png.sha1 new file mode 100644 index 0000000..2e77b10 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_HIDE_CARD.png.sha1
@@ -0,0 +1 @@ +470616ac06e7e3c8729c85a70a61c8804dd0942c \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_TITLE.png.sha1 index 99e5595..eea4f44 100644 --- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_TITLE.png.sha1 +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_TITLE.png.sha1
@@ -1 +1 @@ -1d167d888ef24a35629dcbf6599466ccd9b8fcd6 \ No newline at end of file +dee0b4d80f93e3c3cbdb4d8610503e388e942f89 \ No newline at end of file
diff --git a/ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_tab_helper.mm b/ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_tab_helper.mm index 88b23a04..d6e609e 100644 --- a/ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_tab_helper.mm +++ b/ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_tab_helper.mm
@@ -539,7 +539,10 @@ autofill::FormGlobalId form_id, bool only_new) { autofill::FormStructure* form_structure = manager.FindCachedFormById(form_id); - if (!form_structure || !form_structure->IsCompleteCreditCardForm()) { + if (!form_structure || + !form_structure->IsCompleteCreditCardForm( + autofill::FormStructure::CreditCardFormCompleteness:: + kCompleteCreditCardForm)) { return; } if (manager.client()
diff --git a/ios/chrome/browser/credential_provider/model/BUILD.gn b/ios/chrome/browser/credential_provider/model/BUILD.gn index ab051cc3..903b1ac 100644 --- a/ios/chrome/browser/credential_provider/model/BUILD.gn +++ b/ios/chrome/browser/credential_provider/model/BUILD.gn
@@ -55,6 +55,7 @@ "//ios/chrome/browser/shared/model/profile:profile_keyed_service_factory", "//ios/chrome/browser/shared/model/web_state_list", "//ios/chrome/browser/shared/public/commands", + "//ios/chrome/browser/shared/public/features", "//ios/chrome/browser/shared/ui/symbols", "//ios/chrome/browser/signin/model", "//ios/chrome/browser/signin/model:system_identity", @@ -107,6 +108,7 @@ "//ios/chrome/browser/shared/model/profile/test", "//ios/chrome/browser/shared/model/web_state_list", "//ios/chrome/browser/shared/public/commands", + "//ios/chrome/browser/shared/public/features", "//ios/chrome/browser/signin/model:fake_system_identity", "//ios/chrome/browser/signin/model:fake_system_identity_manager", "//ios/chrome/browser/signin/model:test_support",
diff --git a/ios/chrome/browser/credential_provider/model/credential_provider_service.h b/ios/chrome/browser/credential_provider/model/credential_provider_service.h index a573d0d..8217f804 100644 --- a/ios/chrome/browser/credential_provider/model/credential_provider_service.h +++ b/ios/chrome/browser/credential_provider/model/credential_provider_service.h
@@ -141,6 +141,9 @@ // Syncs whether or not PRF is enabled. void UpdatePasskeyPRFSetting(); + // Syncs whether or not the Passkeys M2 feature is enabled. + void UpdatePasskeysM2Availability(); + // PasswordStoreConsumer: void OnGetPasswordStoreResultsOrErrorFrom( password_manager::PasswordStoreInterface* store, @@ -217,7 +220,7 @@ // The preference associated with // password_manager::prefs::kCredentialsEnablePasskeys. See - // `AppGroupUserDefaulsCredentialProviderSavingPasskeysEnabled` documentation + // `AppGroupUserDefaultsCredentialProviderSavingPasskeysEnabled` documentation // for important caveats. BooleanPrefMember saving_passkeys_enabled_;
diff --git a/ios/chrome/browser/credential_provider/model/credential_provider_service.mm b/ios/chrome/browser/credential_provider/model/credential_provider_service.mm index dcb5122..128ee7a 100644 --- a/ios/chrome/browser/credential_provider/model/credential_provider_service.mm +++ b/ios/chrome/browser/credential_provider/model/credential_provider_service.mm
@@ -30,6 +30,7 @@ #import "ios/chrome/browser/credential_provider/model/archivable_credential+password_form.h" #import "ios/chrome/browser/credential_provider/model/credential_provider_util.h" #import "ios/chrome/browser/credential_provider/model/features.h" +#import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/signin/model/system_identity.h" #import "ios/chrome/common/app_group/app_group_constants.h" #import "ios/chrome/common/credential_provider/ASPasskeyCredentialIdentity+credential.h" @@ -216,6 +217,7 @@ OnPrefOrPolicyStatusChanged(); UpdatePasswordSyncSetting(); UpdatePasskeyPRFSetting(); + UpdatePasskeysM2Availability(); } CredentialProviderService::~CredentialProviderService() {} @@ -543,6 +545,12 @@ forKey:AppGroupUserDefaulsCredentialProviderPasskeyPRFEnabled()]; } +void CredentialProviderService::UpdatePasskeysM2Availability() { + [app_group::GetGroupUserDefaults() + setObject:[NSNumber numberWithBool:IOSPasskeysM2Enabled()] + forKey:AppGroupUserDefaultsCredentialProviderPasskeysM2Enabled()]; +} + void CredentialProviderService::OnGetPasswordStoreResultsOrErrorFrom( password_manager::PasswordStoreInterface* store, password_manager::LoginsResultOrError results) { @@ -644,13 +652,13 @@ void CredentialProviderService::OnPrefOrPolicyStatusChanged() { [app_group::GetGroupUserDefaults() setObject:[NSNumber numberWithBool:saving_passwords_enabled_.GetValue()] - forKey:AppGroupUserDefaulsCredentialProviderSavingPasswordsEnabled()]; + forKey:AppGroupUserDefaultsCredentialProviderSavingPasswordsEnabled()]; [app_group::GetGroupUserDefaults() setObject:[NSNumber numberWithBool:saving_passwords_enabled_.IsManaged()] - forKey:AppGroupUserDefaulsCredentialProviderSavingPasswordsManaged()]; + forKey:AppGroupUserDefaultsCredentialProviderSavingPasswordsManaged()]; [app_group::GetGroupUserDefaults() setObject:[NSNumber numberWithBool:saving_passkeys_enabled_.GetValue()] - forKey:AppGroupUserDefaulsCredentialProviderSavingPasskeysEnabled()]; + forKey:AppGroupUserDefaultsCredentialProviderSavingPasskeysEnabled()]; } MemoryCredentialStore* CredentialProviderService::GetCredentialStore(
diff --git a/ios/chrome/browser/credential_provider/model/credential_provider_service_unittest.mm b/ios/chrome/browser/credential_provider/model/credential_provider_service_unittest.mm index 38cb750..a74ba0f 100644 --- a/ios/chrome/browser/credential_provider/model/credential_provider_service_unittest.mm +++ b/ios/chrome/browser/credential_provider/model/credential_provider_service_unittest.mm
@@ -34,6 +34,7 @@ #import "ios/chrome/browser/credential_provider/model/features.h" #import "ios/chrome/browser/favicon/model/favicon_loader.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/common/app_group/app_group_constants.h" #import "ios/chrome/common/credential_provider/constants.h" #import "ios/chrome/common/credential_provider/credential.h" @@ -170,6 +171,11 @@ } void CreateCredentialProviderService(bool with_account_store = false) { + // Make sure to shut down the previous instance before creating a new one. + if (credential_provider_service_) { + credential_provider_service_->Shutdown(); + } + credential_provider_service_ = std::make_unique<CredentialProviderService>( &testing_pref_service_, password_store_, with_account_store ? account_password_store_ : nullptr, @@ -355,7 +361,7 @@ // NSUserDefaults value is also true. EXPECT_TRUE([[app_group::GetGroupUserDefaults() objectForKey: - AppGroupUserDefaulsCredentialProviderSavingPasswordsEnabled()] + AppGroupUserDefaultsCredentialProviderSavingPasswordsEnabled()] boolValue]); // Change the pref value to false. @@ -365,7 +371,7 @@ // Make sure the NSUserDefaults value is now false. EXPECT_FALSE([[app_group::GetGroupUserDefaults() objectForKey: - AppGroupUserDefaulsCredentialProviderSavingPasswordsEnabled()] + AppGroupUserDefaultsCredentialProviderSavingPasswordsEnabled()] boolValue]); } @@ -429,6 +435,32 @@ stringForKey:AppGroupUserDefaultsCredentialProviderUserEmail()]); } +// Tests that the CredentialProviderService correctly stores the enabled state +// of the Passkeys M2 feature. +TEST_F(CredentialProviderServiceTest, PasskeysM2Availability) { + { + // Enable the `kIOSPasskeysM2` feature. + base::test::ScopedFeatureList feature_list(kIOSPasskeysM2); + + CreateCredentialProviderService(); + + EXPECT_TRUE([[app_group::GetGroupUserDefaults() + objectForKey:AppGroupUserDefaultsCredentialProviderPasskeysM2Enabled()] + boolValue]); + } + { + // Disable the `kIOSPasskeysM2` feature. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(kIOSPasskeysM2); + + CreateCredentialProviderService(); + + EXPECT_FALSE([[app_group::GetGroupUserDefaults() + objectForKey:AppGroupUserDefaultsCredentialProviderPasskeysM2Enabled()] + boolValue]); + } +} + TEST_F(CredentialProviderServiceTest, AddCredentialsWithValidURL) { CreateCredentialProviderService();
diff --git a/ios/chrome/browser/iph_for_new_chrome_user/model/BUILD.gn b/ios/chrome/browser/iph_for_new_chrome_user/model/BUILD.gn index 57d6b419..9c3074d 100644 --- a/ios/chrome/browser/iph_for_new_chrome_user/model/BUILD.gn +++ b/ios/chrome/browser/iph_for_new_chrome_user/model/BUILD.gn
@@ -14,11 +14,13 @@ "//base", "//components/bookmarks/browser", "//components/feature_engagement/public", + "//components/reading_list/core", "//components/segmentation_platform/embedder/default_model", "//components/segmentation_platform/public", "//components/send_tab_to_self", "//ios/chrome/browser/bookmarks/model", "//ios/chrome/browser/feature_engagement/model", + "//ios/chrome/browser/reading_list/model", "//ios/chrome/browser/shared/model/browser", "//ios/chrome/browser/shared/model/url:constants", "//ios/chrome/browser/shared/model/utils",
diff --git a/ios/chrome/browser/iph_for_new_chrome_user/model/DEPS b/ios/chrome/browser/iph_for_new_chrome_user/model/DEPS index 7258d58c..86db2e2 100644 --- a/ios/chrome/browser/iph_for_new_chrome_user/model/DEPS +++ b/ios/chrome/browser/iph_for_new_chrome_user/model/DEPS
@@ -2,5 +2,6 @@ "+ios/chrome/browser/bookmarks/model", "+ios/chrome/browser/first_run/model", "+ios/chrome/browser/feature_engagement/model", + "+ios/chrome/browser/reading_list/model", "+ios/chrome/browser/url_loading/model", ]
diff --git a/ios/chrome/browser/iph_for_new_chrome_user/model/tab_based_iph_browser_agent.h b/ios/chrome/browser/iph_for_new_chrome_user/model/tab_based_iph_browser_agent.h index 09eab1b..2014108 100644 --- a/ios/chrome/browser/iph_for_new_chrome_user/model/tab_based_iph_browser_agent.h +++ b/ios/chrome/browser/iph_for_new_chrome_user/model/tab_based_iph_browser_agent.h
@@ -8,6 +8,7 @@ #import "base/memory/raw_ptr.h" #import "base/scoped_observation.h" #import "components/bookmarks/browser/base_bookmark_model_observer.h" +#import "components/reading_list/core/reading_list_model_observer.h" #import "ios/chrome/browser/shared/model/browser/browser_observer.h" #import "ios/chrome/browser/shared/model/browser/browser_user_data.h" #import "ios/chrome/browser/shared/model/web_state_list/active_web_state_observation_forwarder.h" @@ -18,9 +19,14 @@ class BookmarkNode; } // namespace bookmarks +namespace reading_list { +enum EntrySource; +} // namespace reading_list + class Browser; @class CommandDispatcher; @protocol HelpCommands; +class ReadingListModel; class UrlLoadingNotifierBrowserAgent; class WebStateList; @@ -33,6 +39,7 @@ class TabBasedIPHBrowserAgent : public bookmarks::BaseBookmarkModelObserver, public BrowserUserData<TabBasedIPHBrowserAgent>, public BrowserObserver, + public ReadingListModelObserver, public UrlLoadingObserver, public web::WebStateObserver { public: @@ -81,6 +88,13 @@ // BrowserObserver void BrowserDestroyed(Browser* browser) override; + // ReadingListModelObserver + void ReadingListModelLoaded(const ReadingListModel* model) override; + void ReadingListModelBeingShutdown(const ReadingListModel* model) override; + void ReadingListDidAddEntry(const ReadingListModel* model, + const GURL& url, + reading_list::EntrySource source) override; + // UrlLoadingObserver void TabDidLoadUrl(const GURL& url, ui::PageTransition transition_type) override; @@ -109,6 +123,12 @@ // longer react to bookmark modifications. void StopObservingBookmarkModel(); + // Stops observing changes to the reading list model. This is typically + // called when `TabBasedIPHBrowserAgent` is being destroyed, when reactions + // to reading list modifications are no longer needed, or when the reading + // list model itself is being destroyed. + void StopObservingReadingListModel(); + // For all IPH features managed by this class, resets their tracker variables // to `false`, and remove currently displaying IPH views from the view. void ResetFeatureStatesAndRemoveIPHViews(); @@ -128,6 +148,16 @@ base::ScopedObservation<bookmarks::BookmarkModel, bookmarks::BaseBookmarkModelObserver> bookmark_model_observation_{this}; + // `ReadingListModel` instance providing access to the reading list. May be + // `nullptr`. + raw_ptr<ReadingListModel> reading_list_model_ = nullptr; + // Tracks whether the reading list model has finished loading. Until the model + // is fully loaded, it is unsafe to use or interact with it. + bool reading_list_model_loaded_ = false; + // Automatically removes this observer from the reading list model when + // destroyed. + base::ScopedObservation<ReadingListModel, ReadingListModelObserver> + reading_list_model_observation_{this}; // Observer for URL loading. raw_ptr<UrlLoadingNotifierBrowserAgent> url_loading_notifier_; // Command dispatcher for the browser; used to retrieve help handler.
diff --git a/ios/chrome/browser/iph_for_new_chrome_user/model/tab_based_iph_browser_agent.mm b/ios/chrome/browser/iph_for_new_chrome_user/model/tab_based_iph_browser_agent.mm index 4dc522f..c5ff221 100644 --- a/ios/chrome/browser/iph_for_new_chrome_user/model/tab_based_iph_browser_agent.mm +++ b/ios/chrome/browser/iph_for_new_chrome_user/model/tab_based_iph_browser_agent.mm
@@ -9,9 +9,12 @@ #import "components/bookmarks/browser/bookmark_node.h" #import "components/feature_engagement/public/event_constants.h" #import "components/feature_engagement/public/tracker.h" +#import "components/reading_list/core/reading_list_entry.h" +#import "components/reading_list/core/reading_list_model.h" #import "components/send_tab_to_self/features.h" #import "ios/chrome/browser/bookmarks/model/bookmark_model_factory.h" #import "ios/chrome/browser/feature_engagement/model/tracker_factory.h" +#import "ios/chrome/browser/reading_list/model/reading_list_model_factory.h" #import "ios/chrome/browser/shared/model/browser/browser.h" #import "ios/chrome/browser/shared/model/url/chrome_url_constants.h" #import "ios/chrome/browser/shared/model/web_state_list/active_web_state_observation_forwarder.h" @@ -30,6 +33,8 @@ this)), bookmark_model_( ios::BookmarkModelFactory::GetForProfile(browser->GetProfile())), + reading_list_model_( + ReadingListModelFactory::GetForProfile(browser->GetProfile())), url_loading_notifier_( UrlLoadingNotifierBrowserAgent::FromBrowser(browser)), command_dispatcher_(browser->GetCommandDispatcher()), @@ -40,6 +45,7 @@ IsSendTabIOSPushNotificationsEnabledWithTabReminders() && bookmark_model_) { bookmark_model_observation_.Observe(bookmark_model_.get()); + reading_list_model_observation_.Observe(reading_list_model_.get()); } url_loading_notifier_->AddObserver(this); } @@ -132,6 +138,7 @@ if (send_tab_to_self:: IsSendTabIOSPushNotificationsEnabledWithTabReminders()) { StopObservingBookmarkModel(); + StopObservingReadingListModel(); } web_state_list_ = nil; @@ -140,6 +147,48 @@ engagement_tracker_ = nil; } +#pragma mark - ReadingListModelObserver + +void TabBasedIPHBrowserAgent::ReadingListModelLoaded( + const ReadingListModel* model) { + CHECK( + send_tab_to_self::IsSendTabIOSPushNotificationsEnabledWithTabReminders()); + + reading_list_model_loaded_ = true; +} + +void TabBasedIPHBrowserAgent::ReadingListModelBeingShutdown( + const ReadingListModel* model) { + CHECK( + send_tab_to_self::IsSendTabIOSPushNotificationsEnabledWithTabReminders()); + CHECK(reading_list_model_loaded_); + + // The model passed is `const`, which makes it impossible to call + // `model->RemoveObserver(...)`. Other `ReadingListModelObserver` + // clients address this by removing themselves as observers using a reference + // to the model maintained in their class, so a similar approach is followed + // in `StopObservingReadingListModel()`. Fortunately, + // `reading_list_model_observation_` will gracefully handle removing + // `TabBasedIPHBrowserAgent` as an observer if all else fails. + StopObservingReadingListModel(); +} + +void TabBasedIPHBrowserAgent::ReadingListDidAddEntry( + const ReadingListModel* model, + const GURL& url, + reading_list::EntrySource source) { + CHECK( + send_tab_to_self::IsSendTabIOSPushNotificationsEnabledWithTabReminders()); + CHECK(reading_list_model_loaded_); + + if (source == reading_list::EntrySource::ADDED_VIA_CURRENT_APP) { + // A reading list entry was manually added by the user. + + // TODO(crbug.com/389911609): Fire a UI command to display the relevant + // Reminder Notifications Bubble IPH. + } +} + #pragma mark - UrlLoadingObserver void TabBasedIPHBrowserAgent::TabDidLoadUrl( @@ -252,6 +301,19 @@ bookmark_model_observation_.Reset(); } +void TabBasedIPHBrowserAgent::StopObservingReadingListModel() { + CHECK( + send_tab_to_self::IsSendTabIOSPushNotificationsEnabledWithTabReminders()); + + if (reading_list_model_) { + reading_list_model_->RemoveObserver(this); + } + + reading_list_model_ = nullptr; + reading_list_model_observation_.Reset(); + reading_list_model_loaded_ = false; +} + void TabBasedIPHBrowserAgent::ResetFeatureStatesAndRemoveIPHViews() { multi_gesture_refresh_ = false; back_forward_button_tapped_ = false;
diff --git a/ios/chrome/browser/parcel_tracking/features.mm b/ios/chrome/browser/parcel_tracking/features.mm index a394bf8..0195151 100644 --- a/ios/chrome/browser/parcel_tracking/features.mm +++ b/ios/chrome/browser/parcel_tracking/features.mm
@@ -11,7 +11,7 @@ BASE_FEATURE(kIOSDisableParcelTracking, "IOSDisableParcelTracking", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); bool IsIOSParcelTrackingEnabled() { variations::VariationsService* variations_service =
diff --git a/ios/chrome/browser/parcel_tracking/parcel_tracking_util_unittest.mm b/ios/chrome/browser/parcel_tracking/parcel_tracking_util_unittest.mm index aed1ab7..037f21c 100644 --- a/ios/chrome/browser/parcel_tracking/parcel_tracking_util_unittest.mm +++ b/ios/chrome/browser/parcel_tracking/parcel_tracking_util_unittest.mm
@@ -72,6 +72,9 @@ // Tests that IsUserEligibleParcelTrackingOptInPrompt returns true when the user // is eligible. TEST_F(ParcelTrackingUtilTest, UserIsEligibleForPrompt) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature(kIOSDisableParcelTracking); + SignIn(); SetPromptDisplayedStatus(false); IOSChromeScopedTestingVariationsService scoped_variations_service; @@ -83,6 +86,9 @@ // Tests that IsUserEligibleParcelTrackingOptInPrompt returns false when the // user is not signed in. TEST_F(ParcelTrackingUtilTest, NotSignedIn) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature(kIOSDisableParcelTracking); + SignOut(); SetPromptDisplayedStatus(false); shopping_service_->SetIsParcelTrackingEligible(false); @@ -93,9 +99,9 @@ } // Tests that IsUserEligibleParcelTrackingOptInPrompt returns false when the -// feature is disabled. +// feature is disabled. This is now the default behavior, so doesn't require a +// specific feature override. TEST_F(ParcelTrackingUtilTest, FeatureDisabled) { - base::test::ScopedFeatureList scoped_feature_list(kIOSDisableParcelTracking); SignIn(); SetPromptDisplayedStatus(false); EXPECT_FALSE(IsUserEligibleParcelTrackingOptInPrompt( @@ -105,6 +111,9 @@ // Tests that IsUserEligibleParcelTrackingOptInPrompt returns false when the // user has seen the prompt. TEST_F(ParcelTrackingUtilTest, UserHasSeenPrompt) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature(kIOSDisableParcelTracking); + SignIn(); SetPromptDisplayedStatus(true); IOSChromeScopedTestingVariationsService scoped_variations_service; @@ -116,6 +125,9 @@ // Tests that IsUserEligibleParcelTrackingOptInPrompt returns false when the // permanent country is not set to US. TEST_F(ParcelTrackingUtilTest, CountryNotUS) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature(kIOSDisableParcelTracking); + SignIn(); SetPromptDisplayedStatus(true); EXPECT_FALSE(IsUserEligibleParcelTrackingOptInPrompt(
diff --git a/ios/chrome/browser/settings/ui_bundled/google_services/google_services_settings_egtest.mm b/ios/chrome/browser/settings/ui_bundled/google_services/google_services_settings_egtest.mm index 1b9c48a..8522a0b 100644 --- a/ios/chrome/browser/settings/ui_bundled/google_services/google_services_settings_egtest.mm +++ b/ios/chrome/browser/settings/ui_bundled/google_services/google_services_settings_egtest.mm
@@ -122,7 +122,7 @@ // the feature is not enabled. config.features_enabled.push_back(kIdentityDiscAccountMenu); } - if ([self isRunningTest:@selector(DISABLED_testParcelTrackingSetting)]) { + if ([self isRunningTest:@selector(testParcelTrackingSetting)]) { config.features_disabled.push_back(kIOSDisableParcelTracking); } return config; @@ -343,12 +343,9 @@ } // Tests the parcel tracking settings row is properly shown. -// TODO(crbug.com/389954360): Restore this test. -- (void)DISABLED_testParcelTrackingSetting { +- (void)testParcelTrackingSetting { // Parcel tracking is only enabled in the US. - [ChromeEarlGrey setStringValue:"us" - forLocalStatePref:variations::prefs:: - kVariationsPermanentOverriddenCountry]; + [ChromeEarlGrey overrideVariationsServiceStoredPermanentCountry:@"us"]; [self openGoogleServicesSettings]; @@ -365,9 +362,7 @@ // Tests the parcel tracking settings row is not shown for non-US countries. - (void)testParcelTrackingSetting_notShownOutsideUS { // Set permanent country to somthing other than the US. - [ChromeEarlGrey setStringValue:"fr" - forLocalStatePref:variations::prefs:: - kVariationsPermanentOverriddenCountry]; + [ChromeEarlGrey overrideVariationsServiceStoredPermanentCountry:@"fr"]; [self openGoogleServicesSettings];
diff --git a/ios/chrome/browser/settings/ui_bundled/password/BUILD.gn b/ios/chrome/browser/settings/ui_bundled/password/BUILD.gn index 019af96f..221274c 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/BUILD.gn +++ b/ios/chrome/browser/settings/ui_bundled/password/BUILD.gn
@@ -84,7 +84,6 @@ ] deps = [ ":common", - ":features", ":password_constants", ":title_view", "//base", @@ -97,7 +96,6 @@ "//components/prefs", "//components/signin/public/identity_manager/objc", "//components/strings", - "//components/sync/base", "//components/sync/service", "//ios/chrome/app/strings", "//ios/chrome/browser/net/model:crurl", @@ -171,7 +169,6 @@ "password_manager_ui_features.h", "password_manager_ui_features.mm", ] - deps = [ "//components/sync/base:features" ] public_deps = [ "//base" ] }
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h b/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h index 456614e..a975397d 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h +++ b/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h
@@ -11,19 +11,18 @@ // components. namespace password_manager::features { +// Kill switch for the logic that allows the user to open the native Password +// Settings page. Used when the user wants to access the Password Manager UI +// without a passcode set. BASE_DECLARE_FEATURE(kIOSEnablePasscodeSettings); +// Feature switch for the logic that allows the user to delete all saved +// credentials in PWM. BASE_DECLARE_FEATURE(kIOSEnableDeleteAllSavedCredentials); -BASE_DECLARE_FEATURE(kIOSPasskeysM2); - -// Helper function returning the status of `kIOSEnablePasscodeShortcut`. +// Helper function returning the status of `kIOSEnablePasscodeSettings`. bool IsPasscodeSettingsEnabled(); -// Helper function returning the status of `kIOSPasskeysM2` and the M1 -// prerequisite. -bool IOSPasskeysM2Enabled(); - } // namespace password_manager::features #endif // IOS_CHROME_BROWSER_SETTINGS_UI_BUNDLED_PASSWORD_PASSWORD_MANAGER_UI_FEATURES_H_
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.mm b/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.mm index 6bf7764..796f7963 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.mm +++ b/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.mm
@@ -4,37 +4,18 @@ #import "ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h" -#import "components/sync/base/features.h" - namespace password_manager::features { -// Kill switch for the logic that allows the user to open the native Password -// Settings page. Used when the user wants to access the Password Manager UI -// without a passcode set. BASE_FEATURE(kIOSEnablePasscodeSettings, "IOSEnablePasscodeSettings", base::FEATURE_ENABLED_BY_DEFAULT); -// Feature switch for the logic that allows the user to delete all saved -// credentials in PWM. BASE_FEATURE(kIOSEnableDeleteAllSavedCredentials, "IOSEnableDeleteAllSavedCredentials", base::FEATURE_DISABLED_BY_DEFAULT); -// Enables passkey syncing follow-up features. -BASE_FEATURE(kIOSPasskeysM2, - "IOSPasskeysM2", - base::FEATURE_DISABLED_BY_DEFAULT); - -// Helper function returning the status of `kIOSEnablePasscodeSettings`. bool IsPasscodeSettingsEnabled() { return base::FeatureList::IsEnabled(kIOSEnablePasscodeSettings); } -bool IOSPasskeysM2Enabled() { - return syncer::IsWebauthnCredentialSyncEnabled() && - base::FeatureList::IsEnabled( - password_manager::features::kIOSPasskeysM2); -} - } // namespace password_manager::features
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_manager_view_controller.mm b/ios/chrome/browser/settings/ui_bundled/password/password_manager_view_controller.mm index 197692c..059ee9c 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/password_manager_view_controller.mm +++ b/ios/chrome/browser/settings/ui_bundled/password/password_manager_view_controller.mm
@@ -39,7 +39,6 @@ #import "ios/chrome/browser/settings/ui_bundled/cells/settings_check_item.h" #import "ios/chrome/browser/settings/ui_bundled/elements/enterprise_info_popover_view_controller.h" #import "ios/chrome/browser/settings/ui_bundled/password/create_password_manager_title_view.h" -#import "ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h" #import "ios/chrome/browser/settings/ui_bundled/password/password_manager_view_controller+Testing.h" #import "ios/chrome/browser/settings/ui_bundled/password/password_manager_view_controller_delegate.h" #import "ios/chrome/browser/settings/ui_bundled/password/password_manager_view_controller_items.h" @@ -53,6 +52,7 @@ #import "ios/chrome/browser/settings/ui_bundled/utils/password_utils.h" #import "ios/chrome/browser/shared/model/application_context/application_context.h" #import "ios/chrome/browser/shared/model/url/chrome_url_constants.h" +#import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/shared/ui/elements/home_waiting_view.h" #import "ios/chrome/browser/shared/ui/symbols/symbols.h" #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_detail_icon_item.h" @@ -87,7 +87,6 @@ #import "url/gurl.h" using base::UmaHistogramEnumeration; -using password_manager::features::IOSPasskeysM2Enabled; using password_manager::metrics_util::PasswordCheckInteraction; namespace {
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_settings/BUILD.gn b/ios/chrome/browser/settings/ui_bundled/password/password_settings/BUILD.gn index 3591881..8e1246f 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/password_settings/BUILD.gn +++ b/ios/chrome/browser/settings/ui_bundled/password/password_settings/BUILD.gn
@@ -70,10 +70,10 @@ deps = [ ":password_settings_constants", "//components/strings", - "//components/sync/base", "//ios/chrome/app/strings", "//ios/chrome/browser/settings/ui_bundled/password:features", "//ios/chrome/browser/shared/public/commands", + "//ios/chrome/browser/shared/public/features", "//ios/chrome/browser/shared/ui/symbols", "//ios/chrome/browser/shared/ui/table_view", "//ios/chrome/browser/shared/ui/table_view:utils", @@ -127,7 +127,6 @@ "//ios/chrome/app/strings", "//ios/chrome/browser/passwords/model:store_factory", "//ios/chrome/browser/passwords/model/metrics", - "//ios/chrome/browser/settings/ui_bundled/password:features", "//ios/chrome/browser/settings/ui_bundled/password/reauthentication:reauthentication_ui", "//ios/chrome/browser/shared/coordinator/scene:scene_state_header", "//ios/chrome/browser/shared/model/application_context", @@ -135,6 +134,7 @@ "//ios/chrome/browser/shared/model/profile", "//ios/chrome/browser/shared/model/profile/test", "//ios/chrome/browser/shared/public/commands", + "//ios/chrome/browser/shared/public/features", "//ios/chrome/browser/shared/ui/table_view", "//ios/chrome/browser/shared/ui/table_view:test_support", "//ios/chrome/browser/signin/model",
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller.mm b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller.mm index cd5f7e6c..7592596 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller.mm +++ b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller.mm
@@ -18,6 +18,7 @@ #import "components/strings/grit/components_strings.h" #import "ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h" #import "ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_constants.h" +#import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/shared/ui/symbols/symbols.h" #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_detail_icon_item.h" #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_image_item.h" @@ -38,8 +39,6 @@ namespace { -using ::password_manager::features::IOSPasskeysM2Enabled; - // Sections of the password settings UI. typedef NS_ENUM(NSInteger, SectionIdentifier) { SectionIdentifierSavePasswordsSwitch = kSectionIdentifierEnumZero,
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller_unittest.mm b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller_unittest.mm index 709f298..d184ff2 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller_unittest.mm +++ b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller_unittest.mm
@@ -7,8 +7,8 @@ #import "base/apple/foundation_util.h" #import "base/test/scoped_feature_list.h" #import "components/sync/base/features.h" -#import "ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h" #import "ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_consumer.h" +#import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_detail_icon_item.h" #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_image_item.h" #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_info_button_item.h" @@ -28,11 +28,7 @@ // displayed on top. This differs based on the addition of the automatic passkey // upgrades toggle. Should be cleaned up after the feature is launched. int ExpectedSectionAfterAlwaysVisibleTopSections() { - return syncer::IsWebauthnCredentialSyncEnabled() && - base::FeatureList::IsEnabled( - password_manager::features::kIOSPasskeysM2) - ? 3 - : 2; + return IOSPasskeysM2Enabled() ? 3 : 2; } } // namespace @@ -137,8 +133,7 @@ } base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - password_manager::features::kIOSPasskeysM2); + scoped_feature_list.InitAndEnableFeature(kIOSPasskeysM2); // Re-create the controller so that the enabled flag is picked up. CreateController();
diff --git a/ios/chrome/browser/settings/ui_bundled/password/passwords_in_other_apps/BUILD.gn b/ios/chrome/browser/settings/ui_bundled/password/passwords_in_other_apps/BUILD.gn index abfa5fd..a7c8e34 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/passwords_in_other_apps/BUILD.gn +++ b/ios/chrome/browser/settings/ui_bundled/password/passwords_in_other_apps/BUILD.gn
@@ -34,7 +34,6 @@ "//components/strings", "//ios/chrome/app/strings", "//ios/chrome/browser/settings/ui_bundled:settings_root", - "//ios/chrome/browser/settings/ui_bundled/password:features", "//ios/chrome/browser/settings/ui_bundled/resources", "//ios/chrome/browser/settings/ui_bundled/utils", "//ios/chrome/browser/shared/public/features", @@ -69,7 +68,6 @@ ":passwords_in_other_apps", ":passwords_in_other_apps_ui", "//base/test:test_support", - "//ios/chrome/browser/settings/ui_bundled/password:features", "//ios/chrome/browser/settings/ui_bundled/password/password_settings:common", "//ios/chrome/browser/settings/ui_bundled/password/reauthentication:reauthentication_ui", "//ios/chrome/browser/settings/ui_bundled/utils",
diff --git a/ios/chrome/browser/settings/ui_bundled/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm b/ios/chrome/browser/settings/ui_bundled/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm index 63eaadf9..f98b7f4 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm +++ b/ios/chrome/browser/settings/ui_bundled/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.mm
@@ -5,7 +5,6 @@ #import "ios/chrome/browser/settings/ui_bundled/password/passwords_in_other_apps/passwords_in_other_apps_view_controller.h" #import "base/ios/ios_util.h" -#import "ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h" #import "ios/chrome/browser/settings/ui_bundled/password/passwords_in_other_apps/constants.h" #import "ios/chrome/browser/settings/ui_bundled/password/passwords_in_other_apps/passwords_in_other_apps_view_controller_delegate.h" #import "ios/chrome/browser/settings/ui_bundled/settings_navigation_controller.h" @@ -29,8 +28,6 @@ namespace { -using ::password_manager::features::IOSPasskeysM2Enabled; - CGFloat const kCaptionTextViewOffset = 16; CGFloat const kDefaultMargin = 16; CGFloat const kTitleTopMinimumMargin = 48; @@ -543,7 +540,6 @@ - (UIView*)turnOffInstructionView { if (!_turnOffInstructionView) { UITextView* captionTextView = [self drawCaptionTextView]; - NSLog(@"%@", captionTextView.text); UIImage* checkmark = [[UIImage imageNamed:@"settings_safe_state"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; UIImageView* checkmarkView = [[UIImageView alloc] initWithImage:checkmark]; @@ -622,9 +618,7 @@ } - (BOOL)useShortInstruction { - return ios::provider::SupportShortenedInstructionForPasswordAutoFill() && - base::FeatureList::IsEnabled( - kEnableShortenedPasswordAutoFillInstruction); + return ios::provider::SupportShortenedInstructionForPasswordAutoFill(); } - (NSArray<NSString*>*)steps {
diff --git a/ios/chrome/browser/shared/public/features/BUILD.gn b/ios/chrome/browser/shared/public/features/BUILD.gn index e454581..6c384f5 100644 --- a/ios/chrome/browser/shared/public/features/BUILD.gn +++ b/ios/chrome/browser/shared/public/features/BUILD.gn
@@ -11,6 +11,7 @@ "//components/country_codes", "//components/segmentation_platform/embedder/home_modules:constants", "//components/segmentation_platform/public", + "//components/sync/base:features", "//components/version_info:channel", "//ios/chrome/app:background_mode_buildflags", "//ios/chrome/browser/ntp/shared/metrics:constants",
diff --git a/ios/chrome/browser/shared/public/features/features.h b/ios/chrome/browser/shared/public/features/features.h index acba01a..d11c2fd 100644 --- a/ios/chrome/browser/shared/public/features/features.h +++ b/ios/chrome/browser/shared/public/features/features.h
@@ -357,10 +357,6 @@ // Feature flag to enable duplicate NTP cleanup. BASE_DECLARE_FEATURE(kRemoveExcessNTPs); -// Feature flag to enable shortened instruction to turn on Password AutoFill for -// Chrome. -BASE_DECLARE_FEATURE(kEnableShortenedPasswordAutoFillInstruction); - // Feature flag / Kill Switch for TCRex. BASE_DECLARE_FEATURE(kTCRexKillSwitch); @@ -1000,4 +996,11 @@ // Returns whether 'kFRESignInSecondaryActionLabelUpdate' is enabled bool FRESignInSecondaryActionLabelUpdate(); +// Enables passkey syncing follow-up features. +BASE_DECLARE_FEATURE(kIOSPasskeysM2); + +// Helper function returning the status of `kIOSPasskeysM2` and the M1 +// prerequisite. +bool IOSPasskeysM2Enabled(); + #endif // IOS_CHROME_BROWSER_SHARED_PUBLIC_FEATURES_FEATURES_H_
diff --git a/ios/chrome/browser/shared/public/features/features.mm b/ios/chrome/browser/shared/public/features/features.mm index d5e4d89..868a1a3 100644 --- a/ios/chrome/browser/shared/public/features/features.mm +++ b/ios/chrome/browser/shared/public/features/features.mm
@@ -11,6 +11,7 @@ #import "base/metrics/field_trial_params.h" #import "components/country_codes/country_codes.h" #import "components/segmentation_platform/public/features.h" +#import "components/sync/base/features.h" #import "components/version_info/channel.h" #import "ios/chrome/app/background_mode_buildflags.h" #import "ios/chrome/browser/ntp/shared/metrics/feed_metrics_constants.h" @@ -299,10 +300,6 @@ "RemoveExcessNTPs", base::FEATURE_ENABLED_BY_DEFAULT); -BASE_FEATURE(kEnableShortenedPasswordAutoFillInstruction, - "EnableShortenedPasswordAutoFillInstruction", - base::FEATURE_ENABLED_BY_DEFAULT); - BASE_FEATURE(kTCRexKillSwitch, "kTCRexKillSwitch", base::FEATURE_DISABLED_BY_DEFAULT); @@ -1220,3 +1217,12 @@ bool FRESignInSecondaryActionLabelUpdate() { return base::FeatureList::IsEnabled(kFRESignInSecondaryActionLabelUpdate); } + +BASE_FEATURE(kIOSPasskeysM2, + "IOSPasskeysM2", + base::FEATURE_DISABLED_BY_DEFAULT); + +bool IOSPasskeysM2Enabled() { + return syncer::IsWebauthnCredentialSyncEnabled() && + base::FeatureList::IsEnabled(kIOSPasskeysM2); +}
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn index 6570e3d..dd99125 100644 --- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -364,6 +364,7 @@ "//ios/chrome/browser/ntp/model:set_up_list_prefs", "//ios/chrome/browser/ntp/shared/metrics:home_metrics", "//ios/chrome/browser/ntp/ui_bundled", + "//ios/chrome/browser/parcel_tracking:features", "//ios/chrome/browser/reading_list/model", "//ios/chrome/browser/reading_list/model:test_support", "//ios/chrome/browser/safety_check/model:constants",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn index aee6ad43..f645116 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
@@ -46,6 +46,7 @@ "//ios/chrome/browser/ui/content_suggestions:content_suggestions_constant", "//ios/chrome/browser/ui/content_suggestions:public", "//ios/chrome/browser/ui/content_suggestions/cells/resources", + "//ios/chrome/browser/ui/content_suggestions/magic_stack:constants", "//ios/chrome/common:timing", "//ios/chrome/common/ui/colors", "//ios/chrome/common/ui/elements", @@ -100,6 +101,7 @@ "//ios/chrome/browser/ui/content_suggestions:metrics", "//ios/chrome/browser/ui/content_suggestions:public", "//ios/chrome/browser/ui/content_suggestions/magic_stack:public", + "//ios/chrome/browser/ui/content_suggestions/magic_stack:utils", "//ios/chrome/browser/url_loading/model", "//ios/chrome/browser/url_loading/model:url_loading_params_header", "//ios/chrome/browser/widget_kit/model:features",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_view.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_view.mm index df3240fd..7b7b42c 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_view.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_view.mm
@@ -171,11 +171,13 @@ UIContentSizeCategory category = self.traitCollection.preferredContentSizeCategory; NSComparisonResult result = UIContentSizeCategoryCompareToCategory( - category, UIContentSizeCategoryExtraLarge); + category, UIContentSizeCategoryExtraExtraExtraLarge); if (result == NSOrderedAscending) { self.titleLabel.numberOfLines = kLabelNumLines; + self.titleLabel.lineBreakMode = NSLineBreakByCharWrapping; } else { self.titleLabel.numberOfLines = 1; + self.titleLabel.lineBreakMode = NSLineBreakByTruncatingTail; } }
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/icon_detail_view.mm b/ios/chrome/browser/ui/content_suggestions/cells/icon_detail_view.mm index 8e22518..5b921b1 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/icon_detail_view.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/icon_detail_view.mm
@@ -7,6 +7,7 @@ #import "ios/chrome/browser/shared/ui/symbols/symbols.h" #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h" #import "ios/chrome/browser/ui/content_suggestions/cells/icon_view.h" +#import "ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_constants.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" #import "ios/chrome/common/ui/elements/gradient_view.h" #import "ios/chrome/common/ui/util/constraints_ui_util.h" @@ -711,10 +712,18 @@ label.translatesAutoresizingMaskIntoConstraints = NO; label.numberOfLines = 0; label.lineBreakMode = NSLineBreakByWordWrapping; - label.font = - _layoutType == IconDetailViewLayoutType::kHero - ? CreateDynamicFont(UIFontTextStyleFootnote, UIFontWeightSemibold) - : [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]; + if (_layoutType == IconDetailViewLayoutType::kHero) { + label.font = [[UIFontMetrics defaultMetrics] + scaledFontForFont:CreateDynamicFont(UIFontTextStyleFootnote, + UIFontWeightSemibold) + maximumPointSize:kMaxTextSizeForStyleFootnote]; + } else { + label.font = [[UIFontMetrics defaultMetrics] + scaledFontForFont:[UIFont + preferredFontForTextStyle:UIFontTextStyleFootnote] + maximumPointSize:kMaxTextSizeForStyleFootnote]; + } + label.adjustsFontForContentSizeCategory = YES; label.textColor = [UIColor colorNamed:kTextPrimaryColor]; @@ -729,7 +738,10 @@ label.text = _description; label.numberOfLines = 2; label.lineBreakMode = NSLineBreakByTruncatingTail; - label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]; + label.font = [[UIFontMetrics defaultMetrics] + scaledFontForFont:[UIFont + preferredFontForTextStyle:UIFontTextStyleFootnote] + maximumPointSize:kMaxTextSizeForStyleFootnote]; label.adjustsFontForContentSizeCategory = YES; label.textColor = [UIColor colorNamed:kTextSecondaryColor];
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_mediator.h b/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_mediator.h index 206d411..faee516 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_mediator.h +++ b/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_mediator.h
@@ -104,6 +104,9 @@ // Trigger a refresh of the Most Visited tiles. - (void)refreshMostVisitedTiles; +// Disable the most visited sites module. +- (void)disableModule; + @end #endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_MOST_VISITED_TILES_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_mediator.mm b/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_mediator.mm index 687d8da..4d0e256 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_mediator.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_mediator.mm
@@ -146,6 +146,10 @@ _mostVisitedSites->Refresh(); } +- (void)disableModule { + _prefService->SetBoolean(prefs::kHomeCustomizationMostVisitedEnabled, false); +} + - (MostVisitedTilesConfig*)mostVisitedTilesConfig { return _mostVisitedConfig; }
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_stack_view.mm b/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_stack_view.mm index b8da76c4..072c4a3 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_stack_view.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_stack_view.mm
@@ -4,6 +4,7 @@ #import "ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_stack_view.h" +#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile_view.h" #import "ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_commands.h" @@ -11,17 +12,35 @@ #import "ios/chrome/browser/ui/content_suggestions/cells/most_visited_tiles_stack_view_consumer_source.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_image_data_source.h" +#import "ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_utils.h" #import "ios/chrome/common/ui/favicon/favicon_attributes.h" #import "ios/chrome/common/ui/favicon/favicon_view.h" #import "url/gurl.h" -@implementation MostVisitedTilesStackView +@implementation MostVisitedTilesStackView { + NSLayoutConstraint* _heightConstraint; + BOOL _inMagicStack; +} - (instancetype)initWithConfig:(MostVisitedTilesConfig*)config spacing:(CGFloat)spacing { if ((self = [super init])) { if (config.inMagicStack) { + _inMagicStack = YES; [config.consumerSource addConsumer:self]; + + _heightConstraint = [self.heightAnchor + constraintLessThanOrEqualToConstant:GetMagicStackHeight(self) - 10]; + _heightConstraint.active = YES; + + if (@available(iOS 17, *)) { + NSArray<UITrait>* traits = TraitCollectionSetForTraits( + @[ UITraitPreferredContentSizeCategory.class ]); + [self registerForTraitChanges:traits + withAction:@selector(updateHeight)]; + } + } else { + _inMagicStack = NO; } self.axis = UILayoutConstraintAxisHorizontal; self.distribution = UIStackViewDistributionFillEqually; @@ -32,6 +51,21 @@ return self; } +#if !defined(__IPHONE_17_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_17_0 +- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection { + [super traitCollectionDidChange:previousTraitCollection]; + if (@available(iOS 17, *)) { + return; + } + + if (previousTraitCollection.preferredContentSizeCategory != + self.traitCollection.preferredContentSizeCategory && + _inMagicStack) { + [self updateHeight]; + } +} +#endif + #pragma mark - MostVisitedTilesStackViewConsumer - (void)updateWithConfig:(MostVisitedTilesConfig*)config { @@ -80,4 +114,9 @@ } } +// Resizes the Most Visted card height. +- (void)updateHeight { + _heightConstraint.constant = GetMagicStackHeight(self) - 10; +} + @end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm index 6ebec48..a3a0b58 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
@@ -854,6 +854,9 @@ - (void)neverShowModuleType:(ContentSuggestionsModuleType)type { switch (type) { + case ContentSuggestionsModuleType::kMostVisited: + [_mostVisitedTilesMediator disableModule]; + break; case ContentSuggestionsModuleType::kTabResumption: [_tabResumptionMediator disableModule]; break;
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/magic_stack/BUILD.gn index e82c11c..d729d522 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack/BUILD.gn
@@ -121,6 +121,7 @@ ":constants", ":magic_stack_module_content_view_delegate", ":public", + ":utils", "//base", "//google_apis", "//ios/chrome/app/strings", @@ -228,6 +229,7 @@ "//ios/chrome/browser/first_run/ui_bundled:utils", "//ios/chrome/browser/ntp/model:set_up_list_prefs", "//ios/chrome/browser/ntp/shared/metrics:constants", + "//ios/chrome/browser/parcel_tracking:features", "//ios/chrome/browser/reading_list/model", "//ios/chrome/browser/reading_list/model:test_support", "//ios/chrome/browser/safety_check/model:factory",
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_collection_view.mm b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_collection_view.mm index 0877d88c..04b98ff 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_collection_view.mm +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_collection_view.mm
@@ -55,6 +55,7 @@ // The most recently selected MagicStack module's page index. NSUInteger _magicStackPage; BOOL _hasSeenEphemeralCard; + NSLayoutConstraint* _heightConstraint; } - (void)loadView { @@ -63,9 +64,20 @@ [self populateWithPlaceholders]; self.view = _collectionView; - [NSLayoutConstraint - activateConstraints:@[ [_collectionView.heightAnchor - constraintEqualToConstant:kModuleMaxHeight] ]]; + + if (@available(iOS 17, *)) { + NSArray<UITrait>* traits = TraitCollectionSetForTraits( + @[ UITraitPreferredContentSizeCategory.class ]); + [self registerForTraitChanges:traits + withAction:@selector(updateCardHeightOnTraitChange)]; + } +} + +- (void)viewDidLoad { + _heightConstraint = [_collectionView.heightAnchor + constraintEqualToConstant:GetMagicStackHeight(self.view)]; + + [NSLayoutConstraint activateConstraints:@[ _heightConstraint ]]; } - (void)viewWillLayoutSubviews { @@ -91,6 +103,20 @@ completion:nil]; } +#if !defined(__IPHONE_17_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_17_0 +- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection { + [super traitCollectionDidChange:previousTraitCollection]; + if (@available(iOS 17, *)) { + return; + } + + if (previousTraitCollection.preferredContentSizeCategory != + self.traitCollection.preferredContentSizeCategory) { + [self updateCardHeightOnTraitChange]; + } +} +#endif + #pragma mark - Public - (void)moduleWidthDidUpdate { @@ -489,4 +515,12 @@ } } +// Resizes the Magic Stack card height. +- (void)updateCardHeightOnTraitChange { + _heightConstraint.constant = GetMagicStackHeight(self.view); + + [_magicStackCollectionViewLayoutConfigurator + .magicStackCompositionalLayout invalidateLayout]; +} + @end
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_collection_view_unittest.mm b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_collection_view_unittest.mm index e4d1506c5..d472990 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_collection_view_unittest.mm +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_collection_view_unittest.mm
@@ -39,6 +39,7 @@ audience_ = OCMStrictProtocolMock( @protocol(MagicStackCollectionViewControllerAudience)); view_controller_.audience = audience_; + [view_controller_ loadViewIfNeeded]; [view_controller_ viewDidLoad]; [_window addSubview:[view_controller_ view]]; AddSameConstraints(_window, [view_controller_ view]);
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_constants.h b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_constants.h index 1cce039..d1d20f8 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_constants.h +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_constants.h
@@ -11,8 +11,8 @@ extern NSString* const kMagicStackSectionIdentifier; extern NSString* const kMagicStackEditSectionIdentifier; -// The max height of the modules. -extern const int kModuleMaxHeight; +// The max text size of text with the Footnote Text Style. +extern const int kMaxTextSizeForStyleFootnote; // The spacing between modules in the Magic Stack. extern const CGFloat kMagicStackSpacing;
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_constants.mm b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_constants.mm index 3cfdd3b7b..2796635 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_constants.mm +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_constants.mm
@@ -9,7 +9,7 @@ NSString* const kMagicStackEditSectionIdentifier = @"MagicStackEditSectionIdentifier"; -const int kModuleMaxHeight = 150; +const int kMaxTextSizeForStyleFootnote = 24; const CGFloat kMagicStackSpacing = 12.0f;
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_collection_view_cell.mm b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_collection_view_cell.mm index 9745294c..bcb2841 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_collection_view_cell.mm +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_collection_view_cell.mm
@@ -196,6 +196,7 @@ case ContentSuggestionsModuleType::kSendTabPromo: case ContentSuggestionsModuleType::kTipsWithProductImage: case ContentSuggestionsModuleType::kTips: + case ContentSuggestionsModuleType::kMostVisited: return YES; default: return NO; @@ -327,6 +328,9 @@ case ContentSuggestionsModuleType::kTips: return l10n_util::GetNSString( IDS_IOS_MAGIC_STACK_TIP_CONTEXT_MENU_DESCRIPTION); + case ContentSuggestionsModuleType::kMostVisited: + return l10n_util::GetNSString( + IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_CONTEXT_MENU_DESCRIPTION); default: NOTREACHED(); } @@ -371,6 +375,9 @@ IDS_IOS_MAGIC_STACK_TIP_CONTEXT_MENU_HIDE_CHROME_TIPS, base::SysNSStringToUTF16( l10n_util::GetNSString(IDS_IOS_MAGIC_STACK_TIP_TITLE))); + case ContentSuggestionsModuleType::kMostVisited: + return l10n_util::GetNSString( + IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_HIDE_CARD); default: NOTREACHED(); }
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_container.mm b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_container.mm index ce435f6..a31acae9 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_container.mm +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_container.mm
@@ -18,6 +18,7 @@ #import "ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_container_delegate.h" #import "ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_content_view_delegate.h" #import "ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_module_contents_factory.h" +#import "ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_utils.h" #import "ios/chrome/browser/ui/content_suggestions/safety_check/safety_check_state.h" #import "ios/chrome/browser/ui/content_suggestions/safety_check/utils.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" @@ -40,6 +41,7 @@ // The bottom inset for the content within this container. const CGFloat kContentBottomInset = 24.0f; const CGFloat kReducedContentBottomInset = 10.0f; +const CGFloat kOversizedReducedContentBottomInset = 20.0f; // Vertical spacing between the content views. const CGFloat kContentVerticalSpacing = 16.0f; @@ -69,6 +71,7 @@ NSLayoutConstraint* _containerHeightAnchor; NSLayoutConstraint* _contentStackViewBottomMarginAnchor; ContentSuggestionsModuleType _type; + BOOL _reducedBottomMargin; } - (instancetype)initWithFrame:(CGRect)frame { @@ -91,6 +94,7 @@ _title.textColor = [UIColor colorNamed:kTextPrimaryColor]; _title.numberOfLines = 1; _title.lineBreakMode = NSLineBreakByTruncatingTail; + _title.adjustsFontForContentSizeCategory = YES; _title.accessibilityTraits |= UIAccessibilityTraitHeader; [_title setContentHuggingPriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal]; @@ -110,6 +114,9 @@ [_title.bottomAnchor constraintEqualToAnchor:_titleStackView.bottomAnchor] ]]; + _containerHeightAnchor = [self.heightAnchor + constraintLessThanOrEqualToConstant:GetMagicStackHeight(_stackView)]; + _seeMoreButton = [self actionButton:l10n_util::GetNSString(IDS_IOS_MAGIC_STACK_SEE_MORE)]; _seeMoreButton.hidden = YES; @@ -130,11 +137,14 @@ _subtitle = [[UILabel alloc] init]; _subtitle.hidden = YES; - _subtitle.font = [MagicStackModuleContainer fontForSubtitle]; + _subtitle.font = [[UIFontMetrics defaultMetrics] + scaledFontForFont:[MagicStackModuleContainer fontForSubtitle] + maximumPointSize:kMaxTextSizeForStyleFootnote]; _subtitle.textColor = [UIColor colorNamed:kTextSecondaryColor]; _subtitle.numberOfLines = 0; _subtitle.lineBreakMode = NSLineBreakByWordWrapping; _subtitle.accessibilityTraits |= UIAccessibilityTraitHeader; + _subtitle.maximumContentSizeCategory = UIContentSizeCategoryMedium; [_subtitle setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; [_subtitle @@ -168,10 +178,6 @@ constraintEqualToAnchor:_stackView.trailingAnchor], ]]; - _containerHeightAnchor = - [self.heightAnchor constraintEqualToConstant:kModuleMaxHeight]; - [NSLayoutConstraint activateConstraints:@[ _containerHeightAnchor ]]; - [self addSubview:_stackView]; AddSameConstraintsToSidesWithInsets( _stackView, self, @@ -194,9 +200,11 @@ if (!strongSelf) { return; } - strongSelf->_title.font = [strongSelf fontForTitle]; + [weakSelf updateTitleFont]; }; [self registerForTraitChanges:traits withHandler:handler]; + [self registerForTraitChanges:traits + withAction:@selector(updateCardSizing)]; } } return self; @@ -250,7 +258,7 @@ [self resetView]; // By default, the container is in the magic stack. BOOL inMagicStack = YES; - // Ensures that the modules conforms to a height of kModuleMaxHeight. For + // Ensures that the modules conforms to the dynamic MS height. For // the MVT when it lives outside of the Magic Stack to stay as close to its // intrinsic size as possible, the constraint is configured to be less than // or equal to. @@ -263,8 +271,6 @@ self.layer.cornerRadius = kCornerRadius; self.clipsToBounds = YES; _containerHeightAnchor.active = NO; - _containerHeightAnchor = [self.heightAnchor - constraintLessThanOrEqualToConstant:kModuleMaxHeight]; [NSLayoutConstraint activateConstraints:@[ _containerHeightAnchor ]]; } } @@ -421,6 +427,11 @@ return CreateDynamicFont(UIFontTextStyleFootnote, UIFontWeightRegular); } +// Updates the title font. +- (void)updateTitleFont { + _title.font = [self fontForTitle]; +} + // Updates the bottom content margins if the module contents need it. - (void)updateBottomContentMarginsForConfig:(MagicStackModule*)config { switch (config.type) { @@ -428,19 +439,25 @@ case ContentSuggestionsModuleType::kShortcuts: case ContentSuggestionsModuleType::kCompactedSetUpList: _contentStackViewBottomMarginAnchor.constant = - -kReducedContentBottomInset; + isContentOversized(_stackView) ? -kOversizedReducedContentBottomInset + : -kReducedContentBottomInset; + _reducedBottomMargin = true; break; case ContentSuggestionsModuleType::kSafetyCheck: { SafetyCheckState* safetyCheckConfig = static_cast<SafetyCheckState*>(config); if ([safetyCheckConfig numberOfIssues] > 1) { _contentStackViewBottomMarginAnchor.constant = - -kReducedContentBottomInset; + isContentOversized(_stackView) + ? -kOversizedReducedContentBottomInset + : -kReducedContentBottomInset; + _reducedBottomMargin = true; } break; } default: + _reducedBottomMargin = false; break; } } @@ -457,6 +474,7 @@ if (previousTraitCollection.preferredContentSizeCategory != self.traitCollection.preferredContentSizeCategory) { _title.font = [self fontForTitle]; + [self updateCardSizing]; } } #endif @@ -540,4 +558,14 @@ } } +// Updates the card sizing based on the dynamic Magic Stack Height. +- (void)updateCardSizing { + _containerHeightAnchor.constant = GetMagicStackHeight(_stackView); + if (_reducedBottomMargin) { + _contentStackViewBottomMarginAnchor.constant = + isContentOversized(_stackView) ? -kOversizedReducedContentBottomInset + : -kReducedContentBottomInset; + } +} + @end
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_ranking_model_unittest.mm b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_ranking_model_unittest.mm index 0dee0d3..b45c192 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_ranking_model_unittest.mm +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_ranking_model_unittest.mm
@@ -38,6 +38,7 @@ #import "ios/chrome/browser/first_run/ui_bundled/first_run_util.h" #import "ios/chrome/browser/ntp/model/set_up_list_prefs.h" #import "ios/chrome/browser/ntp/shared/metrics/feed_metrics_constants.h" +#import "ios/chrome/browser/parcel_tracking/features.h" #import "ios/chrome/browser/reading_list/model/reading_list_model_factory.h" #import "ios/chrome/browser/reading_list/model/reading_list_test_utils.h" #import "ios/chrome/browser/safety_check/model/ios_chrome_safety_check_manager_factory.h" @@ -239,7 +240,8 @@ segmentation_platform::kEphemeralModuleBackendRankerTestOverride, "price_tracking_notification_promo"); scoped_feature_list_.InitWithFeaturesAndParameters( - {{kMagicStack, {{kMagicStackMostVisitedModuleParam, "true"}}}}, {}); + {{kMagicStack, {{kMagicStackMostVisitedModuleParam, "true"}}}}, + {kIOSDisableParcelTracking}); TestProfileIOS::Builder builder; builder.AddTestingFactory( @@ -734,7 +736,7 @@ {{segmentation_platform::features:: kEphemeralCardRankerForceShowCardParam, segmentation_platform::kPriceTrackingNotificationPromo}}}}, - {}); + {kIOSDisableParcelTracking}); commerce::MockShoppingService* shopping_service = static_cast<commerce::MockShoppingService*>( commerce::ShoppingServiceFactory::GetForProfile(GetProfile()));
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_utils.h b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_utils.h index c2e8524b..08532a0 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_utils.h +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_utils.h
@@ -24,4 +24,10 @@ AuthenticationService* auth_service, PrefService* pref_service); +/// True if the user's preferred content size is an accessibility size. +bool isContentOversized(id<UITraitEnvironment> trait_environment); + +/// Returns the dynamic height of the Magic Stack modules. +CGFloat GetMagicStackHeight(id<UITraitEnvironment> trait_environment); + #endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_MAGIC_STACK_MAGIC_STACK_UTILS_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_utils.mm b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_utils.mm index 9d608fe..694138d1 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_utils.mm +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack/magic_stack_utils.mm
@@ -59,3 +59,32 @@ base::ToLowerASCII(GetCurrentCountryCode( GetApplicationContext()->GetVariationsService())) == "us")); } + +bool isContentOversized(id<UITraitEnvironment> trait_environment) { + // The preferred content size of the user's device. + NSString* preferred_content_size = + trait_environment.traitCollection.preferredContentSizeCategory; + NSComparisonResult result = UIContentSizeCategoryCompareToCategory( + preferred_content_size, UIContentSizeCategoryAccessibilityMedium); + return result != NSOrderedAscending; +} + +CGFloat GetMagicStackHeight(id<UITraitEnvironment> trait_environment) { + // The preferred content size of the user's device. + NSString* preferred_content_size = + trait_environment.traitCollection.preferredContentSizeCategory; + if (isContentOversized(trait_environment)) { + // The maximum Magic Stack height in px. + return 190; + } else if (preferred_content_size == + UIContentSizeCategoryExtraExtraExtraLarge) { + return 180; + } else if (preferred_content_size == UIContentSizeCategoryExtraExtraLarge) { + return 170; + } else if (preferred_content_size == UIContentSizeCategoryExtraLarge) { + return 160; + } else { + // The minimum Magic Stack height in px. + return 150; + } +}
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack_half_sheet_mediator_unittest.mm b/ios/chrome/browser/ui/content_suggestions/magic_stack_half_sheet_mediator_unittest.mm index 1cef203..7fd1f88e 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack_half_sheet_mediator_unittest.mm +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack_half_sheet_mediator_unittest.mm
@@ -12,6 +12,7 @@ #import "ios/chrome/browser/first_run/ui_bundled/first_run_util.h" #import "ios/chrome/browser/metrics/model/constants.h" #import "ios/chrome/browser/ntp/model/set_up_list_prefs.h" +#import "ios/chrome/browser/parcel_tracking/features.h" #import "ios/chrome/browser/shared/model/application_context/application_context.h" #import "ios/chrome/browser/shared/model/prefs/pref_names.h" #import "ios/chrome/browser/shared/public/features/features.h" @@ -30,8 +31,8 @@ class MagicStackHalfSheetMediatorTest : public PlatformTest { public: void SetUp() override { - scoped_feature_list_.InitWithFeatures({kTabResumption, kNewFeedPositioning}, - {}); + scoped_feature_list_.InitWithFeatures( + {kTabResumption, kNewFeedPositioning}, {kIOSDisableParcelTracking}); pref_service_ = std::make_unique<TestingPrefServiceSimple>(); // Necessary set up for kIOSSetUpList.
diff --git a/ios/chrome/browser/ui/content_suggestions/magic_stack_half_sheet_table_view_controller_unittest.mm b/ios/chrome/browser/ui/content_suggestions/magic_stack_half_sheet_table_view_controller_unittest.mm index f525b17..2e2cd76 100644 --- a/ios/chrome/browser/ui/content_suggestions/magic_stack_half_sheet_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/content_suggestions/magic_stack_half_sheet_table_view_controller_unittest.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/ui/content_suggestions/magic_stack_half_sheet_table_view_controller.h" #import "base/test/scoped_feature_list.h" +#import "ios/chrome/browser/parcel_tracking/features.h" #import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_switch_item.h" #import "ios/chrome/browser/shared/ui/table_view/table_view_utils.h" @@ -18,7 +19,8 @@ class MagicStackHalfSheetTableViewControllerUnittest : public PlatformTest { public: void SetUp() override { - scoped_feature_list_.InitWithFeatures({kTabResumption}, {}); + scoped_feature_list_.InitWithFeatures( + {kTabResumption}, {kIOSDisableParcelTracking}); view_controller_ = [[MagicStackHalfSheetTableViewController alloc] init]; }
diff --git a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_item_view.mm b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_item_view.mm index 01758e82..a3b7b59 100644 --- a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_item_view.mm +++ b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_item_view.mm
@@ -35,7 +35,7 @@ constexpr CGFloat kPadding = 15; // The spacing between the title and description labels. -constexpr CGFloat kTextSpacing = 5; +constexpr CGFloat kTextSpacing = 2; constexpr CGFloat kCompactTextSpacing = 0; // The duration of the icon / label crossfade animation. @@ -152,12 +152,6 @@ kTextSpacing, }; } - if (@available(iOS 17, *)) { - NSArray<UITrait>* traits = TraitCollectionSetForTraits( - @[ UITraitPreferredContentSizeCategory.class ]); - [self registerForTraitChanges:traits - withAction:@selector(hideDescriptionOnTraitChange)]; - } } return self; } @@ -183,11 +177,6 @@ if (@available(iOS 17, *)) { return; } - - if (previousTraitCollection.preferredContentSizeCategory != - self.traitCollection.preferredContentSizeCategory) { - [self hideDescriptionOnTraitChange]; - } } #endif @@ -298,6 +287,8 @@ textStack.axis = UILayoutConstraintAxisVertical; textStack.translatesAutoresizingMaskIntoConstraints = NO; textStack.spacing = _config.text_spacing; + textStack.maximumContentSizeCategory = + UIContentSizeCategoryAccessibilityMedium; // Add a horizontal stack to contain the icon(s) and the text stack. NSArray* arrangedSubviews = putIconInSquareBackground @@ -358,6 +349,10 @@ if (_complete) { label.attributedText = Strikethrough(label.text); } + // Set height constraint. Applicable for larger text. + [NSLayoutConstraint activateConstraints:@[ [label.heightAnchor + constraintEqualToConstant:26] ]]; + [label setContentCompressionResistancePriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisVertical]; @@ -442,16 +437,6 @@ } } -// Hides `_description` if the font size category is larger than -// extra-extra-large. -- (void)hideDescriptionOnTraitChange { - _description.hidden = self.traitCollection.preferredContentSizeCategory > - UIContentSizeCategoryExtraExtraLarge; - // Force a layout since the size of text components may have changed. - [self setNeedsLayout]; - [self layoutIfNeeded]; -} - #pragma mark - Private methods (animation helpers) // Sets the various subview properties that should be animated.
diff --git a/ios/chrome/common/credential_provider/constants.h b/ios/chrome/common/credential_provider/constants.h index 4fefa4a7..2681ed3 100644 --- a/ios/chrome/common/credential_provider/constants.h +++ b/ios/chrome/common/credential_provider/constants.h
@@ -23,18 +23,18 @@ // Key for the app group user defaults containing whether saving passwords and // passkeys is currently enabled. -NSString* AppGroupUserDefaulsCredentialProviderSavingPasswordsEnabled(); +NSString* AppGroupUserDefaultsCredentialProviderSavingPasswordsEnabled(); // Key for the app group user defaults containing whether saving passwords is // currently managed by an enterprise policy. -NSString* AppGroupUserDefaulsCredentialProviderSavingPasswordsManaged(); +NSString* AppGroupUserDefaultsCredentialProviderSavingPasswordsManaged(); // Key for the app group user defaults indicating whether saving passkeys is // allowed by enterprise policy. Even if this is set to `YES`, passkey creation // could still be blocked by `...CredentialProviderSavingPasswordsEnabled` // above. This pref is only configurable by enterprise policy, not by users, so // if this is set to `NO` then it is because the behavior is managed. -NSString* AppGroupUserDefaulsCredentialProviderSavingPasskeysEnabled(); +NSString* AppGroupUserDefaultsCredentialProviderSavingPasskeysEnabled(); // Key for the app group user defaults containing whether syncing passwords is // currently enabled. @@ -44,6 +44,10 @@ // currently enabled. NSString* AppGroupUserDefaulsCredentialProviderPasskeyPRFEnabled(); +// Key for the app group user defaults containing whether the passkeys M2 +// feature is currently enabled. +NSString* AppGroupUserDefaultsCredentialProviderPasskeysM2Enabled(); + // Key for the app group user defaults indicating if the credentials have been // synced with iOS via AuthenticationServices. extern NSString* const
diff --git a/ios/chrome/common/credential_provider/constants.mm b/ios/chrome/common/credential_provider/constants.mm index e606f7b..e736ca4 100644 --- a/ios/chrome/common/credential_provider/constants.mm +++ b/ios/chrome/common/credential_provider/constants.mm
@@ -61,6 +61,11 @@ NSString* const kUserDefaultsCredentialProviderPasskeyPRFSetting = @"kUserDefaultsCredentialProviderPasskeyPRFSetting"; +// Used to generate the key for the app group user defaults containing whether +// the passkeys M2 feature is currently enabled. +NSString* const kUserDefaultsCredentialProviderPasskeysM2Enabled = + @"kUserDefaultsCredentialProviderPasskeysM2Enabled"; + // Used to generate a unique AppGroupPrefix to differentiate between different // versions of Chrome running in the same device. NSString* AppGroupPrefix() { @@ -115,19 +120,19 @@ stringByAppendingString:kUserDefaultsCredentialProviderNewCredentials]; } -NSString* AppGroupUserDefaulsCredentialProviderSavingPasswordsEnabled() { +NSString* AppGroupUserDefaultsCredentialProviderSavingPasswordsEnabled() { return [AppGroupPrefix() stringByAppendingString: kUserDefaulsCredentialProviderSavingPasswordsEnabled]; } -NSString* AppGroupUserDefaulsCredentialProviderSavingPasswordsManaged() { +NSString* AppGroupUserDefaultsCredentialProviderSavingPasswordsManaged() { return [AppGroupPrefix() stringByAppendingString: kUserDefaultsCredentialProviderSavingPasswordsManaged]; } -NSString* AppGroupUserDefaulsCredentialProviderSavingPasskeysEnabled() { +NSString* AppGroupUserDefaultsCredentialProviderSavingPasskeysEnabled() { return [AppGroupPrefix() stringByAppendingString: kUserDefaulsCredentialProviderSavingPasskeysEnabled]; @@ -143,3 +148,8 @@ return [AppGroupPrefix() stringByAppendingString:kUserDefaultsCredentialProviderPasskeyPRFSetting]; } + +NSString* AppGroupUserDefaultsCredentialProviderPasskeysM2Enabled() { + return [AppGroupPrefix() + stringByAppendingString:kUserDefaultsCredentialProviderPasskeysM2Enabled]; +}
diff --git a/ios/chrome/credential_provider_extension/ui/feature_flags.h b/ios/chrome/credential_provider_extension/ui/feature_flags.h index d72b056..fd4112a 100644 --- a/ios/chrome/credential_provider_extension/ui/feature_flags.h +++ b/ios/chrome/credential_provider_extension/ui/feature_flags.h
@@ -27,4 +27,7 @@ // policy. BOOL IsPasskeyCreationAllowedByPolicy(); +// Whether the passkeys M2 feature is currently enabled. +BOOL IsPasskeysM2Enabled(); + #endif // IOS_CHROME_CREDENTIAL_PROVIDER_EXTENSION_UI_FEATURE_FLAGS_H_
diff --git a/ios/chrome/credential_provider_extension/ui/feature_flags.mm b/ios/chrome/credential_provider_extension/ui/feature_flags.mm index 02d63af..e7cee2cb 100644 --- a/ios/chrome/credential_provider_extension/ui/feature_flags.mm +++ b/ios/chrome/credential_provider_extension/ui/feature_flags.mm
@@ -17,14 +17,14 @@ BOOL IsPasswordCreationUserEnabled() { return [[app_group::GetGroupUserDefaults() objectForKey: - AppGroupUserDefaulsCredentialProviderSavingPasswordsEnabled()] + AppGroupUserDefaultsCredentialProviderSavingPasswordsEnabled()] boolValue]; } BOOL IsPasswordCreationManaged() { return [[app_group::GetGroupUserDefaults() objectForKey: - AppGroupUserDefaulsCredentialProviderSavingPasswordsManaged()] + AppGroupUserDefaultsCredentialProviderSavingPasswordsManaged()] boolValue]; } @@ -36,6 +36,13 @@ BOOL IsPasskeyCreationAllowedByPolicy() { return [[app_group::GetGroupUserDefaults() - objectForKey:AppGroupUserDefaulsCredentialProviderSavingPasskeysEnabled()] + objectForKey: + AppGroupUserDefaultsCredentialProviderSavingPasskeysEnabled()] + boolValue]; +} + +BOOL IsPasskeysM2Enabled() { + return [[app_group::GetGroupUserDefaults() + objectForKey:AppGroupUserDefaultsCredentialProviderPasskeysM2Enabled()] boolValue]; }
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn index beb6b036f..6c80aaf0 100644 --- a/ios/chrome/test/earl_grey/BUILD.gn +++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -101,6 +101,7 @@ "//components/translate/core/browser", "//components/unified_consent", "//components/variations", + "//components/variations/service", "//ios/chrome/app:app_internal", "//ios/chrome/app/application_delegate:app_state", "//ios/chrome/app/strings",
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.h b/ios/chrome/test/earl_grey/chrome_earl_grey.h index 8f820f7..5a8f57c 100644 --- a/ios/chrome/test/earl_grey/chrome_earl_grey.h +++ b/ios/chrome/test/earl_grey/chrome_earl_grey.h
@@ -993,6 +993,11 @@ - (void)requestTipsNotification:(TipsNotificationType)type; +#pragma mark - Variations Utilities + +// Forces an override of the variations stored permanent country. +- (void)overrideVariationsServiceStoredPermanentCountry:(NSString*)country; + @end #endif // IOS_CHROME_TEST_EARL_GREY_CHROME_EARL_GREY_H_
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.mm b/ios/chrome/test/earl_grey/chrome_earl_grey.mm index 0375cb8..285bae50 100644 --- a/ios/chrome/test/earl_grey/chrome_earl_grey.mm +++ b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
@@ -1902,8 +1902,17 @@ return [ChromeEarlGreyAppInterface hasFirstRunSentinel]; } +#pragma mark - Notification Utilities + - (void)requestTipsNotification:(TipsNotificationType)type { return [ChromeEarlGreyAppInterface requestTipsNotification:type]; } +#pragma mark - Variations Utilities + +- (void)overrideVariationsServiceStoredPermanentCountry:(NSString*)country { + return [ChromeEarlGreyAppInterface + overrideVariationsServiceStoredPermanentCountry:country]; +} + @end
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h index eddae7c6a..25640ab 100644 --- a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h +++ b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
@@ -744,6 +744,11 @@ + (void)requestTipsNotification:(TipsNotificationType)type; +#pragma mark - Variations Utilities + +// Forces an override of the variations stored permanent country. ++ (void)overrideVariationsServiceStoredPermanentCountry:(NSString*)country; + @end #endif // IOS_CHROME_TEST_EARL_GREY_CHROME_EARL_GREY_APP_INTERFACE_H_
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm index 51999e6e..e34cdff 100644 --- a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm +++ b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
@@ -33,6 +33,7 @@ #import "components/sync/service/sync_user_settings.h" #import "components/sync/test/fake_server_http_post_provider.h" #import "components/unified_consent/unified_consent_service.h" +#import "components/variations/service/variations_service.h" #import "components/variations/variations_associated_data.h" #import "components/variations/variations_ids_provider.h" #import "ios/chrome/app/application_delegate/app_state.h" @@ -1568,6 +1569,8 @@ return HasFirstRunSentinel(); } +#pragma mark - Notification Utilities + + (void)requestTipsNotification:(TipsNotificationType)type { UNUserNotificationCenter* center = UNUserNotificationCenter.currentNotificationCenter; @@ -1580,4 +1583,13 @@ [center addNotificationRequest:request withCompletionHandler:nil]; } +#pragma mark - Variations Utilities + ++ (void)overrideVariationsServiceStoredPermanentCountry:(NSString*)country { + std::string UTF8Country = base::SysNSStringToUTF8(country); + variations::VariationsService* variationsService = + GetApplicationContext()->GetVariationsService(); + variationsService->OverrideStoredPermanentCountry(UTF8Country); +} + @end
diff --git a/ios/components/security_interstitials/safe_browsing/OWNERS b/ios/components/security_interstitials/safe_browsing/OWNERS new file mode 100644 index 0000000..4db0888 --- /dev/null +++ b/ios/components/security_interstitials/safe_browsing/OWNERS
@@ -0,0 +1 @@ +danieltwhite@google.com
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 62a3c003..39711a4 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 @@ -a5e717b5d9fe678a8a06950824a2a6f6395067aa \ No newline at end of file +76e0304f3c7eb54da7758cefe02c7ecabbb9f69e \ 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 920f468..8fd3b64 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 @@ -2800e223789d188c394f99ff6b471e9f3fbecac5 \ No newline at end of file +532e168f087d8ad075ba0c7551aea0dde5096c22 \ 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 e404a8c..150dc0fd 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 @@ -961c51dc2c57cc9d88a98fd4d34fa6fb8298d88d \ No newline at end of file +6206a84499863947808c3871c4932c7361153511 \ 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 4f7acfad..0c261619 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 @@ -cce7637b65bdb339f2766d212060283e44c07975 \ No newline at end of file +10b2e19eb1abc053496245e25efe717546b849e8 \ 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 29a757f..9e7276ec 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 @@ -9049c1bfdc4a50fc1a9fb21c43a9bcd26c0d33d5 \ No newline at end of file +ed25f56d9cafd447debe0262db98203e8032f16d \ 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 0c9b88d2..e44618f 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 @@ -9f0d93ec5443360075bc72873bb8dd34f3903715 \ No newline at end of file +11e061b6a7c3d0d3a3fdd18ec143b58690df31d9 \ 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 704c59f..b1e1b8d 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 @@ -a8a5fcbd6421119f00a7d00b38f1866b2bdac8d1 \ No newline at end of file +1f39d1e56905252e310f062087c77230aab860a1 \ 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 42ee2b79..57273719 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 @@ -7255f07c433e3e21c75ce11823280277337829c5 \ No newline at end of file +2d0f5bd377e4064f59214f258133bd4499b06505 \ 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 0a8a3883..c7f91719 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 @@ -783e9e5d44efe6c0f6aa6b576891f9ff501c5cb5 \ No newline at end of file +dcba949bedb460b8e214f8aed332657843740c4c \ 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 f93593c8..7d97f43d 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 @@ -491450aeae4618be9a377289eeda240120fb0afc \ No newline at end of file +ae436559871bd938b8e5638c56ea1044463615d8 \ 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 7a9eeca..15e1d2d 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 @@ -9af7806bb62c900c0a79400d2a1c456c004ba147 \ No newline at end of file +6757346754c96c56fe45f5a98667b98269c2ac33 \ 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 98fa7a0..a9f4fe2 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 @@ -5ab6e9eecdf7523c45b8ff8bd5783b136ea97013 \ No newline at end of file +b47722f65ee17ef3e22bd3e282fb1b8ffdcba974 \ 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 d2b4480..4114bac8 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 @@ -4e230f53f8790e654608aac45150e2301621464e \ No newline at end of file +843a5e0c466fe3a2ddf4836bb2381099baa603cc \ 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 f6ae8ead..9838fde 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 @@ -1c665c7894774e6661a78666515a5680ad4a9a09 \ No newline at end of file +a91e07a6dc2c84ebb6fd59e70b3fce5435ba238a \ 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 abeb4b4..031a1f91 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 @@ -653662a2d00744062a57010a0d1cb889aad94777 \ No newline at end of file +b6cc3af165fca4418cf4bdb3b03d05a24cd2a602 \ 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 984c65b..0ba44d72 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 @@ -d7389179d2efedc9497d72a7a8e8d3f316893041 \ No newline at end of file +4ecfcad9aa77c3410767d90c8da5dd6140ed7291 \ 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 37d9a869..61d05fa0 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 @@ -328ce723fb81728e175e92d8ba557f983fade509 \ No newline at end of file +f108fa143b64e64baaf79e51916a8f5dd4f4324a \ 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 184f1962..b5f0504 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 @@ -00f228b0cde3aacdfe4345c895f8717fa488f8a3 \ No newline at end of file +852457ea05e2b15d809500d5346b0450d7c7a205 \ 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 a8f1383..cf9dc4d0 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 @@ -64c923742881c016b12ebfd1058781d9ba7d6fda \ No newline at end of file +e65f82af4d169a9c7dd6fa7de9bd5c459843d927 \ 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 8fdeb92..80c3015 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 @@ -4be27ec6957a30b889b0deb554d2fc6593c68369 \ No newline at end of file +780c83d6c3786b8ef78c770ef11a246ccc8f05a5 \ 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 f413614..a4dbb50 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 @@ -11e90efb75c21f121dd818bff3cac0b18f478f69 \ No newline at end of file +cd0fb916d552c46c352177e9e4ddfc63bd0123eb \ 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 53e05c5..91748bc 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 @@ -51f074d9e251145b4cb6bbaca2ecde1aceb7631f \ No newline at end of file +afc549af00f08509354b7b5298b2fe9bc90cc7cf \ 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 ad39524..18bd54a 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 @@ -dc304d6d69b3e4dda0417c5888f6c6a9ccaa5d93 \ No newline at end of file +2a37ae8e058999ee85c191d8a2ddf422189f28a2 \ 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 47ee08b..f825f2e 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 @@ -cab653359c1e8180398bfab476c9bac66b7882a6 \ No newline at end of file +13fae50fffe710fb0790f93457b47d3c0dbd5883 \ 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 61660b0..bcc0dc6b 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 @@ -4b286483aaa0f1c6a7f29320f0ec69e104883304 \ No newline at end of file +f24c423da6b26b884cc3e77826e1bc21c015aebd \ 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 805be703..288ea38 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 @@ -8f80106257c79a626dfb214dd2d5ff7dc16ad826 \ No newline at end of file +f769d2c3d3ffb1cdb1deb97171472319632f9934 \ 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 63e8e8b..bf624ae 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 @@ -b579b34f8a078931ab70044e702f2dd4db5e7c52 \ No newline at end of file +19e435d22d03f140ff358aac55cced87bb8c1d20 \ 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 8583f49..2fbbdf30 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 @@ -fd223a2b5fab49f82015a503ecc5e1ffb6f2a205 \ No newline at end of file +2b1790089ab632fd3b53c9da5554493f68175e90 \ No newline at end of file
diff --git a/ios_internal b/ios_internal index 46e2e65..63647fd 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit 46e2e655940ecae3d363c4f438c1aabeaa5669e8 +Subproject commit 63647fd54313ac65206bb1093278b8e2e73bfcf8
diff --git a/media/gpu/chromeos/frame_resource.h b/media/gpu/chromeos/frame_resource.h index cbe25d4..50dd11ef 100644 --- a/media/gpu/chromeos/frame_resource.h +++ b/media/gpu/chromeos/frame_resource.h
@@ -98,11 +98,6 @@ virtual std::unique_ptr<VideoFrame::ScopedMapping> MapGMBOrSharedImage() const = 0; - // Returns an identifier based on the frame data's underlying storage. This - // returns consistent results even if the frame gets wrapped. Returns an - // invalid GenericSharedMemoryId if an identifier cannot be determined. - virtual gfx::GenericSharedMemoryId GetSharedMemoryId() const = 0; - virtual const VideoFrameLayout& layout() const = 0; virtual VideoPixelFormat format() const = 0;
diff --git a/media/gpu/chromeos/native_pixmap_frame_resource.cc b/media/gpu/chromeos/native_pixmap_frame_resource.cc index cd9c02b7..528e4864 100644 --- a/media/gpu/chromeos/native_pixmap_frame_resource.cc +++ b/media/gpu/chromeos/native_pixmap_frame_resource.cc
@@ -305,7 +305,7 @@ gmb_handle.type = gfx::GpuMemoryBufferType::NATIVE_PIXMAP; // |gmb_handle.id| is set to the GenericSharedMemoryId from |this|. This // allows for more predictable caching when converting to a VideoFrame. - gmb_handle.id = GetSharedMemoryId(); + gmb_handle.id = id_; gmb_handle.native_pixmap_handle = std::move(native_pixmap_handle); return gmb_handle; } @@ -317,11 +317,6 @@ return nullptr; } -gfx::GenericSharedMemoryId NativePixmapFrameResource::GetSharedMemoryId() - const { - return id_; -} - const VideoFrameLayout& NativePixmapFrameResource::layout() const { return layout_; } @@ -430,8 +425,8 @@ // constructor. auto wrapping_frame = base::WrapRefCounted<NativePixmapFrameResource>( new NativePixmapFrameResource(layout(), visible_rect, natural_size, - timestamp(), GetSharedMemoryId(), - tracking_token(), buffer_usage_, pixmap_)); + timestamp(), id_, tracking_token(), + buffer_usage_, pixmap_)); // All other metadata is copied to the "wrapping" frame. wrapping_frame->metadata().MergeMetadataFrom(metadata());
diff --git a/media/gpu/chromeos/native_pixmap_frame_resource.h b/media/gpu/chromeos/native_pixmap_frame_resource.h index 3d942f74..a02275f5 100644 --- a/media/gpu/chromeos/native_pixmap_frame_resource.h +++ b/media/gpu/chromeos/native_pixmap_frame_resource.h
@@ -74,14 +74,13 @@ scoped_refptr<const gfx::NativePixmapDmaBuf> GetNativePixmapDmaBuf() const override; // CreateGpuMemoryBufferHandle() will duplicate file descriptors to make a - // gfx::GpuMemoryBufferHandle. The GpuMemoryBufferId will match - // GetSharedMemoryId(). Doing this helps with identification of original - // FrameResource from a VideoFrame produced by CreateVideoFrame(). + // gfx::GpuMemoryBufferHandle. The GpuMemoryBufferId will be set to a + // consistent value in subsequent calls for |this| or for any wrapping frame + // of |this|. gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferHandle() const override; // Always returns nullptr. std::unique_ptr<VideoFrame::ScopedMapping> MapGMBOrSharedImage() const override; - gfx::GenericSharedMemoryId GetSharedMemoryId() const override; const VideoFrameLayout& layout() const override; VideoPixelFormat format() const override; int stride(size_t plane) const override; @@ -148,7 +147,9 @@ // is wrapped, |id_| is copied to the wrapping frame. The ID's will be unique // per underlying NativePixmapDmaBuf object, per process. The ID is generated // by and stored in NativePixmapFrameResource because the ID returned by - // gxf::NativePixmapDmaBuf::GetUniqueId() is currently always zero. + // gxf::NativePixmapDmaBuf::GetUniqueId() is currently always zero. It is used + // by CreateGpuMemoryBufferHandle to create GpuMemoryBufferHandle's with + // consistent ID's. const gfx::GenericSharedMemoryId id_; // |buffer_usage_| affects how a buffer can be used. It is only set if it was
diff --git a/media/gpu/chromeos/video_frame_resource.cc b/media/gpu/chromeos/video_frame_resource.cc index 225954b..ad11f6f 100644 --- a/media/gpu/chromeos/video_frame_resource.cc +++ b/media/gpu/chromeos/video_frame_resource.cc
@@ -86,10 +86,6 @@ return frame_->MapGMBOrSharedImage(); } -gfx::GenericSharedMemoryId VideoFrameResource::GetSharedMemoryId() const { - return media::GetSharedMemoryId(*frame_); -} - const VideoFrameLayout& VideoFrameResource::layout() const { return frame_->layout(); }
diff --git a/media/gpu/chromeos/video_frame_resource.h b/media/gpu/chromeos/video_frame_resource.h index 87e529d..51827af 100644 --- a/media/gpu/chromeos/video_frame_resource.h +++ b/media/gpu/chromeos/video_frame_resource.h
@@ -40,7 +40,6 @@ gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferHandle() const override; std::unique_ptr<VideoFrame::ScopedMapping> MapGMBOrSharedImage() const override; - gfx::GenericSharedMemoryId GetSharedMemoryId() const override; const VideoFrameLayout& layout() const override; VideoPixelFormat format() const override; int stride(size_t plane) const override;
diff --git a/media/mojo/clients/mojo_stable_video_decoder.cc b/media/mojo/clients/mojo_stable_video_decoder.cc index f0dc61c1..039e01f 100644 --- a/media/mojo/clients/mojo_stable_video_decoder.cc +++ b/media/mojo/clients/mojo_stable_video_decoder.cc
@@ -129,16 +129,14 @@ return nullptr; } - return base::WrapRefCounted(new SharedImageHolder( - frame_resource->GetSharedMemoryId(), std::move(new_client_shared_image), - frame_resource->ColorSpace(), std::move(sii))); + return base::WrapRefCounted( + new SharedImageHolder(std::move(new_client_shared_image), + frame_resource->ColorSpace(), std::move(sii))); } SharedImageHolder(const SharedImageHolder&) = delete; SharedImageHolder& operator=(const SharedImageHolder&) = delete; - gfx::GenericSharedMemoryId id() const { return id_; } - const scoped_refptr<gpu::ClientSharedImage> client_shared_image() const { return client_shared_image_; } @@ -165,18 +163,15 @@ private: friend class base::RefCountedThreadSafe<SharedImageHolder>; - SharedImageHolder(gfx::GenericSharedMemoryId id, - scoped_refptr<gpu::ClientSharedImage> client_shared_image, + SharedImageHolder(scoped_refptr<gpu::ClientSharedImage> client_shared_image, const gfx::ColorSpace& color_space, scoped_refptr<gpu::SharedImageInterface> sii) - : id_(id), - color_space_(color_space), + : color_space_(color_space), sii_(std::move(sii)), client_shared_image_(std::move(client_shared_image)) {} ~SharedImageHolder() { CHECK(client_shared_image_->HasOneRef()); } - const gfx::GenericSharedMemoryId id_; const gfx::ColorSpace color_space_; const scoped_refptr<gpu::SharedImageInterface> sii_; @@ -341,13 +336,14 @@ const scoped_refptr<FrameResource>& frame_resource) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - const gfx::GenericSharedMemoryId frame_id = - frame_resource->GetSharedMemoryId(); - CHECK(frame_id.is_valid()); + const base::UnguessableToken frame_token = frame_resource->tracking_token(); + CHECK(!frame_token.is_empty()); // First, let's see if the buffer for this frame already has a SharedImage // that can be re-used. - SharedImageHolder* shared_image_holder = shared_images_.Lookup(frame_id); + const auto iter = shared_images_.find(frame_token); + SharedImageHolder* shared_image_holder = + iter != shared_images_.end() ? iter->second.get() : nullptr; if (shared_image_holder && shared_image_holder->IsCompatibleWith(frame_resource)) { shared_image_holder->Update(); @@ -370,7 +366,7 @@ // SharedImage if the user of the decoded frames still hasn't released all // frames that use that SharedImage. shared_image_holder = nullptr; - shared_images_.Replace(frame_id, new_shared_image); + shared_images_.insert_or_assign(frame_token, new_shared_image); } else { // In this case, the buffer does not have a SharedImage associated with it. // Therefore, we need to ask the containing FrameResource to notify us when @@ -379,22 +375,21 @@ FrameResource* original_frame_resource = oop_video_decoder()->GetOriginalFrame(frame_resource->tracking_token()); CHECK(original_frame_resource); - shared_images_.AddWithID(new_shared_image, frame_id); + shared_images_.insert_or_assign(frame_token, new_shared_image); original_frame_resource->AddDestructionObserver( base::BindPostTaskToCurrentDefault( base::BindOnce(&MojoStableVideoDecoder::UnregisterSharedImage, - weak_this_factory_.GetWeakPtr(), frame_id))); + weak_this_factory_.GetWeakPtr(), frame_token))); } return new_shared_image; } void MojoStableVideoDecoder::UnregisterSharedImage( - gfx::GenericSharedMemoryId frame_id) { + base::UnguessableToken frame_token) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - CHECK(frame_id.is_valid()); - CHECK(shared_images_.Lookup(frame_id)); - shared_images_.Remove(frame_id); + CHECK(!frame_token.is_empty()); + CHECK_EQ(1u, shared_images_.erase(frame_token)); } void MojoStableVideoDecoder::OnFrameResourceDecoded(
diff --git a/media/mojo/clients/mojo_stable_video_decoder.h b/media/mojo/clients/mojo_stable_video_decoder.h index fbefdecf..45d683bb 100644 --- a/media/mojo/clients/mojo_stable_video_decoder.h +++ b/media/mojo/clients/mojo_stable_video_decoder.h
@@ -5,7 +5,7 @@ #ifndef MEDIA_MOJO_CLIENTS_MOJO_STABLE_VIDEO_DECODER_H_ #define MEDIA_MOJO_CLIENTS_MOJO_STABLE_VIDEO_DECODER_H_ -#include "base/containers/id_map.h" +#include "base/containers/flat_map.h" #include "base/containers/lru_cache.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" @@ -95,7 +95,7 @@ scoped_refptr<SharedImageHolder> CreateOrUpdateSharedImageForFrame( const scoped_refptr<FrameResource>& frame_resource); - void UnregisterSharedImage(gfx::GenericSharedMemoryId frame_id); + void UnregisterSharedImage(base::UnguessableToken frame_token); void OnFrameResourceDecoded(scoped_refptr<FrameResource> frame_resource); @@ -136,8 +136,7 @@ // possible. The fact that we keep a reference to a SharedImageHolder // guarantees that the corresponding SharedImage lives for at least as long as // the OOPVideoDecoder knows about the corresponding buffer. - base::IDMap</*V=*/scoped_refptr<SharedImageHolder>, - /*K=*/gfx::GenericSharedMemoryId> + base::flat_map<base::UnguessableToken, scoped_refptr<SharedImageHolder>> shared_images_ GUARDED_BY_CONTEXT(sequence_checker_); OutputCB output_cb_ GUARDED_BY_CONTEXT(sequence_checker_);
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc index d14df39f..7e64f9a 100644 --- a/net/cookies/cookie_monster.cc +++ b/net/cookies/cookie_monster.cc
@@ -730,7 +730,7 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); std::optional<base::ElapsedTimer> timer; - if (get_cookie_list_timing_subsampler_.ShouldSample(0.001)) { + if (metrics_subsampler_.ShouldSample(0.001)) { timer.emplace(); } @@ -1409,8 +1409,11 @@ CookieAccessResult& access_result = cookie_result.second; // We want to collect these metrics for cookies that would be included - // without considering shadowing domain cookies. - if (access_result.status.IsInclude()) { + // without considering shadowing domain cookies. Recording them on every + // resource sequest results in unnecessarily large amounts of samples + // and has a non-zero runtime cost, so only collect 1/1000 times. + if (metrics_subsampler_.ShouldSample(0.001) && + access_result.status.IsInclude()) { int destination_port = url.EffectiveIntPort(); if (IsLocalhost(url)) {
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h index e0ded49..da8bf6df 100644 --- a/net/cookies/cookie_monster.h +++ b/net/cookies/cookie_monster.h
@@ -813,7 +813,7 @@ bool persist_session_cookies_ = false; - base::MetricsSubSampler get_cookie_list_timing_subsampler_; + base::MetricsSubSampler metrics_subsampler_; THREAD_CHECKER(thread_checker_);
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc index f3ebb52..da0e755 100644 --- a/net/cookies/cookie_monster_unittest.cc +++ b/net/cookies/cookie_monster_unittest.cc
@@ -24,6 +24,7 @@ #include "base/memory/ref_counted.h" #include "base/metrics/histogram.h" #include "base/metrics/histogram_samples.h" +#include "base/rand_util.h" #include "base/ranges/algorithm.h" #include "base/run_loop.h" #include "base/strings/strcat.h" @@ -6433,6 +6434,10 @@ } TEST_F(CookieMonsterTest, CookiePortReadHistogram) { + // The per-resource cookie histograms are subsampled, simulate for this test + // that the dice roll makes them record. + base::MetricsSubSampler::ScopedAlwaysSampleForTesting no_subsampling; + base::HistogramTester histograms; const char kHistogramName[] = "Cookie.Port.Read.RemoteHost"; const char kHistogramNameLocal[] = "Cookie.Port.Read.Localhost"; @@ -6538,6 +6543,10 @@ } TEST_F(CookieMonsterTest, CookiePortReadDiffersFromSetHistogram) { + // The per-resource cookie histograms are subsampled, simulate for this test + // that the dice roll makes them record. + base::MetricsSubSampler::ScopedAlwaysSampleForTesting no_subsampling; + base::HistogramTester histograms; const char kHistogramName[] = "Cookie.Port.ReadDiffersFromSet.RemoteHost"; const char kHistogramNameLocal[] = "Cookie.Port.ReadDiffersFromSet.Localhost";
diff --git a/net/log/trace_net_log_observer.cc b/net/log/trace_net_log_observer.cc index 7e5f791..0faf0fe 100644 --- a/net/log/trace_net_log_observer.cc +++ b/net/log/trace_net_log_observer.cc
@@ -55,6 +55,9 @@ void TraceNetLogObserver::OnAddEntry(const NetLogEntry& entry) { base::Value::Dict params = entry.params.Clone(); + // Add source's start time as a parameter. The net-log viewer requires it. + params.Set("source_start_time", + NetLog::TickCountToString(entry.source.start_time)); switch (entry.phase) { case NetLogEventPhase::BEGIN: TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
diff --git a/net/log/trace_net_log_observer_unittest.cc b/net/log/trace_net_log_observer_unittest.cc index 051a610..0a77aa2 100644 --- a/net/log/trace_net_log_observer_unittest.cc +++ b/net/log/trace_net_log_observer_unittest.cc
@@ -435,11 +435,17 @@ item1->GetDict().FindStringByDottedPath("args.params.foo"); ASSERT_TRUE(item1_params); EXPECT_EQ("bar", *item1_params); + const std::string* item1_param_source_start_time = + item1->GetDict().FindStringByDottedPath("args.params.source_start_time"); + EXPECT_NE(item1_param_source_start_time, nullptr); - // Perfetto tracing backend skips empty args. + // Events emitted by TraceNetLogObserver always have params. const base::Value::Dict* item2_args = item2->GetDict().FindDictByDottedPath("args"); - EXPECT_FALSE(item2_args->contains("params")); + EXPECT_TRUE(item2_args->contains("params")); + const std::string* item2_param_source_start_time = + item2->GetDict().FindStringByDottedPath("args.params.source_start_time"); + EXPECT_NE(item2_param_source_start_time, nullptr); } TEST(TraceNetLogObserverCategoryTest, DisabledCategory) {
diff --git a/printing/backend/cups_helper.cc b/printing/backend/cups_helper.cc index 2d63c3f..20860c5 100644 --- a/printing/backend/cups_helper.cc +++ b/printing/backend/cups_helper.cc
@@ -163,21 +163,22 @@ std::vector<gfx::Size> dpis; gfx::Size default_dpi; if (res) { - UNSAFE_TODO({ - for (int i = 0; i < res->num_choices; i++) { - char* choice = res->choices[i].choice; - CHECK(choice); - std::optional<gfx::Size> parsed_size = ParseResolutionString(choice); - if (!parsed_size.has_value()) { - continue; - } - - dpis.push_back(parsed_size.value()); - if (!strcmp(choice, res->defchoice)) { - default_dpi = dpis.back(); - } + // SAFETY: Required from CUPS. + auto choices = UNSAFE_BUFFERS(base::span<const ppd_choice_t>( + res->choices, static_cast<size_t>(res->num_choices))); + for (const auto& choice : choices) { + const char* choice_str = choice.choice; + CHECK(choice_str); + std::optional<gfx::Size> parsed_size = ParseResolutionString(choice_str); + if (!parsed_size.has_value()) { + continue; } - }); + + dpis.push_back(parsed_size.value()); + if (!strcmp(choice_str, res->defchoice)) { + default_dpi = dpis.back(); + } + } } else { // If there is no resolution option, then check for a standalone // DefaultResolution. @@ -865,63 +866,62 @@ VLOG(1) << "Paper list size - " << ppd->num_sizes; ppd_option_t* paper_option = ppdFindOption(ppd, kPageSize); bool is_default_found = false; - UNSAFE_TODO({ - for (int i = 0; i < ppd->num_sizes; ++i) { - const gfx::Size paper_size_um( - ConvertUnit(ppd->sizes[i].width, kPointsPerInch, kMicronsPerInch), - ConvertUnit(ppd->sizes[i].length, kPointsPerInch, kMicronsPerInch)); - if (!paper_size_um.IsEmpty()) { - std::string display_name; - if (paper_option) { - ppd_choice_t* paper_choice = - ppdFindChoice(paper_option, ppd->sizes[i].name); - // Human readable paper name should be UTF-8 encoded, but some PPDs - // do not follow this standard. - if (paper_choice && base::IsStringUTF8(paper_choice->text)) { - display_name = paper_choice->text; - } - } - int printable_area_left_um = - ConvertUnit(ppd->sizes[i].left, kPointsPerInch, kMicronsPerInch); - int printable_area_bottom_um = ConvertUnit( - ppd->sizes[i].bottom, kPointsPerInch, kMicronsPerInch); - // ppd->sizes[i].right is the horizontal distance from the left of the - // paper to the right of the printable area. - int printable_area_right_um = - ConvertUnit(ppd->sizes[i].right, kPointsPerInch, kMicronsPerInch); - // ppd->sizes[i].top is the vertical distance from the bottom of the - // paper to the top of the printable area. - int printable_area_top_um = - ConvertUnit(ppd->sizes[i].top, kPointsPerInch, kMicronsPerInch); - - gfx::Rect printable_area_um( - printable_area_left_um, printable_area_bottom_um, - /*width=*/printable_area_right_um - printable_area_left_um, - /*height=*/printable_area_top_um - printable_area_bottom_um); - - // Default to the paper size if printable area is empty. - // We've seen some drivers have a printable area that goes out of - // bounds of the paper size. In those cases, set the printable area to - // be the size. (See crbug.com/1412305.) - const gfx::Rect size_um_rect = gfx::Rect(paper_size_um); - if (printable_area_um.IsEmpty() || - !size_um_rect.Contains(printable_area_um)) { - printable_area_um = size_um_rect; - } - - PrinterSemanticCapsAndDefaults::Paper paper( - display_name, - /*vendor_id=*/ppd->sizes[i].name, paper_size_um, - printable_area_um); - - caps.papers.push_back(paper); - if (ppd->sizes[i].marked) { - caps.default_paper = paper; - is_default_found = true; + // SAFETY: Required from CUPS. + auto sizes = UNSAFE_BUFFERS(base::span<const ppd_size_t>( + ppd->sizes, static_cast<size_t>(ppd->num_sizes))); + for (const auto& size : sizes) { + const gfx::Size paper_size_um( + ConvertUnit(size.width, kPointsPerInch, kMicronsPerInch), + ConvertUnit(size.length, kPointsPerInch, kMicronsPerInch)); + if (!paper_size_um.IsEmpty()) { + std::string display_name; + if (paper_option) { + ppd_choice_t* paper_choice = ppdFindChoice(paper_option, size.name); + // Human readable paper name should be UTF-8 encoded, but some PPDs + // do not follow this standard. + if (paper_choice && base::IsStringUTF8(paper_choice->text)) { + display_name = paper_choice->text; } } + int printable_area_left_um = + ConvertUnit(size.left, kPointsPerInch, kMicronsPerInch); + int printable_area_bottom_um = + ConvertUnit(size.bottom, kPointsPerInch, kMicronsPerInch); + // `size.right` is the horizontal distance from the left of the paper to + // the right of the printable area. + int printable_area_right_um = + ConvertUnit(size.right, kPointsPerInch, kMicronsPerInch); + // `size.top` is the vertical distance from the bottom of the paper to + // the top of the printable area. + int printable_area_top_um = + ConvertUnit(size.top, kPointsPerInch, kMicronsPerInch); + + gfx::Rect printable_area_um( + printable_area_left_um, printable_area_bottom_um, + /*width=*/printable_area_right_um - printable_area_left_um, + /*height=*/printable_area_top_um - printable_area_bottom_um); + + // Default to the paper size if printable area is empty. + // We've seen some drivers have a printable area that goes out of + // bounds of the paper size. In those cases, set the printable area to + // be the size. (See crbug.com/1412305.) + const gfx::Rect size_um_rect = gfx::Rect(paper_size_um); + if (printable_area_um.IsEmpty() || + !size_um_rect.Contains(printable_area_um)) { + printable_area_um = size_um_rect; + } + + PrinterSemanticCapsAndDefaults::Paper paper( + display_name, + /*vendor_id=*/size.name, paper_size_um, printable_area_um); + + caps.papers.push_back(paper); + if (size.marked) { + caps.default_paper = paper; + is_default_found = true; + } } - }); + } if (!is_default_found) { gfx::Size locale_paper_um = GetDefaultPaperSizeFromLocaleMicrons(locale); for (const PrinterSemanticCapsAndDefaults::Paper& paper : caps.papers) {
diff --git a/printing/backend/cups_printer.cc b/printing/backend/cups_printer.cc index 7c879e9..cfd8ae2 100644 --- a/printing/backend/cups_printer.cc +++ b/printing/backend/cups_printer.cc
@@ -165,12 +165,14 @@ printer_info->options[kDriverInfoTagName] = make_and_model; // Store printer options. - UNSAFE_TODO({ - for (int opt_index = 0; opt_index < printer->num_options; ++opt_index) { - printer_info->options[printer->options[opt_index].name] = - printer->options[opt_index].value; + if (printer->num_options > 0) { + // SAFETY: Required from CUPS. + auto options = UNSAFE_BUFFERS(base::span<const cups_option_t>( + printer->options, static_cast<size_t>(printer->num_options))); + for (const auto& option : options) { + printer_info->options[option.name] = option.value; } - }); + } return true; }
diff --git a/printing/backend/print_backend_cups.cc b/printing/backend/print_backend_cups.cc index f5596b2..f3a75c2 100644 --- a/printing/backend/print_backend_cups.cc +++ b/printing/backend/print_backend_cups.cc
@@ -111,12 +111,14 @@ printer_info->options[kDriverInfoTagName] = drv_info; // Store printer options. - UNSAFE_TODO({ - for (int opt_index = 0; opt_index < printer.num_options; ++opt_index) { - printer_info->options[printer.options[opt_index].name] = - printer.options[opt_index].value; + if (printer.num_options > 0) { + // SAFETY: Required from CUPS. + auto options = UNSAFE_BUFFERS(base::span<const cups_option_t>( + printer.options, static_cast<size_t>(printer.num_options))); + for (const auto& option : options) { + printer_info->options[option.name] = option.value; } - }); + } std::string_view info = info_option ? std::string_view(info_option) : std::string_view(); printer_info->display_name = GetDisplayName(printer_info->printer_name, info); @@ -181,18 +183,16 @@ return mojom::ResultCode::kSuccess; } - UNSAFE_TODO({ - for (int printer_index = 0; printer_index < dests_data.num_dests; - ++printer_index) { - const cups_dest_t& printer = dests_data.dests[printer_index]; - - PrinterBasicInfo printer_info; - if (PrinterBasicInfoFromCUPS(printer, &printer_info) == - mojom::ResultCode::kSuccess) { - printer_list.push_back(printer_info); - } + // SAFETY: Required from CUPS. + auto printers = UNSAFE_BUFFERS(base::span<const cups_dest_t>( + dests_data.dests, static_cast<size_t>(dests_data.num_dests))); + for (const auto& printer : printers) { + PrinterBasicInfo printer_info; + if (PrinterBasicInfoFromCUPS(printer, &printer_info) == + mojom::ResultCode::kSuccess) { + printer_list.push_back(printer_info); } - }); + } cupsFreeDests(dests_data.num_dests, dests_data.dests);
diff --git a/printing/common/metafile_utils.cc b/printing/common/metafile_utils.cc index e28fb6e..9b901f3 100644 --- a/printing/common/metafile_utils.cc +++ b/printing/common/metafile_utils.cc
@@ -10,6 +10,7 @@ #include "base/check.h" #include "base/compiler_specific.h" #include "base/containers/span.h" +#include "base/containers/span_reader.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" #include "build/build_config.h" @@ -234,6 +235,21 @@ return valid; } +sk_sp<SkData> GetImageData(SkImage* img) { + // Skip the encoding step if the image is already encoded + if (sk_sp<SkData> data = img->refEncodedData()) { + return data; + } + + // TODO(crbug.com/40073326) Convert texture-backed images to raster + // *before* they get this far if possible. + if (img->isTextureBacked()) { + GrDirectContext* ctx = SkImages::GetContext(img); + return skia::EncodePngAsSkData(ctx, img); + } + return skia::EncodePngAsSkData(nullptr, img); +} + } // namespace namespace printing { @@ -363,43 +379,86 @@ return typeface; } -sk_sp<SkData> SerializeRasterImage(SkImage* img, void*) { +sk_sp<SkData> SerializeRasterImage(SkImage* img, void* ctx) { if (!img) { return nullptr; } - // Skip the encoding step if the image is already encoded - if (sk_sp<SkData> data = img->refEncodedData()) { - return data; + + auto* context = reinterpret_cast<ImageSerializationContext*>(ctx); + + uint32_t img_id = img->uniqueID(); + if (context->contains(img_id)) { + return SkData::MakeWithCopy(&img_id, sizeof(img_id)); } - // TODO(crbug.com/40073326) Convert texture-backed images to raster - // *before* they get this far if possible. - if (img->isTextureBacked()) { - GrDirectContext* ctx = SkImages::GetContext(img); - return skia::EncodePngAsSkData(ctx, img); + sk_sp<SkData> img_data = GetImageData(img); + if (!img_data) { + return nullptr; } - return skia::EncodePngAsSkData(nullptr, img); + + // Store image id followed by the image data on the first occurrence + // of an image. + auto data = SkData::MakeUninitialized( + base::CheckAdd(img_data->size(), sizeof(img_id)).ValueOrDie()); + + // SAFETY: The span is used as a view to avoid direct pointer access. + auto [id_span, data_span] = + UNSAFE_BUFFERS(base::span(static_cast<uint8_t*>(data->writable_data()), + data->size())) + .split_at<sizeof(img_id)>(); + id_span.copy_from(base::byte_span_from_ref(img_id)); + data_span.copy_from(gfx::SkDataToSpan(img_data)); + + context->insert(img_id); + + return data; } -sk_sp<SkImage> DeserializeRasterImage(const void* bytes, size_t length, void*) { +sk_sp<SkImage> DeserializeRasterImage(const void* bytes, + size_t length, + void* ctx) { + auto* context = reinterpret_cast<ImageDeserializationContext*>(ctx); + // SAFETY: The caller must provide a valid pointer and length. - auto bytes_span = - UNSAFE_BUFFERS(base::span(static_cast<const uint8_t*>(bytes), length)); - // Safe for `data` to be a span over `bytes_span` because `bytes_span` will - // outlive `data`. - auto data = gfx::MakeSkDataFromSpanWithoutCopy(bytes_span); - //TODO(b/40045064): Explicitly decode other supported codecs - auto codec = SkPngDecoder::Decode(data, nullptr); - if (codec) { - return std::get<0>(codec->getImage()); + base::SpanReader reader{ + UNSAFE_BUFFERS(base::span(static_cast<const uint8_t*>(bytes), length))}; + + uint32_t img_id; + if (!reader.ReadU32NativeEndian(img_id)) { + // If there is no room for id, there cannot be meaningful image data. + return nullptr; } - return nullptr; + + auto iter = context->find(img_id); + if (iter != context->end() && iter->second) { + return iter->second; + } + + if (!reader.remaining()) { + return nullptr; + } + + // Copy the data to avoid `bytes` being freed before the image is decoded. + auto data_span = reader.remaining_span(); + auto img_data = SkData::MakeWithCopy(data_span.data(), data_span.size()); + + // Need to explicitly decode here, as the data are prefixed with image id, + // invalidating the built-in Skia fallback. + auto image = SkImages::DeferredFromEncodedData(img_data); + if (!image) { + return nullptr; + } + + (*context)[img_id] = image; + return image; } SkSerialProcs SerializationProcs(PictureSerializationContext* picture_ctx, - TypefaceSerializationContext* typeface_ctx) { + TypefaceSerializationContext* typeface_ctx, + ImageSerializationContext* image_ctx) { SkSerialProcs procs; procs.fImageProc = SerializeRasterImage; + procs.fImageCtx = image_ctx; procs.fPictureProc = SerializeOopPicture; procs.fPictureCtx = picture_ctx; procs.fTypefaceProc = SerializeOopTypeface; @@ -409,9 +468,11 @@ SkDeserialProcs DeserializationProcs( PictureDeserializationContext* picture_ctx, - TypefaceDeserializationContext* typeface_ctx) { + TypefaceDeserializationContext* typeface_ctx, + ImageDeserializationContext* image_ctx) { SkDeserialProcs procs; procs.fImageProc = DeserializeRasterImage; + procs.fImageCtx = image_ctx; procs.fPictureProc = DeserializeOopPicture; procs.fPictureCtx = picture_ctx; procs.fTypefaceProc = DeserializeOopTypeface;
diff --git a/printing/common/metafile_utils.h b/printing/common/metafile_utils.h index dee4f240..f304a0e 100644 --- a/printing/common/metafile_utils.h +++ b/printing/common/metafile_utils.h
@@ -31,6 +31,7 @@ base::flat_map<uint32_t, sk_sp<SkPicture>>; using TypefaceDeserializationContext = base::flat_map<uint32_t, sk_sp<SkTypeface>>; +using ImageDeserializationContext = base::flat_map<uint32_t, sk_sp<SkImage>>; // Stores the mapping between content's unique id and its corresponding frame // proxy token. @@ -39,6 +40,9 @@ // Stores the set of typeface unique ids used by the picture frame content. using TypefaceSerializationContext = ContentProxySet; +// Stores the set of serialized image ids used by the content. +using ImageSerializationContext = ContentProxySet; + sk_sp<SkDocument> MakePdfDocument( std::string_view creator, std::string_view title, @@ -51,11 +55,13 @@ #endif SkSerialProcs SerializationProcs(PictureSerializationContext* picture_ctx, - TypefaceSerializationContext* typeface_ctx); + TypefaceSerializationContext* typeface_ctx, + ImageSerializationContext* image_ctx); SkDeserialProcs DeserializationProcs( PictureDeserializationContext* picture_ctx, - TypefaceDeserializationContext* typeface_ctx); + TypefaceDeserializationContext* typeface_ctx, + ImageDeserializationContext* image_ctx); } // namespace printing
diff --git a/printing/metafile_skia.cc b/printing/metafile_skia.cc index 41c74e26..0f8510e 100644 --- a/printing/metafile_skia.cc +++ b/printing/metafile_skia.cc
@@ -79,6 +79,7 @@ std::map<uint32_t, sk_sp<SkPicture>> subframe_pics; int document_cookie = 0; raw_ptr<ContentProxySet> typeface_content_info = nullptr; + raw_ptr<ContentProxySet> image_content_info = nullptr; // The scale factor is used because Blink occasionally calls // PaintCanvas::getTotalMatrix() even though the total matrix is not as @@ -113,6 +114,10 @@ data_->typeface_content_info = typeface_content_info; } +void MetafileSkia::UtilizeImageContext(ContentProxySet* image_content_info) { + data_->image_content_info = image_content_info; +} + // TODO(halcanary): Create a Metafile class that only stores data. // Metafile::InitFromData is orthogonal to what the rest of // MetafileSkia does. @@ -213,7 +218,8 @@ #endif case mojom::SkiaDocumentType::kMSKP: SkSerialProcs procs = SerializationProcs(&data_->subframe_content_info, - data_->typeface_content_info); + data_->typeface_content_info, + data_->image_content_info); doc = SkMultiPictureDocument::Make(&stream, &procs); // It is safe to use base::Unretained(this) because the callback // is only used by `canvas` in the following loop which has shorter @@ -249,7 +255,8 @@ sk_sp<SkPicture> pic = data_->pages[0].content.ToSkPicture( SkRect::MakeSize(data_->pages[0].size), nullptr, callbacks); SkSerialProcs procs = SerializationProcs(&data_->subframe_content_info, - data_->typeface_content_info); + data_->typeface_content_info, + data_->image_content_info); SkDynamicMemoryWStream stream; pic->serialize(&stream, &procs); data_->data_stream = stream.detachAsStream(); @@ -404,6 +411,7 @@ metafile->data_->subframe_content_info = data_->subframe_content_info; metafile->data_->subframe_pics = data_->subframe_pics; metafile->data_->typeface_content_info = data_->typeface_content_info; + metafile->data_->image_content_info = data_->image_content_info; if (!metafile->FinishDocument()) // Generate PDF. metafile.reset();
diff --git a/printing/metafile_skia.h b/printing/metafile_skia.h index 097a4f134..d6afae9 100644 --- a/printing/metafile_skia.h +++ b/printing/metafile_skia.h
@@ -121,6 +121,8 @@ void UtilizeTypefaceContext(ContentProxySet* typeface_content_info); + void UtilizeImageContext(ContentProxySet* image_content_info); + const ui::AXTreeUpdate& accessibility_tree() const { return accessibility_tree_; }
diff --git a/printing/metafile_skia_unittest.cc b/printing/metafile_skia_unittest.cc index 1dbadb4e..0c2e113 100644 --- a/printing/metafile_skia_unittest.cc +++ b/printing/metafile_skia_unittest.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/containers/span_reader.h" #include "build/build_config.h" #include "cc/paint/paint_op.h" #include "cc/paint/paint_record.h" @@ -14,8 +15,8 @@ #include "skia/ext/font_utils.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/codec/SkCodec.h" -#include "third_party/skia/include/codec/SkPngDecoder.h" #include "third_party/skia/include/codec/SkJpegDecoder.h" +#include "third_party/skia/include/codec/SkPngDecoder.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkFont.h" @@ -33,6 +34,7 @@ #include "third_party/skia/include/core/SkTextBlob.h" #include "third_party/skia/include/core/SkTypeface.h" #include "third_party/skia/include/encode/SkJpegEncoder.h" +#include "ui/gfx/skia_span_util.h" namespace printing { @@ -80,7 +82,7 @@ // Get the complete picture by replacing the placeholder. PictureDeserializationContext subframes; subframes[content_id] = picture; - SkDeserialProcs procs = DeserializationProcs(&subframes, nullptr); + SkDeserialProcs procs = DeserializationProcs(&subframes, nullptr, nullptr); sk_sp<SkPicture> pic = SkPicture::MakeFromStream(metafile_stream, &procs); ASSERT_TRUE(pic); @@ -153,7 +155,7 @@ ContentProxySet serialize_typeface_ctx; PictureDeserializationContext subframes; TypefaceDeserializationContext typefaces; - SkDeserialProcs procs = DeserializationProcs(&subframes, &typefaces); + SkDeserialProcs procs = DeserializationProcs(&subframes, &typefaces, nullptr); // The typefaces which will be reused across the multiple (duplicate) pages. constexpr char kTypefaceName1[] = "sans-serif"; @@ -254,13 +256,25 @@ // Use the image serialization proc and assert that we get encoded data back PictureSerializationContext subframes; - SkSerialProcs procs = SerializationProcs(&subframes, nullptr); + ImageSerializationContext images; + SkSerialProcs procs = SerializationProcs(&subframes, nullptr, &images); - sk_sp<SkData> encoded_data = (*procs.fImageProc)(image.get(), nullptr); + sk_sp<SkData> encoded_data = + (*procs.fImageProc)(image.get(), procs.fImageCtx); ASSERT_TRUE(encoded_data); + EXPECT_GT(encoded_data->size(), sizeof(uint32_t)); + + base::SpanReader reader{gfx::SkDataToSpan(encoded_data)}; + + uint32_t img_id; + ASSERT_TRUE(reader.ReadU32NativeEndian(img_id)); + EXPECT_EQ(img_id, image->uniqueID()); + ASSERT_TRUE(images.contains(img_id)); // We expect unencoded images to be encoded as PNG. - ASSERT_TRUE(SkPngDecoder::IsPng(encoded_data->data(), encoded_data->size())); + auto encoded_image = reader.remaining_span(); + ASSERT_TRUE( + SkPngDecoder::IsPng(encoded_image.data(), encoded_image.size())); } TEST(MetafileSkiaTest, SkipEncodingAsPngWhenImageIsAlreadyEncoded) { @@ -288,12 +302,96 @@ // Call serialization proc on the JPEG image PictureSerializationContext subframes; - SkSerialProcs procs = SerializationProcs(&subframes, nullptr); - sk_sp<SkData> encoded_data = (*procs.fImageProc)(jpeg_img.get(), nullptr); + ImageSerializationContext images; + SkSerialProcs procs = SerializationProcs(&subframes, nullptr, &images); + sk_sp<SkData> encoded_data = + (*procs.fImageProc)(jpeg_img.get(), procs.fImageCtx); ASSERT_TRUE(encoded_data); + EXPECT_GT(encoded_data->size(), sizeof(uint32_t)); + + base::SpanReader reader{gfx::SkDataToSpan(encoded_data)}; + + uint32_t img_id; + ASSERT_TRUE(reader.ReadU32NativeEndian(img_id)); + EXPECT_EQ(img_id, jpeg_img->uniqueID()); + ASSERT_TRUE(images.contains(img_id)); // Make sure the data is still encoded as JPEG - ASSERT_TRUE(SkJpegDecoder::IsJpeg(encoded_data->data(), encoded_data->size())); + auto encoded_image = reader.remaining_span(); + ASSERT_TRUE( + SkJpegDecoder::IsJpeg(encoded_image.data(), encoded_image.size())); +} + +TEST(MetafileSkiaTest, SerializeUniqueImages) { + // Make raster surface + sk_sp<SkSurface> surface = + SkSurfaces::Raster(SkImageInfo::MakeN32(100, 50, kOpaque_SkAlphaType)); + SkCanvas* canvas = surface->getCanvas(); + + // Draw to it + SkPaint paint; + paint.setColor(SK_ColorGREEN); + canvas->clear(SK_ColorYELLOW); + canvas->drawRect(SkRect::MakeSize(SkSize::Make(75, 25)), paint); + + // Get an image that is not encoded + sk_sp<SkImage> unencoded_img = surface->makeImageSnapshot(); + ASSERT_FALSE(unencoded_img->refEncodedData()); + + // Call serialization proc on the image for the first time. + PictureSerializationContext subframes; + ImageSerializationContext images; + SkSerialProcs procs = SerializationProcs(&subframes, nullptr, &images); + + sk_sp<SkData> encoded_data1 = + (*procs.fImageProc)(unencoded_img.get(), procs.fImageCtx); + ASSERT_TRUE(encoded_data1); + EXPECT_GT(encoded_data1->size(), sizeof(uint32_t)); + + { + base::SpanReader reader{gfx::SkDataToSpan(encoded_data1)}; + uint32_t img_id; + ASSERT_TRUE(reader.ReadU32NativeEndian(img_id)); + EXPECT_EQ(img_id, unencoded_img->uniqueID()); + ASSERT_TRUE(images.contains(img_id)); + + // The image is expected to be encoded as PNG. + auto encoded_image = reader.remaining_span(); + ASSERT_FALSE(encoded_image.empty()); + ASSERT_TRUE( + SkPngDecoder::IsPng(encoded_image.data(), encoded_image.size())); + } + + // Call the serialization proc on the image for the second time. + sk_sp<SkData> encoded_data2 = + (*procs.fImageProc)(unencoded_img.get(), procs.fImageCtx); + ASSERT_TRUE(encoded_data2); + EXPECT_EQ(encoded_data2->size(), sizeof(uint32_t)); + + { + // The second serialization should only return image id. + base::SpanReader reader{gfx::SkDataToSpan(encoded_data2)}; + uint32_t img_id; + ASSERT_TRUE(reader.ReadU32NativeEndian(img_id)); + EXPECT_EQ(img_id, unencoded_img->uniqueID()); + EXPECT_FALSE(reader.remaining()); + } + + // Deserialization. + SkCodecs::Register(SkPngDecoder::Decoder()); + PictureDeserializationContext d_subframes; + ImageDeserializationContext d_images; + SkDeserialProcs d_procs = + DeserializationProcs(&d_subframes, nullptr, &d_images); + + sk_sp<SkImage> decoded_image1 = (*d_procs.fImageProc)( + encoded_data1->data(), encoded_data1->size(), d_procs.fImageCtx); + ASSERT_TRUE(decoded_image1); + + sk_sp<SkImage> decoded_image2 = (*d_procs.fImageProc)( + encoded_data2->data(), encoded_data2->size(), d_procs.fImageCtx); + ASSERT_TRUE(decoded_image2); + EXPECT_EQ(decoded_image1->uniqueID(), decoded_image2->uniqueID()); } } // namespace printing
diff --git a/remoting/base/cloud_session_authz_service_client_factory.cc b/remoting/base/cloud_session_authz_service_client_factory.cc index 6515b38..7edd0d8 100644 --- a/remoting/base/cloud_session_authz_service_client_factory.cc +++ b/remoting/base/cloud_session_authz_service_client_factory.cc
@@ -49,10 +49,10 @@ // SessionAuthzServiceClient implementation. void GenerateHostToken(GenerateHostTokenCallback callback) override; - void VerifySessionToken( - const internal::VerifySessionTokenRequestStruct& request, - VerifySessionTokenCallback callback) override; - void ReauthorizeHost(const internal::ReauthorizeHostRequestStruct& request, + void VerifySessionToken(std::string_view session_token, + VerifySessionTokenCallback callback) override; + void ReauthorizeHost(std::string_view session_reauth_token, + std::string_view session_id, ReauthorizeHostCallback callback) override; private: @@ -89,20 +89,21 @@ } void CloudSessionAuthzServiceClient::VerifySessionToken( - const internal::VerifySessionTokenRequestStruct& request, + std::string_view session_token, VerifySessionTokenCallback callback) { client_.VerifySessionToken( - request.session_token, + std::string(session_token), base::BindOnce( &CloudSessionAuthzServiceClient::OnVerifySessionTokenResponse, weak_factory_.GetWeakPtr(), std::move(callback))); } void CloudSessionAuthzServiceClient::ReauthorizeHost( - const internal::ReauthorizeHostRequestStruct& request, + std::string_view session_reauth_token, + std::string_view session_id, ReauthorizeHostCallback callback) { client_.ReauthorizeHost( - request.session_reauth_token, request.session_id, + std::string(session_reauth_token), std::string(session_id), base::BindOnce(&CloudSessionAuthzServiceClient::OnReauthorizeHostResponse, weak_factory_.GetWeakPtr(), std::move(callback))); }
diff --git a/remoting/base/corp_session_authz_service_client.cc b/remoting/base/corp_session_authz_service_client.cc index c6432e6..bc346802 100644 --- a/remoting/base/corp_session_authz_service_client.cc +++ b/remoting/base/corp_session_authz_service_client.cc
@@ -8,6 +8,7 @@ #include <utility> #include "base/functional/bind.h" +#include "base/strings/strcat.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "remoting/base/internal_headers.h" #include "remoting/base/protobuf_http_request.h" @@ -49,11 +50,17 @@ CorpSessionAuthzServiceClient::CorpSessionAuthzServiceClient( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - std::unique_ptr<OAuthTokenGetter> oauth_token_getter) + std::unique_ptr<OAuthTokenGetter> oauth_token_getter, + std::string_view support_id) : oauth_token_getter_(std::move(oauth_token_getter)), http_client_(ServiceUrls::GetInstance()->remoting_corp_endpoint(), oauth_token_getter_.get(), - url_loader_factory) {} + url_loader_factory), + support_id_(support_id) { + session_authz_path_ = support_id.empty() + ? internal::GetRemoteAccessSessionAuthzPath() + : internal::GetRemoteSupportSessionAuthzPath(); +} CorpSessionAuthzServiceClient::~CorpSessionAuthzServiceClient() = default; @@ -94,14 +101,14 @@ "Not implemented." })"); ExecuteRequest( - traffic_annotation, internal::GetGenerateHostTokenRequestPath(), - internal::GetGenerateHostTokenRequest({}), + traffic_annotation, internal::GetGenerateHostTokenRequestVerb(), + internal::GetGenerateHostTokenRequest({.support_id = support_id_}), ConvertCallback(std::move(callback), &internal::GetGenerateHostTokenResponseStruct)); } void CorpSessionAuthzServiceClient::VerifySessionToken( - const internal::VerifySessionTokenRequestStruct& request, + std::string_view session_token, VerifySessionTokenCallback callback) { constexpr net::NetworkTrafficAnnotationTag traffic_annotation = net::DefineNetworkTrafficAnnotation( @@ -139,15 +146,19 @@ policy_exception_justification: "Not implemented." })"); + internal::VerifySessionTokenRequestStruct request; + request.session_token = session_token; + request.support_id = support_id_; ExecuteRequest( - traffic_annotation, internal::GetVerifySessionTokenRequestPath(), + traffic_annotation, internal::GetVerifySessionTokenRequestVerb(), internal::GetVerifySessionTokenRequest(request), ConvertCallback(std::move(callback), &internal::GetVerifySessionTokenResponseStruct)); } void CorpSessionAuthzServiceClient::ReauthorizeHost( - const internal::ReauthorizeHostRequestStruct& request, + std::string_view session_reauth_token, + std::string_view session_id, ReauthorizeHostCallback callback) { constexpr net::NetworkTrafficAnnotationTag traffic_annotation = net::DefineNetworkTrafficAnnotation( @@ -183,7 +194,11 @@ policy_exception_justification: "Not implemented." })"); - ExecuteRequest(traffic_annotation, internal::GetReauthorizeHostRequestPath(), + internal::ReauthorizeHostRequestStruct request; + request.session_reauth_token = session_reauth_token; + request.session_id = session_id; + request.support_id = support_id_; + ExecuteRequest(traffic_annotation, internal::GetReauthorizeHostRequestVerb(), internal::GetReauthorizeHostRequest(request), ConvertCallback(std::move(callback), &internal::GetReauthorizeHostResponseStruct)); @@ -192,12 +207,12 @@ template <typename CallbackType> void CorpSessionAuthzServiceClient::ExecuteRequest( const net::NetworkTrafficAnnotationTag& traffic_annotation, - const std::string& path, + std::string_view verb, std::unique_ptr<google::protobuf::MessageLite> request_message, CallbackType callback) { auto request_config = std::make_unique<ProtobufHttpRequestConfig>(traffic_annotation); - request_config->path = path; + request_config->path = base::StrCat({session_authz_path_, ":", verb}); request_config->api_key = internal::GetRemotingCorpApiKey(); request_config->authenticated = true; request_config->provide_certificate = true;
diff --git a/remoting/base/corp_session_authz_service_client.h b/remoting/base/corp_session_authz_service_client.h index e6f7a191..4e137e9c 100644 --- a/remoting/base/corp_session_authz_service_client.h +++ b/remoting/base/corp_session_authz_service_client.h
@@ -7,6 +7,7 @@ #include <memory> #include <string> +#include <string_view> #include "base/memory/scoped_refptr.h" #include "remoting/base/oauth_token_getter.h" @@ -29,9 +30,12 @@ // API. For internal details, see go/crd-sessionauthz. class CorpSessionAuthzServiceClient : public SessionAuthzServiceClient { public: + // |support_id|: The 7-digit support ID. Empty implies that the connection + // mode is remote access. CorpSessionAuthzServiceClient( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - std::unique_ptr<OAuthTokenGetter> oauth_token_getter); + std::unique_ptr<OAuthTokenGetter> oauth_token_getter, + std::string_view support_id); ~CorpSessionAuthzServiceClient() override; CorpSessionAuthzServiceClient(const CorpSessionAuthzServiceClient&) = delete; @@ -39,22 +43,24 @@ const CorpSessionAuthzServiceClient&) = delete; void GenerateHostToken(GenerateHostTokenCallback callback) override; - void VerifySessionToken( - const internal::VerifySessionTokenRequestStruct& request, - VerifySessionTokenCallback callback) override; - void ReauthorizeHost(const internal::ReauthorizeHostRequestStruct& request, + void VerifySessionToken(std::string_view session_token, + VerifySessionTokenCallback callback) override; + void ReauthorizeHost(std::string_view session_reauth_token, + std::string_view session_id, ReauthorizeHostCallback callback) override; private: template <typename CallbackType> void ExecuteRequest( const net::NetworkTrafficAnnotationTag& traffic_annotation, - const std::string& path, + std::string_view verb, std::unique_ptr<google::protobuf::MessageLite> request_message, CallbackType callback); std::unique_ptr<OAuthTokenGetter> oauth_token_getter_; ProtobufHttpClient http_client_; + std::string support_id_; + std::string_view session_authz_path_; }; } // namespace remoting
diff --git a/remoting/base/corp_session_authz_service_client_factory.cc b/remoting/base/corp_session_authz_service_client_factory.cc index 10606891..122b49cd 100644 --- a/remoting/base/corp_session_authz_service_client_factory.cc +++ b/remoting/base/corp_session_authz_service_client_factory.cc
@@ -19,7 +19,8 @@ CorpSessionAuthzServiceClientFactory::CorpSessionAuthzServiceClientFactory( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& service_account_email, - const std::string& refresh_token) { + const std::string& refresh_token, + std::string_view support_id) { DCHECK(url_loader_factory); url_loader_factory_ = url_loader_factory; @@ -27,6 +28,7 @@ url_loader_factory, service_account_email, refresh_token); oauth_token_getter_task_runner_ = base::SequencedTaskRunner::GetCurrentDefault(); + support_id_ = support_id; } CorpSessionAuthzServiceClientFactory::~CorpSessionAuthzServiceClientFactory() = @@ -37,7 +39,8 @@ return std::make_unique<CorpSessionAuthzServiceClient>( url_loader_factory_, std::make_unique<OAuthTokenGetterProxy>(oauth_token_getter_->GetWeakPtr(), - oauth_token_getter_task_runner_)); + oauth_token_getter_task_runner_), + support_id_); } AuthenticationMethod CorpSessionAuthzServiceClientFactory::method() {
diff --git a/remoting/base/corp_session_authz_service_client_factory.h b/remoting/base/corp_session_authz_service_client_factory.h index 0835233..12c506f98 100644 --- a/remoting/base/corp_session_authz_service_client_factory.h +++ b/remoting/base/corp_session_authz_service_client_factory.h
@@ -6,11 +6,12 @@ #define REMOTING_BASE_CORP_SESSION_AUTHZ_SERVICE_CLIENT_FACTORY_H_ #include <memory> -#include <string> +#include <string_view> #include "base/memory/scoped_refptr.h" #include "base/task/sequenced_task_runner.h" #include "remoting/base/authentication_method.h" +#include "remoting/base/corp_session_authz_service_client.h" #include "remoting/base/session_authz_service_client_factory.h" namespace network { @@ -27,10 +28,13 @@ class CorpSessionAuthzServiceClientFactory : public SessionAuthzServiceClientFactory { public: + // |support_id|: The 7-digit support ID. Should only be provided for remote + // support. CorpSessionAuthzServiceClientFactory( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& service_account_email, - const std::string& refresh_token); + const std::string& refresh_token, + std::string_view support_id = {}); CorpSessionAuthzServiceClientFactory( const CorpSessionAuthzServiceClientFactory&) = delete; @@ -46,6 +50,7 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; std::unique_ptr<OAuthTokenGetterImpl> oauth_token_getter_; scoped_refptr<base::SequencedTaskRunner> oauth_token_getter_task_runner_; + std::string support_id_; }; } // namespace remoting
diff --git a/remoting/base/mock_session_authz_service_client.h b/remoting/base/mock_session_authz_service_client.h index 71cfccc..70865461 100644 --- a/remoting/base/mock_session_authz_service_client.h +++ b/remoting/base/mock_session_authz_service_client.h
@@ -20,11 +20,12 @@ MOCK_METHOD(void, GenerateHostToken, (GenerateHostTokenCallback callback)); MOCK_METHOD(void, VerifySessionToken, - (const internal::VerifySessionTokenRequestStruct& request, + (std::string_view session_token, VerifySessionTokenCallback callback)); MOCK_METHOD(void, ReauthorizeHost, - (const internal::ReauthorizeHostRequestStruct& request, + (std::string_view session_reauth_token, + std::string_view session_id, ReauthorizeHostCallback callback)); };
diff --git a/remoting/base/session_authz_service_client.h b/remoting/base/session_authz_service_client.h index 67199226..8f8a863 100644 --- a/remoting/base/session_authz_service_client.h +++ b/remoting/base/session_authz_service_client.h
@@ -6,6 +6,7 @@ #define REMOTING_BASE_SESSION_AUTHZ_SERVICE_CLIENT_H_ #include <memory> +#include <string_view> #include "base/functional/callback_forward.h" #include "remoting/base/protobuf_http_status.h" @@ -30,12 +31,11 @@ virtual ~SessionAuthzServiceClient() = default; virtual void GenerateHostToken(GenerateHostTokenCallback callback) = 0; - virtual void VerifySessionToken( - const internal::VerifySessionTokenRequestStruct& request, - VerifySessionTokenCallback callback) = 0; - virtual void ReauthorizeHost( - const internal::ReauthorizeHostRequestStruct& request, - ReauthorizeHostCallback callback) = 0; + virtual void VerifySessionToken(std::string_view session_token, + VerifySessionTokenCallback callback) = 0; + virtual void ReauthorizeHost(std::string_view session_reauth_token, + std::string_view session_id, + ReauthorizeHostCallback callback) = 0; protected: SessionAuthzServiceClient() = default;
diff --git a/remoting/host/it2me/BUILD.gn b/remoting/host/it2me/BUILD.gn index 81e56cc11..59bc09b 100644 --- a/remoting/host/it2me/BUILD.gn +++ b/remoting/host/it2me/BUILD.gn
@@ -138,10 +138,7 @@ if (is_chromeos) { source_set("chrome_os_host") { - sources = [ - "it2me_native_messaging_host_allowed_origins.cc", - "it2me_native_messaging_host_allowed_origins.h", - ] + sources = [ "it2me_native_messaging_host_allowed_origins.h" ] if (is_chromeos_lacros) { sources += [
diff --git a/remoting/host/it2me/it2me_native_messaging_host_allowed_origins.cc b/remoting/host/it2me/it2me_native_messaging_host_allowed_origins.cc deleted file mode 100644 index 321efa8..0000000 --- a/remoting/host/it2me/it2me_native_messaging_host_allowed_origins.cc +++ /dev/null
@@ -1,23 +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. - -#include "remoting/host/it2me/it2me_native_messaging_host_allowed_origins.h" - -#include <iterator> - -namespace remoting { - -// If you modify the list of allowed_origins, don't forget to update -// remoting/host/it2me/com.google.chrome.remote_assistance.json.jinja2 -// to keep the two lists in sync. -const char* const kIt2MeOrigins[] = { - "chrome-extension://inomeogfingihgjfjlpeplalcfajhgai/", - "chrome-extension://hpodccmdligbeohchckkeajbfohibipg/"}; - -const size_t kIt2MeOriginsSize = std::size(kIt2MeOrigins); - -const char kIt2MeNativeMessageHostName[] = - "com.google.chrome.remote_assistance"; - -} // namespace remoting
diff --git a/remoting/host/it2me/it2me_native_messaging_host_allowed_origins.h b/remoting/host/it2me/it2me_native_messaging_host_allowed_origins.h index a037c1d2..d9c09c1 100644 --- a/remoting/host/it2me/it2me_native_messaging_host_allowed_origins.h +++ b/remoting/host/it2me/it2me_native_messaging_host_allowed_origins.h
@@ -9,13 +9,16 @@ namespace remoting { // The set of origins which are allowed to instantiate an It2Me host. -extern const char* const kIt2MeOrigins[]; - -// The number of entries defined in |kIt2MeOrigins|. -extern const size_t kIt2MeOriginsSize; +// If you modify the list of allowed_origins, don't forget to update +// remoting/host/it2me/com.google.chrome.remote_assistance.json.jinja2 +// to keep the two lists in sync. +inline constexpr const char* kIt2MeOrigins[] = { + "chrome-extension://inomeogfingihgjfjlpeplalcfajhgai/", + "chrome-extension://hpodccmdligbeohchckkeajbfohibipg/"}; // The name used to register the It2Me native message host. -extern const char kIt2MeNativeMessageHostName[]; +inline constexpr char kIt2MeNativeMessageHostName[] = + "com.google.chrome.remote_assistance"; } // namespace remoting
diff --git a/remoting/internal b/remoting/internal index bc8e5db..f4b7da7f 160000 --- a/remoting/internal +++ b/remoting/internal
@@ -1 +1 @@ -Subproject commit bc8e5dbe2ea801d77d77ed8400e752f631f352a8 +Subproject commit f4b7da7fe40499ad775d1b2a730f4cd1de4ac05c
diff --git a/remoting/proto/internal_stubs.cc b/remoting/proto/internal_stubs.cc index 2c23af74..07ac238c 100644 --- a/remoting/proto/internal_stubs.cc +++ b/remoting/proto/internal_stubs.cc
@@ -128,10 +128,18 @@ // SessionAuthzService helpers // =========================== +std::string_view GetRemoteAccessSessionAuthzPath() { + return {}; +} + +std::string_view GetRemoteSupportSessionAuthzPath() { + return {}; +} + // GenerateHostToken -std::string GetGenerateHostTokenRequestPath() { - return ""; +std::string_view GetGenerateHostTokenRequestVerb() { + return {}; } std::unique_ptr<GenerateHostTokenRequest> GetGenerateHostTokenRequest( @@ -146,8 +154,8 @@ // VerifySessionToken -std::string GetVerifySessionTokenRequestPath() { - return ""; +std::string_view GetVerifySessionTokenRequestVerb() { + return {}; } std::unique_ptr<VerifySessionTokenRequest> GetVerifySessionTokenRequest( @@ -162,8 +170,8 @@ // ReauthorizeHost -std::string GetReauthorizeHostRequestPath() { - return ""; +std::string_view GetReauthorizeHostRequestVerb() { + return {}; } std::unique_ptr<ReauthorizeHostRequest> GetReauthorizeHostRequest(
diff --git a/remoting/proto/internal_stubs.h b/remoting/proto/internal_stubs.h index e9eee2ed..0c65e413 100644 --- a/remoting/proto/internal_stubs.h +++ b/remoting/proto/internal_stubs.h
@@ -8,6 +8,7 @@ #include <memory> #include <optional> #include <string> +#include <string_view> #include "remoting/proto/logging_service.h" #include "remoting/proto/session_authz_service.h" @@ -89,9 +90,12 @@ // SessionAuthzService helpers // =========================== +extern std::string_view GetRemoteAccessSessionAuthzPath(); +extern std::string_view GetRemoteSupportSessionAuthzPath(); + // GenerateHostToken using GenerateHostTokenRequest = DoNothingProto; -extern std::string GetGenerateHostTokenRequestPath(); +extern std::string_view GetGenerateHostTokenRequestVerb(); extern std::unique_ptr<GenerateHostTokenRequest> GetGenerateHostTokenRequest( const GenerateHostTokenRequestStruct&); @@ -101,7 +105,7 @@ // VerifySessionToken using VerifySessionTokenRequest = DoNothingProto; -extern std::string GetVerifySessionTokenRequestPath(); +extern std::string_view GetVerifySessionTokenRequestVerb(); extern std::unique_ptr<VerifySessionTokenRequest> GetVerifySessionTokenRequest( const VerifySessionTokenRequestStruct&); @@ -111,7 +115,7 @@ // ReauthorizeHost using ReauthorizeHostRequest = DoNothingProto; -extern std::string GetReauthorizeHostRequestPath(); +extern std::string_view GetReauthorizeHostRequestVerb(); extern std::unique_ptr<ReauthorizeHostRequest> GetReauthorizeHostRequest( const ReauthorizeHostRequestStruct&);
diff --git a/remoting/proto/session_authz_service.h b/remoting/proto/session_authz_service.h index 779ba1b..757111c 100644 --- a/remoting/proto/session_authz_service.h +++ b/remoting/proto/session_authz_service.h
@@ -16,7 +16,9 @@ // builds, they are populated by code in internal_stubs.h. namespace remoting::internal { -struct GenerateHostTokenRequestStruct {}; +struct GenerateHostTokenRequestStruct { + std::string support_id; +}; struct GenerateHostTokenResponseStruct { GenerateHostTokenResponseStruct(); @@ -33,6 +35,7 @@ bool operator==(const VerifySessionTokenRequestStruct&) const; std::string session_token; + std::string support_id; }; struct VerifySessionTokenResponseStruct { @@ -53,6 +56,7 @@ std::string session_reauth_token; std::string session_id; + std::string support_id; }; struct ReauthorizeHostResponseStruct {
diff --git a/remoting/protocol/session_authz_authenticator.cc b/remoting/protocol/session_authz_authenticator.cc index 0ca22a7..0d8b74e5 100644 --- a/remoting/protocol/session_authz_authenticator.cc +++ b/remoting/protocol/session_authz_authenticator.cc
@@ -197,10 +197,9 @@ const jingle_xmpp::XmlElement& message, base::OnceClosure resume_callback) { session_authz_state_ = SessionAuthzState::VERIFYING_SESSION_TOKEN; - internal::VerifySessionTokenRequestStruct request; - request.session_token = message.TextNamed(kSessionTokenTag); + std::string session_token = message.TextNamed(kSessionTokenTag); service_client_->VerifySessionToken( - request, + session_token, base::BindOnce(&SessionAuthzAuthenticator::OnVerifiedSessionToken, base::Unretained(this), message, std::move(resume_callback)));
diff --git a/remoting/protocol/session_authz_authenticator_unittest.cc b/remoting/protocol/session_authz_authenticator_unittest.cc index 6e86234..1f3c2f4 100644 --- a/remoting/protocol/session_authz_authenticator_unittest.cc +++ b/remoting/protocol/session_authz_authenticator_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> #include <optional> +#include <string_view> #include <tuple> #include "base/functional/bind.h" @@ -40,11 +41,12 @@ using testing::ByMove; using testing::Return; -constexpr char kFakeHostToken[] = "fake_host_token"; -constexpr char kFakeSessionId[] = "fake_session_id"; -constexpr char kFakeSessionToken[] = "fake_session_token"; -constexpr char kFakeSharedSecret[] = "fake_shared_secret"; -constexpr char kFakeSessionReauthToken[] = "fake_session_reauth_token"; +constexpr std::string_view kFakeHostToken = "fake_host_token"; +constexpr std::string_view kFakeSessionId = "fake_session_id"; +constexpr std::string_view kFakeSessionToken = "fake_session_token"; +constexpr std::string_view kFakeSharedSecret = "fake_shared_secret"; +constexpr std::string_view kFakeSessionReauthToken = + "fake_session_reauth_token"; constexpr base::TimeDelta kFakeSessionReauthTokenLifetime = base::Minutes(5); constexpr int kMessageSize = 100; constexpr int kMessages = 1; @@ -58,8 +60,8 @@ } auto RespondVerifySessionToken( - const std::string& session_id = kFakeSessionId, - const std::string& shared_secret = kFakeSharedSecret, + std::string_view session_id = kFakeSessionId, + std::string_view shared_secret = kFakeSharedSecret, const std::optional<SessionPolicies>& session_policies = std::nullopt) { auto response = std::make_unique<internal::VerifySessionTokenResponseStruct>(); @@ -175,8 +177,8 @@ message->TextNamed(SessionAuthzAuthenticator::kHostTokenTag); ASSERT_FALSE(host_token_.empty()); session_authz_state_ = SessionAuthzState::READY_TO_SEND_SESSION_TOKEN; - underlying_ = create_base_authenticator_callback_.Run(kFakeSharedSecret, - MESSAGE_READY); + underlying_ = create_base_authenticator_callback_.Run( + std::string(kFakeSharedSecret), MESSAGE_READY); std::move(resume_callback).Run(); return; case SessionAuthzState::AUTHORIZED: @@ -205,7 +207,7 @@ jingle_xmpp::XmlElement* session_token_element = new jingle_xmpp::XmlElement( SessionAuthzAuthenticator::kSessionTokenTag); - session_token_element->SetBodyText(kFakeSessionToken); + session_token_element->SetBodyText(std::string(kFakeSessionToken)); message->AddElement(session_token_element); session_authz_state_ = SessionAuthzState::AUTHORIZED; } @@ -278,11 +280,7 @@ TEST_F(SessionAuthzAuthenticatorTest, SuccessfulAuth) { EXPECT_CALL(*mock_service_client_, GenerateHostToken(_)) .WillOnce(RespondGenerateHostToken()); - internal::VerifySessionTokenRequestStruct - expected_verify_session_token_request; - expected_verify_session_token_request.session_token = kFakeSessionToken; - EXPECT_CALL(*mock_service_client_, - VerifySessionToken(expected_verify_session_token_request, _)) + EXPECT_CALL(*mock_service_client_, VerifySessionToken(kFakeSessionToken, _)) .WillOnce(RespondVerifySessionToken()); StartAuthExchange(); @@ -431,11 +429,9 @@ ASSERT_EQ(host_->state(), Authenticator::ACCEPTED); ASSERT_EQ(client_->state(), Authenticator::ACCEPTED); - internal::ReauthorizeHostRequestStruct request; - request.session_id = kFakeSessionId; - request.session_reauth_token = kFakeSessionReauthToken; - EXPECT_CALL(*mock_service_client_, ReauthorizeHost(request, _)) - .WillOnce(base::test::RunOnceCallback<1>( + EXPECT_CALL(*mock_service_client_, + ReauthorizeHost(kFakeSessionReauthToken, kFakeSessionId, _)) + .WillOnce(base::test::RunOnceCallback<2>( ProtobufHttpStatus(net::HttpStatusCode::HTTP_FORBIDDEN), nullptr)); EXPECT_CALL(state_change_after_accepted_callback, Run());
diff --git a/remoting/protocol/session_authz_reauthorizer.cc b/remoting/protocol/session_authz_reauthorizer.cc index 1b45b06..db24e80 100644 --- a/remoting/protocol/session_authz_reauthorizer.cc +++ b/remoting/protocol/session_authz_reauthorizer.cc
@@ -83,12 +83,10 @@ void SessionAuthzReauthorizer::Reauthorize() { HOST_LOG << "Reauthorizing session..."; - internal::ReauthorizeHostRequestStruct request; - request.session_id = session_id_; - request.session_reauth_token = session_reauth_token_; service_client_->ReauthorizeHost( - request, base::BindOnce(&SessionAuthzReauthorizer::OnReauthorizeResult, - base::Unretained(this))); + session_reauth_token_, session_id_, + base::BindOnce(&SessionAuthzReauthorizer::OnReauthorizeResult, + base::Unretained(this))); } void SessionAuthzReauthorizer::OnReauthorizeResult(
diff --git a/remoting/protocol/session_authz_reauthorizer_unittest.cc b/remoting/protocol/session_authz_reauthorizer_unittest.cc index 054a8bd4..0a39394 100644 --- a/remoting/protocol/session_authz_reauthorizer_unittest.cc +++ b/remoting/protocol/session_authz_reauthorizer_unittest.cc
@@ -27,31 +27,22 @@ using testing::_; -constexpr char kSessionId[] = "fake_session_id"; -constexpr char kInitialReauthToken[] = "fake_initial_reauth_token"; +constexpr std::string_view kSessionId = "fake_session_id"; +constexpr std::string_view kInitialReauthToken = "fake_initial_reauth_token"; constexpr base::TimeDelta kInitialTokenLifetime = base::Minutes(10); -internal::ReauthorizeHostRequestStruct CreateRequest( - std::string_view session_id, - std::string_view session_reauth_token) { - internal::ReauthorizeHostRequestStruct request; - request.session_id = session_id; - request.session_reauth_token = session_reauth_token; - return request; -} - auto Respond(std::string_view session_reauth_token, base::TimeDelta session_reauth_token_lifetime) { auto response = std::make_unique<internal::ReauthorizeHostResponseStruct>(); response->session_reauth_token = session_reauth_token; response->session_reauth_token_lifetime = session_reauth_token_lifetime; - return base::test::RunOnceCallback<1>(ProtobufHttpStatus::OK(), + return base::test::RunOnceCallback<2>(ProtobufHttpStatus::OK(), std::move(response)); } template <typename CodeType> auto RespondError(CodeType code) { - return base::test::RunOnceCallbackRepeatedly<1>(ProtobufHttpStatus(code), + return base::test::RunOnceCallbackRepeatedly<2>(ProtobufHttpStatus(code), nullptr); } @@ -87,32 +78,29 @@ TEST_F(SessionAuthzReauthorizerTest, MultipleSuccessfulReauths) { // Reauth is not triggered before half of the token lifetime has passed. - EXPECT_CALL(service_client_, ReauthorizeHost(_, _)).Times(0); + EXPECT_CALL(service_client_, ReauthorizeHost(_, _, _)).Times(0); task_environment_.FastForwardBy(kInitialTokenLifetime / 2 - base::Seconds(10)); // Reauth is triggered now. - EXPECT_CALL( - service_client_, - ReauthorizeHost(CreateRequest(kSessionId, kInitialReauthToken), _)) + EXPECT_CALL(service_client_, + ReauthorizeHost(kInitialReauthToken, kSessionId, _)) .WillOnce(Respond("fake_second_reauth_token", base::Minutes(8))); task_environment_.FastForwardBy(base::Seconds(10)); - EXPECT_CALL(service_client_, ReauthorizeHost(_, _)).Times(0); + EXPECT_CALL(service_client_, ReauthorizeHost(_, _, _)).Times(0); task_environment_.FastForwardBy(base::Minutes(4) - base::Seconds(10)); - EXPECT_CALL( - service_client_, - ReauthorizeHost(CreateRequest(kSessionId, "fake_second_reauth_token"), _)) + EXPECT_CALL(service_client_, + ReauthorizeHost("fake_second_reauth_token", kSessionId, _)) .WillOnce(Respond("fake_third_reauth_token", base::Minutes(6))); task_environment_.FastForwardBy(base::Seconds(10)); } TEST_F(SessionAuthzReauthorizerTest, ReauthFailedWithNonretriableError_ClosesSession) { - EXPECT_CALL( - service_client_, - ReauthorizeHost(CreateRequest(kSessionId, kInitialReauthToken), _)) + EXPECT_CALL(service_client_, + ReauthorizeHost(kInitialReauthToken, kSessionId, _)) .WillOnce(RespondError(net::HTTP_FORBIDDEN)); EXPECT_CALL(on_reauthorization_failed_callback_, Run()) .WillOnce(ResetReauthorizer()); @@ -120,9 +108,8 @@ } TEST_F(SessionAuthzReauthorizerTest, RetryReauthAndSucceed) { - EXPECT_CALL( - service_client_, - ReauthorizeHost(CreateRequest(kSessionId, kInitialReauthToken), _)) + EXPECT_CALL(service_client_, + ReauthorizeHost(kInitialReauthToken, kSessionId, _)) .WillRepeatedly(RespondError(net::ERR_INTERNET_DISCONNECTED)); task_environment_.FastForwardBy(kInitialTokenLifetime / 2); const net::BackoffEntry* backoff_entry = @@ -130,23 +117,20 @@ task_environment_.FastForwardBy(backoff_entry->GetTimeUntilRelease()); task_environment_.FastForwardBy(backoff_entry->GetTimeUntilRelease()); - EXPECT_CALL( - service_client_, - ReauthorizeHost(CreateRequest(kSessionId, kInitialReauthToken), _)) + EXPECT_CALL(service_client_, + ReauthorizeHost(kInitialReauthToken, kSessionId, _)) .WillOnce(Respond("fake_second_reauth_token", base::Minutes(8))); task_environment_.FastForwardBy(backoff_entry->GetTimeUntilRelease()); - EXPECT_CALL( - service_client_, - ReauthorizeHost(CreateRequest(kSessionId, "fake_second_reauth_token"), _)) + EXPECT_CALL(service_client_, + ReauthorizeHost("fake_second_reauth_token", kSessionId, _)) .WillOnce(Respond("fake_third_reauth_token", base::Minutes(6))); task_environment_.FastForwardBy(base::Minutes(4)); } TEST_F(SessionAuthzReauthorizerTest, RetriesExceedTokenLifetime_ClosesSession) { - EXPECT_CALL( - service_client_, - ReauthorizeHost(CreateRequest(kSessionId, kInitialReauthToken), _)) + EXPECT_CALL(service_client_, + ReauthorizeHost(kInitialReauthToken, kSessionId, _)) .WillRepeatedly(RespondError(net::ERR_INTERNET_DISCONNECTED)); EXPECT_CALL(on_reauthorization_failed_callback_, Run()).Times(0); task_environment_.FastForwardBy(kInitialTokenLifetime / 2);
diff --git a/remoting/test/session_authz_playground.cc b/remoting/test/session_authz_playground.cc index f4367bf3..8b05982 100644 --- a/remoting/test/session_authz_playground.cc +++ b/remoting/test/session_authz_playground.cc
@@ -7,6 +7,7 @@ #include <cstdio> #include <cstdlib> #include <memory> +#include <string_view> #include <vector> #include "base/command_line.h" @@ -67,7 +68,8 @@ service_client_ = std::make_unique<CorpSessionAuthzServiceClient>( url_loader_factory_owner_->GetURLLoaderFactory(), - CreateOAuthTokenGetter(host_config_file_path)); + CreateOAuthTokenGetter(host_config_file_path), + /* support_id= */ std::string_view()); run_loop_ = std::make_unique<base::RunLoop>(); GenerateHostToken(); @@ -99,10 +101,8 @@ void SessionAuthzPlayground::VerifySessionToken(const std::string& session_id) { printf("Enter session token generated by the client: "); std::string session_token = test::ReadString(); - internal::VerifySessionTokenRequestStruct request; - request.session_token = session_token; service_client_->VerifySessionToken( - request, + session_token, base::BindOnce( [](const std::string& session_id, const ProtobufHttpStatus& status, std::unique_ptr<internal::VerifySessionTokenResponseStruct> @@ -139,11 +139,8 @@ if (!shouldReauthorize) { run_loop_->Quit(); } - internal::ReauthorizeHostRequestStruct request; - request.session_id = session_id; - request.session_reauth_token = reauth_token; service_client_->ReauthorizeHost( - request, + reauth_token, session_id, base::BindOnce([](const ProtobufHttpStatus& status, std::unique_ptr<internal::ReauthorizeHostResponseStruct> response) {
diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc index 1c3ead1..4fb8e2a9 100644 --- a/sandbox/policy/win/sandbox_win.cc +++ b/sandbox/policy/win/sandbox_win.cc
@@ -594,6 +594,7 @@ base::Process* process) { base::LaunchOptions options; options.handles_to_inherit = handles_to_inherit; + options.feedback_cursor_off = true; // Network process runs in a job even when unsandboxed. This is to ensure it // does not outlive the browser, which could happen if there is a lot of I/O // on process shutdown, in which case TerminateProcess can fail. See @@ -829,6 +830,16 @@ trace_id, "pid", process_id); } + void OnCreateThreadActionCreateFailure(DWORD last_error) override { + UMA_HISTOGRAM_SPARSE( + "Process.Sandbox.IPC.ThreadCreateRemoteThreadErrorCode", last_error); + } + + void OnCreateThreadActionDuplicateFailure(DWORD last_error) override { + UMA_HISTOGRAM_SPARSE("Process.Sandbox.IPC.ThreadDuplicateHandleErrorCode", + last_error); + } + private: // When parallel launching is enabled, target creation will happen on the // thread pool. This is atomic to keep track of the number of threads that are
diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc index 89159fd..f6b6d8f95 100644 --- a/sandbox/win/src/broker_services.cc +++ b/sandbox/win/src/broker_services.cc
@@ -735,6 +735,10 @@ alt_desktop_.reset(); } +BrokerServicesDelegate* BrokerServicesBase::GetMetricsDelegate() { + return broker_services_delegate_.get(); +} + void BrokerServicesBase::SetBrokerServicesDelegateForTesting( std::unique_ptr<BrokerServicesDelegate> delegate) { broker_services_delegate_ = std::move(delegate);
diff --git a/sandbox/win/src/broker_services.h b/sandbox/win/src/broker_services.h index fc2ef22..bfad1f5 100644 --- a/sandbox/win/src/broker_services.h +++ b/sandbox/win/src/broker_services.h
@@ -74,6 +74,9 @@ void SetBrokerServicesDelegateForTesting( std::unique_ptr<BrokerServicesDelegate> delegate); + // Gets helper to log histograms from within the exe. + BrokerServicesDelegate* GetMetricsDelegate(); + static void FreezeTargetConfigForTesting(TargetConfig* config); private:
diff --git a/sandbox/win/src/handle_closer_agent.cc b/sandbox/win/src/handle_closer_agent.cc index e1fa5e0..4facea7 100644 --- a/sandbox/win/src/handle_closer_agent.cc +++ b/sandbox/win/src/handle_closer_agent.cc
@@ -44,6 +44,7 @@ // Additional warmup done just when CSRSS is being disconnected. bool CsrssDisconnectWarmup() { + std::ignore = ::GetUserDefaultLCID(); return ::EnumSystemLocalesEx(EnumLocalesProcEx, LOCALE_WINDOWS, 0, 0); }
diff --git a/sandbox/win/src/parallel_launch_test.cc b/sandbox/win/src/parallel_launch_test.cc index a4fd309..9d95060 100644 --- a/sandbox/win/src/parallel_launch_test.cc +++ b/sandbox/win/src/parallel_launch_test.cc
@@ -38,6 +38,8 @@ void AfterTargetProcessCreateOnCreationThread(const void* trace_id, DWORD process_id) override {} + void OnCreateThreadActionCreateFailure(DWORD last_error) override {} + void OnCreateThreadActionDuplicateFailure(DWORD last_error) override {} }; class ParallelLaunchTest : public testing::Test {
diff --git a/sandbox/win/src/process_thread_dispatcher.cc b/sandbox/win/src/process_thread_dispatcher.cc index 48af0fe..2f9a75f 100644 --- a/sandbox/win/src/process_thread_dispatcher.cc +++ b/sandbox/win/src/process_thread_dispatcher.cc
@@ -97,7 +97,6 @@ DWORD ret = ProcessPolicy::CreateThreadAction(*ipc->client_info, stack_size, start_address, parameter, creation_flags, &handle); - ipc->return_info.win32_result = ret; ipc->return_info.handle = handle; return true;
diff --git a/sandbox/win/src/process_thread_policy.cc b/sandbox/win/src/process_thread_policy.cc index 1211a8b..d6e7ce2 100644 --- a/sandbox/win/src/process_thread_policy.cc +++ b/sandbox/win/src/process_thread_policy.cc
@@ -13,10 +13,12 @@ #include "base/memory/free_deleter.h" #include "base/win/scoped_handle.h" #include "build/build_config.h" +#include "sandbox/win/src/broker_services.h" #include "sandbox/win/src/ipc_tags.h" #include "sandbox/win/src/nt_internals.h" #include "sandbox/win/src/policy_engine_opcodes.h" #include "sandbox/win/src/policy_params.h" +#include "sandbox/win/src/sandbox.h" #include "sandbox/win/src/sandbox_nt_util.h" #include "sandbox/win/src/sandbox_types.h" #include "sandbox/win/src/win_utils.h" @@ -109,11 +111,24 @@ ::CreateRemoteThread(client_info.process, nullptr, stack_size, start_address, parameter, creation_flags, nullptr)); if (!local_handle.is_valid()) { - return ::GetLastError(); + // Gather diagnostics for failures - we avoid always DumpWithoutCrashing as + // it might mask child process crashes that result when this IPC returns + // failure. See crbug.com/389729365. + DWORD gle = ::GetLastError(); + BrokerServicesBase::GetInstance() + ->GetMetricsDelegate() + ->OnCreateThreadActionCreateFailure(gle); + return gle; } if (!CallDuplicateHandle(::GetCurrentProcess(), local_handle.get(), client_info.process, handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { + // Gather diagnostics for failures - we avoid always DumpWithoutCrashing as + // it might mask child process crashes that result when this IPC returns + // failure. See crbug.com/389729365. + BrokerServicesBase::GetInstance() + ->GetMetricsDelegate() + ->OnCreateThreadActionDuplicateFailure(::GetLastError()); return ERROR_ACCESS_DENIED; } return ERROR_SUCCESS;
diff --git a/sandbox/win/src/sandbox.h b/sandbox/win/src/sandbox.h index 483ea39..f6c4b29 100644 --- a/sandbox/win/src/sandbox.h +++ b/sandbox/win/src/sandbox.h
@@ -303,6 +303,14 @@ // this will be called on the thread pool. virtual void AfterTargetProcessCreateOnCreationThread(const void* trace_id, DWORD process_id) = 0; + + // Record error histograms when CreateThreadAction IPC failed to create a + // thread in the target process. + virtual void OnCreateThreadActionCreateFailure(DWORD last_error) = 0; + // Record error histograms when CreateThreadAction IPC failed to duplicate a + // handle into the child process. + virtual void OnCreateThreadActionDuplicateFailure(DWORD last_error) = 0; + virtual ~BrokerServicesDelegate() {} };
diff --git a/sandbox/win/tests/common/controller.cc b/sandbox/win/tests/common/controller.cc index 72f9ad5d..ff3a801a 100644 --- a/sandbox/win/tests/common/controller.cc +++ b/sandbox/win/tests/common/controller.cc
@@ -155,6 +155,8 @@ void AfterTargetProcessCreateOnCreationThread(const void* trace_id, DWORD process_id) override {} + void OnCreateThreadActionCreateFailure(DWORD last_error) override {} + void OnCreateThreadActionDuplicateFailure(DWORD last_error) override {} }; BrokerServices* GetBroker() {
diff --git a/services/network/cookie_settings.cc b/services/network/cookie_settings.cc index 36483846..e37e8f3a 100644 --- a/services/network/cookie_settings.cc +++ b/services/network/cookie_settings.cc
@@ -49,6 +49,15 @@ !cookie.IsPartitioned(); } +// Third-party cookies are considered restricted when they are blocked and could +// be unblocked by mitigations. +bool OverridesSimulateThirdPartyCookieRestriction( + net::CookieSettingOverrides overrides) { + return overrides.HasAll( + {net::CookieSettingOverride::kForceDisableThirdPartyCookies, + net::CookieSettingOverride::kForceEnableThirdPartyCookieMitigations}); +} + bool IsValidType(ContentSettingsType type) { // ContentSettingsType::TPCD_METADATA_GRANTS settings are managed by the // `network::tpcd::metadata::Manager` and are considered valid ContentSettings @@ -220,7 +229,8 @@ bool allowed = IsCookieAllowed(cookie, setting_with_metadata); if (cookie_inclusion_status) { AugmentInclusionStatus(cookie, top_frame_origin, setting_with_metadata, - first_party_set_metadata, *cookie_inclusion_status); + first_party_set_metadata, overrides, + *cookie_inclusion_status); } RecordAllowedByStorageAccessType( @@ -295,12 +305,12 @@ for (net::CookieWithAccessResult& cookie : maybe_included_cookies) { AugmentInclusionStatus(cookie.cookie, top_frame_origin, setting_with_metadata, first_party_set_metadata, - cookie.access_result.status); + overrides, cookie.access_result.status); } for (net::CookieWithAccessResult& cookie : excluded_cookies) { AugmentInclusionStatus(cookie.cookie, top_frame_origin, setting_with_metadata, first_party_set_metadata, - cookie.access_result.status); + overrides, cookie.access_result.status); } const auto to_be_moved = std::ranges::stable_partition( maybe_included_cookies, [](const net::CookieWithAccessResult& cookie) { @@ -399,17 +409,21 @@ base::optional_ref<const url::Origin> top_frame_origin, const CookieSettings::CookieSettingWithMetadata& setting_with_metadata, const net::FirstPartySetMetadata& first_party_set_metadata, + net::CookieSettingOverrides overrides, net::CookieInclusionStatus& out_status) const { bool affected_by_3pcd_origin_trial = top_frame_origin && IsBlockedByTopLevel3pcdOriginTrial(top_frame_origin->GetURL()); + bool should_attach_3pcd_status = + OverridesSimulateThirdPartyCookieRestriction(overrides); if (IsCookieAllowed(cookie, setting_with_metadata)) { if (!setting_with_metadata.is_third_party_request() || !ShouldApply3pcdRelatedReasons(cookie)) { return; } - if (ShouldBlockThirdPartyCookies() || affected_by_3pcd_origin_trial) { + if (ShouldBlockThirdPartyCookies() || affected_by_3pcd_origin_trial || + should_attach_3pcd_status) { out_status.MaybeSetExemptionReason(GetExemptionReason( setting_with_metadata.third_party_cookie_allow_mechanism())); return; @@ -427,7 +441,8 @@ if (setting_with_metadata.is_third_party_request() && setting_with_metadata.allow_partitioned_cookies()) { - if (IsThirdPartyPhaseoutEnabled() && + if ((IsThirdPartyPhaseoutEnabled() || affected_by_3pcd_origin_trial || + should_attach_3pcd_status) && !setting_with_metadata.is_explicit_setting()) { // This cookie is blocked due to 3PCD. if (!ShouldApply3pcdRelatedReasons(cookie)) { @@ -443,14 +458,6 @@ } return; } - if (affected_by_3pcd_origin_trial && - ShouldApply3pcdRelatedReasons(cookie)) { - // This cookie is blocked by the Origin Trial for 3PCD. - out_status.AddExclusionReason( - net::CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT); - - return; - } } // The cookie is blocked, but not by 3PCD.
diff --git a/services/network/cookie_settings.h b/services/network/cookie_settings.h index 84f2bbc..314d9abc 100644 --- a/services/network/cookie_settings.h +++ b/services/network/cookie_settings.h
@@ -222,6 +222,7 @@ base::optional_ref<const url::Origin> top_frame_origin, const CookieSettings::CookieSettingWithMetadata& setting_with_metadata, const net::FirstPartySetMetadata& first_party_set_metadata, + net::CookieSettingOverrides overrides, net::CookieInclusionStatus& out_status) const; // Returns true if at least one content settings is session only.
diff --git a/services/network/cookie_settings_unittest.cc b/services/network/cookie_settings_unittest.cc index f6efc93..f86847b 100644 --- a/services/network/cookie_settings_unittest.cc +++ b/services/network/cookie_settings_unittest.cc
@@ -519,6 +519,66 @@ /*expected_bucket_count=*/1); } +TEST_F(CookieSettingsTest, + IsCookieAccessible_CookieSettingOverrideBlockSameSiteNoneCookie) { + CookieSettings settings; + net::CookieInclusionStatus status; + + std::unique_ptr<net::CanonicalCookie> cookie = + MakeCanonicalSameSiteNoneCookie("name", kURL); + const url::Origin top_level_origin = url::Origin::Create(GURL(kOtherURL)); + + settings.set_block_third_party_cookies(false); + + auto is_third_party_cookie_accessible = + [&](net::CookieSettingOverrides overrides) -> bool { + return settings.IsCookieAccessible( + *cookie, GURL(kURL), net::SiteForCookies(), top_level_origin, + net::FirstPartySetMetadata(), overrides, &status); + }; + // Third-party cookie is accessible with no source blocking it. + ASSERT_TRUE(is_third_party_cookie_accessible(net::CookieSettingOverrides())); + ASSERT_TRUE(status.HasWarningReason( + net::CookieInclusionStatus::WARN_THIRD_PARTY_PHASEOUT)); + + status.ResetForTesting(); + // Third-party cookies are blocked by overrides. + EXPECT_FALSE(is_third_party_cookie_accessible( + {net::CookieSettingOverride::kForceDisableThirdPartyCookies})); + EXPECT_TRUE(status.HasExclusionReason( + net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES)); + + net::CookieSettingOverrides overrides( + {net::CookieSettingOverride::kForceDisableThirdPartyCookies, + net::CookieSettingOverride::kForceEnableThirdPartyCookieMitigations}); + status.ResetForTesting(); + // Verify that cookie has the phaseout exclusion reason with both required + // overrides present. + EXPECT_FALSE(is_third_party_cookie_accessible(overrides)); + EXPECT_TRUE(status.HasExclusionReason( + net::CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT)); + + // No override can overrule a site-specific setting. + settings.set_content_settings( + ContentSettingsType::COOKIES, + {CreateSetting(kURL, "*", CONTENT_SETTING_BLOCK)}); + status.ResetForTesting(); + EXPECT_FALSE(is_third_party_cookie_accessible(overrides)); + // Cookies blocked by a site-specific setting should still use + // `EXCLUDE_USER_PREFERENCES` reason. + EXPECT_TRUE(status.HasExclusionReason( + net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES)); + + // No override can overrule a global setting. + status.ResetForTesting(); + settings.set_content_settings( + ContentSettingsType::COOKIES, + {CreateSetting("*", "*", CONTENT_SETTING_BLOCK)}); + EXPECT_FALSE(is_third_party_cookie_accessible(overrides)); + EXPECT_TRUE(status.HasOnlyExclusionReason( + net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES)); +} + TEST_F(CookieSettingsTest, ShouldAlwaysAllowCookies) { CookieSettings settings; settings.set_secure_origin_cookies_allowed_schemes({kChromeScheme}); @@ -1817,6 +1877,63 @@ _, _, _)))); } +TEST_F( + CookieSettingsTest, + AnnotateAndMoveUserBlockedCookies_CrossSiteEmbed_CookieSettingOverrideBlock3PC) { + CookieSettings settings; + settings.set_block_third_party_cookies(false); + + const url::Origin origin = url::Origin::Create(GURL(kOtherURL)); + + net::CookieSettingOverrides overrides( + {net::CookieSettingOverride::kForceDisableThirdPartyCookies}); + { + net::CookieAccessResultList maybe_included_cookies = { + {*MakeCanonicalSameSiteNoneCookie("third_party", kURL), {}}}; + net::CookieAccessResultList excluded_cookies = {}; + + EXPECT_FALSE(settings.AnnotateAndMoveUserBlockedCookies( + GURL(kURL), net::SiteForCookies(), &origin, + net::FirstPartySetMetadata(), overrides, maybe_included_cookies, + excluded_cookies)); + + EXPECT_THAT( + excluded_cookies, + UnorderedElementsAre(MatchesCookieWithAccessResult( + net::MatchesCookieWithName("third_party"), + MatchesCookieAccessResult( + net::HasExactlyExclusionReasonsForTesting( + std::vector<net::CookieInclusionStatus::ExclusionReason>{ + net::CookieInclusionStatus::ExclusionReason:: + EXCLUDE_USER_PREFERENCES}), + _, _, _)))); + } + // Both overrides should be present to yield the phaseout exclusion reason. + overrides.Put( + net::CookieSettingOverride::kForceEnableThirdPartyCookieMitigations); + { + net::CookieAccessResultList maybe_included_cookies = { + {*MakeCanonicalSameSiteNoneCookie("third_party", kURL), {}}}; + net::CookieAccessResultList excluded_cookies = {}; + EXPECT_FALSE(settings.AnnotateAndMoveUserBlockedCookies( + GURL(kURL), net::SiteForCookies(), &origin, + net::FirstPartySetMetadata(), overrides, maybe_included_cookies, + excluded_cookies)); + + // Verify that the excluded cookie has the expected reason. + EXPECT_THAT( + excluded_cookies, + UnorderedElementsAre(MatchesCookieWithAccessResult( + net::MatchesCookieWithName("third_party"), + MatchesCookieAccessResult( + net::HasExactlyExclusionReasonsForTesting( + std::vector<net::CookieInclusionStatus::ExclusionReason>{ + net::CookieInclusionStatus::ExclusionReason:: + EXCLUDE_THIRD_PARTY_PHASEOUT}), + _, _, _)))); + } +} + TEST_F(CookieSettingsTest, AnnotateAndMoveUserBlockedCookies_SameSiteEmbed_3PCAllowed) { CookieSettings settings;
diff --git a/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.cc b/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.cc index 0cee2e02..2c73f897 100644 --- a/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.cc +++ b/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.cc
@@ -55,6 +55,7 @@ out->may_throttle_if_undrawn_frames = data.may_throttle_if_undrawn_frames(); out->has_shared_element_resources = data.has_shared_element_resources(); out->is_handling_interaction = data.is_handling_interaction(); + out->is_handling_animation = data.is_handling_animation(); out->send_frame_token_to_embedder = data.send_frame_token_to_embedder(); out->min_page_scale_factor = data.min_page_scale_factor(); out->is_software = data.is_software();
diff --git a/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.h b/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.h index 1b5b9c0e..378d4858 100644 --- a/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.h +++ b/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.h
@@ -79,6 +79,11 @@ return metadata.is_handling_interaction; } + static bool is_handling_animation( + const viz::CompositorFrameMetadata& metadata) { + return metadata.is_handling_animation; + } + static SkColor4f root_background_color( const viz::CompositorFrameMetadata& metadata) { return metadata.root_background_color;
diff --git a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc index 9eec4eb..c3330ff 100644 --- a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc +++ b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc
@@ -61,7 +61,7 @@ viz::ResourceId id; gpu::SyncToken sync_token; - viz::MemoryBufferId memory_buffer_id; + gpu::Mailbox memory_buffer_id; if (!data.ReadSize(&out->size) || !data.ReadFormat(&out->format) || !data.ReadMemoryBufferId(&memory_buffer_id) || !data.ReadSyncToken(&sync_token) || @@ -91,46 +91,4 @@ return true; } -// static -viz::mojom::MemoryBufferIdDataView::Tag -UnionTraits<viz::mojom::MemoryBufferIdDataView, viz::MemoryBufferId>::GetTag( - const viz::MemoryBufferId& memory_buffer_id) { - return absl::visit( - base::Overloaded{ - [](gpu::Mailbox) { - return viz::mojom::MemoryBufferIdDataView::Tag::kMailbox; - }, - - [](viz::SharedBitmapId) { - return viz::mojom::MemoryBufferIdDataView::Tag::kSharedBitmapId; - }, - }, - memory_buffer_id); -} - -// static -bool UnionTraits<viz::mojom::MemoryBufferIdDataView, viz::MemoryBufferId>::Read( - viz::mojom::MemoryBufferIdDataView memory_buffer_id, - viz::MemoryBufferId* out) { - switch (memory_buffer_id.tag()) { - case viz::mojom::MemoryBufferIdDataView::Tag::kMailbox: { - gpu::Mailbox mailbox; - if (!memory_buffer_id.ReadMailbox(&mailbox)) { - return false; - } - *out = mailbox; - return true; - } - case viz::mojom::MemoryBufferIdDataView::Tag::kSharedBitmapId: { - viz::SharedBitmapId shared_bitmap_id; - if (!memory_buffer_id.ReadSharedBitmapId(&shared_bitmap_id)) { - return false; - } - *out = shared_bitmap_id; - return true; - } - } - return false; -} - } // namespace mojo
diff --git a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h index 94add9ba..57c556c 100644 --- a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h +++ b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h
@@ -45,7 +45,7 @@ return resource.size; } - static viz::MemoryBufferId memory_buffer_id( + static gpu::Mailbox memory_buffer_id( const viz::TransferableResource& resource) { return resource.memory_buffer_id(); } @@ -120,24 +120,6 @@ viz::TransferableResource* out); }; -template <> -struct UnionTraits<viz::mojom::MemoryBufferIdDataView, viz::MemoryBufferId> { - static viz::mojom::MemoryBufferIdDataView::Tag GetTag( - const viz::MemoryBufferId& memory_buffer_id); - - static gpu::Mailbox mailbox(const viz::MemoryBufferId& memory_buffer_id) { - return absl::get<gpu::Mailbox>(memory_buffer_id); - } - - static viz::SharedBitmapId shared_bitmap_id( - const viz::MemoryBufferId& memory_buffer_id) { - return absl::get<viz::SharedBitmapId>(memory_buffer_id); - } - - static bool Read(viz::mojom::MemoryBufferIdDataView memory_buffer_id, - viz::MemoryBufferId* out); -}; - } // namespace mojo #endif // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_TRANSFERABLE_RESOURCE_MOJOM_TRAITS_H_
diff --git a/services/viz/public/mojom/compositing/compositor_frame_metadata.mojom b/services/viz/public/mojom/compositing/compositor_frame_metadata.mojom index 9ae2759..95c491ee 100644 --- a/services/viz/public/mojom/compositing/compositor_frame_metadata.mojom +++ b/services/viz/public/mojom/compositing/compositor_frame_metadata.mojom
@@ -35,6 +35,7 @@ bool may_contain_video; bool may_throttle_if_undrawn_frames; bool is_handling_interaction; + bool is_handling_animation; skia.mojom.SkColor4f root_background_color; array<ui.mojom.LatencyInfo> latency_info; array<SurfaceRange> referenced_surfaces;
diff --git a/services/viz/public/mojom/compositing/transferable_resource.mojom b/services/viz/public/mojom/compositing/transferable_resource.mojom index 688db8b1..3038b05 100644 --- a/services/viz/public/mojom/compositing/transferable_resource.mojom +++ b/services/viz/public/mojom/compositing/transferable_resource.mojom
@@ -23,12 +23,6 @@ kReleaseFence, }; -// See components/viz/common/resources/transferable_resource.h. -union MemoryBufferId { - gpu.mojom.Mailbox mailbox; - SharedBitmapId shared_bitmap_id; -}; - // Represents a visual resource (e.g., image, video frame) that can be // transferred between processes for rendering and compositing within Chromium's // Viz display system. Encapsulates the resource's data, format, and metadata @@ -39,7 +33,7 @@ ResourceId id; SharedImageFormat format; gfx.mojom.Size size; - MemoryBufferId memory_buffer_id; + gpu.mojom.Mailbox memory_buffer_id; gpu.mojom.SyncToken sync_token; uint32 texture_target; SynchronizationType synchronization_type;
diff --git a/styleguide/java/nullaway.md b/styleguide/java/nullaway.md index 1312756c..8a48f880 100644 --- a/styleguide/java/nullaway.md +++ b/styleguide/java/nullaway.md
@@ -16,7 +16,7 @@ [Chromium's NullAway configuration] is as follows: * [JSpecify mode] is enabled. * `@Nullable` is `TYPE_USE`. - * Non-annotated means non-null for fields, parameters, and return types. + * Non-annotated means non-null (no need for `@NonNull`). * Nullness of local variables is inferred. * Copies of [supported annotations] exist under `org.chromium.build.annotations`.
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn index 133e945..1e4a2d3 100644 --- a/testing/buildbot/filters/BUILD.gn +++ b/testing/buildbot/filters/BUILD.gn
@@ -240,6 +240,7 @@ testonly = true data = [ + "//testing/buildbot/filters/android.emulator_10.content_unittests.filter", "//testing/buildbot/filters/android.emulator_14.content_unittests.filter", "//testing/buildbot/filters/android.emulator_15_16.content_unittests.filter", "//testing/buildbot/filters/android.device.content_unittests.filter",
diff --git a/testing/buildbot/filters/android.emulator_10.content_unittests.filter b/testing/buildbot/filters/android.emulator_10.content_unittests.filter new file mode 100644 index 0000000..359ceb8d --- /dev/null +++ b/testing/buildbot/filters/android.emulator_10.content_unittests.filter
@@ -0,0 +1,2 @@ +# crbug.com/390669723 +-FontUniqueNameLookupTest.TestMatchPostScriptNameTtc \ No newline at end of file
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index a0eafd3..5835ec90 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -341,6 +341,38 @@ ] } ], + "AndroidAppIntegrationV2": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled_SkipSchemaCheck", + "params": { + "skip_schema_check": "true", + "use_large_favicon": "true" + }, + "enable_features": [ + "AndroidAppIntegrationModule", + "AndroidAppIntegrationV2", + "AndroidAppIntegrationWithFavicon" + ] + }, + { + "name": "Enabled", + "params": { + "use_large_favicon": "true" + }, + "enable_features": [ + "AndroidAppIntegrationModule", + "AndroidAppIntegrationV2", + "AndroidAppIntegrationWithFavicon" + ] + } + ] + } + ], "AndroidAutofillPrefillRequestsForChangePassword": [ { "platforms": [ @@ -5349,8 +5381,10 @@ ], "experiments": [ { - "name": "Enabled", + "name": "EnabledV2", "params": { + "disable_blend": "true", + "enable_v2": "true", "max_tiles_number": "1", "show_see_more": "true", "show_tabs_in_one_module": "true", @@ -5362,10 +5396,8 @@ ] }, { - "name": "EnabledV2", + "name": "Enabled", "params": { - "disable_blend": "true", - "enable_v2": "true", "max_tiles_number": "1", "show_see_more": "true", "show_tabs_in_one_module": "true", @@ -9584,21 +9616,6 @@ ] } ], - "ExternalRateControlForMediaFoundationVideoEncoder": [ - { - "platforms": [ - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "MediaFoundationUseSWBRCForH264Camera" - ] - } - ] - } - ], "ExtremeLightweightUAFDetector": [ { "platforms": [ @@ -11635,21 +11652,6 @@ ] } ], - "IOSDisableParcelTracking": [ - { - "platforms": [ - "ios" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "IOSDisableParcelTracking" - ] - } - ] - } - ], "IOSDockingPromo": [ { "platforms": [ @@ -14868,27 +14870,6 @@ ] } ], - "NewEvSignalsEnabled": [ - { - "platforms": [ - "windows", - "mac", - "linux" - ], - "experiments": [ - { - "name": "Enabled", - "params": { - "DisableFileSystemInfo": "true", - "DisableSettings": "true" - }, - "enable_features": [ - "NewEvSignalsEnabled" - ] - } - ] - } - ], "NewOSCryptAlgorithmForPasswords": [ { "platforms": [ @@ -21965,6 +21946,27 @@ ] } ], + "ServiceWorkerSrcdocSupport": [ + { + "platforms": [ + "android", + "android_webview", + "chromeos", + "fuchsia", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "ServiceWorkerSrcdocSupport" + ] + } + ] + } + ], "ServiceWorkerStaticRouterRaceNetworkRequestPerformanceImprovement": [ { "platforms": [ @@ -24068,6 +24070,22 @@ ] } ], + "UseAdHocSigningForWebAppShims": [ + { + "platforms": [ + "mac" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "MachPortRendezvousValidatePeerRequirements", + "UseAdHocSigningForWebAppShims" + ] + } + ] + } + ], "UseBoringSSLForRandBytes": [ { "platforms": [ @@ -24941,10 +24959,7 @@ ], "experiments": [ { - "name": "Enabled_2_pending_frames", - "params": { - "PendingFrames": "2" - }, + "name": "Enabled", "enable_features": [ "VSyncAlignedPresent" ]
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn index 0f84aa08..26b9996c9 100644 --- a/third_party/android_deps/BUILD.gn +++ b/third_party/android_deps/BUILD.gn
@@ -694,28 +694,6 @@ } # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. - java_prebuilt("com_google_dagger_hilt_core_java") { - jar_path = "cipd/libs/com_google_dagger_hilt_core/hilt-core-2.52.jar" - output_name = "com_google_dagger_hilt_core" - supports_android = true - enable_bytecode_checks = false - deps = [ - ":com_google_code_findbugs_jsr305_java", - ":javax_inject_javax_inject_java", - "//third_party/android_deps:dagger_java", - ] - - # https://crbug.com/1412551 - requires_android = true - - # Google3 organizes targets differently from maven. Restrict to the only classes we use. - jar_included_patterns = [ - "dagger/hilt/internal/GeneratedComponentManager.class", - "dagger/hilt/internal/GeneratedComponentManagerHolder.class", - ] - } - - # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. if (google_play_services_package == "//third_party/android_deps") { android_aar_prebuilt("google_firebase_firebase_iid_java") { aar_path =
diff --git a/third_party/android_deps/additional_readme_paths.json b/third_party/android_deps/additional_readme_paths.json index 36c906a..bec9a62 100644 --- a/third_party/android_deps/additional_readme_paths.json +++ b/third_party/android_deps/additional_readme_paths.json
@@ -36,7 +36,6 @@ "libs/com_google_code_findbugs_jsr305", "libs/com_google_code_gson_gson", "libs/com_google_dagger_dagger", - "libs/com_google_dagger_hilt_core", "libs/com_google_errorprone_error_prone_annotations", "libs/com_google_firebase_firebase_annotations", "libs/com_google_firebase_firebase_common",
diff --git a/third_party/android_deps/build.gradle b/third_party/android_deps/build.gradle index 40e7d31b..9960005 100644 --- a/third_party/android_deps/build.gradle +++ b/third_party/android_deps/build.gradle
@@ -142,7 +142,6 @@ String daggerVersion = '2.52' compile "com.google.dagger:dagger:${daggerVersion}" - compile "com.google.dagger:hilt-core:${daggerVersion}" // Used by ModuleInterfaceProcessor.java buildCompile 'com.squareup:javapoet:1.13.0'
diff --git a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy index 71ae93c..f41bb3ff 100644 --- a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy +++ b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
@@ -716,7 +716,6 @@ if (dependencyExtension == 'jar' && ( dependencyId.startsWith('io_grpc_') || dependencyId == 'com_google_firebase_firebase_encoders' || - dependencyId == 'com_google_dagger_hilt_core' || dependencyId == 'com_google_guava_guava_android')) { sb.append(' # https://crbug.com/1412551\n') sb.append(' requires_android = true\n') @@ -816,14 +815,6 @@ // and android_aar_prebuilt template will fail if it's not set explictly. sb.append(' extract_native_libraries = true\n') break - case 'com_google_dagger_hilt_core': - sb.append('\n') - sb.append(' # Google3 organizes targets differently from maven. Restrict to the only classes we use.\n') - sb.append(' jar_included_patterns = [\n') - sb.append(' "dagger/hilt/internal/GeneratedComponentManager.class",\n') - sb.append(' "dagger/hilt/internal/GeneratedComponentManagerHolder.class",\n') - sb.append(' ]\n') - break case 'com_google_auto_service_auto_service_annotations_java': sb.append(' preferred_dep = true\n') break
diff --git a/third_party/android_deps/libs/com_google_dagger_hilt_core/3pp/3pp.pb b/third_party/android_deps/libs/com_google_dagger_hilt_core/3pp/3pp.pb deleted file mode 100644 index d743b51b..0000000 --- a/third_party/android_deps/libs/com_google_dagger_hilt_core/3pp/3pp.pb +++ /dev/null
@@ -1,16 +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. - -# This is generated, do not edit. Update BuildConfigGenerator.groovy instead. - -create { - source { - script { name: "fetch.py" } - } -} - -upload { - pkg_prefix: "chromium/third_party/android_deps/libs" - universal: true -}
diff --git a/third_party/android_deps/libs/com_google_dagger_hilt_core/3pp/fetch.py b/third_party/android_deps/libs/com_google_dagger_hilt_core/3pp/fetch.py deleted file mode 100755 index 772e0a0..0000000 --- a/third_party/android_deps/libs/com_google_dagger_hilt_core/3pp/fetch.py +++ /dev/null
@@ -1,26 +0,0 @@ -#!/usr/bin/env python3 -# 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. - -# This is generated, do not edit. Update BuildConfigGenerator.groovy and -# 3ppFetch.template instead. - -import pathlib -import sys - -_3PP_DIR = pathlib.Path(__file__).resolve().parent -sys.path.insert(0, str(_3PP_DIR.parents[2])) -import fetch_common - -_REPO_URL = 'https://repo.maven.apache.org/maven2' -SPEC = fetch_common.Spec(repo_url=_REPO_URL, - group_name='com/google/dagger', - module_name='hilt-core', - file_ext='jar', - patch_version='cr1', - version_override=None, - version_filter=None) - -if __name__ == '__main__': - fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_google_dagger_hilt_core/LICENSE b/third_party/android_deps/libs/com_google_dagger_hilt_core/LICENSE deleted file mode 100644 index d645695..0000000 --- a/third_party/android_deps/libs/com_google_dagger_hilt_core/LICENSE +++ /dev/null
@@ -1,202 +0,0 @@ - - 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/android_deps/libs/com_google_dagger_hilt_core/OWNERS b/third_party/android_deps/libs/com_google_dagger_hilt_core/OWNERS deleted file mode 100644 index aea47a05..0000000 --- a/third_party/android_deps/libs/com_google_dagger_hilt_core/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_google_dagger_hilt_core/README.chromium b/third_party/android_deps/libs/com_google_dagger_hilt_core/README.chromium deleted file mode 100644 index 63a52ab..0000000 --- a/third_party/android_deps/libs/com_google_dagger_hilt_core/README.chromium +++ /dev/null
@@ -1,15 +0,0 @@ -Name: Hilt Core -Short Name: hilt-core -URL: https://github.com/google/dagger -Version: 2.52 -License: Apache-2.0 -License File: LICENSE -CPEPrefix: unknown -Security Critical: yes -Shipped: yes - -Description: -A fast dependency injector for Android and Java. - -Local Modifications: -No modifications.
diff --git a/third_party/android_deps/libs/com_google_dagger_hilt_core/cipd.yaml b/third_party/android_deps/libs/com_google_dagger_hilt_core/cipd.yaml deleted file mode 100644 index 1aca8a3..0000000 --- a/third_party/android_deps/libs/com_google_dagger_hilt_core/cipd.yaml +++ /dev/null
@@ -1,10 +0,0 @@ -# Copyright 2018 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@2.52.cr1 -package: chromium/third_party/android_deps/libs/com_google_dagger_hilt_core -description: "Hilt Core" -data: -- file: hilt-core-2.52.jar
diff --git a/third_party/angle b/third_party/angle index 6dc14de..0dabfe5 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 6dc14dedf85a49786d5503fdf5e692d87d57bb2d +Subproject commit 0dabfe5a6ac5377854a3f5ee673d56315c175e71
diff --git a/third_party/blink/common/permissions_policy/README.md b/third_party/blink/common/permissions_policy/README.md index 8bbaff4..f1f7e9f 100644 --- a/third_party/blink/common/permissions_policy/README.md +++ b/third_party/blink/common/permissions_policy/README.md
@@ -1,6 +1,6 @@ ## Permissions Policy Guide (Previously Feature Policy) Permissions policy is the new name for feature policy with a new HTTP header which uses -[structured header](https://www.rfc-editor.org/rfc/rfc9651) syntax. +[Structured Field](https://www.rfc-editor.org/rfc/rfc9651) syntax. ### How to add a new feature to permissions policy @@ -103,10 +103,11 @@ Example HTTP header: `Document-Policy: force-load-at-top=?0, lossy-images-max-bpp=1.0` -- `force-load-at-top` is set to boolean value false (`?0` in [structured header syntax](https://httpwg.org/http-extensions/draft-ietf-httpbis-header-structure.html)), i.e. the - feature is disallowed in current document; -- `lossy-images-max-bpp` is set to 1.0, i.e. lossy image format (e.g. jpeg) images with -byte per pixel rate higher than 1.0 will be blocked. +- `force-load-at-top` is set to boolean value false (`?0` in [Structured Field +syntax](https://www.rfc-editor.org/rfc/rfc9651#section-3.3.6)), i.e. the feature +is disallowed in current document; +- `lossy-images-max-bpp` is set to 1.0, i.e. lossy image format (e.g. jpeg) +images with byte per pixel rate higher than 1.0 will be blocked. #### Adding a new feature to document policy
diff --git a/third_party/blink/perf_tests/webcodecs/copyTo-test.js b/third_party/blink/perf_tests/webcodecs/copyTo-test.js index cae17ce9..6d18a00 100644 --- a/third_party/blink/perf_tests/webcodecs/copyTo-test.js +++ b/third_party/blink/perf_tests/webcodecs/copyTo-test.js
@@ -10,10 +10,10 @@ function runCopyToTest(frame, desc) { let isDone = false; + let size = frame.allocationSize(); + let buf = new makeSharedBuffer(size); function runTest() { - let size = frame.allocationSize(); - let buf = new makeSharedBuffer(size); let startTime = PerfTestRunner.now(); PerfTestRunner.addRunTestStartMarker(); frame.copyTo(buf) @@ -43,16 +43,15 @@ function runBatchCopyToTest(frames, desc) { let isDone = false; + let frames_and_buffers = frames.map(frame => { + let size = frame.allocationSize(); + let buf = new makeSharedBuffer(size); + return [frame, buf]; + }); function runTest() { let startTime = PerfTestRunner.now(); PerfTestRunner.addRunTestStartMarker(); - - let frames_and_buffers = frames.map(frame => { - let size = frame.allocationSize(); - let buf = new makeSharedBuffer(size); - return [frame, buf]; - }); let readback_promises = frames_and_buffers.map(([frame, buf]) => { return frame.copyTo(buf); });
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom index 103a4b29..88fb5e1b 100644 --- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom +++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -684,16 +684,16 @@ kExecCommandOnInputOrTextarea = 1027, kV8History_ScrollRestoration_AttributeGetter = 1028, kV8History_ScrollRestoration_AttributeSetter = 1029, - kSVG1DOMFilter = 1030, + kObsoleteSVG1DOMFilter = 1030, kOfflineAudioContextStartRendering = 1031, kOfflineAudioContextSuspend = 1032, kOfflineAudioContextResume = 1033, - kSVG1DOMPaintServer = 1035, + kObsoleteSVG1DOMPaintServer = 1035, kSVGSVGElementFragmentSVGView = 1036, kSVGSVGElementFragmentSVGViewElement = 1037, kPresentationConnectionClose = 1038, kSVG1DOMShape = 1039, - kSVG1DOMText = 1040, + kObsoleteSVG1DOMText = 1040, kRTCPeerConnectionConstructorConstraints = 1041, kRTCPeerConnectionConstructorCompliant = 1042, kRTCPeerConnectionCreateOfferLegacyFailureCallback = 1044,
diff --git a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md index afe3cce2a..8bcc4034 100644 --- a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md +++ b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
@@ -707,7 +707,6 @@ ```webidl [HighEntropy] attribute Node interestingAttribute; [HighEntropy] Node getInterestingNode(); -[HighEntropy] const INTERESTING_CONSTANT = 1; ``` Attributes and methods labeled with `[HighEntropy=Direct]` are simple surfaces which can be expressed as a sequence of bytes without any need for additional parsing logic. @@ -764,7 +763,7 @@ ```webidl [Measure] attribute Node interestingAttribute; [Measure] Node getInterestingNode(); -[Measure] const INTERESTING_CONSTANT = 1; +// Note that Measure is longer supported on constants. ``` ### [MeasureAs] @@ -781,7 +780,7 @@ ```webidl [MeasureAs=AttributeWeAreInterestedIn] attribute Node interestingAttribute; [MeasureAs=MethodsAreInterestingToo] Node getInterestingNode(); -[MeasureAs=EvenSomeConstantsAreInteresting] const INTERESTING_CONSTANT = 1; +// Note that MeasureAs is longer supported on constants. ``` ### [NotEnumerable]
diff --git a/third_party/blink/renderer/bindings/core/v8/script_function.cc b/third_party/blink/renderer/bindings/core/v8/script_function.cc index abadeca..a78b8c7 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_function.cc +++ b/third_party/blink/renderer/bindings/core/v8/script_function.cc
@@ -27,8 +27,7 @@ kDOMWrappersTag, WrapperTypeInfo::kWrapperTypeNoPrototype, WrapperTypeInfo::kCustomWrappableId, - WrapperTypeInfo::kNotInheritFromActiveScriptWrappable, - WrapperTypeInfo::kCustomWrappableKind, + WrapperTypeInfo::kIdlOtherType, }; } // namespace
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni index d0e982dc..0d68f8d 100644 --- a/third_party/blink/renderer/bindings/generated_in_modules.gni +++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -2470,6 +2470,8 @@ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_launch_params.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_launch_queue.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_launch_queue.h", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_layout_worklet_global_scope.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_layout_worklet_global_scope.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_linear_acceleration_sensor.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_linear_acceleration_sensor.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_lock.cc", @@ -2814,6 +2816,8 @@ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_service_worker_global_scope.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_service_worker_registration.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_service_worker_registration.h", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_shadow_realm_global_scope.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_shadow_realm_global_scope.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_shared_storage.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_shared_storage.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_shared_storage_worklet.cc",
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py index 3d7a12e..8303f4df 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -2248,35 +2248,6 @@ return func_def -def make_constant_callback_def(cg_context, function_name): - assert isinstance(cg_context, CodeGenContext) - assert isinstance(function_name, str) - - logging_nodes = SequenceNode([ - make_report_deprecate_as(cg_context), - make_report_measure_as(cg_context), - make_log_activity(cg_context), - ]) - if not logging_nodes: - return None - - func_def = _make_empty_callback_def(cg_context, function_name) - body = func_def.body - - v8_set_return_value = _format( - "bindings::V8SetReturnValue(${info}, ${class_name}::Constant::{});", - constant_name(cg_context)) - body.extend([ - make_runtime_call_timer_scope(cg_context), - make_bindings_trace_event(cg_context), - logging_nodes, - EmptyNode(), - TextNode(v8_set_return_value), - ]) - - return func_def - - def make_constant_constant_def(cg_context, constant_name): # IDL constant's C++ constant definition assert isinstance(cg_context, CodeGenContext) @@ -4634,43 +4605,11 @@ ]) -def _make_constant_callback_registration_table(table_name, constant_entries): - assert isinstance(table_name, str) - assert isinstance(constant_entries, (list, tuple)) - assert all( - isinstance(entry, _PropEntryConstant) - and isinstance(entry.const_callback_name, str) - for entry in constant_entries) - - T = TextNode - - entry_nodes = [] - pattern = ( - "{{" # - "\"{property_name}\", " - "{constant_callback}" - "}},") - for entry in constant_entries: - text = _format( - pattern, - property_name=entry.property_.identifier, - constant_callback=entry.const_callback_name) - entry_nodes.append(T(text)) - - return ListNode([ - T("static const IDLMemberInstaller::ConstantCallbackConfig " + - table_name + "[] = {"), - ListNode(entry_nodes), - T("};"), - ]) - - def _make_constant_value_registration_table(table_name, constant_entries): assert isinstance(table_name, str) assert isinstance(constant_entries, (list, tuple)) assert all( - isinstance(entry, _PropEntryConstant) - and entry.const_callback_name is None for entry in constant_entries) + isinstance(entry, _PropEntryConstant) for entry in constant_entries) T = TextNode @@ -4892,13 +4831,11 @@ class _PropEntryConstant(_PropEntryBase): def __init__(self, is_context_dependent, exposure_conditional, world, - constant, const_callback_name, const_constant_name): - assert _is_none_or_str(const_callback_name) + constant, const_constant_name): assert isinstance(const_constant_name, str) _PropEntryBase.__init__(self, is_context_dependent, exposure_conditional, world, constant) - self.const_callback_name = const_callback_name self.const_constant_name = const_constant_name @@ -5053,27 +4990,16 @@ constant=constant, for_world=world, v8_callback_type=CodeGenContext.V8_ACCESSOR_NAME_GETTER_CALLBACK) - const_callback_name = callback_function_name(cgc) - const_callback_node = make_constant_callback_def( - cgc, const_callback_name) - if const_callback_node is None: - const_callback_name = None # IDL constant's C++ constant name const_constant_name = _format("${class_name}::Constant::{}", constant_name(cgc)) - callback_def_nodes.extend([ - const_callback_node, - EmptyNode(), - ]) - constant_entries.append( _PropEntryConstant( is_context_dependent=is_context_dependent, exposure_conditional=exposure_conditional, world=world, constant=constant, - const_callback_name=const_callback_name, const_constant_name=const_constant_name)) def process_constructor_group(constructor_group, is_context_dependent, @@ -5936,25 +5862,12 @@ install_properties(table_name, entries, _make_attribute_registration_table, installer_call_text) - table_name = "kConstantCallbackTable" - installer_call_text = _format( - pattern_without_interface_name, - install_func="IDLMemberInstaller::InstallConstants", - table_name=table_name) - constant_callback_entries = list( - filter(lambda entry: entry.const_callback_name, constant_entries)) - install_properties(table_name, constant_callback_entries, - _make_constant_callback_registration_table, - installer_call_text) - table_name = "kConstantValueTable" installer_call_text = _format( pattern_without_interface_name, install_func="IDLMemberInstaller::InstallConstants", table_name=table_name) - constant_value_entries = list( - filter(lambda entry: not entry.const_callback_name, constant_entries)) - install_properties(table_name, constant_value_entries, + install_properties(table_name, constant_entries, _make_constant_value_registration_table, installer_call_text) @@ -6539,7 +6452,6 @@ ${class_name}::kMaxSubclassTag, {wrapper_type_prototype}, {wrapper_class_id}, - {active_script_wrappable_inheritance}, {idl_definition_kind}, {is_skipped_in_interface_object_prototype_chain}, }}; @@ -6567,20 +6479,12 @@ wrapper_class_id = "WrapperTypeInfo::kNodeClassId" else: wrapper_class_id = "WrapperTypeInfo::kObjectClassId" - if class_like.code_generator_info.is_active_script_wrappable: - active_script_wrappable_inheritance = ( - "WrapperTypeInfo::kInheritFromActiveScriptWrappable") - else: - active_script_wrappable_inheritance = ( - "WrapperTypeInfo::kNotInheritFromActiveScriptWrappable") - if class_like.is_interface: + if class_like.is_interface or class_like.is_callback_interface: idl_definition_kind = "WrapperTypeInfo::kIdlInterface" elif class_like.is_namespace: idl_definition_kind = "WrapperTypeInfo::kIdlNamespace" - elif class_like.is_callback_interface: - idl_definition_kind = "WrapperTypeInfo::kIdlCallbackInterface" elif class_like.is_async_iterator or class_like.is_sync_iterator: - idl_definition_kind = "WrapperTypeInfo::kIdlAsyncOrSyncIterator" + idl_definition_kind = "WrapperTypeInfo::kIdlOtherType" else: assert False is_skipped_in_interface_object_prototype_chain = ( @@ -6592,8 +6496,6 @@ wrapper_type_info_of_inherited=wrapper_type_info_of_inherited, wrapper_type_prototype=wrapper_type_prototype, wrapper_class_id=wrapper_class_id, - active_script_wrappable_inheritance=( - active_script_wrappable_inheritance), idl_definition_kind=idl_definition_kind, is_skipped_in_interface_object_prototype_chain=( is_skipped_in_interface_object_prototype_chain))) @@ -6695,9 +6597,6 @@ if entry.exposure_conditional.is_always_true: callback_names.append(entry.attr_get_callback_name) callback_names.append(entry.attr_set_callback_name) - for entry in constant_entries: - if entry.exposure_conditional.is_always_true: - callback_names.append(entry.const_callback_name) for entry in constructor_entries: if entry.exposure_conditional.is_always_true: callback_names.append(entry.ctor_callback_name)
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/observable_array.py b/third_party/blink/renderer/bindings/scripts/bind_gen/observable_array.py index e6a93ea..ae77342 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/observable_array.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/observable_array.py
@@ -86,8 +86,7 @@ kDOMWrappersTag, WrapperTypeInfo::kWrapperTypeNoPrototype, WrapperTypeInfo::kObjectClassId, - WrapperTypeInfo::kNotInheritFromActiveScriptWrappable, - WrapperTypeInfo::kIdlObservableArray, + WrapperTypeInfo::kIdlOtherType, }; // static
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py b/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py index 95a24e9b..de97f07 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py
@@ -9,6 +9,7 @@ from . import name_style from .blink_v8_bridge import blink_class_name +from web_idl.composition_parts import WithExtendedAttributes class PathManager(object): @@ -104,9 +105,22 @@ self._impl_component = default_component elif len(components) == 1: component = components[0] - self._is_cross_components = False - self._api_component = component - self._impl_component = component + # Global interfaces generally have exposed constructors, which we + # don't currently label with their component. If a global interface + # is defined in core, put the impl in modules even if no partial + # interfaces are defined in modules. + # TODO(japhet, caseq): Figure out why exposed constructors don't + # influence component calculations. + if (isinstance(idl_definition, WithExtendedAttributes) + and "Global" in idl_definition.extended_attributes + and component == "core"): + self._is_cross_components = True + self._api_component = web_idl.Component("core") + self._impl_component = web_idl.Component("modules") + else: + self._is_cross_components = False + self._api_component = component + self._impl_component = component elif len(components) == 2: assert components[0] == "core" assert components[1] == "modules"
diff --git a/third_party/blink/renderer/core/dom/container_node.cc b/third_party/blink/renderer/core/dom/container_node.cc index 0ac17ca2..0778eed 100644 --- a/third_party/blink/renderer/core/dom/container_node.cc +++ b/third_party/blink/renderer/core/dom/container_node.cc
@@ -171,7 +171,11 @@ ExceptionState& exception_state) { if (auto* fragment = DynamicTo<DocumentFragment>(node)) { GetChildNodes(*fragment, nodes); - fragment->RemoveChildren(); + if (fragment->HoldsUnnotifiedChildren()) { + fragment->ForgetChildren(); + } else { + fragment->RemoveChildren(); + } return !nodes.empty(); } nodes.push_back(&node); @@ -1247,7 +1251,8 @@ probe::DidInsertDOMNode(this); } -void ContainerNode::ParserFinishedBuildingDocumentFragment() { +void ContainerNode::ParserFinishedBuildingDocumentFragment( + ShouldNotifyInsertedNodes call_mode) { EventDispatchForbiddenScope assert_no_event_dispatch; ScriptForbiddenScope forbid_script; const bool may_contain_shadow_roots = GetDocument().MayContainShadowRoots(); @@ -1256,10 +1261,11 @@ ChildrenChange::ForFinishingBuildingDocumentFragmentTree(); for (Node& node : NodeTraversal::DescendantsOf(*this)) { NotifyNodeAtEndOfBuildingFragmentTree(node, change, - may_contain_shadow_roots); + may_contain_shadow_roots, call_mode); } - if (GetDocument().ShouldInvalidateNodeListCaches(nullptr)) { + if (call_mode == ShouldNotifyInsertedNodes::kNotify && + GetDocument().ShouldInvalidateNodeListCaches(nullptr)) { GetDocument().InvalidateNodeListCaches(nullptr); } } @@ -1267,7 +1273,8 @@ void ContainerNode::NotifyNodeAtEndOfBuildingFragmentTree( Node& node, const ChildrenChange& change, - bool may_contain_shadow_roots) { + bool may_contain_shadow_roots, + ShouldNotifyInsertedNodes call_mode) { // Fast path parser only creates disconnected nodes. DCHECK(!node.isConnected()); @@ -1287,13 +1294,15 @@ // kInsertionShouldCallDidNotifySubtreeInsertions, but only if the node // is connected. None of the nodes are connected at this point, so it's // not needed here. - node.InsertedInto(*this); + if (call_mode == ShouldNotifyInsertedNodes::kNotify) { + node.InsertedInto(*this); + } if (ShadowRoot* shadow_root = node.GetShadowRoot()) { for (Node& shadow_node : NodeTraversal::InclusiveDescendantsOf(*shadow_root)) { - NotifyNodeAtEndOfBuildingFragmentTree(shadow_node, change, - may_contain_shadow_roots); + NotifyNodeAtEndOfBuildingFragmentTree( + shadow_node, change, may_contain_shadow_roots, call_mode); } }
diff --git a/third_party/blink/renderer/core/dom/container_node.h b/third_party/blink/renderer/core/dom/container_node.h index f9b48f2..fff8df5 100644 --- a/third_party/blink/renderer/core/dom/container_node.h +++ b/third_party/blink/renderer/core/dom/container_node.h
@@ -188,7 +188,11 @@ // Called when the parser has finished building a DocumentFragment. This is // not called if the parser fails parsing (if parsing fails, the // DocumentFragment is orphaned and will eventually be gc'd). - void ParserFinishedBuildingDocumentFragment(); + // + // ShouldNotifyInsertedNodes controls whether to skip notifications that are + // redone if the contents of the DocumentFragment are moved to a new parent. + enum class ShouldNotifyInsertedNodes { kNotify, kSkip }; + void ParserFinishedBuildingDocumentFragment(ShouldNotifyInsertedNodes); void ParserRemoveChild(Node&); void ParserInsertBefore(Node* new_child, Node& ref_child); void ParserTakeAllChildrenFrom(ContainerNode&); @@ -528,7 +532,8 @@ // it was inserted. void NotifyNodeAtEndOfBuildingFragmentTree(Node& node, const ChildrenChange& change, - bool may_contain_shadow_roots); + bool may_contain_shadow_roots, + ShouldNotifyInsertedNodes); NodeListsNodeData& EnsureNodeLists(); void RemoveBetween(Node* previous_child, Node* next_child, Node& old_child);
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 6395917c..a55e16e 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -1643,6 +1643,8 @@ parser_behavior, nullptr); SetParsingState(kFinishedParsing); if (success) { + body->ParserFinishedBuildingDocumentFragment( + ShouldNotifyInsertedNodes::kNotify); // When DCHECK is enabled, use SetContent() and verify fast-path // content matches. This effectively means the results of the fast-path // parser aren't used with DCHECK enabled, but it provides a way to
diff --git a/third_party/blink/renderer/core/dom/document_fragment.cc b/third_party/blink/renderer/core/dom/document_fragment.cc index 31fd2d1..c548af0e 100644 --- a/third_party/blink/renderer/core/dom/document_fragment.cc +++ b/third_party/blink/renderer/core/dom/document_fragment.cc
@@ -103,6 +103,26 @@ source, this, context_element, parser_content_policy, exception_state); } +void DocumentFragment::ForgetChildren() { + DCHECK(HoldsUnnotifiedChildren()); + + if (!hasChildren()) { + return; + } + + Node* next_child = firstChild(); + do { + Node* child = next_child; + child->SetParentOrShadowHostNode(nullptr); + child->SetPreviousSibling(nullptr); + next_child = child->nextSibling(); + child->SetNextSibling(nullptr); + } while (next_child); + + SetFirstChild(nullptr); + SetLastChild(nullptr); +} + void DocumentFragment::Trace(Visitor* visitor) const { visitor->Trace(document_part_root_); ContainerNode::Trace(visitor);
diff --git a/third_party/blink/renderer/core/dom/document_fragment.h b/third_party/blink/renderer/core/dom/document_fragment.h index c71cf52..fda76b52 100644 --- a/third_party/blink/renderer/core/dom/document_fragment.h +++ b/third_party/blink/renderer/core/dom/document_fragment.h
@@ -53,6 +53,19 @@ bool CanContainRangeEndPoint() const final { return true; } virtual bool IsTemplateContent() const { return false; } + // These represent whether this DocumentFragment is one that holds + // children that have not had Node::InsertedInto called. We use such + // DocumentFragment objects internally for temporary storage of + // parsing results. This requires that when we move the children + // *out* of the DocumentFragment we also not call RemovedFrom. + bool HoldsUnnotifiedChildren() const { return holds_unnotified_children_; } + void SetHoldsUnnotifiedChildren(bool v) { holds_unnotified_children_ = v; } + + // When HoldsUnnotifiedChildren() is true, a caller that is taking the + // children can call ForgetChildren to disconnect them without any + // notifications. + void ForgetChildren(); + // This will catch anyone doing an unnecessary check. bool IsDocumentFragment() const = delete; @@ -74,6 +87,7 @@ bool ChildTypeAllowed(NodeType) const override; Member<DocumentPartRoot> document_part_root_; + bool holds_unnotified_children_ = false; }; template <>
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index b64fcd3..eb91d32 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1273,45 +1273,63 @@ void Element::InterestGained() { CHECK(RuntimeEnabledFeatures::HTMLInterestTargetAttributeEnabled()); + CHECK(IsInTreeScope()); + CHECK(GetDocument().IsActive()); - if (!IsInTreeScope()) { - return; - } - - Element* interest_target_element = this->interestTargetElement(); - AtomicString interest_action = this->interestAction(); - if (interest_target_element && !interest_action.IsNull()) { - // TODO(crbug.com/326681249): This should only fire if action is valid. - Event* interest_event = InterestEvent::Create(event_type_names::kInterest, - interest_action, this); + if (Element* interest_target_element = this->interestTargetElement()) { + Event* interest_event = + InterestEvent::Create(event_type_names::kInterest, this); interest_target_element->DispatchEvent(*interest_event); if (!interest_event->defaultPrevented()) { if (auto* popover = DynamicTo<HTMLElement>(interest_target_element); popover && popover->PopoverType() != PopoverValueType::kNone) { - if (!(interest_action.empty() || - EqualIgnoringASCIICase(interest_action, - keywords::kTogglePopover))) { - return; - } - // TODO(crbug.com/326681249): This might need to queue a task with a // delay based on CSS properties. - auto& document = GetDocument(); - bool can_show = popover->IsPopoverReady( - PopoverTriggerAction::kShow, - /*exception_state=*/nullptr, - /*include_event_handler_text=*/true, &document); - bool can_hide = popover->IsPopoverReady( - PopoverTriggerAction::kHide, - /*exception_state=*/nullptr, - /*include_event_handler_text=*/true, &document); - if (can_hide) { + if (popover->IsPopoverReady(PopoverTriggerAction::kShow, + /*exception_state=*/nullptr, + /*include_event_handler_text=*/true, + &GetDocument())) { + popover->InvokePopover(*this); + } + } else if (auto* dialog = + DynamicTo<HTMLDialogElement>(interest_target_element)) { + if (!dialog->IsOpen()) { + dialog->showModal(ASSERT_NO_EXCEPTION); + } + } + } + } +} + +void Element::InterestLost() { + CHECK(RuntimeEnabledFeatures::HTMLInterestTargetAttributeEnabled()); + CHECK(IsInTreeScope()); + + // TODO(masonf): It would be a good idea to add a DHECK method that makes sure + // we never get InterestLost without first getting an InterestGained. + + if (Element* interest_target_element = this->interestTargetElement()) { + Event* lose_interest_event = + InterestEvent::Create(event_type_names::kLoseinterest, this); + interest_target_element->DispatchEvent(*lose_interest_event); + if (!lose_interest_event->defaultPrevented()) { + if (auto* popover = DynamicTo<HTMLElement>(interest_target_element); + popover && popover->PopoverType() != PopoverValueType::kNone) { + // TODO(crbug.com/326681249): This might need to queue a task with a + // delay based on CSS properties. + if (popover->IsPopoverReady(PopoverTriggerAction::kHide, + /*exception_state=*/nullptr, + /*include_event_handler_text=*/true, + &GetDocument())) { popover->HidePopoverInternal( HidePopoverFocusBehavior::kFocusPreviousElement, HidePopoverTransitionBehavior::kFireEventsAndWaitForTransitions, /*exception_state=*/nullptr); - } else if (can_show) { - popover->InvokePopover(*this); + } + } else if (auto* dialog = + DynamicTo<HTMLDialogElement>(interest_target_element)) { + if (dialog->IsOpen()) { + dialog->close(); } } } @@ -6625,11 +6643,6 @@ FocusStateChanged(); - if (received && - RuntimeEnabledFeatures::HTMLInterestTargetAttributeEnabled()) { - InterestGained(); - } - if (GetLayoutObject() || received) { return; } @@ -10205,8 +10218,13 @@ InvalidateIfHasEffectiveAppearance(); - if (hovered && RuntimeEnabledFeatures::HTMLInterestTargetAttributeEnabled()) { - InterestGained(); + if (RuntimeEnabledFeatures::HTMLInterestTargetAttributeEnabled() && + IsInTreeScope() && GetDocument().IsActive()) { + if (hovered) { + InterestGained(); + } else { + InterestLost(); + } } }
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h index 356ebee..026f1c33 100644 --- a/third_party/blink/renderer/core/dom/element.h +++ b/third_party/blink/renderer/core/dom/element.h
@@ -1071,10 +1071,10 @@ return false; } + // Implementation of the `interesttarget` feature. void InterestGained(); - + void InterestLost(); virtual Element* interestTargetElement() { return nullptr; } - virtual AtomicString interestAction() const { return g_null_atom; } // The implementations of |innerText()| and |GetInnerTextWithoutUpdate()| are // found in "element_inner_text.cc".
diff --git a/third_party/blink/renderer/core/dom/interest_invoker_element.idl b/third_party/blink/renderer/core/dom/interest_invoker_element.idl index 95f7549..e47885c 100644 --- a/third_party/blink/renderer/core/dom/interest_invoker_element.idl +++ b/third_party/blink/renderer/core/dom/interest_invoker_element.idl
@@ -5,5 +5,4 @@ [RuntimeEnabled=HTMLInterestTargetAttribute] interface mixin InterestInvokerElement { [CEReactions,Reflect=interesttarget] attribute Element? interestTargetElement; - [CEReactions,Reflect=interestaction] attribute DOMString interestAction; };
diff --git a/third_party/blink/renderer/core/editing/element_inner_text.cc b/third_party/blink/renderer/core/editing/element_inner_text.cc index 3238fe2..abea002b89 100644 --- a/third_party/blink/renderer/core/editing/element_inner_text.cc +++ b/third_party/blink/renderer/core/editing/element_inner_text.cc
@@ -92,6 +92,7 @@ unsigned ProcessFirstLineAndGetOffset(const LayoutText& layout_text); void ProcessNode(const Node& node); void ProcessOptionElement(const HTMLOptionElement& element); + void ProcessOptGroupElement(const HTMLOptGroupElement& element); void ProcessSelectElement(const HTMLSelectElement& element); void ProcessTextNode(const Text& node); @@ -427,8 +428,59 @@ result_.EmitRequiredLineBreak(1); } +void ElementInnerTextCollector::ProcessOptGroupElement( + const HTMLOptGroupElement& optgroup) { + CHECK(RuntimeEnabledFeatures::SelectParserRelaxationEnabled()); + // Note: We should emit newline for OPTGROUP even if it has no OPTION. + // e.g. <div>a<select><optgroup></select>b</div>.innerText == "a\nb" + result_.EmitRequiredLineBreak(1); + Element* descendant = ElementTraversal::FirstChild(optgroup); + while (descendant) { + if (visitor_) { + visitor_->WillVisit(*descendant, result_.length()); + } + // TODO(crbug.com/389573453): Consider handling <hr> elements here. + if (auto* option = DynamicTo<HTMLOptionElement>(descendant)) { + ProcessOptionElement(*option); + descendant = + ElementTraversal::NextSkippingChildren(*descendant, &optgroup); + } else if (IsA<HTMLOptGroupElement>(descendant)) { + // TODO(crbug.com/389573453): Consider adding nested <optgroup>s here. For + // now we will skip them. + descendant = + ElementTraversal::NextSkippingChildren(*descendant, &optgroup); + } else { + descendant = ElementTraversal::Next(*descendant, &optgroup); + } + } + result_.EmitRequiredLineBreak(1); +} + void ElementInnerTextCollector::ProcessSelectElement( const HTMLSelectElement& select_element) { + if (RuntimeEnabledFeatures::SelectParserRelaxationEnabled()) { + // TODO(crbug.com/40271842): Consider Handling display:none on various + // elements here, especially options. + Element* descendant = ElementTraversal::FirstChild(select_element); + while (descendant) { + if (visitor_) { + visitor_->WillVisit(*descendant, result_.length()); + } + // TODO(crbug.com/389573453): Consider handling <hr> elements here. + if (auto* option = DynamicTo<HTMLOptionElement>(descendant)) { + ProcessOptionElement(*option); + descendant = ElementTraversal::NextSkippingChildren(*descendant, + &select_element); + } else if (auto* optgroup = DynamicTo<HTMLOptGroupElement>(descendant)) { + ProcessOptGroupElement(*optgroup); + descendant = ElementTraversal::NextSkippingChildren(*descendant, + &select_element); + } else { + descendant = ElementTraversal::Next(*descendant, &select_element); + } + } + return; + } for (const Node& child : NodeTraversal::ChildrenOf(select_element)) { if (visitor_) { visitor_->WillVisit(child, result_.length());
diff --git a/third_party/blink/renderer/core/editing/serializers/serialization.cc b/third_party/blink/renderer/core/editing/serializers/serialization.cc index 19abbc7..736ad759 100644 --- a/third_party/blink/renderer/core/editing/serializers/serialization.cc +++ b/third_party/blink/renderer/core/editing/serializers/serialization.cc
@@ -683,6 +683,9 @@ markup, document, *fragment, *context_element, parser_content_policy, parser_behavior, &log_tag_stats); if (parsed_fast_path) { + fragment->SetHoldsUnnotifiedChildren(true); + fragment->ParserFinishedBuildingDocumentFragment( + DocumentFragment::ShouldNotifyInsertedNodes::kSkip); LogFastPathParserTotalTime(parse_timer.Elapsed()); #if DCHECK_IS_ON() // As a sanity check for the fast-path, create another fragment using
diff --git a/third_party/blink/renderer/core/events/interest_event.cc b/third_party/blink/renderer/core/events/interest_event.cc index b943932..8eec3c0 100644 --- a/third_party/blink/renderer/core/events/interest_event.cc +++ b/third_party/blink/renderer/core/events/interest_event.cc
@@ -16,39 +16,33 @@ const InterestEventInit* initializer) : Event(type, initializer) { DCHECK(RuntimeEnabledFeatures::HTMLInterestTargetAttributeEnabled()); - if (initializer->hasInvoker()) { - invoker_ = initializer->invoker(); - } - if (initializer->hasAction()) { - action_ = initializer->action(); + if (initializer->hasSource()) { + source_ = initializer->source(); } } -InterestEvent::InterestEvent(const AtomicString& type, - const String& action, - Element* invoker) +InterestEvent::InterestEvent(const AtomicString& type, Element* source) : Event(type, Bubbles::kNo, Cancelable::kYes, ComposedMode::kComposed), - invoker_(invoker), - action_(action) { + source_(source) { DCHECK(RuntimeEnabledFeatures::HTMLInterestTargetAttributeEnabled()); } -Element* InterestEvent::invoker() const { - Element* invoker = invoker_.Get(); - if (!invoker) { +Element* InterestEvent::source() const { + Element* source = source_.Get(); + if (!source) { return nullptr; } if (auto* current = currentTarget()) { CHECK(current->ToNode()); - return ¤t->ToNode()->GetTreeScope().Retarget(*invoker); + return ¤t->ToNode()->GetTreeScope().Retarget(*source); } DCHECK_EQ(eventPhase(), Event::PhaseType::kNone); - return invoker; + return source; } void InterestEvent::Trace(Visitor* visitor) const { - visitor->Trace(invoker_); + visitor->Trace(source_); Event::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/events/interest_event.h b/third_party/blink/renderer/core/events/interest_event.h index fed5bd7..6db27e7 100644 --- a/third_party/blink/renderer/core/events/interest_event.h +++ b/third_party/blink/renderer/core/events/interest_event.h
@@ -23,16 +23,12 @@ return MakeGarbageCollected<InterestEvent>(type, initializer); } - static InterestEvent* Create(const AtomicString& type, - const String& action, - Element* invoker) { - return MakeGarbageCollected<InterestEvent>(type, action, invoker); + static InterestEvent* Create(const AtomicString& type, Element* source) { + return MakeGarbageCollected<InterestEvent>(type, source); } InterestEvent(const AtomicString& type, const InterestEventInit* initializer); - InterestEvent(const AtomicString& type, - const String& action, - Element* invoker); + InterestEvent(const AtomicString& type, Element* source); const AtomicString& InterfaceName() const override { return event_interface_names::kInterestEvent; @@ -40,14 +36,11 @@ void Trace(Visitor*) const override; - const String& action() const { return action_; } - - Element* invoker() const; - void SetInvoker(Element* invoker) { invoker_ = invoker; } + Element* source() const; + void SetSource(Element* source) { source_ = source; } private: - Member<Element> invoker_; - String action_; + Member<Element> source_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/events/interest_event.idl b/third_party/blink/renderer/core/events/interest_event.idl index 4b71a42..2717627 100644 --- a/third_party/blink/renderer/core/events/interest_event.idl +++ b/third_party/blink/renderer/core/events/interest_event.idl
@@ -7,11 +7,9 @@ Exposed=Window ] interface InterestEvent : Event { constructor(DOMString type, optional InterestEventInit eventInitDict = {}); - readonly attribute Element? invoker; - readonly attribute DOMString action; + readonly attribute Element? source; }; dictionary InterestEventInit : EventInit { - Element? invoker = null; - DOMString action = ""; + Element? source = null; };
diff --git a/third_party/blink/renderer/core/frame/deprecation/PRESUBMIT.py b/third_party/blink/renderer/core/frame/deprecation/PRESUBMIT.py index 60a1350..c7d43f4 100644 --- a/third_party/blink/renderer/core/frame/deprecation/PRESUBMIT.py +++ b/third_party/blink/renderer/core/frame/deprecation/PRESUBMIT.py
@@ -17,8 +17,6 @@ # add more formal support. EXEMPTED_FROM_RENDERER_GENERATION = { "PrivacySandboxExtensionsAPI": True, - "ThirdPartyCookieAccessWarning": True, - "ThirdPartyCookieAccessError": True, } # pyright: reportMissingImports=false
diff --git a/third_party/blink/renderer/core/frame/deprecation/deprecation.json5 b/third_party/blink/renderer/core/frame/deprecation/deprecation.json5 index 6e9ba4c..3b59d1a 100644 --- a/third_party/blink/renderer/core/frame/deprecation/deprecation.json5 +++ b/third_party/blink/renderer/core/frame/deprecation/deprecation.json5
@@ -557,24 +557,6 @@ milestone: 71, }, { - name: "ThirdPartyCookieAccessError", - message: "Cookies marked with `SameSite=None; Secure` and not `Partitioned` are blocked in cross-site contexts.", - translation_note: "This error occurs when the website attempts to access third-party cookies and the browser blocks them.", - web_features: [ - // This deprecation is used for Legacy Technology Report generation only. - ], - chrome_status_feature: 5133113939722240, - }, - { - name: "ThirdPartyCookieAccessWarning", - message: "In a future version of the browser, cookies marked with `SameSite=None; Secure` and not `Partitioned` will be blocked in cross-site context.", - translation_note: "This warning occurs when the website attempts to access third-party cookies but the browser does not block them yet.", - web_features: [ - // This deprecation is used for Legacy Technology Report generation only. - ], - chrome_status_feature: 5133113939722240, - }, - { name: "UnloadHandler", message: "Unload event listeners are deprecated and will be removed.", translation_note: "A deprecation warning shown in the DevTools Issues tab. It's shown when a listener for the `unload` event is added.",
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_image_source.h b/third_party/blink/renderer/core/html/canvas/canvas_image_source.h index d40a6cd697..bab9631 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_image_source.h +++ b/third_party/blink/renderer/core/html/canvas/canvas_image_source.h
@@ -29,7 +29,6 @@ #include "base/memory/scoped_refptr.h" #include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h" #include "third_party/blink/renderer/platform/graphics/graphics_types.h" #include "third_party/blink/renderer/platform/graphics/image_orientation.h" #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
diff --git a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc index 22ee4d2..a755f48 100644 --- a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
@@ -417,17 +417,6 @@ setAttribute(html_names::kPopovertargetactionAttr, value); } -AtomicString HTMLFormControlElement::interestAction() const { - CHECK(RuntimeEnabledFeatures::HTMLInterestTargetAttributeEnabled()); - const AtomicString& attribute_value = - FastGetAttribute(html_names::kInterestactionAttr); - if (attribute_value && !attribute_value.IsNull() && - !attribute_value.empty()) { - return attribute_value; - } - return g_empty_atom; -} - void HTMLFormControlElement::DefaultEventHandler(Event& event) { // Buttons that aren't form participants might be Invoker buttons or Popover // buttons.
diff --git a/third_party/blink/renderer/core/html/forms/html_form_control_element.h b/third_party/blink/renderer/core/html/forms/html_form_control_element.h index 2352765..e26d943f 100644 --- a/third_party/blink/renderer/core/html/forms/html_form_control_element.h +++ b/third_party/blink/renderer/core/html/forms/html_form_control_element.h
@@ -117,8 +117,6 @@ Element* interestTargetElement() override; - AtomicString interestAction() const override; - void DefaultEventHandler(Event&) override; void SetHovered(bool hovered) override;
diff --git a/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc b/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc index 5e01b04..5e4beeac 100644 --- a/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_opt_group_element.cc
@@ -50,6 +50,10 @@ node.HasTagName(html_names::kHrTag); } +HTMLLegendElement* FirstChildLegend(const HTMLOptGroupElement& optgroup) { + return Traversal<HTMLLegendElement>::FirstChild(optgroup); +} + } // namespace HTMLOptGroupElement::HTMLOptGroupElement(Document& document) @@ -102,15 +106,24 @@ DCHECK_NE(change.type, ChildrenChangeType::kFinishedBuildingDocumentFragmentTree); if (change.type == ChildrenChangeType::kElementInserted) { - if (auto* option = DynamicTo<HTMLOptionElement>(change.sibling_changed)) + if (auto* option = DynamicTo<HTMLOptionElement>(change.sibling_changed)) { select->OptionInserted(*option, option->Selected()); + } else if (IsA<HTMLLegendElement>(change.sibling_changed)) { + UpdateGroupLabel(); + } } else if (change.type == ChildrenChangeType::kElementRemoved) { - if (auto* option = DynamicTo<HTMLOptionElement>(change.sibling_changed)) + if (auto* option = DynamicTo<HTMLOptionElement>(change.sibling_changed)) { select->OptionRemoved(*option); + } else if (IsA<HTMLLegendElement>(change.sibling_changed)) { + UpdateGroupLabel(); + } } else if (change.type == ChildrenChangeType::kAllChildrenRemoved) { for (Node* node : change.removed_nodes) { - if (auto* option = DynamicTo<HTMLOptionElement>(node)) + if (auto* option = DynamicTo<HTMLOptionElement>(node)) { select->OptionRemoved(*option); + } else if (IsA<HTMLLegendElement>(change.sibling_changed)) { + UpdateGroupLabel(); + } } } } @@ -150,10 +163,8 @@ String label_attribute_text = LabelAttributeText(); if (RuntimeEnabledFeatures::CustomizableSelectEnabled() && label_attribute_text.ContainsOnlyWhitespaceOrEmpty()) { - for (auto& node : NodeTraversal::DescendantsOf(*this)) { - if (auto* legend = DynamicTo<HTMLLegendElement>(node)) { - return legend->textContent(); - } + if (auto* legend = FirstChildLegend(*this)) { + return legend->textContent(); } } return label_attribute_text; @@ -233,7 +244,7 @@ HTMLDivElement& label = OptGroupLabelElement(); label.setTextContent(label_text); label.setAttribute(html_names::kAriaLabelAttr, AtomicString(label_text)); - if (label_text.ContainsOnlyWhitespaceOrEmpty()) { + if (label_text.ContainsOnlyWhitespaceOrEmpty() || FirstChildLegend(*this)) { if (customizable_select_rendering_) { // If the author uses <legend> to label the <optgroup> instead of the // label attribute, then we don't want extra space being taken up for the
diff --git a/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc b/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc index 27043496..02ca1a7 100644 --- a/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc +++ b/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
@@ -385,6 +385,7 @@ const HeapVector<Member<HTMLElement>>& items = owner_element.GetListItems(); for (; context.list_index_ < items.size(); ++context.list_index_) { Element& child = *items[context.list_index_]; + // TODO this shouldn't just look at parentNode right?? if (!IsA<HTMLOptGroupElement>(child.parentNode())) context.FinishGroupIfNecessary(); if (auto* option = DynamicTo<HTMLOptionElement>(child))
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc index 2a34e87..e1440edf 100644 --- a/third_party/blink/renderer/core/html/html_anchor_element.cc +++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -629,17 +629,6 @@ html_names::kInteresttargetAttr); } -AtomicString HTMLAnchorElementBase::interestAction() const { - CHECK(RuntimeEnabledFeatures::HTMLInterestTargetAttributeEnabled()); - const AtomicString& attribute_value = - FastGetAttribute(html_names::kInterestactionAttr); - if (attribute_value && !attribute_value.IsNull() && - !attribute_value.empty()) { - return attribute_value; - } - return g_empty_atom; -} - void HTMLAnchorElementBase::HandleClick(MouseEvent& event) { event.SetDefaultHandled();
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.h b/third_party/blink/renderer/core/html/html_anchor_element.h index ae3a23b..f9dcb765 100644 --- a/third_party/blink/renderer/core/html/html_anchor_element.h +++ b/third_party/blink/renderer/core/html/html_anchor_element.h
@@ -114,8 +114,6 @@ Element* interestTargetElement() override; - AtomicString interestAction() const override; - void Trace(Visitor*) const override; protected:
diff --git a/third_party/blink/renderer/core/html/html_area_element.cc b/third_party/blink/renderer/core/html/html_area_element.cc index 699ddc0..0602e0e4 100644 --- a/third_party/blink/renderer/core/html/html_area_element.cc +++ b/third_party/blink/renderer/core/html/html_area_element.cc
@@ -239,17 +239,6 @@ html_names::kInteresttargetAttr); } -AtomicString HTMLAreaElement::interestAction() const { - CHECK(RuntimeEnabledFeatures::HTMLInterestTargetAttributeEnabled()); - const AtomicString& attribute_value = - FastGetAttribute(html_names::kInterestactionAttr); - if (attribute_value && !attribute_value.IsNull() && - !attribute_value.empty()) { - return attribute_value; - } - return g_empty_atom; -} - void HTMLAreaElement::UpdateSelectionOnFocus( SelectionBehaviorOnFocus selection_behavior, const FocusOptions* options) {
diff --git a/third_party/blink/renderer/core/html/html_area_element.h b/third_party/blink/renderer/core/html/html_area_element.h index c99edcb8..7622ae2 100644 --- a/third_party/blink/renderer/core/html/html_area_element.h +++ b/third_party/blink/renderer/core/html/html_area_element.h
@@ -72,7 +72,6 @@ void SetFocused(bool, mojom::blink::FocusType) override; Element* interestTargetElement() override; - AtomicString interestAction() const override; enum Shape { kDefault, kPoly, kRect, kCircle }; void InvalidateCachedPath();
diff --git a/third_party/blink/renderer/core/html/html_attribute_names.json5 b/third_party/blink/renderer/core/html/html_attribute_names.json5 index 868d155..ccb30fd 100644 --- a/third_party/blink/renderer/core/html/html_attribute_names.json5 +++ b/third_party/blink/renderer/core/html/html_attribute_names.json5
@@ -118,7 +118,6 @@ "inert", "inputmode", "integrity", - "interestaction", "interesttarget", "is", "ismap",
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/third_party/blink/renderer/core/html/html_frame_owner_element.cc index 344cb61..5a708bb 100644 --- a/third_party/blink/renderer/core/html/html_frame_owner_element.cc +++ b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
@@ -201,11 +201,7 @@ // perform some bookkeeping that ordinarily would only be done deeper in the // frame setup logic that gets triggered in the *NON* state-preserving atomic // move flow. - if (GetDocument().StatePreservingAtomicMoveInProgress()) { - // State-preserving atomic moves can only be in-progress when all elements - // are connected, and when `HTMLFrameOwnerElement` is connected, it must - // have a non-null `ContentFrame()`. - CHECK(ContentFrame()); + if (GetDocument().StatePreservingAtomicMoveInProgress() && ContentFrame()) { // During a state-preserving atomic move, we must specifically inform all of // `this`'s ancestor nodes of the new connected frame they are adopting. // @@ -231,7 +227,8 @@ // Not doing (1) is a good thing, since we're trying to preserve the frame, // but we still have to do (2) manually to maintain bookkeeping consistency // among the ancestor nodes. - if (GetDocument().StatePreservingAtomicMoveInProgress()) { + if (GetDocument().StatePreservingAtomicMoveInProgress() && + insertion_point.isConnected()) { // `this` is no longer connected, so we have to decrement our subframe count // separately from our old ancestors's subframe count (i.e., // `insertion_point`).
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc index 508002b..fab0b60 100644 --- a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc +++ b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc
@@ -1716,7 +1716,6 @@ number_of_bytes_parsed = parser.NumberOfBytesParsed(); // The time needed to parse is typically < 1ms (even at the 99%). if (success) { - root_node.ParserFinishedBuildingDocumentFragment(); UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( "Blink.HTMLFastPathParser.SuccessfulParseTime2", parse_timer.Elapsed(), base::Microseconds(1), base::Milliseconds(10), 100);
diff --git a/third_party/blink/renderer/core/layout/block_node.cc b/third_party/blink/renderer/core/layout/block_node.cc index c1293752..2f8b8bc 100644 --- a/third_party/blink/renderer/core/layout/block_node.cc +++ b/third_party/blink/renderer/core/layout/block_node.cc
@@ -169,7 +169,6 @@ template <typename Callback> NOINLINE void DetermineAlgorithmAndRun(const LayoutAlgorithmParams& params, const Callback& callback) { - const ComputedStyle& style = params.node.Style(); const LayoutBox& box = *params.node.GetLayoutBox(); if (box.IsFlexibleBox()) { CreateAlgorithmAndRun<FlexLayoutAlgorithm>(params, callback); @@ -198,7 +197,7 @@ // we would have done block fragmentation with the legacy engine. // Otherwise writing data back into the legacy tree will fail. Look for // the flow thread. - else if (GetFlowThread(box) && style.SpecifiesColumns()) { + else if (GetFlowThread(box) && params.node.Style().SpecifiesColumns()) { CreateAlgorithmAndRun<ColumnLayoutAlgorithm>(params, callback); } else if (!box.Parent() && params.node.IsPaginatedRoot()) [[unlikely]] { CreateAlgorithmAndRun<PaginatedRootLayoutAlgorithm>(params, callback); @@ -1359,15 +1358,6 @@ PlaceChildrenInLayoutBox(child_fragment, previous_column_break_token, /* needs_invalidation_check */ true); - // If the multicol container has inline children, there may still be floats - // there, but they aren't stored as child fragments of |column| in that case - // (but rather inside fragment items). Make sure that they get positioned, - // too. - if (const FragmentItems* items = child_fragment.Items()) { - CopyFragmentItemsToLayoutBox(child_fragment, *items, - previous_column_break_token); - } - previous_column_break_token = child_fragment.GetBreakToken(); }
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni index 1033f64..b35e22d 100644 --- a/third_party/blink/renderer/core/layout/build.gni +++ b/third_party/blink/renderer/core/layout/build.gni
@@ -199,6 +199,8 @@ "grid/grid_subtree.h", "grid/grid_track_collection.cc", "grid/grid_track_collection.h", + "grid/grid_track_sizing_algorithm.cc", + "grid/grid_track_sizing_algorithm.h", "grid/layout_grid.cc", "grid/layout_grid.h", "grid/subgrid_min_max_sizes_cache.h",
diff --git a/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc index 84bdbb0..8b0d3e5b 100644 --- a/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/core/layout/fragmentation_utils.h" #include "third_party/blink/renderer/core/layout/grid/grid_break_token_data.h" #include "third_party/blink/renderer/core/layout/grid/grid_item.h" +#include "third_party/blink/renderer/core/layout/grid/grid_track_sizing_algorithm.h" #include "third_party/blink/renderer/core/layout/length_utils.h" #include "third_party/blink/renderer/core/layout/logical_box_fragment.h" #include "third_party/blink/renderer/core/layout/relative_utils.h" @@ -85,111 +86,6 @@ namespace { -void CacheGridItemsProperties(const GridLayoutTrackCollection& track_collection, - GridItems* grid_items) { - DCHECK(grid_items); - - GridItemDataPtrVector grid_items_spanning_multiple_ranges; - const auto track_direction = track_collection.Direction(); - - for (auto& grid_item : grid_items->IncludeSubgriddedItems()) { - if (!grid_item.MustCachePlacementIndices(track_direction)) { - continue; - } - - const auto& range_indices = grid_item.RangeIndices(track_direction); - auto& track_span_properties = (track_direction == kForColumns) - ? grid_item.column_span_properties - : grid_item.row_span_properties; - - grid_item.ComputeSetIndices(track_collection); - track_span_properties.Reset(); - - // If a grid item spans only one range, then we can just cache the track - // span properties directly. On the contrary, if a grid item spans multiple - // tracks, it is added to |grid_items_spanning_multiple_ranges| as we need - // to do more work to cache its track span properties. - // - // TODO(layout-dev): Investigate applying this concept to spans > 1. - if (range_indices.begin == range_indices.end) { - track_span_properties = - track_collection.RangeProperties(range_indices.begin); - } else { - grid_items_spanning_multiple_ranges.emplace_back(&grid_item); - } - } - - if (grid_items_spanning_multiple_ranges.empty()) - return; - - auto CompareGridItemsByStartLine = - [track_direction](GridItemData* lhs, GridItemData* rhs) -> bool { - return lhs->StartLine(track_direction) < rhs->StartLine(track_direction); - }; - std::sort(grid_items_spanning_multiple_ranges.begin(), - grid_items_spanning_multiple_ranges.end(), - CompareGridItemsByStartLine); - - auto CacheGridItemsSpanningMultipleRangesProperty = - [&](TrackSpanProperties::PropertyId property) { - // At this point we have the remaining grid items sorted by start line - // in the respective direction; this is important since we'll process - // both, the ranges in the track collection and the grid items, - // incrementally. - wtf_size_t current_range_index = 0; - const wtf_size_t range_count = track_collection.RangeCount(); - - for (auto* grid_item : grid_items_spanning_multiple_ranges) { - // We want to find the first range in the collection that: - // - Spans tracks located AFTER the start line of the current grid - // item; this can be done by checking that the last track number of - // the current range is NOT less than the current grid item's start - // line. Furthermore, since grid items are sorted by start line, if - // at any point a range is located BEFORE the current grid item's - // start line, the same range will also be located BEFORE any - // subsequent item's start line. - // - Contains a track that fulfills the specified property. - while (current_range_index < range_count && - (track_collection.RangeEndLine(current_range_index) <= - grid_item->StartLine(track_direction) || - !track_collection.RangeProperties(current_range_index) - .HasProperty(property))) { - ++current_range_index; - } - - // Since we discarded every range in the track collection, any - // following grid item cannot fulfill the property. - if (current_range_index == range_count) - break; - - // Notice that, from the way we build the ranges of a track collection - // (see |GridRangeBuilder::EnsureTrackCoverage|), any given range - // must either be completely contained or excluded from a grid item's - // span. Thus, if the current range's last track is also located - // BEFORE the item's end line, then this range, including a track that - // fulfills the specified property, is completely contained within - // this item's boundaries. Otherwise, this and every subsequent range - // are excluded from the grid item's span, meaning that such item - // cannot satisfy the property we are looking for. - if (track_collection.RangeEndLine(current_range_index) <= - grid_item->EndLine(track_direction)) { - grid_item->SetTrackSpanProperty(property, track_direction); - } - } - }; - - CacheGridItemsSpanningMultipleRangesProperty( - TrackSpanProperties::kHasFlexibleTrack); - CacheGridItemsSpanningMultipleRangesProperty( - TrackSpanProperties::kHasIntrinsicTrack); - CacheGridItemsSpanningMultipleRangesProperty( - TrackSpanProperties::kHasAutoMinimumTrack); - CacheGridItemsSpanningMultipleRangesProperty( - TrackSpanProperties::kHasFixedMinimumTrack); - CacheGridItemsSpanningMultipleRangesProperty( - TrackSpanProperties::kHasFixedMaximumTrack); -} - bool HasBlockSizeDependentGridItem(const GridItems& grid_items) { for (const auto& grid_item : grid_items.IncludeSubgriddedItems()) { if (grid_item.is_sizing_dependent_on_block_size) @@ -733,132 +629,6 @@ : track_collection.MinorBaseline(end_set_index - 1); } -namespace { - -struct FirstSetGeometry { - LayoutUnit start_offset; - LayoutUnit gutter_size; -}; - -FirstSetGeometry ComputeFirstSetGeometry( - const GridSizingTrackCollection& track_collection, - const ComputedStyle& container_style, - LayoutUnit available_size, - LayoutUnit start_border_scrollbar_padding) { - const bool is_for_columns = track_collection.Direction() == kForColumns; - - const auto& content_alignment = is_for_columns - ? container_style.JustifyContent() - : container_style.AlignContent(); - const auto overflow = content_alignment.Overflow(); - - // Determining the free-space is typically unnecessary, i.e. if there is - // default alignment. Only compute this on-demand. - auto FreeSpace = [&]() -> LayoutUnit { - LayoutUnit free_space = available_size - track_collection.TotalTrackSize(); - - // If overflow is 'safe', make sure we don't overflow the 'start' edge - // (potentially causing some data loss as the overflow is unreachable). - return (overflow == OverflowAlignment::kSafe) - ? free_space.ClampNegativeToZero() - : free_space; - }; - - // The default alignment, perform adjustments on top of this. - FirstSetGeometry geometry{start_border_scrollbar_padding, - track_collection.GutterSize()}; - - // If we have an indefinite |available_size| we can't perform any alignment, - // just return the default alignment. - if (available_size == kIndefiniteSize) - return geometry; - - // TODO(ikilpatrick): 'space-between', 'space-around', and 'space-evenly' all - // divide by the free-space, and may have a non-zero modulo. Investigate if - // this should be distributed between the tracks. - switch (content_alignment.Distribution()) { - case ContentDistributionType::kSpaceBetween: { - // Default behavior for 'space-between' is to start align content. - const wtf_size_t track_count = track_collection.NonCollapsedTrackCount(); - const LayoutUnit free_space = FreeSpace(); - if (track_count < 2 || free_space < LayoutUnit()) - return geometry; - - geometry.gutter_size += free_space / (track_count - 1); - return geometry; - } - case ContentDistributionType::kSpaceAround: { - // Default behavior for 'space-around' is to safe center content. - const wtf_size_t track_count = track_collection.NonCollapsedTrackCount(); - const LayoutUnit free_space = FreeSpace(); - if (free_space < LayoutUnit()) { - return geometry; - } - if (track_count < 1) { - geometry.start_offset += free_space / 2; - return geometry; - } - - LayoutUnit track_space = free_space / track_count; - geometry.start_offset += track_space / 2; - geometry.gutter_size += track_space; - return geometry; - } - case ContentDistributionType::kSpaceEvenly: { - // Default behavior for 'space-evenly' is to safe center content. - const wtf_size_t track_count = track_collection.NonCollapsedTrackCount(); - const LayoutUnit free_space = FreeSpace(); - if (free_space < LayoutUnit()) { - return geometry; - } - - LayoutUnit track_space = free_space / (track_count + 1); - geometry.start_offset += track_space; - geometry.gutter_size += track_space; - return geometry; - } - case ContentDistributionType::kStretch: - case ContentDistributionType::kDefault: - break; - } - - switch (content_alignment.GetPosition()) { - case ContentPosition::kLeft: { - DCHECK(is_for_columns); - if (IsLtr(container_style.Direction())) - return geometry; - - geometry.start_offset += FreeSpace(); - return geometry; - } - case ContentPosition::kRight: { - DCHECK(is_for_columns); - if (IsRtl(container_style.Direction())) - return geometry; - - geometry.start_offset += FreeSpace(); - return geometry; - } - case ContentPosition::kCenter: { - geometry.start_offset += FreeSpace() / 2; - return geometry; - } - case ContentPosition::kEnd: - case ContentPosition::kFlexEnd: { - geometry.start_offset += FreeSpace(); - return geometry; - } - case ContentPosition::kStart: - case ContentPosition::kFlexStart: - case ContentPosition::kNormal: - case ContentPosition::kBaseline: - case ContentPosition::kLastBaseline: - return geometry; - } -} - -} // namespace - void GridLayoutAlgorithm::ComputeGridGeometry( const GridSizingTree& grid_sizing_tree, LayoutUnit* intrinsic_block_size) { @@ -959,9 +729,10 @@ // Re-compute the row geometry now that we resolved the available block // size. "align-content: space-evenly", etc, require the resolved size. - auto first_set_geometry = ComputeFirstSetGeometry( - track_collection, container_style, grid_available_size_.block_size, - border_scrollbar_padding.block_start); + auto first_set_geometry = + GridTrackSizingAlgorithm::ComputeFirstSetGeometry( + track_collection, container_style, grid_available_size_, + border_scrollbar_padding); track_collection.FinalizeSetsGeometry(first_set_geometry.start_offset, first_set_geometry.gutter_size); @@ -1743,27 +1514,24 @@ } } else { auto& track_collection = layout_data.SizingCollection(track_direction); - CacheGridItemsProperties(track_collection, &grid_items); - - const bool is_for_columns = track_direction == kForColumns; - const auto start_border_scrollbar_padding = - is_for_columns ? BorderScrollbarPadding().inline_start - : BorderScrollbarPadding().block_start; + GridTrackSizingAlgorithm::CacheGridItemsProperties(track_collection, + &grid_items); // If all tracks have a definite size upfront, we can use the current set // sizes as the used track sizes (applying alignment, if present). if (!track_collection.HasNonDefiniteTrack()) { - auto first_set_geometry = ComputeFirstSetGeometry( - track_collection, Style(), - is_for_columns ? grid_available_size_.inline_size - : grid_available_size_.block_size, - start_border_scrollbar_padding); + auto first_set_geometry = + GridTrackSizingAlgorithm::ComputeFirstSetGeometry( + track_collection, Style(), grid_available_size_, + BorderScrollbarPadding()); track_collection.FinalizeSetsGeometry(first_set_geometry.start_offset, first_set_geometry.gutter_size); } else { track_collection.CacheInitializedSetsGeometry( - start_border_scrollbar_padding); + (track_direction == kForColumns) + ? BorderScrollbarPadding().inline_start + : BorderScrollbarPadding().block_start); } if (track_collection.HasBaselines()) { @@ -1935,12 +1703,10 @@ sizing_subtree.GetGridItems(), track_collection); } - auto first_set_geometry = ComputeFirstSetGeometry( - track_collection, Style(), - is_for_columns ? grid_available_size_.inline_size - : grid_available_size_.block_size, - is_for_columns ? BorderScrollbarPadding().inline_start - : BorderScrollbarPadding().block_start); + auto first_set_geometry = + GridTrackSizingAlgorithm::ComputeFirstSetGeometry( + track_collection, Style(), grid_available_size_, + BorderScrollbarPadding()); track_collection.FinalizeSetsGeometry(first_set_geometry.start_offset, first_set_geometry.gutter_size);
diff --git a/third_party/blink/renderer/core/layout/grid/grid_track_sizing_algorithm.cc b/third_party/blink/renderer/core/layout/grid/grid_track_sizing_algorithm.cc new file mode 100644 index 0000000..f702994 --- /dev/null +++ b/third_party/blink/renderer/core/layout/grid/grid_track_sizing_algorithm.cc
@@ -0,0 +1,255 @@ +// 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/grid/grid_track_sizing_algorithm.h" + +#include "third_party/blink/renderer/core/layout/geometry/box_strut.h" +#include "third_party/blink/renderer/core/layout/grid/grid_item.h" +#include "third_party/blink/renderer/core/layout/grid/grid_track_collection.h" + +namespace blink { + +namespace { + +using GridItemDataPtrVector = Vector<GridItemData*, 16>; + +} // namespace + +// static +void GridTrackSizingAlgorithm::CacheGridItemsProperties( + const GridSizingTrackCollection& track_collection, + GridItems* grid_items) { + DCHECK(grid_items); + + GridItemDataPtrVector grid_items_spanning_multiple_ranges; + const auto track_direction = track_collection.Direction(); + + for (auto& grid_item : grid_items->IncludeSubgriddedItems()) { + if (!grid_item.MustCachePlacementIndices(track_direction)) { + continue; + } + + const auto& range_indices = grid_item.RangeIndices(track_direction); + auto& track_span_properties = (track_direction == kForColumns) + ? grid_item.column_span_properties + : grid_item.row_span_properties; + + grid_item.ComputeSetIndices(track_collection); + track_span_properties.Reset(); + + // If a grid item spans only one range, then we can just cache the track + // span properties directly. On the contrary, if a grid item spans multiple + // tracks, it is added to `grid_items_spanning_multiple_ranges` as we need + // to do more work to cache its track span properties. + // + // TODO(layout-dev): Investigate applying this concept to spans > 1. + if (range_indices.begin == range_indices.end) { + track_span_properties = + track_collection.RangeProperties(range_indices.begin); + } else { + grid_items_spanning_multiple_ranges.emplace_back(&grid_item); + } + } + + if (grid_items_spanning_multiple_ranges.empty()) { + return; + } + + auto CompareGridItemsByStartLine = + [track_direction](GridItemData* lhs, GridItemData* rhs) -> bool { + return lhs->StartLine(track_direction) < rhs->StartLine(track_direction); + }; + std::sort(grid_items_spanning_multiple_ranges.begin(), + grid_items_spanning_multiple_ranges.end(), + CompareGridItemsByStartLine); + + auto CacheGridItemsSpanningMultipleRangesProperty = + [&](TrackSpanProperties::PropertyId property) { + // At this point we have the remaining grid items sorted by start line + // in the respective direction; this is important since we'll process + // both, the ranges in the track collection and the grid items, + // incrementally. + wtf_size_t current_range_index = 0; + const wtf_size_t range_count = track_collection.RangeCount(); + + for (auto* grid_item : grid_items_spanning_multiple_ranges) { + // We want to find the first range in the collection that: + // - Spans tracks located AFTER the start line of the current grid + // item; this can be done by checking that the last track number of + // the current range is NOT less than the current grid item's start + // line. Furthermore, since grid items are sorted by start line, if + // at any point a range is located BEFORE the current grid item's + // start line, the same range will also be located BEFORE any + // subsequent item's start line. + // - Contains a track that fulfills the specified property. + while (current_range_index < range_count && + (track_collection.RangeEndLine(current_range_index) <= + grid_item->StartLine(track_direction) || + !track_collection.RangeProperties(current_range_index) + .HasProperty(property))) { + ++current_range_index; + } + + // Since we discarded every range in the track collection, any + // following grid item cannot fulfill the property. + if (current_range_index == range_count) { + break; + } + + // Notice that, from the way we build the ranges of a track collection + // (see `GridRangeBuilder::EnsureTrackCoverage`), any given range + // must either be completely contained or excluded from a grid item's + // span. Thus, if the current range's last track is also located + // BEFORE the item's end line, then this range, including a track that + // fulfills the specified property, is completely contained within + // this item's boundaries. Otherwise, this and every subsequent range + // are excluded from the grid item's span, meaning that such item + // cannot satisfy the property we are looking for. + if (track_collection.RangeEndLine(current_range_index) <= + grid_item->EndLine(track_direction)) { + grid_item->SetTrackSpanProperty(property, track_direction); + } + } + }; + + CacheGridItemsSpanningMultipleRangesProperty( + TrackSpanProperties::kHasFlexibleTrack); + CacheGridItemsSpanningMultipleRangesProperty( + TrackSpanProperties::kHasIntrinsicTrack); + CacheGridItemsSpanningMultipleRangesProperty( + TrackSpanProperties::kHasAutoMinimumTrack); + CacheGridItemsSpanningMultipleRangesProperty( + TrackSpanProperties::kHasFixedMinimumTrack); + CacheGridItemsSpanningMultipleRangesProperty( + TrackSpanProperties::kHasFixedMaximumTrack); +} + +// static +GridTrackSizingAlgorithm::FirstSetGeometry +GridTrackSizingAlgorithm::ComputeFirstSetGeometry( + const GridSizingTrackCollection& track_collection, + const ComputedStyle& container_style, + const LogicalSize& container_available_size, + const BoxStrut& container_border_scrollbar_padding) { + const bool is_for_columns = track_collection.Direction() == kForColumns; + + const auto& available_size = is_for_columns + ? container_available_size.inline_size + : container_available_size.block_size; + + // The default alignment, perform adjustments on top of this. + FirstSetGeometry geometry{ + track_collection.GutterSize(), + is_for_columns ? container_border_scrollbar_padding.inline_start + : container_border_scrollbar_padding.block_start}; + + // If we have an indefinite `available_size` we can't perform any alignment. + if (available_size == kIndefiniteSize) { + return geometry; + } + + const auto& content_alignment = is_for_columns + ? container_style.JustifyContent() + : container_style.AlignContent(); + + // Determining the free space is typically unnecessary, i.e., if there is + // default alignment. Only compute this on-demand. + auto FreeSpace = [&]() -> LayoutUnit { + const auto free_space = available_size - track_collection.TotalTrackSize(); + + // If overflow is 'safe', make sure we don't overflow the 'start' edge + // (potentially causing some data loss as the overflow is unreachable). + return (content_alignment.Overflow() == OverflowAlignment::kSafe) + ? free_space.ClampNegativeToZero() + : free_space; + }; + + // TODO(ikilpatrick): 'space-between', 'space-around', and 'space-evenly' all + // divide by the free-space, and may have a non-zero modulo. Investigate if + // this should be distributed between the tracks. + switch (content_alignment.Distribution()) { + case ContentDistributionType::kSpaceBetween: { + // Default behavior for 'space-between' is to start align content. + const wtf_size_t track_count = track_collection.NonCollapsedTrackCount(); + const LayoutUnit free_space = FreeSpace(); + if (track_count < 2 || free_space < LayoutUnit()) { + return geometry; + } + + geometry.gutter_size += free_space / (track_count - 1); + return geometry; + } + case ContentDistributionType::kSpaceAround: { + // Default behavior for 'space-around' is to safe center content. + const wtf_size_t track_count = track_collection.NonCollapsedTrackCount(); + const LayoutUnit free_space = FreeSpace(); + if (free_space < LayoutUnit()) { + return geometry; + } + if (track_count < 1) { + geometry.start_offset += free_space / 2; + return geometry; + } + + LayoutUnit track_space = free_space / track_count; + geometry.start_offset += track_space / 2; + geometry.gutter_size += track_space; + return geometry; + } + case ContentDistributionType::kSpaceEvenly: { + // Default behavior for 'space-evenly' is to safe center content. + const wtf_size_t track_count = track_collection.NonCollapsedTrackCount(); + const LayoutUnit free_space = FreeSpace(); + if (free_space < LayoutUnit()) { + return geometry; + } + + LayoutUnit track_space = free_space / (track_count + 1); + geometry.start_offset += track_space; + geometry.gutter_size += track_space; + return geometry; + } + case ContentDistributionType::kStretch: + case ContentDistributionType::kDefault: + break; + } + + switch (content_alignment.GetPosition()) { + case ContentPosition::kLeft: { + DCHECK(is_for_columns); + if (IsLtr(container_style.Direction())) { + return geometry; + } + + geometry.start_offset += FreeSpace(); + return geometry; + } + case ContentPosition::kRight: { + DCHECK(is_for_columns); + if (IsRtl(container_style.Direction())) { + return geometry; + } + + geometry.start_offset += FreeSpace(); + return geometry; + } + case ContentPosition::kCenter: { + geometry.start_offset += FreeSpace() / 2; + return geometry; + } + case ContentPosition::kEnd: + case ContentPosition::kFlexEnd: { + geometry.start_offset += FreeSpace(); + return geometry; + } + case ContentPosition::kStart: + case ContentPosition::kFlexStart: + case ContentPosition::kNormal: + case ContentPosition::kBaseline: + case ContentPosition::kLastBaseline: + return geometry; + } +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/grid/grid_track_sizing_algorithm.h b/third_party/blink/renderer/core/layout/grid/grid_track_sizing_algorithm.h new file mode 100644 index 0000000..eb376e8a --- /dev/null +++ b/third_party/blink/renderer/core/layout/grid/grid_track_sizing_algorithm.h
@@ -0,0 +1,43 @@ +// 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_LAYOUT_GRID_GRID_TRACK_SIZING_ALGORITHM_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_GRID_TRACK_SIZING_ALGORITHM_H_ + +#include "third_party/blink/renderer/core/layout/geometry/logical_size.h" + +namespace blink { + +class ComputedStyle; +class GridItems; +class GridSizingTrackCollection; +struct BoxStrut; + +class GridTrackSizingAlgorithm { + STACK_ALLOCATED(); + + public: + struct FirstSetGeometry { + LayoutUnit gutter_size; + LayoutUnit start_offset; + }; + + // Caches the track span properties necessary for the track sizing algorithm + // to work based on the grid items' placement within the track collection. + static void CacheGridItemsProperties( + const GridSizingTrackCollection& track_collection, + GridItems* grid_items); + + // For the first track, computes the start offset and gutter size based on the + // alignment properties and available size of the container. + static FirstSetGeometry ComputeFirstSetGeometry( + const GridSizingTrackCollection& track_collection, + const ComputedStyle& container_style, + const LogicalSize& container_available_size, + const BoxStrut& container_border_scrollbar_padding); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_GRID_TRACK_SIZING_ALGORITHM_H_
diff --git a/third_party/blink/renderer/core/svg/svg_a_element.cc b/third_party/blink/renderer/core/svg/svg_a_element.cc index 09f7ae3..9bac8ecb8 100644 --- a/third_party/blink/renderer/core/svg/svg_a_element.cc +++ b/third_party/blink/renderer/core/svg/svg_a_element.cc
@@ -179,17 +179,6 @@ svg_names::kInteresttargetAttr); } -AtomicString SVGAElement::interestAction() const { - CHECK(RuntimeEnabledFeatures::HTMLInterestTargetAttributeEnabled()); - const AtomicString& attribute_value = - FastGetAttribute(svg_names::kInterestactionAttr); - if (attribute_value && !attribute_value.IsNull() && - !attribute_value.empty()) { - return attribute_value; - } - return g_empty_atom; -} - bool SVGAElement::HasActivationBehavior() const { return true; }
diff --git a/third_party/blink/renderer/core/svg/svg_a_element.h b/third_party/blink/renderer/core/svg/svg_a_element.h index 0515d909a..59cb21f 100644 --- a/third_party/blink/renderer/core/svg/svg_a_element.h +++ b/third_party/blink/renderer/core/svg/svg_a_element.h
@@ -38,7 +38,6 @@ explicit SVGAElement(Document&); Element* interestTargetElement() override; - AtomicString interestAction() const override; void Trace(Visitor*) const override;
diff --git a/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.idl b/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.idl index 91954532..ae72b520 100644 --- a/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.idl +++ b/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.idl
@@ -29,18 +29,18 @@ Exposed=Window ] interface SVGComponentTransferFunctionElement : SVGElement { // Component Transfer Types - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY = 1; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_TABLE = 2; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE = 3; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_LINEAR = 4; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_GAMMA = 5; + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0; + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY = 1; + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_TABLE = 2; + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE = 3; + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_LINEAR = 4; + const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_GAMMA = 5; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration type; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumberList tableValues; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber slope; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber intercept; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber amplitude; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber exponent; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber offset; + readonly attribute SVGAnimatedEnumeration type; + readonly attribute SVGAnimatedNumberList tableValues; + readonly attribute SVGAnimatedNumber slope; + readonly attribute SVGAnimatedNumber intercept; + readonly attribute SVGAnimatedNumber amplitude; + readonly attribute SVGAnimatedNumber exponent; + readonly attribute SVGAnimatedNumber offset; };
diff --git a/third_party/blink/renderer/core/svg/svg_fe_blend_element.idl b/third_party/blink/renderer/core/svg/svg_fe_blend_element.idl index ed662a9..b2dc700 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_blend_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_blend_element.idl
@@ -30,27 +30,27 @@ ] interface SVGFEBlendElement : SVGElement { // Blend Mode Types - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_UNKNOWN = 0; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_NORMAL = 1; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_MULTIPLY = 2; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_SCREEN = 3; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_DARKEN = 4; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_LIGHTEN = 5; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_OVERLAY = 6; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_COLOR_DODGE = 7; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_COLOR_BURN = 8; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_HARD_LIGHT = 9; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_SOFT_LIGHT = 10; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_DIFFERENCE = 11; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_EXCLUSION = 12; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_HUE = 13; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_SATURATION = 14; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_COLOR = 15; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FEBLEND_MODE_LUMINOSITY = 16; + const unsigned short SVG_FEBLEND_MODE_UNKNOWN = 0; + const unsigned short SVG_FEBLEND_MODE_NORMAL = 1; + const unsigned short SVG_FEBLEND_MODE_MULTIPLY = 2; + const unsigned short SVG_FEBLEND_MODE_SCREEN = 3; + const unsigned short SVG_FEBLEND_MODE_DARKEN = 4; + const unsigned short SVG_FEBLEND_MODE_LIGHTEN = 5; + const unsigned short SVG_FEBLEND_MODE_OVERLAY = 6; + const unsigned short SVG_FEBLEND_MODE_COLOR_DODGE = 7; + const unsigned short SVG_FEBLEND_MODE_COLOR_BURN = 8; + const unsigned short SVG_FEBLEND_MODE_HARD_LIGHT = 9; + const unsigned short SVG_FEBLEND_MODE_SOFT_LIGHT = 10; + const unsigned short SVG_FEBLEND_MODE_DIFFERENCE = 11; + const unsigned short SVG_FEBLEND_MODE_EXCLUSION = 12; + const unsigned short SVG_FEBLEND_MODE_HUE = 13; + const unsigned short SVG_FEBLEND_MODE_SATURATION = 14; + const unsigned short SVG_FEBLEND_MODE_COLOR = 15; + const unsigned short SVG_FEBLEND_MODE_LUMINOSITY = 16; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in2; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration mode; + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedString in2; + readonly attribute SVGAnimatedEnumeration mode; }; SVGFEBlendElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.idl b/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.idl index 50ea924..ec591a2 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.idl
@@ -29,15 +29,15 @@ Exposed=Window ] interface SVGFEColorMatrixElement : SVGElement { // Color Matrix Types - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOLORMATRIX_TYPE_MATRIX = 1; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOLORMATRIX_TYPE_SATURATE = 2; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOLORMATRIX_TYPE_HUEROTATE = 3; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4; + const unsigned short SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0; + const unsigned short SVG_FECOLORMATRIX_TYPE_MATRIX = 1; + const unsigned short SVG_FECOLORMATRIX_TYPE_SATURATE = 2; + const unsigned short SVG_FECOLORMATRIX_TYPE_HUEROTATE = 3; + const unsigned short SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration type; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumberList values; + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedEnumeration type; + readonly attribute SVGAnimatedNumberList values; }; SVGFEColorMatrixElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.idl b/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.idl index 52a4341..caf7f1c8 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.idl
@@ -28,7 +28,7 @@ [ Exposed=Window ] interface SVGFEComponentTransferElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedString in1; }; SVGFEComponentTransferElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_composite_element.idl b/third_party/blink/renderer/core/svg/svg_fe_composite_element.idl index 525ef250..d2810ea 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_composite_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_composite_element.idl
@@ -29,21 +29,21 @@ Exposed=Window ] interface SVGFECompositeElement : SVGElement { // Composite Operators - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPOSITE_OPERATOR_OVER = 1; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPOSITE_OPERATOR_IN = 2; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPOSITE_OPERATOR_OUT = 3; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPOSITE_OPERATOR_ATOP = 4; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPOSITE_OPERATOR_XOR = 5; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6; + const unsigned short SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0; + const unsigned short SVG_FECOMPOSITE_OPERATOR_OVER = 1; + const unsigned short SVG_FECOMPOSITE_OPERATOR_IN = 2; + const unsigned short SVG_FECOMPOSITE_OPERATOR_OUT = 3; + const unsigned short SVG_FECOMPOSITE_OPERATOR_ATOP = 4; + const unsigned short SVG_FECOMPOSITE_OPERATOR_XOR = 5; + const unsigned short SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in2; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; - [ImplementedAs=svgOperator, MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration operator; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber k1; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber k2; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber k3; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber k4; + readonly attribute SVGAnimatedString in2; + readonly attribute SVGAnimatedString in1; + [ImplementedAs=svgOperator] readonly attribute SVGAnimatedEnumeration operator; + readonly attribute SVGAnimatedNumber k1; + readonly attribute SVGAnimatedNumber k2; + readonly attribute SVGAnimatedNumber k3; + readonly attribute SVGAnimatedNumber k4; }; SVGFECompositeElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.idl b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.idl index 3538b18..c7fc8cf 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.idl
@@ -29,22 +29,22 @@ Exposed=Window ] interface SVGFEConvolveMatrixElement : SVGElement { // Edge Mode Values - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_EDGEMODE_UNKNOWN = 0; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_EDGEMODE_DUPLICATE = 1; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_EDGEMODE_WRAP = 2; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_EDGEMODE_NONE = 3; + const unsigned short SVG_EDGEMODE_UNKNOWN = 0; + const unsigned short SVG_EDGEMODE_DUPLICATE = 1; + const unsigned short SVG_EDGEMODE_WRAP = 2; + const unsigned short SVG_EDGEMODE_NONE = 3; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedInteger orderX; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedInteger orderY; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumberList kernelMatrix; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber divisor; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber bias; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedInteger targetX; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedInteger targetY; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration edgeMode; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber kernelUnitLengthX; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber kernelUnitLengthY; + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedInteger orderX; + readonly attribute SVGAnimatedInteger orderY; + readonly attribute SVGAnimatedNumberList kernelMatrix; + readonly attribute SVGAnimatedNumber divisor; + readonly attribute SVGAnimatedNumber bias; + readonly attribute SVGAnimatedInteger targetX; + readonly attribute SVGAnimatedInteger targetY; + readonly attribute SVGAnimatedEnumeration edgeMode; + readonly attribute SVGAnimatedNumber kernelUnitLengthX; + readonly attribute SVGAnimatedNumber kernelUnitLengthY; [Measure] readonly attribute SVGAnimatedBoolean preserveAlpha; };
diff --git a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.idl b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.idl index 593d161..1036bc3 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.idl
@@ -28,11 +28,11 @@ [ Exposed=Window ] interface SVGFEDiffuseLightingElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber surfaceScale; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber diffuseConstant; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber kernelUnitLengthX; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber kernelUnitLengthY; + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedNumber surfaceScale; + readonly attribute SVGAnimatedNumber diffuseConstant; + readonly attribute SVGAnimatedNumber kernelUnitLengthX; + readonly attribute SVGAnimatedNumber kernelUnitLengthY; }; SVGFEDiffuseLightingElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.idl b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.idl index c535b68e..4ee5f02 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.idl
@@ -29,17 +29,17 @@ Exposed=Window ] interface SVGFEDisplacementMapElement : SVGElement { // Channel Selectors - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_CHANNEL_UNKNOWN = 0; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_CHANNEL_R = 1; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_CHANNEL_G = 2; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_CHANNEL_B = 3; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_CHANNEL_A = 4; + const unsigned short SVG_CHANNEL_UNKNOWN = 0; + const unsigned short SVG_CHANNEL_R = 1; + const unsigned short SVG_CHANNEL_G = 2; + const unsigned short SVG_CHANNEL_B = 3; + const unsigned short SVG_CHANNEL_A = 4; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in2; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber scale; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration xChannelSelector; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration yChannelSelector; + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedString in2; + readonly attribute SVGAnimatedNumber scale; + readonly attribute SVGAnimatedEnumeration xChannelSelector; + readonly attribute SVGAnimatedEnumeration yChannelSelector; }; SVGFEDisplacementMapElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.idl b/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.idl index 0efa530..3f0fed1 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.idl
@@ -28,6 +28,6 @@ [ Exposed=Window ] interface SVGFEDistantLightElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber azimuth; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber elevation; + readonly attribute SVGAnimatedNumber azimuth; + readonly attribute SVGAnimatedNumber elevation; };
diff --git a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.idl b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.idl index 7766e41..6da4c9e 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.idl
@@ -22,13 +22,13 @@ [ Exposed=Window ] interface SVGFEDropShadowElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber dx; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber dy; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber stdDeviationX; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber stdDeviationY; + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedNumber dx; + readonly attribute SVGAnimatedNumber dy; + readonly attribute SVGAnimatedNumber stdDeviationX; + readonly attribute SVGAnimatedNumber stdDeviationY; - [MeasureAs=SVG1DOMFilter] void setStdDeviation(float stdDeviationX, float stdDeviationY); + void setStdDeviation(float stdDeviationX, float stdDeviationY); }; SVGFEDropShadowElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.idl b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.idl index 31392491..ae6298b5 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.idl
@@ -28,11 +28,11 @@ [ Exposed=Window ] interface SVGFEGaussianBlurElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber stdDeviationX; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber stdDeviationY; + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedNumber stdDeviationX; + readonly attribute SVGAnimatedNumber stdDeviationY; - [MeasureAs=SVG1DOMFilter] void setStdDeviation(float stdDeviationX, float stdDeviationY); + void setStdDeviation(float stdDeviationX, float stdDeviationY); }; SVGFEGaussianBlurElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_image_element.idl b/third_party/blink/renderer/core/svg/svg_fe_image_element.idl index 69340c2..5e7dbb6 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_image_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_image_element.idl
@@ -28,7 +28,7 @@ [ Exposed=Window ] interface SVGFEImageElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio; + readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio; }; SVGFEImageElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.idl b/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.idl index 5cdde1ff..1752919 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.idl
@@ -28,5 +28,5 @@ [ Exposed=Window ] interface SVGFEMergeNodeElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedString in1; };
diff --git a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.idl b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.idl index d1714bd..b9dc359 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.idl
@@ -29,14 +29,14 @@ Exposed=Window ] interface SVGFEMorphologyElement : SVGElement { // Morphology Operators - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_MORPHOLOGY_OPERATOR_ERODE = 1; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_MORPHOLOGY_OPERATOR_DILATE = 2; + const unsigned short SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0; + const unsigned short SVG_MORPHOLOGY_OPERATOR_ERODE = 1; + const unsigned short SVG_MORPHOLOGY_OPERATOR_DILATE = 2; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; - [ImplementedAs=svgOperator, MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration operator; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber radiusX; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber radiusY; + readonly attribute SVGAnimatedString in1; + [ImplementedAs=svgOperator] readonly attribute SVGAnimatedEnumeration operator; + readonly attribute SVGAnimatedNumber radiusX; + readonly attribute SVGAnimatedNumber radiusY; }; SVGFEMorphologyElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_offset_element.idl b/third_party/blink/renderer/core/svg/svg_fe_offset_element.idl index 187b340..13feff0 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_offset_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_offset_element.idl
@@ -28,9 +28,9 @@ [ Exposed=Window ] interface SVGFEOffsetElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber dx; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber dy; + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedNumber dx; + readonly attribute SVGAnimatedNumber dy; }; SVGFEOffsetElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_point_light_element.idl b/third_party/blink/renderer/core/svg/svg_fe_point_light_element.idl index 9ce287b..46e068f 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_point_light_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_point_light_element.idl
@@ -28,7 +28,7 @@ [ Exposed=Window ] interface SVGFEPointLightElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber x; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber y; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber z; + readonly attribute SVGAnimatedNumber x; + readonly attribute SVGAnimatedNumber y; + readonly attribute SVGAnimatedNumber z; };
diff --git a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.idl b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.idl index 9a90e14b..ee9f1d5 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.idl
@@ -28,12 +28,12 @@ [ Exposed=Window ] interface SVGFESpecularLightingElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber surfaceScale; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber specularConstant; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber specularExponent; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber kernelUnitLengthX; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber kernelUnitLengthY; + readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedNumber surfaceScale; + readonly attribute SVGAnimatedNumber specularConstant; + readonly attribute SVGAnimatedNumber specularExponent; + readonly attribute SVGAnimatedNumber kernelUnitLengthX; + readonly attribute SVGAnimatedNumber kernelUnitLengthY; }; SVGFESpecularLightingElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.idl b/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.idl index bd4ee0c..b880c0f 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.idl
@@ -28,12 +28,12 @@ [ Exposed=Window ] interface SVGFESpotLightElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber x; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber y; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber z; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber pointsAtX; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber pointsAtY; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber pointsAtZ; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber specularExponent; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber limitingConeAngle; + readonly attribute SVGAnimatedNumber x; + readonly attribute SVGAnimatedNumber y; + readonly attribute SVGAnimatedNumber z; + readonly attribute SVGAnimatedNumber pointsAtX; + readonly attribute SVGAnimatedNumber pointsAtY; + readonly attribute SVGAnimatedNumber pointsAtZ; + readonly attribute SVGAnimatedNumber specularExponent; + readonly attribute SVGAnimatedNumber limitingConeAngle; };
diff --git a/third_party/blink/renderer/core/svg/svg_fe_tile_element.idl b/third_party/blink/renderer/core/svg/svg_fe_tile_element.idl index ff6e867..c0d24fe0 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_tile_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_tile_element.idl
@@ -28,7 +28,7 @@ [ Exposed=Window ] interface SVGFETileElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString in1; + readonly attribute SVGAnimatedString in1; }; SVGFETileElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.idl b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.idl index 42ad8ab7..eaf1503 100644 --- a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.idl +++ b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.idl
@@ -29,21 +29,21 @@ Exposed=Window ] interface SVGFETurbulenceElement : SVGElement { // Turbulence Types - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_TURBULENCE_TYPE_UNKNOWN = 0; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_TURBULENCE_TYPE_FRACTALNOISE = 1; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_TURBULENCE_TYPE_TURBULENCE = 2; + const unsigned short SVG_TURBULENCE_TYPE_UNKNOWN = 0; + const unsigned short SVG_TURBULENCE_TYPE_FRACTALNOISE = 1; + const unsigned short SVG_TURBULENCE_TYPE_TURBULENCE = 2; // Stitch Options - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_STITCHTYPE_UNKNOWN = 0; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_STITCHTYPE_STITCH = 1; - [MeasureAs=SVG1DOMFilter] const unsigned short SVG_STITCHTYPE_NOSTITCH = 2; + const unsigned short SVG_STITCHTYPE_UNKNOWN = 0; + const unsigned short SVG_STITCHTYPE_STITCH = 1; + const unsigned short SVG_STITCHTYPE_NOSTITCH = 2; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber baseFrequencyX; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber baseFrequencyY; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedInteger numOctaves; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedNumber seed; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration stitchTiles; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration type; + readonly attribute SVGAnimatedNumber baseFrequencyX; + readonly attribute SVGAnimatedNumber baseFrequencyY; + readonly attribute SVGAnimatedInteger numOctaves; + readonly attribute SVGAnimatedNumber seed; + readonly attribute SVGAnimatedEnumeration stitchTiles; + readonly attribute SVGAnimatedEnumeration type; }; SVGFETurbulenceElement includes SVGFilterPrimitiveStandardAttributes;
diff --git a/third_party/blink/renderer/core/svg/svg_filter_element.idl b/third_party/blink/renderer/core/svg/svg_filter_element.idl index 06e1295c0..3f76157 100644 --- a/third_party/blink/renderer/core/svg/svg_filter_element.idl +++ b/third_party/blink/renderer/core/svg/svg_filter_element.idl
@@ -29,12 +29,12 @@ [ Exposed=Window ] interface SVGFilterElement : SVGElement { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration filterUnits; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedEnumeration primitiveUnits; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedLength x; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedLength y; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedLength width; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedLength height; + readonly attribute SVGAnimatedEnumeration filterUnits; + readonly attribute SVGAnimatedEnumeration primitiveUnits; + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; }; SVGFilterElement includes SVGURIReference;
diff --git a/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.idl b/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.idl index f6852b7..4a524220 100644 --- a/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.idl +++ b/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.idl
@@ -27,9 +27,9 @@ // https://drafts.fxtf.org/filter-effects/#InterfaceSVGFilterPrimitiveStandardAttributes interface mixin SVGFilterPrimitiveStandardAttributes { - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedLength x; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedLength y; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedLength width; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedLength height; - [MeasureAs=SVG1DOMFilter] readonly attribute SVGAnimatedString result; + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; + readonly attribute SVGAnimatedString result; };
diff --git a/third_party/blink/renderer/core/svg/svg_gradient_element.idl b/third_party/blink/renderer/core/svg/svg_gradient_element.idl index 8c1fa4f..62fb390 100644 --- a/third_party/blink/renderer/core/svg/svg_gradient_element.idl +++ b/third_party/blink/renderer/core/svg/svg_gradient_element.idl
@@ -29,14 +29,14 @@ Exposed=Window ] interface SVGGradientElement : SVGElement { // Spread Method Types - [MeasureAs=SVG1DOMPaintServer] const unsigned short SVG_SPREADMETHOD_UNKNOWN = 0; - [MeasureAs=SVG1DOMPaintServer] const unsigned short SVG_SPREADMETHOD_PAD = 1; - [MeasureAs=SVG1DOMPaintServer] const unsigned short SVG_SPREADMETHOD_REFLECT = 2; - [MeasureAs=SVG1DOMPaintServer] const unsigned short SVG_SPREADMETHOD_REPEAT = 3; + const unsigned short SVG_SPREADMETHOD_UNKNOWN = 0; + const unsigned short SVG_SPREADMETHOD_PAD = 1; + const unsigned short SVG_SPREADMETHOD_REFLECT = 2; + const unsigned short SVG_SPREADMETHOD_REPEAT = 3; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedEnumeration gradientUnits; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedTransformList gradientTransform; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedEnumeration spreadMethod; + readonly attribute SVGAnimatedEnumeration gradientUnits; + readonly attribute SVGAnimatedTransformList gradientTransform; + readonly attribute SVGAnimatedEnumeration spreadMethod; }; SVGGradientElement includes SVGURIReference;
diff --git a/third_party/blink/renderer/core/svg/svg_linear_gradient_element.idl b/third_party/blink/renderer/core/svg/svg_linear_gradient_element.idl index 02a6d07..b806265 100644 --- a/third_party/blink/renderer/core/svg/svg_linear_gradient_element.idl +++ b/third_party/blink/renderer/core/svg/svg_linear_gradient_element.idl
@@ -27,8 +27,8 @@ [Exposed=Window] interface SVGLinearGradientElement : SVGGradientElement { - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength x1; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength y1; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength x2; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength y2; + readonly attribute SVGAnimatedLength x1; + readonly attribute SVGAnimatedLength y1; + readonly attribute SVGAnimatedLength x2; + readonly attribute SVGAnimatedLength y2; };
diff --git a/third_party/blink/renderer/core/svg/svg_pattern_element.idl b/third_party/blink/renderer/core/svg/svg_pattern_element.idl index 49098b490..168a6425 100644 --- a/third_party/blink/renderer/core/svg/svg_pattern_element.idl +++ b/third_party/blink/renderer/core/svg/svg_pattern_element.idl
@@ -27,13 +27,13 @@ [Exposed=Window] interface SVGPatternElement : SVGElement { - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedEnumeration patternUnits; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedEnumeration patternContentUnits; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedTransformList patternTransform; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength x; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength y; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength width; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength height; + readonly attribute SVGAnimatedEnumeration patternUnits; + readonly attribute SVGAnimatedEnumeration patternContentUnits; + readonly attribute SVGAnimatedTransformList patternTransform; + readonly attribute SVGAnimatedLength x; + readonly attribute SVGAnimatedLength y; + readonly attribute SVGAnimatedLength width; + readonly attribute SVGAnimatedLength height; }; SVGPatternElement includes SVGFitToViewBox;
diff --git a/third_party/blink/renderer/core/svg/svg_radial_gradient_element.idl b/third_party/blink/renderer/core/svg/svg_radial_gradient_element.idl index 3330290..a52e2d5 100644 --- a/third_party/blink/renderer/core/svg/svg_radial_gradient_element.idl +++ b/third_party/blink/renderer/core/svg/svg_radial_gradient_element.idl
@@ -27,10 +27,10 @@ [Exposed=Window] interface SVGRadialGradientElement : SVGGradientElement { - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength cx; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength cy; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength r; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength fx; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength fy; - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedLength fr; + readonly attribute SVGAnimatedLength cx; + readonly attribute SVGAnimatedLength cy; + readonly attribute SVGAnimatedLength r; + readonly attribute SVGAnimatedLength fx; + readonly attribute SVGAnimatedLength fy; + readonly attribute SVGAnimatedLength fr; };
diff --git a/third_party/blink/renderer/core/svg/svg_stop_element.idl b/third_party/blink/renderer/core/svg/svg_stop_element.idl index 36fc16ec..7bed08a 100644 --- a/third_party/blink/renderer/core/svg/svg_stop_element.idl +++ b/third_party/blink/renderer/core/svg/svg_stop_element.idl
@@ -27,5 +27,5 @@ [Exposed=Window] interface SVGStopElement : SVGElement { - [MeasureAs=SVG1DOMPaintServer] readonly attribute SVGAnimatedNumber offset; + readonly attribute SVGAnimatedNumber offset; };
diff --git a/third_party/blink/renderer/core/svg/svg_text_content_element.idl b/third_party/blink/renderer/core/svg/svg_text_content_element.idl index 2117f0d..a51524b7 100644 --- a/third_party/blink/renderer/core/svg/svg_text_content_element.idl +++ b/third_party/blink/renderer/core/svg/svg_text_content_element.idl
@@ -28,12 +28,12 @@ [Exposed=Window] interface SVGTextContentElement : SVGGraphicsElement { // lengthAdjust Types - [MeasureAs=SVG1DOMText] const unsigned short LENGTHADJUST_UNKNOWN = 0; - [MeasureAs=SVG1DOMText] const unsigned short LENGTHADJUST_SPACING = 1; - [MeasureAs=SVG1DOMText] const unsigned short LENGTHADJUST_SPACINGANDGLYPHS = 2; + const unsigned short LENGTHADJUST_UNKNOWN = 0; + const unsigned short LENGTHADJUST_SPACING = 1; + const unsigned short LENGTHADJUST_SPACINGANDGLYPHS = 2; - [MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedLength textLength; - [MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedEnumeration lengthAdjust; + readonly attribute SVGAnimatedLength textLength; + readonly attribute SVGAnimatedEnumeration lengthAdjust; long getNumberOfChars(); [HighEntropy, Measure] float getComputedTextLength();
diff --git a/third_party/blink/renderer/core/svg/svg_text_path_element.idl b/third_party/blink/renderer/core/svg/svg_text_path_element.idl index 4fa851e..04b8c6a2 100644 --- a/third_party/blink/renderer/core/svg/svg_text_path_element.idl +++ b/third_party/blink/renderer/core/svg/svg_text_path_element.idl
@@ -28,18 +28,18 @@ [Exposed=Window] interface SVGTextPathElement : SVGTextContentElement { // textPath Method Types - [MeasureAs=SVG1DOMText] const unsigned short TEXTPATH_METHODTYPE_UNKNOWN = 0; - [MeasureAs=SVG1DOMText] const unsigned short TEXTPATH_METHODTYPE_ALIGN = 1; - [MeasureAs=SVG1DOMText] const unsigned short TEXTPATH_METHODTYPE_STRETCH = 2; + const unsigned short TEXTPATH_METHODTYPE_UNKNOWN = 0; + const unsigned short TEXTPATH_METHODTYPE_ALIGN = 1; + const unsigned short TEXTPATH_METHODTYPE_STRETCH = 2; // textPath Spacing Types - [MeasureAs=SVG1DOMText] const unsigned short TEXTPATH_SPACINGTYPE_UNKNOWN = 0; - [MeasureAs=SVG1DOMText] const unsigned short TEXTPATH_SPACINGTYPE_AUTO = 1; - [MeasureAs=SVG1DOMText] const unsigned short TEXTPATH_SPACINGTYPE_EXACT = 2; + const unsigned short TEXTPATH_SPACINGTYPE_UNKNOWN = 0; + const unsigned short TEXTPATH_SPACINGTYPE_AUTO = 1; + const unsigned short TEXTPATH_SPACINGTYPE_EXACT = 2; - [MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedLength startOffset; - [MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedEnumeration method; - [MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedEnumeration spacing; + readonly attribute SVGAnimatedLength startOffset; + readonly attribute SVGAnimatedEnumeration method; + readonly attribute SVGAnimatedEnumeration spacing; }; SVGTextPathElement includes SVGURIReference;
diff --git a/third_party/blink/renderer/core/svg/svg_text_positioning_element.idl b/third_party/blink/renderer/core/svg/svg_text_positioning_element.idl index 3e3e90c..dcf973b5 100644 --- a/third_party/blink/renderer/core/svg/svg_text_positioning_element.idl +++ b/third_party/blink/renderer/core/svg/svg_text_positioning_element.idl
@@ -27,9 +27,9 @@ [Exposed=Window] interface SVGTextPositioningElement : SVGTextContentElement { - [MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedLengthList x; - [MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedLengthList y; - [MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedLengthList dx; - [MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedLengthList dy; - [MeasureAs=SVG1DOMText] readonly attribute SVGAnimatedNumberList rotate; + readonly attribute SVGAnimatedLengthList x; + readonly attribute SVGAnimatedLengthList y; + readonly attribute SVGAnimatedLengthList dx; + readonly attribute SVGAnimatedLengthList dy; + readonly attribute SVGAnimatedNumberList rotate; };
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc index 293871a6..a8cf2d3 100644 --- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc +++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
@@ -36,8 +36,7 @@ kDOMWrappersTag, WrapperTypeInfo::kWrapperTypeObjectPrototype, WrapperTypeInfo::kObjectClassId, - WrapperTypeInfo::kNotInheritFromActiveScriptWrappable, - WrapperTypeInfo::kIdlBufferSourceType, + WrapperTypeInfo::kIdlOtherType, }; const WrapperTypeInfo& DOMArrayBuffer::wrapper_type_info_ =
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.cc b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.cc index 07ac168..33b5841 100644 --- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.cc +++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.cc
@@ -26,8 +26,7 @@ kDOMWrappersTag, WrapperTypeInfo::kWrapperTypeObjectPrototype, WrapperTypeInfo::kObjectClassId, - WrapperTypeInfo::kNotInheritFromActiveScriptWrappable, - WrapperTypeInfo::kIdlBufferSourceType, + WrapperTypeInfo::kIdlOtherType, }; const WrapperTypeInfo& DOMArrayBufferView::wrapper_type_info_ =
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc b/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc index f139eedd..02a277fe 100644 --- a/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc +++ b/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc
@@ -31,8 +31,7 @@ kDOMWrappersTag, WrapperTypeInfo::kWrapperTypeObjectPrototype, WrapperTypeInfo::kObjectClassId, - WrapperTypeInfo::kNotInheritFromActiveScriptWrappable, - WrapperTypeInfo::kIdlBufferSourceType, + WrapperTypeInfo::kIdlOtherType, }; const WrapperTypeInfo& DOMDataView::wrapper_type_info_ =
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc b/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc index 58b2b72..4029df7 100644 --- a/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc +++ b/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc
@@ -28,8 +28,7 @@ kDOMWrappersTag, WrapperTypeInfo::kWrapperTypeObjectPrototype, WrapperTypeInfo::kObjectClassId, - WrapperTypeInfo::kNotInheritFromActiveScriptWrappable, - WrapperTypeInfo::kIdlBufferSourceType, + WrapperTypeInfo::kIdlOtherType, }; const WrapperTypeInfo& DOMSharedArrayBuffer::wrapper_type_info_ =
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc b/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc index 84e804c..c143c18 100644 --- a/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc +++ b/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc
@@ -63,8 +63,7 @@ kDOMWrappersTag, \ WrapperTypeInfo::kWrapperTypeObjectPrototype, \ WrapperTypeInfo::kObjectClassId, \ - WrapperTypeInfo::kNotInheritFromActiveScriptWrappable, \ - WrapperTypeInfo::kIdlBufferSourceType, \ + WrapperTypeInfo::kIdlOtherType, \ }; \ template <> \ const WrapperTypeInfo& DOMTypedArray<val_t, v8::Type##Array, \
diff --git a/third_party/blink/renderer/modules/hid/hid_device.cc b/third_party/blink/renderer/modules/hid/hid_device.cc index 27fcf6f..41c20ab 100644 --- a/third_party/blink/renderer/modules/hid/hid_device.cc +++ b/third_party/blink/renderer/modules/hid/hid_device.cc
@@ -323,9 +323,10 @@ return promise; } -ScriptPromise<IDLUndefined> HIDDevice::sendReport(ScriptState* script_state, - uint8_t report_id, - const DOMArrayPiece& data) { +ScriptPromise<IDLUndefined> HIDDevice::sendReport( + ScriptState* script_state, + uint8_t report_id, + base::span<const uint8_t> data) { auto* resolver = MakeGarbageCollected<ScriptPromiseResolver<IDLUndefined>>(script_state); auto promise = resolver->Promise(); @@ -340,14 +341,14 @@ return promise; } - if (!base::CheckedNumeric<wtf_size_t>(data.ByteLength()).IsValid()) { + if (!base::CheckedNumeric<wtf_size_t>(data.size()).IsValid()) { resolver->RejectWithDOMException(DOMExceptionCode::kNotSupportedError, kArrayBufferTooBig); return promise; } Vector<uint8_t> vector; - vector.AppendSpan(data.ByteSpan()); + vector.AppendSpan(data); device_requests_.insert(resolver); connection_->Write( @@ -360,7 +361,7 @@ ScriptPromise<IDLUndefined> HIDDevice::sendFeatureReport( ScriptState* script_state, uint8_t report_id, - const DOMArrayPiece& data) { + base::span<const uint8_t> data) { auto* resolver = MakeGarbageCollected<ScriptPromiseResolver<IDLUndefined>>(script_state); auto promise = resolver->Promise(); @@ -375,14 +376,14 @@ return promise; } - if (!base::CheckedNumeric<wtf_size_t>(data.ByteLength()).IsValid()) { + if (!base::CheckedNumeric<wtf_size_t>(data.size()).IsValid()) { resolver->RejectWithDOMException(DOMExceptionCode::kNotSupportedError, kArrayBufferTooBig); return promise; } Vector<uint8_t> vector; - vector.AppendSpan(data.ByteSpan()); + vector.AppendSpan(data); device_requests_.insert(resolver); connection_->SendFeatureReport(
diff --git a/third_party/blink/renderer/modules/hid/hid_device.h b/third_party/blink/renderer/modules/hid/hid_device.h index 7eee882..877ef1f 100644 --- a/third_party/blink/renderer/modules/hid/hid_device.h +++ b/third_party/blink/renderer/modules/hid/hid_device.h
@@ -81,10 +81,10 @@ ExceptionState& exception_state); ScriptPromise<IDLUndefined> sendReport(ScriptState*, uint8_t report_id, - const DOMArrayPiece& data); + base::span<const uint8_t> data); ScriptPromise<IDLUndefined> sendFeatureReport(ScriptState*, uint8_t report_id, - const DOMArrayPiece& data); + base::span<const uint8_t> data); ScriptPromise<NotShared<DOMDataView>> receiveFeatureReport(ScriptState*, uint8_t report_id);
diff --git a/third_party/blink/renderer/modules/hid/hid_device.idl b/third_party/blink/renderer/modules/hid/hid_device.idl index 21785814..b749d32 100644 --- a/third_party/blink/renderer/modules/hid/hid_device.idl +++ b/third_party/blink/renderer/modules/hid/hid_device.idl
@@ -54,7 +54,7 @@ CallWith=ScriptState, MeasureAs=HidDeviceSendReport ] Promise<undefined> sendReport( - [EnforceRange] octet reportId, BufferSource data); + [EnforceRange] octet reportId, [PassAsSpan] BufferSource data); // Send a feature report to the device. Set |reportId| to the first byte of // the report and |data| to the remaining bytes. Set |reportId| to zero if @@ -64,7 +64,7 @@ CallWith=ScriptState, MeasureAs=HidDeviceSendFeatureReport ] Promise<undefined> sendFeatureReport( - [EnforceRange] octet reportId, BufferSource data); + [EnforceRange] octet reportId, [PassAsSpan] BufferSource data); // Request a feature report from the device. Set |reportId| to the ID of the // feature report to request, or zero if the device does not use report IDs.
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc index e22bc6b..6a0a54a 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
@@ -55,9 +55,6 @@ if (ElementFromCenter(*this) != &MediaElement()) { SetIsWanted(false); } - - base::UmaHistogramBoolean("Media.Controls.OverlayCastButtonIsCovered", - !IsWanted()); } void MediaControlCastButtonElement::UpdateDisplayType() {
diff --git a/third_party/blink/renderer/modules/webcodecs/array_buffer_util.cc b/third_party/blink/renderer/modules/webcodecs/array_buffer_util.cc index 6bf03ab..4b93f4a 100644 --- a/third_party/blink/renderer/modules/webcodecs/array_buffer_util.cc +++ b/third_party/blink/renderer/modules/webcodecs/array_buffer_util.cc
@@ -1,46 +1,32 @@ // 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. - -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/351564777): Remove this and convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #include "third_party/blink/renderer/modules/webcodecs/array_buffer_util.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h" namespace blink { -ArrayBufferContents PinArrayBufferContent( +ArrayBufferContents PinSharedArrayBufferContent( const AllowSharedBufferSource* buffer_union) { ArrayBufferContents result; switch (buffer_union->GetContentType()) { case AllowSharedBufferSource::ContentType::kArrayBufferAllowShared: { auto* buffer = buffer_union->GetAsArrayBufferAllowShared(); - if (buffer && !buffer->IsDetached()) { - if (buffer->IsShared()) { - buffer->Content()->ShareWith(result); - } else { - static_cast<blink::DOMArrayBuffer*>(buffer) - ->ShareNonSharedForInternalUse(result); - } + if (buffer && !buffer->IsDetached() && buffer->IsShared()) { + buffer->Content()->ShareWith(result); } - return result; + break; } case AllowSharedBufferSource::ContentType::kArrayBufferViewAllowShared: { auto* view = buffer_union->GetAsArrayBufferViewAllowShared().Get(); - if (view && !view->IsDetached()) { - if (view->IsShared()) { - view->BufferShared()->Content()->ShareWith(result); - } else { - view->buffer()->ShareNonSharedForInternalUse(result); - } + if (view && !view->IsDetached() && view->IsShared()) { + view->BufferShared()->Content()->ShareWith(result); } - return result; + break; } } + return result; } ArrayBufferContents TransferArrayBufferForSpan( @@ -88,10 +74,10 @@ continue; } - auto* contents_data = static_cast<const uint8_t*>(contents.Data()); - if (data_range.data() < contents_data || - data_range.data() + data_range.size() > - contents_data + contents.DataLength()) { + auto contents_data = contents.ByteSpan(); + if (contents_data.empty() || data_range.empty() || + data_range.data() < contents_data.data() || + &data_range.back() > &contents_data.back()) { // This array buffer doesn't contain `data_range`. Let's ignore it. continue; }
diff --git a/third_party/blink/renderer/modules/webcodecs/array_buffer_util.h b/third_party/blink/renderer/modules/webcodecs/array_buffer_util.h index 98b2bac..f6390e4 100644 --- a/third_party/blink/renderer/modules/webcodecs/array_buffer_util.h +++ b/third_party/blink/renderer/modules/webcodecs/array_buffer_util.h
@@ -49,7 +49,9 @@ // Ensures that the underlying memory for `buffer_union` remains valid // (owned by a returned instance of ArrayBufferContents) // even if the buffer is detached or truncated by client activity. -ArrayBufferContents PinArrayBufferContent( +// Returns a valid ArrayBufferContents only for shared buffers, otherwise +// returns an empty ArrayBufferContents. +ArrayBufferContents PinSharedArrayBufferContent( const AllowSharedBufferSource* buffer_union); // 1. Check if any on the array buffers from the `transfer_list` contain
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc index 9a1151e..f34853c 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -1297,12 +1297,16 @@ const VideoFrameLayout& dest_layout) { auto* background_readback = BackgroundReadback::From( *ExecutionContext::From(resolver->GetScriptState())); - if (!background_readback) + if (!background_readback) { return false; + } - ArrayBufferContents contents = PinArrayBufferContent(destination); - if (!contents.DataLength()) + ArrayBufferContents contents = PinSharedArrayBufferContent(destination); + if (!contents.IsValid() || !contents.DataLength()) { + // `contents` is empty, most likely destination isn't a shared buffer. + // Async copyTo() can't be used. return false; + } auto readback_done_handler = [](ArrayBufferContents contents, @@ -1388,12 +1392,14 @@ DCHECK(local_frame->HasSharedImage()); if (base::FeatureList::IsEnabled(kVideoFrameAsyncCopyTo)) { + // Check if we can run copyTo() asynchronously. if (CopyToAsync(resolver, local_frame, src_rect, destination, dest_layout)) { return promise; } } + // Async version didn't work, let's copy planes synchronously. if (!CopyTexturablePlanes(*local_frame, src_rect, dest_layout, buffer)) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, "Failed to read VideoFrame data.");
diff --git a/third_party/blink/renderer/modules/xr/BUILD.gn b/third_party/blink/renderer/modules/xr/BUILD.gn index eca19ca..70c6d52 100644 --- a/third_party/blink/renderer/modules/xr/BUILD.gn +++ b/third_party/blink/renderer/modules/xr/BUILD.gn
@@ -115,6 +115,7 @@ "xr_space.cc", "xr_space.h", "xr_sub_image.h", + "xr_swap_chain.h", "xr_system.cc", "xr_system.h", "xr_target_ray_space.cc", @@ -136,7 +137,13 @@ "xr_webgl_depth_information.h", "xr_webgl_layer.cc", "xr_webgl_layer.h", + "xr_webgl_layer_client.h", + "xr_webgl_projection_layer.cc", + "xr_webgl_projection_layer.h", + "xr_webgl_sub_image.cc", "xr_webgl_sub_image.h", + "xr_webgl_swap_chain.cc", + "xr_webgl_swap_chain.h", ] deps = [
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc index 797e4e6..6a9e396 100644 --- a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc +++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
@@ -23,10 +23,14 @@ #include "third_party/blink/renderer/modules/xr/xr_gpu_binding.h" #include "third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.h" #include "third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.h" +#include "third_party/blink/renderer/modules/xr/xr_graphics_binding.h" +#include "third_party/blink/renderer/modules/xr/xr_projection_layer.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" #include "third_party/blink/renderer/modules/xr/xr_system.h" #include "third_party/blink/renderer/modules/xr/xr_viewport.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_layer_client.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h" #include "third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "ui/display/display.h" @@ -629,9 +633,14 @@ return high_res_now_ms; } -void XRFrameProvider::SubmitWebGLLayer(XRWebGLLayer* layer, bool was_changed) { - CHECK(layer); +void XRFrameProvider::SubmitWebGLLayer(XRWebGLLayerClient* layer_client, + bool was_changed) { + CHECK(layer_client); CHECK(immersive_session_); + + const XRLayer* layer = layer_client->layer(); + CHECK(layer); + CHECK_EQ(layer->session(), immersive_session_); CHECK_EQ(layer->session()->GraphicsApi(), XRGraphicsBinding::Api::kWebGL); if (!immersive_presentation_provider_.is_bound()) @@ -640,7 +649,7 @@ TRACE_EVENT1("gpu", "XRFrameProvider::SubmitWebGLLayer", "frame", frame_id_); DVLOG(3) << __func__ << ": frame=" << frame_id_; - WebGLRenderingContextBase* webgl_context = layer->context(); + WebGLRenderingContextBase* webgl_context = layer_client->context(); if (frame_id_ < 0) { // There is no valid frame_id_, and the browser side is not currently @@ -681,7 +690,7 @@ } scoped_refptr<StaticBitmapImage> image_ref = - layer->TransferToStaticBitmapImage(); + layer_client->TransferToStaticBitmapImage(); if (!image_ref) return; @@ -802,15 +811,17 @@ // TODO(bajones): This only works because we're restricted to a single layer at // the moment. Will need an overhaul when we get more robust layering support. -void XRFrameProvider::UpdateWebGPULayerViewports(XRGPUProjectionLayer* layer) { +void XRFrameProvider::UpdateLayerViewports(XRProjectionLayer* layer) { DCHECK(layer->session() == immersive_session_); - DCHECK(layer->session()->GraphicsApi() == XRGraphicsBinding::Api::kWebGPU); DCHECK(immersive_presentation_provider_.is_bound()); - XRGPUBinding* webgpu_binding = static_cast<XRGPUBinding*>(layer->binding()); + XRGraphicsBinding* binding = layer->binding(); - // TODO(crbug.com/359418629): Adjust viewport calculations once we start using - // texture array-capable mailboxes. + // TODO(crbug.com/359418629): Currently we have no way to submit texture + // arrays to the compositor, so any array textures produced by the page will + // be copied to a side-by-side texture prior to submission. That does mean + // that we need to adjust the viewports from those reported to the page, + // however, by altering the texture width here... float width = layer->textureWidth() * layer->textureArrayLength(); float height = layer->textureHeight(); @@ -822,16 +833,20 @@ XRViewData* right_view = immersive_session_->ViewDataForEye(device::mojom::blink::XREye::kRight); - gfx::Rect left = webgpu_binding->GetViewportForView(layer, left_view); - gfx::Rect right = webgpu_binding->GetViewportForView(layer, right_view); - right.set_x(right.x() + layer->textureWidth()); + gfx::Rect left = binding->GetViewportForView(layer, left_view); + gfx::Rect right = binding->GetViewportForView(layer, right_view); + + // (continued from prior comment) ...and offsetting the viewports here. + if (layer->textureArrayLength() > 1) { + right.set_x(right.x() + layer->textureWidth()); + } left_coords = NormalizeViewport(left, width, height); right_coords = NormalizeViewport(right, width, height); } else { XRViewData* mono_view = immersive_session_->ViewDataForEye(device::mojom::blink::XREye::kNone); - gfx::Rect viewport = webgpu_binding->GetViewportForView(layer, mono_view); + gfx::Rect viewport = binding->GetViewportForView(layer, mono_view); left_coords = NormalizeViewport(viewport, width, height);
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.h b/third_party/blink/renderer/modules/xr/xr_frame_provider.h index 2d75ce3689..0fa6d06 100644 --- a/third_party/blink/renderer/modules/xr/xr_frame_provider.h +++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.h
@@ -26,9 +26,11 @@ class LocalDOMWindow; class XRFrameTransport; class XRGPUProjectionLayer; +class XRProjectionLayer; class XRSession; class XRSystem; class XRWebGLLayer; +class XRWebGLLayerClient; // This class manages requesting and dispatching frame updates, which includes // pose information for a given XRDevice. @@ -60,11 +62,13 @@ void OnNonImmersiveVSync(double high_res_now_ms); - void SubmitWebGLLayer(XRWebGLLayer*, bool was_changed); + void SubmitWebGLLayer(XRWebGLLayerClient*, bool was_changed); void UpdateWebGLLayerViewports(XRWebGLLayer*); void SubmitWebGPULayer(XRGPUProjectionLayer*, bool was_queried); - void UpdateWebGPULayerViewports(XRGPUProjectionLayer*); + + // Used for both WebGPU and WebGL layers. + void UpdateLayerViewports(XRProjectionLayer*); void Dispose(); void OnFocusChanged();
diff --git a/third_party/blink/renderer/modules/xr/xr_gpu_binding.h b/third_party/blink/renderer/modules/xr/xr_gpu_binding.h index 42b05595..8104244 100644 --- a/third_party/blink/renderer/modules/xr/xr_gpu_binding.h +++ b/third_party/blink/renderer/modules/xr/xr_gpu_binding.h
@@ -52,7 +52,8 @@ GPUDevice* device() const { return device_.Get(); } - gfx::Rect GetViewportForView(XRProjectionLayer* layer, XRViewData* view); + gfx::Rect GetViewportForView(XRProjectionLayer* layer, + XRViewData* view) override; void Trace(Visitor*) const override;
diff --git a/third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.cc b/third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.cc index 41b49d5..aeb2b2e 100644 --- a/third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_gpu_projection_layer.cc
@@ -61,7 +61,7 @@ XRFrameProvider* frame_provider = session()->xr()->frameProvider(); if (viewport_updated_) { - frame_provider->UpdateWebGPULayerViewports(this); + frame_provider->UpdateLayerViewports(this); viewport_updated_ = false; }
diff --git a/third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.cc b/third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.cc index 213e9495..30121c7 100644 --- a/third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.cc +++ b/third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.cc
@@ -5,8 +5,6 @@ #include "third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.h" #include "third_party/blink/renderer/modules/webgpu/gpu_device.h" -#include "third_party/blink/renderer/modules/webgpu/gpu_texture.h" -#include "third_party/blink/renderer/modules/xr/xr_composition_layer.h" #include "third_party/blink/renderer/modules/xr/xr_layer_shared_image_manager.h" namespace blink { @@ -39,41 +37,19 @@ CHECK(device); } -void XRGPUSwapChain::OnFrameStart() { - texture_queried_ = false; -} -void XRGPUSwapChain::OnFrameEnd() { - ResetCurrentTexture(); -} - -GPUTexture* XRGPUSwapChain::GetCurrentTexture() { - texture_queried_ = true; - if (!current_texture_) { - current_texture_ = ProduceTexture(); - } - return current_texture_; -} - -// Resets the cached texture so that next GetCurrentTexture call will trigger a -// ProduceTexture call. -GPUTexture* XRGPUSwapChain::ResetCurrentTexture() { - GPUTexture* texture = current_texture_.Get(); - current_texture_ = nullptr; - return texture; -} - // Clears the contents of the current texture to transparent black or 0 (for // depth/stencil textures). void XRGPUSwapChain::ClearCurrentTexture(wgpu::CommandEncoder command_encoder) { - if (!current_texture_) { + GPUTexture* texture = current_texture(); + if (!texture) { return; } - bool hasDepth = IsDepthFormat(current_texture_->Format()); - bool hasStencil = IsStencilFormat(current_texture_->Format()); + bool hasDepth = IsDepthFormat(texture->Format()); + bool hasStencil = IsStencilFormat(texture->Format()); // Clear each level of the texture array. - for (uint32_t i = 0; i < current_texture_->depthOrArrayLayers(); ++i) { + for (uint32_t i = 0; i < texture->depthOrArrayLayers(); ++i) { wgpu::TextureViewDescriptor view_desc = { .dimension = wgpu::TextureViewDimension::e2D, .baseMipLevel = 0, @@ -82,8 +58,7 @@ .arrayLayerCount = 1, }; - wgpu::TextureView view = - current_texture_->GetHandle().CreateView(&view_desc); + wgpu::TextureView view = texture->GetHandle().CreateView(&view_desc); wgpu::RenderPassEncoder render_pass; if (hasDepth || hasStencil) { @@ -131,8 +106,7 @@ void XRGPUSwapChain::Trace(Visitor* visitor) const { visitor->Trace(device_); - visitor->Trace(current_texture_); - visitor->Trace(layer_); + XRSwapChain::Trace(visitor); } XRGPUStaticSwapChain::XRGPUStaticSwapChain(GPUDevice* device,
diff --git a/third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.h b/third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.h index c707ea7..da24ae3 100644 --- a/third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.h +++ b/third_party/blink/renderer/modules/xr/xr_gpu_swap_chain.h
@@ -5,6 +5,8 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_GPU_SWAP_CHAIN_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_GPU_SWAP_CHAIN_H_ +#include "third_party/blink/renderer/modules/webgpu/gpu_texture.h" +#include "third_party/blink/renderer/modules/xr/xr_swap_chain.h" #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/member.h" @@ -13,39 +15,22 @@ class GPUDevice; class GPUTexture; -class XRCompositionLayer; -class XRGPUSwapChain : public GarbageCollected<XRGPUSwapChain> { +class XRGPUSwapChain : public XRSwapChain<GPUTexture> { public: explicit XRGPUSwapChain(GPUDevice*); - virtual ~XRGPUSwapChain() = default; - - GPUTexture* GetCurrentTexture(); - virtual void OnFrameStart(); - virtual void OnFrameEnd(); - - virtual const wgpu::TextureDescriptor& descriptor() const = 0; + ~XRGPUSwapChain() override = default; GPUDevice* device() { return device_.Get(); } + virtual const wgpu::TextureDescriptor& descriptor() const = 0; - virtual void SetLayer(XRCompositionLayer* layer) { layer_ = layer; } - XRCompositionLayer* layer() { return layer_.Get(); } - - bool texture_was_queried() const { return texture_queried_; } - - virtual void Trace(Visitor* visitor) const; + void Trace(Visitor* visitor) const override; protected: - virtual GPUTexture* ProduceTexture() = 0; - - GPUTexture* ResetCurrentTexture(); void ClearCurrentTexture(wgpu::CommandEncoder); private: Member<GPUDevice> device_; - Member<GPUTexture> current_texture_; - Member<XRCompositionLayer> layer_; - bool texture_queried_; }; // A texture swap chain that is not communicated back to the compositor, used
diff --git a/third_party/blink/renderer/modules/xr/xr_graphics_binding.h b/third_party/blink/renderer/modules/xr/xr_graphics_binding.h index 85ab25c..b108ce2 100644 --- a/third_party/blink/renderer/modules/xr/xr_graphics_binding.h +++ b/third_party/blink/renderer/modules/xr/xr_graphics_binding.h
@@ -8,10 +8,16 @@ #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/member.h" +namespace gfx { +class Rect; +} // namespace gfx + namespace blink { class XRCompositionLayer; +class XRProjectionLayer; class XRSession; +class XRViewData; // Base class for XRWebGLBinding and XRGPUBinding, which helps facilitate type // checking when layers are passed in to get sub images. @@ -28,6 +34,9 @@ bool OwnsLayer(XRCompositionLayer*); + virtual gfx::Rect GetViewportForView(XRProjectionLayer* layer, + XRViewData* view) = 0; + void Trace(Visitor*) const override; private:
diff --git a/third_party/blink/renderer/modules/xr/xr_swap_chain.h b/third_party/blink/renderer/modules/xr/xr_swap_chain.h new file mode 100644 index 0000000..953da37 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_swap_chain.h
@@ -0,0 +1,77 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SWAP_CHAIN_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SWAP_CHAIN_H_ + +#include "third_party/blink/renderer/modules/xr/xr_composition_layer.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/member.h" + +namespace blink { + +// An XRSwapChain manages the creation and lifetime of textures used by an +// XRCompositorLayer. The general lifetime is expected to be: +// +// OnFrameStart() - Called prior to the XRFrame callback for any active layers +// GetCurrentTexture() - Called when a sub image is requested for the layer +// > ProduceTexture() - Called by GetCurrentTexture if a new texture is needed +// OnFrameEnd() - Called prior to the frame submission +// > ResetCurrentTexture() - Called by OnFrameEnd if a new texture is required +// for the next frame. + +template <typename Texture> +class XRSwapChain : public GarbageCollected<XRSwapChain<Texture>> { + public: + XRSwapChain() {} + virtual ~XRSwapChain() = default; + + Texture* GetCurrentTexture() { + texture_queried_ = true; + if (!current_texture_) { + current_texture_ = ProduceTexture(); + } + return current_texture_; + } + virtual void OnFrameStart() { texture_queried_ = false; } + virtual void OnFrameEnd() { ResetCurrentTexture(); } + + // Manage the XRCompositorLayer this swap chain is associated with. + virtual void SetLayer(XRCompositionLayer* layer) { layer_ = layer; } + XRCompositionLayer* layer() { return layer_.Get(); } + + // Indicates if the texture was queried during the most recent frame. + bool texture_was_queried() const { return texture_queried_; } + + virtual void Trace(Visitor* visitor) const { + visitor->Trace(current_texture_); + visitor->Trace(layer_); + } + + protected: + // Produces a new Texture for the swap chain. Will not be called again unless + // the current texture is reset. + virtual Texture* ProduceTexture() = 0; + + // Resets the cached texture so that next GetCurrentTexture call will trigger + // a ProduceTexture call. + Texture* ResetCurrentTexture() { + Texture* texture = current_texture_.Get(); + current_texture_ = nullptr; + return texture; + } + + // Return the current texture if one has been produced and not reset. + Texture* current_texture() { return current_texture_; } + + private: + Member<Texture> current_texture_; + Member<XRCompositionLayer> layer_; + + bool texture_queried_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SWAP_CHAIN_H_
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc b/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc index 5cd8144..abfb1bab 100644 --- a/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc +++ b/third_party/blink/renderer/modules/xr/xr_webgl_binding.cc
@@ -19,12 +19,22 @@ #include "third_party/blink/renderer/modules/xr/xr_utils.h" #include "third_party/blink/renderer/modules/xr/xr_viewer_pose.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_layer.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h" #include "third_party/blink/renderer/modules/xr/xr_webgl_sub_image.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/size_conversions.h" +#include "ui/gfx/geometry/size_f.h" namespace blink { +namespace { + +const double kMinScaleFactor = 0.2; + +} // namespace + XRWebGLBinding* XRWebGLBinding::Create(XRSession* session, const V8XRWebGLRenderingContext* context, ExceptionState& exception_state) { @@ -85,16 +95,114 @@ XRProjectionLayer* XRWebGLBinding::createProjectionLayer( const XRProjectionLayerInit* init, ExceptionState& exception_state) { - NOTIMPLEMENTED(); - return nullptr; + if (!CanCreateLayer(exception_state) || + !ValidateLayerColorFormat(init->colorFormat(), exception_state) || + !ValidateLayerDepthStencilFormat(init->depthFormat(), exception_state)) { + return nullptr; + } + + // The max size will be either the native resolution or the default + // if that happens to be larger than the native res. (That can happen on + // desktop systems.) + double max_scale = std::max(session()->NativeFramebufferScale(), 1.0); + + // Clamp the developer-requested framebuffer scale to ensure it's not too + // small to see or unreasonably large. + double scale_factor = + std::clamp(init->scaleFactor(), kMinScaleFactor, max_scale); + gfx::SizeF scaled_size = + gfx::ScaleSize(session()->RecommendedArrayTextureSize(), scale_factor); + + // TODO(crbug.com/359418629): Remove once array Mailboxes are available. + scaled_size.set_width(scaled_size.width() * + session()->array_texture_layers()); + + // If the scaled texture dimensions are larger than the max texture dimension + // for the context scale it down till it fits. + GLint max_texture_size = 0; + webgl_context_->ContextGL()->GetIntegerv(GL_MAX_TEXTURE_SIZE, + &max_texture_size); + if (scaled_size.width() > max_texture_size || + scaled_size.height() > max_texture_size) { + double max_dimension = std::max(scaled_size.width(), scaled_size.height()); + scaled_size = gfx::ScaleSize(scaled_size, max_texture_size / max_dimension); + } + + gfx::Size texture_size = gfx::ToFlooredSize(scaled_size); + + XRWebGLSwapChain::Descriptor color_desc = {}; + color_desc.format = FormatForLayerFormat(init->colorFormat()); + color_desc.internal_format = + InternalFormatForLayerFormat(init->colorFormat()); + color_desc.type = TypeForLayerFormat(init->colorFormat()); + color_desc.attachment_target = GL_COLOR_ATTACHMENT0; + color_desc.width = static_cast<uint32_t>(texture_size.width()); + color_desc.height = static_cast<uint32_t>(texture_size.height()); + color_desc.depth = 1; + + XRWebGLSharedImageSwapChain* color_swap_chain = + MakeGarbageCollected<XRWebGLSharedImageSwapChain>(webgl_context_, + color_desc, webgl2_); + + // TODO(crbug.com/40700985): Return a wrapped swap chain for texture-array + // layers, like with the WebGPU layers. + + XRWebGLStaticSwapChain* depth_stencil_swap_chain = nullptr; + if (init->depthFormat() != GL_NONE) { + XRWebGLSwapChain::Descriptor depth_stencil_desc = {}; + depth_stencil_desc.format = FormatForLayerFormat(init->depthFormat()); + depth_stencil_desc.internal_format = + InternalFormatForLayerFormat(init->depthFormat()); + depth_stencil_desc.type = TypeForLayerFormat(init->depthFormat()); + depth_stencil_desc.attachment_target = GL_DEPTH_ATTACHMENT; + depth_stencil_desc.width = static_cast<uint32_t>(texture_size.width()); + depth_stencil_desc.height = static_cast<uint32_t>(texture_size.height()); + depth_stencil_desc.depth = 1; + + depth_stencil_swap_chain = MakeGarbageCollected<XRWebGLStaticSwapChain>( + webgl_context_, depth_stencil_desc, webgl2_); + } + + return MakeGarbageCollected<XRWebGLProjectionLayer>(this, color_swap_chain, + depth_stencil_swap_chain); } XRWebGLSubImage* XRWebGLBinding::getViewSubImage( XRProjectionLayer* layer, XRView* view, ExceptionState& exception_state) { - NOTIMPLEMENTED(); - return nullptr; + CHECK(layer); + CHECK(view); + if (!OwnsLayer(layer)) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "Layer was not created with this binding."); + return nullptr; + } + + if (!view || view->session() != session()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "View was not created with the same session as this binding."); + return nullptr; + } + + // Because we have validated that this is a layer owned by this binding we + // know that it is a XRWebGLProjectionLayer, because that's the only type of + // projection layer that this class returns. + XRWebGLProjectionLayer* gl_layer = + static_cast<XRWebGLProjectionLayer*>(layer); + + XRViewData* viewData = view->ViewData(); + if (viewData->ApplyViewportScaleForFrame()) { + gl_layer->MarkViewportUpdated(); + } + + gfx::Rect viewport = GetViewportForView(layer, viewData); + + return MakeGarbageCollected<XRWebGLSubImage>( + viewport, viewData->index(), gl_layer->color_swap_chain(), + gl_layer->depth_stencil_swap_chain(), nullptr); } WebGLTexture* XRWebGLBinding::getReflectionCubeMap( @@ -264,6 +372,183 @@ return view->GetWebGLDepthInformation(exception_state); } +gfx::Rect XRWebGLBinding::GetViewportForView(XRProjectionLayer* layer, + XRViewData* view) { + CHECK(OwnsLayer(layer)); + + // If the layer is not side-by-side return the full texture size adjusted by + // the viewport scale. + if (layer->textureArrayLength() > 1) { + return gfx::Rect(0, 0, layer->textureWidth() * view->CurrentViewportScale(), + layer->textureHeight() * view->CurrentViewportScale()); + } + + // Otherwise the layer is side-by-side, so the viewports should be distributed + // across the texture width. + uint32_t viewport_width = + layer->textureWidth() / session()->array_texture_layers(); + uint32_t viewport_offset = viewport_width * view->index(); + return gfx::Rect(viewport_offset, 0, + viewport_width * view->CurrentViewportScale(), + layer->textureHeight() * view->CurrentViewportScale()); +} + +bool XRWebGLBinding::CanCreateLayer(ExceptionState& exception_state) { + if (session()->ended()) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "Cannot create a new layer for an " + "XRSession which has already ended."); + return false; + } + + if (webgl_context_->isContextLost()) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "Cannot create a new layer with a lost " + "WebGL context."); + return false; + } + + return true; +} + +bool XRWebGLBinding::ValidateLayerColorFormat(GLenum color_format, + ExceptionState& exception_state) { + switch (color_format) { + case GL_RGBA: + case GL_RGB: + case GL_SRGB_EXT: + case GL_SRGB_ALPHA_EXT: + return true; + case GL_RGBA8: + case GL_RGB8: + case GL_SRGB8: + case GL_SRGB8_ALPHA8: + if (!webgl2_) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "Specified colorFormat only available with WebGL 2 contexts."); + return false; + } + return true; + default: + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "Invalid colorFormat."); + return false; + } +} + +bool XRWebGLBinding::ValidateLayerDepthStencilFormat( + GLenum depth_stencil_format, + ExceptionState& exception_state) { + switch (depth_stencil_format) { + case GL_NONE: + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL: + return true; + case GL_DEPTH_COMPONENT24: + case GL_DEPTH24_STENCIL8: + if (!webgl2_) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "Specified depthFormat only available with WebGL 2 contexts."); + return false; + } + return true; + default: + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "depthFormat must be a valid depth format or GL_NONE."); + return false; + } +} + +GLenum XRWebGLBinding::FormatForLayerFormat(GLenum layer_format) { + switch (layer_format) { + case GL_RGBA: + case GL_RGBA8: + return GL_RGBA; + + case GL_RGB: + case GL_RGB8: + return GL_RGB; + + case GL_SRGB_EXT: + case GL_SRGB8: + return GL_SRGB_EXT; + + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8_ALPHA8: + return GL_SRGB_ALPHA_EXT; + + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT24: + return GL_DEPTH_COMPONENT; + + case GL_DEPTH_STENCIL: + case GL_DEPTH24_STENCIL8: + return GL_DEPTH_STENCIL; + + default: + NOTREACHED(); + } +} + +GLenum XRWebGLBinding::InternalFormatForLayerFormat(GLenum layer_format) { + switch (layer_format) { + case GL_RGBA: + case GL_RGBA8: + return GL_RGBA8; + + case GL_RGB: + case GL_RGB8: + return GL_RGB8; + + case GL_SRGB_EXT: + case GL_SRGB8: + return GL_SRGB8; + + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8_ALPHA8: + return GL_SRGB8_ALPHA8; + + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT24: + return GL_DEPTH_COMPONENT24; + + case GL_DEPTH_STENCIL: + case GL_DEPTH24_STENCIL8: + return GL_DEPTH24_STENCIL8; + + default: + NOTREACHED(); + } +} + +GLenum XRWebGLBinding::TypeForLayerFormat(GLenum layer_format) { + switch (layer_format) { + case GL_RGBA: + case GL_RGBA8: + case GL_RGB: + case GL_RGB8: + case GL_SRGB_EXT: + case GL_SRGB8: + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8_ALPHA8: + return GL_BYTE; + + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL: + return GL_UNSIGNED_SHORT; + + case GL_DEPTH_COMPONENT24: + case GL_DEPTH24_STENCIL8: + return GL_UNSIGNED_INT; + + default: + NOTREACHED(); + } +} + void XRWebGLBinding::Trace(Visitor* visitor) const { visitor->Trace(webgl_context_); XRGraphicsBinding::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_binding.h b/third_party/blink/renderer/modules/xr/xr_webgl_binding.h index 3699c84..d7cf503 100644 --- a/third_party/blink/renderer/modules/xr/xr_webgl_binding.h +++ b/third_party/blink/renderer/modules/xr/xr_webgl_binding.h
@@ -52,9 +52,23 @@ XRWebGLDepthInformation* getDepthInformation(XRView* view, ExceptionState& exception_state); + gfx::Rect GetViewportForView(XRProjectionLayer* layer, + XRViewData* view) override; + + WebGLRenderingContextBase* context() const { return webgl_context_.Get(); } + void Trace(Visitor*) const override; private: + bool CanCreateLayer(ExceptionState& exception_state); + bool ValidateLayerColorFormat(GLenum color_format, + ExceptionState& exception_state); + bool ValidateLayerDepthStencilFormat(GLenum depth_stencil_format, + ExceptionState& exception_state); + GLenum FormatForLayerFormat(GLenum format); + GLenum InternalFormatForLayerFormat(GLenum format); + GLenum TypeForLayerFormat(GLenum format); + Member<WebGLRenderingContextBase> webgl_context_; bool webgl2_; };
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_layer.h b/third_party/blink/renderer/modules/xr/xr_webgl_layer.h index 5458dab1..2a5f760 100644 --- a/third_party/blink/renderer/modules/xr/xr_webgl_layer.h +++ b/third_party/blink/renderer/modules/xr/xr_webgl_layer.h
@@ -14,6 +14,7 @@ #include "third_party/blink/renderer/modules/xr/xr_layer.h" #include "third_party/blink/renderer/modules/xr/xr_utils.h" #include "third_party/blink/renderer/modules/xr/xr_view.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_layer_client.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h" #include "third_party/blink/renderer/platform/wtf/ref_counted.h" @@ -27,7 +28,7 @@ class XRSession; class XRViewport; -class XRWebGLLayer final : public XRLayer { +class XRWebGLLayer final : public XRLayer, public XRWebGLLayerClient { DEFINE_WRAPPERTYPEINFO(); public: @@ -44,7 +45,12 @@ const XRWebGLLayerInit*, ExceptionState&); - WebGLRenderingContextBase* context() const { return webgl_context_.Get(); } + // XRWebGLLayerClient implementation + const XRLayer* layer() const override { return this; } + WebGLRenderingContextBase* context() const override { + return webgl_context_.Get(); + } + scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage() override; WebGLFramebuffer* framebuffer() const { return framebuffer_.Get(); } uint32_t framebufferWidth() const; @@ -80,8 +86,6 @@ // mailbox holder and its size respectively. void HandleBackgroundImage(const gpu::MailboxHolder&, const gfx::Size&) {} - scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage(); - void Trace(Visitor*) const override; private:
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_layer_client.h b/third_party/blink/renderer/modules/xr/xr_webgl_layer_client.h new file mode 100644 index 0000000..892e8ee9 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_webgl_layer_client.h
@@ -0,0 +1,27 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_LAYER_CLIENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_LAYER_CLIENT_H_ + +#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" +#include "third_party/blink/renderer/platform/wtf/ref_counted.h" + +namespace blink { + +class WebGLRenderingContextBase; +class XRLayer; + +// Shared interface for XRWebGLLayer and WebGL-based XRProjectionLayers to +// submit frames with. +class XRWebGLLayerClient { + public: + virtual const XRLayer* layer() const = 0; + virtual WebGLRenderingContextBase* context() const = 0; + virtual scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage() = 0; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_LAYER_CLIENT_H_
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.cc b/third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.cc new file mode 100644 index 0000000..225834a3 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.cc
@@ -0,0 +1,78 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h" + +#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_gpu_projection_layer_init.h" +#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h" +#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h" +#include "third_party/blink/renderer/modules/xr/xr_session.h" +#include "third_party/blink/renderer/modules/xr/xr_system.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_binding.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_swap_chain.h" +#include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h" + +namespace blink { + +XRWebGLProjectionLayer::XRWebGLProjectionLayer( + XRWebGLBinding* binding, + XRWebGLSwapChain* color_swap_chain, + XRWebGLSwapChain* depth_stencil_swap_chain) + : XRProjectionLayer(binding), + webgl_context_(binding->context()), + color_swap_chain_(color_swap_chain), + depth_stencil_swap_chain_(depth_stencil_swap_chain) { + CHECK(color_swap_chain_); + color_swap_chain_->SetLayer(this); + if (depth_stencil_swap_chain_) { + depth_stencil_swap_chain_->SetLayer(this); + } +} + +uint16_t XRWebGLProjectionLayer::textureWidth() const { + return color_swap_chain_->descriptor().width; +} + +uint16_t XRWebGLProjectionLayer::textureHeight() const { + return color_swap_chain_->descriptor().height; +} + +uint16_t XRWebGLProjectionLayer::textureArrayLength() const { + return color_swap_chain_->descriptor().depth; +} + +void XRWebGLProjectionLayer::OnFrameStart() { + color_swap_chain_->OnFrameStart(); + if (depth_stencil_swap_chain_) { + depth_stencil_swap_chain_->OnFrameStart(); + } +} + +void XRWebGLProjectionLayer::OnFrameEnd() { + color_swap_chain_->OnFrameEnd(); + if (depth_stencil_swap_chain_) { + depth_stencil_swap_chain_->OnFrameEnd(); + } + + XRFrameProvider* frame_provider = session()->xr()->frameProvider(); + + if (viewport_updated_) { + frame_provider->UpdateLayerViewports(this); + viewport_updated_ = false; + } + + frame_provider->SubmitWebGLLayer(this, + color_swap_chain_->texture_was_queried()); +} + +void XRWebGLProjectionLayer::OnResize() {} + +void XRWebGLProjectionLayer::Trace(Visitor* visitor) const { + visitor->Trace(webgl_context_); + visitor->Trace(color_swap_chain_); + visitor->Trace(depth_stencil_swap_chain_); + XRProjectionLayer::Trace(visitor); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h b/third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h new file mode 100644 index 0000000..238202a89 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_webgl_projection_layer.h
@@ -0,0 +1,60 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_PROJECTION_LAYER_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_PROJECTION_LAYER_H_ + +#include "third_party/blink/renderer/modules/xr/xr_projection_layer.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_layer_client.h" + +namespace blink { + +class WebGLRenderingContextBase; +class XRWebGLBinding; +class XRWebGLSwapChain; + +class XRWebGLProjectionLayer final : public XRProjectionLayer, + public XRWebGLLayerClient { + public: + XRWebGLProjectionLayer(XRWebGLBinding*, + XRWebGLSwapChain* color_swap_chain, + XRWebGLSwapChain* depth_stencil_swap_chain); + ~XRWebGLProjectionLayer() override = default; + + // XRWebGLLayerClient implementation + const XRLayer* layer() const override { return this; } + WebGLRenderingContextBase* context() const override { + return webgl_context_.Get(); + } + scoped_refptr<StaticBitmapImage> TransferToStaticBitmapImage() override { + return nullptr; + } + + uint16_t textureWidth() const override; + uint16_t textureHeight() const override; + uint16_t textureArrayLength() const override; + + void OnFrameStart() override; + void OnFrameEnd() override; + void OnResize() override; + + XRWebGLSwapChain* color_swap_chain() const { return color_swap_chain_.Get(); } + XRWebGLSwapChain* depth_stencil_swap_chain() const { + return depth_stencil_swap_chain_.Get(); + } + + void MarkViewportUpdated() { viewport_updated_ = true; } + + void Trace(Visitor*) const override; + + private: + Member<WebGLRenderingContextBase> webgl_context_; + Member<XRWebGLSwapChain> color_swap_chain_; + Member<XRWebGLSwapChain> depth_stencil_swap_chain_; + bool viewport_updated_ = true; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_PROJECTION_LAYER_H_
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_sub_image.cc b/third_party/blink/renderer/modules/xr/xr_webgl_sub_image.cc new file mode 100644 index 0000000..1262583 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_webgl_sub_image.cc
@@ -0,0 +1,45 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/xr/xr_webgl_sub_image.h" + +#include "third_party/blink/renderer/modules/webgl/webgl_unowned_texture.h" + +namespace blink { + +XRWebGLSubImage::XRWebGLSubImage(const gfx::Rect& viewport, + std::optional<uint16_t> image_index, + XRWebGLSwapChain* color_swap_chain, + XRWebGLSwapChain* depth_stencil_swap_chain, + XRWebGLSwapChain* motion_vector_swap_chain) + : XRSubImage(viewport), image_index_(image_index) { + // Must have color swap chain, depth/stencil and motion vector are optional. + CHECK(color_swap_chain); + color_texture_ = color_swap_chain->GetCurrentTexture(); + color_texture_width_ = color_swap_chain->descriptor().width; + color_texture_height_ = color_swap_chain->descriptor().height; + + if (depth_stencil_swap_chain) { + depth_stencil_texture_ = depth_stencil_swap_chain->GetCurrentTexture(); + depth_stencil_texture_width_ = depth_stencil_swap_chain->descriptor().width; + depth_stencil_texture_height_ = + depth_stencil_swap_chain->descriptor().height; + } + + if (motion_vector_swap_chain) { + motion_vector_texture_ = motion_vector_swap_chain->GetCurrentTexture(); + motion_vector_texture_width_ = motion_vector_swap_chain->descriptor().width; + motion_vector_texture_height_ = + motion_vector_swap_chain->descriptor().height; + } +} + +void XRWebGLSubImage::Trace(Visitor* visitor) const { + visitor->Trace(color_texture_); + visitor->Trace(depth_stencil_texture_); + visitor->Trace(motion_vector_texture_); + XRSubImage::Trace(visitor); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_sub_image.h b/third_party/blink/renderer/modules/xr/xr_webgl_sub_image.h index f8374195..2be308e 100644 --- a/third_party/blink/renderer/modules/xr/xr_webgl_sub_image.h +++ b/third_party/blink/renderer/modules/xr/xr_webgl_sub_image.h
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/modules/webgl/webgl_texture.h" #include "third_party/blink/renderer/modules/xr/xr_sub_image.h" +#include "third_party/blink/renderer/modules/xr/xr_webgl_swap_chain.h" namespace blink { @@ -16,7 +17,11 @@ DEFINE_WRAPPERTYPEINFO(); public: - explicit XRWebGLSubImage(const gfx::Rect& viewport) : XRSubImage(viewport) {} + XRWebGLSubImage(const gfx::Rect& viewport, + std::optional<uint16_t> image_index, + XRWebGLSwapChain* color_swap_chain, + XRWebGLSwapChain* depth_stencil_swap_chain, + XRWebGLSwapChain* motion_vector_swap_chain); WebGLTexture* colorTexture() const { return color_texture_.Get(); } WebGLTexture* depthStencilTexture() const { @@ -42,12 +47,7 @@ return motion_vector_texture_height_; } - void Trace(Visitor* visitor) const override { - visitor->Trace(color_texture_); - visitor->Trace(depth_stencil_texture_); - visitor->Trace(motion_vector_texture_); - XRSubImage::Trace(visitor); - } + void Trace(Visitor* visitor) const override; private: Member<WebGLTexture> color_texture_{nullptr};
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_swap_chain.cc b/third_party/blink/renderer/modules/xr/xr_webgl_swap_chain.cc new file mode 100644 index 0000000..de8c413 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_webgl_swap_chain.cc
@@ -0,0 +1,175 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/xr/xr_webgl_swap_chain.h" + +#include "third_party/blink/renderer/modules/webgl/webgl_framebuffer.h" +#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h" +#include "third_party/blink/renderer/modules/webgl/webgl_texture.h" +#include "third_party/blink/renderer/modules/xr/xr_layer_shared_image_manager.h" +#include "third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.h" + +namespace blink { + +XRWebGLSwapChain::XRWebGLSwapChain( + WebGLRenderingContextBase* context, + const XRWebGLSwapChain::Descriptor& descriptor, + bool webgl2) + : webgl_context_(context), descriptor_(descriptor), webgl2_(webgl2) { + CHECK(context); +} + +// Clears the contents of the current texture to transparent black or 0 (for +// depth/stencil textures). +void XRWebGLSwapChain::ClearCurrentTexture() { + WebGLUnownedTexture* texture = current_texture(); + if (!texture) { + return; + } + + gpu::gles2::GLES2Interface* gl = context()->ContextGL(); + if (!gl) { + return; + } + + if (!clear_framebuffer_) { + clear_framebuffer_ = webgl_context_->createFramebuffer(); + } + + GLenum attachment = descriptor_.attachment_target; + gl->BindFramebuffer(GL_FRAMEBUFFER, clear_framebuffer_->Object()); + gl->FramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, + texture->Object(), 0); + + GLbitfield clear_bits = 0; + if (attachment == GL_COLOR_ATTACHMENT0) { + clear_bits |= GL_COLOR_BUFFER_BIT; + gl->ColorMask(true, true, true, true); + gl->ClearColor(0, 0, 0, 0); + } else if (attachment == GL_DEPTH_ATTACHMENT) { + clear_bits |= GL_DEPTH_BUFFER_BIT; + gl->DepthMask(true); + gl->ClearDepthf(1.0f); + } else if (attachment == GL_STENCIL_ATTACHMENT) { + clear_bits |= GL_STENCIL_BUFFER_BIT; + gl->StencilMaskSeparate(GL_FRONT, true); + gl->ClearStencil(0); + } + + gl->Disable(GL_SCISSOR_TEST); + gl->Clear(clear_bits); + + // WebGLRenderingContextBase inherits from DrawingBuffer::Client, but makes + // all the methods private. Downcasting allows us to access them. + DrawingBuffer::Client* client = + static_cast<DrawingBuffer::Client*>(context()); + + client->DrawingBufferClientRestoreScissorTest(); + client->DrawingBufferClientRestoreMaskAndClearValues(); + client->DrawingBufferClientRestoreFramebufferBinding(); +} + +void XRWebGLSwapChain::Trace(Visitor* visitor) const { + visitor->Trace(webgl_context_); + visitor->Trace(clear_framebuffer_); + XRSwapChain::Trace(visitor); +} + +XRWebGLStaticSwapChain::XRWebGLStaticSwapChain( + WebGLRenderingContextBase* context, + const XRWebGLSwapChain::Descriptor& descriptor, + bool webgl2) + : XRWebGLSwapChain(context, descriptor, webgl2) {} + +XRWebGLStaticSwapChain::~XRWebGLStaticSwapChain() { + if (owned_texture_) { + gpu::gles2::GLES2Interface* gl = context()->ContextGL(); + if (!gl) { + return; + } + + gl->DeleteTextures(1, &owned_texture_); + } +} + +WebGLUnownedTexture* XRWebGLStaticSwapChain::ProduceTexture() { + gpu::gles2::GLES2Interface* gl = context()->ContextGL(); + if (!gl) { + return nullptr; + } + + gl->GenTextures(1, &owned_texture_); + gl->BindTexture(GL_TEXTURE_2D, owned_texture_); + + if (webgl2()) { + gl->TexStorage2DEXT(GL_TEXTURE_2D, 1, descriptor().internal_format, + descriptor().width, descriptor().height); + } else { + gl->TexImage2D(GL_TEXTURE_2D, 0, descriptor().format, descriptor().width, + descriptor().height, 0, descriptor().format, + descriptor().type, nullptr); + } + + // WebGLRenderingContextBase inherits from DrawingBuffer::Client, but makes + // all the methods private. Downcasting allows us to access them. + DrawingBuffer::Client* client = + static_cast<DrawingBuffer::Client*>(context()); + client->DrawingBufferClientRestoreTexture2DBinding(); + + return MakeGarbageCollected<WebGLUnownedTexture>(context(), owned_texture_, + GL_TEXTURE_2D); +} + +void XRWebGLStaticSwapChain::OnFrameEnd() { + ClearCurrentTexture(); + + // Intentionally not calling ResetCurrentTexture() here to keep the previously + // produced texture for the next frame. +} + +XRWebGLSharedImageSwapChain::XRWebGLSharedImageSwapChain( + WebGLRenderingContextBase* context, + const XRWebGLSwapChain::Descriptor& descriptor, + bool webgl2) + : XRWebGLSwapChain(context, descriptor, webgl2) {} + +WebGLUnownedTexture* XRWebGLSharedImageSwapChain::ProduceTexture() { + gpu::gles2::GLES2Interface* context_gl = context()->ContextGL(); + if (!context_gl) { + return nullptr; + } + + const XRLayerSharedImages& shared_images = layer()->GetSharedImages(); + const XRSharedImageData& content_image_data = + shared_images.content_image_data; + + CHECK(content_image_data.shared_image); + CHECK(content_image_data.sync_token.HasData()); + + // Create a texture backed by the shared image. + CHECK(!shared_image_texture_); + shared_image_texture_ = + content_image_data.shared_image->CreateGLTexture(context_gl); + shared_image_scoped_access_ = + shared_image_texture_->BeginAccess(content_image_data.sync_token, + /*readonly=*/false); + + return MakeGarbageCollected<WebGLUnownedTexture>( + context(), shared_image_texture_->id(), GL_TEXTURE_2D); +} + +void XRWebGLSharedImageSwapChain::OnFrameEnd() { + WebGLUnownedTexture* texture = ResetCurrentTexture(); + if (texture) { + DCHECK(shared_image_texture_); + gpu::SharedImageTexture::ScopedAccess::EndAccess( + std::move(shared_image_scoped_access_)); + shared_image_texture_.reset(); + + // Notify our WebGLUnownedTexture that we have deleted it. + static_cast<WebGLUnownedTexture*>(texture)->OnGLDeleteTextures(); + } +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_swap_chain.h b/third_party/blink/renderer/modules/xr/xr_webgl_swap_chain.h new file mode 100644 index 0000000..a5d4810 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_webgl_swap_chain.h
@@ -0,0 +1,90 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_SWAP_CHAIN_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_SWAP_CHAIN_H_ + +#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h" +#include "third_party/blink/renderer/modules/webgl/webgl_unowned_texture.h" +#include "third_party/blink/renderer/modules/xr/xr_swap_chain.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/member.h" + +namespace blink { + +class WebGLRenderingContextBase; +class WebGLUnownedTexture; + +class XRWebGLSwapChain : public XRSwapChain<WebGLUnownedTexture> { + public: + struct Descriptor { + GLenum format; + GLenum internal_format; + GLenum type; + GLenum attachment_target; + uint16_t width; + uint16_t height; + uint16_t depth; + }; + + XRWebGLSwapChain(WebGLRenderingContextBase*, + const XRWebGLSwapChain::Descriptor&, + bool webgl_2); + ~XRWebGLSwapChain() override = default; + + WebGLRenderingContextBase* context() { return webgl_context_.Get(); } + const XRWebGLSwapChain::Descriptor& descriptor() const { return descriptor_; } + bool webgl2() const { return webgl2_; } + + void Trace(Visitor* visitor) const override; + + protected: + void ClearCurrentTexture(); + + private: + Member<WebGLRenderingContextBase> webgl_context_; + Member<WebGLFramebuffer> clear_framebuffer_; + + XRWebGLSwapChain::Descriptor descriptor_; + bool webgl2_; +}; + +// A texture swap chain that is not communicated back to the compositor, used +// for things like depth/stencil attachments that don't assist reprojection. +class XRWebGLStaticSwapChain final : public XRWebGLSwapChain { + public: + XRWebGLStaticSwapChain(WebGLRenderingContextBase*, + const XRWebGLSwapChain::Descriptor&, + bool webgl2); + ~XRWebGLStaticSwapChain() override; + + WebGLUnownedTexture* ProduceTexture() override; + + void OnFrameEnd() override; + + private: + GLuint owned_texture_; +}; + +// A swap chain backed by SharedImages +class XRWebGLSharedImageSwapChain final : public XRWebGLSwapChain { + public: + XRWebGLSharedImageSwapChain(WebGLRenderingContextBase*, + const XRWebGLSwapChain::Descriptor&, + bool webgl2); + ~XRWebGLSharedImageSwapChain() override = default; + + WebGLUnownedTexture* ProduceTexture() override; + + void OnFrameEnd() override; + + private: + std::unique_ptr<gpu::SharedImageTexture> shared_image_texture_; + std::unique_ptr<gpu::SharedImageTexture::ScopedAccess> + shared_image_scoped_access_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_WEBGL_SWAP_CHAIN_H_
diff --git a/third_party/blink/renderer/platform/bindings/frozen_array_base.cc b/third_party/blink/renderer/platform/bindings/frozen_array_base.cc index 53271c66..c19ae71 100644 --- a/third_party/blink/renderer/platform/bindings/frozen_array_base.cc +++ b/third_party/blink/renderer/platform/bindings/frozen_array_base.cc
@@ -25,8 +25,7 @@ kDOMWrappersTag, WrapperTypeInfo::kWrapperTypeNoPrototype, WrapperTypeInfo::kNoInternalFieldClassId, - WrapperTypeInfo::kNotInheritFromActiveScriptWrappable, - WrapperTypeInfo::kCustomWrappableKind, + WrapperTypeInfo::kIdlOtherType, }; } // namespace
diff --git a/third_party/blink/renderer/platform/bindings/idl_member_installer.cc b/third_party/blink/renderer/platform/bindings/idl_member_installer.cc index 5d15cde..66c62ef 100644 --- a/third_party/blink/renderer/platform/bindings/idl_member_installer.cc +++ b/third_party/blink/renderer/platform/bindings/idl_member_installer.cc
@@ -503,31 +503,6 @@ v8::Local<v8::Template> prototype_template, v8::Local<v8::Template> interface_template, v8::Local<v8::Signature> signature, - base::span<const ConstantCallbackConfig> configs) { - const bool has_prototype_template = !prototype_template.IsEmpty(); - const v8::PropertyAttribute v8_property_attribute = - static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); - for (const auto& config : configs) { - v8::Local<v8::String> name = V8AtomicString(isolate, config.name); - if (has_prototype_template) { - prototype_template->SetLazyDataProperty( - name, config.callback, v8::Local<v8::Value>(), v8_property_attribute, - v8::SideEffectType::kHasNoSideEffect); - } - interface_template->SetLazyDataProperty( - name, config.callback, v8::Local<v8::Value>(), v8_property_attribute, - v8::SideEffectType::kHasNoSideEffect); - } -} - -// static -void IDLMemberInstaller::InstallConstants( - v8::Isolate* isolate, - const DOMWrapperWorld& world, - v8::Local<v8::Template> instance_template, - v8::Local<v8::Template> prototype_template, - v8::Local<v8::Template> interface_template, - v8::Local<v8::Signature> signature, base::span<const ConstantValueConfig> configs) { const bool has_prototype_template = !prototype_template.IsEmpty(); const v8::PropertyAttribute v8_property_attribute =
diff --git a/third_party/blink/renderer/platform/bindings/idl_member_installer.h b/third_party/blink/renderer/platform/bindings/idl_member_installer.h index b5393ea..cd9c147 100644 --- a/third_party/blink/renderer/platform/bindings/idl_member_installer.h +++ b/third_party/blink/renderer/platform/bindings/idl_member_installer.h
@@ -107,22 +107,6 @@ const char* interface_name, base::span<const NoAllocDirectCallAttributeConfig> configs); - // Web IDL constant - struct ConstantCallbackConfig { - ConstantCallbackConfig& operator=(const ConstantCallbackConfig&) = delete; - - const char* name; - v8::AccessorNameGetterCallback callback; - }; - static void InstallConstants( - v8::Isolate* isolate, - const DOMWrapperWorld& world, - v8::Local<v8::Template> instance_template, - v8::Local<v8::Template> prototype_template, - v8::Local<v8::Template> interface_template, - v8::Local<v8::Signature> signature, - base::span<const ConstantCallbackConfig> configs); - struct ConstantValueConfig { ConstantValueConfig& operator=(const ConstantValueConfig&) = delete;
diff --git a/third_party/blink/renderer/platform/bindings/observable_array.cc b/third_party/blink/renderer/platform/bindings/observable_array.cc index fd03c41a..a05b21e 100644 --- a/third_party/blink/renderer/platform/bindings/observable_array.cc +++ b/third_party/blink/renderer/platform/bindings/observable_array.cc
@@ -31,8 +31,7 @@ WrapperTypeInfo::kWrapperTypeNoPrototype, // v8::Proxy (without an internal field) is used as a (pseudo) wrapper. WrapperTypeInfo::kNoInternalFieldClassId, - WrapperTypeInfo::kNotInheritFromActiveScriptWrappable, - WrapperTypeInfo::kIdlObservableArray, + WrapperTypeInfo::kIdlOtherType, }; } // namespace
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc b/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc index 0fdfa584..b48fb94 100644 --- a/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc +++ b/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc
@@ -118,7 +118,7 @@ v8::Local<v8::Function> parent_interface_object; if (auto* parent = type->parent_class) { - if (parent->is_skipped_in_interface_object_prototype_chain) { + if (parent->is_skipped_in_interface_object_prototype_chain) [[unlikely]] { // This is a special case for WindowProperties. // We need to set up the inheritance of Window as the following: // Window.__proto__ === EventTarget
diff --git a/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc b/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc index 3a37aec3..817a9f2 100644 --- a/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc +++ b/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
@@ -32,19 +32,7 @@ case kIdlNamespace: v8_template = v8::ObjectTemplate::New(isolate); break; - case kIdlCallbackInterface: - v8_template = v8::FunctionTemplate::New( - isolate, V8ObjectConstructor::IsValidConstructorMode); - break; - case kIdlBufferSourceType: - NOTREACHED(); - case kIdlObservableArray: - v8_template = v8::FunctionTemplate::New(isolate); - break; - case kIdlAsyncOrSyncIterator: - v8_template = v8::FunctionTemplate::New(isolate); - break; - case kCustomWrappableKind: + case kIdlOtherType: v8_template = v8::FunctionTemplate::New(isolate); break; default:
diff --git a/third_party/blink/renderer/platform/bindings/wrapper_type_info.h b/third_party/blink/renderer/platform/bindings/wrapper_type_info.h index e14d065..9ca03a32 100644 --- a/third_party/blink/renderer/platform/bindings/wrapper_type_info.h +++ b/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
@@ -70,19 +70,11 @@ kCustomWrappableId, }; - enum ActiveScriptWrappableInheritance { - kNotInheritFromActiveScriptWrappable, - kInheritFromActiveScriptWrappable, - }; - enum IdlDefinitionKind { - kIdlInterface, + kIdlInterface, // includes callback interfaces kIdlNamespace, - kIdlCallbackInterface, - kIdlBufferSourceType, - kIdlObservableArray, - kIdlAsyncOrSyncIterator, - kCustomWrappableKind, + // iterators, observably arrays, buffer sources, internal script functions. + kIdlOtherType, }; static const WrapperTypeInfo* Unwrap(v8::Local<v8::Value> type_info_wrapper) { @@ -111,11 +103,7 @@ // // - kIdlInterface: v8::FunctionTemplate of interface object // - kIdlNamespace: v8::ObjectTemplate of namespace object - // - kIdlCallbackInterface: v8::FunctionTemplate of legacy callback - // interface object - // - kIdlAsyncOrSyncIterator: v8::FunctionTemplate of default (asynchronous - // or synchronous) iterator object - // - kCustomWrappableKind: v8::FunctionTemplate + // - kIdlOtherType: v8::FunctionTemplate v8::Local<v8::Template> GetV8ClassTemplate( v8::Isolate* isolate, const DOMWrapperWorld& world) const; @@ -135,11 +123,6 @@ interface_template, bindings::V8InterfaceBridgeBase::FeatureSelector()); } - bool IsActiveScriptWrappable() const { - return active_script_wrappable_inheritance == - kInheritFromActiveScriptWrappable; - } - static bool HasLegacyInternalFieldsSet(v8::Local<v8::Object> object) { for (int i = 0, n = object->InternalFieldCount(); i < n; ++i) { if (object->GetAlignedPointerFromInternalField(i)) { @@ -171,9 +154,7 @@ unsigned wrapper_type_prototype : 2; // WrapperTypePrototype unsigned wrapper_class_id : 2; // WrapperClassId - unsigned // ActiveScriptWrappableInheritance - active_script_wrappable_inheritance : 1; - unsigned idl_definition_kind : 3; // IdlDefinitionKind + unsigned idl_definition_kind : 2; // IdlDefinitionKind // This is a special case only used by V8WindowProperties::WrapperTypeInfo(). // WindowProperties is part of Window's prototype object's prototype chain,
diff --git a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc index 1e625f0b..4a5446e9 100644 --- a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc +++ b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc
@@ -184,8 +184,7 @@ // The SharedBitmapManager is null since software compositing is not supported // or used on Android. frame_sink_manager_ = std::make_unique<viz::FrameSinkManagerImpl>( - viz::FrameSinkManagerImpl::InitParams( - /*shared_bitmap_manager=*/nullptr)); + viz::FrameSinkManagerImpl::InitParams()); if (synthetic_begin_frame_source_) { client_->SetBeginFrameSource(synthetic_begin_frame_source_.get());
diff --git a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h index 4f4a6b9..a8e23a1 100644 --- a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h +++ b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h
@@ -28,7 +28,6 @@ #include "components/viz/common/surfaces/local_surface_id.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/service/display/display_client.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" @@ -161,11 +160,6 @@ // Not owned. raw_ptr<SynchronousLayerTreeFrameSinkClient> sync_client_ = nullptr; - // Used to allocate bitmaps in the software Display. - // TODO(crbug.com/692814): The Display never sends its resources out of - // process so there is no reason for it to use a SharedBitmapManager. - viz::ServerSharedBitmapManager shared_bitmap_manager_; - // Only valid (non-null) during a DemandDrawSw() call. raw_ptr<SkCanvas> current_sw_canvas_ = nullptr;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 5f90d9d..b6a6f77 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -1556,6 +1556,9 @@ crbug.com/335223786 virtual/html-anchor-attribute-disabled/external/wpt/html/semantics/popovers/popover-anchor-nested-display.tentative.html [ Failure ] crbug.com/335223786 virtual/html-anchor-attribute-disabled/external/wpt/html/semantics/popovers/popover-anchor-scroll-display.tentative.html [ Failure ] +# Interesttarget related tests +crbug.com/326681249 external/wpt/html/semantics/the-button-element/interest-target/interesttarget-svg-a-event-dispatch.tentative.html [ Failure ] + crbug.com/1107923 inspector-protocol/debugger/wasm-streaming-url.js [ Failure Pass Timeout ] crbug.com/350730710 inspector-protocol/css/css-get-position-try.js [ Failure Skip ] @@ -2729,9 +2732,10 @@ crbug.com/388319476 [ Win ] virtual/threaded/external/wpt/css/css-view-transitions/nested/compute-explicit-name-nested-vt-names.tentative.html [ Crash ] crbug.com/388319476 [ Mac13 ] virtual/threaded/external/wpt/css/css-view-transitions/new-content-captures-clip-path.html [ Crash ] crbug.com/388319476 [ Win ] virtual/threaded/external/wpt/css/css-view-transitions/new-content-captures-clip-path.html [ Crash ] -[ Mac15 ] virtual/threaded/wpt_internal/view-transition/browser-controls-root-offset-old.html [ Crash Failure ] -[ Mac12 ] virtual/threaded/wpt_internal/view-transition/browser-controls-root-offset-old.html [ Crash Failure ] -[ Win ] virtual/threaded/wpt_internal/view-transition/browser-controls-root-offset-old.html [ Crash Failure ] +crbug.com/390459301 [ Mac15 ] virtual/threaded/wpt_internal/view-transition/browser-controls-root-offset-old.html [ Crash Failure ] +crbug.com/390459301 [ Mac12 ] virtual/threaded/wpt_internal/view-transition/browser-controls-root-offset-old.html [ Crash Failure ] +crbug.com/390459301 [ Mac14 ] virtual/view-transition-wide-gamut/wpt_internal/view-transition/browser-controls-root-offset-old.html [ Crash Failure Skip ] +crbug.com/390459301 [ Win ] virtual/threaded/wpt_internal/view-transition/browser-controls-root-offset-old.html [ Crash Failure ] crbug.com/388319476 [ Mac15 ] virtual/view-transition-layered-capture/external/wpt/css/css-view-transitions/layered-capture/nested-overflow.tentative.sub.html?overflow=visible&margin=0&contain=paint&radius=0 [ Crash ] crbug.com/388319476 [ Win ] virtual/view-transition-layered-capture/external/wpt/css/css-view-transitions/layered-capture/nested-overflow.tentative.sub.html?overflow=visible&margin=0&contain=paint&radius=0 [ Crash ] [ Mac15 ] virtual/view-transition-mpa-serialization/wpt_internal/view-transition/browser-controls-root-offset-new.html [ Crash ] @@ -2763,6 +2767,7 @@ crbug.com/385918146 [ Win11 ] external/wpt/webrtc-encoded-transform/tentative/RTCEncodedVideoFrame-clone.https.html [ Timeout ] crbug.com/386713385 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-content-height-with-dynamic-change.html [ Failure ] crbug.com/385993738 [ Mac12 ] external/wpt/css/css-masking/clip-path/clip-path-inline-001.html [ Failure ] +crbug.com/386128935 [ Mac11 ] external/wpt/css/css-position/position-fixed-scroll-nested-fixed.html [ Failure ] crbug.com/386128935 [ Mac13 ] external/wpt/css/css-position/position-fixed-scroll-nested-fixed.html [ Failure ] crbug.com/386128935 [ Mac14 ] external/wpt/css/css-position/position-fixed-scroll-nested-fixed.html [ Failure ] crbug.com/385918134 [ Linux ] external/wpt/wasm/core/address.wast.js.html [ Crash ] @@ -2783,6 +2788,7 @@ crbug.com/384980894 [ Mac12 ] external/wpt/html/semantics/forms/the-select-element/customizable-select/select-mouse-behavior.tentative.html [ Timeout ] crbug.com/384980894 [ Mac13 ] external/wpt/html/semantics/forms/the-select-element/customizable-select/select-mouse-behavior.tentative.html [ Timeout ] crbug.com/384980894 [ Mac14 ] external/wpt/html/semantics/forms/the-select-element/customizable-select/select-mouse-behavior.tentative.html [ Timeout ] +crbug.com/384980894 [ Mac14-arm64 ] external/wpt/html/semantics/forms/the-select-element/customizable-select/select-mouse-behavior.tentative.html [ Timeout ] crbug.com/384980894 [ Mac15 ] external/wpt/html/semantics/forms/the-select-element/customizable-select/select-mouse-behavior.tentative.html [ Timeout ] crbug.com/384980894 [ Win11-arm64 ] external/wpt/html/semantics/forms/the-select-element/customizable-select/select-mouse-behavior.tentative.html [ Timeout ] crbug.com/384773801 [ Mac13 ] external/wpt/webrtc/RTCRtpReceiver-jitterBufferTarget.html [ Timeout ] @@ -9053,10 +9059,6 @@ # Gardener 2025-01-08 crbug.com/376320405 [ Debug Linux ] external/wpt/css/css-sizing/keyword-sizes-for-intrinsic-contributions.tentative.html [ Failure ] -# TODO(crrev.com/c/6159568): Re-enable after landing CL. -crbug.com/388589515 http/tests/devtools/profiler/heap-snapshot-summary-sorting.js [ Failure Skip ] -crbug.com/388589515 http/tests/devtools/profiler/heap-snapshot-summary-show-ranges.js [ Failure Skip ] - # Gardener 2025-01-10 crbug.com/389012014 [ Mac13 ] fast/peerconnection/RTCRtpSender-getParameters.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index fe27a8a2..733f544 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -6818,6 +6818,13 @@ {} ] ], + "remove-all-children-of-documentElement-in-designMode-when-no-body.html": [ + "28984449ea3eecc37f19ae5688d468dd15b555a7", + [ + null, + {} + ] + ], "remove-document-element-of-iframe-having-style-content.html": [ "b032311fa7552767a2356a181ce0ffb1fb9b3511", [ @@ -7831,7 +7838,7 @@ {} ] ], - "popover-hint-crash.tentative.html": [ + "popover-hint-crash.html": [ "3de269952624db643f21260ac9a2cb659f5c212c", [ null, @@ -109016,7 +109023,7 @@ ] ], "content-visibility-auto-svg-text.html": [ - "93b570999fc7c0834575bbf0f8dc71417ee23c3a", + "60aac70f55ca383f61f29b5333e8bfb6693139ae", [ null, [ @@ -171549,6 +171556,19 @@ {} ] ], + "scrollable-overflow-empty-newline-span.html": [ + "39f72d9fbff4204a09ab9bbfe88fa2ec60da408c", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], "scrollable-overflow-input-001.html": [ "1b58803079f8b60b68eb1c57a0c522962e0a8019", [ @@ -210165,6 +210185,32 @@ {} ] ], + "text-wrap-balance-before-after-001.html": [ + "9f5741e23492875670f1406e934a1306bdd51973", + [ + null, + [ + [ + "/css/css-text/white-space/reference/text-wrap-balance-before-after-001-ref.html", + "==" + ] + ], + {} + ] + ], + "text-wrap-balance-before-after-002.html": [ + "e9d08953fac0963ba2a9639ac9aabb6f3f59764b", + [ + null, + [ + [ + "/css/css-text/white-space/reference/text-wrap-balance-before-after-002-ref.html", + "==" + ] + ], + {} + ] + ], "text-wrap-balance-dynamic-001.html": [ "76b4cbbb433568b7cc25f7b1fb6e419b9a9570be", [ @@ -312768,43 +312814,171 @@ "9b01ed7dae7fa79886cef7f1c4c1b593f6a52b55", [] ], - "generate.py": [ - "505375d55fede4f613f4c37b938c4f4b9e16e3c9", - [] - ], - "generate_test.py": [ - "6f46ae913a279b23c8debe1bb2d27e558499f37c", - [] - ], - "getAvailability": { - "reject_opaque_origin.https.html.headers": [ - "c7e4e7cc5bd3fa25851c1e26c3c04eb95050d94b", + "legacy": { + "generate.py": [ + "505375d55fede4f613f4c37b938c4f4b9e16e3c9", [] - ] - }, - "getDevices": { - "reject_opaque_origin.https.html.headers": [ - "c7e4e7cc5bd3fa25851c1e26c3c04eb95050d94b", + ], + "generate_test.py": [ + "6f46ae913a279b23c8debe1bb2d27e558499f37c", [] - ] - }, - "idl": { - "idlharness.tentative.https.window-expected.txt": [ - "9840c87492ed100f65c5d31bf2f616fdc9380d44", - [] - ] - }, - "requestDevice": { - "reject_opaque_origin.https.html.headers": [ - "c7e4e7cc5bd3fa25851c1e26c3c04eb95050d94b", - [] - ] - }, - "requestLEScan": { - "reject_opaque_origin.https.html.headers": [ - "c7e4e7cc5bd3fa25851c1e26c3c04eb95050d94b", - [] - ] + ], + "getAvailability": { + "reject_opaque_origin.https.html.headers": [ + "c7e4e7cc5bd3fa25851c1e26c3c04eb95050d94b", + [] + ] + }, + "getDevices": { + "reject_opaque_origin.https.html.headers": [ + "c7e4e7cc5bd3fa25851c1e26c3c04eb95050d94b", + [] + ] + }, + "idl": { + "idlharness.tentative.https.window-expected.txt": [ + "9840c87492ed100f65c5d31bf2f616fdc9380d44", + [] + ] + }, + "requestDevice": { + "reject_opaque_origin.https.html.headers": [ + "c7e4e7cc5bd3fa25851c1e26c3c04eb95050d94b", + [] + ] + }, + "requestLEScan": { + "reject_opaque_origin.https.html.headers": [ + "c7e4e7cc5bd3fa25851c1e26c3c04eb95050d94b", + [] + ] + }, + "script-tests": { + "base_test_js.template": [ + "04c7a70ba4f3b84a38a91d1be971f0ec0d4843ff", + [] + ], + "characteristic": { + "characteristic-is-removed.js": [ + "48aaec3e93015dd656e8c3dac75860875bfcd4cd", + [] + ], + "descriptor-get-same-object.js": [ + "4e6bc3519bc176c293868ab1d92be843e31dea39", + [] + ], + "service-is-removed.js": [ + "2f5824082b1a9b5166e807e9ec9582aa4a9f3330", + [] + ] + }, + "descriptor": { + "service-is-removed.js": [ + "5373364399e9cd30eefbeb04ed3bff3b70b5d155", + [] + ] + }, + "server": { + "disconnect-called-before.js": [ + "57704ee2992689f602cf2990d863129d2dc1bb6e", + [] + ], + "disconnect-called-during-error.js": [ + "edabb07bccb977e8ef9b018c00292579525c9d22", + [] + ], + "disconnect-called-during-success.js": [ + "84157a0693b4ebd6c8e1cacf5f3ead53a4ff55d1", + [] + ], + "disconnect-discovery-timeout.js": [ + "718e290950d25e52faf5dfccc56610b8dda868a8", + [] + ], + "disconnect-invalidates-objects.js": [ + "995fda34411d1534debe9ba1502390fb5cd8a42b", + [] + ], + "disconnected-device.js": [ + "2b6011642b61c5da786a5819be38f5f14f4fe144", + [] + ], + "discovery-complete-no-permission-absent-service.js": [ + "e9e972359a73edc23da95373156f41c9902d828b", + [] + ], + "discovery-complete-service-not-found.js": [ + "6b745d7e2a8296c54e475d312045d77bac126086", + [] + ], + "garbage-collection-ran-during-error.js": [ + "cf508a928ee72fbd97816d2f2f2b66004de9423c", + [] + ], + "garbage-collection-ran-during-success.js": [ + "bb472fcca4ef2437b03bed6762131ebfefa6c2da", + [] + ], + "get-different-service-after-reconnection.js": [ + "e72128a76ff592f08ad888a538fdcecbf95c2c1a", + [] + ], + "get-same-object.js": [ + "3b3bdd19d201f56addef5fa7a50ca570ec7844ae", + [] + ], + "invalid-service-name.js": [ + "52cbb24f4a3f45c2e2718a530d8cde8e1b221cc9", + [] + ], + "no-permission-absent-service.js": [ + "200dab3e937e174170b3ec7879998d95a1369b3e", + [] + ], + "no-permission-for-any-service.js": [ + "60e3ef00806bcef4c7b49be36f062d58c13274c6", + [] + ], + "no-permission-present-service.js": [ + "3257410685ee405bad8cc4a9dad96a10434278b5", + [] + ], + "service-not-found.js": [ + "0fd2dace7871f7edf00251d53532263901ffe86b", + [] + ] + }, + "service": { + "blocklisted-characteristic.js": [ + "b26f039a70684792e0672b7993aae27fe493fc6c", + [] + ], + "characteristic-not-found.js": [ + "366e046774b6a9cbcd22071a3afa6c1d0857bd1e", + [] + ], + "garbage-collection-ran-during-error.js": [ + "7ed4aaa9622313c2479ac7ff9d6a9dd5c0cf6288", + [] + ], + "get-same-object.js": [ + "db9d740c83cd6bd0796a26338f62eaeee374a2b6", + [] + ], + "invalid-characteristic-name.js": [ + "74cba7ec4314bb4ae002470e7c4f7e591a93ab9b", + [] + ], + "reconnect-during.js": [ + "cc71547ac248e8ecdd5c79c1b3e4816f6525f794", + [] + ], + "service-is-removed.js": [ + "aaf0f14436742c04848749b5acf6d52b7bb2e98c", + [] + ] + } + } }, "resources": { "bluetooth-fake-devices.js": [ @@ -312823,132 +312997,6 @@ "f9f7a6f0d7d9cff3e2c24edba6751292a003f6de", [] ] - }, - "script-tests": { - "base_test_js.template": [ - "04c7a70ba4f3b84a38a91d1be971f0ec0d4843ff", - [] - ], - "characteristic": { - "characteristic-is-removed.js": [ - "48aaec3e93015dd656e8c3dac75860875bfcd4cd", - [] - ], - "descriptor-get-same-object.js": [ - "4e6bc3519bc176c293868ab1d92be843e31dea39", - [] - ], - "service-is-removed.js": [ - "2f5824082b1a9b5166e807e9ec9582aa4a9f3330", - [] - ] - }, - "descriptor": { - "service-is-removed.js": [ - "5373364399e9cd30eefbeb04ed3bff3b70b5d155", - [] - ] - }, - "server": { - "disconnect-called-before.js": [ - "57704ee2992689f602cf2990d863129d2dc1bb6e", - [] - ], - "disconnect-called-during-error.js": [ - "edabb07bccb977e8ef9b018c00292579525c9d22", - [] - ], - "disconnect-called-during-success.js": [ - "84157a0693b4ebd6c8e1cacf5f3ead53a4ff55d1", - [] - ], - "disconnect-discovery-timeout.js": [ - "718e290950d25e52faf5dfccc56610b8dda868a8", - [] - ], - "disconnect-invalidates-objects.js": [ - "995fda34411d1534debe9ba1502390fb5cd8a42b", - [] - ], - "disconnected-device.js": [ - "2b6011642b61c5da786a5819be38f5f14f4fe144", - [] - ], - "discovery-complete-no-permission-absent-service.js": [ - "e9e972359a73edc23da95373156f41c9902d828b", - [] - ], - "discovery-complete-service-not-found.js": [ - "6b745d7e2a8296c54e475d312045d77bac126086", - [] - ], - "garbage-collection-ran-during-error.js": [ - "cf508a928ee72fbd97816d2f2f2b66004de9423c", - [] - ], - "garbage-collection-ran-during-success.js": [ - "bb472fcca4ef2437b03bed6762131ebfefa6c2da", - [] - ], - "get-different-service-after-reconnection.js": [ - "e72128a76ff592f08ad888a538fdcecbf95c2c1a", - [] - ], - "get-same-object.js": [ - "3b3bdd19d201f56addef5fa7a50ca570ec7844ae", - [] - ], - "invalid-service-name.js": [ - "52cbb24f4a3f45c2e2718a530d8cde8e1b221cc9", - [] - ], - "no-permission-absent-service.js": [ - "200dab3e937e174170b3ec7879998d95a1369b3e", - [] - ], - "no-permission-for-any-service.js": [ - "60e3ef00806bcef4c7b49be36f062d58c13274c6", - [] - ], - "no-permission-present-service.js": [ - "3257410685ee405bad8cc4a9dad96a10434278b5", - [] - ], - "service-not-found.js": [ - "0fd2dace7871f7edf00251d53532263901ffe86b", - [] - ] - }, - "service": { - "blocklisted-characteristic.js": [ - "b26f039a70684792e0672b7993aae27fe493fc6c", - [] - ], - "characteristic-not-found.js": [ - "366e046774b6a9cbcd22071a3afa6c1d0857bd1e", - [] - ], - "garbage-collection-ran-during-error.js": [ - "7ed4aaa9622313c2479ac7ff9d6a9dd5c0cf6288", - [] - ], - "get-same-object.js": [ - "db9d740c83cd6bd0796a26338f62eaeee374a2b6", - [] - ], - "invalid-characteristic-name.js": [ - "74cba7ec4314bb4ae002470e7c4f7e591a93ab9b", - [] - ], - "reconnect-during.js": [ - "cc71547ac248e8ecdd5c79c1b3e4816f6525f794", - [] - ], - "service-is-removed.js": [ - "aaf0f14436742c04848749b5acf6d52b7bb2e98c", - [] - ] - } } }, "browsing-topics": { @@ -313035,6 +313083,10 @@ [] ], "support": { + "clear-site-data-cache.py": [ + "87107693b46edbd52a4bbc6a100ab1a62e9fc19c", + [] + ], "clear-site-data-cookie.py": [ "eb50cb54ef867844ea741fe1fdb01df970e4deea", [] @@ -313689,7 +313741,7 @@ [] ], "OWNERS": [ - "0da9e4cde6027cfd7f1d3fa6e60ac64937e6c846", + "09f04d1a1f02f18aeffcb57a2bca454e51da0fbb", [] ], "WEB_FEATURES.yml": [ @@ -328813,7 +328865,11 @@ [] ], "at-container-parsing-expected.txt": [ - "b85a3d39580ad774b01d5d487e94dbd84dc85327", + "bcf11af075d1e05ae57cea5f7d77df7b77a4cb07", + [] + ], + "at-container-serialization-expected.txt": [ + "12a5c81a28963b953141106a99c0b9bf93b213cc", [] ], "change-display-in-container-ref.html": [ @@ -328924,7 +328980,7 @@ ], "support": { "cq-testcommon.js": [ - "357657870e6c488db9130831e323706a05166300", + "8d1e03f2073fd2073bdbd0270ec9aa112030e55d", [] ], "test.vtt": [ @@ -346008,12 +346064,8 @@ "758ef35275eeacc96b6e584f672f86c4b170e0e1", [] ], - "clip-path-interpolation-shape-control-points.tentative-expected.txt": [ - "ce0d856f8d4c798f997a59ff9da72941e1a7bf9c", - [] - ], "clip-path-interpolation-shape-expected.txt": [ - "4fb9216a99530e54216ec12996863f3a76b3d520", + "03fe0ea48d1ca056a9d5a52b177ca4b4f6bbabf1", [] ], "mask-border-outset-composition-expected.txt": [ @@ -358267,6 +358319,14 @@ "e522e3711c9d1a68f6a90d97cba248ecb4e47d32", [] ], + "text-wrap-balance-before-after-001-ref.html": [ + "9bf7820c6ab2799a292764c4e209a71e8b299cb5", + [] + ], + "text-wrap-balance-before-after-002-ref.html": [ + "6fbfe89c7d3173a89a1061d83ad578336478a3d2", + [] + ], "text-wrap-balance-dynamic-001-ref.html": [ "43202e4d97f03c1694176f5c6a95b4a48e938a96", [] @@ -379797,7 +379857,7 @@ [] ], "OWNERS": [ - "49d68bb82b1ca6e4654bf0e8daeda2f8c7fe51df", + "92a7265767d3e13f6c5f3dd628ff2f042858719c", [] ], "README.md": [ @@ -380960,7 +381020,7 @@ [] ], "FileSystemDirectoryHandle-removeEntry.js": [ - "4193839e2c1df72db9218af0e6fb85bb118b5900", + "f059ec313f916425cd744e7268b7690ceac0f9c4", [] ], "FileSystemDirectoryHandle-resolve.js": [ @@ -385862,32 +385922,6 @@ [] ] }, - "fill-and-stroke-styles": { - "2d.gradient.interpolate.alpha.png": [ - "af5ac0f07d64e7598e0ea6a8e37cff2a5c4ea2a0", - [] - ], - "2d.gradient.interpolate.color.png": [ - "af5ac0f07d64e7598e0ea6a8e37cff2a5c4ea2a0", - [] - ], - "2d.gradient.interpolate.coloralpha.png": [ - "552e6ee44b1a3bed7d474e198e7cf1ed3a1be5cb", - [] - ], - "2d.gradient.interpolate.multiple.png": [ - "86122450d3a35ef2db3c2917dfdb919fdfb9c4ec", - [] - ], - "2d.gradient.interpolate.overlap.png": [ - "5c2bb964e0fd379309797343aa869c195f2f742a", - [] - ], - "2d.gradient.interpolate.vertical.png": [ - "37d6a00c6279daf43fa436d201799b8c2e527cb7", - [] - ] - }, "filters": { "2d.filter.canvasFilterObject.componentTransfer.discrete.tentative-expected.html": [ "8b81b134aeab6d4457853556563ce927ccefea5f", @@ -386209,14 +386243,6 @@ } }, "path-objects": { - "2d.path.fill.overlap.png": [ - "e2a35d48d4c4363294aec671a38cbd4b39c9a53c", - [] - ], - "2d.path.stroke.overlap.png": [ - "e2a35d48d4c4363294aec671a38cbd4b39c9a53c", - [] - ], "2d.path.stroke.prune.arc-expected.txt": [ "5a66b29c4a3019444e0b629b47713efb6ce1572d", [] @@ -386230,12 +386256,6 @@ [] ] }, - "pixel-manipulation": { - "2d.imageData.put.alpha.png": [ - "5428c65524eebf083e2772bd66b496eeb1c1745e", - [] - ] - }, "reset": { "2d.reset.after-rasterization-expected.html": [ "3162e16e63d9fa5cc495401ca53d6c0242d3ee65", @@ -386274,65 +386294,7 @@ [] ] }, - "shadows": { - "2d.shadow.alpha.2.png": [ - "8764e89b371d41428f0ba45d9c0391e41b0dd8a2", - [] - ], - "2d.shadow.alpha.3.png": [ - "8764e89b371d41428f0ba45d9c0391e41b0dd8a2", - [] - ], - "2d.shadow.alpha.4.png": [ - "8764e89b371d41428f0ba45d9c0391e41b0dd8a2", - [] - ], - "2d.shadow.alpha.5.png": [ - "8764e89b371d41428f0ba45d9c0391e41b0dd8a2", - [] - ], - "2d.shadow.blur.high.png": [ - "743640b79f8810c193ae9ad86fdfaa76ee5f4943", - [] - ], - "2d.shadow.blur.low.png": [ - "99fb651c21bca0fe563843d987bdf0f0ff9a6db6", - [] - ], - "2d.shadow.canvas.alpha.png": [ - "8764e89b371d41428f0ba45d9c0391e41b0dd8a2", - [] - ], - "2d.shadow.gradient.alpha.png": [ - "8764e89b371d41428f0ba45d9c0391e41b0dd8a2", - [] - ], - "2d.shadow.image.alpha.png": [ - "8764e89b371d41428f0ba45d9c0391e41b0dd8a2", - [] - ], - "2d.shadow.pattern.alpha.png": [ - "8764e89b371d41428f0ba45d9c0391e41b0dd8a2", - [] - ] - }, "text": { - "2d.text.draw.fill.basic.png": [ - "70d7b046cb226cfcb2bfeebe3477d3b580d8270a", - [] - ], - "2d.text.draw.fill.maxWidth.large.png": [ - "70d7b046cb226cfcb2bfeebe3477d3b580d8270a", - [] - ], - "2d.text.draw.fill.rtl.png": [ - "70d7b046cb226cfcb2bfeebe3477d3b580d8270a", - [] - ], - "2d.text.draw.stroke.basic.png": [ - "fb3b5b830d345d2aa858e41673e08f99977baf08", - [] - ], "2d.text.drawing.style.reset.fontKerning.none2-expected.html": [ "ce5874653d76b29c22d6b237f88cb4afe6000ef5", [] @@ -386455,7 +386417,7 @@ [] ], "gentestutilsunion.py": [ - "c0e09736934a40d7003a164fe558799532f77368", + "dbd729c82447fa9c9dfed522a35667b1aa19fc16", [] ], "name2dir-canvas.yaml": [ @@ -387529,6 +387491,10 @@ "bcc6f0734d580474a8bd25f25d4662f175cdc39b", [] ], + "reporting-subresource-corp.tentative.https.html.headers": [ + "bcc6f0734d580474a8bd25f25d4662f175cdc39b", + [] + ], "resources": { "common.js": [ "df4bfcfc7d52ac006f84f4ca046cc64b4dd7a171", @@ -387554,6 +387520,14 @@ "34b4e9f8ea41fd1aed28b86715df31c1692b88aa", [] ], + "reporting-empty-frame-multiple-headers.html.asis": [ + "5020ad39fee282b2755f020133f09a6c5058ec1f", + [] + ], + "reporting-empty-frame.html": [ + "b1579add2e033e9dfc6c8bb18f9e523b246326ac", + [] + ], "shared-worker-fetch.js.py": [ "bf46cd291d4b955c35082e8f611b772d70267253", [] @@ -395912,11 +395886,11 @@ [] ], "popover-top-layer-nesting.js": [ - "ace10b3f7bc47f32c04ad1435e1d2eb28f3ec3a0", + "affb08ca726c2ed6602385150a025afe0bd3df9f", [] ], "popover-utils.js": [ - "96ac7e03f0e7fc6bdd3c44ef400b243dba8b735d", + "eb5dab38245d5a85eb80bbaaf1dce7e5ccbb7728", [] ] } @@ -401420,8 +401394,12 @@ "a5db8f3c494d61f1c1ae9829debb647e5e8b1e02", [] ], + "css-fonts-5.idl": [ + "06461b0366ca75fc860ab0523c87d5dfb17e5246", + [] + ], "css-fonts.idl": [ - "d5c9dc86705efe3ad28e2ba7904207d021b5e4c7", + "9b8034bc6d7a3f2e42a9ad778c240ab75de62f6f", [] ], "css-highlight-api.idl": [ @@ -401441,7 +401419,7 @@ [] ], "css-mixins.idl": [ - "49806ab54709b29efbad52ca1e1af4d53e00e733", + "6629b3861f6a3fc02885081f02abbd548f00a3d2", [] ], "css-nav.idl": [ @@ -401533,7 +401511,7 @@ [] ], "digital-credentials.idl": [ - "e20079efa14f9a894181d1cafb66129a1634c627", + "e4ebb3b3e8621b668a18dcdeed7974e6446234e0", [] ], "digital-goods.idl": [ @@ -401581,7 +401559,7 @@ [] ], "fedcm.idl": [ - "16b5b2faf10529c9633efe5f2c44431b1fe00229", + "07f7955ff648b882ae44c319ff5b8414b877d2fb", [] ], "fenced-frame.idl": [ @@ -401665,7 +401643,7 @@ [] ], "html.idl": [ - "d4f8b9a7680cb7a5ee124e85a1ea6d7df1100cd7", + "3832a6f9b7187a0b6e5bb0b08717f09579ff7c69", [] ], "idle-detection.idl": [ @@ -401793,7 +401771,7 @@ [] ], "mediacapture-surface-control.idl": [ - "b0bbd22304fd7add21b5910a3377a5100ecb02ec", + "964f662da7fa0a488dd776e5e485a9c731607083", [] ], "mediacapture-transform.idl": [ @@ -401885,7 +401863,7 @@ [] ], "permissions-policy.idl": [ - "5878d8d150a6db19f9f060fe5c60c420eb8ed12b", + "806d2eb80f6562300ad4cc664d13a968995e0012", [] ], "permissions-request.idl": [ @@ -402049,7 +402027,7 @@ [] ], "shared-storage.idl": [ - "b6863eff8eecf597a85183683ea444e93c241858", + "6f38d673952f781dd99b6c6f39475c7f8aa39523", [] ], "speech-api.idl": [ @@ -402257,7 +402235,7 @@ [] ], "webnn.idl": [ - "132280b05f8d3fa6074955a1be2cb8e40706d500", + "3e1d9a9f440fd66f413ea628c6d2395fd7d2e8d2", [] ], "webrtc-encoded-transform.idl": [ @@ -402780,7 +402758,7 @@ ] }, "lint.ignore": [ - "6ee7bfa9b70249e010f02c42b7d68f5ace40b39e", + "27728b07fc2af6687ef827e2ba52a0c976db6847", [] ], "loading": { @@ -407137,7 +407115,7 @@ [] ], "unload-helper.js": [ - "9739ead69d6d5864ef1753cdaec888a9cae87905", + "d1bf0105ce5d6fb8f1afe02a3cea8ac4ab2bbfce", [] ], "vertical-scroll-scrollable-content.html": [ @@ -407179,7 +407157,7 @@ ] }, "idlharness.window-expected.txt": [ - "f9013562402a9b732c243e18fc890b3ac5103a08", + "a49f0943676d1429d1309127703f90a97831ba20", [] ], "payment-allowed-by-permissions-policy.https.sub.html.headers": [ @@ -410387,6 +410365,14 @@ "02c275f37b66e8a0b434c6fa57b347994d523118", [] ], + "compressed-data.py": [ + "8445f762d50c7a80b1ae55b7a960080d4db31eab", + [] + ], + "compressed-js.py": [ + "20207577b975209013ffd767798f4dea79594766", + [] + ], "connection-reuse-test.js": [ "453fbd34051067480139058d40541368bce2207c", [] @@ -410439,6 +410425,10 @@ "167386d7a52d7cb3472a82c894b5868b53f3d049", [] ], + "dummy.js": [ + "cb7fc3481600bd01945267b7f79dd4b6b7244c6c", + [] + ], "embed-navigate-back.html": [ "c9c7340f5307dacfafd67e6f749f56abe2430c87", [] @@ -410491,6 +410481,30 @@ "2ee92b2a5511c0d43359e0db7ee3b64ae5f9115c", [] ], + "foo.text.br": [ + "30cb2f7095e15aca510a4a8cbae00f5d35f0918b", + [] + ], + "foo.text.br.headers": [ + "8c03b823e09e9135244d15c9e82697c30f8da33a", + [] + ], + "foo.text.gz": [ + "05a5cce07b514365d9c468f4a1763b8173cfecfc", + [] + ], + "foo.text.gz.headers": [ + "7def3ddc148d1c2457240a9741ed4a2b8b3a5927", + [] + ], + "foo.text.zst": [ + "a73bbdd22458db57635bf88e97a4e47b4886e722", + [] + ], + "foo.text.zst.headers": [ + "c5974e126a34d876cf69fe69573682ac97f0b977", + [] + ], "frame-timing.js": [ "019bd424b55065451eb4ad0a132d3a6befbbb5fc", [] @@ -410516,7 +410530,7 @@ [] ], "gzip_xml.py": [ - "7debc9ce3f6cb061be8ca37b73fcf9f2a5396389", + "b5a0f72d3d4569ffaff833aebb5a2aa376dc063e", [] ], "header-delay.h2.py": [ @@ -419454,7 +419468,7 @@ [] ], "urlpatterntestdata.json": [ - "058079bb6d17ace15e7cf6505dc966ea2de0ee45", + "1d2ba25ff7d696ab9fafb71164e76d661d50fd17", [] ], "urlpatterntests.js": [ @@ -424304,7 +424318,7 @@ [] ], "utils_validation.js": [ - "0f07b777def10fcebba8cd0282dea463e0c1b37e", + "4ee0a9fd25701881920273238642b89664080e49", [] ] }, @@ -450803,526 +450817,12 @@ ] }, "bluetooth": { - "adapter": { - "adapter-absent-getAvailability.https.window.js": [ - "55f4a675da158ac8cd116ea4346c39ff11195f21", - [ - "bluetooth/adapter/adapter-absent-getAvailability.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "adapter-added-getAvailability.https.window.js": [ - "f8e25b2ac2fc48b865ce7f9e3702a7688f89dbc3", - [ - "bluetooth/adapter/adapter-added-getAvailability.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "adapter-powered-off-getAvailability.https.window.js": [ - "1ffcd3bb096cebd80c34d5c57cadc8c00a128d2a", - [ - "bluetooth/adapter/adapter-powered-off-getAvailability.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "adapter-powered-on-getAvailability.https.window.js": [ - "84c7982d2146b8660d098e21c1c30496a189549a", - [ - "bluetooth/adapter/adapter-powered-on-getAvailability.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "adapter-powered-on-off-on-getAvailability.https.window.js": [ - "c4ba9b5f3a9b13eaba51a3d29cfa62405816753e", - [ - "bluetooth/adapter/adapter-powered-on-off-on-getAvailability.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "adapter-removed-getAvailability.https.window.js": [ - "ca0b51f47dc6807b79a861d85ea5a7f2549e691a", - [ - "bluetooth/adapter/adapter-removed-getAvailability.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "cross-origin-iframe-getAvailability.sub.https.window.js": [ - "54abfbb5cefcb364be4c01f34e40a62ca49156d7", - [ - "bluetooth/adapter/cross-origin-iframe-getAvailability.sub.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "characteristic": { - "characteristicProperties.https.window.js": [ - "f7a57a9c4b8922249976d4f980c3e07555b05969", - [ - "bluetooth/characteristic/characteristicProperties.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "getDescriptor": { - "detachedIframe.https.window.js": [ - "de7d0b0b7ce79ffc4391a1aa476b88beb8be2c27", + "legacy": { + "adapter": { + "adapter-absent-getAvailability.https.window.js": [ + "55f4a675da158ac8cd116ea4346c39ff11195f21", [ - "bluetooth/characteristic/getDescriptor/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-characteristic-is-removed.https.window.js": [ - "9e48a7caabc29a610f72fef370cc4ee6571220ea", - [ - "bluetooth/characteristic/getDescriptor/gen-characteristic-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-descriptor-get-same-object.https.window.js": [ - "708f67da6a8c38738c6ddb2d1990b6440426627f", - [ - "bluetooth/characteristic/getDescriptor/gen-descriptor-get-same-object.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-service-is-removed.https.window.js": [ - "c256050b0fc4dfe84ad174d1e62c54a0dfa49686", - [ - "bluetooth/characteristic/getDescriptor/gen-service-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "getDescriptors": { - "detachedIframe.https.window.js": [ - "45dd23752f2fd836b751c4700f910ddb1de26e2c", - [ - "bluetooth/characteristic/getDescriptors/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-characteristic-is-removed-with-uuid.https.window.js": [ - "a0424c01106ac6f9ab921b0cbea3c2b960c8f938", - [ - "bluetooth/characteristic/getDescriptors/gen-characteristic-is-removed-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-characteristic-is-removed.https.window.js": [ - "29325c3bb527996a7bbb8b7bdaff17f7dc39e256", - [ - "bluetooth/characteristic/getDescriptors/gen-characteristic-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-descriptor-get-same-object.https.window.js": [ - "7f1001f3eee795307dfac2899f4dac78e2f2de23", - [ - "bluetooth/characteristic/getDescriptors/gen-descriptor-get-same-object.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-service-is-removed-with-uuid.https.window.js": [ - "b7c4bff32d91b46e2f70c3181d617c8aac5d5480", - [ - "bluetooth/characteristic/getDescriptors/gen-service-is-removed-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-service-is-removed.https.window.js": [ - "22dc30f6d825736f0ed6a48e2e794fcb0bca4258", - [ - "bluetooth/characteristic/getDescriptors/gen-service-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "notifications": { - "characteristic-is-removed.https.window.js": [ - "9641ad71e970aeb8b4b53b6b7f1415cc28e889e6", - [ - "bluetooth/characteristic/notifications/characteristic-is-removed.https.window.html", + "bluetooth/legacy/adapter/adapter-absent-getAvailability.https.window.html", { "script_metadata": [ [ @@ -451345,10 +450845,140 @@ } ] ], - "service-is-removed.https.window.js": [ - "a5851fc473323741f9f2a3a6f793287e4b2cd1ab", + "adapter-added-getAvailability.https.window.js": [ + "f8e25b2ac2fc48b865ce7f9e3702a7688f89dbc3", [ - "bluetooth/characteristic/notifications/service-is-removed.https.window.html", + "bluetooth/legacy/adapter/adapter-added-getAvailability.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "adapter-powered-off-getAvailability.https.window.js": [ + "1ffcd3bb096cebd80c34d5c57cadc8c00a128d2a", + [ + "bluetooth/legacy/adapter/adapter-powered-off-getAvailability.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "adapter-powered-on-getAvailability.https.window.js": [ + "84c7982d2146b8660d098e21c1c30496a189549a", + [ + "bluetooth/legacy/adapter/adapter-powered-on-getAvailability.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "adapter-powered-on-off-on-getAvailability.https.window.js": [ + "c4ba9b5f3a9b13eaba51a3d29cfa62405816753e", + [ + "bluetooth/legacy/adapter/adapter-powered-on-off-on-getAvailability.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "adapter-removed-getAvailability.https.window.js": [ + "ca0b51f47dc6807b79a861d85ea5a7f2549e691a", + [ + "bluetooth/legacy/adapter/adapter-removed-getAvailability.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "cross-origin-iframe-getAvailability.sub.https.window.js": [ + "54abfbb5cefcb364be4c01f34e40a62ca49156d7", + [ + "bluetooth/legacy/adapter/cross-origin-iframe-getAvailability.sub.https.window.html", { "script_metadata": [ [ @@ -451372,11 +451002,11 @@ ] ] }, - "readValue": { - "add-multiple-event-listeners.https.window.js": [ - "0eeafd0b79ba30fe7325c48727c13c3cf4fc3fab", + "characteristic": { + "characteristicProperties.https.window.js": [ + "f7a57a9c4b8922249976d4f980c3e07555b05969", [ - "bluetooth/characteristic/readValue/add-multiple-event-listeners.https.window.html", + "bluetooth/legacy/characteristic/characteristicProperties.https.window.html", { "script_metadata": [ [ @@ -451399,10 +451029,591 @@ } ] ], - "characteristic-is-removed.https.window.js": [ - "76dc206fb9301915df4cefdc1238b0e486820d92", + "getDescriptor": { + "detachedIframe.https.window.js": [ + "de7d0b0b7ce79ffc4391a1aa476b88beb8be2c27", + [ + "bluetooth/legacy/characteristic/getDescriptor/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-characteristic-is-removed.https.window.js": [ + "9e48a7caabc29a610f72fef370cc4ee6571220ea", + [ + "bluetooth/legacy/characteristic/getDescriptor/gen-characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-descriptor-get-same-object.https.window.js": [ + "708f67da6a8c38738c6ddb2d1990b6440426627f", + [ + "bluetooth/legacy/characteristic/getDescriptor/gen-descriptor-get-same-object.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-service-is-removed.https.window.js": [ + "c256050b0fc4dfe84ad174d1e62c54a0dfa49686", + [ + "bluetooth/legacy/characteristic/getDescriptor/gen-service-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "getDescriptors": { + "detachedIframe.https.window.js": [ + "45dd23752f2fd836b751c4700f910ddb1de26e2c", + [ + "bluetooth/legacy/characteristic/getDescriptors/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-characteristic-is-removed-with-uuid.https.window.js": [ + "a0424c01106ac6f9ab921b0cbea3c2b960c8f938", + [ + "bluetooth/legacy/characteristic/getDescriptors/gen-characteristic-is-removed-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-characteristic-is-removed.https.window.js": [ + "29325c3bb527996a7bbb8b7bdaff17f7dc39e256", + [ + "bluetooth/legacy/characteristic/getDescriptors/gen-characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-descriptor-get-same-object.https.window.js": [ + "7f1001f3eee795307dfac2899f4dac78e2f2de23", + [ + "bluetooth/legacy/characteristic/getDescriptors/gen-descriptor-get-same-object.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-service-is-removed-with-uuid.https.window.js": [ + "b7c4bff32d91b46e2f70c3181d617c8aac5d5480", + [ + "bluetooth/legacy/characteristic/getDescriptors/gen-service-is-removed-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-service-is-removed.https.window.js": [ + "22dc30f6d825736f0ed6a48e2e794fcb0bca4258", + [ + "bluetooth/legacy/characteristic/getDescriptors/gen-service-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "notifications": { + "characteristic-is-removed.https.window.js": [ + "9641ad71e970aeb8b4b53b6b7f1415cc28e889e6", + [ + "bluetooth/legacy/characteristic/notifications/characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "service-is-removed.https.window.js": [ + "a5851fc473323741f9f2a3a6f793287e4b2cd1ab", + [ + "bluetooth/legacy/characteristic/notifications/service-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "readValue": { + "add-multiple-event-listeners.https.window.js": [ + "0eeafd0b79ba30fe7325c48727c13c3cf4fc3fab", + [ + "bluetooth/legacy/characteristic/readValue/add-multiple-event-listeners.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "characteristic-is-removed.https.window.js": [ + "76dc206fb9301915df4cefdc1238b0e486820d92", + [ + "bluetooth/legacy/characteristic/readValue/characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "detachedIframe.https.window.js": [ + "6e2510b58d6af5117144fb21b2e7049ad9120d02", + [ + "bluetooth/legacy/characteristic/readValue/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "event-is-fired.https.window.js": [ + "52b70e7a080e870c27bf86d9ba591292f0b273bb", + [ + "bluetooth/legacy/characteristic/readValue/event-is-fired.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-characteristic-is-removed.https.window.js": [ + "5bee6db1076bdbc57462ab9298c50c2542a0f702", + [ + "bluetooth/legacy/characteristic/readValue/gen-characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "read-succeeds.https.window.js": [ + "e5ddfb81696c009743622929d3c490a6469e4c4b", + [ + "bluetooth/legacy/characteristic/readValue/read-succeeds.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "read-updates-value.https.window.js": [ + "bb98aeb18f2dcd068735d8d492dc604ead3970e4", + [ + "bluetooth/legacy/characteristic/readValue/read-updates-value.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "service-is-removed.https.window.js": [ + "1f699ca25eebcd35e0dc76be4be735d7dfd801b6", + [ + "bluetooth/legacy/characteristic/readValue/service-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "service-same-from-2-characteristics.https.window.js": [ + "dafd755fd1d49b48bcd0a2623a07a5f6855a8164", [ - "bluetooth/characteristic/readValue/characteristic-is-removed.https.window.html", + "bluetooth/legacy/characteristic/service-same-from-2-characteristics.https.window.html", { "script_metadata": [ [ @@ -451420,6 +451631,1522 @@ [ "script", "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "service-same-object.https.window.js": [ + "01b3a25e35e4a8c2e8a1626e12de90e625dda0a8", + [ + "bluetooth/legacy/characteristic/service-same-object.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "startNotifications": { + "detachedIframe.https.window.js": [ + "f09c52d32822e1dc412e158c18e9cafa0a931e29", + [ + "bluetooth/legacy/characteristic/startNotifications/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-characteristic-is-removed.https.window.js": [ + "c2a23d7f44191fc3a64a397aac447801f3c6ce47", + [ + "bluetooth/legacy/characteristic/startNotifications/gen-characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "stopNotifications": { + "detachedIframe.https.window.js": [ + "a459a5b15d9fa7f87b27fda23f8edaa547584e71", + [ + "bluetooth/legacy/characteristic/stopNotifications/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "writeValue": { + "buffer-is-detached.https.window.js": [ + "43c50d763a0973a498d861fcb80a2efc24f92daa", + [ + "bluetooth/legacy/characteristic/writeValue/buffer-is-detached.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "characteristic-is-removed.https.window.js": [ + "6e9da8802c7adf343d0dd9683c2b03afe11d28e2", + [ + "bluetooth/legacy/characteristic/writeValue/characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "detachedIframe.https.window.js": [ + "eb243a3508c3de75d29f3df91060040da231e1a6", + [ + "bluetooth/legacy/characteristic/writeValue/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-characteristic-is-removed.https.window.js": [ + "5750cb82c7f848dba7fd4f3783f6a340636a3661", + [ + "bluetooth/legacy/characteristic/writeValue/gen-characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "service-is-removed.https.window.js": [ + "89c3112475012de82ca637ec09fbd372f76516fc", + [ + "bluetooth/legacy/characteristic/writeValue/service-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "write-succeeds.https.window.js": [ + "b57fe941d0a88091b08f1f573c7af06c88dc85a6", + [ + "bluetooth/legacy/characteristic/writeValue/write-succeeds.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "writeValueWithResponse": { + "buffer-is-detached.https.window.js": [ + "5fb4aa23553986791279430b44f8bb50efa5abcd", + [ + "bluetooth/legacy/characteristic/writeValueWithResponse/buffer-is-detached.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "characteristic-is-removed.https.window.js": [ + "9309cd5a3cd325e5df4d9b38260a2fcd4b47ea2b", + [ + "bluetooth/legacy/characteristic/writeValueWithResponse/characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-characteristic-is-removed.https.window.js": [ + "e202376da7c64fa3a906e6f169a76e61d1e6a916", + [ + "bluetooth/legacy/characteristic/writeValueWithResponse/gen-characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "service-is-removed.https.window.js": [ + "81b2dff44e34080b4088f7a6fd5ed9f58feb6eff", + [ + "bluetooth/legacy/characteristic/writeValueWithResponse/service-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "write-succeeds.https.window.js": [ + "c87e7ac6aba26b31319becd030d34657506ba57d", + [ + "bluetooth/legacy/characteristic/writeValueWithResponse/write-succeeds.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "writeValueWithoutResponse": { + "buffer-is-detached.https.window.js": [ + "23721380cbdb69c84dce985b26ba92a79f6c4f3e", + [ + "bluetooth/legacy/characteristic/writeValueWithoutResponse/buffer-is-detached.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "characteristic-is-removed.https.window.js": [ + "8d3ed1f663369bfb11448a3739d3773f55b53c61", + [ + "bluetooth/legacy/characteristic/writeValueWithoutResponse/characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-characteristic-is-removed.https.window.js": [ + "b88246aae834f0ea54e72ec9a292c6b93eafb3cc", + [ + "bluetooth/legacy/characteristic/writeValueWithoutResponse/gen-characteristic-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "service-is-removed.https.window.js": [ + "feb711c64ea6b46d3401d3888de8d757c9a567b2", + [ + "bluetooth/legacy/characteristic/writeValueWithoutResponse/service-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "write-succeeds.https.window.js": [ + "0dcf8ad0b196adde1941e0c4e31b36ba08741384", + [ + "bluetooth/legacy/characteristic/writeValueWithoutResponse/write-succeeds.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + } + }, + "descriptor": { + "readValue": { + "detachedIframe.https.window.js": [ + "47765a13159b7facc753e7951b94377abc8b54b9", + [ + "bluetooth/legacy/descriptor/readValue/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-service-is-removed.https.window.js": [ + "d6c73ba60e6a1e5d8d10c80796729baf039ee702", + [ + "bluetooth/legacy/descriptor/readValue/gen-service-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "read-succeeds.https.window.js": [ + "d81db2f8c0ddb54042a6178677df309a7c6248ef", + [ + "bluetooth/legacy/descriptor/readValue/read-succeeds.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "writeValue": { + "buffer-is-detached.https.window.js": [ + "454b23ea4c2c44e4f011b77520c69dac5d469fb2", + [ + "bluetooth/legacy/descriptor/writeValue/buffer-is-detached.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "detachedIframe.https.window.js": [ + "aa143ca8e53e993273a6887b67566ff3265992d4", + [ + "bluetooth/legacy/descriptor/writeValue/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-service-is-removed.https.window.js": [ + "c7f6d6efe3e3a19f5c954a3ca83aa87f0386c98c", + [ + "bluetooth/legacy/descriptor/writeValue/gen-service-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + } + }, + "device": { + "forget": { + "connect-after-forget.https.window.js": [ + "0b15b4d060d9ae8e4795b2a4fbb684db53218f69", + [ + "bluetooth/legacy/device/forget/connect-after-forget.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "detachedIframe.https.window.js": [ + "f4803542fbb30c2aff401fd0951271e5e39bc999", + [ + "bluetooth/legacy/device/forget/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "getDevices.https.window.js": [ + "0594a6f03bf377ea19c5856298c03ed136973656", + [ + "bluetooth/legacy/device/forget/getDevices.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "gattserverdisconnected-event": { + "disconnected.https.window.js": [ + "43a11a88cbf655ee4aab6ac70215ae3fb5f9a541", + [ + "bluetooth/legacy/device/gattserverdisconnected-event/disconnected.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "disconnected_gc.https.window.js": [ + "0cf4973e2167766ece047cbcac8034d089482acc", + [ + "bluetooth/legacy/device/gattserverdisconnected-event/disconnected_gc.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "one-event-per-disconnection.https.window.js": [ + "ab273adbc88bcd4d03c9bf5309a34cb30cf3246a", + [ + "bluetooth/legacy/device/gattserverdisconnected-event/one-event-per-disconnection.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "reconnect-during-disconnected-event.https.window.js": [ + "bdaf47c66198ce70f9a1951358f27b38dcfac4ca", + [ + "bluetooth/legacy/device/gattserverdisconnected-event/reconnect-during-disconnected-event.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "watchAdvertisements": { + "abort-before-watchAdvertisements.https.window.js": [ + "e1ac1fb136902244055e88f859d9d536bc58951c", + [ + "bluetooth/legacy/device/watchAdvertisements/abort-before-watchAdvertisements.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "abort-pending-operation.https.window.js": [ + "c1022ff4a9c1b8c57703a8ce5b8bdfa309b7d985", + [ + "bluetooth/legacy/device/watchAdvertisements/abort-pending-operation.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "abort-signal-stops-events.https.window.js": [ + "21b6883fee433a2a04c689ae82c9a8a30aed5c91", + [ + "bluetooth/legacy/device/watchAdvertisements/abort-signal-stops-events.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "abort-subsequent-watchAdvertisements-call-stops-events.https.window.js": [ + "a5da75012bab1991a762c48f9a76f32906f2db11", + [ + "bluetooth/legacy/device/watchAdvertisements/abort-subsequent-watchAdvertisements-call-stops-events.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "advertisementreceived-event-fired.https.window.js": [ + "fff18bc47eed8434e3b4ff46cd157b5a5e41ea1a", + [ + "bluetooth/legacy/device/watchAdvertisements/advertisementreceived-event-fired.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "blocklisted-manufacturer-data-filtered-from-event.https.window.js": [ + "c73e3dbad1b20dd26a02d6ca4326a53b3f668a92", + [ + "bluetooth/legacy/device/watchAdvertisements/blocklisted-manufacturer-data-filtered-from-event.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "concurrent-watchAdvertisements-calls.https.window.js": [ + "cb6532be68ece2a04f5d70106f7b58869906b086", + [ + "bluetooth/legacy/device/watchAdvertisements/concurrent-watchAdvertisements-calls.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "detachedIframe.https.window.js": [ + "202a8dab7da3efdefc01089695f402cff7bb3309", + [ + "bluetooth/legacy/device/watchAdvertisements/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "service-and-manufacturer-data-filtered-from-event.https.window.js": [ + "f6b93ffb4bfa0f90310f56b1b6d946acdcceb8f2", + [ + "bluetooth/legacy/device/watchAdvertisements/service-and-manufacturer-data-filtered-from-event.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "subsequent-watchAdvertisements-call.https.window.js": [ + "797bfd1fa0b3ff4375d654895c21ca0d248982ad", + [ + "bluetooth/legacy/device/watchAdvertisements/subsequent-watchAdvertisements-call.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "watching-two-devices-abort-one-watchAdvertisements.https.window.js": [ + "8be02adb349a2010fea7e8f6424bdcb3d1788d93", + [ + "bluetooth/legacy/device/watchAdvertisements/watching-two-devices-abort-one-watchAdvertisements.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "watching-two-devices.https.window.js": [ + "32ec89a1eb0eaecf8b95f7c7b8026ad402438fd4", + [ + "bluetooth/legacy/device/watchAdvertisements/watching-two-devices.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + } + }, + "getAvailability": { + "reject_opaque_origin.https.html": [ + "8745fc9551bba2148632563b5f125b21e2d1427c", + [ + null, + {} + ] + ], + "sandboxed_iframe.https.window.js": [ + "0fc520e4aec3648164690de5061b4ce05a0d6c67", + [ + "bluetooth/legacy/getAvailability/sandboxed_iframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "getDevices": { + "granted-devices-with-services.https.window.js": [ + "3228543617decdc9a213883d650ba33ffd9b90c1", + [ + "bluetooth/legacy/getDevices/granted-devices-with-services.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "no-granted-devices.https.window.js": [ + "304aa3820d5b80bff80928feabc982b8b156b591", + [ + "bluetooth/legacy/getDevices/no-granted-devices.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "reject_opaque_origin.https.html": [ + "64b2808fbce3663ee447b8ecd3d00b6fc07a73f7", + [ + null, + {} + ] + ], + "returns-same-bluetooth-device-object.https.window.js": [ + "81c0f6a97e947c9a469ca74a180d595f493561e2", + [ + "bluetooth/legacy/getDevices/returns-same-bluetooth-device-object.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "sandboxed_iframe.https.window.js": [ + "b9b0ac93c27a054433d9853b3dced0fa1e6a9d13", + [ + "bluetooth/legacy/getDevices/sandboxed_iframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "idl": { + "idl-Bluetooth.https.window.js": [ + "2b40eaff4900f5385b19d27115626fafe386a1cb", + [ + "bluetooth/legacy/idl/idl-Bluetooth.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ] + ] + } + ] + ], + "idl-BluetoothDevice.https.window.js": [ + "c715926df3be6615f4b34aa3383b057347325f25", + [ + "bluetooth/legacy/idl/idl-BluetoothDevice.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "idl-BluetoothUUID.window.js": [ + "cf9c14bb2c5c80d2e693401eb916423f9ca33b98", + [ + "bluetooth/legacy/idl/idl-BluetoothUUID.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ] + ] + } + ] + ], + "idl-NavigatorBluetooth.https.window.js": [ + "a087d308962074acb52057f229ff4c31bb6f8f42", + [ + "bluetooth/legacy/idl/idl-NavigatorBluetooth.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ] + ] + } + ] + ], + "idl-NavigatorBluetooth.window.js": [ + "db6bf89f9f3396243a2acfdd68cbdb0cb09d6901", + [ + "bluetooth/legacy/idl/idl-NavigatorBluetooth.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ] + ] + } + ] + ], + "idlharness.tentative.https.window.js": [ + "a632060e20aefd43a2c6b976e891062ad0c2f7b5", + [ + "bluetooth/legacy/idl/idlharness.tentative.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/WebIDLParser.js" + ], + [ + "script", + "/resources/idlharness.js" ], [ "timeout", @@ -451429,11 +453156,3209 @@ "timeout": "long" } ] + ] + }, + "requestDevice": { + "acceptAllDevices": { + "device-with-empty-name.https.window.js": [ + "15bde6a9336c9e4cb7a13e6cc3864fc3000d2fbc", + [ + "bluetooth/legacy/requestDevice/acceptAllDevices/device-with-empty-name.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "device-with-name.https.window.js": [ + "f3373a6bb64f517c57c7a1decd2c3c553478a55e", + [ + "bluetooth/legacy/requestDevice/acceptAllDevices/device-with-name.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "optional-services-missing.https.window.js": [ + "5226a645a868df080da1a71dcb1305fbbb59158a", + [ + "bluetooth/legacy/requestDevice/acceptAllDevices/optional-services-missing.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "optional-services-present.https.window.js": [ + "7c200d03f181e7f4593dabb01f30c485e6cbea27", + [ + "bluetooth/legacy/requestDevice/acceptAllDevices/optional-services-present.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "blocklisted-manufacturer-data-in-filter.https.window.js": [ + "2dae7f4cc654ab0bb3b6093826bf3e4d643755a1", + [ + "bluetooth/legacy/requestDevice/blocklisted-manufacturer-data-in-filter.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] ], + "blocklisted-service-in-filter.https.window.js": [ + "80eaf14447fba398897bc4ee1530a8afe3de6d5d", + [ + "bluetooth/legacy/requestDevice/blocklisted-service-in-filter.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "blocklisted-service-in-optionalServices.https.window.js": [ + "4c01974e557b2f359d12e27e68d0949a22111994", + [ + "bluetooth/legacy/requestDevice/blocklisted-service-in-optionalServices.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "canonicalizeFilter": { + "data-prefix-and-mask-size.https.window.js": [ + "fa2645093a6adec4e21da973df84f419a45fca8d", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/data-prefix-and-mask-size.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "dataPrefix-buffer-is-detached.https.window.js": [ + "f4c1a9f6f9b8a3898b8d2fde3136864a9529d165", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/dataPrefix-buffer-is-detached.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "device-name-longer-than-29-bytes.https.window.js": [ + "20ed383d397046ece557f6698cf29fe15a874e7c", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "empty-dataPrefix.https.window.js": [ + "75e12219ccdffa3525342ea4f8fc00384c0ac049", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/empty-dataPrefix.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "empty-exclusion-filter.https.window.js": [ + "0d4b196cc7d22bb574d7baffa1af68251b299245", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/empty-exclusion-filter.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "empty-exclusion-filters-member.https.window.js": [ + "d380fa0268efff3f24a351f69b82066614eda7f9", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/empty-exclusion-filters-member.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "empty-filter.https.window.js": [ + "bfe94f2721d9542bd75cb46b4557fc40db41443d", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/empty-filter.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "empty-filters-member.https.window.js": [ + "3265e54fd880bdf900d73332c74499a81f923015", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/empty-filters-member.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "empty-manufacturerData-member.https.window.js": [ + "0996137f517d8ef167e86efcec11d5952a52b187", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/empty-manufacturerData-member.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "empty-namePrefix.https.window.js": [ + "8ce2e649676ee0161c00c61449ed9e9d8ecceca5", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/empty-namePrefix.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "empty-services-member.https.window.js": [ + "a24611631d360d6ec6ef65648f25d41f7ba916f2", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/empty-services-member.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "exclusion-filters-require-filters.https.window.js": [ + "d7db260deeb6500cc8eb4809bf7368a0dc59936b", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/exclusion-filters-require-filters.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "filters-xor-acceptAllDevices.https.window.js": [ + "a6c48f2962a321ccf08c8ad9e3d9bbea2d014f7c", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/filters-xor-acceptAllDevices.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "invalid-companyIdentifier.https.window.js": [ + "18cdbb4b4a85fa9fc19146d72e5494161b7dffe6", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/invalid-companyIdentifier.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "mask-buffer-is-detached.https.window.js": [ + "ae3f712db58a9e991fd5660679f8d453c2ab33a2", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/mask-buffer-is-detached.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "max-length-exceeded-name-unicode.https.window.js": [ + "3458c92b65efa8314a2af6ab00c7084d469a103b", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/max-length-exceeded-name-unicode.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "max-length-exceeded-name.https.window.js": [ + "f14f78fe7d7ecc8d68ecbd1175c1719c311c0483", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/max-length-exceeded-name.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "max-length-exceeded-namePrefix-unicode.https.window.js": [ + "b2e6668e4b98a9a0e8a23803327a890f86e593ca", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix-unicode.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "max-length-exceeded-namePrefix.https.window.js": [ + "5d27629eaa14744e6bb436472b734d3f80cd0a0f", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "max-length-name-unicode.https.window.js": [ + "6a3cf5bead0eefd561064785f3289797cb0a01e3", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/max-length-name-unicode.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "max-length-name.https.window.js": [ + "7ede93ce72166a177fa8f1db693bd49c1f7ccc2d", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/max-length-name.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "max-length-namePrefix-unicode.https.window.js": [ + "2061e9863b4026024a4170fb9794f42692cba0f7", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/max-length-namePrefix-unicode.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "max-length-namePrefix.https.window.js": [ + "f922bb2f0d0579ed5db7012e58d961fccd9dd7c9", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/max-length-namePrefix.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "no-arguments.https.window.js": [ + "075a97f1a9478a23dc693c169bea9cef9433f8ed", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/no-arguments.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "same-company-identifier.https.window.js": [ + "41f851adc5ee046eab4a98be19ff8f4ebea5da27", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/same-company-identifier.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "unicode-valid-length-name-name.https.window.js": [ + "cd10288ddb72f2cb2989bdf96f640853d29b61ee", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "unicode-valid-length-name-namePrefix.https.window.js": [ + "494f324ee2480e40d22fe3dc05030955a2f84e83", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "wrong-service-in-optionalServices-member.https.window.js": [ + "bfba220f4799db5ac19700df083cd8896d1fa356", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "wrong-service-in-services-member.https.window.js": [ + "352437d0e5a48f56572c78296ef65b7fcc73dc32", + [ + "bluetooth/legacy/requestDevice/canonicalizeFilter/wrong-service-in-services-member.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "cross-origin-iframe.sub.https.window.js": [ + "d802a862791e98e5a8694e34bd4fbaf554b9f9b5", + [ + "bluetooth/legacy/requestDevice/cross-origin-iframe.sub.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "discovery-succeeds.https.window.js": [ + "4941d185cad0508069184bc19c0ad81871e2a301", + [ + "bluetooth/legacy/requestDevice/discovery-succeeds.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "doesnt-consume-user-gesture.https.window.js": [ + "9c742733e1d793d9becda42d8afd245f7c9b633d", + [ + "bluetooth/legacy/requestDevice/doesnt-consume-user-gesture.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "filter-matches.https.window.js": [ + "1a0f52ac309b1ff116297ae86c27fc3008060cdb", + [ + "bluetooth/legacy/requestDevice/filter-matches.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "le-not-supported.https.window.js": [ + "c961ab4492c42e0d62c599580b07e87c3f336040", + [ + "bluetooth/legacy/requestDevice/le-not-supported.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "manufacturer-data-filter-matches.https.window.js": [ + "c4c0e805328a5aa52ff21025e0ad56e0517cce7e", + [ + "bluetooth/legacy/requestDevice/manufacturer-data-filter-matches.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "name-empty-device-from-name-empty-filter.https.window.js": [ + "2ff22cb70200809e5cbaf7dc8ac63bbf4f2f3c92", + [ + "bluetooth/legacy/requestDevice/name-empty-device-from-name-empty-filter.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "not-processing-user-gesture.https.window.js": [ + "a063b61163019336cfe3e776ed14b8dc54aea227", + [ + "bluetooth/legacy/requestDevice/not-processing-user-gesture.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "radio-not-present.https.window.js": [ + "b55d63c6ff45fa30f973facc43de58f560a2f28c", + [ + "bluetooth/legacy/requestDevice/radio-not-present.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "reject_opaque_origin.https.html": [ + "df348dd39e0b62cb38605b94e0c98e4e155c1dbc", + [ + null, + {} + ] + ], + "request-from-iframe.https.window.js": [ + "d3f3cf897ff6f4eb97253f63843db888824a54fa", + [ + "bluetooth/legacy/requestDevice/request-from-iframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "request-from-sandboxed-iframe.https.window.js": [ + "2101cf0d6b747836f60d04c07774e3a100efed1f", + [ + "bluetooth/legacy/requestDevice/request-from-sandboxed-iframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "same-device.https.window.js": [ + "41a42cf4c8fd70c10c096c50733d9a517b77f54b", + [ + "bluetooth/legacy/requestDevice/same-device.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "sandboxed_iframe.https.window.js": [ + "e9192a9305b14763d3cabe7c6ddfb3b38f1015da", + [ + "bluetooth/legacy/requestDevice/sandboxed_iframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "single-filter-single-service.https.window.js": [ + "67afad0b930c7930614f3ed17a0db78e1aa20d69", + [ + "bluetooth/legacy/requestDevice/single-filter-single-service.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "requestLEScan": { + "reject_opaque_origin.https.html": [ + "272c5aa760cf7f5bedc24e2d652d68164ab353d3", + [ + null, + {} + ] + ], + "sandboxed_iframe.https.window.js": [ + "32d1e74b778d9932b5104824b69cf21cf6a3ff6b", + [ + "bluetooth/legacy/requestLEScan/sandboxed_iframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "server": { + "connect": { + "connection-succeeds.https.window.js": [ + "90b62b9265b1c337f05993f7169c9bd33cf6e962", + [ + "bluetooth/legacy/server/connect/connection-succeeds.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "detachedIframe.https.window.js": [ + "2332cef7070baddc84573120edb0f0dc1fc83efa", + [ + "bluetooth/legacy/server/connect/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "garbage-collection-ran-during-success.https.window.js": [ + "2d2211dec30f87a988acf24fc4a283ed174405f8", + [ + "bluetooth/legacy/server/connect/garbage-collection-ran-during-success.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "get-same-gatt-server.https.window.js": [ + "59d7243a65382cd3509f425bcf6db9087c49c74f", + [ + "bluetooth/legacy/server/connect/get-same-gatt-server.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "device-same-object.https.window.js": [ + "f9a66d9b6915cf9b093ffafb6cb7fe11b3febf88", + [ + "bluetooth/legacy/server/device-same-object.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "disconnect": { + "connect-disconnect-twice.https.window.js": [ + "5d9908df4c8ac20d5fbea9966ff56b13a3b19de9", + [ + "bluetooth/legacy/server/disconnect/connect-disconnect-twice.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "detach-gc.https.window.js": [ + "b934b3797325a255b77e5cf39011ab2803bbb90b", + [ + "bluetooth/legacy/server/disconnect/detach-gc.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "detachedIframe.https.window.js": [ + "04e0ca0117fcc2974e02bde54802ee8d279e234a", + [ + "bluetooth/legacy/server/disconnect/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "disconnect-twice-in-a-row.https.window.js": [ + "acca9796d5751d2e5c3fa73e2cd32bcd8ba31bda", + [ + "bluetooth/legacy/server/disconnect/disconnect-twice-in-a-row.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gc-detach.https.window.js": [ + "1c062a775903bf0396a33592231851e2da2b7660", + [ + "bluetooth/legacy/server/disconnect/gc-detach.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "getPrimaryService": { + "gen-disconnect-called-before.https.window.js": [ + "631545a38542689762605f53af4ed7a7753a9134", + [ + "bluetooth/legacy/server/getPrimaryService/gen-disconnect-called-before.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-called-during-error.https.window.js": [ + "bcf19665d5fcf2cd720717f3f602f9d9795a6a33", + [ + "bluetooth/legacy/server/getPrimaryService/gen-disconnect-called-during-error.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-called-during-success.https.window.js": [ + "0d2fc1044a5bbb4c205741db61a3946d5b37c724", + [ + "bluetooth/legacy/server/getPrimaryService/gen-disconnect-called-during-success.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-discovery-timeout.https.window.js": [ + "03b0c9d0f382c3462beed1ee282321a7d91d94f1", + [ + "bluetooth/legacy/server/getPrimaryService/gen-disconnect-discovery-timeout.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-invalidates-objects.https.window.js": [ + "56468b24eabf2d99a3f4a10eef7cdbc0c2594ebc", + [ + "bluetooth/legacy/server/getPrimaryService/gen-disconnect-invalidates-objects.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnected-device.https.window.js": [ + "741b2db5ee82e8f268fca71143fd419bda0af87b", + [ + "bluetooth/legacy/server/getPrimaryService/gen-disconnected-device.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-discovery-complete-no-permission-absent-service.https.window.js": [ + "e2f5c87630559a7a5fef08bf37b68e84d3356648", + [ + "bluetooth/legacy/server/getPrimaryService/gen-discovery-complete-no-permission-absent-service.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-discovery-complete-service-not-found.https.window.js": [ + "8e9166b41a140832ccc121b6ec63415fccb5bbca", + [ + "bluetooth/legacy/server/getPrimaryService/gen-discovery-complete-service-not-found.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-garbage-collection-ran-during-error.https.window.js": [ + "df182fe8fff6b3001d355fe4c70b67b9b64bdc56", + [ + "bluetooth/legacy/server/getPrimaryService/gen-garbage-collection-ran-during-error.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-garbage-collection-ran-during-success.https.window.js": [ + "8e278af224234f1ab005e52cfff0fafcfe729537", + [ + "bluetooth/legacy/server/getPrimaryService/gen-garbage-collection-ran-during-success.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-get-different-service-after-reconnection.https.window.js": [ + "d4557f67535001a64a0b7347e336f95db547fe6c", + [ + "bluetooth/legacy/server/getPrimaryService/gen-get-different-service-after-reconnection.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-get-same-object.https.window.js": [ + "b43cefb567f01d0b7cdb8b53bc3da40e785fe007", + [ + "bluetooth/legacy/server/getPrimaryService/gen-get-same-object.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-invalid-service-name.https.window.js": [ + "cf4ab6c665d6a9605507b01e1e0c3e1a807376ba", + [ + "bluetooth/legacy/server/getPrimaryService/gen-invalid-service-name.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-no-permission-absent-service.https.window.js": [ + "3466ded4f9e910d30c3f5a55dd3e1172addeb3d8", + [ + "bluetooth/legacy/server/getPrimaryService/gen-no-permission-absent-service.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-no-permission-for-any-service.https.window.js": [ + "6576ef20a3de120529c4bf2997b13b40d7ce3f26", + [ + "bluetooth/legacy/server/getPrimaryService/gen-no-permission-for-any-service.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-no-permission-present-service.https.window.js": [ + "3d0b460bc33b9e246dfa59d30248edefd7d13d6a", + [ + "bluetooth/legacy/server/getPrimaryService/gen-no-permission-present-service.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-service-not-found.https.window.js": [ + "6e0d2c446ba90199f1bab1158e6147ed632deda6", + [ + "bluetooth/legacy/server/getPrimaryService/gen-service-not-found.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "service-found.https.window.js": [ + "b8a930d10c79b345f7a0c6c6ec9d89b095dccec4", + [ + "bluetooth/legacy/server/getPrimaryService/service-found.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "two-iframes-from-same-origin.https.window.js": [ + "b7f23a14913914d3e3bc2f57b98b2b1cc91a185c", + [ + "bluetooth/legacy/server/getPrimaryService/two-iframes-from-same-origin.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + }, + "getPrimaryServices": { + "blocklisted-services-with-uuid.https.window.js": [ + "ccc913e5bfdc7df6efe6627dc97899e12f981660", + [ + "bluetooth/legacy/server/getPrimaryServices/blocklisted-services-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "blocklisted-services.https.window.js": [ + "ae6be9099466b725521e54bec72013bcf175762a", + [ + "bluetooth/legacy/server/getPrimaryServices/blocklisted-services.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "correct-services.https.window.js": [ + "f3d883dd2ef181ca7c7a88999a9620056a42f046", + [ + "bluetooth/legacy/server/getPrimaryServices/correct-services.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-called-before-with-uuid.https.window.js": [ + "21b561375dfed914f011a4de18148053087a6c4f", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnect-called-before-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-called-before.https.window.js": [ + "8e5fea83ab4e53299ed6f5c78bd5d0322d2cf410", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnect-called-before.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-called-during-error-with-uuid.https.window.js": [ + "5c28716b90bf32e0e25e5e16ac37fc085f50fb9a", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnect-called-during-error-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-called-during-error.https.window.js": [ + "ddc31247911d64f1995cdae41af9da15a11bb890", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnect-called-during-error.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-called-during-success-with-uuid.https.window.js": [ + "13e3806d313e40ffc1d69503ad9ebb18cf4630ba", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnect-called-during-success-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-called-during-success.https.window.js": [ + "d6b31936c60a9a17af6a4764ac16b7580b3649a9", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnect-called-during-success.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-discovery-timeout-with-uuid.https.window.js": [ + "77f7bc81d99cc2f0b7f72e5a5866d0d89e625dce", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnect-discovery-timeout-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-discovery-timeout.https.window.js": [ + "ea55b7b495259c58027ac24be4b918585cb44fed", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnect-discovery-timeout.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-invalidates-objects-with-uuid.https.window.js": [ + "8cdb83e3ad7a2fea327c45b67388082c4e58e09e", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnect-invalidates-objects-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnect-invalidates-objects.https.window.js": [ + "9fd536f05161e0582e88ecbf2f5987a92214a4ba", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnect-invalidates-objects.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnected-device-with-uuid.https.window.js": [ + "e0393d5e69ca867e09b049576c33efbbc397866d", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnected-device-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-disconnected-device.https.window.js": [ + "87d74c6ab14083fdd6ed32aa74d01e5b1206b53d", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-disconnected-device.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-discovery-complete-no-permission-absent-service-with-uuid.https.window.js": [ + "6e179dc5d9a373a6a10c17a8083116e464264658", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-discovery-complete-no-permission-absent-service-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-discovery-complete-service-not-found-with-uuid.https.window.js": [ + "66cfb491c078d7ca378cb4418d399a0b33a9d07b", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-discovery-complete-service-not-found-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-garbage-collection-ran-during-error-with-uuid.https.window.js": [ + "a235cf5d189bebdaf2d8e6b04e5796075fb34098", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-garbage-collection-ran-during-error-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-garbage-collection-ran-during-error.https.window.js": [ + "f174d4aef98dbe1fb3fa148992cab34b8a475263", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-garbage-collection-ran-during-error.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-garbage-collection-ran-during-success-with-uuid.https.window.js": [ + "cf5dfb246fbd12ef3a4597926cdbf877bae2cc4a", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-garbage-collection-ran-during-success-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-garbage-collection-ran-during-success.https.window.js": [ + "f1c080a9463b79462bab70dbe611ee01ea6880b8", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-garbage-collection-ran-during-success.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-get-different-service-after-reconnection-with-uuid.https.window.js": [ + "2e40d580f3399ddccd7b84d60f9ffa87b0fb2d51", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-get-different-service-after-reconnection-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-get-different-service-after-reconnection.https.window.js": [ + "ee1fc971bfa942e4f0c204acb80b055f311dc611", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-get-different-service-after-reconnection.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-get-same-object-with-uuid.https.window.js": [ + "b589056a23a9e67ad9673713bab2cd2e93c1b8f9", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-get-same-object-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-get-same-object.https.window.js": [ + "63739add912351f1da86a4cfdcd02d4cfd8567fa", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-get-same-object.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-invalid-service-name.https.window.js": [ + "a9b1262e6a181d1017ead79b1972ecd85e942098", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-invalid-service-name.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-no-permission-absent-service-with-uuid.https.window.js": [ + "27ad9f008ee0d296dcbcf1c27199ce11a45e6fdd", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-no-permission-absent-service-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-no-permission-for-any-service-with-uuid.https.window.js": [ + "d5f06c23da6660566fbbbdbf8a5dccaaa14904fe", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-no-permission-for-any-service-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-no-permission-for-any-service.https.window.js": [ + "8aa730d2ed2d8de1868d705e026a6a8a2376ee27", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-no-permission-for-any-service.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-no-permission-present-service-with-uuid.https.window.js": [ + "a2047a0e8f0e2236cc968b309aa5340ee5b97a90", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-no-permission-present-service-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "gen-service-not-found-with-uuid.https.window.js": [ + "a2db1edc4b9f30d73b39eb530894983323135090", + [ + "bluetooth/legacy/server/getPrimaryServices/gen-service-not-found-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "services-found-with-uuid.https.window.js": [ + "972e6a75caa3f21935abe9b504d0bccf5249c6a1", + [ + "bluetooth/legacy/server/getPrimaryServices/services-found-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "services-found.https.window.js": [ + "46861175c605d4e2d966df8751d709530f411f02", + [ + "bluetooth/legacy/server/getPrimaryServices/services-found.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ], + "services-not-found.https.window.js": [ + "63503282411b80eba908b91e72ea7a0946945019", + [ + "bluetooth/legacy/server/getPrimaryServices/services-not-found.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } + ] + ] + } + }, + "service": { "detachedIframe.https.window.js": [ - "6e2510b58d6af5117144fb21b2e7049ad9120d02", + "f75fc225a791b57bff086fa8acad026521e22ce4", [ - "bluetooth/characteristic/readValue/detachedIframe.https.window.html", + "bluetooth/legacy/service/detachedIframe.https.window.html", { "script_metadata": [ [ @@ -451460,10 +456385,10 @@ } ] ], - "event-is-fired.https.window.js": [ - "52b70e7a080e870c27bf86d9ba591292f0b273bb", + "device-same-from-2-services.https.window.js": [ + "5b2ba310d356d3eb4f7c0f76ac992bb2f8056034", [ - "bluetooth/characteristic/readValue/event-is-fired.https.window.html", + "bluetooth/legacy/service/device-same-from-2-services.https.window.html", { "script_metadata": [ [ @@ -451486,40 +456411,10 @@ } ] ], - "gen-characteristic-is-removed.https.window.js": [ - "5bee6db1076bdbc57462ab9298c50c2542a0f702", + "device-same-object.https.window.js": [ + "97da769a9eac25b55e72ac9e44d6c3cf1442ec3a", [ - "bluetooth/characteristic/readValue/gen-characteristic-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "read-succeeds.https.window.js": [ - "e5ddfb81696c009743622929d3c490a6469e4c4b", - [ - "bluetooth/characteristic/readValue/read-succeeds.https.window.html", + "bluetooth/legacy/service/device-same-object.https.window.html", { "script_metadata": [ [ @@ -451542,5589 +456437,710 @@ } ] ], - "read-updates-value.https.window.js": [ - "bb98aeb18f2dcd068735d8d492dc604ead3970e4", - [ - "bluetooth/characteristic/readValue/read-updates-value.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" + "getCharacteristic": { + "characteristic-found.https.window.js": [ + "807852ae133c0f024925faaee88309b9f585ea47", + [ + "bluetooth/legacy/service/getCharacteristic/characteristic-found.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] ] - ] - } - ] - ], - "service-is-removed.https.window.js": [ - "1f699ca25eebcd35e0dc76be4be735d7dfd801b6", - [ - "bluetooth/characteristic/readValue/service-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "service-same-from-2-characteristics.https.window.js": [ - "dafd755fd1d49b48bcd0a2623a07a5f6855a8164", - [ - "bluetooth/characteristic/service-same-from-2-characteristics.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + } ] - } - ] - ], - "service-same-object.https.window.js": [ - "01b3a25e35e4a8c2e8a1626e12de90e625dda0a8", - [ - "bluetooth/characteristic/service-same-object.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "detachedIframe.https.window.js": [ + "ea8c96160ff9dfa2498fd9d51f167ddc80e4aa6a", + [ + "bluetooth/legacy/service/getCharacteristic/detachedIframe.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "startNotifications": { - "detachedIframe.https.window.js": [ - "f09c52d32822e1dc412e158c18e9cafa0a931e29", - [ - "bluetooth/characteristic/startNotifications/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" + ], + "gen-blocklisted-characteristic.https.window.js": [ + "cce302d6504f51db4d67553d8f57b915d5ffc645", + [ + "bluetooth/legacy/service/getCharacteristic/gen-blocklisted-characteristic.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] ] - ] - } - ] - ], - "gen-characteristic-is-removed.https.window.js": [ - "c2a23d7f44191fc3a64a397aac447801f3c6ce47", - [ - "bluetooth/characteristic/startNotifications/gen-characteristic-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "stopNotifications": { - "detachedIframe.https.window.js": [ - "a459a5b15d9fa7f87b27fda23f8edaa547584e71", - [ - "bluetooth/characteristic/stopNotifications/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "writeValue": { - "buffer-is-detached.https.window.js": [ - "43c50d763a0973a498d861fcb80a2efc24f92daa", - [ - "bluetooth/characteristic/writeValue/buffer-is-detached.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "characteristic-is-removed.https.window.js": [ - "6e9da8802c7adf343d0dd9683c2b03afe11d28e2", - [ - "bluetooth/characteristic/writeValue/characteristic-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "detachedIframe.https.window.js": [ - "eb243a3508c3de75d29f3df91060040da231e1a6", - [ - "bluetooth/characteristic/writeValue/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-characteristic-is-removed.https.window.js": [ - "5750cb82c7f848dba7fd4f3783f6a340636a3661", - [ - "bluetooth/characteristic/writeValue/gen-characteristic-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "service-is-removed.https.window.js": [ - "89c3112475012de82ca637ec09fbd372f76516fc", - [ - "bluetooth/characteristic/writeValue/service-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "write-succeeds.https.window.js": [ - "b57fe941d0a88091b08f1f573c7af06c88dc85a6", - [ - "bluetooth/characteristic/writeValue/write-succeeds.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "writeValueWithResponse": { - "buffer-is-detached.https.window.js": [ - "5fb4aa23553986791279430b44f8bb50efa5abcd", - [ - "bluetooth/characteristic/writeValueWithResponse/buffer-is-detached.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "characteristic-is-removed.https.window.js": [ - "9309cd5a3cd325e5df4d9b38260a2fcd4b47ea2b", - [ - "bluetooth/characteristic/writeValueWithResponse/characteristic-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-characteristic-is-removed.https.window.js": [ - "e202376da7c64fa3a906e6f169a76e61d1e6a916", - [ - "bluetooth/characteristic/writeValueWithResponse/gen-characteristic-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "service-is-removed.https.window.js": [ - "81b2dff44e34080b4088f7a6fd5ed9f58feb6eff", - [ - "bluetooth/characteristic/writeValueWithResponse/service-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "write-succeeds.https.window.js": [ - "c87e7ac6aba26b31319becd030d34657506ba57d", - [ - "bluetooth/characteristic/writeValueWithResponse/write-succeeds.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "writeValueWithoutResponse": { - "buffer-is-detached.https.window.js": [ - "23721380cbdb69c84dce985b26ba92a79f6c4f3e", - [ - "bluetooth/characteristic/writeValueWithoutResponse/buffer-is-detached.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "characteristic-is-removed.https.window.js": [ - "8d3ed1f663369bfb11448a3739d3773f55b53c61", - [ - "bluetooth/characteristic/writeValueWithoutResponse/characteristic-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-characteristic-is-removed.https.window.js": [ - "b88246aae834f0ea54e72ec9a292c6b93eafb3cc", - [ - "bluetooth/characteristic/writeValueWithoutResponse/gen-characteristic-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "service-is-removed.https.window.js": [ - "feb711c64ea6b46d3401d3888de8d757c9a567b2", - [ - "bluetooth/characteristic/writeValueWithoutResponse/service-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "write-succeeds.https.window.js": [ - "0dcf8ad0b196adde1941e0c4e31b36ba08741384", - [ - "bluetooth/characteristic/writeValueWithoutResponse/write-succeeds.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - } - }, - "descriptor": { - "readValue": { - "detachedIframe.https.window.js": [ - "47765a13159b7facc753e7951b94377abc8b54b9", - [ - "bluetooth/descriptor/readValue/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-service-is-removed.https.window.js": [ - "d6c73ba60e6a1e5d8d10c80796729baf039ee702", - [ - "bluetooth/descriptor/readValue/gen-service-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "read-succeeds.https.window.js": [ - "d81db2f8c0ddb54042a6178677df309a7c6248ef", - [ - "bluetooth/descriptor/readValue/read-succeeds.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "writeValue": { - "buffer-is-detached.https.window.js": [ - "454b23ea4c2c44e4f011b77520c69dac5d469fb2", - [ - "bluetooth/descriptor/writeValue/buffer-is-detached.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "detachedIframe.https.window.js": [ - "aa143ca8e53e993273a6887b67566ff3265992d4", - [ - "bluetooth/descriptor/writeValue/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-service-is-removed.https.window.js": [ - "c7f6d6efe3e3a19f5c954a3ca83aa87f0386c98c", - [ - "bluetooth/descriptor/writeValue/gen-service-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - } - }, - "device": { - "forget": { - "connect-after-forget.https.window.js": [ - "0b15b4d060d9ae8e4795b2a4fbb684db53218f69", - [ - "bluetooth/device/forget/connect-after-forget.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "detachedIframe.https.window.js": [ - "f4803542fbb30c2aff401fd0951271e5e39bc999", - [ - "bluetooth/device/forget/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "getDevices.https.window.js": [ - "0594a6f03bf377ea19c5856298c03ed136973656", - [ - "bluetooth/device/forget/getDevices.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "gattserverdisconnected-event": { - "disconnected.https.window.js": [ - "43a11a88cbf655ee4aab6ac70215ae3fb5f9a541", - [ - "bluetooth/device/gattserverdisconnected-event/disconnected.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "disconnected_gc.https.window.js": [ - "0cf4973e2167766ece047cbcac8034d089482acc", - [ - "bluetooth/device/gattserverdisconnected-event/disconnected_gc.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "one-event-per-disconnection.https.window.js": [ - "ab273adbc88bcd4d03c9bf5309a34cb30cf3246a", - [ - "bluetooth/device/gattserverdisconnected-event/one-event-per-disconnection.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "reconnect-during-disconnected-event.https.window.js": [ - "bdaf47c66198ce70f9a1951358f27b38dcfac4ca", - [ - "bluetooth/device/gattserverdisconnected-event/reconnect-during-disconnected-event.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "watchAdvertisements": { - "abort-before-watchAdvertisements.https.window.js": [ - "e1ac1fb136902244055e88f859d9d536bc58951c", - [ - "bluetooth/device/watchAdvertisements/abort-before-watchAdvertisements.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "abort-pending-operation.https.window.js": [ - "c1022ff4a9c1b8c57703a8ce5b8bdfa309b7d985", - [ - "bluetooth/device/watchAdvertisements/abort-pending-operation.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "abort-signal-stops-events.https.window.js": [ - "21b6883fee433a2a04c689ae82c9a8a30aed5c91", - [ - "bluetooth/device/watchAdvertisements/abort-signal-stops-events.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "abort-subsequent-watchAdvertisements-call-stops-events.https.window.js": [ - "a5da75012bab1991a762c48f9a76f32906f2db11", - [ - "bluetooth/device/watchAdvertisements/abort-subsequent-watchAdvertisements-call-stops-events.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "advertisementreceived-event-fired.https.window.js": [ - "fff18bc47eed8434e3b4ff46cd157b5a5e41ea1a", - [ - "bluetooth/device/watchAdvertisements/advertisementreceived-event-fired.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "blocklisted-manufacturer-data-filtered-from-event.https.window.js": [ - "c73e3dbad1b20dd26a02d6ca4326a53b3f668a92", - [ - "bluetooth/device/watchAdvertisements/blocklisted-manufacturer-data-filtered-from-event.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "concurrent-watchAdvertisements-calls.https.window.js": [ - "cb6532be68ece2a04f5d70106f7b58869906b086", - [ - "bluetooth/device/watchAdvertisements/concurrent-watchAdvertisements-calls.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "detachedIframe.https.window.js": [ - "202a8dab7da3efdefc01089695f402cff7bb3309", - [ - "bluetooth/device/watchAdvertisements/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "service-and-manufacturer-data-filtered-from-event.https.window.js": [ - "f6b93ffb4bfa0f90310f56b1b6d946acdcceb8f2", - [ - "bluetooth/device/watchAdvertisements/service-and-manufacturer-data-filtered-from-event.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "subsequent-watchAdvertisements-call.https.window.js": [ - "797bfd1fa0b3ff4375d654895c21ca0d248982ad", - [ - "bluetooth/device/watchAdvertisements/subsequent-watchAdvertisements-call.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "watching-two-devices-abort-one-watchAdvertisements.https.window.js": [ - "8be02adb349a2010fea7e8f6424bdcb3d1788d93", - [ - "bluetooth/device/watchAdvertisements/watching-two-devices-abort-one-watchAdvertisements.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "watching-two-devices.https.window.js": [ - "32ec89a1eb0eaecf8b95f7c7b8026ad402438fd4", - [ - "bluetooth/device/watchAdvertisements/watching-two-devices.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - } - }, - "getAvailability": { - "reject_opaque_origin.https.html": [ - "8745fc9551bba2148632563b5f125b21e2d1427c", - [ - null, - {} - ] - ], - "sandboxed_iframe.https.window.js": [ - "0fc520e4aec3648164690de5061b4ce05a0d6c67", - [ - "bluetooth/getAvailability/sandboxed_iframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + } ] - } - ] - ] - }, - "getDevices": { - "granted-devices-with-services.https.window.js": [ - "3228543617decdc9a213883d650ba33ffd9b90c1", - [ - "bluetooth/getDevices/granted-devices-with-services.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-characteristic-not-found.https.window.js": [ + "2ed48eb5c68798e402193ca195c74c86dbf8909e", + [ + "bluetooth/legacy/service/getCharacteristic/gen-characteristic-not-found.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "no-granted-devices.https.window.js": [ - "304aa3820d5b80bff80928feabc982b8b156b591", - [ - "bluetooth/getDevices/no-granted-devices.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-garbage-collection-ran-during-error.https.window.js": [ + "1fd70c8fad4b454cb0687d48645117edb801c4de", + [ + "bluetooth/legacy/service/getCharacteristic/gen-garbage-collection-ran-during-error.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "reject_opaque_origin.https.html": [ - "64b2808fbce3663ee447b8ecd3d00b6fc07a73f7", - [ - null, - {} - ] - ], - "returns-same-bluetooth-device-object.https.window.js": [ - "81c0f6a97e947c9a469ca74a180d595f493561e2", - [ - "bluetooth/getDevices/returns-same-bluetooth-device-object.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-get-same-object.https.window.js": [ + "c5176cdc5e0a7a310c60e1d4ed15b07dbeb5e7bb", + [ + "bluetooth/legacy/service/getCharacteristic/gen-get-same-object.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "sandboxed_iframe.https.window.js": [ - "b9b0ac93c27a054433d9853b3dced0fa1e6a9d13", - [ - "bluetooth/getDevices/sandboxed_iframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-invalid-characteristic-name.https.window.js": [ + "da0f5bda28080f7486e95a3f14ee1f8838c3bc62", + [ + "bluetooth/legacy/service/getCharacteristic/gen-invalid-characteristic-name.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ] - }, - "idl": { - "idl-Bluetooth.https.window.js": [ - "2b40eaff4900f5385b19d27115626fafe386a1cb", - [ - "bluetooth/idl/idl-Bluetooth.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ] + ], + "gen-reconnect-during.https.window.js": [ + "8801c152e931ef3e631cc7ec649c83254c59b3a2", + [ + "bluetooth/legacy/service/getCharacteristic/gen-reconnect-during.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "idl-BluetoothDevice.https.window.js": [ - "c715926df3be6615f4b34aa3383b057347325f25", - [ - "bluetooth/idl/idl-BluetoothDevice.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-service-is-removed.https.window.js": [ + "bfeb318c46ea54136137f390adaae0a7322dd827", + [ + "bluetooth/legacy/service/getCharacteristic/gen-service-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "idl-BluetoothUUID.window.js": [ - "cf9c14bb2c5c80d2e693401eb916423f9ca33b98", - [ - "bluetooth/idl/idl-BluetoothUUID.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ] + ] + }, + "getCharacteristics": { + "blocklisted-characteristics.https.window.js": [ + "408943585ab86eb3ed73454f82b862820a469aa8", + [ + "bluetooth/legacy/service/getCharacteristics/blocklisted-characteristics.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "idl-NavigatorBluetooth.https.window.js": [ - "a087d308962074acb52057f229ff4c31bb6f8f42", - [ - "bluetooth/idl/idl-NavigatorBluetooth.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ] + ], + "characteristics-found-with-uuid.https.window.js": [ + "f11c69c92e7aed8b177c255a071ef9b3af918a4e", + [ + "bluetooth/legacy/service/getCharacteristics/characteristics-found-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "idl-NavigatorBluetooth.window.js": [ - "db6bf89f9f3396243a2acfdd68cbdb0cb09d6901", - [ - "bluetooth/idl/idl-NavigatorBluetooth.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ] + ], + "characteristics-found.https.window.js": [ + "3244dd3e173d233b65db3ede450464fbc763a531", + [ + "bluetooth/legacy/service/getCharacteristics/characteristics-found.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "idlharness.tentative.https.window.js": [ - "a632060e20aefd43a2c6b976e891062ad0c2f7b5", - [ - "bluetooth/idl/idlharness.tentative.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/WebIDLParser.js" - ], - [ - "script", - "/resources/idlharness.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ] - }, - "requestDevice": { - "acceptAllDevices": { - "device-with-empty-name.https.window.js": [ - "15bde6a9336c9e4cb7a13e6cc3864fc3000d2fbc", - [ - "bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" + ], + "characteristics-not-found.https.window.js": [ + "5b0c1896d64f01b83349a9152cc561ac0b435438", + [ + "bluetooth/legacy/service/getCharacteristics/characteristics-not-found.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] ] - ] - } - ] - ], - "device-with-name.https.window.js": [ - "f3373a6bb64f517c57c7a1decd2c3c553478a55e", - [ - "bluetooth/requestDevice/acceptAllDevices/device-with-name.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "optional-services-missing.https.window.js": [ - "5226a645a868df080da1a71dcb1305fbbb59158a", - [ - "bluetooth/requestDevice/acceptAllDevices/optional-services-missing.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "optional-services-present.https.window.js": [ - "7c200d03f181e7f4593dabb01f30c485e6cbea27", - [ - "bluetooth/requestDevice/acceptAllDevices/optional-services-present.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "blocklisted-manufacturer-data-in-filter.https.window.js": [ - "2dae7f4cc654ab0bb3b6093826bf3e4d643755a1", - [ - "bluetooth/requestDevice/blocklisted-manufacturer-data-in-filter.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + } ] - } - ] - ], - "blocklisted-service-in-filter.https.window.js": [ - "80eaf14447fba398897bc4ee1530a8afe3de6d5d", - [ - "bluetooth/requestDevice/blocklisted-service-in-filter.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-blocklisted-characteristic-with-uuid.https.window.js": [ + "79cd01032b580debd840d885c350d44aa7b5e974", + [ + "bluetooth/legacy/service/getCharacteristics/gen-blocklisted-characteristic-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "blocklisted-service-in-optionalServices.https.window.js": [ - "4c01974e557b2f359d12e27e68d0949a22111994", - [ - "bluetooth/requestDevice/blocklisted-service-in-optionalServices.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-characteristic-not-found-with-uuid.https.window.js": [ + "8a5e2ab4e4ac8e1534f0ccb3666fe5ee71645ec9", + [ + "bluetooth/legacy/service/getCharacteristics/gen-characteristic-not-found-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "canonicalizeFilter": { - "data-prefix-and-mask-size.https.window.js": [ - "fa2645093a6adec4e21da973df84f419a45fca8d", - [ - "bluetooth/requestDevice/canonicalizeFilter/data-prefix-and-mask-size.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" + ], + "gen-garbage-collection-ran-during-error-with-uuid.https.window.js": [ + "683b93e352d0e59fce29c48585d419febd850fb6", + [ + "bluetooth/legacy/service/getCharacteristics/gen-garbage-collection-ran-during-error-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] ] - ] - } - ] - ], - "dataPrefix-buffer-is-detached.https.window.js": [ - "f4c1a9f6f9b8a3898b8d2fde3136864a9529d165", - [ - "bluetooth/requestDevice/canonicalizeFilter/dataPrefix-buffer-is-detached.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "device-name-longer-than-29-bytes.https.window.js": [ - "20ed383d397046ece557f6698cf29fe15a874e7c", - [ - "bluetooth/requestDevice/canonicalizeFilter/device-name-longer-than-29-bytes.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "empty-dataPrefix.https.window.js": [ - "75e12219ccdffa3525342ea4f8fc00384c0ac049", - [ - "bluetooth/requestDevice/canonicalizeFilter/empty-dataPrefix.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "empty-exclusion-filter.https.window.js": [ - "0d4b196cc7d22bb574d7baffa1af68251b299245", - [ - "bluetooth/requestDevice/canonicalizeFilter/empty-exclusion-filter.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "empty-exclusion-filters-member.https.window.js": [ - "d380fa0268efff3f24a351f69b82066614eda7f9", - [ - "bluetooth/requestDevice/canonicalizeFilter/empty-exclusion-filters-member.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "empty-filter.https.window.js": [ - "bfe94f2721d9542bd75cb46b4557fc40db41443d", - [ - "bluetooth/requestDevice/canonicalizeFilter/empty-filter.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "empty-filters-member.https.window.js": [ - "3265e54fd880bdf900d73332c74499a81f923015", - [ - "bluetooth/requestDevice/canonicalizeFilter/empty-filters-member.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "empty-manufacturerData-member.https.window.js": [ - "0996137f517d8ef167e86efcec11d5952a52b187", - [ - "bluetooth/requestDevice/canonicalizeFilter/empty-manufacturerData-member.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "empty-namePrefix.https.window.js": [ - "8ce2e649676ee0161c00c61449ed9e9d8ecceca5", - [ - "bluetooth/requestDevice/canonicalizeFilter/empty-namePrefix.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "empty-services-member.https.window.js": [ - "a24611631d360d6ec6ef65648f25d41f7ba916f2", - [ - "bluetooth/requestDevice/canonicalizeFilter/empty-services-member.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "exclusion-filters-require-filters.https.window.js": [ - "d7db260deeb6500cc8eb4809bf7368a0dc59936b", - [ - "bluetooth/requestDevice/canonicalizeFilter/exclusion-filters-require-filters.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "filters-xor-acceptAllDevices.https.window.js": [ - "a6c48f2962a321ccf08c8ad9e3d9bbea2d014f7c", - [ - "bluetooth/requestDevice/canonicalizeFilter/filters-xor-acceptAllDevices.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "invalid-companyIdentifier.https.window.js": [ - "18cdbb4b4a85fa9fc19146d72e5494161b7dffe6", - [ - "bluetooth/requestDevice/canonicalizeFilter/invalid-companyIdentifier.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "mask-buffer-is-detached.https.window.js": [ - "ae3f712db58a9e991fd5660679f8d453c2ab33a2", - [ - "bluetooth/requestDevice/canonicalizeFilter/mask-buffer-is-detached.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "max-length-exceeded-name-unicode.https.window.js": [ - "3458c92b65efa8314a2af6ab00c7084d469a103b", - [ - "bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name-unicode.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "max-length-exceeded-name.https.window.js": [ - "f14f78fe7d7ecc8d68ecbd1175c1719c311c0483", - [ - "bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-name.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "max-length-exceeded-namePrefix-unicode.https.window.js": [ - "b2e6668e4b98a9a0e8a23803327a890f86e593ca", - [ - "bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix-unicode.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "max-length-exceeded-namePrefix.https.window.js": [ - "5d27629eaa14744e6bb436472b734d3f80cd0a0f", - [ - "bluetooth/requestDevice/canonicalizeFilter/max-length-exceeded-namePrefix.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "max-length-name-unicode.https.window.js": [ - "6a3cf5bead0eefd561064785f3289797cb0a01e3", - [ - "bluetooth/requestDevice/canonicalizeFilter/max-length-name-unicode.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "max-length-name.https.window.js": [ - "7ede93ce72166a177fa8f1db693bd49c1f7ccc2d", - [ - "bluetooth/requestDevice/canonicalizeFilter/max-length-name.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "max-length-namePrefix-unicode.https.window.js": [ - "2061e9863b4026024a4170fb9794f42692cba0f7", - [ - "bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix-unicode.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "max-length-namePrefix.https.window.js": [ - "f922bb2f0d0579ed5db7012e58d961fccd9dd7c9", - [ - "bluetooth/requestDevice/canonicalizeFilter/max-length-namePrefix.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "no-arguments.https.window.js": [ - "075a97f1a9478a23dc693c169bea9cef9433f8ed", - [ - "bluetooth/requestDevice/canonicalizeFilter/no-arguments.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "same-company-identifier.https.window.js": [ - "41f851adc5ee046eab4a98be19ff8f4ebea5da27", - [ - "bluetooth/requestDevice/canonicalizeFilter/same-company-identifier.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "unicode-valid-length-name-name.https.window.js": [ - "cd10288ddb72f2cb2989bdf96f640853d29b61ee", - [ - "bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-name.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "unicode-valid-length-name-namePrefix.https.window.js": [ - "494f324ee2480e40d22fe3dc05030955a2f84e83", - [ - "bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "wrong-service-in-optionalServices-member.https.window.js": [ - "bfba220f4799db5ac19700df083cd8896d1fa356", - [ - "bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "wrong-service-in-services-member.https.window.js": [ - "352437d0e5a48f56572c78296ef65b7fcc73dc32", - [ - "bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "cross-origin-iframe.sub.https.window.js": [ - "d802a862791e98e5a8694e34bd4fbaf554b9f9b5", - [ - "bluetooth/requestDevice/cross-origin-iframe.sub.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + } ] - } - ] - ], - "discovery-succeeds.https.window.js": [ - "4941d185cad0508069184bc19c0ad81871e2a301", - [ - "bluetooth/requestDevice/discovery-succeeds.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-garbage-collection-ran-during-error.https.window.js": [ + "c964781ab44634e0677e5ce46ac5d5b816dff0be", + [ + "bluetooth/legacy/service/getCharacteristics/gen-garbage-collection-ran-during-error.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "doesnt-consume-user-gesture.https.window.js": [ - "9c742733e1d793d9becda42d8afd245f7c9b633d", - [ - "bluetooth/requestDevice/doesnt-consume-user-gesture.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-get-same-object-with-uuid.https.window.js": [ + "64b53f4eb31f0740e0f5c8c591c183ded92ffa79", + [ + "bluetooth/legacy/service/getCharacteristics/gen-get-same-object-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "filter-matches.https.window.js": [ - "1a0f52ac309b1ff116297ae86c27fc3008060cdb", - [ - "bluetooth/requestDevice/filter-matches.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-get-same-object.https.window.js": [ + "6aad17c1e689e7f910698a84f3505226dc77deff", + [ + "bluetooth/legacy/service/getCharacteristics/gen-get-same-object.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "le-not-supported.https.window.js": [ - "c961ab4492c42e0d62c599580b07e87c3f336040", - [ - "bluetooth/requestDevice/le-not-supported.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-invalid-characteristic-name.https.window.js": [ + "c7d439e13affcbac37a872023cd76738a922dd13", + [ + "bluetooth/legacy/service/getCharacteristics/gen-invalid-characteristic-name.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "manufacturer-data-filter-matches.https.window.js": [ - "c4c0e805328a5aa52ff21025e0ad56e0517cce7e", - [ - "bluetooth/requestDevice/manufacturer-data-filter-matches.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-reconnect-during-with-uuid.https.window.js": [ + "db373fbca1581019eada6740e49c0e8fc624ea94", + [ + "bluetooth/legacy/service/getCharacteristics/gen-reconnect-during-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "name-empty-device-from-name-empty-filter.https.window.js": [ - "2ff22cb70200809e5cbaf7dc8ac63bbf4f2f3c92", - [ - "bluetooth/requestDevice/name-empty-device-from-name-empty-filter.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-reconnect-during.https.window.js": [ + "8b3ba7cc6baa1f6f3a37536aeb51fd066a682da0", + [ + "bluetooth/legacy/service/getCharacteristics/gen-reconnect-during.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "not-processing-user-gesture.https.window.js": [ - "a063b61163019336cfe3e776ed14b8dc54aea227", - [ - "bluetooth/requestDevice/not-processing-user-gesture.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-service-is-removed-with-uuid.https.window.js": [ + "2d4db52822d7e44e50a38876747b989a4b5c5017", + [ + "bluetooth/legacy/service/getCharacteristics/gen-service-is-removed-with-uuid.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "radio-not-present.https.window.js": [ - "b55d63c6ff45fa30f973facc43de58f560a2f28c", - [ - "bluetooth/requestDevice/radio-not-present.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] + ], + "gen-service-is-removed.https.window.js": [ + "f922b45cdcca6844772681663fb303f3ba430051", + [ + "bluetooth/legacy/service/getCharacteristics/gen-service-is-removed.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/gc.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-test.js" + ], + [ + "script", + "/bluetooth/resources/bluetooth-fake-devices.js" + ] + ] + } ] - } - ] - ], - "reject_opaque_origin.https.html": [ - "df348dd39e0b62cb38605b94e0c98e4e155c1dbc", - [ - null, - {} - ] - ], - "request-from-iframe.https.window.js": [ - "d3f3cf897ff6f4eb97253f63843db888824a54fa", - [ - "bluetooth/requestDevice/request-from-iframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "request-from-sandboxed-iframe.https.window.js": [ - "2101cf0d6b747836f60d04c07774e3a100efed1f", - [ - "bluetooth/requestDevice/request-from-sandboxed-iframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "same-device.https.window.js": [ - "41a42cf4c8fd70c10c096c50733d9a517b77f54b", - [ - "bluetooth/requestDevice/same-device.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "sandboxed_iframe.https.window.js": [ - "e9192a9305b14763d3cabe7c6ddfb3b38f1015da", - [ - "bluetooth/requestDevice/sandboxed_iframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "single-filter-single-service.https.window.js": [ - "67afad0b930c7930614f3ed17a0db78e1aa20d69", - [ - "bluetooth/requestDevice/single-filter-single-service.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "requestLEScan": { - "reject_opaque_origin.https.html": [ - "272c5aa760cf7f5bedc24e2d652d68164ab353d3", - [ - null, - {} - ] - ], - "sandboxed_iframe.https.window.js": [ - "32d1e74b778d9932b5104824b69cf21cf6a3ff6b", - [ - "bluetooth/requestLEScan/sandboxed_iframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "server": { - "connect": { - "connection-succeeds.https.window.js": [ - "90b62b9265b1c337f05993f7169c9bd33cf6e962", - [ - "bluetooth/server/connect/connection-succeeds.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } ] - ], - "detachedIframe.https.window.js": [ - "2332cef7070baddc84573120edb0f0dc1fc83efa", - [ - "bluetooth/server/connect/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "garbage-collection-ran-during-success.https.window.js": [ - "2d2211dec30f87a988acf24fc4a283ed174405f8", - [ - "bluetooth/server/connect/garbage-collection-ran-during-success.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "get-same-gatt-server.https.window.js": [ - "59d7243a65382cd3509f425bcf6db9087c49c74f", - [ - "bluetooth/server/connect/get-same-gatt-server.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "device-same-object.https.window.js": [ - "f9a66d9b6915cf9b093ffafb6cb7fe11b3febf88", - [ - "bluetooth/server/device-same-object.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "disconnect": { - "connect-disconnect-twice.https.window.js": [ - "5d9908df4c8ac20d5fbea9966ff56b13a3b19de9", - [ - "bluetooth/server/disconnect/connect-disconnect-twice.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "detach-gc.https.window.js": [ - "b934b3797325a255b77e5cf39011ab2803bbb90b", - [ - "bluetooth/server/disconnect/detach-gc.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "detachedIframe.https.window.js": [ - "04e0ca0117fcc2974e02bde54802ee8d279e234a", - [ - "bluetooth/server/disconnect/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "disconnect-twice-in-a-row.https.window.js": [ - "acca9796d5751d2e5c3fa73e2cd32bcd8ba31bda", - [ - "bluetooth/server/disconnect/disconnect-twice-in-a-row.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gc-detach.https.window.js": [ - "1c062a775903bf0396a33592231851e2da2b7660", - [ - "bluetooth/server/disconnect/gc-detach.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "getPrimaryService": { - "gen-disconnect-called-before.https.window.js": [ - "631545a38542689762605f53af4ed7a7753a9134", - [ - "bluetooth/server/getPrimaryService/gen-disconnect-called-before.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-called-during-error.https.window.js": [ - "bcf19665d5fcf2cd720717f3f602f9d9795a6a33", - [ - "bluetooth/server/getPrimaryService/gen-disconnect-called-during-error.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-called-during-success.https.window.js": [ - "0d2fc1044a5bbb4c205741db61a3946d5b37c724", - [ - "bluetooth/server/getPrimaryService/gen-disconnect-called-during-success.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-discovery-timeout.https.window.js": [ - "03b0c9d0f382c3462beed1ee282321a7d91d94f1", - [ - "bluetooth/server/getPrimaryService/gen-disconnect-discovery-timeout.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-invalidates-objects.https.window.js": [ - "56468b24eabf2d99a3f4a10eef7cdbc0c2594ebc", - [ - "bluetooth/server/getPrimaryService/gen-disconnect-invalidates-objects.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnected-device.https.window.js": [ - "741b2db5ee82e8f268fca71143fd419bda0af87b", - [ - "bluetooth/server/getPrimaryService/gen-disconnected-device.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-discovery-complete-no-permission-absent-service.https.window.js": [ - "e2f5c87630559a7a5fef08bf37b68e84d3356648", - [ - "bluetooth/server/getPrimaryService/gen-discovery-complete-no-permission-absent-service.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-discovery-complete-service-not-found.https.window.js": [ - "8e9166b41a140832ccc121b6ec63415fccb5bbca", - [ - "bluetooth/server/getPrimaryService/gen-discovery-complete-service-not-found.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-garbage-collection-ran-during-error.https.window.js": [ - "df182fe8fff6b3001d355fe4c70b67b9b64bdc56", - [ - "bluetooth/server/getPrimaryService/gen-garbage-collection-ran-during-error.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-garbage-collection-ran-during-success.https.window.js": [ - "8e278af224234f1ab005e52cfff0fafcfe729537", - [ - "bluetooth/server/getPrimaryService/gen-garbage-collection-ran-during-success.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-get-different-service-after-reconnection.https.window.js": [ - "d4557f67535001a64a0b7347e336f95db547fe6c", - [ - "bluetooth/server/getPrimaryService/gen-get-different-service-after-reconnection.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-get-same-object.https.window.js": [ - "b43cefb567f01d0b7cdb8b53bc3da40e785fe007", - [ - "bluetooth/server/getPrimaryService/gen-get-same-object.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-invalid-service-name.https.window.js": [ - "cf4ab6c665d6a9605507b01e1e0c3e1a807376ba", - [ - "bluetooth/server/getPrimaryService/gen-invalid-service-name.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-no-permission-absent-service.https.window.js": [ - "3466ded4f9e910d30c3f5a55dd3e1172addeb3d8", - [ - "bluetooth/server/getPrimaryService/gen-no-permission-absent-service.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-no-permission-for-any-service.https.window.js": [ - "6576ef20a3de120529c4bf2997b13b40d7ce3f26", - [ - "bluetooth/server/getPrimaryService/gen-no-permission-for-any-service.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-no-permission-present-service.https.window.js": [ - "3d0b460bc33b9e246dfa59d30248edefd7d13d6a", - [ - "bluetooth/server/getPrimaryService/gen-no-permission-present-service.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-service-not-found.https.window.js": [ - "6e0d2c446ba90199f1bab1158e6147ed632deda6", - [ - "bluetooth/server/getPrimaryService/gen-service-not-found.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "service-found.https.window.js": [ - "b8a930d10c79b345f7a0c6c6ec9d89b095dccec4", - [ - "bluetooth/server/getPrimaryService/service-found.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "two-iframes-from-same-origin.https.window.js": [ - "b7f23a14913914d3e3bc2f57b98b2b1cc91a185c", - [ - "bluetooth/server/getPrimaryService/two-iframes-from-same-origin.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "getPrimaryServices": { - "blocklisted-services-with-uuid.https.window.js": [ - "ccc913e5bfdc7df6efe6627dc97899e12f981660", - [ - "bluetooth/server/getPrimaryServices/blocklisted-services-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "blocklisted-services.https.window.js": [ - "ae6be9099466b725521e54bec72013bcf175762a", - [ - "bluetooth/server/getPrimaryServices/blocklisted-services.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "correct-services.https.window.js": [ - "f3d883dd2ef181ca7c7a88999a9620056a42f046", - [ - "bluetooth/server/getPrimaryServices/correct-services.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-called-before-with-uuid.https.window.js": [ - "21b561375dfed914f011a4de18148053087a6c4f", - [ - "bluetooth/server/getPrimaryServices/gen-disconnect-called-before-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-called-before.https.window.js": [ - "8e5fea83ab4e53299ed6f5c78bd5d0322d2cf410", - [ - "bluetooth/server/getPrimaryServices/gen-disconnect-called-before.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-called-during-error-with-uuid.https.window.js": [ - "5c28716b90bf32e0e25e5e16ac37fc085f50fb9a", - [ - "bluetooth/server/getPrimaryServices/gen-disconnect-called-during-error-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-called-during-error.https.window.js": [ - "ddc31247911d64f1995cdae41af9da15a11bb890", - [ - "bluetooth/server/getPrimaryServices/gen-disconnect-called-during-error.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-called-during-success-with-uuid.https.window.js": [ - "13e3806d313e40ffc1d69503ad9ebb18cf4630ba", - [ - "bluetooth/server/getPrimaryServices/gen-disconnect-called-during-success-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-called-during-success.https.window.js": [ - "d6b31936c60a9a17af6a4764ac16b7580b3649a9", - [ - "bluetooth/server/getPrimaryServices/gen-disconnect-called-during-success.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-discovery-timeout-with-uuid.https.window.js": [ - "77f7bc81d99cc2f0b7f72e5a5866d0d89e625dce", - [ - "bluetooth/server/getPrimaryServices/gen-disconnect-discovery-timeout-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-discovery-timeout.https.window.js": [ - "ea55b7b495259c58027ac24be4b918585cb44fed", - [ - "bluetooth/server/getPrimaryServices/gen-disconnect-discovery-timeout.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-invalidates-objects-with-uuid.https.window.js": [ - "8cdb83e3ad7a2fea327c45b67388082c4e58e09e", - [ - "bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnect-invalidates-objects.https.window.js": [ - "9fd536f05161e0582e88ecbf2f5987a92214a4ba", - [ - "bluetooth/server/getPrimaryServices/gen-disconnect-invalidates-objects.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnected-device-with-uuid.https.window.js": [ - "e0393d5e69ca867e09b049576c33efbbc397866d", - [ - "bluetooth/server/getPrimaryServices/gen-disconnected-device-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-disconnected-device.https.window.js": [ - "87d74c6ab14083fdd6ed32aa74d01e5b1206b53d", - [ - "bluetooth/server/getPrimaryServices/gen-disconnected-device.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-discovery-complete-no-permission-absent-service-with-uuid.https.window.js": [ - "6e179dc5d9a373a6a10c17a8083116e464264658", - [ - "bluetooth/server/getPrimaryServices/gen-discovery-complete-no-permission-absent-service-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-discovery-complete-service-not-found-with-uuid.https.window.js": [ - "66cfb491c078d7ca378cb4418d399a0b33a9d07b", - [ - "bluetooth/server/getPrimaryServices/gen-discovery-complete-service-not-found-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-garbage-collection-ran-during-error-with-uuid.https.window.js": [ - "a235cf5d189bebdaf2d8e6b04e5796075fb34098", - [ - "bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-error-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-garbage-collection-ran-during-error.https.window.js": [ - "f174d4aef98dbe1fb3fa148992cab34b8a475263", - [ - "bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-error.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-garbage-collection-ran-during-success-with-uuid.https.window.js": [ - "cf5dfb246fbd12ef3a4597926cdbf877bae2cc4a", - [ - "bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-success-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-garbage-collection-ran-during-success.https.window.js": [ - "f1c080a9463b79462bab70dbe611ee01ea6880b8", - [ - "bluetooth/server/getPrimaryServices/gen-garbage-collection-ran-during-success.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-get-different-service-after-reconnection-with-uuid.https.window.js": [ - "2e40d580f3399ddccd7b84d60f9ffa87b0fb2d51", - [ - "bluetooth/server/getPrimaryServices/gen-get-different-service-after-reconnection-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-get-different-service-after-reconnection.https.window.js": [ - "ee1fc971bfa942e4f0c204acb80b055f311dc611", - [ - "bluetooth/server/getPrimaryServices/gen-get-different-service-after-reconnection.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-get-same-object-with-uuid.https.window.js": [ - "b589056a23a9e67ad9673713bab2cd2e93c1b8f9", - [ - "bluetooth/server/getPrimaryServices/gen-get-same-object-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-get-same-object.https.window.js": [ - "63739add912351f1da86a4cfdcd02d4cfd8567fa", - [ - "bluetooth/server/getPrimaryServices/gen-get-same-object.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-invalid-service-name.https.window.js": [ - "a9b1262e6a181d1017ead79b1972ecd85e942098", - [ - "bluetooth/server/getPrimaryServices/gen-invalid-service-name.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-no-permission-absent-service-with-uuid.https.window.js": [ - "27ad9f008ee0d296dcbcf1c27199ce11a45e6fdd", - [ - "bluetooth/server/getPrimaryServices/gen-no-permission-absent-service-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-no-permission-for-any-service-with-uuid.https.window.js": [ - "d5f06c23da6660566fbbbdbf8a5dccaaa14904fe", - [ - "bluetooth/server/getPrimaryServices/gen-no-permission-for-any-service-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-no-permission-for-any-service.https.window.js": [ - "8aa730d2ed2d8de1868d705e026a6a8a2376ee27", - [ - "bluetooth/server/getPrimaryServices/gen-no-permission-for-any-service.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-no-permission-present-service-with-uuid.https.window.js": [ - "a2047a0e8f0e2236cc968b309aa5340ee5b97a90", - [ - "bluetooth/server/getPrimaryServices/gen-no-permission-present-service-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-service-not-found-with-uuid.https.window.js": [ - "a2db1edc4b9f30d73b39eb530894983323135090", - [ - "bluetooth/server/getPrimaryServices/gen-service-not-found-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "services-found-with-uuid.https.window.js": [ - "972e6a75caa3f21935abe9b504d0bccf5249c6a1", - [ - "bluetooth/server/getPrimaryServices/services-found-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "services-found.https.window.js": [ - "46861175c605d4e2d966df8751d709530f411f02", - [ - "bluetooth/server/getPrimaryServices/services-found.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "services-not-found.https.window.js": [ - "63503282411b80eba908b91e72ea7a0946945019", - [ - "bluetooth/server/getPrimaryServices/services-not-found.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - } - }, - "service": { - "detachedIframe.https.window.js": [ - "f75fc225a791b57bff086fa8acad026521e22ce4", - [ - "bluetooth/service/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "device-same-from-2-services.https.window.js": [ - "5b2ba310d356d3eb4f7c0f76ac992bb2f8056034", - [ - "bluetooth/service/device-same-from-2-services.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "device-same-object.https.window.js": [ - "97da769a9eac25b55e72ac9e44d6c3cf1442ec3a", - [ - "bluetooth/service/device-same-object.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "getCharacteristic": { - "characteristic-found.https.window.js": [ - "807852ae133c0f024925faaee88309b9f585ea47", - [ - "bluetooth/service/getCharacteristic/characteristic-found.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "detachedIframe.https.window.js": [ - "ea8c96160ff9dfa2498fd9d51f167ddc80e4aa6a", - [ - "bluetooth/service/getCharacteristic/detachedIframe.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-blocklisted-characteristic.https.window.js": [ - "cce302d6504f51db4d67553d8f57b915d5ffc645", - [ - "bluetooth/service/getCharacteristic/gen-blocklisted-characteristic.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-characteristic-not-found.https.window.js": [ - "2ed48eb5c68798e402193ca195c74c86dbf8909e", - [ - "bluetooth/service/getCharacteristic/gen-characteristic-not-found.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-garbage-collection-ran-during-error.https.window.js": [ - "1fd70c8fad4b454cb0687d48645117edb801c4de", - [ - "bluetooth/service/getCharacteristic/gen-garbage-collection-ran-during-error.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-get-same-object.https.window.js": [ - "c5176cdc5e0a7a310c60e1d4ed15b07dbeb5e7bb", - [ - "bluetooth/service/getCharacteristic/gen-get-same-object.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-invalid-characteristic-name.https.window.js": [ - "da0f5bda28080f7486e95a3f14ee1f8838c3bc62", - [ - "bluetooth/service/getCharacteristic/gen-invalid-characteristic-name.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-reconnect-during.https.window.js": [ - "8801c152e931ef3e631cc7ec649c83254c59b3a2", - [ - "bluetooth/service/getCharacteristic/gen-reconnect-during.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-service-is-removed.https.window.js": [ - "bfeb318c46ea54136137f390adaae0a7322dd827", - [ - "bluetooth/service/getCharacteristic/gen-service-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] - }, - "getCharacteristics": { - "blocklisted-characteristics.https.window.js": [ - "408943585ab86eb3ed73454f82b862820a469aa8", - [ - "bluetooth/service/getCharacteristics/blocklisted-characteristics.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "characteristics-found-with-uuid.https.window.js": [ - "f11c69c92e7aed8b177c255a071ef9b3af918a4e", - [ - "bluetooth/service/getCharacteristics/characteristics-found-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "characteristics-found.https.window.js": [ - "3244dd3e173d233b65db3ede450464fbc763a531", - [ - "bluetooth/service/getCharacteristics/characteristics-found.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "characteristics-not-found.https.window.js": [ - "5b0c1896d64f01b83349a9152cc561ac0b435438", - [ - "bluetooth/service/getCharacteristics/characteristics-not-found.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-blocklisted-characteristic-with-uuid.https.window.js": [ - "79cd01032b580debd840d885c350d44aa7b5e974", - [ - "bluetooth/service/getCharacteristics/gen-blocklisted-characteristic-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-characteristic-not-found-with-uuid.https.window.js": [ - "8a5e2ab4e4ac8e1534f0ccb3666fe5ee71645ec9", - [ - "bluetooth/service/getCharacteristics/gen-characteristic-not-found-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-garbage-collection-ran-during-error-with-uuid.https.window.js": [ - "683b93e352d0e59fce29c48585d419febd850fb6", - [ - "bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-garbage-collection-ran-during-error.https.window.js": [ - "c964781ab44634e0677e5ce46ac5d5b816dff0be", - [ - "bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-get-same-object-with-uuid.https.window.js": [ - "64b53f4eb31f0740e0f5c8c591c183ded92ffa79", - [ - "bluetooth/service/getCharacteristics/gen-get-same-object-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-get-same-object.https.window.js": [ - "6aad17c1e689e7f910698a84f3505226dc77deff", - [ - "bluetooth/service/getCharacteristics/gen-get-same-object.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-invalid-characteristic-name.https.window.js": [ - "c7d439e13affcbac37a872023cd76738a922dd13", - [ - "bluetooth/service/getCharacteristics/gen-invalid-characteristic-name.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-reconnect-during-with-uuid.https.window.js": [ - "db373fbca1581019eada6740e49c0e8fc624ea94", - [ - "bluetooth/service/getCharacteristics/gen-reconnect-during-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-reconnect-during.https.window.js": [ - "8b3ba7cc6baa1f6f3a37536aeb51fd066a682da0", - [ - "bluetooth/service/getCharacteristics/gen-reconnect-during.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-service-is-removed-with-uuid.https.window.js": [ - "2d4db52822d7e44e50a38876747b989a4b5c5017", - [ - "bluetooth/service/getCharacteristics/gen-service-is-removed-with-uuid.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ], - "gen-service-is-removed.https.window.js": [ - "f922b45cdcca6844772681663fb303f3ba430051", - [ - "bluetooth/service/getCharacteristics/gen-service-is-removed.https.window.html", - { - "script_metadata": [ - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "/common/gc.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-test.js" - ], - [ - "script", - "/bluetooth/resources/bluetooth-fake-devices.js" - ] - ] - } - ] - ] + } } } }, @@ -457263,6 +457279,15 @@ ] }, "clear-site-data": { + "clear-cache.https.html": [ + "8cdaf2a55271987943dfb25a37d98295068b57b2", + [ + null, + { + "testdriver": true + } + ] + ], "executionContexts.sub.html": [ "b3ae17576a3b09fe576c24d8d454b5ef504832a8", [ @@ -470625,7 +470650,7 @@ ] ], "cookieListItem_attributes.https.any.js": [ - "200cbd06928ff27d2574103fd82f0ae610dff5a4", + "6716d91788db746765593a2a95d34e1ecbb4e3a5", [ "cookie-store/cookieListItem_attributes.https.any.html", { @@ -470781,7 +470806,7 @@ ] ], "cookieStore_delete_arguments.https.any.js": [ - "ddae23888f4f2a7ff203b4189afeb1ced11b0a3d", + "37a551b3a9f2511d915bb06b4d2311e3e7979ae2", [ "cookie-store/cookieStore_delete_arguments.https.any.html", { @@ -470973,6 +470998,24 @@ } ] ], + "cookieStore_getAll_set_creation_url.https.any.js": [ + "d09c4aad4f87712afd70faf8111ee21f88d5f1a8", + [ + "cookie-store/cookieStore_getAll_set_creation_url.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.set()/getAll() with Document URL changing" + ], + [ + "global", + "window" + ] + ] + } + ] + ], "cookieStore_get_arguments.https.any.js": [ "d6ea0edef6a3d4e0cc69d4455d6672ddd433deda", [ @@ -471086,6 +471129,24 @@ } ] ], + "cookieStore_get_set_creation_url.https.any.js": [ + "71f8108095f0e78518f73f5086eb0d2d4dee1253", + [ + "cookie-store/cookieStore_get_set_creation_url.https.any.html", + { + "script_metadata": [ + [ + "title", + "Cookie Store API: cookieStore.set()/get() with Document URL changing" + ], + [ + "global", + "window" + ] + ] + } + ] + ], "cookieStore_get_set_creation_url.sub.https.html": [ "216885298a58829d64653d7e1947fe3e6ec52012", [ @@ -471141,7 +471202,7 @@ ] ], "cookieStore_set_arguments.https.any.js": [ - "8ff66bf7772f22076360fda0b735a7894ed6ad8d", + "064fcc5de529f42c78b853f66f1a5e2f56e6ac01", [ "cookie-store/cookieStore_set_arguments.https.any.html", { @@ -479998,14 +480059,14 @@ ] ], "at-container-parsing.html": [ - "79250dfde066dd96362b773b944a8a4fde2a2906", + "f76e7988a3dee2aee8d20ba2e5cb747218f5cde4", [ null, {} ] ], "at-container-serialization.html": [ - "dbe9ea023e885c3446ba05063f0a005542ea05ed", + "b0c9746e0cc1359f8eea031399374d310f7ec140", [ null, {} @@ -613459,6 +613520,15 @@ {} ] ], + "reporting-subresource-corp.tentative.https.html": [ + "0530956080bb3d027fc1f88ed23572f0e7b9ba02", + [ + null, + { + "timeout": "long" + } + ] + ], "service-worker-coep-credentialless-proxy.https.tentative.window.js": [ "e12c660f7b42f16604bbd3394386876069a4998c", [ @@ -626491,6 +626561,15 @@ } ] ], + "select-click-drag-option.tentative.html": [ + "748c4a92304df58be415a9992c1ac3cd6ca11176", + [ + null, + { + "testdriver": true + } + ] + ], "select-datalist-options-idl.tentative.html": [ "e00fb1951d499a276f15f74c6bd288d79333fa7a", [ @@ -628146,7 +628225,7 @@ ] }, "popovers": { - "button-type-reset-popovertarget.tentative.html": [ + "button-type-reset-popovertarget.html": [ "975eab0d66eabd7216c51a999d87a0cd145898b4", [ null, @@ -628240,7 +628319,7 @@ ] ], "popover-attribute-basic.html": [ - "f13a05288c3e03acf219810022f623ba27793998", + "067ce18f6a0b8ccae75c8a774c5a70243a555b32", [ null, { @@ -628382,7 +628461,7 @@ } ] ], - "popover-invoking-attribute-hint.tentative.html": [ + "popover-invoking-attribute-hint.html": [ "b531ddc460e83ac57e6716686b1ffae353625d5f", [ null, @@ -628420,7 +628499,7 @@ } ] ], - "popover-light-dismiss-hint.tentative.html": [ + "popover-light-dismiss-hint.html": [ "f07363115fba687ef97308fe515abf1c373497ab", [ null, @@ -628614,7 +628693,7 @@ } ] ], - "popover-top-layer-nesting-hints.tentative.html": [ + "popover-top-layer-nesting-hints.html": [ "4ec1f49bda9fbd2f61a1e0bc7a719de1143699e8", [ null, @@ -628632,7 +628711,7 @@ } ] ], - "popover-types-with-hints.tentative.html": [ + "popover-types-with-hints.html": [ "07f0e26fce71b922385d804e5ce5d56ac3af95b3", [ null, @@ -653858,6 +653937,13 @@ {} ] ], + "content-encoding.https.html": [ + "5450b5913bd561613a210885284e5d1531ae0793", + [ + "navigation-timing/content-encoding.https.html?pipe=gzip", + {} + ] + ], "dom-interactive-image-document.html": [ "36742f0eff6d07c7c0694b066dfa017f0d1042be", [ @@ -655789,9 +655875,9 @@ ] ], "partitioned-popins.partitions.tentative.https.window.js": [ - "0f1a7c0a6e0c91793d015150124bc0059400a791", + "ed664f71e105a14b7cc3f002340796ca2928d936", [ - "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html", + "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html?include=variant-1-test", { "script_metadata": [ [ @@ -655816,9 +655902,897 @@ ], [ "script", + "/common/subset-tests-by-key.js" + ], + [ + "script", "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" ], [ + "variant", + "?include=variant-1-test" + ], + [ + "variant", + "?include=variant-2-test" + ], + [ + "variant", + "?include=variant-3-test" + ], + [ + "variant", + "?include=variant-4-test" + ], + [ + "variant", + "?include=variant-5-test" + ], + [ + "variant", + "?include=variant-6-test" + ], + [ + "variant", + "?include=variant-7-test" + ], + [ + "variant", + "?include=variant-8-test" + ], + [ + "variant", + "?include=variant-9-test" + ], + [ + "variant", + "?include=variant-10-test" + ], + [ + "variant", + "?include=variant-11-test" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html?include=variant-10-test", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "variant", + "?include=variant-1-test" + ], + [ + "variant", + "?include=variant-2-test" + ], + [ + "variant", + "?include=variant-3-test" + ], + [ + "variant", + "?include=variant-4-test" + ], + [ + "variant", + "?include=variant-5-test" + ], + [ + "variant", + "?include=variant-6-test" + ], + [ + "variant", + "?include=variant-7-test" + ], + [ + "variant", + "?include=variant-8-test" + ], + [ + "variant", + "?include=variant-9-test" + ], + [ + "variant", + "?include=variant-10-test" + ], + [ + "variant", + "?include=variant-11-test" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html?include=variant-11-test", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "variant", + "?include=variant-1-test" + ], + [ + "variant", + "?include=variant-2-test" + ], + [ + "variant", + "?include=variant-3-test" + ], + [ + "variant", + "?include=variant-4-test" + ], + [ + "variant", + "?include=variant-5-test" + ], + [ + "variant", + "?include=variant-6-test" + ], + [ + "variant", + "?include=variant-7-test" + ], + [ + "variant", + "?include=variant-8-test" + ], + [ + "variant", + "?include=variant-9-test" + ], + [ + "variant", + "?include=variant-10-test" + ], + [ + "variant", + "?include=variant-11-test" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html?include=variant-2-test", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "variant", + "?include=variant-1-test" + ], + [ + "variant", + "?include=variant-2-test" + ], + [ + "variant", + "?include=variant-3-test" + ], + [ + "variant", + "?include=variant-4-test" + ], + [ + "variant", + "?include=variant-5-test" + ], + [ + "variant", + "?include=variant-6-test" + ], + [ + "variant", + "?include=variant-7-test" + ], + [ + "variant", + "?include=variant-8-test" + ], + [ + "variant", + "?include=variant-9-test" + ], + [ + "variant", + "?include=variant-10-test" + ], + [ + "variant", + "?include=variant-11-test" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html?include=variant-3-test", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "variant", + "?include=variant-1-test" + ], + [ + "variant", + "?include=variant-2-test" + ], + [ + "variant", + "?include=variant-3-test" + ], + [ + "variant", + "?include=variant-4-test" + ], + [ + "variant", + "?include=variant-5-test" + ], + [ + "variant", + "?include=variant-6-test" + ], + [ + "variant", + "?include=variant-7-test" + ], + [ + "variant", + "?include=variant-8-test" + ], + [ + "variant", + "?include=variant-9-test" + ], + [ + "variant", + "?include=variant-10-test" + ], + [ + "variant", + "?include=variant-11-test" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html?include=variant-4-test", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "variant", + "?include=variant-1-test" + ], + [ + "variant", + "?include=variant-2-test" + ], + [ + "variant", + "?include=variant-3-test" + ], + [ + "variant", + "?include=variant-4-test" + ], + [ + "variant", + "?include=variant-5-test" + ], + [ + "variant", + "?include=variant-6-test" + ], + [ + "variant", + "?include=variant-7-test" + ], + [ + "variant", + "?include=variant-8-test" + ], + [ + "variant", + "?include=variant-9-test" + ], + [ + "variant", + "?include=variant-10-test" + ], + [ + "variant", + "?include=variant-11-test" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html?include=variant-5-test", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "variant", + "?include=variant-1-test" + ], + [ + "variant", + "?include=variant-2-test" + ], + [ + "variant", + "?include=variant-3-test" + ], + [ + "variant", + "?include=variant-4-test" + ], + [ + "variant", + "?include=variant-5-test" + ], + [ + "variant", + "?include=variant-6-test" + ], + [ + "variant", + "?include=variant-7-test" + ], + [ + "variant", + "?include=variant-8-test" + ], + [ + "variant", + "?include=variant-9-test" + ], + [ + "variant", + "?include=variant-10-test" + ], + [ + "variant", + "?include=variant-11-test" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html?include=variant-6-test", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "variant", + "?include=variant-1-test" + ], + [ + "variant", + "?include=variant-2-test" + ], + [ + "variant", + "?include=variant-3-test" + ], + [ + "variant", + "?include=variant-4-test" + ], + [ + "variant", + "?include=variant-5-test" + ], + [ + "variant", + "?include=variant-6-test" + ], + [ + "variant", + "?include=variant-7-test" + ], + [ + "variant", + "?include=variant-8-test" + ], + [ + "variant", + "?include=variant-9-test" + ], + [ + "variant", + "?include=variant-10-test" + ], + [ + "variant", + "?include=variant-11-test" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html?include=variant-7-test", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "variant", + "?include=variant-1-test" + ], + [ + "variant", + "?include=variant-2-test" + ], + [ + "variant", + "?include=variant-3-test" + ], + [ + "variant", + "?include=variant-4-test" + ], + [ + "variant", + "?include=variant-5-test" + ], + [ + "variant", + "?include=variant-6-test" + ], + [ + "variant", + "?include=variant-7-test" + ], + [ + "variant", + "?include=variant-8-test" + ], + [ + "variant", + "?include=variant-9-test" + ], + [ + "variant", + "?include=variant-10-test" + ], + [ + "variant", + "?include=variant-11-test" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html?include=variant-8-test", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "variant", + "?include=variant-1-test" + ], + [ + "variant", + "?include=variant-2-test" + ], + [ + "variant", + "?include=variant-3-test" + ], + [ + "variant", + "?include=variant-4-test" + ], + [ + "variant", + "?include=variant-5-test" + ], + [ + "variant", + "?include=variant-6-test" + ], + [ + "variant", + "?include=variant-7-test" + ], + [ + "variant", + "?include=variant-8-test" + ], + [ + "variant", + "?include=variant-9-test" + ], + [ + "variant", + "?include=variant-10-test" + ], + [ + "variant", + "?include=variant-11-test" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "partitioned-popins/partitioned-popins.partitions.tentative.https.window.html?include=variant-9-test", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "variant", + "?include=variant-1-test" + ], + [ + "variant", + "?include=variant-2-test" + ], + [ + "variant", + "?include=variant-3-test" + ], + [ + "variant", + "?include=variant-4-test" + ], + [ + "variant", + "?include=variant-5-test" + ], + [ + "variant", + "?include=variant-6-test" + ], + [ + "variant", + "?include=variant-7-test" + ], + [ + "variant", + "?include=variant-8-test" + ], + [ + "variant", + "?include=variant-9-test" + ], + [ + "variant", + "?include=variant-10-test" + ], + [ + "variant", + "?include=variant-11-test" + ], + [ "timeout", "long" ] @@ -658175,6 +659149,181 @@ } ] ], + "unload-allowed-headerless.tentative.window.js": [ + "12c9e1ee79a005140a7d8c5e0ab5498bc895acfd", + [ + "permissions-policy/experimental-features/unload-allowed-headerless.tentative.window.html?urlType=blank", + { + "script_metadata": [ + [ + "title", + "'unload' Policy : allowed in headerless doc when allowed in main frame." + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "script", + "./resources/unload-helper.js" + ], + [ + "variant", + "?urlType=srcdoc" + ], + [ + "variant", + "?urlType=data" + ], + [ + "variant", + "?urlType=blob" + ], + [ + "variant", + "?urlType=blank" + ] + ] + } + ], + [ + "permissions-policy/experimental-features/unload-allowed-headerless.tentative.window.html?urlType=blob", + { + "script_metadata": [ + [ + "title", + "'unload' Policy : allowed in headerless doc when allowed in main frame." + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "script", + "./resources/unload-helper.js" + ], + [ + "variant", + "?urlType=srcdoc" + ], + [ + "variant", + "?urlType=data" + ], + [ + "variant", + "?urlType=blob" + ], + [ + "variant", + "?urlType=blank" + ] + ] + } + ], + [ + "permissions-policy/experimental-features/unload-allowed-headerless.tentative.window.html?urlType=data", + { + "script_metadata": [ + [ + "title", + "'unload' Policy : allowed in headerless doc when allowed in main frame." + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "script", + "./resources/unload-helper.js" + ], + [ + "variant", + "?urlType=srcdoc" + ], + [ + "variant", + "?urlType=data" + ], + [ + "variant", + "?urlType=blob" + ], + [ + "variant", + "?urlType=blank" + ] + ] + } + ], + [ + "permissions-policy/experimental-features/unload-allowed-headerless.tentative.window.html?urlType=srcdoc", + { + "script_metadata": [ + [ + "title", + "'unload' Policy : allowed in headerless doc when allowed in main frame." + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "script", + "./resources/unload-helper.js" + ], + [ + "variant", + "?urlType=srcdoc" + ], + [ + "variant", + "?urlType=data" + ], + [ + "variant", + "?urlType=blob" + ], + [ + "variant", + "?urlType=blank" + ] + ] + } + ] + ], "unload-allowed-object.tentative.window.js": [ "376bb4cb1d06633a77df7b4c8248162455e3979b", [ @@ -658280,6 +659429,181 @@ } ] ], + "unload-disallowed-headerless.tentative.window.js": [ + "76af95f4257de168873ec14fe8bfe15deb97564b", + [ + "permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window.html?urlType=blank", + { + "script_metadata": [ + [ + "title", + "'unload' Policy : disallowed in headerless doc when disallowed in main frame." + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "script", + "./resources/unload-helper.js" + ], + [ + "variant", + "?urlType=srcdoc" + ], + [ + "variant", + "?urlType=data" + ], + [ + "variant", + "?urlType=blob" + ], + [ + "variant", + "?urlType=blank" + ] + ] + } + ], + [ + "permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window.html?urlType=blob", + { + "script_metadata": [ + [ + "title", + "'unload' Policy : disallowed in headerless doc when disallowed in main frame." + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "script", + "./resources/unload-helper.js" + ], + [ + "variant", + "?urlType=srcdoc" + ], + [ + "variant", + "?urlType=data" + ], + [ + "variant", + "?urlType=blob" + ], + [ + "variant", + "?urlType=blank" + ] + ] + } + ], + [ + "permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window.html?urlType=data", + { + "script_metadata": [ + [ + "title", + "'unload' Policy : disallowed in headerless doc when disallowed in main frame." + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "script", + "./resources/unload-helper.js" + ], + [ + "variant", + "?urlType=srcdoc" + ], + [ + "variant", + "?urlType=data" + ], + [ + "variant", + "?urlType=blob" + ], + [ + "variant", + "?urlType=blank" + ] + ] + } + ], + [ + "permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window.html?urlType=srcdoc", + { + "script_metadata": [ + [ + "title", + "'unload' Policy : disallowed in headerless doc when disallowed in main frame." + ], + [ + "script", + "/common/dispatcher/dispatcher.js" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js" + ], + [ + "script", + "./resources/unload-helper.js" + ], + [ + "variant", + "?urlType=srcdoc" + ], + [ + "variant", + "?urlType=data" + ], + [ + "variant", + "?urlType=blob" + ], + [ + "variant", + "?urlType=blank" + ] + ] + } + ] + ], "unload-disallowed-object.tentative.window.js": [ "33c23239e6d6fd3f7f578295da93adcdd07d9941", [ @@ -674872,6 +676196,13 @@ {} ] ], + "content-encoding.https.html": [ + "58ea76ed22b2c1655681c74b303b8f9d33b67a73", + [ + null, + {} + ] + ], "content-type-minimization.html": [ "d7dbc2cc9f3b6ae593ca39188f4a5848a4fcb56e", [ @@ -732299,7 +733630,7 @@ ] ], "per-frame-qp-encoding.https.any.js": [ - "8ec96c3f7035d4d02953dea5a2185fe63844df9a", + "c4c49d81e55bab3a4a9009a8970aeea6224cdd5c", [ "webcodecs/per-frame-qp-encoding.https.any.html?av1", { @@ -758650,7 +759981,7 @@ ] ], "tensor.https.any.js": [ - "582ecdb9d68bddf2905414827622ba91799b4943", + "0906ae96ba2c6ae5eb391c8484e8a42e2dbe0426", [ "webnn/conformance_tests/tensor.https.any.html?cpu", { @@ -760397,7 +761728,7 @@ ] ], "cast.https.any.js": [ - "0dee2f0f07104071ddb8baa959b09b488c4aeeee", + "2ad62125746159cdf0520873a9029edf06eea883", [ "webnn/validation_tests/cast.https.any.html?cpu", { @@ -760775,7 +762106,7 @@ ] ], "concat.https.any.js": [ - "6ccac4e7e8b5a311adc0b47cd85844bd2f7bae34", + "7a55e4f672f0480278c7fc376aa140f9dcd7fb99", [ "webnn/validation_tests/concat.https.any.html?cpu", { @@ -762098,7 +763429,7 @@ ] ], "dequantizeLinear.https.any.js": [ - "672fc4ac72456bfe8ca05cf908dba457819830b3", + "84c55ad8fe47a9c1aabec078c51b12427fcbc271", [ "webnn/validation_tests/dequantizeLinear.https.any.html?cpu", { @@ -762677,7 +764008,7 @@ ] ], "elementwise-binary.https.any.js": [ - "32777f84681a9e621993d78f4395a31b47a6272e", + "bdaf0939033102f7f7bbf213befb42bd1baa4c37", [ "webnn/validation_tests/elementwise-binary.https.any.html?cpu", { @@ -763433,7 +764764,7 @@ ] ], "expand.https.any.js": [ - "c9c60358917f8b961ea45adfa251744458b8fe51", + "c49bcac6583e70ca0b7c779362aa12823838d09d", [ "webnn/validation_tests/expand.https.any.html?cpu", { @@ -763622,7 +764953,7 @@ ] ], "gather.https.any.js": [ - "e4a46a90d4b363783bc9020074d8d261ff59a28b", + "f8ec307c89764cd4fe53a54e951cc7c072681cc3", [ "webnn/validation_tests/gather.https.any.html?cpu", { @@ -764000,7 +765331,7 @@ ] ], "gatherND.https.any.js": [ - "697dda00776404cbe8bba31de89907cabb389a64", + "41e9b6b7968fe499186ac0a5fe8541e0ff69bd8d", [ "webnn/validation_tests/gatherND.https.any.html?cpu", { @@ -764378,7 +765709,7 @@ ] ], "gemm.https.any.js": [ - "6115003d0392bbee3fb396052534f106bc6d86f2", + "4c106bc0180cb7fd91c38b881b5eb150c2874506", [ "webnn/validation_tests/gemm.https.any.html?cpu", { @@ -765323,7 +766654,7 @@ ] ], "input.https.any.js": [ - "cc60c44567046b2bf41ae50eb1d0fd732364dfb5", + "54f50b146cb33dfef1f87a1169f29d17b3ea6008", [ "webnn/validation_tests/input.https.any.html?cpu", { @@ -766835,7 +768166,7 @@ ] ], "matmul.https.any.js": [ - "86440e2b0f1c97585186fab868468abdc2762d47", + "8aba871f275ed17f63d4af82d27a54cbac647ae7", [ "webnn/validation_tests/matmul.https.any.html?cpu", { @@ -767024,7 +768355,7 @@ ] ], "pad.https.any.js": [ - "ca11bd2c9695a4783b1cda24ed9dc96b38523ea3", + "16d8afc1a1f3e62d5b334a2ba3e97c708941578f", [ "webnn/validation_tests/pad.https.any.html?cpu", { @@ -767834,7 +769165,7 @@ ] ], "quantizeLinear.https.any.js": [ - "8516e9cf8e0b4745d5837e9dc3f8a437b9d3301a", + "237960162448274335946dd8a683074892015a57", [ "webnn/validation_tests/quantizeLinear.https.any.html?cpu", { @@ -768401,7 +769732,7 @@ ] ], "resample2d.https.any.js": [ - "1278143d232f0594d876f17b2ac359946ba76a6c", + "d5cd1a4823dcb240b66add15c3acf5fca75135f8", [ "webnn/validation_tests/resample2d.https.any.html?cpu", { @@ -770669,7 +772000,7 @@ ] ], "tile.https.any.js": [ - "067335409178db5dc46e22b64f327b00a952bd68", + "1e5ac04e7c619d8abaa07720ce880be1dc6d63c9", [ "webnn/validation_tests/tile.https.any.html?cpu", { @@ -771455,7 +772786,7 @@ ] ], "where.https.any.js": [ - "424d080c009d325384c134d6095228ce79a80b31", + "9e2a10f6e0019859a06f41321d1ca08affdc47f7", [ "webnn/validation_tests/where.https.any.html?cpu", { @@ -773363,7 +774694,7 @@ ] ], "RTCRtpScriptTransform-encoded-transform.https.html": [ - "c935644f0c6f7e71b50cd241bebdea9cc92826e7", + "9eb7020a781c2d2715fcac3583e7142b50b1da2f", [ null, {
diff --git a/third_party/blink/web_tests/external/wpt/clear-site-data/clear-cache.https.html b/third_party/blink/web_tests/external/wpt/clear-site-data/clear-cache.https.html new file mode 100644 index 0000000..8cdaf2a5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/clear-site-data/clear-cache.https.html
@@ -0,0 +1,110 @@ +<!DOCTYPE html> +<body> +<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> + +// Here's the set-up for this test: +// Step 1 (main window) Open first window with first url putting some resource +// into the cache and maybe receiving clear-site-data header +// Step 2 (first window) Message first window with uuid +// Step 3 (main window) Open second window with second url +// Step 4 (second window) Message first window with uuid (either cached or non-cached) +// Optional Step 5 (main window) Open third window with third url +// Optional Step 6 (third window) Message first window with uuid (either cached or non-cached) +// Step 7 (main window): Assert first and last uuid not equal due to `clear-site-data: "cache"` header +function test_cache_clear(test, params1, params2, params3) { + let cache_helper = "cache_helper=" + self.crypto.randomUUID() + "&"; + let firstUrl = "/clear-site-data/support/clear-site-data-cache.py?" + cache_helper + params1 + let secondUrl = "/clear-site-data/support/clear-site-data-cache.py?" + cache_helper + params2; + let thirdUrl = params3 ? "/clear-site-data/support/clear-site-data-cache.py?" + cache_helper + params3 : null; + + return new Promise(resolve => { + window.addEventListener("message", test.step_func(e => { + // Result Step 2 + let firstUuid = e.data; + + window.addEventListener("message", test.step_func(e => { + // Result Step 4 + let secondUuid = e.data; + + if (thirdUrl === null) { + // Step 7, skipping the optional step 5 and 6 + assert_not_equals(firstUuid, secondUuid); + resolve(); + } else { + window.addEventListener("message", test.step_func(e => { + // Result Step 6 + let thirdUuid = e.data; + + // Step 7 + assert_not_equals(firstUuid, thirdUuid); + resolve(); + + }), {once: true}); + + // Step 5 + let third_window = window.open(thirdUrl); + test.add_cleanup(third_window.close); + } + + }), {once: true}); + + // Step 3 + let second_window = window.open(secondUrl); + test.add_cleanup(second_window.close); + }), {once: true}); + + // Step 1 + let first_window = window.open(firstUrl); + test.add_cleanup(first_window.close); + // tests are using cookies to differentiate between requests + test.add_cleanup(test_driver.delete_all_cookies) + }); +} + +promise_test(t => { + return test_cache_clear(t, "response=single_html&cache&clear_first=cache", "response=single_html&cache&clear_first=cache"); +}, "clear cache: Document with clear-cache header doesn't get cached"); + +promise_test(t => { + return test_cache_clear(t, "response=single_html&cache&clear_first=all", "response=single_html&cache&clear_first=all"); +}, "clear all: Document with clear-cache header doesn't get cached"); + +promise_test(t => { + return test_cache_clear(t, "response=html_embed_json&clear=cache", "response=html_embed_json&clear=cache"); +}, "clear cache: Fetch on docment with clear-cache header doesn't get cached"); + +promise_test(t => { + return test_cache_clear(t, "response=html_embed_json&clear=all", "response=html_embed_json&clear=all"); +}, "clear all: Fetch on docment with clear-cache header doesn't get cached"); + +promise_test(t => { + return test_cache_clear(t, "response=html_embed_json", "response=html_embed_json&clear=cache"); +}, "clear cache: Previously cached fetch gets cleared"); + +promise_test(t => { + return test_cache_clear(t, "response=html_embed_json", "response=html_embed_json&clear=all"); +}, "clear all: Previously cached fetch gets cleared"); + +promise_test(t => { + return test_cache_clear(t, "response=html_embed_json", "response=single_html&clear=cache", "response=html_embed_json"); +}, "clear cache: Clear fetch on intermediate navigation"); + +promise_test(t => { + return test_cache_clear(t, "response=html_embed_json", "response=single_html&clear=all", "response=html_embed_json"); +}, "clear all: Clear fetch on intermediate navigation"); + +promise_test(t => { + return test_cache_clear(t, "response=single_html&cache", "response=single_html&clear=cache", "response=single_html&cache"); +}, "clear cache: Clear document in intermediate load"); + +promise_test(t => { + return test_cache_clear(t, "response=single_html&cache", "response=single_html&clear=all", "response=single_html&cache"); +}, "clear all: Clear document in intermediate load"); + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/clear-site-data/support/clear-site-data-cache.py b/third_party/blink/web_tests/external/wpt/clear-site-data/support/clear-site-data-cache.py new file mode 100644 index 0000000..87107693 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/clear-site-data/support/clear-site-data-cache.py
@@ -0,0 +1,69 @@ +""" +Loaded in Step 2/4/Optional 6 (/clear-site-data/clear-cache.https.html) +Sending Message for Step 3/5/Optional 7 (/clear-site-data/clear-cache.https.html) +""" +import uuid + +def main(request, response): + # type of response: + # - "single_html": Main page html file with a different postMessage uuid on each response + # - "json": Json that always responds with a different uuid in a single-element array + # - "html_embed_json": Main page html that embeds a cachable version of the above json + response_type = request.GET.first(b"response") + + cache_helper = request.GET.first(b"cache_helper") + + # force enable caching when present or force disable if not + cache = b"cache" in request.GET + clear = None + if b"clear" in request.GET: + clear = request.GET.first(b"clear") + if b"clear_first" in request.GET: + if request.server.stash.take(cache_helper) is None: + clear = request.GET.first(b"clear_first") + request.server.stash.put(cache_helper, ()) + + headers = [] + if response_type == b"json": + headers += [(b"Content-Type", b"application/json")] + else: + headers += [(b"Content-Type", b"text/html")] + + if cache: + headers += [(b"cache-control", b"public, max-age=31536000, immutable")] + else: + headers += [(b"cache-control", b"no-store")] + + if clear is not None: + if clear == b"all": + headers += [(b"Clear-Site-Data", b'"*"')] + else: + headers += [(b"Clear-Site-Data", b'"' + clear + b'"')] + + if response_type == b"single_html": + # send unique UUID. Cache got cleared when uuids don't match. + content = f''' + <script> + window.opener.postMessage("{uuid.uuid4()}" , "*"); + </script> + <body> + {request.url} + </body>''' + elif response_type == b"json": + # send unique UUID. helper for below "html_embed_json" + content = f'''["{uuid.uuid4()}"]''' + elif response_type == b"html_embed_json": + url = request.url_parts.path + "?response=json&cache&cache_helper=" + cache_helper.decode() + content = f''' + <script> + fetch("{url}") + .then(response => response.json()) + .then(uuid => window.opener.postMessage(uuid[0], "*")); + </script> + <body> + {request.url}<br> + {url} + </body>''' + + + return 200, headers, content
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any.js b/third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any.js index 200cbd06..6716d91 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookie-store/cookieListItem_attributes.https.any.js
@@ -195,3 +195,15 @@ }, `CookieListItem - cookieStore.set with sameSite set to ${sameSiteValue}`); }); + +promise_test(async testCase => { + await cookieStore.delete('cookie-name'); + + await cookieStore.set('cookie-name', 'cookie-value'); + testCase.add_cleanup(async () => { + await cookieStore.delete('cookie-name'); + }); + + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie.secure, true); +}, 'CookieListItem - secure defaults to true');
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_arguments.https.any.js b/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_arguments.https.any.js index ddae238..37a551b3 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_arguments.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_arguments.https.any.js
@@ -143,7 +143,7 @@ assert_equals(cookie_attributes.name, 'cookie-name'); assert_equals(cookie_attributes.value, 'cookie-value'); - await cookieStore.delete(cookie_attributes); + await cookieStore.delete(cookie_attributes.name); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie, null); }, 'cookieStore.delete with get result');
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_set_creation_url.https.any.js b/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_set_creation_url.https.any.js new file mode 100644 index 0000000..d09c4aa --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_getAll_set_creation_url.https.any.js
@@ -0,0 +1,33 @@ +// META: title=Cookie Store API: cookieStore.set()/getAll() with Document URL changing +// META: global=window + +'use strict'; + +promise_test(async testCase => { + const currentUrl = new URL(self.location.href); + const currentPath = currentUrl.pathname; + const currentDirectory = + currentPath.substr(0, currentPath.lastIndexOf('/') + 1); + + await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); + + await cookieStore.set( + { name: 'cookie-name', value: 'cookie-value', path: currentDirectory }); + testCase.add_cleanup(async () => { + await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); + }); + + // This changes the Document's current URL to this different URL. + // The Document's creation URL does not change. + // If set() and getAll() use Document's current URL, the cookie will be set + // using the original URL above, and the get below will fail since it looks + // for cookies with this different URL. If they both use the creation URL, + // the get will succeed since it won't use this different URL to search. + let different_url = `${self.location.protocol}//${self.location.host}/different/path`; + history.pushState({}, "", different_url); + + const cookies = await cookieStore.getAll(); + assert_equals(cookies.length, 1); + assert_equals(cookies[0].name, 'cookie-name'); + assert_equals(cookies[0].value, 'cookie-value'); +}, 'cookieStore.set and cookieStore.getAll use the creation url');
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_creation_url.https.any.js b/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_creation_url.https.any.js new file mode 100644 index 0000000..71f8108 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_get_set_creation_url.https.any.js
@@ -0,0 +1,32 @@ +// META: title=Cookie Store API: cookieStore.set()/get() with Document URL changing +// META: global=window + +'use strict'; + +promise_test(async testCase => { + const currentUrl = new URL(self.location.href); + const currentPath = currentUrl.pathname; + const currentDirectory = + currentPath.substr(0, currentPath.lastIndexOf('/') + 1); + + await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); + + await cookieStore.set( + { name: 'cookie-name', value: 'cookie-value', path: currentDirectory }); + testCase.add_cleanup(async () => { + await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); + }); + + // This changes the Document's current URL to this different URL. + // The Document's creation URL does not change. + // If set() and get() use Document's current URL, the cookie will be set + // using the original URL above, and the get below will fail since it looks + // for cookies with this different URL. If they both use the creation URL, + // the get will succeed since it won't use this different URL to search. + let different_url = `${self.location.protocol}//${self.location.host}/different/path`; + history.pushState({}, "", different_url); + + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie.name, 'cookie-name'); + assert_equals(cookie.value, 'cookie-value'); +}, 'cookieStore.set and cookieStore.get use the creation url');
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_arguments.https.any.js b/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_arguments.https.any.js index 8ff66bf77..064fcc5 100644 --- a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_arguments.https.any.js +++ b/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_set_arguments.https.any.js
@@ -30,6 +30,11 @@ promise_test(async testCase => { await promise_rejects_js(testCase, TypeError, + cookieStore.set('', '')); +}, "cookieStore.set fails with empty name and empty value"); + +promise_test(async testCase => { + await promise_rejects_js(testCase, TypeError, cookieStore.set('', 'suspicious-value=resembles-name-and-value')); }, "cookieStore.set with empty name and an '=' in value"); @@ -44,6 +49,28 @@ assert_equals(cookie.value, 'suspicious-value=resembles-name-and-value'); }, "cookieStore.set with normal name and an '=' in value"); +let invalidCharacters = [ '\u0000', '\u0001', '\u0002' + , '\u0003', '\u0004', '\u0005' + , '\u0006', '\u0007', '\u0008' + , '\u0010', '\u0011' + , '\u0012', '\u0013', '\u0014' + , '\u0015', '\u0016', '\u0017' + , '\u0018', '\u0019', '\u001A' + , '\u001B', '\u001C', '\u001D' + , '\u001E', '\u001F' + , '\u003B', '\u007F']; + +invalidCharacters.forEach(invalidCharacter => { + let invalidCookieName = 'cookie' + invalidCharacter + 'name'; + let invalidCookieValue = 'cookie' + invalidCharacter + 'value'; + promise_test(async testCase => { + await promise_rejects_js(testCase, TypeError, + cookieStore.set(invalidCookieName, 'cookie-value')); + await promise_rejects_js(testCase, TypeError, + cookieStore.set('cookie-name', invalidCookieValue)); + }, `cookieStore.set checks if name or value contain invalid character U+${invalidCharacter.charCodeAt(0).toString(16).padStart(4, "0").toUpperCase()}`); +}); + promise_test(async testCase => { const tenYears = 10 * 365 * 24 * 60 * 60 * 1000; const tenYearsFromNow = Date.now() + tenYears; @@ -280,7 +307,7 @@ assert_equals(cookie_attributes.value, 'old-cookie-value'); cookie_attributes.value = 'new-cookie-value'; - await cookieStore.set(cookie_attributes); + await cookieStore.set(cookie_attributes.name, cookie_attributes.value); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie.name, 'cookie-name'); assert_equals(cookie.value, 'new-cookie-value');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-auto-svg-text.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-auto-svg-text.html index 93b5709..60aac70 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-auto-svg-text.html +++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-auto-svg-text.html
@@ -12,7 +12,7 @@ </style> </head> <body> -<p>Test passes if there is a filled green square.</p> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> <div style="content-visibility: auto;"> <svg> <text fill="green" x="0" y="80">x</text>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/idlharness-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/idlharness-expected.txt index 47cdf69..c1bb365 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-fonts/idlharness-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/idlharness-expected.txt
@@ -1,77 +1,4 @@ This is a testharness.js-based test. -Found 45 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] CSSFontFaceDescriptors interface: existence and properties of interface object - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface object length - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface object name - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute src - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute fontFamily - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute font-family - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute fontStyle - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute font-style - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute fontWeight - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute font-weight - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute fontStretch - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute font-stretch - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute fontWidth - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute font-width - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute unicodeRange - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute unicode-range - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute fontFeatureSettings - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute font-feature-settings - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute fontVariationSettings - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute font-variation-settings - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute fontNamedInstance - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute font-named-instance - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute fontDisplay - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute font-display - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute fontLanguageOverride - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute font-language-override - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute ascentOverride - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute ascent-override - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute descentOverride - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute descent-override - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute lineGapOverride - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceDescriptors interface: attribute line-gap-override - assert_own_property: self does not have own property "CSSFontFaceDescriptors" expected property "CSSFontFaceDescriptors" missing -[FAIL] CSSFontFaceRule interface: attribute style - assert_equals: setter must be function for PutForwards, Replaceable, or non-readonly attributes expected "function" but got "undefined" [FAIL] CSSFontFeatureValuesRule interface: attribute historicalForms assert_true: The prototype object must have a property "historicalForms" expected true got false [FAIL] CSSFontFeatureValuesMap interface: existence and properties of interface object
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollable-overflow-empty-newline-span.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollable-overflow-empty-newline-span.html new file mode 100644 index 0000000..39f72d9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollable-overflow-empty-newline-span.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<link rel="author" title="David Shin" href="dshin@mozilla.com"> +<link rel="help" href="bugzilla.mozilla.org/show_bug.cgi?id=1940938"> +<link rel="match" href="../reference/ref-filled-green-100px-square-only.html"> +<p>Test passes if there is a filled green square.</p> +<div id="dut" style="overflow: hidden; height: 100px; width: 100px; background: red;"> + <div style="width: 100px; height: 100px; background: green;"></div> + <div style="font-size: 200px;"><span> + </span></div> +</div> +<script> +onload = function () { + dut.scrollTop = 100; + document.documentElement.className = ""; +} +</script> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/text-wrap-balance-before-after-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/text-wrap-balance-before-after-001-ref.html new file mode 100644 index 0000000..9bf7820 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/text-wrap-balance-before-after-001-ref.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<style> +.container { + font: 16px monospace; + margin: 1em; + width: 60ch; +} + +.text1 { + text-wrap: balance; + margin-bottom: 1em; + outline: 1px dashed gray; +} +</style> + +<p>The two paragraphs should look identical, both having balanced lines:</p> + +<div class="container"> +<div class="text1"> +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +</div> +<div class="text1"> +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +</div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/text-wrap-balance-before-after-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/text-wrap-balance-before-after-002-ref.html new file mode 100644 index 0000000..6fbfe89 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/text-wrap-balance-before-after-002-ref.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<style> +.container { + font: 16px monospace; + margin: 1em; + width: 60ch; + outline: 1px dashed gray; +} + +.text { + text-wrap: balance; +} + +.text-before { + letter-spacing: -0.15ch; + margin-bottom: 1em; + text-wrap: balance; +} + +.text-after { + text-wrap-style: stable; + margin-top: 1em; +} +</style> + +<p>The first two paragraphs should be separately balanced; the third should not use balancing:</p> + +<div class="container"> +<div class="text-before"> +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +</div> +<div class="text"> +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +</div> +<div class="text-after"> +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +</div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/text-wrap-balance-before-after-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/text-wrap-balance-before-after-001.html new file mode 100644 index 0000000..9f5741e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/text-wrap-balance-before-after-001.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-text-4/#valdef-text-wrap-balance"> +<link rel="match" href="reference/text-wrap-balance-before-after-001-ref.html"> +<style> +.container { + font: 16px monospace; + margin: 1em; + width: 60ch; +} + +.text1, .text2 { + text-wrap: balance; + margin-bottom: 1em; + outline: 1px dashed gray; +} + +/* :before and :after pseudos with display:block and no content should not affect + the layout of the paragraph content */ +.text2:before, .text2:after { + content: ""; + display: block; +} +</style> + +<p>The two paragraphs should look identical, both having balanced lines:</p> + +<div class="container"> +<div class="text1"> +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +</div> +<div class="text2"> +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +</div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/text-wrap-balance-before-after-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/text-wrap-balance-before-after-002.html new file mode 100644 index 0000000..e9d08953 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/text-wrap-balance-before-after-002.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-text-4/#valdef-text-wrap-balance"> +<link rel="match" href="reference/text-wrap-balance-before-after-002-ref.html"> +<style> +.container { + font: 16px monospace; + margin: 1em; + width: 60ch; +} + +.text { + text-wrap: balance; + outline: 1px dashed gray; +} + +.text:before { + content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; + letter-spacing: -0.15ch; + display: block; + margin-bottom: 1em; +} + +.text:after { + content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; + text-wrap-style: stable; + display: block; + margin-top: 1em; +} +</style> + +<p>The first two paragraphs should be separately balanced; the third should not use balancing:</p> + +<div class="container"> +<div class="text"> +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +</div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/tentative/Node-moveBefore.html b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/tentative/Node-moveBefore.html index 6ea8cfe..a1147c4 100644 --- a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/tentative/Node-moveBefore.html +++ b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/tentative/Node-moveBefore.html
@@ -339,4 +339,11 @@ const div = outer.appendChild(document.createElement('div')); assert_throws_dom("HIERARCHY_REQUEST_ERR", () => div.moveBefore(outer, null)); }, "Invalid node hierarchy with null old parent does not crash"); + +test(t => { + const outerDiv = document.createElement('div'); + const innerDiv = outerDiv.appendChild(document.createElement('div')); + const iframe = innerDiv.appendChild(document.createElement('iframe')); + outerDiv.moveBefore(iframe, null); +}, "Move disconnected iframe does not crash"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/editing/crashtests/remove-all-children-of-documentElement-in-designMode-when-no-body.html b/third_party/blink/web_tests/external/wpt/editing/crashtests/remove-all-children-of-documentElement-in-designMode-when-no-body.html new file mode 100644 index 0000000..2898444 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/editing/crashtests/remove-all-children-of-documentElement-in-designMode-when-no-body.html
@@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<script> +document.addEventListener("DOMContentLoaded", () => { + document.designMode = "on"; + document.documentElement.innerText = "abc def\n"; // causes removing the implicit <body> element + let child; + while ((child = document.documentElement.lastChild)) { + child.remove(); + } +}, {once: true}); +</script> +</head> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window.js b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window.js index d3c41498..5374adb 100644 --- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window.js +++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window.js
@@ -521,103 +521,50 @@ expectNoWinner(auctionResult); }, 'Basic B&A auction - Wrong request Id'); -// Runs responseMutator on a minimal correct server response, and expects -// either success/failure based on expectWin. -// TODO(qingxinwu): Remove this and use the one in ba-fledge-util.sub.js. -async function testWithMutatedServerResponse( - test, expectWin, responseMutator, igMutator = undefined) { - const uuid = generateUuid(test); - const adA = createTrackerURL(window.location.origin, uuid, 'track_get', 'a'); - const adB = createTrackerURL(window.location.origin, uuid, 'track_get', 'b'); - const adsArray = - [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}]; - let ig = {ads: adsArray}; - if (igMutator) { - igMutator(ig, uuid); - } - await joinInterestGroup(test, uuid, ig); - - const result = await navigator.getInterestGroupAdAuctionData({ - coordinatorOrigin: await BA.configureCoordinator(), - seller: window.location.origin - }); - assert_true(result.requestId !== null); - assert_true(result.request.length > 0); - - let decoded = await BA.decodeInterestGroupData(result.request); - - let serverResponseMsg = { - 'biddingGroups': {}, - 'adRenderURL': ig.ads[0].renderURL, - 'interestGroupName': DEFAULT_INTEREST_GROUP_NAME, - 'interestGroupOwner': window.location.origin, - }; - serverResponseMsg.biddingGroups[window.location.origin] = [0]; - await responseMutator(serverResponseMsg, uuid); - - let serverResponse = - await BA.encodeServerResponse(serverResponseMsg, decoded); - - let hashString = await BA.payloadHash(serverResponse); - await BA.authorizeServerResponseHashes([hashString]); - - let auctionResult = await navigator.runAdAuction({ - 'seller': window.location.origin, - 'interestGroupBuyers': [window.location.origin], - 'requestId': result.requestId, - 'serverResponse': serverResponse, - 'resolveToConfig': true, - }); - if (expectWin) { - expectSuccess(auctionResult); - return auctionResult; - } else { - expectNoWinner(auctionResult); - } -} - subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ false, msg => {msg.error = {}}); }, 'Basic B&A auction - response marked as error'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { + await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { msg.error = 4; }); }, 'Basic B&A auction - nonsense error field'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ false, msg => { - msg.error = {message: 'oh no'}; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ false, msg => { + msg.error = {message: 'oh no'}; + }); }, 'Basic B&A auction - response marked as error, with message'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ false, msg => { - msg.error = {message: {}}; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ false, msg => { + msg.error = {message: {}}; + }); }, 'Basic B&A auction - response marked as error, with bad message'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ false, msg => {msg.isChaff = true}); }, 'Basic B&A auction - response marked as chaff'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ true, msg => {msg.isChaff = false}); }, 'Basic B&A auction - response marked as non-chaff'); // Disabled while spec clarifying expected behavior is in-progress. // // subsetTest(promise_test, async test => { -// await testWithMutatedServerResponse( +// await BA.testWithMutatedServerResponse( // test, /*expectSuccess=*/ true, msg => {msg.isChaff = 'yes'}); // }, 'Basic B&A auction - response marked as chaff incorrectly'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ false, msg => {msg.topLevelSeller = 'https://example.org/'}); }, 'Basic B&A auction - incorrectly includes topLevelSeller'); @@ -625,12 +572,12 @@ // Disabled while spec clarifying expected behavior is in-progress. // // subsetTest(promise_test, async test => { -// await testWithMutatedServerResponse( +// await BA.testWithMutatedServerResponse( // test, /*expectSuccess=*/ true, msg => {msg.topLevelSeller = 1}); // }, 'Basic B&A auction - non-string top-level seller ignored'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ false, msg => {msg.topLevelSeller = 'http://example.org/'}); }, 'Basic B&A auction - http:// topLevelSeller is bad, too'); @@ -638,118 +585,135 @@ // Disabled while spec clarifying expected behavior is in-progress. // // subsetTest(promise_test, async test => { -// await testWithMutatedServerResponse( +// await BA.testWithMutatedServerResponse( // test, /*expectSuccess=*/ true, msg => {msg.bid = '10 cents'}); // }, 'Basic B&A auction - non-number bid is ignored'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ true, msg => {msg.bid = 50}); }, 'Basic B&A auction - positive bid is good'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ false, msg => {msg.bid = -50}); }, 'Basic B&A auction - negative bid is bad'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ false, msg => {msg.bid = 0}); }, 'Basic B&A auction - zero bid is bad'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ false, msg => {msg.biddingGroups[window.location.origin] = []}); }, 'Basic B&A auction - winning group did not bid'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ false, msg => {msg.biddingGroups[window.location.origin] = [-1, 0]}); }, 'Basic B&A auction - negative bidding group index'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ false, msg => {msg.biddingGroups[window.location.origin] = [0, 1]}); }, 'Basic B&A auction - too large bidding group index'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ false, msg => { - msg.interestGroupName += 'not'; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ false, msg => { + msg.interestGroupName += 'not'; + }); }, 'Basic B&A auction - wrong IG name'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ false, async msg => { await leaveInterestGroup(); }); }, 'Basic B&A auction - left IG in the middle'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ false, msg => { - msg.adRenderURL += 'not'; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ false, msg => { + msg.adRenderURL += 'not'; + }); }, 'Basic B&A auction - ad URL not in ad'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ false, msg => { - msg.buyerReportingId = 'bid1'; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ false, msg => { + msg.buyerReportingId = 'bid1'; + }); }, 'Basic B&A auction - buyerReportingId not in ad'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { - msg.buyerReportingId = 'bid1'; - }, ig => { - ig.ads[0].buyerReportingId = 'bid1'; - ig.ads[1].buyerReportingId = 'bid2'; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ true, + msg => { + msg.buyerReportingId = 'bid1'; + }, + ig => { + ig.ads[0].buyerReportingId = 'bid1'; + ig.ads[1].buyerReportingId = 'bid2'; + }); }, 'Basic B&A auction - buyerReportingId in ad'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ false, msg => { - msg.buyerReportingId = 'bid2'; - }, ig => { - ig.ads[0].buyerReportingId = 'bid1'; - ig.ads[1].buyerReportingId = 'bid2'; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ false, + msg => { + msg.buyerReportingId = 'bid2'; + }, + ig => { + ig.ads[0].buyerReportingId = 'bid1'; + ig.ads[1].buyerReportingId = 'bid2'; + }); }, 'Basic B&A auction - buyerReportingId in wrong ad'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ false, msg => { - msg.buyerAndSellerReportingId = 'bsid1'; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ false, msg => { + msg.buyerAndSellerReportingId = 'bsid1'; + }); }, 'Basic B&A auction - buyerAndSellerReportingId not in ad'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { - msg.buyerAndSellerReportingId = 'bsid1'; - }, ig => { - ig.ads[0].buyerAndSellerReportingId = 'bsid1'; - ig.ads[1].buyerAndSellerReportingId = 'bsid2'; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ true, + msg => { + msg.buyerAndSellerReportingId = 'bsid1'; + }, + ig => { + ig.ads[0].buyerAndSellerReportingId = 'bsid1'; + ig.ads[1].buyerAndSellerReportingId = 'bsid2'; + }); }, 'Basic B&A auction - buyerAndSellerReportingId in ad'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ false, msg => { - msg.buyerAndSellerReportingId = 'bsid2'; - }, ig => { - ig.ads[0].buyerAndSellerReportingId = 'bsid1'; - ig.ads[1].buyerAndSellerReportingId = 'bsid2'; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ false, + msg => { + msg.buyerAndSellerReportingId = 'bsid2'; + }, + ig => { + ig.ads[0].buyerAndSellerReportingId = 'bsid1'; + ig.ads[1].buyerAndSellerReportingId = 'bsid2'; + }); }, 'Basic B&A auction - buyerAndSellerReportingId in wrong ad'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ false, msg => { - msg.components = ["https://example.org"]; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ false, msg => { + msg.components = ['https://example.org']; + }); }, 'Basic B&A auction - ad component URL not in ad'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse( + await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ true, msg => { msg.components = ['https://example.org']; @@ -762,7 +726,7 @@ subsetTest(promise_test, async test => { let savedUuid; let savedExpectUrls; - let result = await testWithMutatedServerResponse( + let result = await BA.testWithMutatedServerResponse( test, /*expectSuccess=*/ true, (msg, uuid) => { savedUuid = uuid; @@ -809,7 +773,7 @@ subsetTest(promise_test, async test => { let savedUuid; - let result = await testWithMutatedServerResponse( + let result = await BA.testWithMutatedServerResponse( test, /*expectWin=*/ true, (msg, uuid) => { savedUuid = uuid; @@ -852,13 +816,14 @@ }, 'Basic B&A auction --- beacon reporting'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ false, msg => { - msg.bidCurrency = 'cents'; - }); + await BA.testWithMutatedServerResponse( + test, /*expectSuccess=*/ false, msg => { + msg.bidCurrency = 'cents'; + }); }, 'Basic B&A auction - invalid ad currency'); subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { + await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { msg.bidCurrency = 'USD'; }); }, 'Basic B&A auction - valid ad currency'); @@ -1145,7 +1110,7 @@ ///////////////////////////////////////////////////////////////////////////// subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { + await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { msg.updateGroups = {[window.location.origin]: [{index: 2048, updateIfOlderThanMs: 1000}]}; }); @@ -1153,7 +1118,7 @@ subsetTest(promise_test, async test => { - await testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { + await BA.testWithMutatedServerResponse(test, /*expectSuccess=*/ true, msg => { msg.updateGroups = { [window.location.origin]: [ {index: 0, updateIfOlderThanMs: 1000},
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/gentestutilsunion.py b/third_party/blink/web_tests/external/wpt/html/canvas/tools/gentestutilsunion.py index dbd729c..c9d4963d 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/gentestutilsunion.py +++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/gentestutilsunion.py
@@ -30,7 +30,7 @@ # * Test the tests, add new ones to Git, remove deleted ones from Git, etc. from typing import Any, DefaultDict, FrozenSet, List, Mapping, MutableMapping -from typing import Optional, Set, Tuple +from typing import Set, Union import re import collections @@ -38,7 +38,6 @@ import dataclasses import enum import importlib -import itertools import math import os import pathlib @@ -156,8 +155,6 @@ code = re.sub(r'@moz-UniversalBrowserRead;', '', code) - code = _remove_extra_newlines(code) - code = re.sub(r'@nonfinite ([^(]+)\(([^)]+)\)(.*)', lambda m: _expand_nonfinite(m.group(1), m.group(2), m.group(3)), code) # Must come before '@assert throws'. @@ -283,11 +280,15 @@ def _preprocess_code(jinja_env: jinja2.Environment, code: str, params: _TestParams) -> str: - code = _expand_test_code(code) + code = _remove_extra_newlines(code) + # Render the code on its own, as it could contain templates expanding # to multiple lines. This is needed to get proper indentation of the # code in the main template. code = _render_template(jinja_env, jinja_env.from_string(code), params) + + # Expand "@..." macros. + code = _expand_test_code(code) return code @@ -438,7 +439,7 @@ variant_id: int) -> None: """Finalize this variant by adding computed param fields.""" self._params['id'] = variant_id - for param_name in ('name', 'desc', 'attributes'): + for param_name in ('attributes', 'desc', 'expected', 'name'): self._render_param(jinja_env, param_name) self._params['file_name'] = self._get_file_name() self._params['canvas_types'] = self._get_canvas_types() @@ -874,6 +875,29 @@ tested[name].update(canvas_types) +def _indent_filter(s: str, width: Union[int, str] = 4, + first: bool = False, blank: bool = False) -> str: + """Returns a copy of the string with each line indented by the `width` str. + + If `width` is a number, `s` is indented by that number of whitespaces. The + first line and blank lines are not indented by default, unless `first` or + `blank` are `True`, respectively. + + This is a re-implementation of the default `indent` Jinja filter, preserving + line ending characters (\r, \n, \f, etc.) The default `indent` Jinja filter + incorrectly replaces all of these characters with newlines.""" + is_first_line = True + def indent_needed(line): + nonlocal first, blank, is_first_line + is_blank = not line.strip() + need_indent = (not is_first_line or first) and (not is_blank or blank) + is_first_line = False + return need_indent + + indentation = width if isinstance(width, str) else ' ' * width + return textwrap.indent(s, indentation, indent_needed) + + def generate_test_files(name_to_dir_file: str) -> None: """Generate Canvas tests from YAML file definition.""" output_dirs = _OutputPaths(element=pathlib.Path('..') / 'element', @@ -886,6 +910,7 @@ lstrip_blocks=True) jinja_env.filters['double_quote_escape'] = _double_quote_escape + jinja_env.filters['indent'] = _indent_filter # Run with --test argument to run unit tests. if len(sys.argv) > 1 and sys.argv[1] == '--test':
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml-new/the-canvas.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml-new/the-canvas.yaml index 4153b8e..2058adc 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml-new/the-canvas.yaml +++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml-new/the-canvas.yaml
@@ -23,6 +23,142 @@ new_canvas: |- new OffscreenCanvas(100, 50) +- name: 2d.canvas.host.size.attributes + canvas_types: ['HtmlCanvas'] + code: | + {{ set_attributes -}} + @assert canvas.width === {{ result_size[0] }}; + @assert canvas.height === {{ result_size[1] }}; + {% if result_size[0] != 300 %} + {# With "100%", Opera gets canvas.width = 100 but renders at 100% of the + frame width, so check the CSS display width -#} + @assert window.getComputedStyle(canvas, null)\- + .getPropertyValue("width") === "{{ result_size[0] }}px"; + {% endif -%} + + {% set attrib_size = escaped_size or input_size %} + @assert canvas.getAttribute('width') === '{{ attrib_size }}'; + @assert canvas.getAttribute('height') === '{{ attrib_size }}'; + expected: | + {% if result_size[0] != 0 -%} + size {{ result_size[0] }} {{ result_size[1] }} + {% endif %} + variants: + - parse: + desc: Parsing of non-negative integers + size: ['{{ input_size }}', '{{ input_size }}'] + setAttribute: + desc: Parsing of non-negative integers in setAttribute + size: [ 50, 50 ] + set_attributes: | + canvas.setAttribute('width', '{{ escaped_size or input_size }}'); + canvas.setAttribute('height', '{{ escaped_size or input_size }}'); + - zero: + input_size: '0' + result_size: [0, 0] + empty: + input_size: '' + result_size: [300, 150] + onlyspace: + input_size: ' ' + result_size: [300, 150] + space: + input_size: ' 100' + result_size: [100, 100] + whitespace: + input_size: "
\n\t\x0c100" + escaped_size: "\\r\\n\\t\\x0c100" + result_size: [100, 100] + plus: + input_size: '+100' + result_size: [100, 100] + minus: + input_size: '-100' + result_size: [300, 150] + octal: + input_size: '0100' + result_size: [100, 100] + hex: + input_size: '0x100' + result_size: [0, 0] + exp: + input_size: '100e1' + result_size: [100, 100] + decimal: + input_size: '100.999' + result_size: [100, 100] + percent: + input_size: '100%' + result_size: [100, 100] + em: + input_size: '100em' + result_size: [100, 100] + junk: + input_size: '#!?' + result_size: [300, 150] + trailingjunk: + input_size: '100#!?' + result_size: [100, 100] + +- name: 2d.canvas.host.size.attributes.parse + desc: Parsing of non-negative integers + canvas_types: ['OffscreenCanvas', 'Worker'] + code: | + {% if result_size == 'exception' %} + @assert throws TypeError canvas.width = '{{ input_size }}'; + {% else %} + canvas.width = '{{ input_size }}'; + canvas.height = '{{ input_size }}'; + @assert canvas.width === {{ result_size }}; + @assert canvas.height === {{ result_size }}; + {% endif %} + variants: + - zero: + input_size: '0' + result_size: 0 + empty: + input_size: '' + result_size: 0 + onlyspace: + input_size: ' ' + result_size: 0 + space: + input_size: ' 100' + result_size: 100 + whitespace: + input_size: "\t\f100" + result_size: 100 + plus: + input_size: '+100' + result_size: 100 + minus: + input_size: '-100' + result_size: 'exception' + octal: + input_size: '0100' + result_size: 100 + hex: + input_size: '0x100' + result_size: 0x100 + exp: + input_size: '100e1' + result_size: 1000.0 + decimal: + input_size: '100.999' + result_size: 100 + percent: + input_size: '100%' + result_size: 'exception' + em: + input_size: '100em' + result_size: 'exception' + junk: + input_size: '#!?' + result_size: 'exception' + trailingjunk: + input_size: '100#!?' + result_size: 'exception' + - name: 2d.canvas.host.type.delete canvas_types: ['HtmlCanvas'] desc: window.HTMLCanvasElement interface object is [[Configurable]]
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/meta.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/meta.yaml index 358333d9..65ef32cb 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/meta.yaml +++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/element/meta.yaml
@@ -1,66 +1,4 @@ - meta: | - cases = [ - ("zero", "0", 0), - ("empty", "", None), - ("onlyspace", " ", None), - ("space", " 100", 100), - ("whitespace", "\r\n\t\f100", 100), - ("plus", "+100", 100), - ("minus", "-100", None), - ("octal", "0100", 100), - ("hex", "0x100", 0), - ("exp", "100e1", 100), - ("decimal", "100.999", 100), - ("percent", "100%", 100), - ("em", "100em", 100), - ("junk", "#!?", None), - ("trailingjunk", "100#!?", 100), - ] - def gen(name, string, exp, code): - if exp is None: - code += "@assert canvas.width === 300;\n@assert canvas.height === 150;\n" - expected = "size 300 150" - else: - code += "@assert canvas.width === %s;\n@assert canvas.height === %s;\n" % (exp, exp) - expected = "size %s %s" % (exp, exp) - - # With "100%", Opera gets canvas.width = 100 but renders at 100% of the frame width, - # so check the CSS display width - code += '@assert window.getComputedStyle(canvas, null).getPropertyValue("width") === "%spx";\n' % (exp, ) - - code += "@assert canvas.getAttribute('width') === %r;\n" % string - code += "@assert canvas.getAttribute('height') === %r;\n" % string - - if exp == 0: - expected = None # can't generate zero-sized PNGs for the expected image - - return code, expected - - for name, string, exp in cases: - code = "" - code, expected = gen(name, string, exp, code) - # We need to replace \r with 
 because \r\n gets converted to \n in the HTML parser. - htmlString = string.replace('\r', '
') - tests.append( { - "name": "2d.canvas.host.size.attributes.parse.%s" % name, - "desc": "Parsing of non-negative integers", - "size": '%s, %s' % (htmlString, htmlString), - "code": code, - "expected": expected - } ) - - for name, string, exp in cases: - code = "canvas.setAttribute('width', %r);\ncanvas.setAttribute('height', %r);\n" % (string, string) - code, expected = gen(name, string, exp, code) - tests.append( { - "name": "2d.canvas.host.size.attributes.setAttribute.%s" % name, - "desc": "Parsing of non-negative integers in setAttribute", - "size": '50, 50', - "code": code, - "expected": expected - } ) - -- meta: | # Composite operation tests # <http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2007-March/010608.html> ops = [
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/meta.yaml b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/meta.yaml index 9c1cfbf..3026609 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/meta.yaml +++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/yaml/offscreen/meta.yaml
@@ -429,50 +429,3 @@ """ % (string,), } tests.append(test) - -- meta: | - cases = [ - ("zero", "0", 0), - ("empty", "", 0), - ("onlyspace", " ", 0), - ("space", " 100", 100), - ("whitespace", "\t\f100", 100), - ("plus", "+100", 100), - ("minus", "-100", "exception"), - ("octal", "0100", 100), - ("hex", "0x100", 0x100), - ("exp", "100e1", 100e1), - ("decimal", "100.999", 100), - ("percent", "100%", "exception"), - ("em", "100em", "exception"), - ("junk", "#!?", "exception"), - ("trailingjunk", "100#!?", "exception"), - ] - def gen(name, string, exp, code): - if exp is None: - code += "canvas.width = '%s';\ncanvas.height = '%s';\n" % (string, string) - code += "@assert canvas.width === 100;\n@assert canvas.height === 50;\n" - expected = None - elif exp == "exception": - code += "@assert throws TypeError canvas.width = '%s';\n" % string - expected = None - else: - code += "canvas.width = '%s';\ncanvas.height = '%s';\n" % (string, string) - code += "@assert canvas.width === %s;\n@assert canvas.height === %s;\n" % (exp, exp) - expected = None - - code += "t.done();\n" - - if exp == 0: - expected = None # can't generate zero-sized PNGs for the expected image - - return code, expected - - for name, string, exp in cases: - code = "" - code, expected = gen(name, string, exp, code) - tests.append( { - "name": "2d.canvas.host.size.attributes.parse.%s" % name, - "desc": "Parsing of non-negative integers", - "code": code, - } )
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-appearance-optgroup-legend-and-label.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-appearance-optgroup-legend-and-label.tentative.html index 666dde2f..e8400ed 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-appearance-optgroup-legend-and-label.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-appearance-optgroup-legend-and-label.tentative.html
@@ -1,9 +1,9 @@ <!DOCTYPE html> <html class=reftest-wait> <link rel=author href="mailto:jarhar@chromium.org"> -<link rel=help href="https://github.com/whatwg/html/issues/9799"> -<link rel=mismatch href="select-appearance-optgroup-legend-ref.html"> -<meta name=assert content="The label attribute should take precedence over the legend element"> +<link rel=help href="https://issues.chromium.org/issues/378601807"> +<link rel=match href="select-appearance-optgroup-legend-ref.html"> +<meta name=assert content="The legend element should take precedence over the label attribute"> <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-vendor.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-innertext.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-innertext.tentative.html new file mode 100644 index 0000000..a3e0482d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-innertext.tentative.html
@@ -0,0 +1,61 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://issues.chromium.org/issues/387440276"> +<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> + +<select id=oldcontentmodel> + <option>one</option> + <optgroup label=emptygroup></optgroup> + <optgroup label=optgroup> + <option>two</option> + </optgroup> +</select> + +<select id=newcontentmodel> + <option>one</option> + <optgroup label=emptygroup></optgroup> + <div> + <optgroup label=optgroup> + <div> + <option> + <span>two</span> + </option> + </div> + </optgroup> + </div> +</select> + +<style> +.base, .base::picker(select) { + appearance: base-select; +} +</style> + +<script> +const expectedText = 'one\ntwo'; +const oldSelect = document.getElementById('oldcontentmodel'); +const newSelect = document.getElementById('newcontentmodel'); + +test(() => { + assert_equals(oldSelect.innerText, expectedText); +}, '<select> innerText with old content model and appearance:auto.'); + +test(() => { + assert_equals(newSelect.innerText, expectedText); +}, '<select> innerText with new content model and appearance:auto.'); + +promise_test(async () => { + newSelect.classList.add('base'); + await new Promise(requestAnimationFrame); + assert_equals(newSelect.innerText, expectedText); +}, '<select> innerText with new content model and appearance:base-select.'); + +promise_test(async () => { + await test_driver.bless(); + newSelect.showPicker(); + assert_equals(newSelect.innerText, expectedText); +}, '<select> innerText with new content model and appearance:base-select with picker open.'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestelement-interface.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestelement-interface.tentative.html index 8b1e375..bc68dc5 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestelement-interface.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestelement-interface.tentative.html
@@ -84,82 +84,4 @@ "interestTargetElement attribute value must be an instance of Element", ); }, "interestTargetElement throws error on assignment of non Element"); - - test(function () { - assert_false(buttonInvoker.hasAttribute("interestaction")); - assert_equals(buttonInvoker.interestAction, ""); - assert_false(aInvoker.hasAttribute("interestaction")); - assert_equals(aInvoker.interestAction, ""); - assert_false(inputInvoker.hasAttribute("interestaction")); - assert_equals(inputInvoker.interestAction, ""); - }, "interestAction reflects '' when attribute not present"); - - test(function () { - buttonInvoker.setAttribute("interestaction", ""); - assert_equals(buttonInvoker.getAttribute("interestaction"), ""); - assert_equals(buttonInvoker.interestAction, ""); - aInvoker.setAttribute("interestaction", ""); - assert_equals(aInvoker.getAttribute("interestaction"), ""); - assert_equals(aInvoker.interestAction, ""); - inputInvoker.setAttribute("interestaction", ""); - assert_equals(inputInvoker.getAttribute("interestaction"), ""); - assert_equals(inputInvoker.interestAction, ""); - }, "interestAction reflects '' when attribute empty, setAttribute version"); - - test(function () { - buttonInvoker.interestAction = ""; - assert_equals(buttonInvoker.getAttribute("interestaction"), ""); - assert_equals(buttonInvoker.interestAction, ""); - aInvoker.interestAction = ""; - assert_equals(aInvoker.getAttribute("interestaction"), ""); - assert_equals(aInvoker.interestAction, ""); - inputInvoker.interestAction = ""; - assert_equals(inputInvoker.getAttribute("interestaction"), ""); - assert_equals(inputInvoker.interestAction, ""); - }, "interestAction reflects '' when attribute empty, IDL setter version"); - - test(function () { - buttonInvoker.interestAction = "fooBarBaz"; - assert_equals(buttonInvoker.getAttribute("interestaction"), "fooBarBaz"); - assert_equals(buttonInvoker.interestAction, "fooBarBaz"); - aInvoker.interestAction = "fooBarBaz"; - assert_equals(aInvoker.getAttribute("interestaction"), "fooBarBaz"); - assert_equals(aInvoker.interestAction, "fooBarBaz"); - inputInvoker.interestAction = "fooBarBaz"; - assert_equals(inputInvoker.getAttribute("interestaction"), "fooBarBaz"); - assert_equals(inputInvoker.interestAction, "fooBarBaz"); - }, "interestAction reflects same casing"); - - test(function () { - buttonInvoker.interestAction = []; - assert_equals(buttonInvoker.getAttribute("interestaction"), ""); - assert_equals(buttonInvoker.interestAction, ""); - aInvoker.interestAction = []; - assert_equals(aInvoker.getAttribute("interestaction"), ""); - assert_equals(aInvoker.interestAction, ""); - inputInvoker.interestAction = []; - assert_equals(inputInvoker.getAttribute("interestaction"), ""); - assert_equals(inputInvoker.interestAction, ""); - }, "interestAction reflects '' when attribute set to []"); - - test(function () { - buttonInvoker.interestAction = [1, 2, 3]; - assert_equals(buttonInvoker.getAttribute("interestaction"), "1,2,3"); - assert_equals(buttonInvoker.interestAction, "1,2,3"); - aInvoker.interestAction = [1, 2, 3]; - assert_equals(aInvoker.getAttribute("interestaction"), "1,2,3"); - assert_equals(aInvoker.interestAction, "1,2,3"); - inputInvoker.interestAction = [1, 2, 3]; - assert_equals(inputInvoker.getAttribute("interestaction"), "1,2,3"); - assert_equals(inputInvoker.interestAction, "1,2,3"); - }, "interestAction reflects tostring value"); - - test(function () { - buttonInvoker.interestAction = {}; - assert_equals(buttonInvoker.interestAction, "[object Object]"); - aInvoker.interestAction = {}; - assert_equals(aInvoker.interestAction, "[object Object]"); - inputInvoker.interestAction = {}; - assert_equals(inputInvoker.interestAction, "[object Object]"); - }, "interestAction reflects tostring value 2"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestevent-dispatch-shadow.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestevent-dispatch-shadow.tentative.html index d96907e..9911357e 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestevent-dispatch-shadow.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestevent-dispatch-shadow.tentative.html
@@ -1,8 +1,11 @@ -<!doctype html> +<!DOCTYPE html> <meta charset="utf-8" /> <meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" /> <meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" /> -<link rel="help" href="https://open-ui.org/components/interest-invokers.explainer/" /> +<link + rel="help" + href="https://open-ui.org/components/interest-invokers.explainer/" +/> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/resources/testdriver.js"></script> @@ -20,63 +23,35 @@ const slot = shadow.appendChild(document.createElement("slot")); let childEvent = null; let childEventTarget = null; - let childEventInvoker = null; + let childEventSource = null; let hostEvent = null; let hostEventTarget = null; - let hostEventInvoker = null; - slot.addEventListener( - "interest", - (e) => { + let hostEventSource = null; + slot.addEventListener("interest", (e) => { childEvent = e; childEventTarget = e.target; - childEventInvoker = e.invoker; - }, - { once: true }, - ); - host.addEventListener( - "interest", - (e) => { + childEventSource = e.source; + }, { once: true }); + host.addEventListener("interest", (e) => { hostEvent = e; hostEventTarget = e.target; - hostEventInvoker = e.invoker; - }, - { once: true }, - ); + hostEventSource = e.source; + }, { once: true }); const event = new InterestEvent("interest", { bubbles: true, - invoker: slot, + source: slot, composed: true, }); slot.dispatchEvent(event); assert_true(childEvent instanceof InterestEvent, "slot saw interest event"); - assert_equals( - childEventTarget, - slot, - "target is child inside shadow boundary", - ); - assert_equals( - childEventInvoker, - slot, - "invoker is child inside shadow boundary", - ); - assert_equals( - hostEvent, - childEvent, - "event dispatch propagates across shadow boundary", - ); - assert_equals( - hostEventTarget, - host, - "target is retargeted to shadowroot host", - ); - assert_equals( - hostEventInvoker, - host, - "invoker is retargeted to shadowroot host", - ); - }, "InterestEvent propagates across shadow boundaries retargeting invoker"); + assert_equals(childEventTarget, slot, "target is child inside shadow boundary"); + assert_equals(childEventSource, slot, "source is child inside shadow boundary"); + assert_equals(hostEvent, childEvent, "event dispatch propagates across shadow boundary"); + assert_equals(hostEventTarget, host, "target is retargeted to shadowroot host"); + assert_equals(hostEventSource, host, "source is retargeted to shadowroot host"); + }, "InterestEvent propagates across shadow boundaries retargeting invoker source"); - test(function (t) { + promise_test(async (t) => { const host = document.createElement("div"); document.body.append(host); t.add_cleanup(() => host.remove()); @@ -86,19 +61,16 @@ button.interestTargetElement = interestee; let event = null; let eventTarget = null; - let eventInvoker = null; - interestee.addEventListener( - "interest", - (e) => { + let eventSource = null; + interestee.addEventListener("interest", (e) => { event = e; eventTarget = e.target; - eventInvoker = e.invoker; - }, - { once: true }, - ); - button.focus(); + eventSource = e.source; + },{ once: true }); + await hoverOver(button); + assert_true(!!event,"InterestEvent gets fired"); assert_true(event instanceof InterestEvent); assert_equals(eventTarget, interestee, "target is interestee"); - assert_equals(eventInvoker, host, "interestee is host"); + assert_equals(eventSource, host, "interestee is host"); }, "cross shadow InterestEvent retargets interestee to host element"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestevent-interface.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestevent-interface.tentative.html index ed7d82f..9ed95a6 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestevent-interface.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interestevent-interface.tentative.html
@@ -16,152 +16,80 @@ <script> test(function () { const event = new InterestEvent("test"); - assert_equals(event.action, ""); - assert_readonly(event, "action", "readonly attribute value"); - }, "action is a readonly defaulting to ''"); + assert_equals(event.source, null); + assert_readonly(event, "source", "readonly attribute value"); + }, "source is readonly defaulting to null"); test(function () { - const event = new InterestEvent("test"); - assert_equals(event.invoker, null); - assert_readonly(event, "invoker", "readonly attribute value"); - }, "invoker is readonly defaulting to null"); - - test(function () { - const event = new InterestEvent("test", { action: "sAmPle" }); - assert_equals(event.action, "sAmPle"); - }, "action reflects initialized attribute"); - - test(function () { - const event = new InterestEvent("test", { action: undefined }); - assert_equals(event.action, ""); - }, "action set to undefined"); - - test(function () { - const event = new InterestEvent("test", { action: null }); - assert_equals(event.action, "null"); - }, "action set to null"); - - test(function () { - const event = new InterestEvent("test", { action: false }); - assert_equals(event.action, "false"); - }, "action set to false"); - - test(function () { - const event = new InterestEvent("test", { action: "" }); - assert_equals(event.action, ""); - }, "action explicitly set to empty string"); - - test(function () { - const event = new InterestEvent("test", { action: true }); - assert_equals(event.action, "true"); - }, "action set to true"); - - test(function () { - const event = new InterestEvent("test", { action: 0.5 }); - assert_equals(event.action, "0.5"); - }, "action set to a number"); - - test(function () { - const event = new InterestEvent("test", { action: [] }); - assert_equals(event.action, ""); - }, "action set to []"); - - test(function () { - const event = new InterestEvent("test", { action: [1, 2, 3] }); - assert_equals(event.action, "1,2,3"); - }, "action set to [1, 2, 3]"); - - test(function () { - const event = new InterestEvent("test", { action: { sample: 0.5 } }); - assert_equals(event.action, "[object Object]"); - }, "action set to an object"); - - test(function () { - const event = new InterestEvent("test", { - action: { - toString() { - return "sample"; - }, - }, - }); - assert_equals(event.action, "sample"); - }, "action set to an object with a toString function"); - - test(function () { - const eventInit = { action: "sample", invoker: document.body }; + const eventInit = { source: document.body }; const event = new InterestEvent("test", eventInit); - assert_equals(event.action, "sample"); - assert_equals(event.invoker, document.body); - }, "InterestEventInit properties set value"); + assert_equals(event.source, document.body); + }, "InterestEventInit properties set value (manual event)"); test(function () { const eventInit = { - action: "open", - invoker: document.getElementById("div"), + source: document.getElementById("div"), }; const event = new InterestEvent("beforetoggle", eventInit); - assert_equals(event.action, "open"); - assert_equals(event.invoker, document.getElementById("div")); - }, "InterestEventInit properties set value 2"); + assert_equals(event.source, document.getElementById("div")); + }, "InterestEventInit properties set value (beforetoggle event)"); test(function () { const eventInit = { - action: "closed", - invoker: document.getElementById("button"), + source: document.getElementById("button"), }; const event = new InterestEvent("toggle", eventInit); - assert_equals(event.action, "closed"); - assert_equals(event.invoker, document.getElementById("button")); - }, "InterestEventInit properties set value 3"); + assert_equals(event.source, document.getElementById("button")); + }, "InterestEventInit properties set value (toggle event)"); test(function () { - const event = new InterestEvent("test", { invoker: undefined }); - assert_equals(event.invoker, null); - }, "invoker set to undefined"); + const event = new InterestEvent("test", { source: undefined }); + assert_equals(event.source, null); + }, "source set to undefined"); test(function () { - const event = new InterestEvent("test", { invoker: null }); - assert_equals(event.invoker, null); - }, "invoker set to null"); + const event = new InterestEvent("test", { source: null }); + assert_equals(event.source, null); + }, "source set to null"); test(function () { assert_throws_js( TypeError, function () { - new InterestEvent("test", { invoker: false }); + new InterestEvent("test", { source: false }); }, - "invoker is not an object", + "source is not an object", ); - }, "invoker set to false"); + }, "source set to false"); test(function () { assert_throws_js( TypeError, function () { - const event = new InterestEvent("test", { invoker: true }); + const event = new InterestEvent("test", { source: true }); }, - "invoker is not an object", + "source is not an object", ); - }, "invoker set to true"); + }, "source set to true"); test(function () { assert_throws_js( TypeError, function () { - const event = new InterestEvent("test", { invoker: {} }); + const event = new InterestEvent("test", { source: {} }); }, - "invoker is not an object", + "source is not an object", ); - }, "invoker set to {}"); + }, "source set to {}"); test(function () { assert_throws_js( TypeError, function () { - const eventInit = { action: "closed", invoker: new XMLHttpRequest() }; + const eventInit = { source: new XMLHttpRequest() }; const event = new InterestEvent("toggle", eventInit); }, - "invoker is not an Element", + "source is not an Element", ); - }, "invoker set to non-Element EventTarget"); + }, "source set to non-Element EventTarget"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-anchor-event-dispatch.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-anchor-event-dispatch.tentative.html index b5a481a..88a54c21 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-anchor-event-dispatch.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-anchor-event-dispatch.tentative.html
@@ -19,29 +19,14 @@ t.add_cleanup(() => otherbutton.focus()); let event = null; interestee.addEventListener("interest", (e) => (event = e), { once: true }); - interestanchor.focus(); - assert_true(event instanceof InterestEvent, "event is InterestEvent"); - assert_equals(event.type, "interest", "type"); - assert_equals(event.bubbles, false, "bubbles"); - assert_equals(event.composed, true, "composed"); - assert_equals(event.isTrusted, true, "isTrusted"); - assert_equals(event.action, "", "action"); - assert_equals(event.target, interestee, "target"); - assert_equals(event.invoker, interestanchor, "invoker"); - }, "InterestEvent dispatches on anchor focus"); - - promise_test(async function (t) { - t.add_cleanup(() => otherbutton.focus()); - let event = null; - interestee.addEventListener("interest", (e) => (event = e), { once: true }); await hoverOver(interestanchor); + assert_true(!!event, "InterestEvent is fired"); assert_true(event instanceof InterestEvent, "event is InterestEvent"); assert_equals(event.type, "interest", "type"); assert_equals(event.bubbles, false, "bubbles"); assert_equals(event.composed, true, "composed"); assert_equals(event.isTrusted, true, "isTrusted"); - assert_equals(event.action, "", "action"); assert_equals(event.target, interestee, "target"); - assert_equals(event.invoker, interestanchor, "invoker"); + assert_equals(event.source, interestanchor, "source"); }, "InterestEvent dispatches on anchor hover"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-area-event-dispatch.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-area-event-dispatch.tentative.html index 358acbb..5573235 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-area-event-dispatch.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-area-event-dispatch.tentative.html
@@ -22,29 +22,14 @@ t.add_cleanup(() => otherbutton.focus()); let event = null; interestee.addEventListener("interest", (e) => (event = e), { once: true }); - interestarea.focus(); - assert_true(event instanceof InterestEvent, "event is InterestEvent"); - assert_equals(event.type, "interest", "type"); - assert_equals(event.bubbles, false, "bubbles"); - assert_equals(event.composed, true, "composed"); - assert_equals(event.isTrusted, true, "isTrusted"); - assert_equals(event.action, "", "action"); - assert_equals(event.target, interestee, "target"); - assert_equals(event.invoker, interestarea, "invoker"); - }, "InterestEvent dispatches on area focus"); - - promise_test(async function (t) { - t.add_cleanup(() => otherbutton.focus()); - let event = null; - interestee.addEventListener("interest", (e) => (event = e), { once: true }); await hoverOver(interestarea); + assert_true(!!event, "InterestEvent is fired"); assert_true(event instanceof InterestEvent, "event is InterestEvent"); assert_equals(event.type, "interest", "type"); assert_equals(event.bubbles, false, "bubbles"); assert_equals(event.composed, true, "composed"); assert_equals(event.isTrusted, true, "isTrusted"); - assert_equals(event.action, "", "action"); assert_equals(event.target, interestee, "target"); - assert_equals(event.invoker, interestarea, "invoker"); + assert_equals(event.source, interestarea, "source"); }, "InterestEvent dispatches on area hover"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-button-event-dispatch.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-button-event-dispatch.tentative.html index 69126dbe..a9d68bb03 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-button-event-dispatch.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-button-event-dispatch.tentative.html
@@ -16,71 +16,23 @@ <script> promise_test(async function (t) { - t.add_cleanup(() => otherbutton.focus()); - let event = null; - interestee.addEventListener("interest", (e) => (event = e), { once: true }); - interestbutton.focus(); - assert_true(event instanceof InterestEvent, "event is InterestEvent"); - assert_equals(event.type, "interest", "type"); - assert_equals(event.bubbles, false, "bubbles"); - assert_equals(event.composed, true, "composed"); - assert_equals(event.isTrusted, true, "isTrusted"); - assert_equals(event.action, "", "action"); - assert_equals(event.target, interestee, "target"); - assert_equals(event.invoker, interestbutton, "invoker"); - }, "InterestEvent dispatches on button focus"); - - promise_test(async function (t) { - t.add_cleanup(() => otherbutton.focus()); let event = null; interestee.addEventListener("interest", (e) => (event = e), { once: true }); await hoverOver(interestbutton); + assert_true(!!event, "InterestEvent is fired"); assert_true(event instanceof InterestEvent, "event is InterestEvent"); assert_equals(event.type, "interest", "type"); assert_equals(event.bubbles, false, "bubbles"); assert_equals(event.composed, true, "composed"); assert_equals(event.isTrusted, true, "isTrusted"); - assert_equals(event.action, "", "action"); assert_equals(event.target, interestee, "target"); - assert_equals(event.invoker, interestbutton, "invoker"); + assert_equals(event.source, interestbutton, "source"); }, "InterestEvent dispatches on button hover"); promise_test(async function (t) { - t.add_cleanup(() => otherbutton.focus()); - let event = null; - interestee.addEventListener("interest", (e) => (event = e), { once: true }); - interestbutton.interestAction = "fooBar"; - interestbutton.focus(); - assert_true(event instanceof InterestEvent, "event is InterestEvent"); - assert_equals(event.type, "interest", "type"); - assert_equals(event.bubbles, false, "bubbles"); - assert_equals(event.composed, true, "composed"); - assert_equals(event.isTrusted, true, "isTrusted"); - assert_equals(event.action, "fooBar", "action"); - assert_equals(event.target, interestee, "target"); - assert_equals(event.invoker, interestbutton, "invoker"); - }, "event action is set to interestAction"); - - promise_test(async function (t) { - t.add_cleanup(() => otherbutton.focus()); - let event = null; - interestee.addEventListener("interest", (e) => (event = e), { once: true }); - interestbutton.setAttribute("interestaction", "BaRbAz"); - interestbutton.focus(); - assert_true(event instanceof InterestEvent, "event is InterestEvent"); - assert_equals(event.type, "interest", "type"); - assert_equals(event.bubbles, false, "bubbles"); - assert_equals(event.composed, true, "composed"); - assert_equals(event.isTrusted, true, "isTrusted"); - assert_equals(event.action, "BaRbAz", "action"); - assert_equals(event.target, interestee, "target"); - assert_equals(event.invoker, interestbutton, "invoker"); - }, "event action is set to interestaction attribute"); - - promise_test(async function (t) { - t.add_cleanup(() => { + t.add_cleanup(async () => { interestbutton.removeAttribute('disabled'); - otherbutton.focus(); + await hoverOver(otherbutton); }); let called = false; interestee.addEventListener( @@ -91,34 +43,27 @@ { once: true }, ); interestbutton.setAttribute("disabled", ""); - interestbutton.focus(); + await hoverOver(interestbutton); assert_false(called, "event was not called"); }, "event does not dispatch if invoker is disabled"); promise_test(async function (t) { svgInterestee = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - t.add_cleanup(() => { + t.add_cleanup(async () => { interestbutton.interestTargetElement = interestee; svgInterestee.remove(); - otherbutton.focus(); + await hoverOver(otherbutton); }); document.body.append(svgInterestee); let called = false; assert_false(svgInterestee instanceof HTMLElement); assert_true(svgInterestee instanceof Element); let event = null; - svgInterestee.addEventListener( - "interest", - (e) => { - event = e; - called = true; - }, - { once: true }, - ); + svgInterestee.addEventListener("interest", (e) => (event = e), { once: true }); interestbutton.interestTargetElement = svgInterestee; - interestbutton.focus(); - assert_true(called, "event was called"); - assert_equals(event.invoker, interestbutton, "event.invoker is set to right element"); + await hoverOver(interestbutton); + assert_true(!!event, "InterestEvent is fired"); + assert_equals(event.source, interestbutton, "event.source is set to right element"); assert_equals(event.target, svgInterestee, "event.target is set to right element"); }, "event dispatches if interestee is non-HTML Element"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-on-popover-behavior.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-on-popover-behavior.tentative.html index fd0a77b9..cbb5e40 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-on-popover-behavior.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-on-popover-behavior.tentative.html
@@ -17,44 +17,17 @@ <button id="otherbutton">Other button</button> <script> - function reset() { + async function reset() { hoverOver(otherbutton); - otherbutton.focus(); + await hoverOver(otherbutton); interestee.hidePopover(); - interestbutton.removeAttribute("interestaction"); } - - // auto - promise_test(async function (t) { t.add_cleanup(reset); assert_false(interestee.matches(":popover-open")); await hoverOver(interestbutton); assert_true(interestee.matches(":popover-open")); - }, "hover interest invoking (as auto) closed popover opens"); - - promise_test(async function (t) { - t.add_cleanup(reset); - interestee.showPopover(); - assert_true(interestee.matches(":popover-open")); - await hoverOver(interestbutton); - assert_false(interestee.matches(":popover-open")); - }, "hover interest invoking (as auto) open popover closes"); - - promise_test(async function (t) { - t.add_cleanup(reset); - assert_false(interestee.matches(":popover-open")); - interestbutton.focus(); - assert_true(interestee.matches(":popover-open")); - }, "focus interest invoking (as auto) closed popover opens"); - - promise_test(async function (t) { - t.add_cleanup(reset); - interestee.showPopover(); - assert_true(interestee.matches(":popover-open")); - interestbutton.focus(); - assert_false(interestee.matches(":popover-open")); - }, "focus interest invoking (as auto) open popover closes"); + }, "hover interest invoking closed popover opens"); promise_test(async function (t) { t.add_cleanup(reset); @@ -64,50 +37,5 @@ }); await hoverOver(interestbutton); assert_false(interestee.matches(":popover-open")); - }, "interest invoking (as auto) closed popover with preventDefault does not open"); - - // togglepopover - - promise_test(async function (t) { - t.add_cleanup(reset); - assert_false(interestee.matches(":popover-open")); - interestbutton.setAttribute("interestaction", "toggle-popover"); - await hoverOver(interestbutton); - assert_true(interestee.matches(":popover-open")); - }, "hover interest invoking (as togglepopover) closed popover opens"); - - promise_test(async function (t) { - t.add_cleanup(reset); - interestee.showPopover(); - assert_true(interestee.matches(":popover-open")); - interestbutton.setAttribute("interestaction", "toggle-popover"); - await hoverOver(interestbutton); - assert_false(interestee.matches(":popover-open")); - }, "hover interest invoking (as togglepopover) open popover closes"); - - promise_test(async function (t) { - t.add_cleanup(reset); - assert_false(interestee.matches(":popover-open")); - interestbutton.setAttribute("interestaction", "toggle-popover"); - interestbutton.focus(); - assert_true(interestee.matches(":popover-open")); - }, "focus interest invoking (as togglepopover) closed popover opens"); - - promise_test(async function (t) { - t.add_cleanup(reset); - interestee.showPopover(); - assert_true(interestee.matches(":popover-open")); - interestbutton.setAttribute("interestaction", "toggle-popover"); - interestbutton.focus(); - assert_false(interestee.matches(":popover-open")); - }, "focus interest invoking (as togglepopover) open popover closes"); - - promise_test(async function (t) { - t.add_cleanup(reset); - assert_false(interestee.matches(":popover-open")); - interestbutton.setAttribute("interestaction", "tOgGlE-pOpOvEr"); - interestbutton.focus(); - assert_true(interestee.matches(":popover-open")); - }, "interest invoking (as togglepopover - case insensitive) closed popover opens"); - + }, "interest invoking closed popover with preventDefault does not open"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-svg-a-event-dispatch.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-svg-a-event-dispatch.tentative.html index 7fb4b1c19..8208c8d 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-svg-a-event-dispatch.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/the-button-element/interest-target/interesttarget-svg-a-event-dispatch.tentative.html
@@ -20,32 +20,19 @@ <script> promise_test(async function (t) { - t.add_cleanup(() => otherbutton.focus()); - let event = null; - interestee.addEventListener("interest", (e) => (event = e), { once: true }); - interestsvga.focus(); - assert_true(event instanceof InterestEvent, "event is InterestEvent"); - assert_equals(event.type, "interest", "type"); - assert_equals(event.bubbles, false, "bubbles"); - assert_equals(event.composed, true, "composed"); - assert_equals(event.isTrusted, true, "isTrusted"); - assert_equals(event.action, "", "action"); - assert_equals(event.target, interestee, "target"); - assert_equals(event.invoker, interestsvga, "invoker"); - }, "InterestEvent dispatches on svg a focus"); - - promise_test(async function (t) { - t.add_cleanup(() => otherbutton.focus()); + t.add_cleanup(async () => { + await hoverOver(otherbutton); + }); let event = null; interestee.addEventListener("interest", (e) => (event = e), { once: true }); await hoverOver(interestsvga); + assert_true(!!event, "InterestEvent is fired"); assert_true(event instanceof InterestEvent, "event is InterestEvent"); assert_equals(event.type, "interest", "type"); assert_equals(event.bubbles, false, "bubbles"); assert_equals(event.composed, true, "composed"); assert_equals(event.isTrusted, true, "isTrusted"); - assert_equals(event.action, "", "action"); assert_equals(event.target, interestee, "target"); - assert_equals(event.invoker, interestsvga, "invoker"); + assert_equals(event.source, interestsvga, "source"); }, "InterestEvent dispatches on svg a hover"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/css-fonts-5.idl b/third_party/blink/web_tests/external/wpt/interfaces/css-fonts-5.idl new file mode 100644 index 0000000..06461b0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/interfaces/css-fonts-5.idl
@@ -0,0 +1,54 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into webref +// (https://github.com/w3c/webref) +// Source: CSS Fonts Module Level 5 (https://drafts.csswg.org/css-fonts-5/) + +[Exposed=Window] +interface CSSFontFaceDescriptors : CSSStyleDeclaration { + attribute [LegacyNullToEmptyString] CSSOMString src; + attribute [LegacyNullToEmptyString] CSSOMString fontFamily; + attribute [LegacyNullToEmptyString] CSSOMString font-family; + attribute [LegacyNullToEmptyString] CSSOMString fontStyle; + attribute [LegacyNullToEmptyString] CSSOMString font-style; + attribute [LegacyNullToEmptyString] CSSOMString fontWeight; + attribute [LegacyNullToEmptyString] CSSOMString font-weight; + attribute [LegacyNullToEmptyString] CSSOMString fontStretch; + attribute [LegacyNullToEmptyString] CSSOMString font-stretch; + attribute [LegacyNullToEmptyString] CSSOMString fontWidth; + attribute [LegacyNullToEmptyString] CSSOMString font-width; + attribute [LegacyNullToEmptyString] CSSOMString fontSize; + attribute [LegacyNullToEmptyString] CSSOMString font-size; + attribute [LegacyNullToEmptyString] CSSOMString sizeAdjust; + attribute [LegacyNullToEmptyString] CSSOMString size-adjust; + attribute [LegacyNullToEmptyString] CSSOMString unicodeRange; + attribute [LegacyNullToEmptyString] CSSOMString unicode-range; + attribute [LegacyNullToEmptyString] CSSOMString fontFeatureSettings; + attribute [LegacyNullToEmptyString] CSSOMString font-feature-settings; + attribute [LegacyNullToEmptyString] CSSOMString fontVariationSettings; + attribute [LegacyNullToEmptyString] CSSOMString font-variation-settings; + attribute [LegacyNullToEmptyString] CSSOMString fontNamedInstance; + attribute [LegacyNullToEmptyString] CSSOMString font-named-instance; + attribute [LegacyNullToEmptyString] CSSOMString fontDisplay; + attribute [LegacyNullToEmptyString] CSSOMString font-display; + attribute [LegacyNullToEmptyString] CSSOMString fontLanguageOverride; + attribute [LegacyNullToEmptyString] CSSOMString font-language-override; + attribute [LegacyNullToEmptyString] CSSOMString ascentOverride; + attribute [LegacyNullToEmptyString] CSSOMString ascent-override; + attribute [LegacyNullToEmptyString] CSSOMString descentOverride; + attribute [LegacyNullToEmptyString] CSSOMString descent-override; + attribute [LegacyNullToEmptyString] CSSOMString lineGapOverride; + attribute [LegacyNullToEmptyString] CSSOMString line-gap-override; + attribute [LegacyNullToEmptyString] CSSOMString superscriptPositionOverride; + attribute [LegacyNullToEmptyString] CSSOMString superscript-position-override; + attribute [LegacyNullToEmptyString] CSSOMString subscriptPositionOverride; + attribute [LegacyNullToEmptyString] CSSOMString subscript-position-override; + attribute [LegacyNullToEmptyString] CSSOMString superscriptSizeOverride; + attribute [LegacyNullToEmptyString] CSSOMString superscript-size-override; + attribute [LegacyNullToEmptyString] CSSOMString subscriptSizeOverride; + attribute [LegacyNullToEmptyString] CSSOMString subscript-size-override; +}; + +[Exposed=Window] +interface CSSFontFaceRule : CSSRule { + [SameObject, PutForwards=cssText] readonly attribute CSSFontFaceDescriptors style; +};
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/css-fonts.idl b/third_party/blink/web_tests/external/wpt/interfaces/css-fonts.idl index d5c9dc8..9b8034bc 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/css-fonts.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/css-fonts.idl
@@ -3,44 +3,6 @@ // (https://github.com/w3c/webref) // Source: CSS Fonts Module Level 4 (https://drafts.csswg.org/css-fonts-4/) -[Exposed=Window] -interface CSSFontFaceDescriptors : CSSStyleDeclaration { - attribute [LegacyNullToEmptyString] CSSOMString src; - attribute [LegacyNullToEmptyString] CSSOMString fontFamily; - attribute [LegacyNullToEmptyString] CSSOMString font-family; - attribute [LegacyNullToEmptyString] CSSOMString fontStyle; - attribute [LegacyNullToEmptyString] CSSOMString font-style; - attribute [LegacyNullToEmptyString] CSSOMString fontWeight; - attribute [LegacyNullToEmptyString] CSSOMString font-weight; - attribute [LegacyNullToEmptyString] CSSOMString fontStretch; - attribute [LegacyNullToEmptyString] CSSOMString font-stretch; - attribute [LegacyNullToEmptyString] CSSOMString fontWidth; - attribute [LegacyNullToEmptyString] CSSOMString font-width; - attribute [LegacyNullToEmptyString] CSSOMString unicodeRange; - attribute [LegacyNullToEmptyString] CSSOMString unicode-range; - attribute [LegacyNullToEmptyString] CSSOMString fontFeatureSettings; - attribute [LegacyNullToEmptyString] CSSOMString font-feature-settings; - attribute [LegacyNullToEmptyString] CSSOMString fontVariationSettings; - attribute [LegacyNullToEmptyString] CSSOMString font-variation-settings; - attribute [LegacyNullToEmptyString] CSSOMString fontNamedInstance; - attribute [LegacyNullToEmptyString] CSSOMString font-named-instance; - attribute [LegacyNullToEmptyString] CSSOMString fontDisplay; - attribute [LegacyNullToEmptyString] CSSOMString font-display; - attribute [LegacyNullToEmptyString] CSSOMString fontLanguageOverride; - attribute [LegacyNullToEmptyString] CSSOMString font-language-override; - attribute [LegacyNullToEmptyString] CSSOMString ascentOverride; - attribute [LegacyNullToEmptyString] CSSOMString ascent-override; - attribute [LegacyNullToEmptyString] CSSOMString descentOverride; - attribute [LegacyNullToEmptyString] CSSOMString descent-override; - attribute [LegacyNullToEmptyString] CSSOMString lineGapOverride; - attribute [LegacyNullToEmptyString] CSSOMString line-gap-override; -}; - -[Exposed=Window] -interface CSSFontFaceRule : CSSRule { - [SameObject, PutForwards=cssText] readonly attribute CSSFontFaceDescriptors style; -}; - partial interface CSSRule { const unsigned short FONT_FEATURE_VALUES_RULE = 14; }; [Exposed=Window]
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/css-mixins.idl b/third_party/blink/web_tests/external/wpt/interfaces/css-mixins.idl index 49806ab..6629b38 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/css-mixins.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/css-mixins.idl
@@ -5,3 +5,13 @@ [Exposed=Window] interface CSSFunctionRule : CSSGroupingRule { }; + +[Exposed=Window] +interface CSSFunctionDescriptors : CSSStyleDeclaration { + attribute [LegacyNullToEmptyString] CSSOMString result; +}; + +[Exposed=Window] +interface CSSFunctionDeclarations : CSSRule { + [SameObject, PutForwards=cssText] readonly attribute CSSFunctionDescriptors style; +};
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/digital-credentials.idl b/third_party/blink/web_tests/external/wpt/interfaces/digital-credentials.idl index e20079e..e4ebb3b 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/digital-credentials.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/digital-credentials.idl
@@ -19,5 +19,5 @@ [Exposed=Window, SecureContext] interface DigitalCredential : Credential { readonly attribute DOMString protocol; - readonly attribute object data; + [SameObject] readonly attribute object data; };
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/fedcm.idl b/third_party/blink/web_tests/external/wpt/interfaces/fedcm.idl index 16b5b2f..07f7955f 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/fedcm.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/fedcm.idl
@@ -49,6 +49,7 @@ USVString nonce; DOMString loginHint; DOMString domainHint; + sequence<USVString> fields; any params; };
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/html.idl b/third_party/blink/web_tests/external/wpt/interfaces/html.idl index d4f8b9a7..3832a6f9 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/html.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/html.idl
@@ -1222,9 +1222,11 @@ [CEReactions] attribute boolean open; attribute DOMString returnValue; + [CEReactions] attribute DOMString closedBy; [CEReactions] undefined show(); [CEReactions] undefined showModal(); [CEReactions] undefined close(optional DOMString returnValue); + [CEReactions] undefined requestClose(optional DOMString returnValue); }; [Exposed=Window]
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/mediacapture-surface-control.idl b/third_party/blink/web_tests/external/wpt/interfaces/mediacapture-surface-control.idl index b0bbd22..964f662d 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/mediacapture-surface-control.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/mediacapture-surface-control.idl
@@ -12,5 +12,5 @@ partial interface CaptureController { constructor(); - Promise<undefined> forwardWheel(HTMLElement element); + Promise<undefined> forwardWheel(HTMLElement? element); };
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/permissions-policy.idl b/third_party/blink/web_tests/external/wpt/interfaces/permissions-policy.idl index 5878d8d1..806d2eb 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/permissions-policy.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/permissions-policy.idl
@@ -27,4 +27,5 @@ readonly attribute long? lineNumber; readonly attribute long? columnNumber; readonly attribute DOMString disposition; + readonly attribute DOMString? allowAttribute; };
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/shared-storage.idl b/third_party/blink/web_tests/external/wpt/interfaces/shared-storage.idl index b6863eff..6f38d67 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/shared-storage.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/shared-storage.idl
@@ -39,14 +39,48 @@ }; [Exposed=(Window,SharedStorageWorklet)] +interface SharedStorageModifierMethod {}; + +[Exposed=(Window, SharedStorageWorklet)] +interface SharedStorageSetMethod : SharedStorageModifierMethod { + constructor(DOMString key, DOMString value, optional SharedStorageSetMethodOptions options = {}); +}; + +[Exposed=(Window, SharedStorageWorklet)] +interface SharedStorageAppendMethod : SharedStorageModifierMethod { + constructor(DOMString key, DOMString value, optional SharedStorageModifierMethodOptions options = {}); +}; + +[Exposed=(Window, SharedStorageWorklet)] +interface SharedStorageDeleteMethod : SharedStorageModifierMethod { + constructor(DOMString key, optional SharedStorageModifierMethodOptions options = {}); +}; + +[Exposed=(Window, SharedStorageWorklet)] +interface SharedStorageClearMethod : SharedStorageModifierMethod { + constructor(optional SharedStorageModifierMethodOptions options = {}); +}; + +dictionary SharedStorageModifierMethodOptions { + DOMString withLock; +}; + +dictionary SharedStorageSetMethodOptions : SharedStorageModifierMethodOptions { + boolean ignoreIfPresent; +}; + +[Exposed=(Window,SharedStorageWorklet)] interface SharedStorage { Promise<any> set(DOMString key, DOMString value, optional SharedStorageSetMethodOptions options = {}); Promise<any> append(DOMString key, - DOMString value); - Promise<any> delete(DOMString key); - Promise<any> clear(); + DOMString value, + optional SharedStorageModifierMethodOptions options = {}); + Promise<any> delete(DOMString key, optional SharedStorageModifierMethodOptions options = {}); + Promise<any> clear(optional SharedStorageModifierMethodOptions options = {}); + Promise<any> batchUpdate(sequence<SharedStorageModifierMethod> methods, + optional SharedStorageModifierMethodOptions options = {}); [Exposed=Window] Promise<SharedStorageResponse> selectURL(DOMString name, @@ -76,10 +110,6 @@ async iterable<DOMString, DOMString>; }; -dictionary SharedStorageSetMethodOptions { - boolean ignoreIfPresent = false; -}; - dictionary SharedStoragePrivateAggregationConfig { USVString aggregationCoordinatorOrigin; USVString contextId;
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/webnn.idl b/third_party/blink/web_tests/external/wpt/interfaces/webnn.idl index 132280b..3e1d9a9f4 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/webnn.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/webnn.idl
@@ -34,6 +34,10 @@ typedef record<USVString, MLTensor> MLNamedTensors; +dictionary MLContextLostInfo { + DOMString message; +}; + [SecureContext, Exposed=(Window, DedicatedWorker)] interface MLContext { undefined dispatch(MLGraph graph, MLNamedTensors inputs, MLNamedTensors outputs); @@ -46,6 +50,10 @@ undefined writeTensor(MLTensor tensor, AllowSharedBufferSource inputData); MLOpSupportLimits opSupportLimits(); + + undefined destroy(); + + readonly attribute Promise<MLContextLostInfo> lost; }; dictionary MLOpSupportLimits { @@ -71,7 +79,9 @@ }; [SecureContext, Exposed=(Window, DedicatedWorker)] -interface MLGraph {}; +interface MLGraph { + undefined destroy(); +}; enum MLInputOperandLayout { "nchw",
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/idlharness.window-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/idlharness.window-expected.txt index f901356..a49f0943 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/idlharness.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/idlharness.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 34 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 35 FAIL, 0 TIMEOUT, 0 NOTRUN. [FAIL] PermissionsPolicy interface: existence and properties of interface object assert_own_property: self does not have own property "PermissionsPolicy" expected property "PermissionsPolicy" missing [FAIL] PermissionsPolicy interface object length @@ -60,6 +60,8 @@ assert_own_property: self does not have own property "PermissionsPolicyViolationReportBody" expected property "PermissionsPolicyViolationReportBody" missing [FAIL] PermissionsPolicyViolationReportBody interface: attribute disposition assert_own_property: self does not have own property "PermissionsPolicyViolationReportBody" expected property "PermissionsPolicyViolationReportBody" missing +[FAIL] PermissionsPolicyViolationReportBody interface: attribute allowAttribute + assert_own_property: self does not have own property "PermissionsPolicyViolationReportBody" expected property "PermissionsPolicyViolationReportBody" missing [FAIL] HTMLIFrameElement interface: attribute permissionsPolicy assert_true: The prototype object must have a property "permissionsPolicy" expected true got false [FAIL] HTMLIFrameElement interface: document.createElement("iframe") must inherit property "permissionsPolicy" with the proper type
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/about-blank-replacement.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/about-blank-replacement.https-expected.txt index 329f457..dff7120 100644 --- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/about-blank-replacement.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/about-blank-replacement.https-expected.txt
@@ -7,8 +7,6 @@ assert_false: result: failure: could not find about:blank client expected false got true [FAIL] Simple about:blank is controlled and is exposed to clients.matchAll(). promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of null (reading 'scriptURL')" -[FAIL] Nested about:srcdoc is controlled and is exposed to clients.matchAll(). - promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of null (reading 'scriptURL')" [FAIL] Dynamic about:blank is controlled and is exposed to clients.matchAll(). promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of null (reading 'scriptURL')" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/srcdoc-iframe-worker.js b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/srcdoc-iframe-worker.js new file mode 100644 index 0000000..548116c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/srcdoc-iframe-worker.js
@@ -0,0 +1,11 @@ +self.addEventListener('message', event => { + event.source.postMessage('passed'); +}); + +self.addEventListener('fetch', event => { + let url = new URL(event.request.url); + if (!url.searchParams.get('test_resource')) { + return; + } + event.respondWith(new Response('passed')); +});
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/srcdoc-iframe.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/srcdoc-iframe.html new file mode 100644 index 0000000..6407845 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/srcdoc-iframe.html
@@ -0,0 +1,92 @@ +<!doctype html> +<html> +<body> +<iframe id="srcdocFrame" srcdoc=" +<script> + function reportTestResult(result) { + top.postMessage({ type: 'TEST_RESULT', result: result }, '*'); + } + + async function postMessageToController() { + let controller = navigator.serviceWorker.controller; + if (!controller) { + reportTestResult('no navigator.serviceWorker.controller'); + } + try { + controller.postMessage('test'); + } catch (e) { + reportTestResult('Unexpected Error ' + e.name + ' : ' + e.message); + } + } + + async function getServiceWorkerRegistration(scope) { + try { + let reg = await navigator.serviceWorker.getRegistration(scope); + if (!reg) { + reportTestResult('no regsitration for ' + scope); + } + if (reg.scope !== scope) { + reportTestResult('regsitration scope does not match'); + } + + if (!reg.active) { + reportTestResult('regsitration.active is not valid' + reg.active); + } + reportTestResult('passed'); + } catch (e) { + reportTestResult('Unexpected Error ' + e.name + ' : ' + e.message); + } + } + + function addSrcdocIframeWithSandbox(sandbox) { + let frame = document.createElement('iframe'); + frame.sandbox = sandbox; + frame.srcdoc = ` + <script> + function reportTestResult(result) { + top.postMessage({ type: 'TEST_RESULT', result: result }, '*'); + } + + window.onload = function onLoad() { + try { + let controller = navigator.serviceWorker.controller; + reportTestResult(controller ? 'HasController' : 'NoController'); + } catch (e) { + reportTestResult((e.name == 'SecurityError') ? + 'NoController' : 'UnexpectedError:' + e.message); + } + } + <\/script>`; + document.body.appendChild(frame); + } + + function addSandboxedSrcdocFrame() { + addSrcdocIframeWithSandbox('allow-scripts'); + } + + function addSameOriginSandboxedSrcdocFrame() { + addSrcdocIframeWithSandbox('allow-scripts allow-same-origin'); + } + + async function fetchResource() { + let response = await fetch('?test_resource=1'); + reportTestResult(await response.text()); + } + + window.navigator.serviceWorker.addEventListener( + 'message', function onMsg(evt) { + // Forward the message as test result. + reportTestResult(evt.data); + }); +</script> +"></iframe> + +<script> +// Helper routine to make it slightly easier for our parent to find +// the srcdoc frame. +function srcdocFrame() { + return document.getElementById('srcdocFrame').contentWindow; +} +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/srcdoc-iframe.https.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/srcdoc-iframe.https.html new file mode 100644 index 0000000..9c1c88e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/srcdoc-iframe.https.html
@@ -0,0 +1,66 @@ +<!DOCTYPE html> +<title>Service Worker: srcdoc frame handling</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/test-helpers.sub.js"></script> +<body> +<script> + +// This test attempts to verify various service worker behaviors in +// srcdoc iframe. + +function runTestInSrcDocFrame(testFunc, testFuncParam) { + return new Promise((resolve, reject) => { + window.addEventListener('message', function onMsg(evt) { + if (evt.data.type !== 'TEST_RESULT') { + return; + } + window.removeEventListener('message', onMsg); + resolve(evt.data.result); + }); + testFunc(testFuncParam); + }); +} + +async function doAsyncTest(t, testFuncName, expectedResult) { + const worker = 'resources/srcdoc-iframe-worker.js'; + const scope = 'resources/srcdoc-iframe.html'; + + let reg = await service_worker_unregister_and_register(t, worker, scope); + + t.add_cleanup(() => service_worker_unregister(t, scope)); + + await wait_for_state(t, reg.installing, 'activated'); + + let frame = await with_iframe(scope); + let scopeFullUlr = frame.contentWindow.location.href; + + let testFunc = frame.contentWindow.srcdocFrame()[testFuncName]; + let testResult = await runTestInSrcDocFrame(testFunc, scopeFullUlr); + assert_equals(testResult, expectedResult); + + frame.remove(); +} + +promise_test(async function(t) { + await doAsyncTest(t, 'addSandboxedSrcdocFrame', 'NoController'); +}, 'nested sandboxed srcdoc frame should not inherit controller'); + +promise_test(async function(t) { + await doAsyncTest(t, 'addSameOriginSandboxedSrcdocFrame', 'HasController'); +}, 'nested same origin sandboxed srcdoc frame should inherit controller'); + +promise_test(async function(t) { + await doAsyncTest(t, 'fetchResource', 'passed'); +}, 'should be able to serve resource from controller for srcdoc frame'); + +promise_test(async function(t) { + await doAsyncTest(t, 'getServiceWorkerRegistration', 'passed'); +}, 'getRegistration should work in srcdoc iframe'); + +promise_test(async function(t) { + await doAsyncTest(t, 'postMessageToController', 'passed'); +}, 'controller.postMessage should work in srcdoc iframe'); + +</script> +</body> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/urlpattern/resources/urlpatterntestdata.json b/third_party/blink/web_tests/external/wpt/urlpattern/resources/urlpatterntestdata.json index 058079b..1d2ba25 100644 --- a/third_party/blink/web_tests/external/wpt/urlpattern/resources/urlpatterntestdata.json +++ b/third_party/blink/web_tests/external/wpt/urlpattern/resources/urlpatterntestdata.json
@@ -1122,6 +1122,63 @@ } }, { + "pattern": ["http://\uD83D\uDEB2.com/"], + "inputs": ["http://\uD83D\uDEB2.com/"], + "exactly_empty_components": [ "port" ], + "expected_obj": { + "protocol": "http", + "hostname": "xn--h78h.com", + "pathname": "/" + }, + "expected_match": { + "protocol": { "input": "http", "groups": {}}, + "hostname": { "input": "xn--h78h.com", "groups": {}}, + "pathname": { "input": "/", "groups": {}} + } + }, + { + "pattern": ["http://\uD83D \uDEB2"], + "expected_obj": "error" + }, + { + "pattern": [{"hostname":"\uD83D \uDEB2"}], + "expected_obj": "error" + }, + { + "pattern": [{"pathname":"\uD83D \uDEB2"}], + "inputs": [], + "expected_obj": { + "pathname": "%EF%BF%BD%20%EF%BF%BD" + }, + "expected_match": null + }, + { + "pattern": [{"pathname":":\uD83D \uDEB2"}], + "expected_obj": "error" + }, + { + "pattern": [{"pathname":":a\uDB40\uDD00b"}], + "inputs": [], + "expected_obj": { + "pathname": ":a\uDB40\uDD00b" + }, + "expected_match": null + }, + { + "pattern": [{"pathname":"test/:a\uD801\uDC50b"}], + "inputs": [{"pathname":"test/foo"}], + "expected_obj": { + "pathname": "test/:a\uD801\uDC50b" + }, + "expected_match": { + "pathname": { "input": "test/foo", "groups": { "a\uD801\uDC50b": "foo" }} + } + }, + { + "pattern": [{"pathname":":\uD83D\uDEB2"}], + "expected_obj": "error" + }, + { "pattern": [{ "port": "" }], "inputs": [{ "protocol": "http", "port": "80" }], "exactly_empty_components": [ "port" ],
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html index c935644..9eb7020a 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html +++ b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html
@@ -46,8 +46,6 @@ assert_equals(await updatePromise, "got expected"); await playingPromise; - assert_equals(video.videoTracks.length, 1); - assert_equals(video.audioTracks.length, 0); }, "Receiver and sender read, modifiy and write video frames."); @@ -83,8 +81,6 @@ assert_equals(await updatePromise, "got expected"); await playingPromise; - assert_equals(video.videoTracks.length, 0); - assert_equals(video.audioTracks.length, 1); }, "Receiver and sender read, modifiy and write audio frames.");
diff --git a/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt b/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt index 6b6aa1fd..bd3d4734 100644 --- a/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt +++ b/third_party/blink/web_tests/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt
@@ -11,7 +11,19 @@ .. .. - + +.. +.. + +.. +.. + +.. +.. + +.. +.. + .. .. @@ -19,9 +31,17 @@ 1 2 +.. +.. +.. +.. +.. +.. +.. +.. @@ -31,7 +51,9 @@ One Two - + +some text + .. ..
diff --git a/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt b/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt index befdf3c..736fa94 100644 --- a/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt +++ b/third_party/blink/web_tests/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt
@@ -24,5 +24,12 @@ .. - - + +.. .. + +.. .. + + +.. .. + +.. ..
diff --git a/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges-expected.txt b/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges-expected.txt index 90b80b7..0c2aa15e 100644 --- a/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges-expected.txt
@@ -8,235 +8,235 @@ Step 3 Retrieved ranges: [{"from":0,"to":10}] -[0] A 773492 492 -[1] A 213482 482 -[2] A 613482 482 -[3] A 853472 472 -[4] A 1813462 462 -[5] A 413452 452 -[6] A 1413452 452 -[7] A 1853442 442 -[8] A 573432 432 -[9] A 533412 412 +[0] A 77349 2 49 2 +[1] A 21348 2 48 2 +[2] A 61348 2 48 2 +[3] A 85347 2 47 2 +[4] A 181346 2 46 2 +[5] A 41345 2 45 2 +[6] A 141345 2 45 2 +[7] A 185344 2 44 2 +[8] A 57343 2 43 2 +[9] A 53341 2 41 2 [10] Show 10 beforeShow all 40Show 10 after Step 4 Retrieved ranges: [{"from":0,"to":10},{"from":30,"to":40}] -[0] A 773492 492 -[1] A 213482 482 -[2] A 613482 482 -[3] A 853472 472 -[4] A 1813462 462 -[5] A 413452 452 -[6] A 1413452 452 -[7] A 1853442 442 -[8] A 573432 432 -[9] A 533412 412 +[0] A 77349 2 49 2 +[1] A 21348 2 48 2 +[2] A 61348 2 48 2 +[3] A 85347 2 47 2 +[4] A 181346 2 46 2 +[5] A 41345 2 45 2 +[6] A 141345 2 45 2 +[7] A 185344 2 44 2 +[8] A 57343 2 43 2 +[9] A 53341 2 41 2 [10] Show 10 beforeShow all 20Show 10 after -[11] A 1333241 241 -[12] A 173231 231 -[13] A 1453231 231 -[14] A 1773211 211 -[15] A 1973211 211 -[16] A 1893181 181 -[17] A 253161 161 -[18] A 1093151 151 -[19] A 2013151 151 -[20] A 1933131 131 +[11] A 133324 1 24 1 +[12] A 17323 1 23 1 +[13] A 145323 1 23 1 +[14] A 177321 1 21 1 +[15] A 197321 1 21 1 +[16] A 189318 1 18 1 +[17] A 25316 1 16 1 +[18] A 109315 1 15 1 +[19] A 201315 1 15 1 +[20] A 193313 1 13 1 [21] Show 10 beforeShow all 10Show 10 after Step 5 Retrieved ranges: [{"from":0,"to":10},{"from":20,"to":25},{"from":30,"to":40}] -[0] A 773492 492 -[1] A 213482 482 -[2] A 613482 482 -[3] A 853472 472 -[4] A 1813462 462 -[5] A 413452 452 -[6] A 1413452 452 -[7] A 1853442 442 -[8] A 573432 432 -[9] A 533412 412 +[0] A 77349 2 49 2 +[1] A 21348 2 48 2 +[2] A 61348 2 48 2 +[3] A 85347 2 47 2 +[4] A 181346 2 46 2 +[5] A 41345 2 45 2 +[6] A 141345 2 45 2 +[7] A 185344 2 44 2 +[8] A 57343 2 43 2 +[9] A 53341 2 41 2 [10] Show 10 beforeShow all 10Show 10 after -[11] A 1293342 342 -[12] A 813312 312 -[13] A 1573302 302 -[14] A 1373291 291 -[15] A 1693291 291 +[11] A 129334 2 34 2 +[12] A 81331 2 31 2 +[13] A 157330 2 30 2 +[14] A 137329 1 29 1 +[15] A 169329 1 29 1 [16] Show 10 beforeShow all 5Show 10 after -[17] A 1333241 241 -[18] A 173231 231 -[19] A 1453231 231 -[20] A 1773211 211 -[21] A 1973211 211 -[22] A 1893181 181 -[23] A 253161 161 -[24] A 1093151 151 -[25] A 2013151 151 -[26] A 1933131 131 +[17] A 133324 1 24 1 +[18] A 17323 1 23 1 +[19] A 145323 1 23 1 +[20] A 177321 1 21 1 +[21] A 197321 1 21 1 +[22] A 189318 1 18 1 +[23] A 25316 1 16 1 +[24] A 109315 1 15 1 +[25] A 201315 1 15 1 +[26] A 193313 1 13 1 [27] Show 10 beforeShow all 10Show 10 after Step 6 Retrieved ranges: [{"from":0,"to":10},{"from":20,"to":25},{"from":28,"to":40}] -[0] A 773492 492 -[1] A 213482 482 -[2] A 613482 482 -[3] A 853472 472 -[4] A 1813462 462 -[5] A 413452 452 -[6] A 1413452 452 -[7] A 1853442 442 -[8] A 573432 432 -[9] A 533412 412 +[0] A 77349 2 49 2 +[1] A 21348 2 48 2 +[2] A 61348 2 48 2 +[3] A 85347 2 47 2 +[4] A 181346 2 46 2 +[5] A 41345 2 45 2 +[6] A 141345 2 45 2 +[7] A 185344 2 44 2 +[8] A 57343 2 43 2 +[9] A 53341 2 41 2 [10] Show 10 beforeShow all 10Show 10 after -[11] A 1293342 342 -[12] A 813312 312 -[13] A 1573302 302 -[14] A 1373291 291 -[15] A 1693291 291 +[11] A 129334 2 34 2 +[12] A 81331 2 31 2 +[13] A 157330 2 30 2 +[14] A 137329 1 29 1 +[15] A 169329 1 29 1 [16] Show 10 beforeShow all 3Show 10 after -[17] A 453251 251 -[18] A 333241 241 -[19] A 1333241 241 -[20] A 173231 231 -[21] A 1453231 231 -[22] A 1773211 211 -[23] A 1973211 211 -[24] A 1893181 181 -[25] A 253161 161 -[26] A 1093151 151 -[27] A 2013151 151 -[28] A 1933131 131 +[17] A 45325 1 25 1 +[18] A 33324 1 24 1 +[19] A 133324 1 24 1 +[20] A 17323 1 23 1 +[21] A 145323 1 23 1 +[22] A 177321 1 21 1 +[23] A 197321 1 21 1 +[24] A 189318 1 18 1 +[25] A 25316 1 16 1 +[26] A 109315 1 15 1 +[27] A 201315 1 15 1 +[28] A 193313 1 13 1 [29] Show 10 beforeShow all 10Show 10 after Step 7 Retrieved ranges: [{"from":0,"to":10},{"from":18,"to":26},{"from":28,"to":40}] -[0] A 773492 492 -[1] A 213482 482 -[2] A 613482 482 -[3] A 853472 472 -[4] A 1813462 462 -[5] A 413452 452 -[6] A 1413452 452 -[7] A 1853442 442 -[8] A 573432 432 -[9] A 533412 412 +[0] A 77349 2 49 2 +[1] A 21348 2 48 2 +[2] A 61348 2 48 2 +[3] A 85347 2 47 2 +[4] A 181346 2 46 2 +[5] A 41345 2 45 2 +[6] A 141345 2 45 2 +[7] A 185344 2 44 2 +[8] A 57343 2 43 2 +[9] A 53341 2 41 2 [10] Show 10 beforeShow all 8Show 10 after -[11] A 1253352 352 -[12] A 1173342 342 -[13] A 1293342 342 -[14] A 813312 312 -[15] A 1573302 302 -[16] A 1373291 291 -[17] A 1693291 291 -[18] A 2053281 281 +[11] A 125335 2 35 2 +[12] A 117334 2 34 2 +[13] A 129334 2 34 2 +[14] A 81331 2 31 2 +[15] A 157330 2 30 2 +[16] A 137329 1 29 1 +[17] A 169329 1 29 1 +[18] A 205328 1 28 1 [19] Show 10 beforeShow all 2Show 10 after -[20] A 453251 251 -[21] A 333241 241 -[22] A 1333241 241 -[23] A 173231 231 -[24] A 1453231 231 -[25] A 1773211 211 -[26] A 1973211 211 -[27] A 1893181 181 -[28] A 253161 161 -[29] A 1093151 151 -[30] A 2013151 151 -[31] A 1933131 131 +[20] A 45325 1 25 1 +[21] A 33324 1 24 1 +[22] A 133324 1 24 1 +[23] A 17323 1 23 1 +[24] A 145323 1 23 1 +[25] A 177321 1 21 1 +[26] A 197321 1 21 1 +[27] A 189318 1 18 1 +[28] A 25316 1 16 1 +[29] A 109315 1 15 1 +[30] A 201315 1 15 1 +[31] A 193313 1 13 1 [32] Show 10 beforeShow all 10Show 10 after Step 8 Retrieved ranges: [{"from":0,"to":10},{"from":15,"to":45}] -[0] A 773492 492 -[1] A 213482 482 -[2] A 613482 482 -[3] A 853472 472 -[4] A 1813462 462 -[5] A 413452 452 -[6] A 1413452 452 -[7] A 1853442 442 -[8] A 573432 432 -[9] A 533412 412 +[0] A 77349 2 49 2 +[1] A 21348 2 48 2 +[2] A 61348 2 48 2 +[3] A 85347 2 47 2 +[4] A 181346 2 46 2 +[5] A 41345 2 45 2 +[6] A 141345 2 45 2 +[7] A 185344 2 44 2 +[8] A 57343 2 43 2 +[9] A 53341 2 41 2 [10] Show 10 beforeShow all 5Show 10 after -[11] A 653382 382 -[12] A 1133382 382 -[13] A 1533362 362 -[14] A 1253352 352 -[15] A 1173342 342 -[16] A 1293342 342 -[17] A 813312 312 -[18] A 1573302 302 -[19] A 1373291 291 -[20] A 1693291 291 -[21] A 2053281 281 -[22] A 373271 271 -[23] A 493261 261 -[24] A 453251 251 -[25] A 333241 241 -[26] A 1333241 241 -[27] A 173231 231 -[28] A 1453231 231 -[29] A 1773211 211 -[30] A 1973211 211 -[31] A 1893181 181 -[32] A 253161 161 -[33] A 1093151 151 -[34] A 2013151 151 -[35] A 1933131 131 -[36] A 1493121 121 -[37] A 693111 111 -[38] A 29390 90 -[39] A 121380 80 -[40] A 165380 80 +[11] A 65338 2 38 2 +[12] A 113338 2 38 2 +[13] A 153336 2 36 2 +[14] A 125335 2 35 2 +[15] A 117334 2 34 2 +[16] A 129334 2 34 2 +[17] A 81331 2 31 2 +[18] A 157330 2 30 2 +[19] A 137329 1 29 1 +[20] A 169329 1 29 1 +[21] A 205328 1 28 1 +[22] A 37327 1 27 1 +[23] A 49326 1 26 1 +[24] A 45325 1 25 1 +[25] A 33324 1 24 1 +[26] A 133324 1 24 1 +[27] A 17323 1 23 1 +[28] A 145323 1 23 1 +[29] A 177321 1 21 1 +[30] A 197321 1 21 1 +[31] A 189318 1 18 1 +[32] A 25316 1 16 1 +[33] A 109315 1 15 1 +[34] A 201315 1 15 1 +[35] A 193313 1 13 1 +[36] A 149312 1 12 1 +[37] A 69311 1 11 1 +[38] A 2939 0 9 0 +[39] A 12138 0 8 0 +[40] A 16538 0 8 0 [41] Show 10 beforeShow all 5Show 10 after Step 9 Retrieved ranges: [{"from":0,"to":45}] -[0] A 773492 492 -[1] A 213482 482 -[2] A 613482 482 -[3] A 853472 472 -[4] A 1813462 462 -[5] A 413452 452 -[6] A 1413452 452 -[7] A 1853442 442 -[8] A 573432 432 -[9] A 533412 412 -[10] A 893402 402 -[11] A 973402 402 -[12] A 733392 392 -[13] A 1013392 392 -[14] A 133382 382 -[15] A 653382 382 -[16] A 1133382 382 -[17] A 1533362 362 -[18] A 1253352 352 -[19] A 1173342 342 -[20] A 1293342 342 -[21] A 813312 312 -[22] A 1573302 302 -[23] A 1373291 291 -[24] A 1693291 291 -[25] A 2053281 281 -[26] A 373271 271 -[27] A 493261 261 -[28] A 453251 251 -[29] A 333241 241 -[30] A 1333241 241 -[31] A 173231 231 -[32] A 1453231 231 -[33] A 1773211 211 -[34] A 1973211 211 -[35] A 1893181 181 -[36] A 253161 161 -[37] A 1093151 151 -[38] A 2013151 151 -[39] A 1933131 131 -[40] A 1493121 121 -[41] A 693111 111 -[42] A 29390 90 -[43] A 121380 80 -[44] A 165380 80 +[0] A 77349 2 49 2 +[1] A 21348 2 48 2 +[2] A 61348 2 48 2 +[3] A 85347 2 47 2 +[4] A 181346 2 46 2 +[5] A 41345 2 45 2 +[6] A 141345 2 45 2 +[7] A 185344 2 44 2 +[8] A 57343 2 43 2 +[9] A 53341 2 41 2 +[10] A 89340 2 40 2 +[11] A 97340 2 40 2 +[12] A 73339 2 39 2 +[13] A 101339 2 39 2 +[14] A 13338 2 38 2 +[15] A 65338 2 38 2 +[16] A 113338 2 38 2 +[17] A 153336 2 36 2 +[18] A 125335 2 35 2 +[19] A 117334 2 34 2 +[20] A 129334 2 34 2 +[21] A 81331 2 31 2 +[22] A 157330 2 30 2 +[23] A 137329 1 29 1 +[24] A 169329 1 29 1 +[25] A 205328 1 28 1 +[26] A 37327 1 27 1 +[27] A 49326 1 26 1 +[28] A 45325 1 25 1 +[29] A 33324 1 24 1 +[30] A 133324 1 24 1 +[31] A 17323 1 23 1 +[32] A 145323 1 23 1 +[33] A 177321 1 21 1 +[34] A 197321 1 21 1 +[35] A 189318 1 18 1 +[36] A 25316 1 16 1 +[37] A 109315 1 15 1 +[38] A 201315 1 15 1 +[39] A 193313 1 13 1 +[40] A 149312 1 12 1 +[41] A 69311 1 11 1 +[42] A 2939 0 9 0 +[43] A 12138 0 8 0 +[44] A 16538 0 8 0 [45] Show 10 beforeShow all 5Show 10 after Profiler was disabled.
diff --git a/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges.js b/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges.js index 73cf1cd..dc323cf 100644 --- a/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges.js +++ b/third_party/blink/web_tests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges.js
@@ -23,7 +23,8 @@ TestRunner.addResult(step); TestRunner.addResult('Retrieved ranges: ' + JSON.stringify(row.retrievedChildrenRanges)); for (var i = 0; i < row.children.length; ++i) - TestRunner.addResult('[' + i + '] ' + row.children[i].element().textContent.replace(/[^\w\d]/mg, ' ')); + TestRunner.addResult('[' + i + '] ' + row.children[i].element().textContent + .replace(/[@%B]|\s+/mg, ' ')); return row.populateChildren(from, to); }
diff --git a/third_party/blink/web_tests/platform/webview/external/wpt/bluetooth/idl/idlharness.tentative.https.window-expected.txt b/third_party/blink/web_tests/platform/webview/external/wpt/bluetooth/idl/idlharness.tentative.https.window-expected.txt deleted file mode 100644 index 26bf149b..0000000 --- a/third_party/blink/web_tests/platform/webview/external/wpt/bluetooth/idl/idlharness.tentative.https.window-expected.txt +++ /dev/null
@@ -1,323 +0,0 @@ -This is a testharness.js-based test. -Found 160 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] Bluetooth interface: existence and properties of interface object - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface object length - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface object name - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: operation getAvailability() - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: attribute onavailabilitychanged - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: attribute referringDevice - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: operation getDevices() - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: operation requestDevice(optional RequestDeviceOptions) - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: attribute onadvertisementreceived - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: attribute ongattserverdisconnected - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: attribute oncharacteristicvaluechanged - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: attribute onserviceadded - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: attribute onservicechanged - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth interface: attribute onserviceremoved - assert_own_property: self does not have own property "Bluetooth" expected property "Bluetooth" missing -[FAIL] Bluetooth must be primary interface of navigator.bluetooth - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Stringification of navigator.bluetooth - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: navigator.bluetooth must inherit property "getAvailability()" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: navigator.bluetooth must inherit property "onavailabilitychanged" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: navigator.bluetooth must inherit property "referringDevice" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: navigator.bluetooth must inherit property "getDevices()" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: navigator.bluetooth must inherit property "requestDevice(optional RequestDeviceOptions)" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: calling requestDevice(optional RequestDeviceOptions) on navigator.bluetooth with too few arguments must throw TypeError - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: navigator.bluetooth must inherit property "onadvertisementreceived" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: navigator.bluetooth must inherit property "ongattserverdisconnected" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: navigator.bluetooth must inherit property "oncharacteristicvaluechanged" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: navigator.bluetooth must inherit property "onserviceadded" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: navigator.bluetooth must inherit property "onservicechanged" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Bluetooth interface: navigator.bluetooth must inherit property "onserviceremoved" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] BluetoothPermissionResult interface: existence and properties of interface object - assert_own_property: self does not have own property "BluetoothPermissionResult" expected property "BluetoothPermissionResult" missing -[FAIL] BluetoothPermissionResult interface object length - assert_own_property: self does not have own property "BluetoothPermissionResult" expected property "BluetoothPermissionResult" missing -[FAIL] BluetoothPermissionResult interface object name - assert_own_property: self does not have own property "BluetoothPermissionResult" expected property "BluetoothPermissionResult" missing -[FAIL] BluetoothPermissionResult interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "BluetoothPermissionResult" expected property "BluetoothPermissionResult" missing -[FAIL] BluetoothPermissionResult interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "BluetoothPermissionResult" expected property "BluetoothPermissionResult" missing -[FAIL] BluetoothPermissionResult interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "BluetoothPermissionResult" expected property "BluetoothPermissionResult" missing -[FAIL] BluetoothPermissionResult interface: attribute devices - assert_own_property: self does not have own property "BluetoothPermissionResult" expected property "BluetoothPermissionResult" missing -[FAIL] ValueEvent interface: existence and properties of interface object - assert_own_property: self does not have own property "ValueEvent" expected property "ValueEvent" missing -[FAIL] ValueEvent interface object length - assert_own_property: self does not have own property "ValueEvent" expected property "ValueEvent" missing -[FAIL] ValueEvent interface object name - assert_own_property: self does not have own property "ValueEvent" expected property "ValueEvent" missing -[FAIL] ValueEvent interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "ValueEvent" expected property "ValueEvent" missing -[FAIL] ValueEvent interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "ValueEvent" expected property "ValueEvent" missing -[FAIL] ValueEvent interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "ValueEvent" expected property "ValueEvent" missing -[FAIL] ValueEvent interface: attribute value - assert_own_property: self does not have own property "ValueEvent" expected property "ValueEvent" missing -[FAIL] BluetoothDevice interface: existence and properties of interface object - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface object length - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface object name - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: attribute id - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: attribute name - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: attribute gatt - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: operation forget() - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: operation watchAdvertisements(optional WatchAdvertisementsOptions) - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: attribute watchingAdvertisements - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: attribute onadvertisementreceived - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: attribute ongattserverdisconnected - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: attribute oncharacteristicvaluechanged - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: attribute onserviceadded - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: attribute onservicechanged - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothDevice interface: attribute onserviceremoved - assert_own_property: self does not have own property "BluetoothDevice" expected property "BluetoothDevice" missing -[FAIL] BluetoothAdvertisingEvent interface object length - assert_equals: wrong value for BluetoothAdvertisingEvent.length expected 2 but got 0 -[FAIL] BluetoothAdvertisingEvent must be primary interface of event - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] Stringification of event - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] BluetoothAdvertisingEvent interface: event must inherit property "device" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] BluetoothAdvertisingEvent interface: event must inherit property "uuids" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] BluetoothAdvertisingEvent interface: event must inherit property "name" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] BluetoothAdvertisingEvent interface: event must inherit property "appearance" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] BluetoothAdvertisingEvent interface: event must inherit property "txPower" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] BluetoothAdvertisingEvent interface: event must inherit property "rssi" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] BluetoothAdvertisingEvent interface: event must inherit property "manufacturerData" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] BluetoothAdvertisingEvent interface: event must inherit property "serviceData" with the proper type - assert_equals: wrong typeof object expected "object" but got "undefined" -[FAIL] BluetoothRemoteGATTServer interface: existence and properties of interface object - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTServer interface object length - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTServer interface object name - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTServer interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTServer interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTServer interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTServer interface: attribute device - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTServer interface: attribute connected - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTServer interface: operation connect() - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTServer interface: operation disconnect() - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTServer interface: operation getPrimaryService(BluetoothServiceUUID) - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTServer interface: operation getPrimaryServices(optional BluetoothServiceUUID) - assert_own_property: self does not have own property "BluetoothRemoteGATTServer" expected property "BluetoothRemoteGATTServer" missing -[FAIL] BluetoothRemoteGATTService interface: existence and properties of interface object - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface object length - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface object name - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: attribute device - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: attribute uuid - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: attribute isPrimary - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: operation getCharacteristic(BluetoothCharacteristicUUID) - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: operation getCharacteristics(optional BluetoothCharacteristicUUID) - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: operation getIncludedService(BluetoothServiceUUID) - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: operation getIncludedServices(optional BluetoothServiceUUID) - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: attribute oncharacteristicvaluechanged - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: attribute onserviceadded - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: attribute onservicechanged - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTService interface: attribute onserviceremoved - assert_own_property: self does not have own property "BluetoothRemoteGATTService" expected property "BluetoothRemoteGATTService" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: existence and properties of interface object - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface object length - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface object name - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: attribute service - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: attribute uuid - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: attribute properties - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: attribute value - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: operation getDescriptor(BluetoothDescriptorUUID) - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: operation getDescriptors(optional BluetoothDescriptorUUID) - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: operation readValue() - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: operation writeValue(BufferSource) - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: operation writeValueWithResponse(BufferSource) - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: operation writeValueWithoutResponse(BufferSource) - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: operation startNotifications() - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: operation stopNotifications() - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothRemoteGATTCharacteristic interface: attribute oncharacteristicvaluechanged - assert_own_property: self does not have own property "BluetoothRemoteGATTCharacteristic" expected property "BluetoothRemoteGATTCharacteristic" missing -[FAIL] BluetoothCharacteristicProperties interface: existence and properties of interface object - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface object length - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface object name - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: attribute broadcast - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: attribute read - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: attribute writeWithoutResponse - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: attribute write - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: attribute notify - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: attribute indicate - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: attribute authenticatedSignedWrites - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: attribute reliableWrite - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothCharacteristicProperties interface: attribute writableAuxiliaries - assert_own_property: self does not have own property "BluetoothCharacteristicProperties" expected property "BluetoothCharacteristicProperties" missing -[FAIL] BluetoothRemoteGATTDescriptor interface: existence and properties of interface object - assert_own_property: self does not have own property "BluetoothRemoteGATTDescriptor" expected property "BluetoothRemoteGATTDescriptor" missing -[FAIL] BluetoothRemoteGATTDescriptor interface object length - assert_own_property: self does not have own property "BluetoothRemoteGATTDescriptor" expected property "BluetoothRemoteGATTDescriptor" missing -[FAIL] BluetoothRemoteGATTDescriptor interface object name - assert_own_property: self does not have own property "BluetoothRemoteGATTDescriptor" expected property "BluetoothRemoteGATTDescriptor" missing -[FAIL] BluetoothRemoteGATTDescriptor interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "BluetoothRemoteGATTDescriptor" expected property "BluetoothRemoteGATTDescriptor" missing -[FAIL] BluetoothRemoteGATTDescriptor interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "BluetoothRemoteGATTDescriptor" expected property "BluetoothRemoteGATTDescriptor" missing -[FAIL] BluetoothRemoteGATTDescriptor interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "BluetoothRemoteGATTDescriptor" expected property "BluetoothRemoteGATTDescriptor" missing -[FAIL] BluetoothRemoteGATTDescriptor interface: attribute characteristic - assert_own_property: self does not have own property "BluetoothRemoteGATTDescriptor" expected property "BluetoothRemoteGATTDescriptor" missing -[FAIL] BluetoothRemoteGATTDescriptor interface: attribute uuid - assert_own_property: self does not have own property "BluetoothRemoteGATTDescriptor" expected property "BluetoothRemoteGATTDescriptor" missing -[FAIL] BluetoothRemoteGATTDescriptor interface: attribute value - assert_own_property: self does not have own property "BluetoothRemoteGATTDescriptor" expected property "BluetoothRemoteGATTDescriptor" missing -[FAIL] BluetoothRemoteGATTDescriptor interface: operation readValue() - assert_own_property: self does not have own property "BluetoothRemoteGATTDescriptor" expected property "BluetoothRemoteGATTDescriptor" missing -[FAIL] BluetoothRemoteGATTDescriptor interface: operation writeValue(BufferSource) - assert_own_property: self does not have own property "BluetoothRemoteGATTDescriptor" expected property "BluetoothRemoteGATTDescriptor" missing -[FAIL] BluetoothUUID interface: existence and properties of interface object - assert_own_property: self does not have own property "BluetoothUUID" expected property "BluetoothUUID" missing -[FAIL] BluetoothUUID interface object length - assert_own_property: self does not have own property "BluetoothUUID" expected property "BluetoothUUID" missing -[FAIL] BluetoothUUID interface object name - assert_own_property: self does not have own property "BluetoothUUID" expected property "BluetoothUUID" missing -[FAIL] BluetoothUUID interface: existence and properties of interface prototype object - assert_own_property: self does not have own property "BluetoothUUID" expected property "BluetoothUUID" missing -[FAIL] BluetoothUUID interface: existence and properties of interface prototype object's "constructor" property - assert_own_property: self does not have own property "BluetoothUUID" expected property "BluetoothUUID" missing -[FAIL] BluetoothUUID interface: existence and properties of interface prototype object's @@unscopables property - assert_own_property: self does not have own property "BluetoothUUID" expected property "BluetoothUUID" missing -[FAIL] BluetoothUUID interface: operation getService((DOMString or unsigned long)) - assert_own_property: self does not have own property "BluetoothUUID" expected property "BluetoothUUID" missing -[FAIL] BluetoothUUID interface: operation getCharacteristic((DOMString or unsigned long)) - assert_own_property: self does not have own property "BluetoothUUID" expected property "BluetoothUUID" missing -[FAIL] BluetoothUUID interface: operation getDescriptor((DOMString or unsigned long)) - assert_own_property: self does not have own property "BluetoothUUID" expected property "BluetoothUUID" missing -[FAIL] BluetoothUUID interface: operation canonicalUUID(unsigned long) - assert_own_property: self does not have own property "BluetoothUUID" expected property "BluetoothUUID" missing -[FAIL] Navigator interface: attribute bluetooth - assert_true: The prototype object must have a property "bluetooth" expected true got false -[FAIL] Navigator interface: navigator must inherit property "bluetooth" with the proper type - assert_inherits: property "bluetooth" not found in prototype chain -Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/syntax/charset/without-inheritance-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/syntax/charset/without-inheritance-expected.png index fb04abe..9650133 100644 --- a/third_party/blink/web_tests/platform/win/external/wpt/html/syntax/charset/without-inheritance-expected.png +++ b/third_party/blink/web_tests/platform/win/external/wpt/html/syntax/charset/without-inheritance-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/html/syntax/charset/without-inheritance-expected.png b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/html/syntax/charset/without-inheritance-expected.png index fb04abe..9650133 100644 --- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/html/syntax/charset/without-inheritance-expected.png +++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/html/syntax/charset/without-inheritance-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt b/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt new file mode 100644 index 0000000..bd3d4734 --- /dev/null +++ b/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/forms/select/customizable-select/allowed-select-descendants-console-message-expected.txt
@@ -0,0 +1,64 @@ +CONSOLE MESSAGE: <script> element +CONSOLE MESSAGE: <script> element +CONSOLE MESSAGE: <script> element + +.. + +.. +.. + +.. + +.. +.. + +.. +.. + +.. +.. + +.. +.. + +.. +.. + +.. + +.. +.. +1 +2 + +.. +.. + +.. +.. + +.. +.. + +.. +.. + + + + +One + +One +Two + + +some text + +.. + +.. +.. + +.. + +
diff --git a/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt b/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt index c45eb99..f572451 100644 --- a/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt +++ b/third_party/blink/web_tests/virtual/select-parser-relaxation/fast/forms/select/customizable-select/disallowed-select-descendants-console-message-expected.txt
@@ -5,5 +5,12 @@ .. - - + +.. .. + +.. .. + + +.. .. + +.. ..
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt index 7bd5528..f58ad5e4 100644 --- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -364,7 +364,6 @@ property href property hrefTranslate property hreflang - property interestAction property interestTargetElement property name property origin @@ -395,7 +394,6 @@ property host property hostname property href - property interestAction property interestTargetElement property noHref property origin @@ -517,7 +515,6 @@ property formMethod property formNoValidate property formTarget - property interestAction property interestTargetElement property labels property name @@ -775,7 +772,6 @@ property height property incremental property indeterminate - property interestAction property interestTargetElement property labels property list @@ -1611,7 +1607,6 @@ property getCTM property getScreenCTM property href - property interestAction property interestTargetElement property nearestViewportElement property requiredExtensions
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index 97cf6af..f36ecf2b 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -3564,7 +3564,6 @@ getter href getter hrefTranslate getter hreflang - getter interestAction getter interestTargetElement getter name getter origin @@ -3595,7 +3594,6 @@ setter href setter hrefTranslate setter hreflang - setter interestAction setter interestTargetElement setter name setter password @@ -3623,7 +3621,6 @@ getter host getter hostname getter href - getter interestAction getter interestTargetElement getter noHref getter origin @@ -3649,7 +3646,6 @@ setter host setter hostname setter href - setter interestAction setter interestTargetElement setter noHref setter password @@ -3753,7 +3749,6 @@ getter formMethod getter formNoValidate getter formTarget - getter interestAction getter interestTargetElement getter labels getter name @@ -3776,7 +3771,6 @@ setter formMethod setter formNoValidate setter formTarget - setter interestAction setter interestTargetElement setter name setter popoverTargetAction @@ -4453,7 +4447,6 @@ getter height getter incremental getter indeterminate - getter interestAction getter interestTargetElement getter labels getter list @@ -4514,7 +4507,6 @@ setter height setter incremental setter indeterminate - setter interestAction setter interestTargetElement setter max setter maxLength @@ -5665,8 +5657,7 @@ method getTargetRanges interface InterestEvent : Event attribute @@toStringTag - getter action - getter invoker + getter source method constructor interface IntersectionObserver attribute @@toStringTag @@ -8175,11 +8166,9 @@ interface SVGAElement : SVGGraphicsElement attribute @@toStringTag getter href - getter interestAction getter interestTargetElement getter target method constructor - setter interestAction setter interestTargetElement interface SVGAngle attribute @@toStringTag
diff --git a/third_party/boringssl/src b/third_party/boringssl/src index bca2d72c..d4b6eb5 160000 --- a/third_party/boringssl/src +++ b/third_party/boringssl/src
@@ -1 +1 @@ -Subproject commit bca2d72c5e3174f0e1b541fb0a3d6bdf31c23825 +Subproject commit d4b6eb542d4fd109baacd550935efd00c521e674
diff --git a/third_party/chromium-variations b/third_party/chromium-variations index ecd1b2b..187d83f 160000 --- a/third_party/chromium-variations +++ b/third_party/chromium-variations
@@ -1 +1 @@ -Subproject commit ecd1b2bcb2bca351b58c2d19cf3f149c2ffea50f +Subproject commit 187d83f8ee5fbe166ce2b668b65b67fa9b940c7f
diff --git a/third_party/dawn b/third_party/dawn index 42451fa..4548f0c 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit 42451fad80b27c0fa7332b9d0566ff037d708b04 +Subproject commit 4548f0cdeb8bef00bbce127760a0cda8bdaa9fb7
diff --git a/third_party/depot_tools b/third_party/depot_tools index ea75de4c..80d1969 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit ea75de4c3baba538f4758d507dd304136cfeab52 +Subproject commit 80d1969422e75e8e9eecafa46074074b289e2568
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index d023fd4..c6bb3b2c 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit d023fd41cb61a756301922cb329b5524c7e7110d +Subproject commit c6bb3b2ce900d42eefac9c72600ea69e74d40943
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src index 3fec72b..12809bf 160000 --- a/third_party/llvm-libc/src +++ b/third_party/llvm-libc/src
@@ -1 +1 @@ -Subproject commit 3fec72bd5608491ec977142db828cc42b88f0ef3 +Subproject commit 12809bfa855813dcef51871e2ee3155e53ed35ea
diff --git a/third_party/perfetto b/third_party/perfetto index c28325f..943a0d8 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit c28325f6986bd765e5610569211234e403a47a0f +Subproject commit 943a0d89925e7f9a898c2e49c41feb9bf5dab71e
diff --git a/third_party/search_engines_data/resources b/third_party/search_engines_data/resources index 797c94d..34ba850 160000 --- a/third_party/search_engines_data/resources +++ b/third_party/search_engines_data/resources
@@ -1 +1 @@ -Subproject commit 797c94d72b29932c8095bd7885ae26b7ed267db9 +Subproject commit 34ba850d314fced586dfaaf5b099c4906ce17b2d
diff --git a/third_party/skia b/third_party/skia index c2b103c..a9e8d00 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit c2b103c89e370ea00d0cc918c92d81fa712ff058 +Subproject commit a9e8d004f0ea4088f8a333cc36e7c019542fcf7e
diff --git a/third_party/swiftshader b/third_party/swiftshader index f6ad529..64af418 160000 --- a/third_party/swiftshader +++ b/third_party/swiftshader
@@ -1 +1 @@ -Subproject commit f6ad529e86e441bad3210b0b714dca7faa99b0f8 +Subproject commit 64af4180372914d6d3f37749a5fab2bc3f43a7f9
diff --git a/third_party/webrtc b/third_party/webrtc index 88833e6..b0038dd1 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit 88833e6d22580fa7b358eb5ee551e1b4989fed71 +Subproject commit b0038dd14a1cc637ffbc48e36e55bd96452eef5d
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index b9fcb214..6458507 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -6476,17 +6476,17 @@ <int value="1027" label="ExecCommandOnInputOrTextarea"/> <int value="1028" label="V8History_ScrollRestoration_AttributeGetter"/> <int value="1029" label="V8History_ScrollRestoration_AttributeSetter"/> - <int value="1030" label="SVG1DOMFilter"/> + <int value="1030" label="ObsoleteSVG1DOMFilter"/> <int value="1031" label="OfflineAudioContextStartRendering"/> <int value="1032" label="OfflineAudioContextSuspend"/> <int value="1033" label="OfflineAudioContextResume"/> <int value="1034" label="AttrCloneNode"/> - <int value="1035" label="SVG1DOMPaintServer"/> + <int value="1035" label="ObsoleteSVG1DOMPaintServer"/> <int value="1036" label="SVGSVGElementFragmentSVGView"/> <int value="1037" label="SVGSVGElementFragmentSVGViewElement"/> <int value="1038" label="PresentationConnectionClose"/> <int value="1039" label="SVG1DOMShape"/> - <int value="1040" label="SVG1DOMText"/> + <int value="1040" label="ObsoleteSVG1DOMText"/> <int value="1041" label="RTCPeerConnectionConstructorConstraints"/> <int value="1042" label="RTCPeerConnectionConstructorCompliant"/> <int value="1043"
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml index 4cbcd102..5cc739d2 100644 --- a/tools/metrics/histograms/metadata/apps/histograms.xml +++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -2194,7 +2194,7 @@ </histogram> <histogram name="Apps.AppShimSignatureValidationResult" - enum="WebAppShimSignatureValidationResult" expires_after="2024-11-17"> + enum="WebAppShimSignatureValidationResult" expires_after="2025-07-15"> <owner>markrowe@chromium.org</owner> <owner>chrome-platform-security-core@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/cookie/histograms.xml b/tools/metrics/histograms/metadata/cookie/histograms.xml index 9e40fcf..8f2fcf3 100644 --- a/tools/metrics/histograms/metadata/cookie/histograms.xml +++ b/tools/metrics/histograms/metadata/cookie/histograms.xml
@@ -845,6 +845,8 @@ other origins. This metric is recorded once per included cookie on every read attempt. + + Subsampled to 1/1000. </summary> <token key="HostType"> <variant name="Localhost"/> @@ -875,6 +877,8 @@ domain to set the Domain attribute). This metric is recorded once per included cookie on every read attempt. + + Subsampled to 1/1000. </summary> <token key="HostType"> <variant name="DomainSet"/>
diff --git a/tools/metrics/histograms/metadata/enterprise/enums.xml b/tools/metrics/histograms/metadata/enterprise/enums.xml index 9cc3cfbc..9dbcd07 100644 --- a/tools/metrics/histograms/metadata/enterprise/enums.xml +++ b/tools/metrics/histograms/metadata/enterprise/enums.xml
@@ -2188,7 +2188,7 @@ <int value="1324" label="WebRtcIPHandlingUrl"/> <int value="1325" label="GenAIPhotoEditingSettings"/> <int value="1326" label="PartitionedBlobUrlUsage"/> - <int value="1327" label="GlicEnabled"/> + <int value="1327" label="GlicSettings"/> <int value="1328" label="DefaultControlledFrameSetting"/> <int value="1329" label="ControlledFrameAllowedForUrls"/> <int value="1330" label="ControlledFrameBlockedForUrls"/>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index 7533f44..ccac8073 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -2004,17 +2004,6 @@ </summary> </histogram> -<histogram name="Media.Controls.OverlayCastButtonIsCovered" enum="Boolean" - expires_after="2025-01-26"> - <owner>muyaoxu@google.com</owner> - <owner>openscreen-eng@google.com</owner> - <summary> - Records how often the overlay cast button is hidden because it is covered by - another html element. Emitted when the overlay cast button is tried to be - shown. - </summary> -</histogram> - <histogram name="Media.Controls.PlaybackSpeed" enum="MediaControlsPlaybackSpeed" expires_after="2023-11-12"> <owner>steimel@chromium.org</owner> @@ -5035,7 +5024,7 @@ </histogram> <histogram name="Media.Remoting.RemotePlaybackEnabledByPage" - enum="BooleanEnabled" expires_after="2025-02-01"> + enum="BooleanEnabled" expires_after="2025-08-05"> <owner>jophba@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -5046,35 +5035,35 @@ </histogram> <histogram name="Media.Remoting.SessionDuration" units="ms" - expires_after="2025-02-01"> + expires_after="2025-08-05"> <owner>jophba@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary>Measures the duration of each remoting session.</summary> </histogram> <histogram name="Media.Remoting.SessionStartFailedReason" - enum="RemotingStartFailReason" expires_after="2025-02-01"> + enum="RemotingStartFailReason" expires_after="2025-08-05"> <owner>muyaoxu@google.com</owner> <owner>openscreen-eng@google.com</owner> <summary>Tracks the reason that a session failed to start.</summary> </histogram> <histogram name="Media.Remoting.SessionStartTrigger" - enum="RemotingStartTrigger" expires_after="2025-02-01"> + enum="RemotingStartTrigger" expires_after="2025-08-05"> <owner>jophba@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary>Tracks the trigger for starting a remoting session.</summary> </histogram> <histogram name="Media.Remoting.SessionStopTrigger" enum="RemotingStopTrigger" - expires_after="2025-02-01"> + expires_after="2025-08-05"> <owner>jophba@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary>Tracks the trigger for stopping a remoting session.</summary> </histogram> <histogram name="Media.Remoting.ShortSessionDuration" units="ms" - expires_after="2025-02-01"> + expires_after="2025-08-05"> <owner>jophba@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -7310,17 +7299,6 @@ </summary> </histogram> -<histogram name="MediaRouter.CastStreaming.Audio.PlaybackOnReceiver" - enum="Boolean" expires_after="2024-08-04"> - <owner>muyaoxu@google.com</owner> - <owner>openscreen-eng@google.com</owner> - <summary> - Records whether audio is played on the receiver device. If not, then on the - sender side. Recorded when a new site-initiated mirroring session is - started. - </summary> -</histogram> - <histogram name="MediaRouter.CastStreaming.Session.Launch" units="ms" expires_after="2025-06-08"> <owner>muyaoxu@google.com</owner> @@ -7349,7 +7327,7 @@ </histogram> <histogram name="MediaRouter.CastStreaming.Session.Length.OffscreenTab" - units="ms" expires_after="2025-02-05"> + units="ms" expires_after="2025-08-05"> <owner>muyaoxu@google.com</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -7358,14 +7336,14 @@ </histogram> <histogram name="MediaRouter.CastStreaming.Session.Length.Screen" units="ms" - expires_after="2025-06-08"> + expires_after="2025-08-05"> <owner>muyaoxu@google.com</owner> <owner>openscreen-eng@google.com</owner> <summary>Total length of a Cast Streaming Screen mirror session.</summary> </histogram> <histogram name="MediaRouter.CastStreaming.Session.Length.Tab" units="ms" - expires_after="2025-06-08"> + expires_after="2025-08-05"> <owner>muyaoxu@google.com</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -7441,7 +7419,7 @@ </histogram> <histogram name="MediaRouter.Dial.CreateRoute" - enum="MediaRouterDialCreateRouteResult" expires_after="2025-02-05"> + enum="MediaRouterDialCreateRouteResult" expires_after="2025-08-05"> <owner>muyaoxu@google.com</owner> <owner>mfoltz@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -7452,7 +7430,7 @@ </histogram> <histogram name="MediaRouter.Dial.DeviceDescriptionParsingResult" - enum="MediaRouterDeviceDescriptionParsingResult" expires_after="2025-02-10"> + enum="MediaRouterDeviceDescriptionParsingResult" expires_after="2025-08-05"> <owner>muyaoxu@google.com</owner> <owner>mfoltz@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -7475,7 +7453,7 @@ </histogram> <histogram name="MediaRouter.Dial.KnownDevicesCount" units="devices" - expires_after="2025-02-01"> + expires_after="2025-08-05"> <owner>muyaoxu@google.com</owner> <owner>mfoltz@chromium.org</owner> <owner>openscreen-eng@google.com</owner> @@ -7625,7 +7603,7 @@ </histogram> <histogram name="MediaRouter.Source.CastingSource" - enum="MediaRouterSourceTypes" expires_after="2025-02-10"> + enum="MediaRouterSourceTypes" expires_after="2025-08-05"> <owner>muyaoxu@google.com</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -7635,7 +7613,7 @@ </histogram> <histogram name="MediaRouter.Ui.Android.DialogAction" - enum="MediaRouterAndroidDialogAction" expires_after="2025-02-05"> + enum="MediaRouterAndroidDialogAction" expires_after="2025-08-05"> <owner>muyaoxu@google.com</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -7647,7 +7625,7 @@ </histogram> <histogram name="MediaRouter.Ui.Android.DialogType" - enum="MediaRouterAndroidDialogType" expires_after="2025-02-05"> + enum="MediaRouterAndroidDialogType" expires_after="2025-08-05"> <owner>muyaoxu@google.com</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -7671,7 +7649,7 @@ <histogram name="MediaRouter.Ui.Dialog.ActivationLocationAndCastMode" enum="MediaRouterDialogActivationLocationAndCastMode" - expires_after="2025-02-05"> + expires_after="2025-08-05"> <owner>muyaoxu@google.com</owner> <owner>openscreen-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/mobile/histograms.xml b/tools/metrics/histograms/metadata/mobile/histograms.xml index aff5631f..c32511f 100644 --- a/tools/metrics/histograms/metadata/mobile/histograms.xml +++ b/tools/metrics/histograms/metadata/mobile/histograms.xml
@@ -325,7 +325,7 @@ </histogram> <histogram name="Mobile.Messages.Banner.OnScreenTime" units="ms" - expires_after="2025-02-26"> + expires_after="2026-02-26"> <owner>thegreenfrog@chromium.org</owner> <owner>bling-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml index 55846d3..5e8e9c5e6 100644 --- a/tools/metrics/histograms/metadata/network/histograms.xml +++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -167,6 +167,15 @@ </histogram> <histogram name="Network.Ash.Cellular.Apn.CreateCustomApn.Result" + enum="BooleanSuccess" expires_after="2026-01-14"> + <owner>nikhilcn@google.com</owner> + <owner>cros-device-enablement@google.com</owner> + <summary> + Deprecated. Records the result of an attempt to create a custom APN. + </summary> +</histogram> + +<histogram name="Network.Ash.Cellular.Apn.CreateCustomApn.Result2" enum="CreateCustomApnResult" expires_after="2026-01-14"> <owner>nikhilcn@google.com</owner> <owner>cros-device-enablement@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index 29d0e00..d43f3a1 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -7713,6 +7713,28 @@ </summary> </histogram> +<histogram name="Process.Sandbox.IPC.ThreadCreateRemoteThreadErrorCode" + enum="WinGetLastError" expires_after="2025-06-01"> + <owner>ajgo@chromium.org</owner> + <owner>wfh@chromium.org</owner> + <summary> + Error returned when CreateThreadAction fails to CreateRemoteThread(). Not + logged on success. For decoding error code please refer to + http://goo.gl/fJJiAv. + </summary> +</histogram> + +<histogram name="Process.Sandbox.IPC.ThreadDuplicateHandleErrorCode" + enum="WinGetLastError" expires_after="2025-06-01"> + <owner>ajgo@chromium.org</owner> + <owner>wfh@chromium.org</owner> + <summary> + Error returned when CreateThreadAction fails to DuplicateHandle(). Not + logged on success. For decoding error code please refer to + http://goo.gl/fJJiAv. + </summary> +</histogram> + <histogram name="Process.Sandbox.Launch.Error" enum="WinGetLastError" expires_after="never"> <!-- expires-never: metric needed for diagnosing sandbox issues. -->
diff --git a/tools/metrics/histograms/metadata/stability/histograms.xml b/tools/metrics/histograms/metadata/stability/histograms.xml index 3b58bb8c..0b7e332 100644 --- a/tools/metrics/histograms/metadata/stability/histograms.xml +++ b/tools/metrics/histograms/metadata/stability/histograms.xml
@@ -312,7 +312,7 @@ </histogram> <histogram name="Stability.ChildFrameCrash.TabMarkedForReload" - enum="BooleanMarkedForReload" expires_after="2025-02-16"> + enum="BooleanMarkedForReload" expires_after="2026-02-16"> <owner>alexmos@chromium.org</owner> <owner>boliu@chromium.org</owner> <summary> @@ -322,7 +322,7 @@ </histogram> <histogram name="Stability.ChildFrameCrash.TabMarkedForReload.Visibility" - enum="FrameVisibility" expires_after="2025-02-16"> + enum="FrameVisibility" expires_after="2026-02-16"> <owner>alexmos@chromium.org</owner> <owner>boliu@chromium.org</owner> <summary>
diff --git a/tools/perf/core/perf_benchmark_unittest.py b/tools/perf/core/perf_benchmark_unittest.py index eaa9476..3a399a0 100644 --- a/tools/perf/core/perf_benchmark_unittest.py +++ b/tools/perf/core/perf_benchmark_unittest.py
@@ -60,7 +60,7 @@ self.assertEqual(num_expected_matches, len(ruleset_data_to_copy)) # Flaky: https://crbug.com/1342706 - @decorators.Disabled('android-nougat', 'android-oreo', 'android-pie') + @decorators.Disabled('android') def testVariationArgs(self): benchmark = perf_benchmark.PerfBenchmark() options = options_for_unittests.GetCopy()
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index b770a90..6724392 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@ "full_remote_path": "perfetto-luci-artifacts/v49.0/linux-arm64/trace_processor_shell" }, "win": { - "hash": "dd2db82e436b522f699a72ce3ecfeca786345eee", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/5cac0a369729cd1e8aa92a9ca4cbeee7cbec8ad2/trace_processor_shell.exe" + "hash": "1c92a6e5ce76875a764aafc645124b645187cfd3", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/943a0d89925e7f9a898c2e49c41feb9bf5dab71e/trace_processor_shell.exe" }, "linux_arm": { "hash": "a15d8362d80cfd7cd8d785cf6afc22586de688cd", @@ -21,8 +21,8 @@ "full_remote_path": "perfetto-luci-artifacts/v49.0/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "293465353d9208742e4d269cf28c64bf16c283ed", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/5cac0a369729cd1e8aa92a9ca4cbeee7cbec8ad2/trace_processor_shell" + "hash": "c993ea68c410707bc9f008686392a2c995791669", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/943a0d89925e7f9a898c2e49c41feb9bf5dab71e/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/whats_new/whats_new_util.py b/tools/whats_new/whats_new_util.py index 81399d3..81a2058 100644 --- a/tools/whats_new/whats_new_util.py +++ b/tools/whats_new/whats_new_util.py
@@ -159,7 +159,8 @@ feature_dict: Data for the new What's New feature. """ feature_name = feature_dict['Feature name'] - whats_new_util_file = os.path.join(BASE_DIR, '..', CHROME_ICON_FILENAME) + whats_new_util_file = os.path.join( + BASE_DIR, '..', 'ios/chrome/browser/ui/whats_new/whats_new_util.mm') with open(whats_new_util_file, 'r+', encoding='utf-8', newline='') as file: read_data = file.read() whats_new_type_error_regex = r'case WhatsNewType::kError:' @@ -446,8 +447,7 @@ icon_name_regex = re.compile(r"@\"(.*)\";") - valid_icons_file = os.path.join( - BASE_DIR, '../ios/chrome/browser/shared/ui/symbols/symbol_names.mm') + valid_icons_file = os.path.join(BASE_DIR, '..', CHROME_ICON_FILENAME) found_default_icons = False with open(valid_icons_file, 'r', encoding='utf-8', newline='') as file: # The icons file starts with custom icons until reaching the comment
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn index d7e6690..f30df0d 100644 --- a/ui/android/BUILD.gn +++ b/ui/android/BUILD.gn
@@ -780,6 +780,7 @@ sources = [ "java/src/org/chromium/ui/listmenu/ListMenuButtonTest.java", "java/src/org/chromium/ui/widget/TextViewWithTightWrapTest.java", + "javatests/src/org/chromium/ui/animation/RenderTestAnimationUtils.java", "javatests/src/org/chromium/ui/base/ClipboardAndroidTest.java", "javatests/src/org/chromium/ui/util/WindowInsetsUtilsJavaUnitTest.java", "junit/src/org/chromium/ui/widget/TextViewWithLeadingTest.java",
diff --git a/ui/android/javatests/src/org/chromium/ui/animation/RenderTestAnimationUtils.java b/ui/android/javatests/src/org/chromium/ui/animation/RenderTestAnimationUtils.java new file mode 100644 index 0000000..6051f49 --- /dev/null +++ b/ui/android/javatests/src/org/chromium/ui/animation/RenderTestAnimationUtils.java
@@ -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. + +package org.chromium.ui.animation; + +import android.animation.ValueAnimator; +import android.view.View; + +import org.chromium.base.ThreadUtils; +import org.chromium.ui.test.util.RenderTestRule; + +import java.io.IOException; +import java.util.Locale; + +/** Utilities related to render testing for animations. */ +public class RenderTestAnimationUtils { + /** + * Steps through an animation and generates rendered images for each step. + * + * @param testcaseName The base name for the render test results. + * @param renderTestRule The {@link RenderTestRule} for the render test. + * @param rootView The root {@link View} where the render test takes place. + * @param animator The {@link ValueAnimator} for the render test. + * @param steps The number of steps the animation should take (2 or more). + * @throws IOException if the rendered image cannot be saved to the device. + */ + public static void stepThroughAnimation( + String testcaseName, + RenderTestRule renderTestRule, + View rootView, + ValueAnimator animator, + int steps) + throws IOException { + assert steps >= 2; + float fractionPerStep = 1.0f / (steps - 1); + + // Manually drive the animation instead of using a ValueAnimator for exact control over + // step size and timing. + for (int step = 0; step < steps; step++) { + final float animationFraction = fractionPerStep * step; + ThreadUtils.runOnUiThreadBlocking(() -> animator.setCurrentFraction(animationFraction)); + + renderTestRule.render( + rootView, + testcaseName + + String.format(Locale.ENGLISH, "_step_%d_of_%d", step + 1, steps)); + } + } +}
diff --git a/ui/aura/demo/demo_main.cc b/ui/aura/demo/demo_main.cc index 60467f6..8f29297 100644 --- a/ui/aura/demo/demo_main.cc +++ b/ui/aura/demo/demo_main.cc
@@ -18,7 +18,6 @@ #include "base/task/thread_pool/thread_pool_instance.h" #include "build/build_config.h" #include "components/viz/host/host_frame_sink_manager.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "mojo/core/embedder/embedder.h" #include "third_party/skia/include/core/SkBlendMode.h" @@ -185,9 +184,8 @@ // The ContextFactory must exist before any Compositors are created. viz::HostFrameSinkManager host_frame_sink_manager; - viz::ServerSharedBitmapManager server_shared_bitmap_manager; viz::FrameSinkManagerImpl frame_sink_manager{ - viz::FrameSinkManagerImpl::InitParams(&server_shared_bitmap_manager)}; + viz::FrameSinkManagerImpl::InitParams()}; host_frame_sink_manager.SetLocalManager(&frame_sink_manager); frame_sink_manager.SetLocalClient(&host_frame_sink_manager); auto context_factory = std::make_unique<ui::InProcessContextFactory>(
diff --git a/ui/aura/window.cc b/ui/aura/window.cc index 10d798d..09f237bc 100644 --- a/ui/aura/window.cc +++ b/ui/aura/window.cc
@@ -62,6 +62,7 @@ #include "ui/compositor/compositor.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_animator.h" +#include "ui/compositor/layer_type.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/events/event_target_iterator.h" @@ -333,7 +334,9 @@ return; transparent_ = transparent; - layer()->SetFillsBoundsOpaquely(!transparent_); + if (layer()->type() != ui::LAYER_SOLID_COLOR) { + layer()->SetFillsBoundsOpaquely(!transparent_); + } TriggerChangedCallback(&transparent_); }
diff --git a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc index 09e9ba0..f413108 100644 --- a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc +++ b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc
@@ -35,10 +35,7 @@ scoped_refptr<dbus::Bus> bus) : bus_(std::move(bus)) { if (!bus_) { - dbus::Bus::Options options; - options.bus_type = dbus::Bus::SESSION; - options.dbus_task_runner = dbus_thread_linux::GetTaskRunner(); - bus_ = base::MakeRefCounted<dbus::Bus>(options); + bus_ = dbus_thread_linux::GetSharedSessionBus(); } global_shortcuts_proxy_ = bus_->GetObjectProxy( @@ -69,9 +66,6 @@ base::DoNothing()); } session_map_.clear(); - - dbus_thread_linux::GetTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&dbus::Bus::ShutdownAndBlock, bus_)); } void GlobalAcceleratorListenerLinux::OnSystemdUnitStarted(
diff --git a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux_unittest.cc b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux_unittest.cc index 1907d808..9826e6af 100644 --- a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux_unittest.cc +++ b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux_unittest.cc
@@ -369,7 +369,6 @@ MatchMethod(GlobalAcceleratorListenerLinux::kSessionInterface, GlobalAcceleratorListenerLinux::kMethodCloseSession), _, _)); - EXPECT_CALL(*mock_bus, ShutdownAndBlock()); global_shortcut_listener.reset(); }
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc index 9f8aab7..c2edc927 100644 --- a/ui/base/ui_base_features.cc +++ b/ui/base/ui_base_features.cc
@@ -205,6 +205,12 @@ #endif ); +// TODO(crbug.com/389771428): Switch the ui::Compositor to use +// cc::PropertyTrees and layer lists rather than layer trees. +BASE_FEATURE(kUiCompositorUsesLayerLists, + "UiCompositorUsesLayerLists", + base::FEATURE_DISABLED_BY_DEFAULT); + // Enables the use of a touch fling curve that is based on the behavior of // native apps on Windows. BASE_FEATURE(kExperimentalFlingAnimation,
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h index 27162c4..a66151f1 100644 --- a/ui/base/ui_base_features.h +++ b/ui/base/ui_base_features.h
@@ -25,6 +25,8 @@ COMPONENT_EXPORT(UI_BASE_FEATURES) BASE_DECLARE_FEATURE(kSystemKeyboardLock); COMPONENT_EXPORT(UI_BASE_FEATURES) BASE_DECLARE_FEATURE(kUiCompositorScrollWithLayers); +COMPONENT_EXPORT(UI_BASE_FEATURES) +BASE_DECLARE_FEATURE(kUiCompositorUsesLayerLists); COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsUiGpuRasterizationEnabled();
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc index 75ffc37..4cc0de6 100644 --- a/ui/compositor/layer.cc +++ b/ui/compositor/layer.cc
@@ -307,12 +307,14 @@ clone->SetVisible(GetTargetVisibility()); clone->SetClipRect(GetTargetClipRect()); clone->SetAcceptEvents(accept_events()); - clone->SetFillsBoundsOpaquely(fills_bounds_opaquely_); clone->SetFillsBoundsCompletely(fills_bounds_completely_); clone->SetRoundedCornerRadius(GetTargetRoundedCornerRadius()); clone->SetGradientMask(gradient_mask()); clone->SetIsFastRoundedCorner(is_fast_rounded_corner()); clone->SetName(name_); + if (type() != LAYER_SOLID_COLOR) { + clone->SetFillsBoundsOpaquely(fills_bounds_opaquely_); + } // the |damaged_region_| will be sent to cc later in SendDamagedRects(). clone->damaged_region_ = damaged_region_; @@ -896,6 +898,7 @@ } void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { + CHECK_NE(type_, LayerType::LAYER_SOLID_COLOR); SetFillsBoundsOpaquelyWithReason(fills_bounds_opaquely, PropertyChangeReason::NOT_FROM_ANIMATION); }
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h index 729a8f2..b0d78219 100644 --- a/ui/compositor/layer.h +++ b/ui/compositor/layer.h
@@ -414,6 +414,8 @@ // Note: Setting a layer non-opaque has significant performance impact, // especially on low-end Chrome OS devices. Please ensure you are not // adding unnecessary overdraw. When in doubt, talk to the graphics team. + // NOTE: Opacity of SOLID_COLOR layer is determined by the color's alpha + // channel. Calling this on SOLID_COLOR results in check failure. void SetFillsBoundsOpaquely(bool fills_bounds_opaquely); bool fills_bounds_opaquely() const { return fills_bounds_opaquely_; }
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc index 6bf2754..ecc6b84 100644 --- a/ui/compositor/layer_unittest.cc +++ b/ui/compositor/layer_unittest.cc
@@ -865,7 +865,7 @@ constexpr SkColor kTransparent = SK_ColorTRANSPARENT; layer->SetColor(kTransparent); - layer->SetFillsBoundsOpaquely(false); + // Color and opaqueness targets should be preserved during cloning, even after // switching away from solid color content. ASSERT_TRUE(layer->SwitchCCLayerForTest()); @@ -882,23 +882,6 @@ EXPECT_FALSE(clone->LayerHasCustomColorMatrix()); EXPECT_FALSE(clone->fills_bounds_opaquely()); - // A solid color layer with transparent color can be marked as opaque. The - // clone should retain this state. - layer = CreateLayer(LAYER_SOLID_COLOR); - layer->SetColor(kTransparent); - layer->SetFillsBoundsOpaquely(true); - - clone = layer->Clone(); - EXPECT_TRUE(clone->GetTargetTransform().IsIdentity()); - EXPECT_EQ(kTransparent, clone->background_color()); - EXPECT_EQ(kTransparent, clone->GetTargetColor()); - EXPECT_FALSE(clone->layer_inverted()); - // Sepia and hue rotation should be off by default. - EXPECT_FLOAT_EQ(0, layer->layer_sepia()); - EXPECT_FLOAT_EQ(0, clone->layer_hue_rotation()); - EXPECT_FALSE(clone->LayerHasCustomColorMatrix()); - EXPECT_TRUE(clone->fills_bounds_opaquely()); - layer = CreateLayer(LAYER_SOLID_COLOR); layer->SetVisible(true); layer->SetOpacity(1.0f); @@ -1143,7 +1126,6 @@ TEST_F(LayerWithNullDelegateTest, SwitchLayerPreservesCCLayerState) { std::unique_ptr<Layer> l1 = CreateLayer(LAYER_SOLID_COLOR); - l1->SetFillsBoundsOpaquely(true); l1->SetVisible(false); l1->SetBounds(gfx::Rect(4, 5)); @@ -2690,7 +2672,6 @@ SkColor transparent = SK_ColorTRANSPARENT; std::unique_ptr<Layer> root = CreateLayer(LAYER_SOLID_COLOR); GetCompositor()->SetRootLayer(root.get()); - root->SetFillsBoundsOpaquely(false); root->SetColor(transparent); EXPECT_FALSE(root->fills_bounds_opaquely()); @@ -2727,7 +2708,6 @@ { ui::ScopedLayerAnimationSettings animation(root->GetAnimator()); animation.SetTransitionDuration(base::Milliseconds(1000)); - root->SetFillsBoundsOpaquely(false); root->SetColor(transparent); }
diff --git a/ui/compositor/test/test_context_factories.cc b/ui/compositor/test/test_context_factories.cc index 030afd4..1729d20d 100644 --- a/ui/compositor/test/test_context_factories.cc +++ b/ui/compositor/test/test_context_factories.cc
@@ -7,7 +7,6 @@ #include "base/command_line.h" #include "components/viz/common/features.h" #include "components/viz/host/host_frame_sink_manager.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "ui/compositor/compositor_switches.h" #include "ui/gl/gl_implementation.h" @@ -21,9 +20,8 @@ enable_pixel_output = true; if (enable_pixel_output) disable_null_draw_ = std::make_unique<gl::DisableNullDrawGLBindings>(); - shared_bitmap_manager_ = std::make_unique<viz::ServerSharedBitmapManager>(); frame_sink_manager_ = std::make_unique<viz::FrameSinkManagerImpl>( - viz::FrameSinkManagerImpl::InitParams(shared_bitmap_manager_.get())); + viz::FrameSinkManagerImpl::InitParams()); host_frame_sink_manager_ = std::make_unique<viz::HostFrameSinkManager>(); implicit_factory_ = std::make_unique<InProcessContextFactory>( host_frame_sink_manager_.get(), frame_sink_manager_.get(),
diff --git a/ui/compositor/test/test_context_factories.h b/ui/compositor/test/test_context_factories.h index bccb8fc..299532b 100644 --- a/ui/compositor/test/test_context_factories.h +++ b/ui/compositor/test/test_context_factories.h
@@ -15,7 +15,6 @@ namespace viz { class HostFrameSinkManager; -class ServerSharedBitmapManager; class FrameSinkManagerImpl; } // namespace viz @@ -40,7 +39,6 @@ private: std::unique_ptr<gl::DisableNullDrawGLBindings> disable_null_draw_; - std::unique_ptr<viz::ServerSharedBitmapManager> shared_bitmap_manager_; std::unique_ptr<viz::FrameSinkManagerImpl> frame_sink_manager_; std::unique_ptr<viz::HostFrameSinkManager> host_frame_sink_manager_; std::unique_ptr<ui::InProcessContextFactory> implicit_factory_;
diff --git a/ui/gfx/frame_data.h b/ui/gfx/frame_data.h index cc1a291..38d90bc 100644 --- a/ui/gfx/frame_data.h +++ b/ui/gfx/frame_data.h
@@ -38,6 +38,10 @@ // fall out of delegated mode. gfx::CALayerResult ca_layer_error_code = gfx::kCALayerSuccess; #endif + +#if BUILDFLAG(IS_MAC) + bool is_handling_interaction_or_animation = false; +#endif }; } // namespace gfx
diff --git a/ui/shell_dialogs/shell_dialog_linux.cc b/ui/shell_dialogs/shell_dialog_linux.cc index 2276160..21ce7fae 100644 --- a/ui/shell_dialogs/shell_dialog_linux.cc +++ b/ui/shell_dialogs/shell_dialog_linux.cc
@@ -25,12 +25,6 @@ #endif } -void Finalize() { -#if BUILDFLAG(USE_DBUS) - ui::SelectFileDialogLinuxPortal::DestroyPortalConnection(); -#endif -} - } // namespace shell_dialog_linux namespace ui { @@ -58,8 +52,6 @@ // Check to see if the portal is available. if (SelectFileDialogLinuxPortal::IsPortalAvailable()) return kPortal; - // Make sure to kill the portal connection. - SelectFileDialogLinuxPortal::DestroyPortalConnection(); #endif // Check to see if KDE is the desktop environment.
diff --git a/ui/shell_dialogs/shell_dialog_linux.h b/ui/shell_dialogs/shell_dialog_linux.h index 9e27f2f..2888ae3 100644 --- a/ui/shell_dialogs/shell_dialog_linux.h +++ b/ui/shell_dialogs/shell_dialog_linux.h
@@ -9,13 +9,11 @@ namespace shell_dialog_linux { -// TODO(thomasanderson): Remove Initialize() and Finalize(). +// TODO(thomasanderson): Remove Initialize(). // Should be called before the first call to CreateSelectFileDialog. SHELL_DIALOGS_EXPORT void Initialize(); -SHELL_DIALOGS_EXPORT void Finalize(); - } // namespace shell_dialog_linux #endif // UI_SHELL_DIALOGS_SHELL_DIALOG_LINUX_H_
diff --git a/ui/touch_selection/touch_selection_magnifier_aura.cc b/ui/touch_selection/touch_selection_magnifier_aura.cc index ff95688..dba189ca 100644 --- a/ui/touch_selection/touch_selection_magnifier_aura.cc +++ b/ui/touch_selection/touch_selection_magnifier_aura.cc
@@ -300,7 +300,6 @@ // Create the zoom layer, which will show the zoomed contents. zoom_layer_ = std::make_unique<Layer>(LAYER_SOLID_COLOR); zoom_layer_->SetBackgroundZoom(kMagnifierScale, 0); - zoom_layer_->SetFillsBoundsOpaquely(false); // BackdropFilterBounds applies after the backdrop filter (the zoom effect) // but before anything else, meaning its clipping effect is transformed by // the layer_offset() filter operation. SetRoundedCornerRadius() applies too
diff --git a/ui/views/examples/examples_main_proc.cc b/ui/views/examples/examples_main_proc.cc index c3858f9..48fdc364 100644 --- a/ui/views/examples/examples_main_proc.cc +++ b/ui/views/examples/examples_main_proc.cc
@@ -26,7 +26,6 @@ #include "base/test/test_timeouts.h" #include "build/build_config.h" #include "components/viz/host/host_frame_sink_manager.h" -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "mojo/core/embedder/embedder.h" #include "ui/accessibility/platform/ax_platform_for_test.h"
diff --git a/ui/views/view.cc b/ui/views/view.cc index 4c3aabce..7ca7279 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -61,6 +61,7 @@ #include "ui/compositor/clip_recorder.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer.h" +#include "ui/compositor/layer_type.h" #include "ui/compositor/paint_context.h" #include "ui/compositor/paint_recorder.h" #include "ui/compositor/transform_recorder.h" @@ -2561,7 +2562,9 @@ CreateOrDestroyLayer(); - layer()->SetFillsBoundsOpaquely(false); + if (layer()->type() != ui::LAYER_SOLID_COLOR) { + layer()->SetFillsBoundsOpaquely(false); + } } void View::SetLayerParent(ui::Layer* parent_layer) {
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm index 242a2c8..89247a9e 100644 --- a/ui/views/widget/native_widget_mac.mm +++ b/ui/views/widget/native_widget_mac.mm
@@ -62,8 +62,12 @@ // If the Widget is modal, it will be displayed as a sheet. This works best if // it has NSWindowStyleMaskTitled. For example, with // NSWindowStyleMaskBorderless, the parent window still accepts input. + // A sheet will not have a titlebar despite being NSWindowStyleMaskTitled. // NSWindowStyleMaskFullSizeContentView ensures that calculating the modal's // content rect doesn't account for a nonexistent title bar. + // TODO(crbug.com/390441085): a window-modal should always have a parent. + // Otherwise, it will not be displayed as a sheet. Then it will show a native + // titlebar, which will cover the content. if (params.delegate && params.delegate->GetModalType() == ui::mojom::ModalType::kWindow) { return NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView;
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc index de21236..7d1c482 100644 --- a/ui/views/window/dialog_delegate.cc +++ b/ui/views/window/dialog_delegate.cc
@@ -105,8 +105,7 @@ // static bool DialogDelegate::CanSupportCustomFrame(gfx::NativeView parent) { -#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && \ - BUILDFLAG(ENABLE_DESKTOP_AURA) +#if BUILDFLAG(IS_LINUX) && BUILDFLAG(ENABLE_DESKTOP_AURA) // The new style doesn't support unparented dialogs on Linux desktop. return parent != nullptr; #else
diff --git a/ui/webui/resources/cr_components/commerce/product_specifications_browser_proxy.ts b/ui/webui/resources/cr_components/commerce/product_specifications_browser_proxy.ts index c6eebd7d..8edfbbc 100644 --- a/ui/webui/resources/cr_components/commerce/product_specifications_browser_proxy.ts +++ b/ui/webui/resources/cr_components/commerce/product_specifications_browser_proxy.ts
@@ -6,13 +6,15 @@ import type {Url} from '//resources/mojo/url/mojom/url.mojom-webui.js'; import {PageCallbackRouter, ProductSpecificationsHandlerFactory, ProductSpecificationsHandlerRemote} from './product_specifications.mojom-webui.js'; -import type {DisclosureVersion} from './product_specifications.mojom-webui.ts'; +import type {DisclosureVersion, ShowSetDisposition} from './product_specifications.mojom-webui.ts'; let instance: ProductSpecificationsBrowserProxy|null = null; export interface ProductSpecificationsBrowserProxy { getCallbackRouter(): PageCallbackRouter; showProductSpecificationsSetForUuid(uuid: Uuid, inNewTab: boolean): void; + showProductSpecificationsSetsForUuids( + uuids: Uuid[], disposition: ShowSetDisposition): void; showComparePage(inNewTab: boolean): void; setAcceptedDisclosureVersion(version: DisclosureVersion): void; maybeShowDisclosure(urls: Url[], name: string, setId: string): @@ -51,6 +53,11 @@ this.handler.showProductSpecificationsSetForUuid(uuid, inNewTab); } + showProductSpecificationsSetsForUuids( + uuids: Uuid[], disposition: ShowSetDisposition): void { + this.handler.showProductSpecificationsSetsForUuids(uuids, disposition); + } + showComparePage(inNewTab: boolean) { this.handler.showComparePage(inNewTab); }
diff --git a/url/scheme_host_port.cc b/url/scheme_host_port.cc index d66fdb10..fa0c15b4 100644 --- a/url/scheme_host_port.cc +++ b/url/scheme_host_port.cc
@@ -269,15 +269,10 @@ base::trace_event::EstimateMemoryUsage(host_); } -bool SchemeHostPort::operator==(const SchemeHostPort& other) const { - return (*this <=> other) == 0; -} +bool SchemeHostPort::operator==(const SchemeHostPort& other) const = default; std::strong_ordering SchemeHostPort::operator<=>( - const SchemeHostPort& other) const { - return std::tie(port_, scheme_, host_) <=> - std::tie(other.port_, other.scheme_, other.host_); -} + const SchemeHostPort& other) const = default; std::string SchemeHostPort::SerializeInternal(url::Parsed* parsed) const { std::string result;
diff --git a/url/scheme_host_port.h b/url/scheme_host_port.h index ae8385a..6b02f58b 100644 --- a/url/scheme_host_port.h +++ b/url/scheme_host_port.h
@@ -161,9 +161,10 @@ std::string SerializeInternal(url::Parsed* parsed) const; private: + // Note: `port_` is declared first to control the sort order. + uint16_t port_ = 0; std::string scheme_; std::string host_; - uint16_t port_ = 0; }; COMPONENT_EXPORT(URL)
diff --git a/v8 b/v8 index 15c092a..4bd0d47 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 15c092afb8cad2be5d5a62d970ee38b16a14645b +Subproject commit 4bd0d4731ea90ff9460eeb6d5cfc6cc1127363d3