diff --git a/DEPS b/DEPS index d5c8c1a..8bc91337 100644 --- a/DEPS +++ b/DEPS
@@ -304,15 +304,15 @@ # 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': '284bc9fe6264205e4b08170f549ce8e1d32e3caf', + 'src_internal_revision': '88e16d7638ad0e2c73a70bbd704a06bacd4224ae', # 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': '0bbcd8152d32b349e5eee99b29bccc5fcd58ce9b', + 'skia_revision': '530fa373b797bf1ade172ef591134ea6cc401271', # 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': 'f0366cb2215c9ee342a870b52db0769aad7b20d4', + 'v8_revision': '06b1e2c29489af4922ca60a44347ce0ef7c36ebb', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. @@ -324,7 +324,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '547d96118caf46c07b3e520a971992b6909696bd', + 'pdfium_revision': 'f98c54df162cd2a9324dad9e5b9453425311527d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -383,7 +383,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': '83915e39be4ead9df32167feafc7c2639d603d5a', + 'chromium_variations_revision': 'c90f785907da5911ca61f1116990ad6a7fdb6f67', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. @@ -423,7 +423,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': 'd4d6d18aec677d0e43edac057c0595ed3973f4b7', + 'dawn_revision': '724dd7855543eb1d4c75c517de7b576b092bfd7f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -447,7 +447,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling crabbyavif # and whatever else without interference from each other. - 'crabbyavif_revision': 'ef17807890f60bee1398a752d53204c369076aca', + 'crabbyavif_revision': '2a37e62739815ac00d1195e88135e8b1e5f38c87', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libavifinfo # and whatever else without interference from each other. @@ -1004,7 +1004,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - 'fc1c0897381a14bedb2015ed8d4e0551d2f72088', + '96dc252dcd4740e9bbe8822a8357c5b678cddf01', 'condition': 'checkout_android and checkout_src_internal', }, @@ -1425,7 +1425,7 @@ # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '5ff757e963883d28db6d5b9856e5c7fcc63cdcb0', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8d0f67b603baecf2da3e1ad830062e356430f5ab', 'condition': 'checkout_chromeos', }, @@ -1460,7 +1460,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '274689c4a55104b92bf66248d03249ce0175aa02', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'e0038c0721935fc3d8119e02c19553f2fee8f8fd', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1930,7 +1930,7 @@ Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '09a4f3ec842a8932341b195c5b01e141c8a16eb7', 'src/third_party/openscreen/src': - Var('chromium_git') + '/openscreen' + '@' + '6a097c705fc4bb3d79bcb4a45f71b7a198ba40f8', + Var('chromium_git') + '/openscreen' + '@' + 'a74a035f778762b1c31ae1e9393eefdbf07be714', 'src/third_party/openxr/src': { 'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '95fe35ffb383710a6e0567e958ead9a3b66e930c', @@ -1956,7 +1956,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '3f851caa743d632b338f79ee30e9ae2929eed22d', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'e03af0caee1bf0b7ece55e42e607d738f65f9c7b', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '8ef97ff3b7332e38e61b347a2fbed425a4617151', @@ -2173,7 +2173,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '789c2834ebb5eb936190128379ae15ac70541b12', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'b25c747d5d318827869fe8304bd975285b33bf57', + Var('webrtc_git') + '/src.git' + '@' + '21922847462881016e05b008ffbf7d25c602074b', # 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. @@ -2296,7 +2296,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'LahA7KBiariHlcVMa5sbbjbhVExazWGFemCM8WZzAlEC', + 'version': 'IrldqhI9fm0-uieXg7Zh2UJPJEIVkJsDlmbDOgDIibIC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -2307,7 +2307,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': '0PJ4YF24hxSLkgBddDmjHzKDfo21-MvdPIpsAg9TTZYC', + 'version': 'ugSq-EY57Bf7CmYZg1N033tZoq1YSPg3bnl6W1XFgsgC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -4214,7 +4214,7 @@ 'src/chrome/browser/platform_experience/win': { 'url': Var('chrome_git') + '/chrome/browser/platform_experience/win.git' + '@' + - '3d27dce9761364362fb066b34eca50b767ab53d4', + '203bb990e01a33360e543edbf03db386355a4d26', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/aw_crashy_class_utils.cc b/android_webview/browser/aw_crashy_class_utils.cc index 57f5e4a..7b95472 100644 --- a/android_webview/browser/aw_crashy_class_utils.cc +++ b/android_webview/browser/aw_crashy_class_utils.cc
@@ -5,12 +5,21 @@ #include <ostream> #include "android_webview/browser_jni_headers/AwCrashyClassUtils_jni.h" -#include "base/check.h" +#include "base/compiler_specific.h" +#include "base/logging.h" namespace android_webview { +// Do not inline this function. This is meant to simulate a crash like we would +// see in a real incident. Real crashes will generally have at least 1 +// non-inlined stack frame, so we force this to happen in this case using both +// the NOINLINE and NOOPT annotations (for some reason, NOINLINE is not enough). +NOINLINE NOOPT void ThisFunctionWillCrash() { + LOG(FATAL) << "WebView Forced Native Crash for WebView Browser Process"; +} + static void JNI_AwCrashyClassUtils_CrashInNative(JNIEnv* env) { - CHECK(false) << "WebView Forced Native Crash for WebView Browser Process"; + ThisFunctionWillCrash(); } } // namespace android_webview
diff --git a/android_webview/browser/aw_feature_map.cc b/android_webview/browser/aw_feature_map.cc index e6176ac..6e852ca 100644 --- a/android_webview/browser/aw_feature_map.cc +++ b/android_webview/browser/aw_feature_map.cc
@@ -26,7 +26,6 @@ &features::kWebViewInvokeZoomPickerOnGSU, &features::kWebViewMixedContentAutoupgrades, &features::kWebViewTestFeature, - &features::kWebViewJavaJsBridgeMojo, &features::kWebViewUseMetricsUploadService, &features::kWebViewUseMetricsUploadServiceOnlySdkRuntime, &features::kWebViewXRequestedWithHeaderControl,
diff --git a/android_webview/common/aw_features.cc b/android_webview/common/aw_features.cc index 8f2a351..e0f1172 100644 --- a/android_webview/common/aw_features.cc +++ b/android_webview/common/aw_features.cc
@@ -106,11 +106,6 @@ "WebViewExtraHeadersSameOriginOnly", base::FEATURE_DISABLED_BY_DEFAULT); -// Enable the new Java/JS Bridge code path with mojo implementation. -BASE_FEATURE(kWebViewJavaJsBridgeMojo, - "WebViewJavaJsBridgeMojo", - base::FEATURE_DISABLED_BY_DEFAULT); - // Whether to record size of the embedding app's data directory to the UMA // histogram Android.WebView.AppDataDirectorySize. BASE_FEATURE(kWebViewRecordAppDataDirectorySize,
diff --git a/android_webview/common/aw_features.h b/android_webview/common/aw_features.h index 4f3846c..8b565f20 100644 --- a/android_webview/common/aw_features.h +++ b/android_webview/common/aw_features.h
@@ -32,7 +32,6 @@ // Feature parameter for `network::features::kMaskedDomainList` which is // defined in //services/network. extern const base::FeatureParam<int> kWebViewIpProtectionExclusionCriteria; -BASE_DECLARE_FEATURE(kWebViewJavaJsBridgeMojo); BASE_DECLARE_FEATURE(kWebViewMediaIntegrityApi); BASE_DECLARE_FEATURE(kWebViewMediaIntegrityApiBlinkExtension); BASE_DECLARE_FEATURE(kWebViewMixedContentAutoupgrades);
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 03081b5..2166dac 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -2067,10 +2067,7 @@ private JavascriptInjector getJavascriptInjector() { if (mJavascriptInjector == null) { - mJavascriptInjector = - JavascriptInjector.fromWebContents( - mWebContents, - AwFeatureMap.isEnabled(AwFeatures.WEBVIEW_JAVA_JS_BRIDGE_MOJO)); + mJavascriptInjector = JavascriptInjector.fromWebContents(mWebContents); } return mJavascriptInjector; }
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 58964b6..1aa9e62 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
@@ -208,9 +208,6 @@ "Enables autoupgrades for audio/video/image mixed content when mixed content " + "mode is set to MIXED_CONTENT_COMPATIBILITY_MODE"), Flag.baseFeature( - AwFeatures.WEBVIEW_JAVA_JS_BRIDGE_MOJO, - "Enables the new Java/JS Bridge code path with mojo implementation."), - Flag.baseFeature( BlinkFeatures.GMS_CORE_EMOJI, "Enables retrieval of the emoji font through GMS Core " + "improving emoji glyph coverage."), @@ -879,6 +876,9 @@ "MojoChannelAssociatedSendUsesRunOrPostTask", "Enables optimization for sending messages on channel-associated interfaces"), Flag.baseFeature( + "MojoChannelAssociatedCrashesOnSendError", + "Enable a CHECK to verify if there are Mojo send errors in the field"), + Flag.baseFeature( "MojoBindingsInlineSLS", "Enable small value optimization for current Mojo dispatch context storage"), Flag.baseFeature( @@ -929,6 +929,7 @@ "DoNotEvictOnAXLocationChange", "When enabled, do not evict the bfcache entry even when AXLocationChange happens."), Flag.baseFeature("PassHistogramSharedMemoryOnLaunch"), + Flag.baseFeature("PumpFastToSleepAndroid"), Flag.baseFeature( BlinkFeatures.NO_THROTTLING_VISIBLE_AGENT, "Do not throttle Javascript timers to 1Hz on hidden cross-origin frames that are"
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java index 119730b..e027df0 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java
@@ -502,7 +502,7 @@ InstrumentationRegistry.getInstrumentation() .runOnMainSync( () -> { - JavascriptInjector.fromWebContents(awContents.getWebContents(), false) + JavascriptInjector.fromWebContents(awContents.getWebContents()) .addPossiblyUnsafeInterface( pageChangeNotifier, "pageChangeNotifier", null); awContents.loadUrl(WAIT_FOR_JS_DETACHED_TEST_URL);
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/util/JavascriptEventObserver.java b/android_webview/javatests/src/org/chromium/android_webview/test/util/JavascriptEventObserver.java index 0ca18b6..f8a2c46e 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/util/JavascriptEventObserver.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/util/JavascriptEventObserver.java
@@ -4,8 +4,6 @@ package org.chromium.android_webview.test.util; -import org.chromium.android_webview.AwFeatureMap; -import org.chromium.android_webview.common.AwFeatures; import org.chromium.base.test.util.CallbackHelper; import org.chromium.content_public.browser.JavascriptInjector; import org.chromium.content_public.browser.WebContents; @@ -32,8 +30,7 @@ * @param name the name of object used in javascript */ public void register(WebContents webContents, String name) { - JavascriptInjector.fromWebContents( - webContents, AwFeatureMap.isEnabled(AwFeatures.WEBVIEW_JAVA_JS_BRIDGE_MOJO)) + JavascriptInjector.fromWebContents(webContents) .addPossiblyUnsafeInterface(this, name, null); }
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebSettingsBoundaryInterface.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebSettingsBoundaryInterface.java index f3a27ce..adb1449 100644 --- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebSettingsBoundaryInterface.java +++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebSettingsBoundaryInterface.java
@@ -107,4 +107,6 @@ int getWebViewMediaIntegrityApiDefaultStatus(); Map<String, @WebViewMediaIntegrityApiStatus Integer> getWebViewMediaIntegrityApiOverrideRules(); + + void setPreloadingEnabled(boolean preloadingEnabled); }
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java index 95b6ff57..75298f9 100644 --- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java +++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
@@ -271,4 +271,7 @@ // WebViewCompat.setAudioMuted // WebViewCompat.isAudioMuted public static final String MUTE_AUDIO = "MUTE_AUDIO"; + + // WebSettingsCompat.setPreloadingEnabled + public static final String ENABLE_PRELOADING = "ENABLE_PRELOADING"; }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebSettingsAdapter.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebSettingsAdapter.java index bddaaa3..eb18693a 100644 --- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebSettingsAdapter.java +++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebSettingsAdapter.java
@@ -11,6 +11,7 @@ import org.chromium.android_webview.AwDarkMode; import org.chromium.android_webview.AwSettings; import org.chromium.android_webview.common.MediaIntegrityApiStatus; +import org.chromium.android_webview.settings.PreloadingAllowedFlags; import org.chromium.base.Log; import org.chromium.base.TraceEvent; import org.chromium.components.webauthn.WebauthnMode; @@ -433,4 +434,16 @@ // unreached throw new IllegalArgumentException("Invalid WebView Media Integrity API status: " + status); } + + @Override + public void setPreloadingEnabled(boolean preloadingEnabled) { + try (TraceEvent event = + TraceEvent.scoped("WebView.APICall.AndroidX.SET_PRELOADING_ENABLED")) { + recordApiCall(ApiCall.SET_PRELOADING_ENABLED); + mAwSettings.setPreloadingAllowed( + preloadingEnabled + ? PreloadingAllowedFlags.PRERENDER_ENABLED + : PreloadingAllowedFlags.PRELOADING_DISABLED); + } + } }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java index 7e9f322..0db6b3d 100644 --- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java +++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
@@ -94,6 +94,7 @@ Features.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, Features.MUTE_AUDIO, Features.WEB_AUTHENTICATION, + Features.ENABLE_PRELOADING + Features.DEV_SUFFIX, // Add new features above. New features must include `+ Features.DEV_SUFFIX` // when they're initially added (this can be removed in a future CL). The final // feature should have a trailing comma for cleaner diffs. @@ -205,6 +206,7 @@ ApiCall.IS_AUDIO_MUTED, ApiCall.WEB_SETTINGS_SET_WEBAUTHN_SUPPORT, ApiCall.WEB_SETTINGS_GET_WEBAUTHN_SUPPORT, + ApiCall.SET_PRELOADING_ENABLED, // Add new constants above. The final constant should have a trailing comma for cleaner // diffs. ApiCall.COUNT, // Added to suppress WrongConstant in #recordApiCall @@ -315,8 +317,9 @@ int IS_AUDIO_MUTED = 101; int WEB_SETTINGS_SET_WEBAUTHN_SUPPORT = 102; int WEB_SETTINGS_GET_WEBAUTHN_SUPPORT = 103; + int SET_PRELOADING_ENABLED = 104; // Remember to update AndroidXWebkitApiCall in enums.xml when adding new values here - int COUNT = 104; + int COUNT = 105; } public static void recordApiCall(@ApiCall int apiCall) {
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 46e9c9b..e5bf468 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -333,6 +333,8 @@ "autotest_private_api_utils.cc", "birch/birch_client.h", "birch/birch_data_provider.h", + "birch/birch_icon_cache.cc", + "birch/birch_icon_cache.h", "birch/birch_item.cc", "birch/birch_item.h", "birch/birch_item_remover.cc", @@ -1686,6 +1688,8 @@ "system/focus_mode/sounds/playlist_view.h", "system/focus_mode/sounds/sound_section_view.cc", "system/focus_mode/sounds/sound_section_view.h", + "system/focus_mode/sounds/soundscape/soundscape_types.cc", + "system/focus_mode/sounds/soundscape/soundscape_types.h", "system/focus_mode/youtube_music/youtube_music_client.cc", "system/focus_mode/youtube_music/youtube_music_client.h", "system/focus_mode/youtube_music/youtube_music_controller.cc", @@ -3549,6 +3553,7 @@ "assistant/ui/main_stage/ui_element_container_view_unittest.cc", "assistant/util/deep_link_util_unittest.cc", "assistant/util/resource_util_unittest.cc", + "birch/birch_icon_cache_unittest.cc", "birch/birch_item_remover_unittest.cc", "birch/birch_item_unittest.cc", "birch/birch_model_unittest.cc", @@ -3896,6 +3901,7 @@ "system/focus_mode/focus_mode_task_test_utils.cc", "system/focus_mode/focus_mode_task_test_utils.h", "system/focus_mode/focus_mode_tray_unittest.cc", + "system/focus_mode/sounds/soundscape/soundscape_types_unittest.cc", "system/geolocation/geolocation_controller_test_util.cc", "system/geolocation/geolocation_controller_test_util.h", "system/geolocation/geolocation_controller_unittest.cc", @@ -4823,6 +4829,8 @@ "system/diagnostics/fake_diagnostics_browser_delegate.h", "system/diagnostics/log_test_helpers.cc", "system/diagnostics/log_test_helpers.h", + "system/focus_mode/sounds/soundscape/test/test_data.cc", + "system/focus_mode/sounds/soundscape/test/test_data.h", "system/focus_mode/test/test_focus_mode_delegate.cc", "system/focus_mode/test/test_focus_mode_delegate.h", "system/geolocation/test_geolocation_url_loader_factory.cc",
diff --git a/ash/birch/birch_icon_cache.cc b/ash/birch/birch_icon_cache.cc new file mode 100644 index 0000000..e88fd09 --- /dev/null +++ b/ash/birch/birch_icon_cache.cc
@@ -0,0 +1,31 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/birch/birch_icon_cache.h" + +#include <string> + +#include "base/containers/flat_map.h" +#include "ui/gfx/image/image_skia.h" + +namespace ash { + +BirchIconCache::BirchIconCache() = default; + +BirchIconCache::~BirchIconCache() = default; + +gfx::ImageSkia BirchIconCache::Get(const std::string& url) { + auto it = map_.find(url); + if (it == map_.end()) { + // Return a null image if the URL was not found. + return gfx::ImageSkia(); + } + return it->second; +} + +void BirchIconCache::Put(const std::string& url, const gfx::ImageSkia& icon) { + map_[url] = icon; +} + +} // namespace ash
diff --git a/ash/birch/birch_icon_cache.h b/ash/birch/birch_icon_cache.h new file mode 100644 index 0000000..b5e879ea --- /dev/null +++ b/ash/birch/birch_icon_cache.h
@@ -0,0 +1,42 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_BIRCH_BIRCH_ICON_CACHE_H_ +#define ASH_BIRCH_BIRCH_ICON_CACHE_H_ + +#include <string> + +#include "ash/ash_export.h" +#include "base/containers/flat_map.h" +#include "ui/gfx/image/image_skia.h" + +namespace ash { + +// Caches icons downloaded from URLs. Birch has a very small number of icons so +// there is no cache invalidation or removal of items from the cache. URLs are +// encoded as strings as this is common in client code. +class ASH_EXPORT BirchIconCache { + public: + BirchIconCache(); + BirchIconCache(const BirchIconCache&) = delete; + BirchIconCache& operator=(const BirchIconCache&) = delete; + ~BirchIconCache(); + + // Gets an icon based on a URL. If the icon is not in the cache a null image + // is returned. + gfx::ImageSkia Get(const std::string& url); + + // Adds or replaces an image in the cache. + void Put(const std::string& url, const gfx::ImageSkia& icon); + + size_t size_for_test() const { return map_.size(); } + + private: + // Maps a URL to an icon. + base::flat_map<std::string, gfx::ImageSkia> map_; +}; + +} // namespace ash + +#endif // ASH_BIRCH_BIRCH_ICON_CACHE_H_
diff --git a/ash/birch/birch_icon_cache_unittest.cc b/ash/birch/birch_icon_cache_unittest.cc new file mode 100644 index 0000000..482677ef --- /dev/null +++ b/ash/birch/birch_icon_cache_unittest.cc
@@ -0,0 +1,28 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/birch/birch_icon_cache.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/image/image_unittest_util.h" + +namespace ash { + +TEST(BirchIconCacheTest, NotFound) { + BirchIconCache cache; + gfx::ImageSkia icon = cache.Get("not-present"); + EXPECT_TRUE(icon.isNull()); +} + +TEST(BirchIconCacheTest, Found) { + BirchIconCache cache; + gfx::ImageSkia input_icon = gfx::test::CreateImageSkia(16); + cache.Put("key", input_icon); + gfx::ImageSkia output_icon = cache.Get("key"); + EXPECT_FALSE(output_icon.isNull()); + EXPECT_TRUE(input_icon.BackedBySameObjectAs(output_icon)); +} + +} // namespace ash
diff --git a/ash/birch/birch_item.cc b/ash/birch/birch_item.cc index d757d5f..1f9ec31 100644 --- a/ash/birch/birch_item.cc +++ b/ash/birch/birch_item.cc
@@ -8,6 +8,8 @@ #include <sstream> #include <string> +#include "ash/birch/birch_icon_cache.h" +#include "ash/birch/birch_model.h" #include "ash/public/cpp/image_downloader.h" #include "ash/public/cpp/new_window_delegate.h" #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h" @@ -32,8 +34,11 @@ // Handles when an `image` is downloaded, by converting it to a ui::ImageModel // and running `callback`. -void OnImageDownloaded(base::OnceCallback<void(const ui::ImageModel&)> callback, +void OnImageDownloaded(const GURL& url, + base::OnceCallback<void(const ui::ImageModel&)> callback, const gfx::ImageSkia& image) { + // Add the image to the cache. + Shell::Get()->birch_model()->icon_cache()->Put(url.spec(), image); std::move(callback).Run(ui::ImageModel::FromImageSkia(image)); } @@ -47,6 +52,16 @@ return; } + // Look for the icon in the cache. + gfx::ImageSkia icon = + Shell::Get()->birch_model()->icon_cache()->Get(url.spec()); + if (!icon.isNull()) { + // Use the cached icon. + std::move(callback).Run(ui::ImageModel::FromImageSkia(icon)); + return; + } + + // Download the icon. const UserSession* active_user_session = Shell::Get()->session_controller()->GetUserSession(0); CHECK(active_user_session); @@ -55,7 +70,7 @@ ImageDownloader::Get()->Download( url, MISSING_TRAFFIC_ANNOTATION, active_user_session->user_info.account_id, - base::BindOnce(&OnImageDownloaded, std::move(callback))); + base::BindOnce(&OnImageDownloaded, url, std::move(callback))); } } // namespace
diff --git a/ash/birch/birch_item_unittest.cc b/ash/birch/birch_item_unittest.cc index 25e1d6f..2283c838 100644 --- a/ash/birch/birch_item_unittest.cc +++ b/ash/birch/birch_item_unittest.cc
@@ -7,14 +7,20 @@ #include <memory> #include <utility> +#include "ash/birch/birch_icon_cache.h" +#include "ash/birch/birch_model.h" +#include "ash/constants/ash_features.h" #include "ash/public/cpp/test/test_image_downloader.h" #include "ash/public/cpp/test/test_new_window_delegate.h" +#include "ash/shell.h" #include "ash/system/time/calendar_unittest_utils.h" #include "ash/test/ash_test_base.h" #include "base/files/file_path.h" #include "base/memory/raw_ptr.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/test/scoped_mock_clock_override.h" +#include "base/test/test_future.h" #include "base/time/time.h" #include "chromeos/ash/components/settings/scoped_timezone_settings.h" #include "testing/gtest/include/gtest/gtest.h" @@ -459,7 +465,12 @@ // The icon downloader requires ash::Shell, so use AshTestBase. class BirchItemIconTest : public AshTestBase { public: + BirchItemIconTest() { + feature_list_.InitAndEnableFeature(features::kForestFeature); + } + TestImageDownloader image_downloader_; + base::test::ScopedFeatureList feature_list_; }; TEST_F(BirchItemIconTest, Calendar_LoadIcon) { @@ -482,8 +493,14 @@ /*end_time=*/base::Time(), /*file_id=*/""); - item.LoadIcon(base::BindOnce( - [](const ui::ImageModel& icon) { EXPECT_FALSE(icon.IsEmpty()); })); + base::test::TestFuture<const ui::ImageModel&> future; + item.LoadIcon(future.GetCallback()); + // The icon is not empty. + EXPECT_FALSE(future.Get().IsEmpty()); + + auto* icon_cache = Shell::Get()->birch_model()->icon_cache(); + EXPECT_EQ(icon_cache->size_for_test(), 1u); + EXPECT_FALSE(icon_cache->Get("http://attachment.icon/").isNull()); } TEST_F(BirchItemIconTest, Attachment_LoadIcon_InvalidUrl) { @@ -494,8 +511,13 @@ /*end_time=*/base::Time(), /*file_id=*/""); - item.LoadIcon(base::BindOnce( - [](const ui::ImageModel& icon) { EXPECT_TRUE(icon.IsEmpty()); })); + base::test::TestFuture<const ui::ImageModel&> future; + item.LoadIcon(future.GetCallback()); + // The icon is empty. + EXPECT_TRUE(future.Get().IsEmpty()); + + auto* icon_cache = Shell::Get()->birch_model()->icon_cache(); + EXPECT_EQ(icon_cache->size_for_test(), 0u); } TEST_F(BirchItemIconTest, Tab_LoadIcon) { @@ -504,8 +526,14 @@ /*favicon_url=*/GURL("http://icon.com/"), /*session_name=*/"", BirchTabItem::DeviceFormFactor::kDesktop); - item.LoadIcon(base::BindOnce( - [](const ui::ImageModel& icon) { EXPECT_FALSE(icon.IsEmpty()); })); + base::test::TestFuture<const ui::ImageModel&> future; + item.LoadIcon(future.GetCallback()); + // The icon is not empty. + EXPECT_FALSE(future.Get().IsEmpty()); + + auto* icon_cache = Shell::Get()->birch_model()->icon_cache(); + EXPECT_EQ(icon_cache->size_for_test(), 1u); + EXPECT_FALSE(icon_cache->Get("http://icon.com/").isNull()); } TEST_F(BirchItemIconTest, Tab_LoadIcon_InvalidUrl) { @@ -514,8 +542,13 @@ /*favicon_url=*/GURL("invalid-url"), /*session_name=*/"", BirchTabItem::DeviceFormFactor::kDesktop); - item.LoadIcon(base::BindOnce( - [](const ui::ImageModel& icon) { EXPECT_TRUE(icon.IsEmpty()); })); + base::test::TestFuture<const ui::ImageModel&> future; + item.LoadIcon(future.GetCallback()); + // The icon is empty. + EXPECT_TRUE(future.Get().IsEmpty()); + + auto* icon_cache = Shell::Get()->birch_model()->icon_cache(); + EXPECT_EQ(icon_cache->size_for_test(), 0u); } TEST_F(BirchItemIconTest, Weather_LoadIcon) { @@ -542,8 +575,14 @@ BirchFileItem item(base::FilePath("/path/to/file.gdoc"), u"suggested", base::Time(), "id_1", icon_url); - item.LoadIcon(base::BindOnce( - [](const ui::ImageModel& icon) { EXPECT_FALSE(icon.IsEmpty()); })); + base::test::TestFuture<const ui::ImageModel&> future; + item.LoadIcon(future.GetCallback()); + // The icon is not empty. + EXPECT_FALSE(future.Get().IsEmpty()); + + auto* icon_cache = Shell::Get()->birch_model()->icon_cache(); + EXPECT_EQ(icon_cache->size_for_test(), 1u); + EXPECT_FALSE(icon_cache->Get(icon_url).isNull()); } } // namespace
diff --git a/ash/birch/birch_model.cc b/ash/birch/birch_model.cc index ad30ed8..949e90d 100644 --- a/ash/birch/birch_model.cc +++ b/ash/birch/birch_model.cc
@@ -10,6 +10,7 @@ #include <vector> #include "ash/birch/birch_data_provider.h" +#include "ash/birch/birch_icon_cache.h" #include "ash/birch/birch_item.h" #include "ash/birch/birch_item_remover.h" #include "ash/birch/birch_ranker.h" @@ -58,7 +59,8 @@ recent_tab_data_(prefs::kBirchUseRecentTabs, "Tab"), self_share_data_(prefs::kBirchUseSelfShare, "SelfShare"), release_notes_data_(prefs::kBirchUseReleaseNotes, "ReleaseNotes"), - weather_data_(prefs::kBirchUseWeather, "Weather") { + weather_data_(prefs::kBirchUseWeather, "Weather"), + icon_cache_(std::make_unique<BirchIconCache>()) { if (features::IsBirchWeatherEnabled()) { weather_provider_ = std::make_unique<BirchWeatherProvider>(this); }
diff --git a/ash/birch/birch_model.h b/ash/birch/birch_model.h index 2e2f0d85..c18a9a3 100644 --- a/ash/birch/birch_model.h +++ b/ash/birch/birch_model.h
@@ -24,6 +24,7 @@ namespace ash { class BirchDataProvider; +class BirchIconCache; class BirchItemRemover; // Birch model, which is used to aggregate and store relevant information from @@ -105,6 +106,7 @@ void SetClientAndInit(BirchClient* client); BirchClient* birch_client() { return birch_client_; } + BirchIconCache* icon_cache() { return icon_cache_.get(); } const std::vector<BirchCalendarItem>& GetCalendarItemsForTest() const { return calendar_data_.items; @@ -225,6 +227,8 @@ raw_ptr<BirchClient> birch_client_ = nullptr; + std::unique_ptr<BirchIconCache> icon_cache_; + std::unique_ptr<BirchDataProvider> weather_provider_; // When set, this clock is used to ensure a consistent current time is used
diff --git a/ash/birch/birch_weather_provider.cc b/ash/birch/birch_weather_provider.cc index 28dcaeb..65a9133a 100644 --- a/ash/birch/birch_weather_provider.cc +++ b/ash/birch/birch_weather_provider.cc
@@ -7,6 +7,7 @@ #include <string> #include "ash/ambient/ambient_controller.h" +#include "ash/birch/birch_icon_cache.h" #include "ash/birch/birch_item.h" #include "ash/birch/birch_model.h" #include "ash/public/cpp/ambient/ambient_backend_controller.h" @@ -116,18 +117,29 @@ return; } - // Ideally we should avoid downloading from the same url again to reduce the - // overhead, as it's unlikely that the weather condition is changing - // frequently during the day. + // Check for a cached icon. + gfx::ImageSkia icon = Shell::Get()->birch_model()->icon_cache()->Get( + *weather_info->condition_icon_url); + if (!icon.isNull()) { + // Use the cached icon. + AddItemToBirchModel(base::UTF8ToUTF16(*weather_info->condition_description), + *weather_info->temp_f, weather_info->show_celsius, + icon); + return; + } + + // Download the weather condition icon. DownloadImageFromUrl( *weather_info->condition_icon_url, base::BindOnce(&BirchWeatherProvider::OnWeatherConditionIconDownloaded, weak_factory_.GetWeakPtr(), + *weather_info->condition_icon_url, base::UTF8ToUTF16(*weather_info->condition_description), *weather_info->temp_f, weather_info->show_celsius)); } void BirchWeatherProvider::OnWeatherConditionIconDownloaded( + const std::string& condition_icon_url, const std::u16string& weather_description, float temp_f, bool show_celsius, @@ -137,6 +149,17 @@ return; } + // Add the icon to the cache. + Shell::Get()->birch_model()->icon_cache()->Put(condition_icon_url, icon); + + AddItemToBirchModel(weather_description, temp_f, show_celsius, icon); +} + +void BirchWeatherProvider::AddItemToBirchModel( + const std::u16string& weather_description, + float temp_f, + bool show_celsius, + const gfx::ImageSkia& icon) { std::u16string temperature_string = show_celsius ? l10n_util::GetStringFUTF16Int( IDS_ASH_AMBIENT_MODE_WEATHER_TEMPERATURE_IN_CELSIUS,
diff --git a/ash/birch/birch_weather_provider.h b/ash/birch/birch_weather_provider.h index 00201f5..fde625f2 100644 --- a/ash/birch/birch_weather_provider.h +++ b/ash/birch/birch_weather_provider.h
@@ -44,11 +44,18 @@ // Callback to weather info icon request. It will update birch model with the // fetched weather info (including the downloaded weather icon). void OnWeatherConditionIconDownloaded( + const std::string& condition_icon_url, const std::u16string& weather_description, float temp_f, bool show_celsius, const gfx::ImageSkia& icon); + // Adds the weather item to the birch model. + void AddItemToBirchModel(const std::u16string& weather_description, + float temp_f, + bool show_celsius, + const gfx::ImageSkia& icon); + const raw_ptr<BirchModel> birch_model_; bool is_fetching_ = false;
diff --git a/ash/birch/birch_weather_provider_unittest.cc b/ash/birch/birch_weather_provider_unittest.cc index b32cfe4..10ffce6 100644 --- a/ash/birch/birch_weather_provider_unittest.cc +++ b/ash/birch/birch_weather_provider_unittest.cc
@@ -9,6 +9,7 @@ #include <vector> #include "ash/ambient/ambient_controller.h" +#include "ash/birch/birch_icon_cache.h" #include "ash/birch/birch_model.h" #include "ash/constants/ash_features.h" #include "ash/constants/geolocation_access_level.h" @@ -384,4 +385,64 @@ EXPECT_EQ(ambient_backend_controller_->fetch_weather_count(), 1); } +TEST_F(BirchWeatherProviderTest, IconCache) { + auto* birch_model = Shell::Get()->birch_model(); + auto* icon_cache = birch_model->icon_cache(); + + // The cache starts empty. + EXPECT_EQ(icon_cache->size_for_test(), 0u); + + // Fetch weather. + WeatherInfo info1; + info1.condition_description = "Cloudy"; + info1.condition_icon_url = "https://cloudy-icon-url"; + info1.show_celsius = false; + info1.temp_f = 70.0f; + ambient_backend_controller_->SetWeatherInfo(info1); + + base::RunLoop run_loop; + birch_model->RequestBirchDataFetch(/*is_post_login=*/false, + run_loop.QuitClosure()); + run_loop.Run(); + + // The icon cache has a single item in it. + EXPECT_EQ(icon_cache->size_for_test(), 1u); + EXPECT_FALSE(icon_cache->Get("https://cloudy-icon-url").isNull()); + + // Fetch again with the same icon URL. + WeatherInfo info2; + info2.condition_description = "Cloudy"; + info2.condition_icon_url = "https://cloudy-icon-url"; + info2.show_celsius = false; + info2.temp_f = 70.0f; + ambient_backend_controller_->SetWeatherInfo(info2); + + base::RunLoop run_loop2; + birch_model->RequestBirchDataFetch(/*is_post_login=*/false, + run_loop2.QuitClosure()); + run_loop2.Run(); + + // The cache still has a single item in it because the icon was the same. + EXPECT_EQ(icon_cache->size_for_test(), 1u); + EXPECT_FALSE(icon_cache->Get("https://cloudy-icon-url").isNull()); + + // Fetch again with a different icon URL. + WeatherInfo info3; + info2.condition_description = "Sunny"; + info2.condition_icon_url = "https://sunny-icon-url"; + info2.show_celsius = false; + info2.temp_f = 73.0f; + ambient_backend_controller_->SetWeatherInfo(info2); + + base::RunLoop run_loop3; + birch_model->RequestBirchDataFetch(/*is_post_login=*/false, + run_loop3.QuitClosure()); + run_loop3.Run(); + + // Cache now has two items in it for the two different icons. + EXPECT_EQ(icon_cache->size_for_test(), 2u); + EXPECT_FALSE(icon_cache->Get("https://cloudy-icon-url").isNull()); + EXPECT_FALSE(icon_cache->Get("https://sunny-icon-url").isNull()); +} + } // namespace ash
diff --git a/ash/login/SAML_INTEGRATION_OWNERS b/ash/login/SAML_INTEGRATION_OWNERS index 64ef0f5..530660c 100644 --- a/ash/login/SAML_INTEGRATION_OWNERS +++ b/ash/login/SAML_INTEGRATION_OWNERS
@@ -1,2 +1,3 @@ andreydav@google.com +ayag@chromium.org lmasopust@google.com
diff --git a/ash/search_box/search_box_view_base.cc b/ash/search_box/search_box_view_base.cc index f0af52e..24ecc2ac 100644 --- a/ash/search_box/search_box_view_base.cc +++ b/ash/search_box/search_box_view_base.cc
@@ -657,7 +657,7 @@ .height() : 0; return gfx::Size(kSearchBoxPreferredWidth, - kSearchBoxPreferredHeight + iph_height); + kSearchBoxPreferredHeight + insets.height() + iph_height); } void SearchBoxViewBase::OnEnabledChanged() {
diff --git a/ash/system/focus_mode/sounds/soundscape/README.md b/ash/system/focus_mode/sounds/soundscape/README.md new file mode 100644 index 0000000..01246c3 --- /dev/null +++ b/ash/system/focus_mode/sounds/soundscape/README.md
@@ -0,0 +1,8 @@ +# Focus Sounds + +Soundscapes is the internal name for Focus Sounds. Soundscapes are the +playlists that are only used by Focus Mode and independent of the other +sound options in Focus Mode. + +This folder contains code relevant to downloading and parsing the data for +this backend.
diff --git a/ash/system/focus_mode/sounds/soundscape/soundscape_types.cc b/ash/system/focus_mode/sounds/soundscape/soundscape_types.cc new file mode 100644 index 0000000..9a861015 --- /dev/null +++ b/ash/system/focus_mode/sounds/soundscape/soundscape_types.cc
@@ -0,0 +1,229 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/focus_mode/sounds/soundscape/soundscape_types.h" + +#include "base/json/json_reader.h" +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "base/values.h" + +namespace ash { + +namespace { + +// Maximum allowed length of parsed strings. +constexpr int kStringMax = 255; + +// Maximum number of tracks per playlist. +constexpr int kMaxTracks = 100; + +// For the UI, there should always be 4 playlists in a valid configuration. +constexpr int kNumPlaylists = 4; + +constexpr char kDefaultLocale[] = "en-US"; + +bool ValidString(const std::string* str) { + return !!str && !str->empty() && str->length() <= kStringMax; +} + +bool ValidList(const base::Value::List* list) { + return !!list && !list->empty(); +} + +// Returns the best name for `locale` in `localized_names` which is assumed to +// be a Dict with a "locale" and "name" field. If a match for `locale` is not +// found, returns the result for the default locale (en-US). If a suitable name +// is not found, nullptr is returned. +const std::string* BestLocalizedName(std::string_view locale, + const base::Value::List& localized_names) { + const std::string* default_name = nullptr; + const std::string* language_match = nullptr; + + for (const base::Value& localized_name : localized_names) { + const base::Value::Dict* dict = localized_name.GetIfDict(); + if (!dict) { + continue; + } + const std::string* candidate_locale = dict->FindString("locale"); + if (!candidate_locale) { + continue; + } + const std::string* candidate_name = dict->FindString("name"); + if (!ValidString(candidate_name)) { + continue; + } + + std::string_view locale_view(*candidate_locale); + if (locale_view == locale) { + // Exact matches are best. We're done. + return candidate_name; + } + + if (locale_view.substr(0, 2) == locale.substr(0, 2)) { + // The first 2 letters of the locale represent the language. Try to match + // this in the case that there is no exact match. + language_match = candidate_name; + continue; + } + + if (locale_view == kDefaultLocale) { + default_name = candidate_name; + continue; + } + } + + if (language_match) { + return language_match; + } + + return default_name; +} + +} // namespace + +// static +std::optional<SoundscapeTrack> SoundscapeTrack::FromValue( + const base::Value& value) { + const base::Value::Dict* dict = value.GetIfDict(); + if (!dict) { + return std::nullopt; + } + + const std::string* name = dict->FindString("name"); + const std::string* path = dict->FindString("path"); + + if (!ValidString(name) || !ValidString(path)) { + return std::nullopt; + } + + return SoundscapeTrack(*name, *path); +} + +SoundscapeTrack::SoundscapeTrack(const std::string& name, + const std::string& path) + : name(name), path(path) {} +SoundscapeTrack::SoundscapeTrack(const SoundscapeTrack&) = default; +SoundscapeTrack::~SoundscapeTrack() = default; + +// static +std::optional<SoundscapePlaylist> SoundscapePlaylist::FromValue( + std::string_view locale, + const base::Value& value) { + if (locale.length() != 2 && locale.length() != 5) { + // Locales are either 2 or 5 characters representing just the language (e.g. + // "en") or the language and country with a dash ("en-US") as described in + // RFC 5646. + return std::nullopt; + } + + const base::Value::Dict* dict = value.GetIfDict(); + if (!dict) { + return std::nullopt; + } + + const base::Value::List* localized_names = dict->FindList("name"); + const std::string* thumbnail = dict->FindString("thumbnail"); + const std::string* uuid = dict->FindString("uuid"); + const base::Value::List* tracks = dict->FindList("tracks"); + + if (!ValidList(localized_names) || !ValidList(tracks) || + !ValidString(thumbnail) || !ValidString(uuid)) { + return std::nullopt; + } + + if (tracks->size() > kMaxTracks) { + LOG(WARNING) << "Too many tracks in playlist " << tracks->size(); + return std::nullopt; + } + + const std::string* name = BestLocalizedName(locale, *localized_names); + if (!name) { + return std::nullopt; + } + + base::Uuid parsed_uuid = base::Uuid::ParseLowercase(*uuid); + if (!parsed_uuid.is_valid()) { + return std::nullopt; + } + + SoundscapePlaylist playlist; + playlist.tracks.reserve(tracks->size()); + for (const base::Value& track : *tracks) { + std::optional<SoundscapeTrack> parsed_track = + SoundscapeTrack::FromValue(track); + if (!parsed_track) { + LOG(WARNING) << "Track validation failed"; + return std::nullopt; + } + playlist.tracks.push_back(std::move(*parsed_track)); + } + + playlist.name = *name; + playlist.uuid = parsed_uuid; + playlist.thumbnail = *thumbnail; + + return playlist; +} + +SoundscapePlaylist::SoundscapePlaylist() = default; +SoundscapePlaylist::SoundscapePlaylist(SoundscapePlaylist&&) = default; +SoundscapePlaylist::~SoundscapePlaylist() = default; + +SoundscapeConfiguration::SoundscapeConfiguration() = default; +SoundscapeConfiguration::SoundscapeConfiguration(SoundscapeConfiguration&&) = + default; +SoundscapeConfiguration& SoundscapeConfiguration::operator=( + SoundscapeConfiguration&&) = default; +SoundscapeConfiguration::~SoundscapeConfiguration() = default; + +// static +std::optional<SoundscapeConfiguration> +SoundscapeConfiguration::ParseConfiguration(std::string_view locale, + std::string_view json) { + if (locale.size() != 2u && locale.size() != 5u) { + LOG(ERROR) << "Invalid locale string"; + return std::nullopt; + } + + if (json.empty()) { + return std::nullopt; + } + + std::optional<base::Value> value = + base::JSONReader::Read(json, base::JSONParserOptions::JSON_PARSE_RFC); + if (!value) { + LOG(WARNING) << "Configuration cannot be parsed"; + return std::nullopt; + } + + const base::Value::Dict* dict = value->GetIfDict(); + if (!dict) { + LOG(WARNING) << "Configuration is not a dictionary"; + return std::nullopt; + } + + const base::Value::List* playlists = dict->FindList("playlists"); + // We always expect exactly 4 playlists. + if (!playlists || playlists->size() != kNumPlaylists) { + LOG(WARNING) << "Playlists are invalid"; + return std::nullopt; + } + + SoundscapeConfiguration config; + config.playlists.reserve(kNumPlaylists); + for (const base::Value& playlist : *playlists) { + std::optional<SoundscapePlaylist> parsed = + SoundscapePlaylist::FromValue(locale, playlist); + if (!parsed) { + LOG(WARNING) << "Playlist validation failed"; + return std::nullopt; + } + config.playlists.push_back(std::move(*parsed)); + } + + return config; +} + +} // namespace ash
diff --git a/ash/system/focus_mode/sounds/soundscape/soundscape_types.h b/ash/system/focus_mode/sounds/soundscape/soundscape_types.h new file mode 100644 index 0000000..e7e2cff --- /dev/null +++ b/ash/system/focus_mode/sounds/soundscape/soundscape_types.h
@@ -0,0 +1,83 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_FOCUS_MODE_SOUNDS_SOUNDSCAPE_SOUNDSCAPE_TYPES_H_ +#define ASH_SYSTEM_FOCUS_MODE_SOUNDS_SOUNDSCAPE_SOUNDSCAPE_TYPES_H_ + +#include <optional> +#include <string> +#include <string_view> +#include <vector> + +#include "ash/ash_export.h" +#include "base/uuid.h" + +namespace base { +class Value; +} // namespace base + +namespace ash { + +struct ASH_EXPORT SoundscapeTrack { + // If possible, returns a fully populated `SoundscapeTrack` from `value`. + // Otherwise, nullopt. + static std::optional<SoundscapeTrack> FromValue(const base::Value& value); + + SoundscapeTrack(const std::string& name, const std::string& path); + SoundscapeTrack(const SoundscapeTrack&); + ~SoundscapeTrack(); + + std::string name; + + // Relative path to the audio file. Relative to the configuration origin. + std::string path; +}; + +struct ASH_EXPORT SoundscapePlaylist { + // Returns a fully populated `SoundscapePlaylist` from `value` if all fields + // are available. Uses the name for `locale` if found. Otherwise, names + // default to "en-US". If `value` does not generate a fully populated + // `SoundscapePlaylist`, returns nullptr. + static std::optional<SoundscapePlaylist> FromValue(std::string_view locale, + const base::Value& value); + + SoundscapePlaylist(); + SoundscapePlaylist(const SoundscapePlaylist&) = delete; + SoundscapePlaylist(SoundscapePlaylist&&); + ~SoundscapePlaylist(); + + // Uniquely identifies a playlist. Playlists which share a Uuid will have the + // same contents. + base::Uuid uuid; + + std::string name; + + // A relative path to the thumbnail image (relative to the origin url of + // the configuration). + std::string thumbnail; + std::vector<SoundscapeTrack> tracks; +}; + +// Represents a configuration for Soundscapes consisting of a set of +// playlists which are made of a set of tracks which can be played while +// a user is in a Focus Mode session. +struct ASH_EXPORT SoundscapeConfiguration { + // Attempts to build a `SoundscapeConfiguration` from `json` parsed as JSON. + // If any fields are missing or invalid, returns nullopt. + static std::optional<SoundscapeConfiguration> ParseConfiguration( + std::string_view locale, + std::string_view json); + + SoundscapeConfiguration(); + SoundscapeConfiguration(const SoundscapeConfiguration&) = delete; + SoundscapeConfiguration(SoundscapeConfiguration&&); + SoundscapeConfiguration& operator=(SoundscapeConfiguration&&); + ~SoundscapeConfiguration(); + + std::vector<SoundscapePlaylist> playlists; +}; + +} // namespace ash + +#endif // ASH_SYSTEM_FOCUS_MODE_SOUNDS_SOUNDSCAPE_SOUNDSCAPE_TYPES_H_
diff --git a/ash/system/focus_mode/sounds/soundscape/soundscape_types_unittest.cc b/ash/system/focus_mode/sounds/soundscape/soundscape_types_unittest.cc new file mode 100644 index 0000000..64bbc1ef --- /dev/null +++ b/ash/system/focus_mode/sounds/soundscape/soundscape_types_unittest.cc
@@ -0,0 +1,164 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/focus_mode/sounds/soundscape/soundscape_types.h" + +#include <optional> + +#include "ash/system/focus_mode/sounds/soundscape/test/test_data.h" +#include "base/values.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { + +namespace { + +constexpr char kLocale[] = "en-US"; +constexpr char kTrackUrl[] = "/tracks/track.mp3"; +constexpr char kUuid[] = "bee58263-412c-4f6c-9eb5-7abacc89b2e8"; + +base::Value TestTrack() { + base::Value::Dict dict; + dict.Set("name", "Test Track"); + dict.Set("path", kTrackUrl); + + // The JSON format supports an artist field but it's currently unused. + dict.Set("artist", "Not parsed"); + return base::Value(std::move(dict)); + ; +} + +base::Value TestPlaylist() { + base::Value::List track_list; + for (int i = 0; i < 3; i++) { + track_list.Append(TestTrack()); + } + + base::Value::List name_list = + base::Value::List() + .Append(base::Value::Dict() + .Set("locale", "en-US") + .Set("name", "World's Most Awesome Playlist")) + .Append( + base::Value::Dict() + .Set("locale", "es-US") + .Set("name", + "La lista de reproducción más impresionante del mundo")); + base::Value::Dict dict; + dict.Set("uuid", kUuid); + dict.Set("name", std::move(name_list)); + dict.Set("thumbnail", "/thumbs/pic_123453.png"); + dict.Set("tracks", std::move(track_list)); + return base::Value(std::move(dict)); +} + +TEST(SoundscapeTypeTests, ParseTrack) { + base::Value test_value = TestTrack(); + std::optional<SoundscapeTrack> track = SoundscapeTrack::FromValue(test_value); + ASSERT_TRUE(track); + EXPECT_THAT(track->name, testing::Eq("Test Track")); + EXPECT_THAT(track->path, testing::Eq(kTrackUrl)); +} + +TEST(SoundscapeTypeTests, ParseTrack_Empty) { + // Not a dictionary. + EXPECT_THAT( + SoundscapeTrack::FromValue(base::Value(base::Value::Type::STRING)), + testing::Eq(std::nullopt)); + // Empty dictionary. + EXPECT_THAT(SoundscapeTrack::FromValue(base::Value(base::Value::Type::DICT)), + testing::Eq(std::nullopt)); +} + +TEST(SoundscapeTypeTests, ParsePlaylist) { + base::Value test_value = TestPlaylist(); + std::optional<SoundscapePlaylist> playlist = + SoundscapePlaylist::FromValue(kLocale, test_value); + ASSERT_TRUE(playlist); + EXPECT_THAT(playlist->name, testing::Eq("World's Most Awesome Playlist")); + + EXPECT_TRUE(playlist->uuid.is_valid()); + EXPECT_THAT(playlist->uuid, testing::Eq(base::Uuid::ParseLowercase(kUuid))); + + EXPECT_THAT(playlist->tracks, testing::SizeIs(3)); + EXPECT_THAT(playlist->tracks, + testing::Each(testing::Field(&SoundscapeTrack::name, + testing::Eq("Test Track")))); +} + +TEST(SoundscapeTypeTests, ParsePlaylist_NonEnglish) { + base::Value test_value = TestPlaylist(); + std::optional<SoundscapePlaylist> playlist = + SoundscapePlaylist::FromValue("es-US", test_value); + ASSERT_TRUE(playlist); + EXPECT_THAT( + playlist->name, + testing::Eq("La lista de reproducción más impresionante del mundo")); +} + +TEST(SoundscapeTypeTests, ParsePlaylist_EnglishFallback) { + base::Value test_value = TestPlaylist(); + // ZZ is a user defined country code and ia is the language code for + // Interlingua (for which we do not have a mapping). + const std::string locale = "ia-ZZ"; + std::optional<SoundscapePlaylist> playlist = + SoundscapePlaylist::FromValue(locale, test_value); + ASSERT_TRUE(playlist); + EXPECT_THAT(playlist->name, testing::Eq("World's Most Awesome Playlist")); +} + +TEST(SoundscapeTypeTests, ParsePlaylist_Empty) { + EXPECT_THAT(SoundscapePlaylist::FromValue( + kLocale, base::Value(base::Value::Type::NONE)), + testing::Eq(std::nullopt)); + EXPECT_THAT(SoundscapePlaylist::FromValue( + kLocale, base::Value(base::Value::Type::DICT)), + testing::Eq(std::nullopt)); +} + +TEST(SoundscapeTypeTests, ParseConfiguration) { + std::optional<SoundscapeConfiguration> config = + SoundscapeConfiguration::ParseConfiguration("fr-CA", kTestConfig); + ASSERT_TRUE(config); + EXPECT_THAT(config->playlists, testing::SizeIs(4)); + EXPECT_THAT( + config->playlists, + testing::ElementsAre( + testing::Field(&SoundscapePlaylist::name, "Musique Classique"), + testing::Field(&SoundscapePlaylist::name, "Nature"), + testing::Field(&SoundscapePlaylist::name, "Flux"), + testing::Field(&SoundscapePlaylist::name, "Ambiance"))); +} + +TEST(SoundscapeTypeTests, ParseConfiguration_LangOnly) { + std::optional<SoundscapeConfiguration> config = + SoundscapeConfiguration::ParseConfiguration("fr", kTestConfig); + ASSERT_TRUE(config); + EXPECT_THAT(config->playlists, testing::SizeIs(4)); + EXPECT_THAT(config->playlists, + testing::Contains(testing::Field(&SoundscapePlaylist::name, + "Musique Classique"))); +} + +TEST(SoundscapeTypeTests, ParseConfiguration_Empty) { + std::optional<SoundscapeConfiguration> config = + SoundscapeConfiguration::ParseConfiguration(kLocale, ""); + EXPECT_THAT(config, testing::Eq(std::nullopt)); +} + +TEST(SoundscapeTypeTests, ParseConfiguration_Malformed) { + std::optional<SoundscapeConfiguration> config = + SoundscapeConfiguration::ParseConfiguration(kLocale, "{lksjdfksjdfj}"); + EXPECT_THAT(config, testing::Eq(std::nullopt)); +} + +TEST(SoundscapeTypeTests, ParseConfiguration_InvalidLocale) { + std::optional<SoundscapeConfiguration> config = + SoundscapeConfiguration::ParseConfiguration("foo", kTestConfig); + EXPECT_THAT(config, testing::Eq(std::nullopt)); +} + +} // namespace +} // namespace ash
diff --git a/ash/system/focus_mode/sounds/soundscape/test/test_data.cc b/ash/system/focus_mode/sounds/soundscape/test/test_data.cc new file mode 100644 index 0000000..bf17072 --- /dev/null +++ b/ash/system/focus_mode/sounds/soundscape/test/test_data.cc
@@ -0,0 +1,121 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/focus_mode/sounds/soundscape/test/test_data.h" + +namespace ash { + +constexpr char kTestConfig[] = R"( +{ + "version": "20240426", + "playlists": [ + { + "name": [ + { + "locale": "en-US", + "name": "Classical" + }, + { + "locale": "fr-CA", + "name": "Musique Classique" + } + ], + "uuid": "a58d4418-c835-4254-b5d6-cca909046202", + "thumbnail": "/thumbnails/classical_20240426.png", + "tracks": [ + { + "name": "Violins", + "artist": "Artist", + "path": "/tracks/violins_20240426.mp3" + }, + { + "name": "Cello", + "artist": "Artist", + "path": "/tracks/cello_20240426.mp3" + } + ] + }, + { + "name": [ + { + "locale": "en-US", + "name": "Nature" + }, + { + "locale": "fr-CA", + "name": "Nature" + } + ], + "uuid": "1c25911f-d847-4500-94e3-6e2d9a52846a", + "thumbnail": "/thumbnails/nature_20240426.png", + "tracks": [ + { + "name": "Bears", + "artist": "Artist", + "path": "/tracks/bears_20240426.mp3" + }, + { + "name": "Penguins", + "artist": "Artist", + "path": "/tracks/penguins_20240426.mp3" + } + ] + }, + { + "name": [ + { + "locale": "en-US", + "name": "Flow" + }, + { + "locale": "fr-CA", + "name": "Flux" + } + ], + "uuid": "921c4f5c-ccd8-4f1a-ba19-0b3c2685aa92", + "thumbnail": "/thumbnails/flow_20240426.png", + "tracks": [ + { + "name": "A Longer Song Name", + "artist": "Artist", + "path": "/tracks/track_20240426.mp3" + }, + { + "name": "Release", + "artist": "Artist", + "path": "/tracks/release_20240426.mp3" + } + ] + }, + { + "name": [ + { + "locale": "en-US", + "name": "Ambiance" + }, + { + "locale": "fr-CA", + "name": "Ambiance" + } + ], + "uuid": "1b12ce3a-4857-4aae-95df-65cef1c4d4f3", + "thumbnail": "/thumbnails/ambiance_20240426.png", + "tracks": [ + { + "name": "Rain", + "artist": "Artist", + "path": "/tracks/rain_20240426.mp3" + }, + { + "name": "Coffee Shop", + "artist": "Artist", + "path": "/tracks/coffee_shop_20240426.mp3" + } + ] + } + ] +} +)"; + +} // namespace ash
diff --git a/ash/system/focus_mode/sounds/soundscape/test/test_data.h b/ash/system/focus_mode/sounds/soundscape/test/test_data.h new file mode 100644 index 0000000..00ee9eca --- /dev/null +++ b/ash/system/focus_mode/sounds/soundscape/test/test_data.h
@@ -0,0 +1,14 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_FOCUS_MODE_SOUNDS_SOUNDSCAPE_TEST_TEST_DATA_H_ +#define ASH_SYSTEM_FOCUS_MODE_SOUNDS_SOUNDSCAPE_TEST_TEST_DATA_H_ + +namespace ash { + +extern const char kTestConfig[]; + +} // namespace ash + +#endif // ASH_SYSTEM_FOCUS_MODE_SOUNDS_SOUNDSCAPE_TEST_TEST_DATA_H_
diff --git a/ash/system/notification_center/views/notification_list_view.cc b/ash/system/notification_center/views/notification_list_view.cc index 8db63f0..a971e76 100644 --- a/ash/system/notification_center/views/notification_list_view.cc +++ b/ash/system/notification_center/views/notification_list_view.cc
@@ -744,7 +744,7 @@ // Height is taken from preferred size, which is calculated based on the // tween and animation state when animations are occurring. So views which // are animating will provide the correct interpolated height here. - const int height = view->GetHeightForWidth(message_view_width_); + const int height = view->CalculateHeight(); const int direction = view->GetSlideDirection(); if (y > 0) {
diff --git a/ash/webui/print_preview_cros/resources/BUILD.gn b/ash/webui/print_preview_cros/resources/BUILD.gn index 0b89b338..075ab049 100644 --- a/ash/webui/print_preview_cros/resources/BUILD.gn +++ b/ash/webui/print_preview_cros/resources/BUILD.gn
@@ -16,6 +16,7 @@ css_files = [ "css/print_preview_cros_shared.css" ] non_web_component_files = [ + "js/data/capabilities_manager.ts", "js/data/destination_constants.ts", "js/data/destination_manager.ts", "js/data/preview_ticket_manager.ts",
diff --git a/ash/webui/print_preview_cros/resources/js/data/capabilities_manager.ts b/ash/webui/print_preview_cros/resources/js/data/capabilities_manager.ts new file mode 100644 index 0000000..c74e0d2 --- /dev/null +++ b/ash/webui/print_preview_cros/resources/js/data/capabilities_manager.ts
@@ -0,0 +1,131 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {assert} from 'chrome://resources/js/assert.js'; +import {EventTracker} from 'chrome://resources/js/event_tracker.js'; + +import {createCustomEvent} from '../utils/event_utils.js'; +import {getDestinationProvider} from '../utils/mojo_data_providers.js'; +import {Capabilities, type DestinationProvider, SessionContext} from '../utils/print_preview_cros_app_types.js'; + +import {DESTINATION_MANAGER_ACTIVE_DESTINATION_CHANGED, DestinationManager} from './destination_manager.js'; + +/** + * @fileoverview + * 'capabilties_manager' responsible for requesting and storing the printing + * capabilities for the active destination. + */ + +export const CAPABILITIES_MANAGER_SESSION_INITIALIZED = + 'capabilities-manager.session-initialized'; +export const CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_LOADING = + 'capabilities-manager.active-destination-caps-loading'; +export const CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_READY = + 'capabilities-manager.active-destination-caps-ready'; + +export class CapabilitiesManager extends EventTarget { + private static instance: CapabilitiesManager|null = null; + + static getInstance(): CapabilitiesManager { + if (CapabilitiesManager.instance === null) { + CapabilitiesManager.instance = new CapabilitiesManager(); + } + + return CapabilitiesManager.instance; + } + + static resetInstanceForTesting(): void { + CapabilitiesManager.instance = null; + } + + // Non-static properties: + private destinationProvider: DestinationProvider|null; + private sessionContext: SessionContext; + private eventTracker = new EventTracker(); + private destinationManager: DestinationManager = + DestinationManager.getInstance(); + private capabilitiesCache = new Map<string, Capabilities>(); + + // Prevent additional initialization. + private constructor() { + super(); + + // Setup mojo data providers. + this.destinationProvider = getDestinationProvider(); + + this.eventTracker.add( + this.destinationManager, DESTINATION_MANAGER_ACTIVE_DESTINATION_CHANGED, + (): void => this.fetchCapabilitesForActiveDestination()); + } + + // `initializeSession` is only intended to be called once from the + // `PrintPreviewCrosAppController`. + initializeSession(sessionContext: SessionContext): void { + assert( + !this.sessionContext, 'SessionContext should only be configured once'); + this.sessionContext = sessionContext; + + this.dispatchEvent( + createCustomEvent(CAPABILITIES_MANAGER_SESSION_INITIALIZED)); + } + + private fetchCapabilitesForActiveDestination(): void { + const destination = this.destinationManager.getActiveDestination(); + if (destination === null) { + return; + } + + this.dispatchEvent(createCustomEvent( + CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_LOADING)); + + const cachedCapabilities = this.capabilitiesCache.get(destination.id); + if (cachedCapabilities) { + this.dispatchEvent(createCustomEvent( + CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_READY)); + return; + } + + this.destinationProvider! + .fetchCapabilities(destination.id, destination.printerType) + .then((caps: Capabilities) => this.onCapabilitiesFetched(caps)); + } + + private onCapabilitiesFetched(caps: Capabilities): void { + this.capabilitiesCache.set(caps.destinationId, caps); + + // Since multiple capabilities requests can be in-flight simultaneously, + // verify this capabilities response belongs to the active destination + // before sending the ready event. + const activeDestination = this.destinationManager.getActiveDestination(); + assert(activeDestination); + if (caps.destinationId === activeDestination.id) { + this.dispatchEvent(createCustomEvent( + CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_READY)); + } + } + + // Returns the capabilities from the active destination if available. + getActiveDestinationCapabilities(): Capabilities|undefined { + const activeDestination = this.destinationManager.getActiveDestination(); + if (activeDestination === null) { + return undefined; + } + + return this.capabilitiesCache.get(activeDestination.id); + } + + // Returns true only after the `initializeSession` function has been called + // with a valid `SessionContext`. + isSessionInitialized(): boolean { + return !!this.sessionContext; + } +} + +declare global { + interface HTMLElementEventMap { + [CAPABILITIES_MANAGER_SESSION_INITIALIZED]: CustomEvent<void>; + [CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_LOADING]: CustomEvent<void>; + [CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_READY]: CustomEvent<void>; + } +}
diff --git a/ash/webui/print_preview_cros/resources/js/fakes/fake_data.ts b/ash/webui/print_preview_cros/resources/js/fakes/fake_data.ts index bc98375..cf350a8 100644 --- a/ash/webui/print_preview_cros/resources/js/fakes/fake_data.ts +++ b/ash/webui/print_preview_cros/resources/js/fakes/fake_data.ts
@@ -45,7 +45,8 @@ } -export function getFakeCapabilities(destinationId: string = ''): Capabilities { +export function getFakeCapabilities(destinationId: string = 'Printer1'): + Capabilities { const collate: CollateCapability = { valueDefault: true, };
diff --git a/ash/webui/print_preview_cros/resources/js/print_preview_cros_app_controller.ts b/ash/webui/print_preview_cros/resources/js/print_preview_cros_app_controller.ts index 22a8fca..799da5f 100644 --- a/ash/webui/print_preview_cros/resources/js/print_preview_cros_app_controller.ts +++ b/ash/webui/print_preview_cros/resources/js/print_preview_cros_app_controller.ts
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {CapabilitiesManager} from './data/capabilities_manager.js'; import {DestinationManager} from './data/destination_manager.js'; import {PreviewTicketManager} from './data/preview_ticket_manager.js'; import {PrintTicketManager} from './data/print_ticket_manager.js'; @@ -19,6 +20,7 @@ export class PrintPreviewCrosAppController extends EventTarget { private printPreviewPageHandler = getPrintPreviewPageHandler(); private sessionContext: SessionContext; + private capabilitiesManager = CapabilitiesManager.getInstance(); private destinationManager = DestinationManager.getInstance(); private previewTicketManager = PreviewTicketManager.getInstance(); private printTicketManager = PrintTicketManager.getInstance(); @@ -29,6 +31,7 @@ this.printPreviewPageHandler.startSession().then( (sessionContext: SessionContext): void => { this.sessionContext = sessionContext; + this.capabilitiesManager.initializeSession(this.sessionContext); this.destinationManager.initializeSession(this.sessionContext); this.previewTicketManager.initializeSession(this.sessionContext); this.printTicketManager.initializeSession(this.sessionContext);
diff --git a/ash/webui/print_preview_cros/resources/js/summary_panel_controller.ts b/ash/webui/print_preview_cros/resources/js/summary_panel_controller.ts index 020d9c1..47614c8c 100644 --- a/ash/webui/print_preview_cros/resources/js/summary_panel_controller.ts +++ b/ash/webui/print_preview_cros/resources/js/summary_panel_controller.ts
@@ -25,7 +25,7 @@ export class SummaryPanelController extends EventTarget { private sheetsUsed = 0; private previewTicketManager = PreviewTicketManager.getInstance(); - private printTicketManger = PrintTicketManager.getInstance(); + private printTicketManager = PrintTicketManager.getInstance(); /** * @param eventTracker Passed in by owning element to ensure event handlers @@ -40,10 +40,10 @@ this.previewTicketManager, PREVIEW_REQUEST_FINISHED_EVENT, () => this.onPreviewRequestFinished()); eventTracker.add( - this.printTicketManger, PRINT_REQUEST_STARTED_EVENT, + this.printTicketManager, PRINT_REQUEST_STARTED_EVENT, (e: Event) => this.onPrintRequestStarted(e)); eventTracker.add( - this.printTicketManger, PRINT_REQUEST_FINISHED_EVENT, + this.printTicketManager, PRINT_REQUEST_FINISHED_EVENT, (e: Event) => this.onPrintRequestFinished(e)); } @@ -68,13 +68,13 @@ // Handles behavior for when the print button is clicked. handlePrintClicked(): void { - this.printTicketManger.sendPrintRequest(); + this.printTicketManager.sendPrintRequest(); } // Handles any required cleanup prior to sending a cancel request to the // backend and closing the dialog when the cancel button is clicked. handleCancelClicked(): void { - this.printTicketManger.cancelPrintRequest(); + this.printTicketManager.cancelPrintRequest(); } // CustomEvent dispatch helper. @@ -106,7 +106,7 @@ // Whether the print button should be enabled for the current state. shouldDisablePrintButton(): boolean { return !this.previewTicketManager.isPreviewLoaded() || - this.printTicketManger.isPrintRequestInProgress(); + this.printTicketManager.isPrintRequestInProgress(); } }
diff --git a/ash/wm/session_state_animator_impl.cc b/ash/wm/session_state_animator_impl.cc index 52ca974..87acc54 100644 --- a/ash/wm/session_state_animator_impl.cc +++ b/ash/wm/session_state_animator_impl.cc
@@ -258,24 +258,22 @@ Shell::GetContainer(root_window, kShellWindowId_ShelfContainer)); } if (container_mask & SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS) { - // TODO(antrim): Figure out a way to eliminate a need to exclude shelf - // in such way. - aura::Window* non_lock_screen_containers = Shell::GetContainer( - root_window, kShellWindowId_NonLockScreenContainersContainer); - // |non_lock_screen_containers| may already be removed in some tests. - constexpr int ContainersToAnimate[] = { - kShellWindowId_HomeScreenContainer, - kShellWindowId_AlwaysOnTopContainer, - kShellWindowId_PipContainer, - kShellWindowId_SystemModalContainer, - }; - if (non_lock_screen_containers) { - for (aura::Window* window : non_lock_screen_containers->children()) { - if ((base::Contains(ContainersToAnimate, window->GetId()) || - desks_util::IsActiveDeskContainer(window))) { - containers->push_back(window); - } + // `non_lock_screen_containers` may already be removed in some tests. + if (aura::Window* non_lock_screen_containers = Shell::GetContainer( + root_window, kShellWindowId_NonLockScreenContainersContainer); + non_lock_screen_containers) { + constexpr int ContainersToAnimate[] = { + kShellWindowId_HomeScreenContainer, + kShellWindowId_AlwaysOnTopContainer, + kShellWindowId_FloatContainer, + kShellWindowId_PipContainer, + kShellWindowId_SystemModalContainer, + }; + for (const int id : ContainersToAnimate) { + containers->push_back(Shell::GetContainer(root_window, id)); } + containers->push_back( + desks_util::GetActiveDeskContainerForRoot(root_window)); } } if (container_mask & SessionStateAnimator::LOCK_SCREEN_WALLPAPER) {
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc index 8fa3bd1..15a0d79e 100644 --- a/ash/wm/window_util.cc +++ b/ash/wm/window_util.cc
@@ -79,29 +79,6 @@ namespace ash::window_util { namespace { -// This window targeter reserves space for the portion of the resize handles -// that extend within a top level window. -class InteriorResizeHandleTargeterAsh - : public chromeos::InteriorResizeHandleTargeter { - public: - InteriorResizeHandleTargeterAsh() = default; - InteriorResizeHandleTargeterAsh(const InteriorResizeHandleTargeterAsh&) = - delete; - InteriorResizeHandleTargeterAsh& operator=( - const InteriorResizeHandleTargeterAsh&) = delete; - ~InteriorResizeHandleTargeterAsh() override = default; - - bool ShouldUseExtendedBounds(const aura::Window* target) const override { - // Fullscreen/maximized windows can't be drag-resized. - const WindowState* window_state = WindowState::Get(window()); - if (window_state && window_state->IsMaximizedOrFullscreenOrPinned()) - return false; - - // The shrunken hit region only applies to children of |window()|. - return InteriorResizeHandleTargeter::ShouldUseExtendedBounds(target); - } -}; - // Returns true if `window` has any descendant that is a system modal window or // is itself a system modal window. bool ContainsSystemModalWindow(const aura::Window* window) { @@ -403,7 +380,13 @@ } void InstallResizeHandleWindowTargeterForWindow(aura::Window* window) { - window->SetEventTargeter(std::make_unique<InteriorResizeHandleTargeterAsh>()); + window->SetEventTargeter( + std::make_unique<chromeos::InteriorResizeHandleTargeter>( + base::BindRepeating([](const aura::Window* window) { + const WindowState* window_state = WindowState::Get(window); + return window_state ? window_state->GetStateType() + : chromeos::WindowStateType::kDefault; + }))); } bool IsDraggingTabs(const aura::Window* window) {
diff --git a/base/BUILD.gn b/base/BUILD.gn index 665d93d..0fd8801 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -4819,11 +4819,9 @@ "test/android/javatests/src/org/chromium/base/test/BaseJUnit4TestRule.java", "test/android/javatests/src/org/chromium/base/test/LoadNative.java", "test/android/javatests/src/org/chromium/base/test/MockitoErrorHandler.java", - "test/android/javatests/src/org/chromium/base/test/ResetCachedFlagValuesTestHook.java", "test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java", "test/android/javatests/src/org/chromium/base/test/TestTraceEvent.java", "test/android/javatests/src/org/chromium/base/test/UnitTestLifetimeAssertRule.java", - "test/android/javatests/src/org/chromium/base/test/UnitTestNoBrowserProcessHook.java", "test/android/javatests/src/org/chromium/base/test/params/BaseJUnit4RunnerDelegate.java", "test/android/javatests/src/org/chromium/base/test/params/BlockJUnit4RunnerDelegate.java", "test/android/javatests/src/org/chromium/base/test/params/MethodParamAnnotationRule.java",
diff --git a/base/android/java/src/org/chromium/base/Log.java b/base/android/java/src/org/chromium/base/Log.java index 2d38d8b..27a645d 100644 --- a/base/android/java/src/org/chromium/base/Log.java +++ b/base/android/java/src/org/chromium/base/Log.java
@@ -64,20 +64,11 @@ return "cr_" + tag; } - private static boolean isDebug() { - // Proguard sets value to false in release builds. - return true; - } - /** * In debug: Forwards to {@link android.util.Log#isLoggable(String, int)}. * In release: Always returns false (via proguard rule). */ public static boolean isLoggable(String tag, int level) { - // Early return helps optimizer eliminate calls to isLoggable(). - if (!isDebug() && level <= INFO) { - return false; - } return android.util.Log.isLoggable(tag, level); } @@ -92,7 +83,7 @@ * one is a {@link Throwable}, its trace will be printed. */ public static void v(String tag, String messageTemplate, Object... args) { - if (!isDebug()) return; + if (!isLoggable(tag, VERBOSE)) return; Throwable tr = getThrowableToLog(args); String message = formatLog(messageTemplate, tr, args); @@ -115,7 +106,7 @@ * one is a {@link Throwable}, its trace will be printed. */ public static void d(String tag, String messageTemplate, Object... args) { - if (!isDebug()) return; + if (!isLoggable(tag, DEBUG)) return; Throwable tr = getThrowableToLog(args); String message = formatLog(messageTemplate, tr, args);
diff --git a/base/android/proguard/shared_with_cronet.flags b/base/android/proguard/shared_with_cronet.flags index 9f27079..3a36042 100644 --- a/base/android/proguard/shared_with_cronet.flags +++ b/base/android/proguard/shared_with_cronet.flags
@@ -9,14 +9,6 @@ # Chromium code. They MUST be scoped appropriately to avoid side effects on app # code that we do not own. -# Use assumevalues block instead of assumenosideeffects block because Google3 -# proguard cannot parse assumenosideeffects blocks which overwrite return -# value. Keep this in shared_with_cronet.flags rather than remove_logging.flags -# so that it's included in cronet. --assumevalues class org.chromium.base.Log { - static boolean isDebug() return false; -} - # Keep all CREATOR fields within Parcelable that are kept. -keepclassmembers class !cr_allowunused,org.chromium.** implements android.os.Parcelable { public static *** CREATOR;
diff --git a/base/message_loop/message_pump.cc b/base/message_loop/message_pump.cc index 692aa86..28e1703e 100644 --- a/base/message_loop/message_pump.cc +++ b/base/message_loop/message_pump.cc
@@ -121,6 +121,8 @@ g_explicit_high_resolution_timer_win = FeatureList::IsEnabled(kExplicitHighResolutionTimerWin); MessagePumpWin::InitializeFeatures(); +#elif BUILDFLAG(IS_ANDROID) + MessagePumpAndroid::InitializeFeatures(); #endif }
diff --git a/base/message_loop/message_pump_android.cc b/base/message_loop/message_pump_android.cc index e1ed57ae..e8246037 100644 --- a/base/message_loop/message_pump_android.cc +++ b/base/message_loop/message_pump_android.cc
@@ -12,6 +12,8 @@ #include <sys/timerfd.h> #include <sys/types.h> #include <unistd.h> + +#include <atomic> #include <utility> #include "base/android/input_hint_checker.h" @@ -21,6 +23,7 @@ #include "base/notreached.h" #include "base/numerics/safe_conversions.h" #include "base/run_loop.h" +#include "base/task/task_features.h" #include "base/time/time.h" #include "build/build_config.h" @@ -70,6 +73,8 @@ // A bit added to the |non_delayed_fd_| to keep it signaled when we yield to // native work below. constexpr uint64_t kTryNativeWorkBeforeIdleBit = uint64_t(1) << 32; + +std::atomic_bool g_fast_to_sleep = false; } // namespace MessagePumpAndroid::MessagePumpAndroid() @@ -107,6 +112,10 @@ close(delayed_fd_); } +void MessagePumpAndroid::InitializeFeatures() { + g_fast_to_sleep = base::FeatureList::IsEnabled(kPumpFastToSleepAndroid); +} + void MessagePumpAndroid::OnDelayedLooperCallback() { // There may be non-Chromium callbacks on the same ALooper which may have left // a pending exception set, and ALooper does not check for this between @@ -224,26 +233,32 @@ if (ShouldQuit()) return; - // Before declaring this loop idle, yield to native work items and arrange to - // be called again (unless we're already in that second call). - if (!do_idle_work) { - ScheduleWorkInternal(/*do_idle_work=*/true); - return; + // Under the fast to sleep feature, `do_idle_work` is ignored, and the pump + // will always "sleep" after finishing all its work items. + if (!g_fast_to_sleep) { + // Before declaring this loop idle, yield to native work items and arrange + // to be called again (unless we're already in that second call). + if (!do_idle_work) { + ScheduleWorkInternal(/*do_idle_work=*/true); + return; + } + + // We yielded to native work items already and they didn't generate a + // ScheduleWork() request so we can declare idleness. It's possible for a + // ScheduleWork() request to come in racily while this method unwinds, this + // is fine and will merely result in it being re-invoked shortly after it + // returns. + // TODO(scheduler-dev): this doesn't account for tasks that don't ever call + // SchedulerWork() but still keep the system non-idle (e.g., the Java + // Handler API). It would be better to add an API to query the presence of + // native tasks instead of relying on yielding once + + // kTryNativeWorkBeforeIdleBit. + DCHECK(do_idle_work); } - // We yielded to native work items already and they didn't generate a - // ScheduleWork() request so we can declare idleness. It's possible for a - // ScheduleWork() request to come in racily while this method unwinds, this is - // fine and will merely result in it being re-invoked shortly after it - // returns. - // TODO(scheduler-dev): this doesn't account for tasks that don't ever call - // SchedulerWork() but still keep the system non-idle (e.g., the Java Handler - // API). It would be better to add an API to query the presence of native - // tasks instead of relying on yielding once + kTryNativeWorkBeforeIdleBit. - DCHECK(do_idle_work); - - if (ShouldQuit()) + if (ShouldQuit()) { return; + } // At this point, the java looper might not be idle - it's impossible to know // pre-Android-M, so we may end up doing Idle work while java tasks are still
diff --git a/base/message_loop/message_pump_android.h b/base/message_loop/message_pump_android.h index 3b0d535d..2010492 100644 --- a/base/message_loop/message_pump_android.h +++ b/base/message_loop/message_pump_android.h
@@ -45,6 +45,8 @@ void ScheduleDelayedWork( const Delegate::NextWorkInfo& next_work_info) override; + static void InitializeFeatures(); + // Attaches |delegate| to this native MessagePump. |delegate| will from then // on be invoked by the native loop to process application tasks. virtual void Attach(Delegate* delegate);
diff --git a/base/message_loop/message_pump_epoll.cc b/base/message_loop/message_pump_epoll.cc index 07cf1fbf..0364a2f 100644 --- a/base/message_loop/message_pump_epoll.cc +++ b/base/message_loop/message_pump_epoll.cc
@@ -379,7 +379,6 @@ void MessagePumpEpoll::HandleWakeUp() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - BeginNativeWorkBatch(); processed_io_events_ = true; uint64_t value; ssize_t n = HANDLE_EINTR(read(wake_event_.get(), &value, sizeof(value)));
diff --git a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc index 59160e01..b8c56cc 100644 --- a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc +++ b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
@@ -182,11 +182,20 @@ } } void ThreadControllerWithMessagePumpImpl::BeginNativeWorkBeforeDoWork() { + do_work_needed_before_wait_ = true; + if (!g_avoid_schedule_calls_during_native_event_processing.load( std::memory_order_relaxed)) { return; } - in_native_work_batch_ = true; + + // Native nested loops don't guarantee that `DoWork()` will be called after + // executing native work. This is the invariant that is needed to avoid + // calls to `ScheduleWork()`. Since these calls can't be skipped there is + // nothing left to do in this function. + if (task_execution_allowed_in_native_nested_loop_) { + return; + } // Reuse the deduplicator facility to indicate that there is no need for // ScheduleWork() until the next time we look for work. @@ -304,7 +313,7 @@ void ThreadControllerWithMessagePumpImpl::BeforeWait() { // DoWork is guaranteed to be called after native work batches and before // wait. - CHECK(!in_native_work_batch_); + CHECK(!do_work_needed_before_wait_); // In most cases, DoIdleWork() will already have cleared the // `hang_watch_scope_` but in some cases where the native side of the @@ -320,8 +329,6 @@ MessagePump::Delegate::NextWorkInfo ThreadControllerWithMessagePumpImpl::DoWork() { - in_native_work_batch_ = false; - #if BUILDFLAG(IS_WIN) // We've been already in a wakeup here. Deactivate the high res timer of OS // immediately instead of waiting for next DoIdleWork(). @@ -350,6 +357,10 @@ main_thread_only().yield_to_native_after_batch)) { next_work_info.yield_to_native = true; } + + // There was just a check for more work. + do_work_needed_before_wait_ = false; + // Schedule a continuation. WorkDeduplicator::NextTask next_task = (next_wake_up && next_wake_up->is_immediate()) @@ -714,6 +725,7 @@ pump_->ScheduleWork(); } } + task_execution_allowed_in_native_nested_loop_ = allowed; main_thread_only().task_execution_allowed = allowed; }
diff --git a/base/task/sequence_manager/thread_controller_with_message_pump_impl.h b/base/task/sequence_manager/thread_controller_with_message_pump_impl.h index c1992ec..c75657b 100644 --- a/base/task/sequence_manager/thread_controller_with_message_pump_impl.h +++ b/base/task/sequence_manager/thread_controller_with_message_pump_impl.h
@@ -176,7 +176,8 @@ GUARDED_BY(task_runner_lock_); WorkDeduplicator work_deduplicator_; - bool in_native_work_batch_ = false; + bool do_work_needed_before_wait_ = false; + bool task_execution_allowed_in_native_nested_loop_ = false; ThreadControllerPowerMonitor power_monitor_;
diff --git a/base/task/task_features.cc b/base/task/task_features.cc index 2ec6a7a..3b827c9 100644 --- a/base/task/task_features.cc +++ b/base/task/task_features.cc
@@ -55,6 +55,10 @@ BASE_FEATURE(kUIPumpImprovementsWin, "UIPumpImprovementsWin", + base::FEATURE_ENABLED_BY_DEFAULT); + +BASE_FEATURE(kPumpFastToSleepAndroid, + "PumpFastToSleepAndroid", base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kRunTasksByBatches,
diff --git a/base/task/task_features.h b/base/task/task_features.h index 8e943e1..bc3c1eea 100644 --- a/base/task/task_features.h +++ b/base/task/task_features.h
@@ -62,6 +62,11 @@ // calling Win32 MessagePump functions less often. BASE_EXPORT BASE_DECLARE_FEATURE(kUIPumpImprovementsWin); +// Under this feature, the Android pump will call ALooper_PollOnce() rather than +// unconditionally yielding to native to determine whether there exists native +// work to be done before sleep. +BASE_EXPORT BASE_DECLARE_FEATURE(kPumpFastToSleepAndroid); + // Feature to run tasks by batches before pumping out messages. BASE_EXPORT BASE_DECLARE_FEATURE(kRunTasksByBatches);
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java index 89b34e3..d65b2284 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java +++ b/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java
@@ -22,14 +22,18 @@ import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; -import org.chromium.base.CommandLine; +import org.chromium.base.FeatureParam; +import org.chromium.base.Flag; import org.chromium.base.Log; import org.chromium.base.ResettersForTesting; +import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.test.params.MethodParamAnnotationRule; import org.chromium.base.test.util.AndroidSdkLevelSkipCheck; +import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisableIfSkipCheck; import org.chromium.base.test.util.EspressoIdleTimeoutRule; +import org.chromium.base.test.util.RequiresRestart; import org.chromium.base.test.util.RestrictionSkipCheck; import org.chromium.base.test.util.SkipCheck; @@ -162,60 +166,53 @@ /** * See {@link ClassHook}. Prefer to use TestRules over this. * - * Additional hooks can be added to the list by overriding this method and using {@link - * #addToList}: - * {@code return addToList(super.getPreClassHooks(), hook1, hook2);} + * <p>Additional hooks can be added to the list by overriding this method and using {@link + * #addToList}: {@code return addToList(super.getPreClassHooks(), hook1, hook2);} */ @CallSuper protected List<ClassHook> getPreClassHooks() { - return Arrays.asList(CommandLineFlags.getPreClassHook()); + return Collections.emptyList(); } /** * See {@link ClassHook}. Prefer to use TestRules over this. * - * Additional hooks can be added to the list by overriding this method and using {@link - * #addToList}: - * {@code return addToList(super.getPostClassHooks(), hook1, hook2);} + * <p>Additional hooks can be added to the list by overriding this method and using {@link + * #addToList}: {@code return addToList(super.getPostClassHooks(), hook1, hook2);} */ @CallSuper protected List<ClassHook> getPostClassHooks() { - return Arrays.asList(CommandLineFlags.getPostClassHook()); + return Collections.emptyList(); } /** * See {@link TestHook}. Prefer to use TestRules over this. * - * Additional hooks can be added to the list by overriding this method and using {@link - * #addToList}: - * {@code return addToList(super.getPreTestHooks(), hook1, hook2);} + * <p>Additional hooks can be added to the list by overriding this method and using {@link + * #addToList}: {@code return addToList(super.getPreTestHooks(), hook1, hook2);} */ @CallSuper protected List<TestHook> getPreTestHooks() { - return Arrays.asList( - CommandLineFlags.getPreTestHook(), - new UnitTestNoBrowserProcessHook(), - new ResetCachedFlagValuesTestHook()); + return Collections.emptyList(); } /** * See {@link TestHook}. Prefer to use TestRules over this. * - * Additional hooks can be added to the list by overriding this method and using {@link - * #addToList}: - * {@code return addToList(super.getPostTestHooks(), hook1, hook2);} + * <p>Additional hooks can be added to the list by overriding this method and using {@link + * #addToList}: {@code return addToList(super.getPostTestHooks(), hook1, hook2);} */ @CallSuper protected List<TestHook> getPostTestHooks() { - return Arrays.asList(CommandLineFlags.getPostTestHook()); + return Collections.emptyList(); } /** - * Override this method to return a list of method rules that should be applied to all tests - * run with this test runner. + * Override this method to return a list of method rules that should be applied to all tests run + * with this test runner. * - * Additional rules can be added to the list using {@link #addToList}: - * {@code return addToList(super.getDefaultMethodRules(), rule1, rule2);} + * <p>Additional rules can be added to the list using {@link #addToList}: {@code return + * addToList(super.getDefaultMethodRules(), rule1, rule2);} */ @CallSuper protected List<MethodRule> getDefaultMethodRules() { @@ -269,18 +266,29 @@ } ResettersForTesting.beforeClassHooksWillExecute(); - runPreClassHooks(getDescription().getTestClass()); - assert CommandLine.isInitialized(); + + Class<?> testClass = getDescription().getTestClass(); + CommandLineFlags.setUpClass(testClass); + runPreClassHooks(testClass); super.run(notifier); try { - runPostClassHooks(getDescription().getTestClass()); + CommandLineFlags.tearDownClass(); + runPostClassHooks(testClass); } finally { ResettersForTesting.afterClassHooksDidExecute(); } } + private static void blockUnitTestsFromStartingBrowser(FrameworkMethod testMethod) { + Batch annotation = testMethod.getDeclaringClass().getAnnotation(Batch.class); + if (annotation != null && annotation.value().equals(Batch.UNIT_TESTS)) { + if (testMethod.getAnnotation(RequiresRestart.class) != null) return; + LibraryLoader.setBrowserProcessStartupBlockedForTesting(); + } + } + @Override protected void runChild(FrameworkMethod method, RunNotifier notifier) { String testName = method.getName(); @@ -289,11 +297,19 @@ long start = SystemClock.uptimeMillis(); ResettersForTesting.beforeHooksWillExecute(); + + CommandLineFlags.setUpMethod(method.getMethod()); + blockUnitTestsFromStartingBrowser(method); + // TODO(agrieve): These should not reset flag values set in @BeforeClass + Flag.resetAllInMemoryCachedValuesForTesting(); + FeatureParam.resetAllInMemoryCachedValuesForTesting(); + runPreTestHooks(method); super.runChild(method, notifier); runPostTestHooks(method); + CommandLineFlags.tearDownMethod(); ResettersForTesting.afterHooksDidExecute(); Bundle b = new Bundle();
diff --git a/base/test/android/javatests/src/org/chromium/base/test/ResetCachedFlagValuesTestHook.java b/base/test/android/javatests/src/org/chromium/base/test/ResetCachedFlagValuesTestHook.java deleted file mode 100644 index 53e86f9..0000000 --- a/base/test/android/javatests/src/org/chromium/base/test/ResetCachedFlagValuesTestHook.java +++ /dev/null
@@ -1,22 +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. - -package org.chromium.base.test; - -import android.content.Context; - -import org.junit.runners.model.FrameworkMethod; - -import org.chromium.base.FeatureParam; -import org.chromium.base.Flag; -import org.chromium.base.test.BaseJUnit4ClassRunner.TestHook; - -/** Resets any cached values held by active {@link Flag} instances. */ -public class ResetCachedFlagValuesTestHook implements TestHook { - @Override - public void run(Context targetContext, FrameworkMethod testMethod) { - Flag.resetAllInMemoryCachedValuesForTesting(); - FeatureParam.resetAllInMemoryCachedValuesForTesting(); - } -}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/UnitTestNoBrowserProcessHook.java b/base/test/android/javatests/src/org/chromium/base/test/UnitTestNoBrowserProcessHook.java deleted file mode 100644 index d7bdada4..0000000 --- a/base/test/android/javatests/src/org/chromium/base/test/UnitTestNoBrowserProcessHook.java +++ /dev/null
@@ -1,28 +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. - -package org.chromium.base.test; - -import android.content.Context; - -import org.junit.runners.model.FrameworkMethod; - -import org.chromium.base.library_loader.LibraryLoader; -import org.chromium.base.test.BaseJUnit4ClassRunner.TestHook; -import org.chromium.base.test.util.Batch; -import org.chromium.base.test.util.RequiresRestart; - -/** - * PreTestHook used to ensure we don't start the browser process in unit tests. - * */ -public final class UnitTestNoBrowserProcessHook implements TestHook { - @Override - public void run(Context targetContext, FrameworkMethod testMethod) { - Batch annotation = testMethod.getDeclaringClass().getAnnotation(Batch.class); - if (annotation != null && annotation.value().equals(Batch.UNIT_TESTS)) { - if (testMethod.getAnnotation(RequiresRestart.class) != null) return; - LibraryLoader.setBrowserProcessStartupBlockedForTesting(); - } - } -}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/ConditionWaiter.java b/base/test/android/javatests/src/org/chromium/base/test/transit/ConditionWaiter.java index 549d6a16..f066c338 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/ConditionWaiter.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/ConditionWaiter.java
@@ -13,6 +13,7 @@ import org.chromium.base.TimeUtils; import org.chromium.base.test.transit.StatusStore.StatusRegion; import org.chromium.base.test.transit.Transition.TransitionOptions; +import org.chromium.base.test.transit.Transition.Trigger; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.CriteriaNotSatisfiedException; @@ -165,14 +166,15 @@ private static final String TAG = "Transit"; /** - * Blocks waiting for multiple {@link Condition}s, polling them and reporting their status to he - * {@link ConditionWait}es. + * Start timers, perform the first Condition checks before running the Trigger. * - * @param conditionWaits the {@link ConditionWait}es to process. - * @param options the {@link TransitionOptions} to configure the polling parameters. - * @throws AssertionError if not all {@link Condition}s are fulfilled before timing out. + * <p>Ensure at least one Condition is not fulfilled before running the Trigger. + * + * <p>This also makes supplied values available for Conditions that implement Supplier before + * {@link Condition#onStartMonitoring()} is called. */ - public static void waitFor(List<ConditionWait> conditionWaits, TransitionOptions options) { + static void preCheck( + List<ConditionWait> conditionWaits, TransitionOptions options, Trigger trigger) { if (conditionWaits.isEmpty()) { Log.i(TAG, "No conditions to fulfill."); } @@ -181,6 +183,32 @@ wait.startTimer(); } + boolean anyCriteriaMissing = false; + for (ConditionWait wait : conditionWaits) { + anyCriteriaMissing |= wait.update(); + } + + // At least one Condition should be not fulfilled, or this is likely an incorrectly designed + // Transition. Exceptions to this rule: + // 1. null Trigger, for example when focusing on secondary elements of a screen that + // aren't declared in Station#declareElements(). + // 2. A explicit exception is made with TransitionOptions.mPossiblyAlreadyFulfilled. + // E.g. when not possible to determine whether the trigger needs to be run. + if (!anyCriteriaMissing && !options.mPossiblyAlreadyFulfilled && trigger != null) { + throw buildWaitConditionsException( + "All Conditions already fulfilled before running Trigger", conditionWaits); + } + } + + /** + * Blocks waiting for multiple {@link Condition}s, polling them and reporting their status to he + * {@link ConditionWait}es. + * + * @param conditionWaits the {@link ConditionWait}es to process. + * @param options the {@link TransitionOptions} to configure the polling parameters. + * @throws AssertionError if not all {@link Condition}s are fulfilled before timing out. + */ + static void waitFor(List<ConditionWait> conditionWaits, TransitionOptions options) { Runnable checker = () -> { boolean anyCriteriaMissing = false; @@ -189,7 +217,8 @@ } if (anyCriteriaMissing) { - throw buildWaitConditionsException(conditionWaits); + throw buildWaitConditionsException( + "Did not meet all conditions", conditionWaits); } else { Log.i( TAG, @@ -203,9 +232,9 @@ } private static CriteriaNotSatisfiedException buildWaitConditionsException( - List<ConditionWait> conditionWaits) { + String message, List<ConditionWait> conditionWaits) { return new CriteriaNotSatisfiedException( - "Did not meet all conditions:\n" + createWaitConditionsSummary(conditionWaits)); + message + ":\n" + createWaitConditionsSummary(conditionWaits)); } private static String createWaitConditionsSummary(List<ConditionWait> conditionStatuses) {
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/FacilityCheckIn.java b/base/test/android/javatests/src/org/chromium/base/test/transit/FacilityCheckIn.java index 2ea0ebacd..2c28bf0 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/FacilityCheckIn.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/FacilityCheckIn.java
@@ -37,6 +37,7 @@ // and FacilityCheckOut#exitSync(). onBeforeTransition(); mWaits = createWaits(); + ConditionWaiter.preCheck(mWaits, mOptions, mTrigger); for (ConditionWait wait : mWaits) { wait.getCondition().onStartMonitoring(); }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/FacilityCheckOut.java b/base/test/android/javatests/src/org/chromium/base/test/transit/FacilityCheckOut.java index 1d98702..5bdad12 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/FacilityCheckOut.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/FacilityCheckOut.java
@@ -38,6 +38,7 @@ // and FacilityCheckOut#exitSync(). onBeforeTransition(); mWaits = createWaits(); + ConditionWaiter.preCheck(mWaits, mOptions, mTrigger); for (ConditionWait wait : mWaits) { wait.getCondition().onStartMonitoring(); }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/Transition.java b/base/test/android/javatests/src/org/chromium/base/test/transit/Transition.java index b44464b0..b0396fb2 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/Transition.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/Transition.java
@@ -22,7 +22,7 @@ } protected final TransitionOptions mOptions; - @Nullable private final Trigger mTrigger; + @Nullable protected final Trigger mTrigger; Transition(TransitionOptions options, @Nullable Trigger trigger) { mOptions = options; @@ -91,6 +91,7 @@ @Nullable List<Condition> mTransitionConditions; long mTimeoutMs; int mTries = 1; + boolean mPossiblyAlreadyFulfilled; private TransitionOptions() {} @@ -128,6 +129,12 @@ mTries = 2; return this; } + + /** The Transition's Conditions might already be all fulfilled before the Trigger. */ + public Builder withPossiblyAlreadyFulfilled() { + mPossiblyAlreadyFulfilled = true; + return this; + } } } }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/Trip.java b/base/test/android/javatests/src/org/chromium/base/test/transit/Trip.java index fb53d78..5382f88 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/Trip.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/Trip.java
@@ -106,6 +106,7 @@ mDestination.setStateTransitioningTo(); mWaits = calculateConditionWaits(mOrigin, mDestination, getTransitionConditions()); + ConditionWaiter.preCheck(mWaits, mOptions, mTrigger); for (ConditionWait wait : mWaits) { wait.getCondition().onStartMonitoring(); }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewConditions.java b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewConditions.java index 4a32e0b..c7d414b 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewConditions.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewConditions.java
@@ -12,7 +12,6 @@ import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.any; -import android.content.res.Resources; import android.view.View; import androidx.test.espresso.AmbiguousViewMatcherException; @@ -21,7 +20,6 @@ import androidx.test.espresso.UiController; import androidx.test.espresso.ViewAction; import androidx.test.espresso.ViewInteraction; -import androidx.test.platform.app.InstrumentationRegistry; import org.hamcrest.Matcher; import org.hamcrest.StringDescription; @@ -29,18 +27,8 @@ import org.chromium.base.ApplicationStatus; import org.chromium.base.test.util.RawFailureHandler; -import java.util.ArrayList; -import java.util.regex.Pattern; - /** {@link Condition}s related to Android {@link View}s. */ public class ViewConditions { - /** Fulfilled when a single matching View exists and is displayed. */ - public static class DisplayedCondition extends ExistsCondition { - public DisplayedCondition(Matcher<View> matcher, ExistsCondition.Options options) { - super(allOf(matcher, isDisplayingAtLeast(ViewElement.MIN_DISPLAYED_PERCENT)), options); - } - } - /** * Fulfilled when a single matching View exists and is displayed, but ignored if |gate| returns * true. @@ -51,7 +39,7 @@ private final Condition mGate; public GatedDisplayedCondition( - Matcher<View> matcher, Condition gate, ExistsCondition.Options options) { + Matcher<View> matcher, Condition gate, DisplayedCondition.Options options) { super(); mDisplayedCondition = new DisplayedCondition(matcher, options); mGate = gate; @@ -81,21 +69,27 @@ } } - /** Fulfilled when a single matching View exists. */ - public static class ExistsCondition extends InstrumentationThreadCondition { + /** Fulfilled when a single matching View exists and is displayed. */ + public static class DisplayedCondition extends InstrumentationThreadCondition { private final Matcher<View> mMatcher; private final Options mOptions; private View mViewMatched; - public ExistsCondition(Matcher<View> matcher, Options options) { + private static final String VERBOSE_DESCRIPTION = + "(view has effective visibility <VISIBLE> and view.getGlobalVisibleRect() covers at" + + " least <90> percent of the view's area)"; + private static final String SUCCINCT_DESCRIPTION = "(getGlobalVisibleRect() > 90%)"; + + public DisplayedCondition(Matcher<View> matcher, Options options) { super(); - mMatcher = matcher; + mMatcher = allOf(matcher, isDisplayingAtLeast(ViewElement.MIN_DISPLAYED_PERCENT)); mOptions = options; } @Override public String buildDescription() { - return "View: " + ViewConditions.createMatcherDescription(mMatcher); + return "View: " + + createMatcherDescription(mMatcher, VERBOSE_DESCRIPTION, SUCCINCT_DESCRIPTION); } @Override @@ -162,7 +156,7 @@ return new Options().new Builder(); } - /** Extra options for declaring ExistsCondition. */ + /** Extra options for declaring DisplayedCondition. */ public static class Options { boolean mExpectEnabled = true; @@ -186,6 +180,11 @@ public static class NotDisplayedAnymoreCondition extends InstrumentationThreadCondition { private final Matcher<View> mMatcher; + private static final String VERBOSE_DESCRIPTION = + "(view has effective visibility <VISIBLE> and view.getGlobalVisibleRect() to return" + + " non-empty rectangle)"; + private static final String SUCCINCT_DESCRIPTION = "(getGlobalVisibleRect() > 0%)"; + public NotDisplayedAnymoreCondition(Matcher<View> matcher) { super(); mMatcher = allOf(matcher, isDisplayed()); @@ -193,7 +192,8 @@ @Override public String buildDescription() { - return "No more view: " + ViewConditions.createMatcherDescription(mMatcher); + return "No more view: " + + createMatcherDescription(mMatcher, VERBOSE_DESCRIPTION, SUCCINCT_DESCRIPTION); } @Override @@ -213,53 +213,12 @@ } } - private static String getResourceName(int resId) { - return InstrumentationRegistry.getInstrumentation() - .getContext() - .getResources() - .getResourceName(resId); - } - - /** Generates a description for the matcher that replaces raw ids with resource names. */ - private static String createMatcherDescription(Matcher<View> matcher) { + /** Returns a less verbose view matcher description. */ + private static String createMatcherDescription( + Matcher<View> matcher, String verboseString, String succinctString) { StringDescription d = new StringDescription(); matcher.describeTo(d); String description = d.toString(); - Pattern numberPattern = Pattern.compile("[0-9]+"); - java.util.regex.Matcher numberMatcher = numberPattern.matcher(description); - ArrayList<Integer> starts = new ArrayList<>(); - ArrayList<Integer> ends = new ArrayList<>(); - ArrayList<String> resourceNames = new ArrayList<>(); - while (numberMatcher.find()) { - int resourceId = Integer.parseInt(numberMatcher.group()); - if (resourceId > 0xFFFFFF) { - // Build-time Android resources have ids > 0xFFFFFF - starts.add(numberMatcher.start()); - ends.add(numberMatcher.end()); - String resourceDescription = createResourceDescription(resourceId); - resourceNames.add(resourceDescription); - } else { - resourceNames.add(numberMatcher.group()); - } - } - - if (starts.size() == 0) return description; - - String newDescription = description.substring(0, starts.get(0)); - for (int i = 0; i < starts.size(); i++) { - newDescription += resourceNames.get(i); - int nextStart = (i == starts.size() - 1) ? description.length() : starts.get(i + 1); - newDescription += description.substring(ends.get(i), nextStart); - } - - return newDescription; - } - - private static String createResourceDescription(int possibleResourceId) { - try { - return getResourceName(possibleResourceId); - } catch (Resources.NotFoundException e) { - return String.valueOf(possibleResourceId); - } + return description.replace(verboseString, succinctString); } }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElementInState.java b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElementInState.java index 5aa9693..02a9192 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElementInState.java +++ b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElementInState.java
@@ -11,7 +11,6 @@ import org.hamcrest.Matcher; import org.chromium.base.test.transit.ViewConditions.DisplayedCondition; -import org.chromium.base.test.transit.ViewConditions.ExistsCondition; import org.chromium.base.test.transit.ViewConditions.GatedDisplayedCondition; import org.chromium.base.test.transit.ViewConditions.NotDisplayedAnymoreCondition; import org.chromium.base.test.transit.ViewElement.Scope; @@ -40,8 +39,8 @@ mGate = gate; Matcher<View> viewMatcher = mViewElement.getViewMatcher(); - ExistsCondition.Options conditionOptions = - ExistsCondition.newOptions() + DisplayedCondition.Options conditionOptions = + DisplayedCondition.newOptions() .withExpectEnabled(mViewElement.getOptions().mExpectEnabled) .build(); if (mGate != null) {
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java b/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java index dfe6045..e9b93124 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java +++ b/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java
@@ -9,17 +9,12 @@ import org.junit.Assert; import org.junit.Rule; -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; import org.chromium.base.ActivityState; import org.chromium.base.ApplicationStatus; import org.chromium.base.CommandLine; import org.chromium.base.CommandLineInitUtil; import org.chromium.base.Log; -import org.chromium.base.test.BaseJUnit4ClassRunner.ClassHook; -import org.chromium.base.test.BaseJUnit4ClassRunner.TestHook; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; @@ -286,50 +281,7 @@ return Arrays.asList(value.split(",")); } - private CommandLineFlags() { - throw new AssertionError("CommandLineFlags is a non-instantiable class"); - } - - private static class CommandLineFlagsTestRule implements TestRule { - @Override - public Statement apply(final Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - try { - Class<?> clazz = description.getTestClass(); - CommandLineFlags.setUpClass(clazz); - CommandLineFlags.setUpMethod(clazz.getMethod(description.getMethodName())); - - base.evaluate(); - } finally { - CommandLineFlags.tearDownMethod(); - CommandLineFlags.tearDownClass(); - } - } - }; - } - } - - public static TestRule getTestRule() { - return new CommandLineFlagsTestRule(); - } - - public static TestHook getPreTestHook() { - return (targetContext, testMethod) -> CommandLineFlags.setUpMethod(testMethod.getMethod()); - } - - public static ClassHook getPreClassHook() { - return (targetContext, testClass) -> CommandLineFlags.setUpClass(testClass); - } - - public static TestHook getPostTestHook() { - return (targetContext, testMethod) -> CommandLineFlags.tearDownMethod(); - } - - public static ClassHook getPostClassHook() { - return (targetContext, testClass) -> CommandLineFlags.tearDownClass(); - } + private CommandLineFlags() {} public static String getTestCmdLineFile() { return "test-cmdline-file";
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn index c45cffe..c613687 100644 --- a/build/config/sanitizers/BUILD.gn +++ b/build/config/sanitizers/BUILD.gn
@@ -14,6 +14,13 @@ import("//build/config/ios/ios_sdk.gni") } +# libfuzzer can't cope with shared objects being unloaded, which sometimes +# occurs for large fuzzers that involve our graphics stack. Shim out dlclose +# so that this doesn't occur. At the moment we've only implemented this on Linux +# since that's the only platform we use these large fuzzers - in the future +# we could choose to do the same on Windows. +use_dlcloseshim = use_libfuzzer && is_linux + # Contains the dependencies needed for sanitizers to link into executables and # shared_libraries. group("deps") { @@ -63,6 +70,9 @@ # .o files which depend on them. deps += [ "//third_party/fuzztest:centipede_weak_sancov_stubs" ] } + if (use_dlcloseshim) { + deps += [ ":dlclose_shim" ] + } } assert(!(is_win && is_asan && current_cpu == "x86"), @@ -170,6 +180,10 @@ } } +source_set("dlclose_shim") { + sources = [ "//build/sanitizers/dlcloseshim.c" ] +} + # Applies linker flags necessary when either :deps or :default_sanitizer_flags # are used. config("default_sanitizer_ldflags") { @@ -269,6 +283,9 @@ ldflags = [ "/INCREMENTAL:NO" ] } } + if (use_dlcloseshim) { + ldflags += [ "-Wl,-wrap,dlclose" ] + } } config("common_sanitizer_flags") {
diff --git a/build/fuchsia/test/isolate_daemon.py b/build/fuchsia/test/isolate_daemon.py index 154819e7..ea39564 100755 --- a/build/fuchsia/test/isolate_daemon.py +++ b/build/fuchsia/test/isolate_daemon.py
@@ -28,7 +28,9 @@ return self def __exit__(self, exc_type, exc_value, traceback): - return self._temp_dir.__exit__(exc_type, exc_value, traceback) + self._temp_dir.__exit__(exc_type, exc_value, traceback) + # Ignore the errors when cleaning up the temporary folder. + return True def name(self): """Returns the location of the isolate dir."""
diff --git a/build/sanitizers/dlcloseshim.c b/build/sanitizers/dlcloseshim.c new file mode 100644 index 0000000..53e2aca5 --- /dev/null +++ b/build/sanitizers/dlcloseshim.c
@@ -0,0 +1,13 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// In due course we may need to replicate more of the complexity from +// base/allocator/partition_allocator/src/partition_alloc/ +// shim/allocator_shim_internals.h +// but as we're targeting just libfuzzer Linux builds, perhaps we don't need +// it. + +__attribute__((visibility("default"), noinline)) void __wrap_dlclose(void *handle) { + // Do nothing. We don't want to call the real dlclose on libfuzzer builds. +}
diff --git a/cc/paint/paint_op.h b/cc/paint/paint_op.h index 0712368..44b1cdd 100644 --- a/cc/paint/paint_op.h +++ b/cc/paint/paint_op.h
@@ -722,10 +722,7 @@ const PaintFlags* flags, SkCanvas* canvas, const PlaybackParams& params); - bool IsValid() const { - // Reproduce SkRRect::isValid without converting. - return flags.IsValid() && oval.isFinite() && oval.isSorted(); - } + bool IsValid() const { return flags.IsValid() && oval.isFinite(); } bool EqualsForTesting(const DrawOvalOp& other) const; HAS_SERIALIZATION_FUNCTIONS();
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc index 7aaf705..0567c5d 100644 --- a/cc/paint/paint_op_buffer_unittest.cc +++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -1587,7 +1587,8 @@ } void PushDrawArcOps(PaintOpBuffer* buffer) { - size_t len = std::min(test_angles.size() / 2, test_flags.size()); + size_t len = + std::min({test_rects.size(), test_angles.size() / 2, test_flags.size()}); for (size_t i = 0; i < len; ++i) { buffer->push<DrawArcOp>(test_rects[i], test_angles[2 * i], test_angles[2 * i + 1], test_flags[i]); @@ -1596,7 +1597,8 @@ } void PushDrawArcLiteOps(PaintOpBuffer* buffer) { - size_t len = std::min(test_angles.size() / 2, test_flags.size()); + size_t len = + std::min({test_rects.size(), test_angles.size() / 2, test_flags.size()}); for (size_t i = 0; i < len; ++i) { if (test_flags[i].CanConvertToCorePaintFlags()) { buffer->push<DrawArcLiteOp>(test_rects[i], test_angles[2 * i], @@ -1611,7 +1613,7 @@ } void PushDrawOvalOps(PaintOpBuffer* buffer) { - size_t len = std::min(test_paths.size(), test_flags.size()); + size_t len = std::min(test_rects.size(), test_flags.size()); for (size_t i = 0; i < len; ++i) buffer->push<DrawOvalOp>(test_rects[i], test_flags[i]); EXPECT_THAT(*buffer, Each(PaintOpIs<DrawOvalOp>()));
diff --git a/cc/test/paint_op_helper.h b/cc/test/paint_op_helper.h index 9e9ee26..4564d9e 100644 --- a/cc/test/paint_op_helper.h +++ b/cc/test/paint_op_helper.h
@@ -142,23 +142,23 @@ const auto& op = static_cast<const DrawLineLiteOp&>(base_op); str << "x0=" << ToString(op.x0) << ", y0=" << ToString(op.y0) << ", x1=" << ToString(op.x1) << ", y1=" << ToString(op.y1) - << ", flags=" << ToString(op.core_paint_flags) << ")"; + << ", flags=" << ToString(op.core_paint_flags); break; } case PaintOpType::kDrawArc: { const auto& op = static_cast<const DrawArcOp&>(base_op); - str << "DrawArcOp(oval=" << ToString(op.oval) + str << "oval=" << ToString(op.oval) << ", start_angle=" << ToString(op.start_angle_degrees) << ", sweep_angle=" << ToString(op.sweep_angle_degrees) - << ", flags=" << ToString(op.flags) << ")"; + << ", flags=" << ToString(op.flags); break; } case PaintOpType::kDrawArcLite: { const auto& op = static_cast<const DrawArcLiteOp&>(base_op); - str << "DrawArcOp(oval=" << ToString(op.oval) + str << "oval=" << ToString(op.oval) << ", start_angle=" << ToString(op.start_angle_degrees) << ", sweep_angle=" << ToString(op.sweep_angle_degrees) - << ", flags=" << ToString(op.core_paint_flags) << ")"; + << ", flags=" << ToString(op.core_paint_flags); break; } case PaintOpType::kDrawOval: {
diff --git a/chrome/VERSION b/chrome/VERSION index 0ee0de0..8e0a020 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=127 MINOR=0 -BUILD=6483 +BUILD=6484 PATCH=0
diff --git a/chrome/android/expectations/monochrome_64_32_public_bundle.proguard_flags.expected b/chrome/android/expectations/monochrome_64_32_public_bundle.proguard_flags.expected index 55ec3130..a0d43843 100644 --- a/chrome/android/expectations/monochrome_64_32_public_bundle.proguard_flags.expected +++ b/chrome/android/expectations/monochrome_64_32_public_bundle.proguard_flags.expected
@@ -960,14 +960,6 @@ # Chromium code. They MUST be scoped appropriately to avoid side effects on app # code that we do not own. -# Use assumevalues block instead of assumenosideeffects block because Google3 -# proguard cannot parse assumenosideeffects blocks which overwrite return -# value. Keep this in shared_with_cronet.flags rather than remove_logging.flags -# so that it's included in cronet. --assumevalues class org.chromium.base.Log { - static boolean isDebug() return false; -} - # Keep all CREATOR fields within Parcelable that are kept. -keepclassmembers class !cr_allowunused,org.chromium.** implements android.os.Parcelable { public static *** CREATOR;
diff --git a/chrome/android/features/start_surface/java/res/values/dimens.xml b/chrome/android/features/start_surface/java/res/values/dimens.xml index 38d0539..0a031816 100644 --- a/chrome/android/features/start_surface/java/res/values/dimens.xml +++ b/chrome/android/features/start_surface/java/res/values/dimens.xml
@@ -5,7 +5,6 @@ found in the LICENSE file. --> <resources xmlns:tools="http://schemas.android.com/tools"> - <dimen name="tasks_surface_body_top_margin">24dp</dimen> <dimen name="mv_tiles_container_top_margin">17dp</dimen> <!-- Surface Polish -->
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceHomeLayout.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceHomeLayout.java index bf11faf..1f98557 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceHomeLayout.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceHomeLayout.java
@@ -15,8 +15,6 @@ import org.chromium.chrome.browser.compositor.layouts.LayoutRenderHost; import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost; import org.chromium.chrome.browser.compositor.scene_layer.SolidColorSceneLayer; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.hub.HubFieldTrial; import org.chromium.chrome.browser.layouts.EventFilter; import org.chromium.chrome.browser.layouts.LayoutType; import org.chromium.chrome.browser.layouts.scene_layer.SceneLayer; @@ -24,7 +22,6 @@ import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.features.tasks.TasksView; import org.chromium.components.browser_ui.styles.ChromeColors; -import org.chromium.components.browser_ui.styles.SemanticColorUtils; /** A {@link Layout} that shows Start Surface home view. */ public class StartSurfaceHomeLayout extends Layout { @@ -172,24 +169,15 @@ private void ensureSceneLayerCreated() { if (mSceneLayer != null) return; - boolean isSurfacePolishEnabled = ChromeFeatureList.sSurfacePolish.isEnabled(); - if (isSurfacePolishEnabled || HubFieldTrial.isHubEnabled()) { - SolidColorSceneLayer sceneLayer = new SolidColorSceneLayer(); - Context context = getContext(); - @ColorInt int color; - if (isSurfacePolishEnabled) { - color = - ChromeColors.getSurfaceColor( - context, R.dimen.home_surface_background_color_elevation); - } else { - color = SemanticColorUtils.getDefaultBgColor(context); - } - sceneLayer.setBackgroundColor(color); + SolidColorSceneLayer sceneLayer = new SolidColorSceneLayer(); + Context context = getContext(); + @ColorInt int color; + color = + ChromeColors.getSurfaceColor( + context, R.dimen.home_surface_background_color_elevation); + sceneLayer.setBackgroundColor(color); - mSceneLayer = sceneLayer; - } else { - mSceneLayer = new SceneLayer(); - } + mSceneLayer = sceneLayer; } private void onTabSelecting(int tabId) {
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java index cd8e2d3..466961f 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -26,7 +26,6 @@ import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_CONTAINER_TOP_MARGIN; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.RESET_TASK_SURFACE_HEADER_SCROLL_POSITION; -import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TASKS_SURFACE_BODY_TOP_MARGIN; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TOP_TOOLBAR_PLACEHOLDER_HEIGHT; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.VOICE_SEARCH_BUTTON_CLICK_LISTENER; @@ -1210,10 +1209,6 @@ if (mIsSurfacePolishEnabled) return; Resources resources = mContext.getResources(); - mPropertyModel.set( - TASKS_SURFACE_BODY_TOP_MARGIN, - resources.getDimensionPixelSize(R.dimen.tasks_surface_body_top_margin)); - // TODO(crbug.com/40221888): Clean up this code when the refactor is enabled. mPropertyModel.set( MV_TILES_CONTAINER_TOP_MARGIN, @@ -1341,13 +1336,13 @@ } /** - * Update the background color of the start surface based on whether it is polished or not , - * in the incognito mode or non-incognito mode. + * Update the background color of the start surface based on whether it is polished or not , in + * the incognito mode or non-incognito mode. */ @VisibleForTesting void updateBackgroundColor(PropertyModel propertyModel) { @ColorInt int surfaceBackgroundColor; - if (mIsSurfacePolishEnabled && !mIsIncognito) { + if (!mIsIncognito) { surfaceBackgroundColor = ChromeColors.getSurfaceColor( mContext, R.dimen.home_surface_background_color_elevation);
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceProperties.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceProperties.java index 1dd03fd9..b11b729 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceProperties.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceProperties.java
@@ -64,8 +64,6 @@ new PropertyModel.WritableBooleanPropertyKey(); public static final PropertyModel.WritableObjectPropertyKey<View.OnClickListener> VOICE_SEARCH_BUTTON_CLICK_LISTENER = new PropertyModel.WritableObjectPropertyKey<>(); - public static final PropertyModel.WritableIntPropertyKey TASKS_SURFACE_BODY_TOP_MARGIN = - new PropertyModel.WritableIntPropertyKey(); public static final PropertyModel.WritableIntPropertyKey MV_TILES_CONTAINER_TOP_MARGIN = new PropertyModel.WritableIntPropertyKey(); public static final PropertyModel.WritableIntPropertyKey TOP_TOOLBAR_PLACEHOLDER_HEIGHT = @@ -99,7 +97,6 @@ QUERY_TILES_VISIBLE, MAGIC_STACK_VISIBLE, VOICE_SEARCH_BUTTON_CLICK_LISTENER, - TASKS_SURFACE_BODY_TOP_MARGIN, MV_TILES_CONTAINER_TOP_MARGIN, RESET_TASK_SURFACE_HEADER_SCROLL_POSITION, TOP_TOOLBAR_PLACEHOLDER_HEIGHT,
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java index 48dc64d..e4f7bb13 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java
@@ -308,16 +308,8 @@ } /** - * Set the top margin for the tasks surface body. - * @param topMargin The top margin to set. - */ - void setTasksSurfaceBodyTopMargin(int topMargin) { - MarginLayoutParams params = (MarginLayoutParams) getBodyViewContainer().getLayoutParams(); - params.topMargin = topMargin; - } - - /** * Set the top margin for the mv tiles container. + * * @param topMargin The top margin to set. */ void setMVTilesContainerTopMargin(int topMargin) {
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java index 035c702..5026985 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java
@@ -27,7 +27,6 @@ import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.QUERY_TILES_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.RESET_TASK_SURFACE_HEADER_SCROLL_POSITION; -import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TASKS_SURFACE_BODY_TOP_MARGIN; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TOP_TOOLBAR_PLACEHOLDER_HEIGHT; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.VOICE_SEARCH_BUTTON_CLICK_LISTENER; @@ -99,8 +98,6 @@ view.getSearchBoxCoordinator() .addVoiceSearchButtonClickListener( model.get(VOICE_SEARCH_BUTTON_CLICK_LISTENER)); - } else if (propertyKey == TASKS_SURFACE_BODY_TOP_MARGIN) { - view.setTasksSurfaceBodyTopMargin(model.get(TASKS_SURFACE_BODY_TOP_MARGIN)); } else if (propertyKey == MV_TILES_CONTAINER_TOP_MARGIN) { view.setMVTilesContainerTopMargin(model.get(MV_TILES_CONTAINER_TOP_MARGIN)); } else if (propertyKey == RESET_TASK_SURFACE_HEADER_SCROLL_POSITION) {
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java index c26b6cf..1606692f 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java
@@ -62,7 +62,6 @@ import org.chromium.chrome.browser.layouts.LayoutTestUtils; import org.chromium.chrome.browser.layouts.LayoutType; import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper; import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; @@ -210,8 +209,6 @@ TabUiTestHelper.finishActivity(mActivityTestRule.getActivity()); StartSurfaceTestUtils.createThumbnailBitmapAndWriteToFile(0, mBrowserControlsStateProvider); StartSurfaceTestUtils.createThumbnailBitmapAndWriteToFile(1, mBrowserControlsStateProvider); - TabAttributeCache.setRootIdForTesting(0, 0); - TabAttributeCache.setRootIdForTesting(1, 0); StartSurfaceTestUtils.createTabStatesAndMetadataFile(new int[] {0, 1}); // Restart and open tab grid dialog.
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java index 58a7617..99862bc 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java
@@ -71,8 +71,6 @@ import org.chromium.chrome.browser.tabpersistence.TabStateDirectory; import org.chromium.chrome.browser.tabpersistence.TabStateFileManager; import org.chromium.chrome.browser.tasks.ReturnToChromeUtil; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; -import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache; import org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper; import org.chromium.chrome.browser.toolbar.top.ToolbarPhone; import org.chromium.chrome.test.ChromeActivityTestRule; @@ -225,7 +223,6 @@ // Creating tabs and restart the activity would do the trick, but we cannot do that for // Instant start because we cannot unload native library. // Create fake TabState files to emulate having one tab in previous session. - TabAttributeCache.setTitleForTesting(0, "tab title"); startMainActivityFromLauncher(activityTestRule); } else { assertFalse(ReturnToChromeUtil.shouldShowTabSwitcher(-1, false)); @@ -355,23 +352,40 @@ * @param tabIds all the Tab IDs in the normal tab model. */ public static void createTabStatesAndMetadataFile(int[] tabIds) throws IOException { - createTabStatesAndMetadataFile(tabIds, null, 0); + createTabStatesAndMetadataFile(tabIds, null, null, 0); } /** * Create all the files so that tab models can be restored. * * @param tabIds all the Tab IDs in the normal tab model. + * @param rootIds all the root IDs in the normal tab model. + */ + public static void createTabStatesAndMetadataFile(int[] tabIds, @Nullable int[] rootIds) + throws IOException { + createTabStatesAndMetadataFile(tabIds, rootIds, null, 0); + } + + /** + * Create all the files so that tab models can be restored. + * + * @param tabIds all the Tab IDs in the normal tab model. + * @param rootIds all the root IDs in the normal tab model. * @param urls all of the URLs in the normal tab model. * @param selectedIndex the selected index of normal tab model. */ public static void createTabStatesAndMetadataFile( - int[] tabIds, @Nullable String[] urls, int selectedIndex) throws IOException { - createTabStatesAndMetadataFile(tabIds, urls, selectedIndex, true); + int[] tabIds, @Nullable int[] rootIds, @Nullable String[] urls, int selectedIndex) + throws IOException { + createTabStatesAndMetadataFile(tabIds, rootIds, urls, selectedIndex, true); } private static void createTabStatesAndMetadataFile( - int[] tabIds, @Nullable String[] urls, int selectedIndex, boolean createStateFile) + int[] tabIds, + int[] rootIds, + @Nullable String[] urls, + int selectedIndex, + boolean createStateFile) throws IOException { TabPersistentStore.TabModelMetadata normalInfo = new TabPersistentStore.TabModelMetadata(selectedIndex); @@ -381,7 +395,8 @@ normalInfo.urls.add(url); if (createStateFile) { - saveTabState(tabIds[i], false); + int rootId = rootIds == null ? tabIds[i] : rootIds[i]; + saveTabState(tabIds[i], rootId, false); } } TabPersistentStore.TabModelMetadata incognitoInfo = @@ -407,11 +422,12 @@ */ public static void prepareTabStateMetadataFile( int[] tabIds, @Nullable String[] urls, int selectedIndex) throws IOException { - createTabStatesAndMetadataFile(tabIds, urls, selectedIndex, false); + createTabStatesAndMetadataFile(tabIds, null, urls, selectedIndex, false); } /** * Create thumbnail bitmap of the tab based on the given id and write it to file. + * * @param tabId The id of the target tab. * @param browserControlsStateProvider For getting the top offset. * @return The bitmap created. @@ -690,10 +706,12 @@ /** * Create a file so that a TabState can be restored later. + * * @param tabId the Tab ID + * @param tabId the Root ID * @param encrypted for Incognito mode */ - private static void saveTabState(int tabId, boolean encrypted) { + private static void saveTabState(int tabId, int rootId, boolean encrypted) { File file = TabStateFileManager.getTabStateFile( TabStateDirectory.getOrCreateTabbedModeStateDirectory(), @@ -703,7 +721,7 @@ writeFile(file, M26_GOOGLE_COM.encodedTabState); TabState tabState = TabStateFileManager.restoreTabStateInternal(file, false); - tabState.rootId = PseudoTab.fromTabId(tabId).getRootId(); + tabState.rootId = rootId; TabStateFileManager.saveStateInternal(file, tabState, encrypted); }
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java index 120bb1e..72d3685 100644 --- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java +++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
@@ -44,7 +44,6 @@ import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_VOICE_RECOGNITION_BUTTON_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_CONTAINER_TOP_MARGIN; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_VISIBLE; -import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TASKS_SURFACE_BODY_TOP_MARGIN; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.VOICE_SEARCH_BUTTON_CLICK_LISTENER; import android.app.Activity; @@ -812,14 +811,8 @@ @Test public void initializeStartSurfaceTopMargins() { - int tasksSurfaceBodyTopMargin = 0; - createStartSurfaceMediatorWithoutInit( - /* hadWarmStart= */ false, /* useMagicStack= */ false); - assertThat( - mPropertyModel.get(TASKS_SURFACE_BODY_TOP_MARGIN), - equalTo(tasksSurfaceBodyTopMargin)); assertThat(mPropertyModel.get(MV_TILES_CONTAINER_TOP_MARGIN), equalTo(0)); }
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/TasksViewBinderUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/TasksViewBinderUnitTest.java index 30e5eb2..7c661cfe 100644 --- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/TasksViewBinderUnitTest.java +++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/TasksViewBinderUnitTest.java
@@ -25,7 +25,6 @@ import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MAGIC_STACK_VISIBLE; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_CONTAINER_TOP_MARGIN; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_VISIBLE; -import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TASKS_SURFACE_BODY_TOP_MARGIN; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TOP_TOOLBAR_PLACEHOLDER_HEIGHT; import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.VOICE_SEARCH_BUTTON_CLICK_LISTENER; @@ -292,18 +291,6 @@ @Test @SmallTest - public void testSetTasksSurfaceBodyTopMargin() { - ViewGroup.MarginLayoutParams params = - (ViewGroup.MarginLayoutParams) mTasksView.getBodyViewContainer().getLayoutParams(); - assertEquals(0, params.topMargin); - - mTasksViewPropertyModel.set(TASKS_SURFACE_BODY_TOP_MARGIN, 16); - - assertEquals(16, params.topMargin); - } - - @Test - @SmallTest public void testSetMVTilesContainerTopMargin() { ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java deleted file mode 100644 index 795a888..0000000 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java +++ /dev/null
@@ -1,324 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.tasks.pseudotab; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.chromium.base.Token; -import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.browser.tabmodel.TabList; -import org.chromium.chrome.browser.tabmodel.TabModelFilter; -import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider; -import org.chromium.chrome.browser.tabmodel.TabModelSelector; -import org.chromium.url.GURL; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import javax.annotation.concurrent.GuardedBy; - -/** Representation of a Tab-like card in the Grid Tab Switcher. */ -public class PseudoTab { - private static final String TAG = "PseudoTab"; - - private final Integer mTabId; - private final WeakReference<Tab> mTab; - - @GuardedBy("sLock") - private static final Map<Integer, PseudoTab> sAllTabs = new LinkedHashMap<>(); - - private static final Object sLock = new Object(); - - /** An interface to get the title to be used for a tab. */ - public interface TitleProvider { - String getTitle(Context context, PseudoTab tab); - } - - /** Construct from a tab ID. An earlier instance with the same ID can be returned. */ - public static PseudoTab fromTabId(int tabId) { - synchronized (sLock) { - PseudoTab cached = sAllTabs.get(tabId); - if (cached != null) return cached; - return new PseudoTab(tabId); - } - } - - private PseudoTab(int tabId) { - mTabId = tabId; - mTab = null; - sAllTabs.put(getId(), this); - } - - /** - * Construct from a {@link Tab}. An earlier instance with the same {@link Tab} can be returned. - */ - public static PseudoTab fromTab(@NonNull Tab tab) { - synchronized (sLock) { - PseudoTab cached = sAllTabs.get(tab.getId()); - if (cached != null && cached.hasRealTab()) { - if (cached.getTab() == tab) { - return cached; - } else { - assert tab.getWebContents() == null - || cached.getTab().getWebContents() == null - || cached.getTab().getWebContents().getTopLevelNativeWindow() == null; - return new PseudoTab(tab); - } - } - // We need to upgrade a pre-native Tab to a post-native Tab. - return new PseudoTab(tab); - } - } - - private PseudoTab(@NonNull Tab tab) { - mTabId = tab.getId(); - mTab = new WeakReference<>(tab); - sAllTabs.put(getId(), this); - } - - /** - * Convert a list of {@link Tab} to a list of {@link PseudoTab}. - * @param tabs A list of {@link Tab} - * @return A list of {@link PseudoTab} - */ - public static List<PseudoTab> getListOfPseudoTab(@Nullable List<Tab> tabs) { - List<PseudoTab> pseudoTabs = null; - if (tabs != null) { - pseudoTabs = new ArrayList<>(); - for (Tab tab : tabs) { - pseudoTabs.add(fromTab(tab)); - } - } - return pseudoTabs; - } - - /** - * Convert a {@link TabList} to a list of {@link PseudoTab}. - * @param tabList A {@link TabList} - * @return A list of {@link PseudoTab} - */ - public static List<PseudoTab> getListOfPseudoTab(@Nullable TabList tabList) { - List<PseudoTab> pseudoTabs = null; - if (tabList != null) { - pseudoTabs = new ArrayList<>(); - for (int i = 0; i < tabList.getCount(); i++) { - Tab tab = tabList.getTabAt(i); - if (tab != null) { - pseudoTabs.add(fromTab(tab)); - } - } - } - return pseudoTabs; - } - - @Override - public String toString() { - assert mTabId != null; - return "Tab " + mTabId; - } - - /** - * @return The ID of the {@link PseudoTab} - */ - public int getId() { - return mTabId; - } - - /** - * Get the title of the {@link PseudoTab} through a {@link TitleProvider}. - * - * If the {@link TitleProvider} is {@code null}, fall back to {@link #getTitle()}. - * - * @param context The activity context. - * @param titleProvider The {@link TitleProvider} to provide the title. - * @return The title - */ - public String getTitle(Context context, @Nullable TitleProvider titleProvider) { - if (titleProvider != null) return titleProvider.getTitle(context, this); - return getTitle(); - } - - /** - * Get the title of the {@link PseudoTab}. - * @return The title - */ - public String getTitle() { - if (mTab != null && mTab.get() != null && mTab.get().isInitialized()) { - return mTab.get().getTitle(); - } - assert mTabId != null; - return TabAttributeCache.getTitle(mTabId); - } - - /** - * Get the URL of the {@link PseudoTab}. - * @return The URL - */ - public GURL getUrl() { - if (mTab != null && mTab.get() != null && mTab.get().isInitialized()) { - return mTab.get().getUrl(); - } - assert mTabId != null; - return TabAttributeCache.getUrl(mTabId); - } - - /** Whether the tab is closing or destroyed. */ - public boolean isClosingOrDestroyed() { - // The tab is not backed by a real tab, assume it is alive. - if (mTab == null) return false; - - // The tab is backed by a real tab check if it still exists and its state. - Tab tab = mTab.get(); - return tab == null || tab.isClosing() || tab.isDestroyed(); - } - - /** - * Get the root ID of the {@link PseudoTab}. - * @return The root ID - */ - public int getRootId() { - if (mTab != null && mTab.get() != null && mTab.get().isInitialized()) { - return mTab.get().getRootId(); - } - assert mTabId != null; - return TabAttributeCache.getRootId(mTabId); - } - - /** - * Get the tab group ID of the {@link PseudoTab}. - * - * @return The tab group ID - */ - public @Nullable Token getTabGroupId() { - if (mTab != null && mTab.get() != null && mTab.get().isInitialized()) { - return mTab.get().getTabGroupId(); - } - assert mTabId != null; - return TabAttributeCache.getTabGroupId(mTabId); - } - - /** - * @return The timestamp of the {@link PseudoTab}. - */ - public long getTimestampMillis() { - if (mTab != null && mTab.get() != null && mTab.get().isInitialized()) { - return mTab.get().getTimestampMillis(); - } - assert mTabId != null; - return TabAttributeCache.getTimestampMillis(mTabId); - } - - /** - * @return Whether the {@link PseudoTab} is in the Incognito mode. - */ - public boolean isIncognito() { - if (mTab != null && mTab.get() != null) return mTab.get().isIncognito(); - assert mTabId != null; - return false; - } - - /** - * @return Whether an underlying real {@link Tab} is available. - */ - public boolean hasRealTab() { - return getTab() != null; - } - - /** - * Get the underlying real {@link Tab}. We should avoid using this. - * @return The underlying real {@link Tab}. - */ - @Deprecated - public @Nullable Tab getTab() { - if (mTab != null) return mTab.get(); - return null; - } - - /** - * Clear the internal static storage as if the app is restarted. This should/can be called when - * emulating restarting in instrumented tests, or between Robolectric tests. - */ - public static void clearForTesting() { - synchronized (sLock) { - sAllTabs.clear(); - } - } - - /** - * Get related tabs of a certain {@link PseudoTab}, through {@link TabModelFilter}s if - * available. - * - * @param context The activity context. - * @param member The {@link PseudoTab} related to - * @param tabModelSelector The {@link TabModelSelector} to query the tab relation - * @return Related {@link PseudoTab}s - */ - public static @NonNull List<PseudoTab> getRelatedTabs( - Context context, PseudoTab member, @NonNull TabModelSelector tabModelSelector) { - synchronized (sLock) { - List<Tab> relatedTabs = getRelatedTabList(tabModelSelector, member.getId()); - if (relatedTabs != null) return getListOfPseudoTab(relatedTabs); - - List<PseudoTab> related = new ArrayList<>(); - int rootId = member.getRootId(); - if (rootId == Tab.INVALID_TAB_ID) { - related.add(member); - return related; - } - for (Integer key : sAllTabs.keySet()) { - PseudoTab tab = sAllTabs.get(key); - assert tab != null; - if (tab.getRootId() == Tab.INVALID_TAB_ID) continue; - if (tab.getRootId() != rootId) continue; - related.add(tab); - } - assert related.size() > 0; - return related; - } - } - - /** - * Get related tabs of a certain {@link PseudoTab}, through {@link TabModelFilter}s if - * available. - * - * @param context The activity context. - * @param member The {@link PseudoTab} related to - * @param tabModelFilter The {@link TabModelFilter} to query the tab relation - * @return Related {@link PseudoTab}s - */ - public static @NonNull List<PseudoTab> getRelatedTabs( - Context context, PseudoTab member, @NonNull TabModelFilter filter) { - assert filter.isTabModelRestored() : "Trying to get related tabs for uninitialized filter."; - synchronized (sLock) { - List<Tab> relatedTabs = filter.getRelatedTabList(member.getId()); - return getListOfPseudoTab(relatedTabs); - } - } - - private static @Nullable List<Tab> getRelatedTabList( - @NonNull TabModelSelector tabModelSelector, int tabId) { - if (!tabModelSelector.isTabStateInitialized()) { - throw new IllegalStateException(); - } - TabModelFilterProvider provider = tabModelSelector.getTabModelFilterProvider(); - List<Tab> related = provider.getTabModelFilter(false).getRelatedTabList(tabId); - if (related.size() > 0) return related; - related = provider.getTabModelFilter(true).getRelatedTabList(tabId); - assert related.size() > 0; - return related; - } - - static int getAllTabsCountForTests() { - synchronized (sLock) { - return sAllTabs.size(); - } - } -}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCache.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCache.java deleted file mode 100644 index e8891bd6f..0000000 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCache.java +++ /dev/null
@@ -1,442 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.tasks.pseudotab; - -import android.content.Context; -import android.content.SharedPreferences; -import android.text.TextUtils; - -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import org.chromium.base.ContextUtils; -import org.chromium.base.ResettersForTesting; -import org.chromium.base.Token; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory; -import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.browser.tabmodel.TabModelFilter; -import org.chromium.chrome.browser.tabmodel.TabModelObserver; -import org.chromium.chrome.browser.tabmodel.TabModelSelector; -import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; -import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; -import org.chromium.components.search_engines.TemplateUrlService; -import org.chromium.content_public.browser.NavigationController; -import org.chromium.content_public.browser.NavigationHandle; -import org.chromium.content_public.browser.NavigationHistory; -import org.chromium.url.GURL; - -import java.util.Objects; - -/** Cache for attributes of {@link PseudoTab} to be available before native is ready. */ -public class TabAttributeCache { - private static final String PREFERENCES_NAME = "tab_attribute_cache"; - private static final long NO_TAB_GROUP_ID = 0L; - - private static SharedPreferences sPref; - private final TabModelSelector mTabModelSelector; - private final TabModelObserver mTabModelObserver; - private final TabModelSelectorTabObserver mTabModelSelectorTabObserver; - private final TabModelSelectorObserver mTabModelSelectorObserver; - - interface LastSearchTermProvider { - String getLastSearchTerm(Tab tab); - } - - private static LastSearchTermProvider sLastSearchTermProviderForTesting; - - private static SharedPreferences getSharedPreferences() { - if (sPref == null) { - sPref = - ContextUtils.getApplicationContext() - .getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); - ResettersForTesting.register(() -> sPref = null); - } - return sPref; - } - - /** - * Create a TabAttributeCache instance to observe tab attribute changes. - * - * Note that querying tab attributes doesn't rely on having an instance. - * @param tabModelSelector The {@link TabModelSelector} to observe. - */ - public TabAttributeCache(TabModelSelector tabModelSelector) { - // TODO(hanxi): makes TabAttributeCache a singleton. The TabAttributeCache should be - // instantiated and exactly once before it is used. - mTabModelSelector = tabModelSelector; - mTabModelSelectorTabObserver = - new TabModelSelectorTabObserver(mTabModelSelector) { - @Override - public void onUrlUpdated(Tab tab) { - if (tab.isIncognito()) return; - cacheUrl(tab.getId(), tab.getUrl()); - } - - @Override - public void onTitleUpdated(Tab tab) { - if (tab.isIncognito()) return; - String title = tab.getTitle(); - cacheTitle(tab.getId(), title); - } - - @Override - public void onRootIdChanged(Tab tab, int newRootId) { - if (tab.isIncognito()) return; - assert newRootId == tab.getRootId(); - cacheRootId(tab.getId(), newRootId); - } - - @Override - public void onTabGroupIdChanged(Tab tab, @Nullable Token tabGroupId) { - if (tab.isIncognito()) return; - assert Objects.equals(tabGroupId, tab.getTabGroupId()); - cacheTabGroupId(tab.getId(), tabGroupId); - } - - @Override - public void onTimestampChanged(Tab tab, long timestampMillis) { - if (tab.isIncognito()) return; - assert timestampMillis == tab.getTimestampMillis(); - cacheTimestampMillis(tab.getId(), timestampMillis); - } - - @Override - public void onDidFinishNavigationInPrimaryMainFrame( - Tab tab, NavigationHandle navigationHandle) { - if (tab.isIncognito()) return; - if (tab.getWebContents() == null) return; - // TODO(crbug.com/40117193): skip cacheLastSearchTerm() according to - // isValidSearchFormUrl() and PageTransition.GENERATED for optimization. - cacheLastSearchTerm(tab); - } - }; - - mTabModelObserver = - new TabModelObserver() { - @Override - public void tabClosureCommitted(Tab tab) { - int id = tab.getId(); - getSharedPreferences() - .edit() - .remove(getDeprecatedUrlKey(id)) - .remove(getUrlKey(id)) - .remove(getTitleKey(id)) - .remove(getRootIdKey(id)) - .remove(getTabGroupIdHighKey(id)) - .remove(getTabGroupIdLowKey(id)) - .remove(getTimestampMillisKey(id)) - .remove(getLastSearchTermKey(id)) - .apply(); - } - }; - - mTabModelSelectorObserver = - new TabModelSelectorObserver() { - @Override - public void onTabStateInitialized() { - // TODO(wychen): after this cache is enabled by default, we only need to - // populate it - // once. - SharedPreferences.Editor editor = getSharedPreferences().edit(); - editor.clear(); - TabModelFilter filter = - mTabModelSelector - .getTabModelFilterProvider() - .getTabModelFilter(false); - for (int i = 0; i < filter.getCount(); i++) { - Tab tab = filter.getTabAt(i); - int id = tab.getId(); - editor.putString(getUrlKey(id), tab.getUrl().serialize()); - editor.putString(getTitleKey(id), tab.getTitle()); - editor.putInt(getRootIdKey(id), tab.getRootId()); - @Nullable Token tabGroupId = tab.getTabGroupId(); - if (tabGroupId != null) { - editor.putLong(getTabGroupIdHighKey(id), tabGroupId.getHigh()); - editor.putLong(getTabGroupIdLowKey(id), tabGroupId.getLow()); - } - editor.putLong(getTimestampMillisKey(id), tab.getTimestampMillis()); - } - editor.apply(); - Tab currentTab = mTabModelSelector.getCurrentTab(); - if (currentTab != null) cacheLastSearchTerm(currentTab); - filter.addObserver(mTabModelObserver); - } - }; - mTabModelSelector.addObserver(mTabModelSelectorObserver); - } - - private static String getTitleKey(int id) { - return id + "_title"; - } - - /** - * Get the title of a {@link PseudoTab}. - * @param id The ID of the {@link PseudoTab}. - * @return The title - */ - public static String getTitle(int id) { - return getSharedPreferences().getString(getTitleKey(id), ""); - } - - private static void cacheTitle(int id, String title) { - getSharedPreferences().edit().putString(getTitleKey(id), title).apply(); - } - - /** - * Set the title of a {@link PseudoTab}. Only for testing. - * @param id The ID of the {@link PseudoTab}. - * @param title The title - */ - public static void setTitleForTesting(int id, String title) { - cacheTitle(id, title); - } - - private static String getUrlKey(int id) { - return id + "_gurl"; - } - - // Legacy from when URL was serialized as raw string. - private static String getDeprecatedUrlKey(int id) { - return id + "_url"; - } - - /** - * Get the URL of a {@link PseudoTab}. - * @param id The ID of the {@link PseudoTab}. - * @return The URL - */ - public static GURL getUrl(int id) { - String url = getSharedPreferences().getString(getUrlKey(id), ""); - if (!url.isEmpty()) { - return GURL.deserialize(url); - } - return new GURL(getSharedPreferences().getString(getDeprecatedUrlKey(id), "")); - } - - private static void cacheUrl(int id, GURL url) { - getSharedPreferences().edit().putString(getUrlKey(id), url.serialize()).apply(); - } - - /** - * Set the URL of a {@link PseudoTab}. - * @param id The ID of the {@link PseudoTab}. - * @param url The URL - */ - static void setUrlForTesting(int id, GURL url) { - cacheUrl(id, url); - } - - private static String getRootIdKey(int id) { - return id + "_rootID"; - } - - /** - * Get the root ID of a {@link PseudoTab}. - * @param id The ID of the {@link PseudoTab}. - * @return The root ID - */ - public static int getRootId(int id) { - return getSharedPreferences().getInt(getRootIdKey(id), Tab.INVALID_TAB_ID); - } - - private static void cacheRootId(int id, int rootId) { - getSharedPreferences().edit().putInt(getRootIdKey(id), rootId).apply(); - } - - private static String getTabGroupIdHighKey(int id) { - return id + "_tabGroupIDHigh"; - } - - private static String getTabGroupIdLowKey(int id) { - return id + "_tabGroupIDLow"; - } - - /** - * Get the tab group ID of a {@link PseudoTab}. - * - * @param id The ID of the {@link PseudoTab}. - * @return The tab group ID - */ - public static @Nullable Token getTabGroupId(int id) { - var sharedPrefs = getSharedPreferences(); - long high = sharedPrefs.getLong(getTabGroupIdHighKey(id), NO_TAB_GROUP_ID); - long low = sharedPrefs.getLong(getTabGroupIdLowKey(id), NO_TAB_GROUP_ID); - Token tabGroupId = new Token(high, low); - return tabGroupId.isZero() ? null : tabGroupId; - } - - private static void cacheTabGroupId(int id, @Nullable Token tabGroupId) { - var sharedPrefs = getSharedPreferences(); - if (tabGroupId == null) { - sharedPrefs - .edit() - .remove(getTabGroupIdHighKey(id)) - .remove(getTabGroupIdLowKey(id)) - .apply(); - } else { - sharedPrefs - .edit() - .putLong(getTabGroupIdHighKey(id), tabGroupId.getHigh()) - .putLong(getTabGroupIdLowKey(id), tabGroupId.getLow()) - .apply(); - } - } - - /** - * Set the root ID for a {@link PseudoTab}. - * @param id The ID of the {@link PseudoTab}. - * @param rootId The root ID - */ - public static void setRootIdForTesting(int id, int rootId) { - cacheRootId(id, rootId); - } - - /** - * Set the tab group ID for a {@link PseudoTab}. - * - * @param id The ID of the {@link PseudoTab}. - * @param tabGroupId The tab group ID - */ - public static void setTabGroupIdForTesting(int id, @Nullable Token tabGroupId) { - cacheTabGroupId(id, tabGroupId); - } - - private static String getTimestampMillisKey(int id) { - return id + "_timestampMillis"; - } - - /** - * Get the timestamp of a {@link PseudoTab}. - * @param id The ID of the {@link PseudoTab}. - * @return The timestamp - */ - public static long getTimestampMillis(int id) { - return getSharedPreferences().getLong(getTimestampMillisKey(id), Tab.INVALID_TIMESTAMP); - } - - private static void cacheTimestampMillis(int id, long timestampMillis) { - getSharedPreferences().edit().putLong(getTimestampMillisKey(id), timestampMillis).apply(); - } - - /** - * Set the timestamp for a {@link PseudoTab}. - * @param id The ID of the {@link PseudoTab}. - * @param timestampMillis The timestamp - */ - public static void setTimestampMillisForTesting(int id, long timestampMillis) { - cacheTimestampMillis(id, timestampMillis); - } - - private static String getLastSearchTermKey(int id) { - return id + "_last_search_term"; - } - - /** - * Get the last search term of the default search engine of a {@link PseudoTab} in the - * navigation stack. - * - * @param id The ID of the {@link PseudoTab}. - * @return The last search term. Null if none. - */ - public static @Nullable String getLastSearchTerm(int id) { - return getSharedPreferences().getString(getLastSearchTermKey(id), null); - } - - private static void cacheLastSearchTerm(Tab tab) { - if (tab.getWebContents() == null) return; - cacheLastSearchTerm(tab.getId(), findLastSearchTerm(tab)); - } - - private static void cacheLastSearchTerm(int id, String searchTerm) { - getSharedPreferences().edit().putString(getLastSearchTermKey(id), searchTerm).apply(); - } - - /** - * Find the latest search term from the navigation stack. - * @param tab The tab to find from. - * @return The search term. Null for no results. - */ - @VisibleForTesting - static @Nullable String findLastSearchTerm(Tab tab) { - if (sLastSearchTermProviderForTesting != null) { - return sLastSearchTermProviderForTesting.getLastSearchTerm(tab); - } - assert tab.getWebContents() != null; - NavigationController controller = tab.getWebContents().getNavigationController(); - NavigationHistory history = controller.getNavigationHistory(); - - Profile profile = tab.getProfile(); - TemplateUrlService templateUrlService = TemplateUrlServiceFactory.getForProfile(profile); - if (!TextUtils.isEmpty(templateUrlService.getSearchQueryForUrl(tab.getUrl()))) { - // If we are already at a search result page, do not show the last search term. - return null; - } - - for (int i = history.getCurrentEntryIndex() - 1; i >= 0; i--) { - GURL url = history.getEntryAtIndex(i).getOriginalUrl(); - String query = templateUrlService.getSearchQueryForUrl(url); - if (!TextUtils.isEmpty(query)) { - return removeEscapedCodePoints(query); - } - } - return null; - } - - /** - * {@link TemplateUrlService#getSearchQueryForUrl(String)} can leave some code points - * unescaped for security reasons. See ShouldUnescapeCodePoint(). - * In our use case, dropping the unescaped code points shouldn't introduce security issues, - * and loss of information is fine because the string is not going to be used other than - * showing in the UI. - * @return the rest of code points - */ - @VisibleForTesting - static String removeEscapedCodePoints(String string) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < string.length(); i++) { - if (string.charAt(i) != '%' || i + 2 >= string.length()) { - sb.append(string.charAt(i)); - continue; - } - if (Character.digit(string.charAt(i + 1), 16) == -1 - || Character.digit(string.charAt(i + 2), 16) == -1) { - sb.append(string.charAt(i)); - continue; - } - i += 2; - } - return sb.toString(); - } - - /** - * Set the LastSearchTermProvider for testing. - * @param lastSearchTermProvider The mocking object. - */ - static void setLastSearchTermMockForTesting(LastSearchTermProvider lastSearchTermProvider) { - sLastSearchTermProviderForTesting = lastSearchTermProvider; - ResettersForTesting.register(() -> sLastSearchTermProviderForTesting = null); - } - - /** - * Set the last search term for a {@link PseudoTab}. - * @param id The ID of the {@link PseudoTab}. - * @param searchTerm The last search term - */ - public static void setLastSearchTermForTesting(int id, String searchTerm) { - cacheLastSearchTerm(id, searchTerm); - } - - /** Remove all the observers. */ - public void destroy() { - mTabModelSelectorTabObserver.destroy(); - TabModelFilter tabModelFilter = - mTabModelSelector.getTabModelFilterProvider().getTabModelFilter(false); - if (tabModelFilter != null) { - tabModelFilter.removeObserver(mTabModelObserver); - } - mTabModelSelector.removeObserver(mTabModelSelectorObserver); - } -}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java index a2c9c299..ad36cc5 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java
@@ -19,14 +19,12 @@ import android.util.Size; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import org.chromium.base.Callback; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabUtils; @@ -36,7 +34,6 @@ import org.chromium.chrome.browser.tab_ui.ThumbnailProvider; import org.chromium.chrome.browser.tabmodel.TabModelFilter; import org.chromium.chrome.browser.tabmodel.TabModelUtils; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; import org.chromium.chrome.tab_ui.R; import org.chromium.components.browser_ui.styles.SemanticColorUtils; import org.chromium.url.GURL; @@ -70,12 +67,12 @@ private final BrowserControlsStateProvider mBrowserControlsStateProvider; private class MultiThumbnailFetcher { - private final PseudoTab mInitialTab; + private final Tab mInitialTab; private final Callback<Bitmap> mFinalCallback; private final boolean mForceUpdate; private final boolean mWriteToCache; private final boolean mIsTabSelected; - private final List<PseudoTab> mTabs = new ArrayList<>(4); + private final List<Tab> mTabs = new ArrayList<>(4); private final AtomicInteger mThumbnailsToFetch = new AtomicInteger(); private Canvas mCanvas; @@ -90,6 +87,7 @@ /** * Fetcher that get the thumbnail drawable depending on if the tab is selected. + * * @see TabContentManager#getTabThumbnailWithCallback * @param initialTab Thumbnail is generated for tabs related to initialTab. * @param thumbnailSize Desired size of multi-thumbnail. @@ -98,7 +96,7 @@ * @param isTabSelected Whether the thumbnail is for a currently selected tab. */ MultiThumbnailFetcher( - PseudoTab initialTab, + Tab initialTab, Size thumbnailSize, Callback<Bitmap> finalCallback, boolean forceUpdate, @@ -195,7 +193,7 @@ } } - private void initializeAndStartFetching(PseudoTab tab) { + private void initializeAndStartFetching(Tab initialTab) { // Initialize mMultiThumbnailBitmap. mMultiThumbnailBitmap = Bitmap.createBitmap(mThumbnailWidth, mThumbnailHeight, Bitmap.Config.ARGB_8888); @@ -203,37 +201,46 @@ mCanvas.drawColor(Color.TRANSPARENT); // Initialize Tabs. - List<PseudoTab> relatedTabList = - PseudoTab.getRelatedTabs(mContext, tab, mCurrentTabModelFilterSupplier.get()); + List<Tab> relatedTabList = + mCurrentTabModelFilterSupplier.get().getRelatedTabList(initialTab.getId()); if (relatedTabList.size() <= 4) { - mThumbnailsToFetch.set(relatedTabList.size()); + int thumbnailCount = relatedTabList.size(); + mThumbnailsToFetch.set(thumbnailCount); - mTabs.add(tab); - relatedTabList.remove(tab); + mTabs.add(initialTab); - for (int i = 0; i < 3; i++) { - mTabs.add(i < relatedTabList.size() ? relatedTabList.get(i) : null); + for (int i = 0; i < thumbnailCount; i++) { + if (relatedTabList.get(i) == initialTab) continue; + + mTabs.add(relatedTabList.get(i)); + } + for (int i = 0; i < 4 - thumbnailCount; i++) { + mTabs.add(null); } } else { - mText = "+" + (relatedTabList.size() - 3); - mThumbnailsToFetch.set(3); + int thumbnailCount = 3; + mText = "+" + (relatedTabList.size() - thumbnailCount); + mThumbnailsToFetch.set(thumbnailCount); - mTabs.add(tab); - relatedTabList.remove(tab); + mTabs.add(initialTab); - mTabs.add(relatedTabList.get(0)); - mTabs.add(relatedTabList.get(1)); + for (int i = 0; i < thumbnailCount; i++) { + if (relatedTabList.get(i) == initialTab) continue; + + mTabs.add(relatedTabList.get(i)); + if (mTabs.size() == thumbnailCount) break; + } mTabs.add(null); } // Fetch and draw all. for (int i = 0; i < 4; i++) { - PseudoTab pseudoTab = mTabs.get(i); + Tab tab = mTabs.get(i); RectF thumbnailRect = mThumbnailRects.get(i); - if (pseudoTab != null) { + if (tab != null) { final int index = i; - final GURL url = pseudoTab.getUrl(); - final boolean isIncognito = pseudoTab.isIncognito(); + final GURL url = tab.getUrl(); + final boolean isIncognito = tab.isIncognito(); final Size tabThumbnailSize = new Size((int) thumbnailRect.width(), (int) thumbnailRect.height()); // getTabThumbnailWithCallback() might call the callback up to twice, @@ -242,10 +249,10 @@ // visible flicker. final AtomicReference<Drawable> lastFavicon = new AtomicReference<>(); mTabContentManager.getTabThumbnailWithCallback( - pseudoTab.getId(), + tab.getId(), tabThumbnailSize, thumbnail -> { - if (pseudoTab.isClosingOrDestroyed()) return; + if (tab.isClosing() || tab.isDestroyed()) return; drawThumbnailBitmapOnCanvasWithFrame(thumbnail, index); if (lastFavicon.get() != null) { @@ -255,7 +262,7 @@ url, isIncognito, (Drawable favicon) -> { - if (pseudoTab.isClosingOrDestroyed()) return; + if (tab.isClosing() || tab.isDestroyed()) return; lastFavicon.set(favicon); drawFaviconThenMaybeSendBack(favicon, index); @@ -449,20 +456,13 @@ boolean writeToCache, boolean isSelected) { TabModelFilter filter = mCurrentTabModelFilterSupplier.get(); - PseudoTab pseudoTab = null; - boolean useMultiThumbnail = false; - if (filter.isTabModelRestored()) { - Tab tab = TabModelUtils.getTabById(filter.getTabModel(), tabId); - useMultiThumbnail = tab != null && filter.isTabInTabGroup(tab); - pseudoTab = tab != null ? PseudoTab.fromTab(tab) : PseudoTab.fromTabId(tabId); - } else { - pseudoTab = PseudoTab.fromTabId(tabId); - useMultiThumbnail = isPseudoTabInTabGroup(filter, pseudoTab); - } + assert filter.isTabModelRestored(); + Tab tab = TabModelUtils.getTabById(filter.getTabModel(), tabId); + boolean useMultiThumbnail = filter.isTabInTabGroup(tab); if (useMultiThumbnail) { - assert pseudoTab != null; + assert tab != null; new MultiThumbnailFetcher( - pseudoTab, + tab, thumbnailSize, finalCallback, forceUpdate, @@ -474,14 +474,4 @@ mTabContentManager.getTabThumbnailWithCallback( tabId, thumbnailSize, finalCallback, forceUpdate, writeToCache); } - - private boolean isPseudoTabInTabGroup( - @NonNull TabModelFilter filter, @Nullable PseudoTab pseudoTab) { - if (ChromeFeatureList.sAndroidTabGroupStableIds.isEnabled()) { - return pseudoTab != null && pseudoTab.getTabGroupId() != null; - } else { - return pseudoTab != null - && PseudoTab.getRelatedTabs(mContext, pseudoTab, filter).size() > 1; - } - } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java index c9db8d1..44d4127 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java
@@ -206,7 +206,6 @@ tabContentManager.getTabThumbnailWithCallback( tabId, thumbnailSize, callback, forceUpdate, writeBack); }, - null, false, gridCardOnClickListenerProvider, mMediator.getTabGridDialogHandler(), @@ -449,7 +448,7 @@ @Override public void resetWithListOfTabs(@Nullable List<Tab> tabs) { - mTabListCoordinator.resetWithListOfTabs(tabs); + mTabListCoordinator.resetWithListOfTabs(tabs, false); mMediator.onReset(tabs); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java index a0eed745..1506323 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
@@ -180,7 +180,6 @@ currentTabModelFilterSupplier, () -> mTabModelSelector.getModel(false), null, - null, false, null, null, @@ -273,12 +272,12 @@ mTabStripCoordinator.getContainerView(), mBottomSheetController); } - mTabStripCoordinator.resetWithListOfTabs(tabs); + mTabStripCoordinator.resetWithListOfTabs(tabs, false); } /** - * Handles a reset event originated from {@link TabGroupUiMediator} - * when the bottom sheet is expanded or the dialog is shown. + * Handles a reset event originated from {@link TabGroupUiMediator} when the bottom sheet is + * expanded or the dialog is shown. * * @param tabs List of Tabs to reset. */
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java index 1a40d3e..54004448 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
@@ -450,8 +450,6 @@ * not, associated tabs from #getTabsToShowForID will be showing in the tab strip. */ private void resetTabStripWithRelatedTabsForId(int id) { - // TODO(crbug.com/40064910): PseudoTab#getRelatedTabList() requires the tab state to be - // initialized. If this is called before tab state is initialized just skip. if (!mTabModelSelector.isTabStateInitialized()) return; // TODO(crbug.com/40133857): We should be able to guard this call behind some checks so that
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java index 8d01c25..7d03bd9 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
@@ -43,7 +43,6 @@ import org.chromium.chrome.browser.tabmodel.TabModelFilter; import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.browser.tasks.ReturnToChromeUtil; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_management.TabListModel.CardProperties.ModelType; import org.chromium.chrome.browser.tasks.tab_management.TabProperties.TabActionState; @@ -125,7 +124,6 @@ * @param tabModelFilterSupplier The supplier for the current tab model filter. * @param regularTabModelSupplier The supplier for the regular tab model. * @param thumbnailProvider Provider to provide screenshot related details. - * @param titleProvider Provider for a given tab's title. * @param actionOnRelatedTabs Whether tab-related actions should be operated on all related * tabs. * @param gridCardOnClickListenerProvider Provides the onClickListener for opening dialog when @@ -155,7 +153,6 @@ @NonNull ObservableSupplier<TabModelFilter> tabModelFilterSupplier, @NonNull Supplier<TabModel> regularTabModelSupplier, @Nullable ThumbnailProvider thumbnailProvider, - @Nullable PseudoTab.TitleProvider titleProvider, boolean actionOnRelatedTabs, @Nullable TabListMediator.GridCardOnClickListenerProvider gridCardOnClickListenerProvider, @@ -176,7 +173,6 @@ tabModelFilterSupplier, regularTabModelSupplier, thumbnailProvider, - titleProvider, actionOnRelatedTabs, gridCardOnClickListenerProvider, dialogHandler, @@ -202,7 +198,6 @@ @NonNull ObservableSupplier<TabModelFilter> tabModelFilterSupplier, @NonNull Supplier<TabModel> regularTabModelSupplier, @Nullable ThumbnailProvider thumbnailProvider, - @Nullable PseudoTab.TitleProvider titleProvider, boolean actionOnRelatedTabs, @Nullable TabListMediator.GridCardOnClickListenerProvider gridCardOnClickListenerProvider, @@ -322,7 +317,6 @@ tabModelFilterSupplier, regularTabModelSupplier, thumbnailProvider, - titleProvider, tabListFaviconProvider, new TabGroupColorFaviconProvider(mContext), actionOnRelatedTabs, @@ -658,14 +652,10 @@ /** * @see TabListMediator#resetWithListOfTabs(List, boolean) */ - boolean resetWithListOfTabs(@Nullable List<PseudoTab> tabs, boolean quickMode) { + boolean resetWithListOfTabs(@Nullable List<Tab> tabs, boolean quickMode) { return mMediator.resetWithListOfTabs(tabs, quickMode); } - boolean resetWithListOfTabs(@Nullable List<Tab> tabs) { - return resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); - } - void softCleanup() { mMediator.softCleanup(); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorCoordinator.java index 6641ec1..0b16f43 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorCoordinator.java
@@ -29,9 +29,6 @@ import org.chromium.chrome.browser.tab_ui.ThumbnailProvider; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelFilter; -import org.chromium.chrome.browser.tabmodel.TabModelUtils; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; -import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; import org.chromium.chrome.browser.tasks.tab_management.TabProperties.TabActionState; import org.chromium.chrome.browser.tasks.tab_management.TabUiMetricsHelper.TabListEditorExitMetricGroups; @@ -179,7 +176,6 @@ ThumbnailProvider thumbnailProvider = initThumbnailProvider(displayGroups, tabContentManager); - PseudoTab.TitleProvider titleProvider = displayGroups ? this::getTitle : null; // TODO(ckitagawa): Lazily instantiate the TabListEditorCoordinator. When doing so, // the Coordinator hosting the TabListEditorCoordinator could share and reconfigure @@ -192,7 +188,6 @@ currentTabModelFilterSupplier, regularTabModelSupplier, thumbnailProvider, - titleProvider, displayGroups, null, null, @@ -319,12 +314,13 @@ /** * Resets {@link TabListCoordinator} with the provided list. + * * @param tabs List of {@link Tab}s to reset. * @param preSelectedCount First {@code preSelectedCount} {@code tabs} are pre-selected. * @param quickMode whether to use quick mode. */ void resetWithListOfTabs(@Nullable List<Tab> tabs, int preSelectedCount, boolean quickMode) { - mTabListCoordinator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), quickMode); + mTabListCoordinator.resetWithListOfTabs(tabs, quickMode); if (tabs != null && preSelectedCount > 0 && preSelectedCount < tabs.size()) { mTabListCoordinator.addSpecialListItem( @@ -334,16 +330,6 @@ } } - private String getTitle(Context context, PseudoTab pseudoTab) { - TabGroupModelFilter filter = (TabGroupModelFilter) mCurrentTabModelFilterSupplier.get(); - Tab tab = TabModelUtils.getTabById(filter.getTabModel(), pseudoTab.getId()); - assert tab != null; - if (!filter.isTabInTabGroup(tab)) return tab.getTitle(); - - return TabGroupTitleEditor.getDefaultTitle( - context, filter.getRelatedTabCountForRootId(tab.getRootId())); - } - private ThumbnailProvider initThumbnailProvider( boolean displayGroups, TabContentManager tabContentManager) { if (displayGroups) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java index a4eace1..2135b3f 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -77,7 +77,6 @@ import org.chromium.chrome.browser.tabmodel.TabModelFilter; import org.chromium.chrome.browser.tabmodel.TabModelObserver; import org.chromium.chrome.browser.tabmodel.TabModelUtils; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupColorUtils; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilterObserver; @@ -374,7 +373,6 @@ private final ValueChangedCallback<TabModelFilter> mOnTabModelFilterChanged = new ValueChangedCallback<>(this::onTabModelFilterChanged); private final TabActionListener mTabClosedListener; - private final PseudoTab.TitleProvider mTitleProvider; private final SelectionDelegateProvider mSelectionDelegateProvider; private final GridCardOnClickListenerProvider mGridCardOnClickListenerProvider; private final TabGridDialogHandler mTabGridDialogHandler; @@ -540,12 +538,12 @@ .model .set( TabProperties.TITLE, - getLatestTitleForTab(PseudoTab.fromTab(updatedTab))); + getLatestTitleForTab(updatedTab, /* useDefault= */ true)); } @Override public void onFaviconUpdated(Tab updatedTab, Bitmap icon, GURL iconUrl) { - updateFaviconForTab(PseudoTab.fromTab(updatedTab), icon, iconUrl); + updateFaviconForTab(updatedTab, icon, iconUrl); } @Override @@ -591,12 +589,12 @@ @Nullable Pair<Integer, Tab> indexAndTab = getIndexAndTabForRootId(rootId); if (indexAndTab == null) return; - PseudoTab pseudoTab = PseudoTab.fromTab(indexAndTab.second); + Tab tab = indexAndTab.second; PropertyModel model = mModel.get(indexAndTab.first).model; model.set(TabProperties.TITLE, newTitle); - updateDescriptionString(pseudoTab, model); - updateActionButtonDescriptionString(pseudoTab, model); + updateDescriptionString(tab, model); + updateActionButtonDescriptionString(tab, model); } @Override @@ -607,16 +605,16 @@ @Nullable Pair<Integer, Tab> indexAndTab = getIndexAndTabForRootId(rootId); if (indexAndTab == null) return; - PseudoTab pseudoTab = PseudoTab.fromTab(indexAndTab.second); + Tab tab = indexAndTab.second; PropertyModel model = mModel.get(indexAndTab.first).model; if (mMode == TabListMode.LIST) { model.set(TabProperties.TAB_GROUP_COLOR_ID, newColor); } else if (mMode == TabListMode.GRID) { - updateFaviconForTab(pseudoTab, null, null); + updateFaviconForTab(tab, null, null); } - updateDescriptionString(pseudoTab, model); - updateActionButtonDescriptionString(pseudoTab, model); + updateDescriptionString(tab, model); + updateActionButtonDescriptionString(tab, model); } @Override @@ -691,14 +689,14 @@ && movedTab != previousGroupTab) { int filterIndex = filter.indexOf(movedTab); addTabInfoToModel( - PseudoTab.fromTab(movedTab), + movedTab, mModel.indexOfNthTabCard(filterIndex), currentSelectedTabId == movedTab.getId()); } boolean isSelected = currentSelectedTabId == previousGroupTab.getId(); updateTab( mModel.indexOfNthTabCard(prevFilterIndex), - PseudoTab.fromTab(previousGroupTab), + previousGroupTab, isSelected, true, false); @@ -751,7 +749,7 @@ TabModelUtils.getTabById( tabModel, mModel.get(desIndex).model.get(TabProperties.TAB_ID)); - updateTab(desIndex, PseudoTab.fromTab(tab), isSelected, false, false); + updateTab(desIndex, tab, isSelected, false, false); return; } @@ -775,12 +773,7 @@ boolean isSelected = TabModelUtils.getCurrentTab(tabModel) == newSelectedTabInMergedGroup; - updateTab( - desIndex, - PseudoTab.fromTab(newSelectedTabInMergedGroup), - isSelected, - true, - false); + updateTab(desIndex, newSelectedTabInMergedGroup, isSelected, true, false); } else { // If the model is empty we can't check if the added tab is part of the // current group. Assume it isn't since a group state with 0 tab should be @@ -888,7 +881,6 @@ * @param modalDialogManager The {@link ModalDialogManager} for managing dialog lifecycles. * @param regularTabModelSupplier The supplier of the regular {@link TabModel}. * @param thumbnailProvider {@link ThumbnailProvider} to provide screenshot related details. - * @param titleProvider {@link PseudoTab.TitleProvider} for a given tab's title to show. * @param tabListFaviconProvider Provider for all favicon related drawables. * @param tabGroupColorFaviconProvider Provider for tab group color favicon related drawables. * @param actionOnRelatedTabs Whether tab-related actions should be operated on all related @@ -912,7 +904,6 @@ @NonNull ObservableSupplier<TabModelFilter> tabModelFilterSupplier, @NonNull Supplier<TabModel> regularTabModelSupplier, @Nullable ThumbnailProvider thumbnailProvider, - @Nullable PseudoTab.TitleProvider titleProvider, TabListFaviconProvider tabListFaviconProvider, @NonNull TabGroupColorFaviconProvider tabGroupColorFaviconProvider, boolean actionOnRelatedTabs, @@ -933,7 +924,6 @@ mTabListFaviconProvider = tabListFaviconProvider; mTabGroupColorFaviconProvider = tabGroupColorFaviconProvider; mComponentName = componentName; - mTitleProvider = titleProvider; mSelectionDelegateProvider = selectionDelegateProvider; mGridCardOnClickListenerProvider = gridCardOnClickListenerProvider; mTabGridDialogHandler = dialogHandler; @@ -1014,7 +1004,7 @@ updateTab( tabListModelIndex, - PseudoTab.fromTab(currentGroupSelectedTab), + currentGroupSelectedTab, mModel.get(tabListModelIndex) .model .get(TabProperties.IS_SELECTED), @@ -1061,7 +1051,7 @@ } updateTab( tabListModelIndex, - PseudoTab.fromTab(currentGroupSelectedTab), + currentGroupSelectedTab, mModel.get(tabListModelIndex) .model .get(TabProperties.IS_SELECTED), @@ -1085,12 +1075,7 @@ final int currentSelectedTabId = TabModelUtils.getCurrentTabId(groupFilter.getTabModel()); boolean isSelected = currentSelectedTabId == groupTab.getId(); - updateTab( - groupIndex, - PseudoTab.fromTab(groupTab), - isSelected, - true, - false); + updateTab(groupIndex, groupTab, isSelected, true, false); return; } @@ -1279,9 +1264,8 @@ int index = mModel.indexFromId(currentGroupSelectedTab.getId()); if (index == TabModel.INVALID_TAB_INDEX) return; mModel.get(index).model.set(TabProperties.TITLE, title); - updateDescriptionString(PseudoTab.fromTab(tab), mModel.get(index).model); - updateActionButtonDescriptionString( - PseudoTab.fromTab(tab), mModel.get(index).model); + updateDescriptionString(tab, mModel.get(index).model); + updateActionButtonDescriptionString(tab, mModel.get(index).model); } @Override @@ -1404,7 +1388,7 @@ Tab currentTab = TabModelUtils.getCurrentTab(mCurrentTabModelFilterSupplier.get().getTabModel()); - addTabInfoToModel(PseudoTab.fromTab(tab), newIndex, currentTab == tab); + addTabInfoToModel(tab, newIndex, currentTab == tab); return newIndex; } @@ -1412,7 +1396,7 @@ return position != TabModel.INVALID_TAB_INDEX && position < mModel.size(); } - private boolean areTabsUnchanged(@Nullable List<PseudoTab> tabs) { + private boolean areTabsUnchanged(@Nullable List<Tab> tabs) { int tabsCount = 0; for (int i = 0; i < mModel.size(); i++) { if (mModel.get(i).model.get(CARD_TYPE) == TAB) { @@ -1441,17 +1425,16 @@ * @param quickMode Whether to skip capturing the selected live tab for the thumbnail. * @return Whether the {@link TabListRecyclerView} can be shown quickly. */ - boolean resetWithListOfTabs(@Nullable List<PseudoTab> tabs, boolean quickMode) { - List<PseudoTab> tabsList = tabs; - mVisible = tabsList != null; + boolean resetWithListOfTabs(@Nullable List<Tab> tabs, boolean quickMode) { + mVisible = tabs != null; if (tabs != null) { recordPriceAnnotationsEnabledMetrics(); } TabModelFilter filter = mCurrentTabModelFilterSupplier.get(); - if (areTabsUnchanged(tabsList)) { - if (tabsList == null) return true; - for (int i = 0; i < tabsList.size(); i++) { - PseudoTab tab = tabsList.get(i); + if (areTabsUnchanged(tabs)) { + if (tabs == null) return true; + for (int i = 0; i < tabs.size(); i++) { + Tab tab = tabs.get(i); int currentTabId = TabModelUtils.getCurrentTabId(filter.getTabModel()); boolean isSelected = isSelectedTab(tab, currentTabId); updateTab(mModel.indexOfNthTabCard(i), tab, isSelected, false, quickMode); @@ -1461,13 +1444,13 @@ mModel.set(new ArrayList<>()); mLastSelectedTabListModelIndex = TabList.INVALID_TAB_INDEX; - if (tabsList == null) { + if (tabs == null) { return true; } int currentTabId = TabModelUtils.getCurrentTabId(filter.getTabModel()); - for (int i = 0; i < tabsList.size(); i++) { - PseudoTab tab = tabsList.get(i); + for (int i = 0; i < tabs.size(); i++) { + Tab tab = tabs.get(i); addTabInfoToModel(tab, i, isSelectedTab(tab, currentTabId)); } @@ -1497,7 +1480,7 @@ } } - private boolean isSelectedTab(PseudoTab tab, int tabModelSelectedTabId) { + private boolean isSelectedTab(Tab tab, int tabModelSelectedTabId) { SelectionDelegate<Integer> selectionDelegate = getTabSelectionDelegate(); if (selectionDelegate == null) { return tab.getId() == tabModelSelectedTabId; @@ -1551,36 +1534,26 @@ } private void updateTab( - int index, - PseudoTab pseudoTab, - boolean isSelected, - boolean isUpdatingId, - boolean quickMode) { + int index, Tab tab, boolean isSelected, boolean isUpdatingId, boolean quickMode) { if (index < 0 || index >= mModel.size()) return; if (isUpdatingId) { - mModel.get(index).model.set(TabProperties.TAB_ID, pseudoTab.getId()); + mModel.get(index).model.set(TabProperties.TAB_ID, tab.getId()); } else { - assert mModel.get(index).model.get(TabProperties.TAB_ID) == pseudoTab.getId(); + assert mModel.get(index).model.get(TabProperties.TAB_ID) == tab.getId(); } // TODO(wychen): refactor this. - boolean isRealTab = pseudoTab.hasRealTab(); - boolean isInTabGroup = isPseudoTabInTabGroup(pseudoTab); + boolean isInTabGroup = isTabInTabGroup(tab); TabActionListener tabSelectedListener; - if (!isRealTab) { - tabSelectedListener = null; + if (mGridCardOnClickListenerProvider == null + || !isInTabGroup + || !mActionsOnAllRelatedTabs) { + tabSelectedListener = mTabSelectedListener; } else { - if (mGridCardOnClickListenerProvider == null - || !isInTabGroup - || !mActionsOnAllRelatedTabs) { - tabSelectedListener = mTabSelectedListener; - } else { - tabSelectedListener = - mGridCardOnClickListenerProvider.openTabGridDialog(pseudoTab.getTab()); + tabSelectedListener = mGridCardOnClickListenerProvider.openTabGridDialog(tab); - if (tabSelectedListener == null) { - tabSelectedListener = mTabSelectedListener; - } + if (tabSelectedListener == null) { + tabSelectedListener = mTabSelectedListener; } } @@ -1589,9 +1562,9 @@ if (mMode == TabListMode.LIST && isInTabGroup) { final @TabGroupColorId int tabGroupColorId = TabGroupColorUtils.getOrCreateTabGroupColor( - pseudoTab.getRootId(), + tab.getRootId(), (TabGroupModelFilter) mCurrentTabModelFilterSupplier.get()); - PropertyModel model = getModelFromId(pseudoTab.getId()); + PropertyModel model = getModelFromId(tab.getId()); if (model != null) { model.set(TabProperties.TAB_GROUP_COLOR_ID, tabGroupColorId); } @@ -1601,17 +1574,19 @@ mModel.get(index).model.set(TabProperties.TAB_SELECTED_LISTENER, tabSelectedListener); mModel.get(index).model.set(TabProperties.IS_SELECTED, isSelected); mModel.get(index).model.set(TabProperties.SHOULD_SHOW_PRICE_DROP_TOOLTIP, false); - mModel.get(index).model.set(TabProperties.TITLE, getLatestTitleForTab(pseudoTab)); + mModel.get(index) + .model + .set(TabProperties.TITLE, getLatestTitleForTab(tab, /* useDefault= */ true)); mModel.get(index) .model .set(TabProperties.ON_MENU_ITEM_CLICKED_CALLBACK, mOnMenuItemClickedCallback); // A tab is deemed a tab group card representation if it is part of a tab group and // based in the tab switcher. - boolean isTabGroup = isPseudoTabInTabGroup(pseudoTab) && isParentComponentTabSwitcher(); + boolean isTabGroup = isTabInTabGroup(tab) && isParentComponentTabSwitcher(); // Update the group color icon. if (ChromeFeatureList.sTabGroupParityAndroid.isEnabled() && isTabGroup) { - updateFaviconForTab(pseudoTab, null, null); + updateFaviconForTab(tab, null, null); } // The ordering of TAB_ACTION_BUTTON_LISTENER and IS_TAB_GROUP must be preserved when // setting the property keys on the model. Both properties modify the onClickListener @@ -1620,9 +1595,7 @@ if (!ChromeFeatureList.sTabGroupPaneAndroid.isEnabled() || !isTabGroup) { mModel.get(index) .model - .set( - TabProperties.TAB_ACTION_BUTTON_LISTENER, - isRealTab ? mTabClosedListener : null); + .set(TabProperties.TAB_ACTION_BUTTON_LISTENER, mTabClosedListener); } // Only set this for tab group representation cards. An onClickListener will be set in the // view as part of the accompanying logic. @@ -1636,17 +1609,13 @@ isTabGroup)); } - updateDescriptionString(pseudoTab, mModel.get(index).model); - updateActionButtonDescriptionString(pseudoTab, mModel.get(index).model); - if (isRealTab) { - mModel.get(index) - .model - .set(TabProperties.URL_DOMAIN, getDomainForTab(pseudoTab.getTab())); - } + updateDescriptionString(tab, mModel.get(index).model); + updateActionButtonDescriptionString(tab, mModel.get(index).model); + mModel.get(index).model.set(TabProperties.URL_DOMAIN, getDomainForTab(tab)); - setupPersistedTabDataFetcherForTab(pseudoTab, index); + setupPersistedTabDataFetcherForTab(tab, index); - updateFaviconForTab(pseudoTab, null, null); + updateFaviconForTab(tab, null, null); boolean forceUpdate = isSelected && !quickMode; boolean forceUpdateLastSelected = mActionsOnAllRelatedTabs && index == mLastSelectedTabListModelIndex && !quickMode; @@ -1663,7 +1632,7 @@ ThumbnailFetcher callback = new ThumbnailFetcher( mThumbnailProvider, - pseudoTab.getId(), + tab.getId(), (forceUpdate || forceUpdateLastSelected) && !isSelectable, forceUpdate && !TabUiFeatureUtilities.isTabToGtsAnimationEnabled(mContext) @@ -1673,18 +1642,11 @@ } @VisibleForTesting - public boolean isPseudoTabInTabGroup(@NonNull PseudoTab pseudoTab) { + public boolean isTabInTabGroup(@NonNull Tab tab) { TabModelFilter filter = mCurrentTabModelFilterSupplier.get(); - if (filter.isTabModelRestored()) { - Tab tab = TabModelUtils.getTabById(filter.getTabModel(), pseudoTab.getId()); - return filter.isTabInTabGroup(tab); - } else { - if (ChromeFeatureList.sAndroidTabGroupStableIds.isEnabled()) { - return pseudoTab.getTabGroupId() != null; - } else { - return PseudoTab.getRelatedTabs(mContext, pseudoTab, filter).size() > 1; - } - } + assert filter.isTabModelRestored(); + + return filter.isTabInTabGroup(tab); } public Set<Integer> getViewedTabIdsForTesting() { @@ -1874,24 +1836,20 @@ } } - private void addTabInfoToModel(final PseudoTab pseudoTab, int index, boolean isSelected) { + private void addTabInfoToModel(Tab tab, int index, boolean isSelected) { assert index != TabModel.INVALID_TAB_INDEX; boolean showIPH = false; - boolean isRealTab = pseudoTab.hasRealTab(); - boolean isInTabGroup = isPseudoTabInTabGroup(pseudoTab); - if (mActionsOnAllRelatedTabs && !mShownIPH && isRealTab) { + boolean isInTabGroup = isTabInTabGroup(tab); + if (mActionsOnAllRelatedTabs && !mShownIPH) { showIPH = isInTabGroup; } TabActionListener tabSelectedListener; - if (!isRealTab) { - tabSelectedListener = null; - } else if (mGridCardOnClickListenerProvider == null + if (mGridCardOnClickListenerProvider == null || !isInTabGroup || !mActionsOnAllRelatedTabs) { tabSelectedListener = mTabSelectedListener; } else { - tabSelectedListener = - mGridCardOnClickListenerProvider.openTabGridDialog(pseudoTab.getTab()); + tabSelectedListener = mGridCardOnClickListenerProvider.openTabGridDialog(tab); if (tabSelectedListener == null) { tabSelectedListener = mTabSelectedListener; } @@ -1906,28 +1864,27 @@ // Rather it's LIST mode where we do this, and additionally not when we've opened a // dialog for a particular group, checked by isParentComponentTabSwitcher(). if (mMode == TabListMode.LIST && isInTabGroup && isParentComponentTabSwitcher()) { - colorId = - TabGroupColorUtils.getOrCreateTabGroupColor(pseudoTab.getRootId(), filter); + colorId = TabGroupColorUtils.getOrCreateTabGroupColor(tab.getRootId(), filter); } } int selectedTabBackgroundDrawableId = - pseudoTab.isIncognito() + tab.isIncognito() ? R.drawable.selected_tab_background_incognito : R.drawable.selected_tab_background; int tabstripFaviconBackgroundDrawableId = - pseudoTab.isIncognito() + tab.isIncognito() ? R.color.favicon_background_color_incognito : R.color.favicon_background_color; PropertyModel tabInfo = new PropertyModel.Builder(TabProperties.ALL_KEYS_TAB_GRID) .with(TabProperties.TAB_ACTION_STATE, mTabActionState) - .with(TabProperties.TAB_ID, pseudoTab.getId()) - .with(TabProperties.TITLE, getLatestTitleForTab(pseudoTab)) + .with(TabProperties.TAB_ID, tab.getId()) .with( - TabProperties.URL_DOMAIN, - isRealTab ? getDomainForTab(pseudoTab.getTab()) : null) + TabProperties.TITLE, + getLatestTitleForTab(tab, /* useDefault= */ true)) + .with(TabProperties.URL_DOMAIN, getDomainForTab(tab)) .with(TabProperties.FAVICON_FETCHER, null) .with(TabProperties.FAVICON_FETCHED, false) .with(TabProperties.IS_SELECTED, isSelected) @@ -1936,10 +1893,8 @@ .with( TabProperties.CARD_ANIMATION_STATUS, TabGridView.AnimationStatus.CARD_RESTORE) - .with( - TabProperties.TAB_SELECTION_DELEGATE, - isRealTab ? getTabSelectionDelegate() : null) - .with(TabProperties.IS_INCOGNITO, pseudoTab.isIncognito()) + .with(TabProperties.TAB_SELECTION_DELEGATE, getTabSelectionDelegate()) + .with(TabProperties.IS_INCOGNITO, tab.isIncognito()) .with( TabProperties.SELECTED_TAB_BACKGROUND_DRAWABLE_ID, selectedTabBackgroundDrawableId) @@ -1955,10 +1910,10 @@ .with(TabProperties.TAB_GROUP_COLOR_ID, colorId) .build(); - if (!mActionsOnAllRelatedTabs || !isPseudoTabInTabGroup(pseudoTab)) { + if (!mActionsOnAllRelatedTabs || !isTabInTabGroup(tab)) { tabInfo.set( TabProperties.FAVICON_FETCHER, - mTabListFaviconProvider.getDefaultFaviconFetcher(pseudoTab.isIncognito())); + mTabListFaviconProvider.getDefaultFaviconFetcher(tab.isIncognito())); } if (mTabActionState == TabActionState.SELECTABLE) { @@ -1967,20 +1922,20 @@ // dark. ColorStateList checkedDrawableColorList = ColorStateList.valueOf( - pseudoTab.isIncognito() + tab.isIncognito() ? mContext.getColor(R.color.default_icon_color_dark) : SemanticColorUtils.getDefaultIconColorInverse(mContext)); ColorStateList actionButtonBackgroundColorList = AppCompatResources.getColorStateList( mContext, - pseudoTab.isIncognito() + tab.isIncognito() ? R.color.default_icon_color_light : R.color.default_icon_color_tint_list); // TODO(crbug.com/41477267): Update color baseline_primary_80 to active_color_dark when // the associated bug is landed. ColorStateList actionbuttonSelectedBackgroundColorList = ColorStateList.valueOf( - pseudoTab.isIncognito() + tab.isIncognito() ? mContext.getColor(R.color.baseline_primary_80) : SemanticColorUtils.getDefaultControlColorActive(mContext)); @@ -1999,15 +1954,13 @@ tabInfo.set(TabProperties.ON_MENU_ITEM_CLICKED_CALLBACK, mOnMenuItemClickedCallback); // A tab is deemed a tab group card representation if it is part of a tab group and // based in the tab switcher. - boolean isTabGroup = isPseudoTabInTabGroup(pseudoTab) && isParentComponentTabSwitcher(); + boolean isTabGroup = isTabInTabGroup(tab) && isParentComponentTabSwitcher(); // The ordering of TAB_ACTION_BUTTON_LISTENER and IS_TAB_GROUP must be preserved when // setting the property keys on the model. Both properties modify the onClickListener // so ensure that the default behavior (close on click) is set first, and tab groups // under valid circumstances will override the listener with alternate behavior. if (!ChromeFeatureList.sTabGroupPaneAndroid.isEnabled() || !isTabGroup) { - tabInfo.set( - TabProperties.TAB_ACTION_BUTTON_LISTENER, - isRealTab ? mTabClosedListener : null); + tabInfo.set(TabProperties.TAB_ACTION_BUTTON_LISTENER, mTabClosedListener); } // Only set this for tab group representation cards. An onClickListener will be set in // the view as part of the accompanying logic. @@ -2018,8 +1971,8 @@ TabGroupSyncFeatures.isTabGroupSyncEnabled(mProfile), isTabGroup)); } - updateDescriptionString(pseudoTab, tabInfo); - updateActionButtonDescriptionString(pseudoTab, tabInfo); + updateDescriptionString(tab, tabInfo); + updateActionButtonDescriptionString(tab, tabInfo); } @UiType @@ -2031,9 +1984,9 @@ mModel.add(index, new SimpleRecyclerViewAdapter.ListItem(tabUiType, tabInfo)); } - setupPersistedTabDataFetcherForTab(pseudoTab, index); + setupPersistedTabDataFetcherForTab(tab, index); - updateFaviconForTab(pseudoTab, null, null); + updateFaviconForTab(tab, null, null); if (mThumbnailProvider != null && mDefaultGridCardSize != null) { if (!mDefaultGridCardSize.equals(tabInfo.get(TabProperties.GRID_CARD_SIZE))) { @@ -2048,17 +2001,16 @@ ThumbnailFetcher callback = new ThumbnailFetcher( mThumbnailProvider, - pseudoTab.getId(), + tab.getId(), isSelected && !isSelectable, isSelected && !TabUiFeatureUtilities.isTabToGtsAnimationEnabled(mContext) && !isSelectable); tabInfo.set(TabProperties.THUMBNAIL_FETCHER, callback); } - if (pseudoTab.getTab() != null) pseudoTab.getTab().addObserver(mTabObserver); + tab.addObserver(mTabObserver); } - // TODO(wychen): make this work with PseudoTab. private String getDomainForTab(Tab tab) { if (!mActionsOnAllRelatedTabs) return getDomain(tab); @@ -2074,13 +2026,12 @@ return TextUtils.join(", ", domainNames); } - private void updateDescriptionString(PseudoTab pseudoTab, PropertyModel model) { + private void updateDescriptionString(Tab tab, PropertyModel model) { if (!mActionsOnAllRelatedTabs) return; - boolean isInTabGroup = isPseudoTabInTabGroup(pseudoTab); - int numOfRelatedTabs = getRelatedTabsForId(pseudoTab.getId()).size(); + boolean isInTabGroup = isTabInTabGroup(tab); + int numOfRelatedTabs = getRelatedTabsForId(tab.getId()).size(); if (isInTabGroup) { - String title = getLatestTitleForTab(pseudoTab); - title = title.equals(pseudoTab.getTitle(mContext, mTitleProvider)) ? "" : title; + String title = getLatestTitleForTab(tab, /* useDefault= */ false); Resources res = mContext.getResources(); if (!ChromeFeatureList.sTabGroupParityAndroid.isEnabled()) { model.set( @@ -2096,7 +2047,7 @@ title, numOfRelatedTabs)); } else { - int colorId = TabGroupColorUtils.getTabGroupColor(pseudoTab.getRootId()); + int colorId = TabGroupColorUtils.getTabGroupColor(tab.getRootId()); // This should never be the case in practice, but if the color is invalid then set // it to the first color in the list. if (colorId == INVALID_COLOR_ID) { @@ -2127,17 +2078,15 @@ } } - private void updateActionButtonDescriptionString(PseudoTab pseudoTab, PropertyModel model) { + private void updateActionButtonDescriptionString(Tab tab, PropertyModel model) { if (mActionsOnAllRelatedTabs) { - boolean isInTabGroup = isPseudoTabInTabGroup(pseudoTab); - int numOfRelatedTabs = getRelatedTabsForId(pseudoTab.getId()).size(); + boolean isInTabGroup = isTabInTabGroup(tab); + int numOfRelatedTabs = getRelatedTabsForId(tab.getId()).size(); if (isInTabGroup) { - String title = getLatestTitleForTab(pseudoTab); - title = title.equals(pseudoTab.getTitle(mContext, mTitleProvider)) ? "" : title; + String title = getLatestTitleForTab(tab, /* useDefault= */ false); String descriptionString = - getActionButtonDescriptionString( - numOfRelatedTabs, title, pseudoTab.getRootId()); + getActionButtonDescriptionString(numOfRelatedTabs, title, tab.getRootId()); model.set(TabProperties.ACTION_BUTTON_DESCRIPTION_STRING, descriptionString); return; } @@ -2145,8 +2094,7 @@ model.set( ACTION_BUTTON_DESCRIPTION_STRING, - mContext.getString( - R.string.accessibility_tabstrip_btn_close_tab, pseudoTab.getTitle())); + mContext.getString(R.string.accessibility_tabstrip_btn_close_tab, tab.getTitle())); } @VisibleForTesting @@ -2176,15 +2124,24 @@ } @VisibleForTesting - String getLatestTitleForTab(PseudoTab pseudoTab) { - String originalTitle = pseudoTab.getTitle(mContext, mTitleProvider); - if (!mActionsOnAllRelatedTabs || mTabGroupTitleEditor == null) return originalTitle; - // If the group degrades to a single tab, delete the stored title. - if (!isPseudoTabInTabGroup(pseudoTab)) { + String getLatestTitleForTab(Tab tab, boolean useDefault) { + String originalTitle = tab.getTitle(); + if (!mActionsOnAllRelatedTabs || mTabGroupTitleEditor == null || !isTabInTabGroup(tab)) { return originalTitle; } - String storedTitle = mTabGroupTitleEditor.getTabGroupTitle(pseudoTab.getRootId()); - return storedTitle == null ? originalTitle : storedTitle; + + String storedTitle = mTabGroupTitleEditor.getTabGroupTitle(tab.getRootId()); + if (storedTitle == null) { + if (useDefault) { + TabGroupModelFilter filter = + (TabGroupModelFilter) mCurrentTabModelFilterSupplier.get(); + return TabGroupTitleEditor.getDefaultTitle( + mContext, filter.getRelatedTabCountForRootId(tab.getRootId())); + } else { + return ""; + } + } + return storedTitle; } int selectedTabId() { @@ -2195,18 +2152,17 @@ return TabModelUtils.getCurrentTabId(mCurrentTabModelFilterSupplier.get().getTabModel()); } - private void setupPersistedTabDataFetcherForTab(PseudoTab pseudoTab, int index) { - if (mMode == TabListMode.GRID && pseudoTab.hasRealTab() && !pseudoTab.isIncognito()) { + private void setupPersistedTabDataFetcherForTab(Tab tab, int index) { + if (mMode == TabListMode.GRID && !tab.isIncognito()) { assert mProfile != null; if (PriceTrackingUtilities.isTrackPricesOnTabsEnabled(mProfile) - && !isPseudoTabInTabGroup(pseudoTab)) { + && !isTabInTabGroup(tab)) { mModel.get(index) .model .set( TabProperties.SHOPPING_PERSISTED_TAB_DATA_FETCHER, new ShoppingPersistedTabDataFetcher( - pseudoTab.getTab(), - mPriceWelcomeMessageControllerSupplier)); + tab, mPriceWelcomeMessageControllerSupplier)); } else { mModel.get(index) .model @@ -2218,12 +2174,12 @@ } @VisibleForTesting - void updateFaviconForTab(PseudoTab pseudoTab, @Nullable Bitmap icon, @Nullable GURL iconUrl) { - int modelIndex = mModel.indexFromId(pseudoTab.getId()); + void updateFaviconForTab(Tab tab, @Nullable Bitmap icon, @Nullable GURL iconUrl) { + int modelIndex = mModel.indexFromId(tab.getId()); if (modelIndex == Tab.INVALID_TAB_ID) return; - if (mActionsOnAllRelatedTabs && isPseudoTabInTabGroup(pseudoTab)) { - List<Tab> relatedTabList = getRelatedTabsForId(pseudoTab.getId()); + if (mActionsOnAllRelatedTabs && isTabInTabGroup(tab)) { + List<Tab> relatedTabList = getRelatedTabsForId(tab.getId()); if (mMode != TabListMode.LIST) { // For tab group card in grid tab switcher, the favicon is set to be null. // With tab group colors, set the the favicon fetcher to a circle of color. @@ -2231,7 +2187,7 @@ if (ChromeFeatureList.sTabGroupParityAndroid.isEnabled()) { TabGroupModelFilter filter = (TabGroupModelFilter) mCurrentTabModelFilterSupplier.get(); - int colorId = TabGroupColorUtils.getTabGroupColor(pseudoTab.getRootId()); + int colorId = TabGroupColorUtils.getTabGroupColor(tab.getRootId()); faviconFetcher = mTabGroupColorFaviconProvider.getFaviconFromTabGroupColorFetcher( colorId, filter.getTabModel().isIncognito()); @@ -2242,9 +2198,9 @@ } else if (mMode == TabListMode.LIST && relatedTabList.size() > 1) { // The order of the url list matches the multi-thumbnail. List<GURL> urls = new ArrayList<>(); - urls.add(pseudoTab.getUrl()); + urls.add(tab.getUrl()); for (int i = 0; urls.size() < 4 && i < relatedTabList.size(); i++) { - if (pseudoTab.getId() == relatedTabList.get(i).getId()) continue; + if (tab.getId() == relatedTabList.get(i).getId()) continue; urls.add(relatedTabList.get(i).getUrl()); } @@ -2254,7 +2210,7 @@ .set( TabProperties.FAVICON_FETCHER, mTabListFaviconProvider.getComposedFaviconImageFetcher( - urls, pseudoTab.isIncognito())); + urls, tab.isIncognito())); return; } } @@ -2273,8 +2229,7 @@ } TabFaviconFetcher fetcher = - mTabListFaviconProvider.getFaviconForUrlFetcher( - pseudoTab.getUrl(), pseudoTab.isIncognito()); + mTabListFaviconProvider.getFaviconForUrlFetcher(tab.getUrl(), tab.isIncognito()); mModel.get(modelIndex).model.set(TabProperties.FAVICON_FETCHER, fetcher); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java index 3f25d9ae..1512f51e 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -48,8 +48,6 @@ import org.chromium.chrome.browser.tabmodel.TabList; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelUtils; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; -import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestionsOrchestrator; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; @@ -201,22 +199,6 @@ tabContentManager, currentTabModelFilterSupplier); - PseudoTab.TitleProvider titleProvider = - (context, pseudoTab) -> { - TabGroupModelFilter filter = - (TabGroupModelFilter) - tabModelSelector - .getTabModelFilterProvider() - .getCurrentTabModelFilterSupplier() - .get(); - Tab tab = TabModelUtils.getTabById(filter.getTabModel(), pseudoTab.getId()); - assert tab != null; - if (!filter.isTabInTabGroup(tab)) return tab.getTitle(); - - return TabGroupTitleEditor.getDefaultTitle( - context, filter.getRelatedTabCountForRootId(tab.getRootId())); - }; - long startTimeMs = SystemClock.uptimeMillis(); int emptyImageResId = @@ -239,7 +221,6 @@ currentTabModelFilterSupplier, () -> tabModelSelector.getModel(false), mMultiThumbnailCardProvider, - titleProvider, true, mMediator, null, @@ -298,6 +279,7 @@ snackbarManager, modalDialogManager, mTabListCoordinator, + /* visibilitySupplier= */ () -> true, tabListEditorControllerSupplier, mMediator, mode); @@ -534,11 +516,11 @@ // ResetHandler implementation. @Override public boolean resetWithTabList(@Nullable TabList tabList, boolean quickMode) { - return resetWithTabs(PseudoTab.getListOfPseudoTab(tabList), quickMode); + return resetWithTabs(TabModelUtils.convertTabListToListOfTabs(tabList), quickMode); } @Override - public boolean resetWithTabs(@Nullable List<PseudoTab> tabs, boolean quickMode) { + public boolean resetWithTabs(@Nullable List<Tab> tabs, boolean quickMode) { mMessageManager.beforeReset(); boolean showQuickly = mTabListCoordinator.resetWithListOfTabs(tabs, quickMode); mMessageManager.afterReset(tabs == null ? 0 : tabs.size());
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java index cb4f200..9786236 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java
@@ -14,6 +14,7 @@ import org.chromium.base.ValueChangedCallback; import org.chromium.base.supplier.LazyOneshotSupplier; import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.incognito.reauth.IncognitoReauthManager; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; @@ -119,6 +120,7 @@ private final @NonNull SnackbarManager mSnackbarManager; private final @NonNull ModalDialogManager mModalDialogManager; private final @NonNull TabListCoordinator mTabListCoordinator; + private final @NonNull Supplier<Boolean> mVisibilitySupplier; private final @NonNull LazyOneshotSupplier<TabListEditorController> mTabListEditorControllerSupplier; private final @NonNull PriceWelcomeMessageReviewActionProvider @@ -146,6 +148,7 @@ * @param snackbarManager The {@link SnackbarManager} for the activity. * @param modalDialogManager The {@link ModalDialogManager} for the activity. * @param tabListCoordinator The {@link TabListCoordinator} to show messages on. + * @param visibilitySupplier A supplier for the visibility of the {@link TabListCoordinator}. * @param tabListEditorControllerSupplier The supplier of the {@link TabListEditorController}. * @param priceWelcomeMessageReviewActionProvider The review action provider for price welcome. * @param mode The {@link TabListMode} the {@link TabListCoordinator} is in. @@ -159,6 +162,7 @@ @NonNull SnackbarManager snackbarManager, @NonNull ModalDialogManager modalDialogManager, @NonNull TabListCoordinator tabListCoordinator, + @NonNull Supplier<Boolean> visibilitySupplier, @NonNull LazyOneshotSupplier<TabListEditorController> tabListEditorControllerSupplier, @NonNull PriceWelcomeMessageReviewActionProvider priceWelcomeMessageReviewActionProvider, @@ -171,6 +175,7 @@ mSnackbarManager = snackbarManager; mModalDialogManager = modalDialogManager; mTabListCoordinator = tabListCoordinator; + mVisibilitySupplier = visibilitySupplier; mTabListEditorControllerSupplier = tabListEditorControllerSupplier; mPriceWelcomeMessageReviewActionProvider = priceWelcomeMessageReviewActionProvider; mMode = mode; @@ -339,7 +344,8 @@ } private void appendMessagesTo(int index) { - if (mMultiWindowModeStateDispatcher.isInMultiWindowMode()) return; + if (!shouldShowMessages()) return; + sAppendedMessagesForTesting = false; List<MessageCardProviderMediator.Message> messages = mMessageCardProviderCoordinator.getMessageItems(); @@ -350,7 +356,10 @@ index, TabProperties.UiType.LARGE_MESSAGE, messages.get(i).model); } else if (messages.get(i).type == MessageService.MessageType.INCOGNITO_REAUTH_PROMO_MESSAGE) { - mayAddIncognitoReauthPromoCard(messages.get(i).model); + if (!mayAddIncognitoReauthPromoCard(messages.get(i).model)) { + // Skip incrementing index if the message was not added. + continue; + } } else if (messages.get(i).type == MessageService.MessageType.TAB_SUGGESTION) { // TODO(crbug.com/40073668): Update to a mayAdd call checking show criteria mTabListCoordinator.addSpecialListItem( @@ -369,11 +378,13 @@ } } - private void mayAddIncognitoReauthPromoCard(PropertyModel model) { + private boolean mayAddIncognitoReauthPromoCard(PropertyModel model) { if (mIncognitoReauthPromoMessageService.isIncognitoReauthPromoMessageEnabled(mProfile)) { mTabListCoordinator.addSpecialListItemToEnd(TabProperties.UiType.LARGE_MESSAGE, model); mIncognitoReauthPromoMessageService.increasePromoShowCountAndMayDisableIfCountExceeds(); + return true; } + return false; } private boolean shouldAppendMessage(MessageCardProviderMediator.Message message) { @@ -420,6 +431,8 @@ * message items when the closure of the last tab in tab switcher is undone. */ private void restoreAllAppendedMessage() { + if (!shouldShowMessages()) return; + // TODO(crbug.com/340730009): The Profile should never be null, and this should be removed // once this bug is addressed. if (mCurrentTabModelFilterSupplier.get().getTabModel().getProfile() == null) return; @@ -522,6 +535,10 @@ } } + private boolean shouldShowMessages() { + return !mMultiWindowModeStateDispatcher.isInMultiWindowMode() && mVisibilitySupplier.get(); + } + /** Returns whether this manager has appended any messages. */ public static boolean hasAppendedMessagesForTesting() { return sAppendedMessagesForTesting;
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManagerUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManagerUnitTest.java index fb4c422..b47b0a7 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManagerUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManagerUnitTest.java
@@ -32,6 +32,7 @@ import org.chromium.base.supplier.LazyOneshotSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; +import org.chromium.base.supplier.Supplier; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; @@ -85,6 +86,8 @@ private final ObservableSupplierImpl<TabModelFilter> mCurrentTabModelFilterSupplier = new ObservableSupplierImpl<>(); + private boolean mVisible; + private final Supplier<Boolean> mVisibilitySupplier = () -> mVisible; private TabSwitcherMessageManager mMessageManager; private MockTab mTab1; @@ -107,6 +110,7 @@ doReturn(mTabModel).when(mTabModelFilter).getTabModel(); doReturn(mProfile).when(mTabModel).getProfile(); mCurrentTabModelFilterSupplier.set(mTabModelFilter); + mVisible = true; mActivityScenarioRule.getScenario().onActivity(this::onActivityReady); } @@ -124,6 +128,7 @@ mSnackbarManager, mModalDialogManager, mTabListCoordinator, + mVisibilitySupplier, LazyOneshotSupplier.fromValue(mTabListEditorController), mPriceWelcomeMessageReviewActionProvider, TabListMode.GRID); @@ -159,6 +164,13 @@ mMessageManager.afterReset(1); verify(mMessageUpdateObserver, times(2)).onRemoveAllAppendedMessage(); verify(mMessageUpdateObserver).onAppendedMessage(); + + mVisible = false; + + mMessageManager.afterReset(1); + verify(mMessageUpdateObserver, times(3)).onRemoveAllAppendedMessage(); + // Not incremented a second time. + verify(mMessageUpdateObserver).onAppendedMessage(); } @Test @@ -230,6 +242,15 @@ @Test @SmallTest + public void exitMultiWindowMode_NotVisible() { + mVisible = false; + mMultiWindowModeObserverCaptor.getValue().onMultiWindowModeChanged(false); + + verify(mMessageUpdateObserver, never()).onRestoreAllAppendedMessage(); + } + + @Test + @SmallTest public void removePriceWelcomeMessageWhenCloseBindingTab() { doReturn(1).when(mTabModel).getCount(); doReturn(TAB1_ID).when(mPriceMessageService).getBindingTabId();
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 a44cf4ad..3dea7cc2 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
@@ -45,7 +45,6 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab_ui.RecyclerViewPosition; import org.chromium.chrome.browser.tab_ui.TabSwitcherCustomViewManager; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; import org.chromium.chrome.tab_ui.R; import org.chromium.components.browser_ui.styles.ChromeColors; @@ -322,7 +321,7 @@ } @Override - public boolean resetWithTabs(@Nullable List<PseudoTab> tabs, boolean quickMode) { + public boolean resetWithTabs(@Nullable List<Tab> tabs, boolean quickMode) { assert false : "Not reached."; return true; }
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 856ed675..a7f3999 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
@@ -42,8 +42,7 @@ import org.chromium.chrome.browser.tabmodel.TabList; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelFilter; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab.TitleProvider; +import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator.DialogController; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; @@ -92,7 +91,6 @@ * @param regularTabModelSupplier The supplier of the regular tab model. * @param tabContentManager For management of thumbnails. * @param tabCreatorManager For creating new tabs. - * @param titleProvider The default title provider for tabs and tab groups. * @param browserControlsStateProvider For determining thumbnail size. * @param multiWindowModeStateDispatcher For managing behavior in multi-window. * @param scrimCoordinator The scrim coordinator to use for the tab grid dialog. @@ -115,7 +113,6 @@ @NonNull Supplier<TabModel> regularTabModelSupplier, @NonNull TabContentManager tabContentManager, @NonNull TabCreatorManager tabCreatorManager, - @NonNull TitleProvider titleProvider, @NonNull BrowserControlsStateProvider browserControlsStateProvider, @NonNull MultiWindowModeStateDispatcher multiWindowModeStateDispatcher, @NonNull ScrimCoordinator scrimCoordinator, @@ -209,7 +206,6 @@ tabModelFilterSupplier, regularTabModelSupplier, mMultiThumbnailCardProvider, - titleProvider, /* actionOnRelatedTabs= */ true, getGridCardOnClickListenerProvider(), /* dialogHandler= */ null, @@ -273,6 +269,7 @@ snackbarManager, modalDialogManager, tabListCoordinator, + isVisibleSupplier, tabListEditorControllerSupplier, /* priceWelcomeMessageReviewActionProvider= */ mMediator, mode); @@ -319,13 +316,14 @@ * @param tabList The {@link TabList} to show tabs for. */ public void resetWithTabList(@Nullable TabList tabList) { - var pseudoTabList = PseudoTab.getListOfPseudoTab(tabList); + List<Tab> tabs = TabModelUtils.convertTabListToListOfTabs(tabList); mMessageManager.beforeReset(); // Quick mode being false here ensures the selected tab's thumbnail gets updated. With Hub // the TabListCoordinator no longer triggers thumbnail captures so this shouldn't guard // against the large amount of work that is used to. - mTabListCoordinator.resetWithListOfTabs(pseudoTabList, /* quickMode= */ false); - mMessageManager.afterReset(pseudoTabList == null ? 0 : pseudoTabList.size()); + mTabListCoordinator.resetWithListOfTabs( + tabList == null ? null : tabs, /* quickMode= */ false); + mMessageManager.afterReset(tabs.size()); } /** Performs soft cleanup which removes thumbnails to relieve memory usage. */
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 d5a4c94..5f5c78c 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
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.tasks.tab_management; import android.app.Activity; -import android.content.Context; import android.view.ViewGroup; import androidx.annotation.NonNull; @@ -19,17 +18,12 @@ import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher; import org.chromium.chrome.browser.profiles.ProfileProvider; -import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab_ui.TabContentManager; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelFilter; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; -import org.chromium.chrome.browser.tabmodel.TabModelUtils; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab.TitleProvider; -import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.tab_ui.R; @@ -41,7 +35,6 @@ /** Holds dependencies for constructing a {@link TabSwitcherPane}. */ public class TabSwitcherPaneCoordinatorFactory { - private final TitleProvider mTitleProvider = this::getTitle; private final Activity mActivity; private final ActivityLifecycleDispatcher mLifecycleDispatcher; private final OneshotSupplier<ProfileProvider> mProfileProviderSupplier; @@ -132,7 +125,6 @@ () -> mTabModelSelector.getModel(false), mTabContentManager, mTabCreatorManager, - mTitleProvider, mBrowserControlsStateProvider, mMultiWindowModeStateDispatcher, mScrimCoordinator, @@ -157,23 +149,6 @@ return mMode; } - /** Returns the title of a tab or tab group for display in the tab switcher. */ - @VisibleForTesting - String getTitle(@NonNull Context context, @NonNull PseudoTab pseudoTab) { - assert mTabModelSelector.isTabStateInitialized(); - TabGroupModelFilter filter = - (TabGroupModelFilter) - mTabModelSelector - .getTabModelFilterProvider() - .getTabModelFilter(pseudoTab.isIncognito()); - Tab tab = TabModelUtils.getTabById(filter.getTabModel(), pseudoTab.getId()); - assert tab != null; - if (!filter.isTabInTabGroup(tab)) return tab.getTitle(); - - return TabGroupTitleEditor.getDefaultTitle( - context, filter.getRelatedTabCountForRootId(tab.getRootId())); - } - /** Returns a scrim coordinator to use for tab grid dialog on LFF devices. */ @VisibleForTesting static ScrimCoordinator createScrimCoordinatorForTablet(Activity activity) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java index 4cb5014..c58dd97 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java
@@ -45,7 +45,6 @@ import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; @@ -166,30 +165,6 @@ @Test @SmallTest - public void testGetTitle_Tab() { - when(mTabModelSelector.isTabStateInitialized()).thenReturn(true); - when(mTabModelFilter.isTabInTabGroup(mTab1)).thenReturn(false); - - PseudoTab tab1 = PseudoTab.fromTab(mTab1); - assertEquals(TAB1_TITLE, mFactory.getTitle(mActivity, tab1)); - } - - @Test - @SmallTest - public void testGetTitle_TabGroup() { - when(mTabModelSelector.isTabStateInitialized()).thenReturn(true); - when(mTabModelFilter.isTabInTabGroup(mTab1)).thenReturn(true); - int tabCount = 2; - when(mTabModelFilter.getRelatedTabCountForRootId(TAB1_ID)).thenReturn(tabCount); - - PseudoTab tab1 = PseudoTab.fromTab(mTab1); - assertEquals( - TabGroupTitleEditor.getDefaultTitle(mActivity, tabCount), - mFactory.getTitle(mActivity, tab1)); - } - - @Test - @SmallTest public void testCreateScrimCoordinatorForTablet() { assertNotNull(TabSwitcherPaneCoordinatorFactory.createScrimCoordinatorForTablet(mActivity)); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java index d69ec9a..26dff8b 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java
@@ -65,7 +65,6 @@ import org.chromium.chrome.browser.tab_ui.TabThumbnailView; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; import org.chromium.chrome.browser.tabmodel.TabModelFilter; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab.TitleProvider; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator.DialogController; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; @@ -106,7 +105,6 @@ @Mock private TabGroupModelFilter mTabModelFilter; @Mock private TabContentManager mTabContentManager; @Mock private TabCreatorManager mTabCreatorManager; - @Mock private TitleProvider mTitleProvider; @Mock private BrowserControlsStateProvider mBrowserControlsStateProvider; @Mock private MultiWindowModeStateDispatcher mMultiWindowModeStateDispatcher; @Mock private ScrimCoordinator mScrimCoordinator; @@ -181,7 +179,6 @@ () -> mTabModel, mTabContentManager, mTabCreatorManager, - mTitleProvider, mBrowserControlsStateProvider, mMultiWindowModeStateDispatcher, mScrimCoordinator,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherResetHandler.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherResetHandler.java index ad015a0..4befde2 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherResetHandler.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherResetHandler.java
@@ -6,8 +6,8 @@ import androidx.annotation.Nullable; +import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabList; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; import java.util.List; @@ -23,15 +23,15 @@ boolean resetWithTabList(@Nullable TabList tabList, boolean quickMode); /** - * Reset the tab grid with the given {@link List<PseudoTab>}, which can be null. + * Reset the tab grid with the given {@link List<Tab>}, which can be null. * - * @param tabs The {@link List<PseudoTab>} to show the tabs for in the grid. + * @param tabs The {@link List<Tab>} to show the tabs for in the grid. * @param quickMode Whether to skip capturing the selected live tab for the thumbnail. * @return Whether the {@link TabListRecyclerView} can be shown quickly. * @deprecated Use resetWithTabList instead to minimize the surface area of PseudoTab which * should be removed with instant start. See https://crbug.com/1413207. */ - boolean resetWithTabs(@Nullable List<PseudoTab> tabs, boolean quickMode); + boolean resetWithTabs(@Nullable List<Tab> tabs, boolean quickMode); /** * Release the thumbnail {@link Bitmap} but keep the {@link TabGridView}.
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java index 22452e9..c3ddf94 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
@@ -138,7 +138,6 @@ import org.chromium.chrome.browser.tab.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; -import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; @@ -1900,9 +1899,7 @@ finishActivity(sActivityTestRule.getActivity()); createThumbnailBitmapAndWriteToFile(0, mBrowserControlsStateProvider); createThumbnailBitmapAndWriteToFile(1, mBrowserControlsStateProvider); - TabAttributeCache.setRootIdForTesting(0, 0); - TabAttributeCache.setRootIdForTesting(1, 0); - createTabStatesAndMetadataFile(new int[] {0, 1}); + createTabStatesAndMetadataFile(new int[] {0, 1}, new int[] {0, 0}); // Restart Chrome and make sure tab strip is showing. sActivityTestRule.startMainActivityFromLauncher();
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiTest.java index 79d1a99e..ba3336a 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiTest.java
@@ -67,7 +67,6 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabModel; -import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.toolbar.bottom.BottomControlsCoordinator; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -292,9 +291,7 @@ finishActivity(sActivityTestRule.getActivity()); createThumbnailBitmapAndWriteToFile(0, mBrowserControlsStateProvider); createThumbnailBitmapAndWriteToFile(1, mBrowserControlsStateProvider); - TabAttributeCache.setRootIdForTesting(0, 0); - TabAttributeCache.setRootIdForTesting(1, 0); - createTabStatesAndMetadataFile(new int[] {0, 1}); + createTabStatesAndMetadataFile(new int[] {0, 1}, new int[] {0, 0}); // Restart Chrome and make sure tab strip is showing. sActivityTestRule.startMainActivityFromLauncher(); @@ -336,9 +333,7 @@ finishActivity(sActivityTestRule.getActivity()); createThumbnailBitmapAndWriteToFile(0, mBrowserControlsStateProvider); createThumbnailBitmapAndWriteToFile(1, mBrowserControlsStateProvider); - TabAttributeCache.setRootIdForTesting(0, 0); - TabAttributeCache.setRootIdForTesting(1, 0); - createTabStatesAndMetadataFile(new int[] {0, 1}); + createTabStatesAndMetadataFile(new int[] {0, 1}, new int[] {0, 0}); // Restart Chrome and make sure both tab strip and IPH text bubble are showing. sActivityTestRule.startMainActivityFromLauncher(); @@ -406,9 +401,7 @@ finishActivity(sActivityTestRule.getActivity()); createThumbnailBitmapAndWriteToFile(0, mBrowserControlsStateProvider); createThumbnailBitmapAndWriteToFile(1, mBrowserControlsStateProvider); - TabAttributeCache.setRootIdForTesting(0, 0); - TabAttributeCache.setRootIdForTesting(1, 0); - createTabStatesAndMetadataFile(new int[] {0, 1}); + createTabStatesAndMetadataFile(new int[] {0, 1}, new int[] {0, 0}); // Restart Chrome and make sure tab strip is showing. sActivityTestRule.startMainActivityFromLauncher();
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabUiTestHelper.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabUiTestHelper.java index b676e54..47594e7 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabUiTestHelper.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabUiTestHelper.java
@@ -79,7 +79,6 @@ import org.chromium.chrome.browser.tab_ui.TabThumbnailView; import org.chromium.chrome.browser.tab_ui.TabUiThemeUtils; import org.chromium.chrome.browser.tabmodel.TabModel; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.tab_ui.R; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; @@ -742,7 +741,6 @@ /** Finishes the given activity and do tab_ui-specific cleanup. */ public static void finishActivity(final Activity activity) throws Exception { ApplicationTestUtils.finishActivity(activity); - PseudoTab.clearForTesting(); } /**
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTabUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTabUnitTest.java deleted file mode 100644 index 542f350..0000000 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTabUnitTest.java +++ /dev/null
@@ -1,439 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.tasks.pseudotab; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.ContextUtils; -import org.chromium.base.Token; -import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.Features; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.tab.MockTab; -import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.browser.tabmodel.TabList; -import org.chromium.chrome.browser.tabmodel.TabModelFilter; -import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider; -import org.chromium.chrome.browser.tabmodel.TabModelSelector; -import org.chromium.chrome.browser.tasks.tab_management.TabUiUnitTestUtils; -import org.chromium.url.GURL; -import org.chromium.url.JUnitTestGURLs; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.stream.IntStream; - -/** Unit tests for {@link PseudoTab}. */ -@SuppressWarnings({"ResultOfMethodCallIgnored", "deprecation"}) -@RunWith(BaseRobolectricTestRunner.class) -public class PseudoTabUnitTest { - @Rule public TestRule mProcessor = new Features.JUnitProcessor(); - - private static final int TAB1_ID = 456; - private static final int TAB2_ID = 789; - private static final int TAB3_ID = 123; - private static final int TAB4_ID = 159; - - @Mock TabModelFilter mTabModelFilter; - @Mock TabModelFilter mTabModelFilter2; - @Mock TabModelSelector mTabModelSelector; - @Mock TabModelFilterProvider mTabModelFilterProvider; - @Mock Profile mProfile; - - private Tab mTab1; - private Tab mTab2; - private Tab mTab3; - private Tab mTab1Copy; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - mTab1 = TabUiUnitTestUtils.prepareTab(TAB1_ID); - mTab2 = TabUiUnitTestUtils.prepareTab(TAB2_ID); - mTab3 = TabUiUnitTestUtils.prepareTab(TAB3_ID); - mTab1Copy = TabUiUnitTestUtils.prepareTab(TAB1_ID); - - doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider(); - } - - @After - public void tearDown() { - PseudoTab.clearForTesting(); - } - - @Test - public void fromTabId() { - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(TAB1_ID, tab.getId()); - Assert.assertFalse(tab.hasRealTab()); - Assert.assertNull(tab.getTab()); - } - - @Test - public void fromTabId_cached() { - PseudoTab tab1 = PseudoTab.fromTabId(TAB1_ID); - PseudoTab tab2 = PseudoTab.fromTabId(TAB2_ID); - PseudoTab tab1prime = PseudoTab.fromTabId(TAB1_ID); - Assert.assertNotEquals(tab1, tab2); - Assert.assertEquals(tab1, tab1prime); - } - - @Test - public void fromTabId_threadSafety() throws InterruptedException { - final int count = 100000; - ExecutorService service = Executors.newCachedThreadPool(); - - IntStream.range(0, count) - .forEach(tabId -> service.submit(() -> PseudoTab.fromTabId(tabId))); - service.awaitTermination(1000, TimeUnit.MILLISECONDS); - - Assert.assertEquals(count, PseudoTab.getAllTabsCountForTests()); - } - - @Test - public void fromTab() { - PseudoTab tab = PseudoTab.fromTab(mTab1); - Assert.assertEquals(TAB1_ID, tab.getId()); - Assert.assertTrue(tab.hasRealTab()); - Assert.assertEquals(mTab1, tab.getTab()); - } - - @Test - public void fromTab_cached() { - PseudoTab tab1 = PseudoTab.fromTab(mTab1); - PseudoTab tab2 = PseudoTab.fromTab(mTab2); - PseudoTab tab1prime = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab1, tab2); - Assert.assertEquals(tab1, tab1prime); - } - - @Test - public void fromTab_obsoleteCache() { - PseudoTab tab1 = PseudoTab.fromTab(mTab1); - PseudoTab tab1copy = PseudoTab.fromTab(mTab1Copy); - Assert.assertNotEquals(tab1, tab1copy); - Assert.assertEquals(tab1.getId(), tab1copy.getId()); - } - - @Test - public void fromTab_cached_upgrade() { - PseudoTab tab1 = PseudoTab.fromTabId(TAB1_ID); - Assert.assertFalse(tab1.hasRealTab()); - - PseudoTab tab1upgraded = PseudoTab.fromTab(mTab1); - Assert.assertTrue(tab1upgraded.hasRealTab()); - - Assert.assertNotEquals(tab1, tab1upgraded); - - PseudoTab tab1prime = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(tab1upgraded, tab1prime); - } - - @Test - public void getListOfPseudoTab_listOfTab() { - List<PseudoTab> list = PseudoTab.getListOfPseudoTab(Arrays.asList(mTab1, mTab2)); - Assert.assertEquals(2, list.size()); - Assert.assertEquals(TAB1_ID, list.get(0).getId()); - Assert.assertEquals(TAB2_ID, list.get(1).getId()); - } - - @Test - public void getListOfPseudoTab_listOfTab_null() { - List<PseudoTab> list = PseudoTab.getListOfPseudoTab((List<Tab>) null); - Assert.assertNull(list); - } - - @Test - public void getListOfPseudoTab_TabList() { - doReturn(mTab1).when(mTabModelFilter).getTabAt(0); - doReturn(mTab2).when(mTabModelFilter).getTabAt(1); - doReturn(mTab3).when(mTabModelFilter).getTabAt(2); - doReturn(3).when(mTabModelFilter).getCount(); - - List<PseudoTab> list = PseudoTab.getListOfPseudoTab(mTabModelFilter); - Assert.assertEquals(3, list.size()); - Assert.assertEquals(TAB1_ID, list.get(0).getId()); - Assert.assertEquals(TAB2_ID, list.get(1).getId()); - Assert.assertEquals(TAB3_ID, list.get(2).getId()); - } - - @Test - public void getListOfPseudoTab_TabList_null() { - List<PseudoTab> list = PseudoTab.getListOfPseudoTab((TabList) null); - Assert.assertNull(list); - } - - @Test - public void testToString() { - Assert.assertEquals("Tab 456", PseudoTab.fromTabId(TAB1_ID).toString()); - } - - @Test - public void getTitle_provider() { - String title = "title provider"; - PseudoTab.TitleProvider provider = (context, tab) -> title; - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(title, tab.getTitle(ContextUtils.getApplicationContext(), provider)); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertEquals( - title, realTab.getTitle(ContextUtils.getApplicationContext(), provider)); - } - - @Test - public void getTitle_nullProvider() { - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals( - tab.getTitle(), tab.getTitle(ContextUtils.getApplicationContext(), null)); - } - - @Test - public void getTitle_realTab() { - String title = "title 1 real"; - doReturn(title).when(mTab1).getTitle(); - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals("", tab.getTitle()); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertEquals(title, realTab.getTitle()); - } - - @Test - public void getTitle_cache() { - String title = "title 1"; - TabAttributeCache.setTitleForTesting(TAB1_ID, title); - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(title, tab.getTitle()); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertNull(realTab.getTitle()); - } - - @Test - public void getUrl_real() { - GURL url = JUnitTestGURLs.EXAMPLE_URL; - doReturn(url).when(mTab1).getUrl(); - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(GURL.emptyGURL(), tab.getUrl()); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertEquals(url, realTab.getUrl()); - } - - @Test - public void getUrl_cache() { - TabAttributeCache.setUrlForTesting(TAB1_ID, JUnitTestGURLs.URL_1); - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(JUnitTestGURLs.URL_1.getSpec(), tab.getUrl().getSpec()); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertNull(realTab.getUrl()); - } - - @Test - public void getRootId_real() { - int rootId = 1337; - doReturn(rootId).when(mTab1).getRootId(); - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(Tab.INVALID_TAB_ID, tab.getRootId()); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertEquals(rootId, realTab.getRootId()); - } - - @Test - public void getRootId_cache() { - int rootId = 42; - TabAttributeCache.setRootIdForTesting(TAB1_ID, rootId); - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(rootId, tab.getRootId()); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertNotEquals(rootId, realTab.getRootId()); - } - - @Test - public void getTabGroupId_real() { - Token tabGroupId = new Token(123L, 456L); - doReturn(tabGroupId).when(mTab1).getTabGroupId(); - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(null, tab.getTabGroupId()); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertEquals(tabGroupId, realTab.getTabGroupId()); - } - - @Test - public void getTabGroupId_cache() { - Token tabGroupId = new Token(1L, 4L); - TabAttributeCache.setTabGroupIdForTesting(TAB1_ID, tabGroupId); - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(tabGroupId, tab.getTabGroupId()); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertNotEquals(tabGroupId, realTab.getTabGroupId()); - } - - @Test - public void getTimestampMillis_real() { - long timestamp = 12345; - doReturn(timestamp).when(mTab1).getTimestampMillis(); - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(Tab.INVALID_TIMESTAMP, tab.getTimestampMillis()); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertEquals(timestamp, realTab.getTimestampMillis()); - } - - @Test - public void getTimestampMillis_cache() { - long timestamp = 42; - TabAttributeCache.setTimestampMillisForTesting(TAB1_ID, timestamp); - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertEquals(timestamp, tab.getTimestampMillis()); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertNotEquals(timestamp, realTab.getTimestampMillis()); - } - - @Test - public void isIncognito() { - doReturn(true).when(mTab1).isIncognito(); - - PseudoTab tab = PseudoTab.fromTabId(TAB1_ID); - Assert.assertFalse(tab.isIncognito()); - - PseudoTab realTab = PseudoTab.fromTab(mTab1); - Assert.assertNotEquals(tab, realTab); - Assert.assertTrue(realTab.isIncognito()); - - doReturn(false).when(mTab1).isIncognito(); - Assert.assertFalse(realTab.isIncognito()); - } - - @Test - public void getRelatedTabs_provider_normal() { - doReturn(true).when(mTabModelSelector).isTabStateInitialized(); - doReturn(mTabModelFilter).when(mTabModelFilterProvider).getTabModelFilter(eq(false)); - List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2, mTab3)); - doReturn(tabs).when(mTabModelFilter).getRelatedTabList(TAB1_ID); - - PseudoTab tab1 = PseudoTab.fromTabId(TAB1_ID); - List<PseudoTab> related = - PseudoTab.getRelatedTabs( - ContextUtils.getApplicationContext(), tab1, mTabModelSelector); - Assert.assertEquals(3, related.size()); - Assert.assertEquals(TAB1_ID, related.get(0).getId()); - Assert.assertEquals(TAB2_ID, related.get(1).getId()); - Assert.assertEquals(TAB3_ID, related.get(2).getId()); - } - - @Test - public void getRelatedTabs_provider_incognito() { - doReturn(true).when(mTabModelSelector).isTabStateInitialized(); - doReturn(mTabModelFilter).when(mTabModelFilterProvider).getTabModelFilter(eq(false)); - List<Tab> empty = new ArrayList<>(); - doReturn(empty).when(mTabModelFilter).getRelatedTabList(TAB1_ID); - doReturn(mTabModelFilter2).when(mTabModelFilterProvider).getTabModelFilter(eq(true)); - List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2)); - doReturn(tabs).when(mTabModelFilter2).getRelatedTabList(TAB1_ID); - - PseudoTab tab1 = PseudoTab.fromTabId(TAB1_ID); - List<PseudoTab> related = - PseudoTab.getRelatedTabs( - ContextUtils.getApplicationContext(), tab1, mTabModelSelector); - Assert.assertEquals(2, related.size()); - Assert.assertEquals(TAB1_ID, related.get(0).getId()); - Assert.assertEquals(TAB2_ID, related.get(1).getId()); - } - - @Test - public void testTabDestroyedTitle() { - Tab tab = new MockTab(TAB4_ID, mProfile); - PseudoTab pseudoTab = PseudoTab.fromTab(tab); - tab.destroy(); - // Title was not set. Without the isInitialized() check, - // pseudoTab.getTitle() would crash here with UnsupportedOperationException - Assert.assertEquals("", pseudoTab.getTitle()); - } - - @Test - public void testTabDestroyedUrl() { - Tab tab = new MockTab(TAB4_ID, mProfile); - PseudoTab pseudoTab = PseudoTab.fromTab(tab); - tab.destroy(); - // Url was not set. Without the isInitialized() check, - // pseudoTab.getUrl() would crash here with UnsupportedOperationException - Assert.assertEquals("", pseudoTab.getUrl().getSpec()); - } - - @Test - public void testTabDestroyedRootId() { - Tab tab = new MockTab(TAB4_ID, mProfile); - PseudoTab pseudoTab = PseudoTab.fromTab(tab); - tab.destroy(); - // Root ID was not set. Without the isInitialized() check, - // pseudoTab.getRootId() would crash here with UnsupportedOperationException - Assert.assertEquals(Tab.INVALID_TAB_ID, pseudoTab.getRootId()); - } - - @Test - public void testTabDestroyedTimestamp() { - Tab tab = new MockTab(TAB4_ID, mProfile); - PseudoTab pseudoTab = PseudoTab.fromTab(tab); - tab.destroy(); - // Timestamp was not set. Without the isInitialized() check, - // pseudoTab.getTimestampMillis() would crash here with - // UnsupportedOperationException - Assert.assertEquals(Tab.INVALID_TIMESTAMP, pseudoTab.getTimestampMillis()); - } - - @Test - public void testTabIsClosingOrDestroyed_Destroyed() { - Tab tab = new MockTab(TAB4_ID, mProfile); - PseudoTab pseudoTab = PseudoTab.fromTab(tab); - Assert.assertFalse(pseudoTab.isClosingOrDestroyed()); - tab.destroy(); - Assert.assertTrue(pseudoTab.isClosingOrDestroyed()); - } -}
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCacheUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCacheUnitTest.java deleted file mode 100644 index 787cceb..0000000 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCacheUnitTest.java +++ /dev/null
@@ -1,438 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.tasks.pseudotab; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; - -import org.chromium.base.Token; -import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.Features; -import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.profiles.ProfileJni; -import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory; -import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.browser.tabmodel.TabModel; -import org.chromium.chrome.browser.tabmodel.TabModelFilter; -import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider; -import org.chromium.chrome.browser.tabmodel.TabModelObserver; -import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; -import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; -import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; -import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache.LastSearchTermProvider; -import org.chromium.chrome.browser.tasks.tab_management.TabUiUnitTestUtils; -import org.chromium.components.search_engines.TemplateUrlService; -import org.chromium.content_public.browser.NavigationController; -import org.chromium.content_public.browser.NavigationEntry; -import org.chromium.content_public.browser.NavigationHandle; -import org.chromium.content_public.browser.NavigationHistory; -import org.chromium.content_public.browser.WebContents; -import org.chromium.url.GURL; -import org.chromium.url.JUnitTestGURLs; - -import java.util.ArrayList; -import java.util.List; - -/** Unit tests for {@link TabAttributeCache}. */ -@SuppressWarnings("ResultOfMethodCallIgnored") -@RunWith(BaseRobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class TabAttributeCacheUnitTest { - @Rule public TestRule mProcessor = new Features.JUnitProcessor(); - @Rule public JniMocker jniMocker = new JniMocker(); - - private static final int TAB1_ID = 456; - private static final int TAB2_ID = 789; - private static final int POSITION1 = 0; - private static final int POSITION2 = 1; - - @Mock TabModelSelectorImpl mTabModelSelector; - @Mock TabModelFilterProvider mTabModelFilterProvider; - @Mock TabModelFilter mTabModelFilter; - @Mock TabModel mTabModel; - @Captor ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; - @Captor ArgumentCaptor<TabModelSelectorObserver> mTabModelSelectorObserverCaptor; - @Captor ArgumentCaptor<TabModelSelectorTabObserver> mTabObserverCaptor; - @Mock Profile.Natives mProfileJniMock; - - private Tab mTab1; - private Tab mTab2; - private TabAttributeCache mCache; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - jniMocker.mock(ProfileJni.TEST_HOOKS, mProfileJniMock); - - mTab1 = TabUiUnitTestUtils.prepareTab(TAB1_ID); - mTab2 = TabUiUnitTestUtils.prepareTab(TAB2_ID); - - List<TabModel> tabModelList = new ArrayList<>(); - tabModelList.add(mTabModel); - - doReturn(tabModelList).when(mTabModelSelector).getModels(); - doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider(); - doReturn(mTabModelFilter).when(mTabModelFilterProvider).getTabModelFilter(eq(false)); - - doNothing().when(mTabModelFilter).addObserver(mTabModelObserverCaptor.capture()); - - doNothing().when(mTabModelSelector).addObserver(mTabModelSelectorObserverCaptor.capture()); - - doReturn(mTab1).when(mTabModel).getTabAt(POSITION1); - doReturn(mTab2).when(mTabModel).getTabAt(POSITION2); - doReturn(POSITION1).when(mTabModel).indexOf(mTab1); - doReturn(POSITION2).when(mTabModel).indexOf(mTab2); - doNothing().when(mTab1).addObserver(mTabObserverCaptor.capture()); - doNothing().when(mTab2).addObserver(mTabObserverCaptor.capture()); - doReturn(0).when(mTabModel).index(); - doReturn(2).when(mTabModel).getCount(); - doReturn(mTabModel).when(mTabModel).getComprehensiveModel(); - - mCache = new TabAttributeCache(mTabModelSelector); - } - - @After - public void tearDown() { - mCache.destroy(); - } - - @Test - public void updateUrl() { - GURL url = JUnitTestGURLs.EXAMPLE_URL; - doReturn(url).when(mTab1).getUrl(); - - Assert.assertNotEquals(url, TabAttributeCache.getUrl(TAB1_ID)); - - mTabObserverCaptor.getValue().onUrlUpdated(mTab1); - Assert.assertEquals(url, TabAttributeCache.getUrl(TAB1_ID)); - - mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); - mTabModelObserverCaptor.getValue().tabClosureCommitted(mTab1); - Assert.assertNotEquals(url, TabAttributeCache.getUrl(TAB1_ID)); - } - - @Test - public void updateUrl_incognito() { - GURL url = JUnitTestGURLs.EXAMPLE_URL; - doReturn(url).when(mTab1).getUrl(); - doReturn(true).when(mTab1).isIncognito(); - - mTabObserverCaptor.getValue().onUrlUpdated(mTab1); - Assert.assertNotEquals(url.getSpec(), TabAttributeCache.getUrl(TAB1_ID)); - } - - @Test - public void updateTitle() { - String title = "title 1"; - doReturn(title).when(mTab1).getTitle(); - - Assert.assertNotEquals(title, TabAttributeCache.getTitle(TAB1_ID)); - - mTabObserverCaptor.getValue().onTitleUpdated(mTab1); - Assert.assertEquals(title, TabAttributeCache.getTitle(TAB1_ID)); - - mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); - mTabModelObserverCaptor.getValue().tabClosureCommitted(mTab1); - Assert.assertNotEquals(title, TabAttributeCache.getTitle(TAB1_ID)); - } - - @Test - public void updateTitle_incognito() { - String title = "title 1"; - doReturn(title).when(mTab1).getTitle(); - doReturn(true).when(mTab1).isIncognito(); - - mTabObserverCaptor.getValue().onTitleUpdated(mTab1); - Assert.assertNotEquals(title, TabAttributeCache.getTitle(TAB1_ID)); - } - - @Test - public void updateRootId() { - int rootId = 1337; - doReturn(rootId).when(mTab1).getRootId(); - - Assert.assertNotEquals(rootId, TabAttributeCache.getRootId(TAB1_ID)); - - mTabObserverCaptor.getValue().onRootIdChanged(mTab1, rootId); - Assert.assertEquals(rootId, TabAttributeCache.getRootId(TAB1_ID)); - - mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); - mTabModelObserverCaptor.getValue().tabClosureCommitted(mTab1); - Assert.assertNotEquals(rootId, TabAttributeCache.getRootId(TAB1_ID)); - } - - @Test - public void updateRootId_incognito() { - int rootId = 1337; - doReturn(rootId).when(mTab1).getRootId(); - doReturn(true).when(mTab1).isIncognito(); - - mTabObserverCaptor.getValue().onRootIdChanged(mTab1, rootId); - Assert.assertNotEquals(rootId, TabAttributeCache.getRootId(TAB1_ID)); - } - - @Test - public void updateTabGroupId() { - Token tabGroupId = new Token(0x1337L, 0xBADL); - doReturn(tabGroupId).when(mTab1).getTabGroupId(); - - Assert.assertNull(TabAttributeCache.getTabGroupId(TAB1_ID)); - - // 1. Set token. - mTabObserverCaptor.getValue().onTabGroupIdChanged(mTab1, tabGroupId); - Assert.assertEquals(tabGroupId, TabAttributeCache.getTabGroupId(TAB1_ID)); - - // 2. Null token. - doReturn(null).when(mTab1).getTabGroupId(); - mTabObserverCaptor.getValue().onTabGroupIdChanged(mTab1, null); - Assert.assertNull(TabAttributeCache.getTabGroupId(TAB1_ID)); - - // 3. Set token. - doReturn(tabGroupId).when(mTab1).getTabGroupId(); - mTabObserverCaptor.getValue().onTabGroupIdChanged(mTab1, tabGroupId); - Assert.assertEquals(tabGroupId, TabAttributeCache.getTabGroupId(TAB1_ID)); - - // 4. Delete on close tab. - mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); - mTabModelObserverCaptor.getValue().tabClosureCommitted(mTab1); - Assert.assertNull(TabAttributeCache.getTabGroupId(TAB1_ID)); - } - - @Test - public void updateTabGroupId_incognito() { - Token tabGroupId = new Token(0x1337L, 0xBADL); - doReturn(tabGroupId).when(mTab1).getTabGroupId(); - doReturn(true).when(mTab1).isIncognito(); - - mTabObserverCaptor.getValue().onTabGroupIdChanged(mTab1, tabGroupId); - Assert.assertNull(TabAttributeCache.getTabGroupId(TAB1_ID)); - } - - @Test - public void updateTimestamp() { - long timestamp = 1337; - doReturn(timestamp).when(mTab1).getTimestampMillis(); - - Assert.assertNotEquals(timestamp, TabAttributeCache.getTimestampMillis(TAB1_ID)); - - mTabObserverCaptor.getValue().onTimestampChanged(mTab1, timestamp); - Assert.assertEquals(timestamp, TabAttributeCache.getTimestampMillis(TAB1_ID)); - - mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); - mTabModelObserverCaptor.getValue().tabClosureCommitted(mTab1); - Assert.assertNotEquals(timestamp, TabAttributeCache.getTimestampMillis(TAB1_ID)); - } - - @Test - public void updateTimestamp_incognito() { - long timestamp = 1337; - doReturn(timestamp).when(mTab1).getTimestampMillis(); - doReturn(true).when(mTab1).isIncognito(); - - mTabObserverCaptor.getValue().onTimestampChanged(mTab1, timestamp); - Assert.assertNotEquals(timestamp, TabAttributeCache.getTimestampMillis(TAB1_ID)); - } - - @Test - public void updateLastSearchTerm() { - String searchTerm = "chromium"; - - LastSearchTermProvider lastSearchTermProvider = mock(LastSearchTermProvider.class); - TabAttributeCache.setLastSearchTermMockForTesting(lastSearchTermProvider); - NavigationHandle navigationHandle = mock(NavigationHandle.class); - - Assert.assertNull(TabAttributeCache.getLastSearchTerm(TAB1_ID)); - - doReturn(searchTerm).when(lastSearchTermProvider).getLastSearchTerm(mTab1); - WebContents webContents = mock(WebContents.class); - doReturn(webContents).when(mTab1).getWebContents(); - - mTabObserverCaptor - .getValue() - .onDidFinishNavigationInPrimaryMainFrame(mTab1, navigationHandle); - Assert.assertEquals(searchTerm, TabAttributeCache.getLastSearchTerm(TAB1_ID)); - - // Empty strings should propagate. - doReturn("").when(lastSearchTermProvider).getLastSearchTerm(mTab1); - mTabObserverCaptor - .getValue() - .onDidFinishNavigationInPrimaryMainFrame(mTab1, navigationHandle); - Assert.assertEquals("", TabAttributeCache.getLastSearchTerm(TAB1_ID)); - - // Null should also propagate. - doReturn(null).when(lastSearchTermProvider).getLastSearchTerm(mTab1); - mTabObserverCaptor - .getValue() - .onDidFinishNavigationInPrimaryMainFrame(mTab1, navigationHandle); - Assert.assertNull(TabAttributeCache.getLastSearchTerm(TAB1_ID)); - - mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); - mTabModelObserverCaptor.getValue().tabClosureCommitted(mTab1); - Assert.assertNull(TabAttributeCache.getLastSearchTerm(TAB1_ID)); - } - - @Test - public void updateLastSearchTerm_incognito() { - String searchTerm = "chromium"; - doReturn(true).when(mTab1).isIncognito(); - - LastSearchTermProvider lastSearchTermProvider = mock(LastSearchTermProvider.class); - TabAttributeCache.setLastSearchTermMockForTesting(lastSearchTermProvider); - doReturn(searchTerm).when(lastSearchTermProvider).getLastSearchTerm(mTab1); - - mTabObserverCaptor.getValue().onDidFinishNavigationInPrimaryMainFrame(mTab1, null); - Assert.assertNull(TabAttributeCache.getLastSearchTerm(TAB1_ID)); - } - - @Test - public void findLastSearchTerm() { - GURL otherUrl = JUnitTestGURLs.EXAMPLE_URL; - GURL searchUrl = JUnitTestGURLs.SEARCH_URL; - String searchTerm = "test"; - GURL searchUrl2 = JUnitTestGURLs.SEARCH_2_URL; - String searchTerm2 = "query"; - - TemplateUrlService service = Mockito.mock(TemplateUrlService.class); - doReturn(null).when(service).getSearchQueryForUrl(otherUrl); - doReturn(searchTerm).when(service).getSearchQueryForUrl(searchUrl); - doReturn(searchTerm2).when(service).getSearchQueryForUrl(searchUrl2); - TemplateUrlServiceFactory.setInstanceForTesting(service); - - WebContents webContents = mock(WebContents.class); - doReturn(webContents).when(mTab1).getWebContents(); - when(mProfileJniMock.fromWebContents(eq(webContents))).thenReturn(mock(Profile.class)); - NavigationController navigationController = mock(NavigationController.class); - doReturn(navigationController).when(webContents).getNavigationController(); - NavigationHistory navigationHistory = mock(NavigationHistory.class); - doReturn(navigationHistory).when(navigationController).getNavigationHistory(); - doReturn(2).when(navigationHistory).getCurrentEntryIndex(); - NavigationEntry navigationEntry1 = mock(NavigationEntry.class); - NavigationEntry navigationEntry0 = mock(NavigationEntry.class); - doReturn(navigationEntry1).when(navigationHistory).getEntryAtIndex(1); - doReturn(navigationEntry0).when(navigationHistory).getEntryAtIndex(0); - doReturn(otherUrl).when(mTab1).getUrl(); - - // No searches. - doReturn(otherUrl).when(navigationEntry1).getOriginalUrl(); - doReturn(otherUrl).when(navigationEntry0).getOriginalUrl(); - Assert.assertNull(TabAttributeCache.findLastSearchTerm(mTab1)); - - // Has SRP. - doReturn(searchUrl).when(navigationEntry1).getOriginalUrl(); - doReturn(otherUrl).when(navigationEntry0).getOriginalUrl(); - Assert.assertEquals(searchTerm, TabAttributeCache.findLastSearchTerm(mTab1)); - - // Has earlier SRP. - doReturn(otherUrl).when(navigationEntry1).getOriginalUrl(); - doReturn(searchUrl2).when(navigationEntry0).getOriginalUrl(); - Assert.assertEquals(searchTerm2, TabAttributeCache.findLastSearchTerm(mTab1)); - - // Latest one wins. - doReturn(searchUrl).when(navigationEntry1).getOriginalUrl(); - doReturn(searchUrl2).when(navigationEntry0).getOriginalUrl(); - Assert.assertEquals(searchTerm, TabAttributeCache.findLastSearchTerm(mTab1)); - - // Only care about previous ones. - doReturn(1).when(navigationHistory).getCurrentEntryIndex(); - Assert.assertEquals(searchTerm2, TabAttributeCache.findLastSearchTerm(mTab1)); - - // Skip if the SRP is showing. - doReturn(2).when(navigationHistory).getCurrentEntryIndex(); - doReturn(searchUrl).when(mTab1).getUrl(); - Assert.assertNull(TabAttributeCache.findLastSearchTerm(mTab1)); - - // Reset current SRP. - doReturn(otherUrl).when(mTab1).getUrl(); - Assert.assertEquals(searchTerm, TabAttributeCache.findLastSearchTerm(mTab1)); - - verify(navigationHistory, never()).getEntryAtIndex(eq(2)); - } - - @Test - public void removeEscapedCodePoints() { - Assert.assertEquals("", TabAttributeCache.removeEscapedCodePoints("")); - Assert.assertEquals("", TabAttributeCache.removeEscapedCodePoints("%0a")); - Assert.assertEquals("", TabAttributeCache.removeEscapedCodePoints("%0A")); - Assert.assertEquals("AB", TabAttributeCache.removeEscapedCodePoints("A%FE%FFB")); - Assert.assertEquals("a%0", TabAttributeCache.removeEscapedCodePoints("a%0")); - Assert.assertEquals("%", TabAttributeCache.removeEscapedCodePoints("%%00")); - Assert.assertEquals("%0G", TabAttributeCache.removeEscapedCodePoints("%0G")); - Assert.assertEquals("abcc", TabAttributeCache.removeEscapedCodePoints("abc%abc")); - Assert.assertEquals("a%a", TabAttributeCache.removeEscapedCodePoints("a%bc%a%bc")); - } - - @Test - public void onTabStateInitialized() { - GURL url1 = JUnitTestGURLs.EXAMPLE_URL; - doReturn(url1).when(mTab1).getUrl(); - String title1 = "title 1"; - doReturn(title1).when(mTab1).getTitle(); - int rootId1 = 1337; - doReturn(rootId1).when(mTab1).getRootId(); - long timestamp1 = 123456; - doReturn(timestamp1).when(mTab1).getTimestampMillis(); - - GURL url2 = JUnitTestGURLs.URL_2; - doReturn(url2).when(mTab2).getUrl(); - String title2 = "title 2"; - doReturn(title2).when(mTab2).getTitle(); - int rootId2 = 42; - doReturn(rootId2).when(mTab2).getRootId(); - - String searchTerm = "chromium"; - LastSearchTermProvider lastSearchTermProvider = mock(LastSearchTermProvider.class); - TabAttributeCache.setLastSearchTermMockForTesting(lastSearchTermProvider); - doReturn(searchTerm).when(lastSearchTermProvider).getLastSearchTerm(mTab1); - WebContents webContents = mock(WebContents.class); - doReturn(webContents).when(mTab1).getWebContents(); - - doReturn(mTab1).when(mTabModelFilter).getTabAt(0); - doReturn(mTab2).when(mTabModelFilter).getTabAt(1); - doReturn(2).when(mTabModelFilter).getCount(); - doReturn(mTab1).when(mTabModelSelector).getCurrentTab(); - - Assert.assertNotEquals(url1, TabAttributeCache.getUrl(TAB1_ID)); - Assert.assertNotEquals(title1, TabAttributeCache.getTitle(TAB1_ID)); - Assert.assertNotEquals(rootId1, TabAttributeCache.getRootId(TAB1_ID)); - Assert.assertNotEquals(timestamp1, TabAttributeCache.getTimestampMillis(TAB1_ID)); - Assert.assertNotEquals(searchTerm, TabAttributeCache.getLastSearchTerm(TAB1_ID)); - - Assert.assertNotEquals(url2, TabAttributeCache.getUrl(TAB2_ID)); - Assert.assertNotEquals(title2, TabAttributeCache.getTitle(TAB2_ID)); - Assert.assertNotEquals(rootId2, TabAttributeCache.getRootId(TAB2_ID)); - - mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); - - Assert.assertEquals(url1, TabAttributeCache.getUrl(TAB1_ID)); - Assert.assertEquals(title1, TabAttributeCache.getTitle(TAB1_ID)); - Assert.assertEquals(rootId1, TabAttributeCache.getRootId(TAB1_ID)); - Assert.assertEquals(timestamp1, TabAttributeCache.getTimestampMillis(TAB1_ID)); - Assert.assertEquals(searchTerm, TabAttributeCache.getLastSearchTerm(TAB1_ID)); - - Assert.assertEquals(url2, TabAttributeCache.getUrl(TAB2_ID)); - Assert.assertEquals(title2, TabAttributeCache.getTitle(TAB2_ID)); - Assert.assertEquals(rootId2, TabAttributeCache.getRootId(TAB2_ID)); - } -}
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java index cf120cef..ba3266a 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -128,7 +128,6 @@ import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelFilter; import org.chromium.chrome.browser.tabmodel.TabModelObserver; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupColorUtils; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilterObserver; @@ -281,7 +280,6 @@ @Mock GridLayoutManager.SpanSizeLookup mSpanSizeLookup; @Mock Profile mProfile; @Mock Tracker mTracker; - @Mock PseudoTab.TitleProvider mTitleProvider; @Mock UrlUtilities.Natives mUrlUtilitiesJniMock; @Mock OptimizationGuideBridgeFactory.Natives mOptimizationGuideBridgeFactoryJniMock; @Mock OptimizationGuideBridge mOptimizationGuideBridge; @@ -463,7 +461,6 @@ @After public void tearDown() { - PseudoTab.clearForTesting(); ProfileManager.resetForTesting(); } @@ -483,16 +480,28 @@ } @Test - public void updatesTitle_WithoutStoredTitle() { + public void updatesTitle_WithoutStoredTitle_Tab() { assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(TAB1_TITLE)); - when(mTitleProvider.getTitle(mActivity, PseudoTab.fromTab(mTab1))).thenReturn(NEW_TITLE); + when(mTab1.getTitle()).thenReturn(NEW_TITLE); mTabObserver.onTitleUpdated(mTab1); assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(NEW_TITLE)); } @Test + public void updatesTitle_WithoutStoredTitle_TabGroup() { + Tab newTab = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL); + List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, newTab)); + createTabGroup(tabs, TAB1_ID, TAB_GROUP_ID); + + mMediator.resetWithListOfTabs(tabs, false); + + String defaultTitle = TabGroupTitleEditor.getDefaultTitle(mActivity, tabs.size()); + assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(defaultTitle)); + } + + @Test public void updatesTitle_WithStoredTitle_TabGroup() { // Mock that tab1 and new tab are in the same group with root ID as TAB1_ID. Tab newTab = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL); @@ -789,8 +798,7 @@ public void sendsOpenGroupSignalCorrectly_SingleTabGroup() { List<Tab> tabs = Arrays.asList(mTab1); createTabGroup(tabs, TAB1_ID, TAB_GROUP_ID); - mMediator.resetWithListOfTabs( - PseudoTab.getListOfPseudoTab(Arrays.asList(mTab1, mTab2)), false); + mMediator.resetWithListOfTabs(Arrays.asList(mTab1, mTab2), false); mModel.get(0) .model .get(TabProperties.TAB_SELECTED_LISTENER) @@ -803,8 +811,7 @@ public void sendsOpenGroupSignalCorrectly_TabGroup() { List<Tab> tabs = Arrays.asList(mTab1, mTab2); createTabGroup(tabs, TAB1_ID, TAB_GROUP_ID); - mMediator.resetWithListOfTabs( - PseudoTab.getListOfPseudoTab(Arrays.asList(mTab1, mTab2)), false); + mMediator.resetWithListOfTabs(Arrays.asList(mTab1, mTab2), false); mModel.get(0) .model .get(TabProperties.TAB_SELECTED_LISTENER) @@ -874,7 +881,7 @@ RecyclerView.ViewHolder fakeViewHolder4 = prepareFakeViewHolder(itemView4, 3); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2, tab3, tab4)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(4)); // Merge 2 to 1. @@ -1211,7 +1218,6 @@ mCurrentTabModelFilterSupplier, () -> mTabModel, getTabThumbnailCallback(), - mTitleProvider, mTabListFaviconProvider, mTabGroupColorFaviconProvider, true, @@ -1300,7 +1306,7 @@ assertThat(mModel.size(), equalTo(1)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB1_ID)); - assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(TAB1_TITLE)); + assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo("2 tabs")); assertNull(mModel.get(0).model.get(TabProperties.FAVICON_FETCHER)); } @@ -1343,7 +1349,7 @@ createTabGroup(List.of(mTab1), TAB1_ID, TAB_GROUP_ID); setUpTabListMediator(TabListMediatorType.TAB_GRID_DIALOG, TabListMode.GRID); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(Arrays.asList(mTab1)), false); + mMediator.resetWithListOfTabs(Arrays.asList(mTab1), false); assertThat(mModel.size(), equalTo(1)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB1_ID)); @@ -1368,7 +1374,7 @@ createTabGroup(List.of(mTab1), TAB1_ID, TAB_GROUP_ID); setUpTabListMediator(TabListMediatorType.TAB_GRID_DIALOG, TabListMode.GRID); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(Arrays.asList(mTab1)), false); + mMediator.resetWithListOfTabs(Arrays.asList(mTab1), false); assertThat(mModel.size(), equalTo(1)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB1_ID)); @@ -1389,7 +1395,7 @@ public void tabMoveOutOfGroup_GTS_Moved_Tab_Selected() { // Assume that two tabs are in the same group before ungroup. List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab2)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(1)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); @@ -1418,7 +1424,7 @@ public void tabMoveOutOfGroup_GTS_Origin_Tab_Selected() { // Assume that two tabs are in the same group before ungroup. List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(1)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB1_ID)); @@ -1444,7 +1450,7 @@ public void tabMoveOutOfGroup_GTS_LastTab() { // Assume that tab1 is a single tab group that became a single tab. List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); doReturn(1).when(mTabGroupModelFilter).getCount(); doReturn(mTab1).when(mTabGroupModelFilter).getTabAt(POSITION1); doReturn(tabs).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID); @@ -1466,7 +1472,7 @@ public void tabMoveOutOfGroup_GTS_TabAdditionWithSameId() { // Assume that two tabs are in the same group before ungroup. List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(1)); assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB1_ID)); @@ -1590,7 +1596,7 @@ List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2)); doReturn(false).when(mTab1).isIncognito(); doReturn(false).when(mTab2).isIncognito(); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); } @Test @@ -1620,7 +1626,7 @@ // Assume that tab1 is a single tab. List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); doReturn(1).when(mTabGroupModelFilter).getCount(); doReturn(mTab1).when(mTabGroupModelFilter).getTabAt(POSITION1); doReturn(tabs).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID); @@ -1752,7 +1758,7 @@ doReturn(TAB3_ID).when(tab3).getRootId(); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, tab3)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(2)); // Select tab3 so the group doesn't have the selected tab. @@ -1817,7 +1823,7 @@ // Select tab3 so the group doesn't have the selected tab. List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, tab3)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(2)); doReturn(2).when(mTabModel).index(); @@ -1881,7 +1887,7 @@ doReturn(TAB1_ID).when(tab3).getRootId(); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(1)); // Assume that moveTab in TabModel is finished. @@ -1944,7 +1950,7 @@ doReturn(TAB1_ID).when(tab3).getRootId(); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(1)); // Assume that moveTab in TabModel is finished. @@ -1987,7 +1993,7 @@ // Assume there are 3 tabs in TabModel, mTab2 just grouped with mTab1; Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, tab3)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(2)); // Assume undo grouping mTab2 with mTab1. @@ -2009,7 +2015,7 @@ // Assume there are 3 tabs in TabModel, tab3 just grouped with mTab1; Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(2)); // Assume undo grouping tab3 with mTab1. @@ -2035,7 +2041,7 @@ // Assume there are 3 tabs in TabModel, mTab1 just grouped with mTab2; Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab2, tab3)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(2)); // Assume undo grouping mTab1 from mTab2. @@ -2063,7 +2069,7 @@ Tab tab4 = prepareTab(TAB4_ID, TAB4_TITLE, TAB4_URL); doReturn(4).when(mTabModel).getCount(); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(1)); // Assume undo grouping tab3 with mTab1. @@ -2188,7 +2194,8 @@ createTabGroup(tabs, TAB1_ID, TAB_GROUP_ID); // Even if we have a stored title, we only show it in tab switcher. - assertThat(mMediator.getLatestTitleForTab(PseudoTab.fromTab(mTab1)), equalTo(TAB1_TITLE)); + assertThat( + mMediator.getLatestTitleForTab(mTab1, /* useDefault= */ true), equalTo(TAB1_TITLE)); } @Test @@ -2205,7 +2212,7 @@ // We never show stored title for single tab. assertThat( - mMediator.getLatestTitleForTab(PseudoTab.fromTab(mTab1)), + mMediator.getLatestTitleForTab(mTab1, /* useDefault= */ true), equalTo(CUSTOMIZED_DIALOG_TITLE1)); } @@ -2223,7 +2230,8 @@ when(mTabGroupModelFilter.isTabInTabGroup(mTab1)).thenReturn(false); // We never show stored title for single tab. - assertThat(mMediator.getLatestTitleForTab(PseudoTab.fromTab(mTab1)), equalTo(TAB1_TITLE)); + assertThat( + mMediator.getLatestTitleForTab(mTab1, /* useDefault= */ true), equalTo(TAB1_TITLE)); } @Test @@ -2239,11 +2247,30 @@ createTabGroup(tabs, TAB1_ID, TAB_GROUP_ID); assertThat( - mMediator.getLatestTitleForTab(PseudoTab.fromTab(mTab1)), + mMediator.getLatestTitleForTab(mTab1, /* useDefault= */ true), equalTo(CUSTOMIZED_DIALOG_TITLE1)); } @Test + public void getLatestTitle_Default_GTS() { + // Mock that tab1 and tab2 are in the same group and group root id is TAB1_ID. + List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + createTabGroup(tabs, TAB1_ID, TAB_GROUP_ID); + + assertThat( + mMediator.getLatestTitleForTab(mTab1, /* useDefault= */ true), equalTo("2 tabs")); + } + + @Test + public void getLatestTitle_NoDefault_GTS() { + // Mock that tab1 and tab2 are in the same group and group root id is TAB1_ID. + List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2)); + createTabGroup(tabs, TAB1_ID, TAB_GROUP_ID); + + assertThat(mMediator.getLatestTitleForTab(mTab1, /* useDefault= */ false), equalTo("")); + } + + @Test public void updateTabGroupTitle_GTS() { setUpTabGroupCardDescriptionString(); String targetString = "Expand tab group with 2 tabs."; @@ -2322,7 +2349,7 @@ assertEquals(TabProperties.UiType.DIVIDER, mModel.get(0).type); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), /* quickMode= */ false); + mMediator.resetWithListOfTabs(tabs, /* quickMode= */ false); assertThat(mModel.size(), equalTo(2)); assertNotEquals(TabProperties.UiType.DIVIDER, mModel.get(0).type); assertNotEquals(TabProperties.UiType.DIVIDER, mModel.get(1).type); @@ -2499,7 +2526,8 @@ setUpTabListMediator(TabListMediatorType.TAB_SWITCHER, TabListMode.LIST); TabListMediator mMediatorSpy = spy(mMediator); - doReturn(true).when(mMediatorSpy).isPseudoTabInTabGroup(any()); + when(mTabGroupModelFilter.isTabInTabGroup(any())).thenReturn(true); + doReturn(true).when(mMediatorSpy).isTabInTabGroup(any()); mMediatorSpy.setComponentNameForTesting(TabSwitcherCoordinator.COMPONENT_NAME); initAndAssertAllProperties(mMediatorSpy); @@ -2531,7 +2559,8 @@ setUpTabListMediator(TabListMediatorType.TAB_SWITCHER, TabListMode.LIST); TabListMediator mMediatorSpy = spy(mMediator); - doReturn(true).when(mMediatorSpy).isPseudoTabInTabGroup(any()); + when(mTabGroupModelFilter.isTabInTabGroup(any())).thenReturn(true); + doReturn(true).when(mMediatorSpy).isTabInTabGroup(any()); mMediatorSpy.setComponentNameForTesting(TabSwitcherCoordinator.COMPONENT_NAME); initAndAssertAllProperties(mMediatorSpy); @@ -2551,8 +2580,7 @@ mModel.get(POSITION1).model.set(TabProperties.TAB_GROUP_COLOR_ID, COLOR_2); // Pass in a mocked newly created tab group. - mMediatorSpy.resetWithListOfTabs( - PseudoTab.getListOfPseudoTab(tabs), /* quickMode= */ false); + mMediatorSpy.resetWithListOfTabs(tabs, /* quickMode= */ false); assertEquals( nextSuggestedColorId, mModel.get(POSITION1).model.get(TabProperties.TAB_GROUP_COLOR_ID)); @@ -2690,9 +2718,7 @@ tabs.add(mTabModel.getTabAt(i)); } - boolean showQuickly = - mMediator.resetWithListOfTabs( - PseudoTab.getListOfPseudoTab(tabs), /* quickMode= */ false); + boolean showQuickly = mMediator.resetWithListOfTabs(tabs, /* quickMode= */ false); assertThat(showQuickly, equalTo(true)); // Create a PropertyModel that is not a tab and add it to the existing TabListModel. @@ -2702,9 +2728,7 @@ assertThat(mModel.size(), equalTo(tabs.size() + 1)); // TabListModel unchange check should ignore the non-Tab item. - showQuickly = - mMediator.resetWithListOfTabs( - PseudoTab.getListOfPseudoTab(tabs), /* quickMode= */ false); + showQuickly = mMediator.resetWithListOfTabs(tabs, /* quickMode= */ false); assertThat(showQuickly, equalTo(true)); } @@ -2716,7 +2740,7 @@ for (boolean priceTrackingEnabled : new boolean[] {false, true}) { for (boolean incognito : new boolean[] {false, true}) { TabListMediator mMediatorSpy = spy(mMediator); - doReturn(false).when(mMediatorSpy).isPseudoTabInTabGroup(any()); + doReturn(false).when(mMediatorSpy).isTabInTabGroup(any()); PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting( signedInAndSyncEnabled); PriceTrackingUtilities.SHARED_PREFERENCES_MANAGER.writeBoolean( @@ -2740,8 +2764,7 @@ tabs.add(mTabModel.getTabAt(0)); tabs.add(mTabModel.getTabAt(1)); - mMediatorSpy.resetWithListOfTabs( - PseudoTab.getListOfPseudoTab(tabs), /* quickMode= */ false); + mMediatorSpy.resetWithListOfTabs(tabs, /* quickMode= */ false); if (signedInAndSyncEnabled && priceTrackingEnabled && !incognito) { mModel.get(0) .model @@ -2902,7 +2925,6 @@ mCurrentTabModelFilterSupplier, () -> mTabModel, getTabThumbnailCallback(), - mTitleProvider, mTabListFaviconProvider, mTabGroupColorFaviconProvider, true, @@ -2937,7 +2959,6 @@ mCurrentTabModelFilterSupplier, () -> mTabModel, getTabThumbnailCallback(), - mTitleProvider, mTabListFaviconProvider, mTabGroupColorFaviconProvider, true, @@ -3154,18 +3175,14 @@ createTabGroup(group1, TAB2_ID, TAB_GROUP_ID); // Reset with show quickly. - assertThat( - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false), - equalTo(true)); + assertThat(mMediator.resetWithListOfTabs(tabs, false), equalTo(true)); assertThat( mModel.get(POSITION2).model.get(TabProperties.CONTENT_DESCRIPTION_STRING), equalTo(targetString)); // Reset without show quickly. mModel.clear(); - assertThat( - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false), - equalTo(false)); + assertThat(mMediator.resetWithListOfTabs(tabs, false), equalTo(false)); assertThat( mModel.get(POSITION2).model.get(TabProperties.CONTENT_DESCRIPTION_STRING), equalTo(targetString)); @@ -3193,7 +3210,7 @@ tabs.add(mTabModel.getTabAt(i)); } - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat( mModel.get(POSITION1).model.get(TabProperties.ACTION_BUTTON_DESCRIPTION_STRING), equalTo(targetString)); @@ -3205,7 +3222,7 @@ setUpCloseButtonDescriptionString(true); targetString = "Close tab group with 2 tabs."; - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat( mModel.get(POSITION1).model.get(TabProperties.ACTION_BUTTON_DESCRIPTION_STRING), equalTo(targetString)); @@ -3231,7 +3248,7 @@ setUpCloseButtonDescriptionString(true); String targetString = "Close tab group with 1 tab."; - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat( mModel.get(POSITION1).model.get(TabProperties.ACTION_BUTTON_DESCRIPTION_STRING), equalTo(targetString)); @@ -3255,7 +3272,7 @@ createTabGroup(group1, TAB1_ID, TAB_GROUP_ID); String targetString = "Close tab group with 2 tabs, color Grey."; - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(group1), false); + mMediator.resetWithListOfTabs(group1, false); assertThat( mModel.get(POSITION1).model.get(TabProperties.ACTION_BUTTON_DESCRIPTION_STRING), equalTo(targetString)); @@ -3282,7 +3299,7 @@ createTabGroup(group1, TAB1_ID, TAB_GROUP_ID); String targetString = "Open the tab group action menu for tab group 2 tabs"; - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(group1), false); + mMediator.resetWithListOfTabs(group1, false); assertThat( mModel.get(POSITION1).model.get(TabProperties.ACTION_BUTTON_DESCRIPTION_STRING), equalTo(targetString)); @@ -3342,7 +3359,7 @@ tabs.add(mTabModel.getTabAt(0)); tabs.add(mTabModel.getTabAt(1)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), /* quickMode= */ false); + mMediator.resetWithListOfTabs(tabs, /* quickMode= */ false); prepareRecyclerViewForScroll(); mMediator.registerOnScrolledListener(mRecyclerView); @@ -3367,7 +3384,6 @@ mCurrentTabModelFilterSupplier, () -> mTabModel, getTabThumbnailCallback(), - mTitleProvider, mTabListFaviconProvider, mTabGroupColorFaviconProvider, true, @@ -3386,7 +3402,7 @@ when(mSelectionDelegate.isItemSelected(TAB1_ID)).thenReturn(false); Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2, tab3)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(3)); assertThat(mModel.get(0).model.get(TabProperties.IS_SELECTED), equalTo(false)); assertThat(mModel.get(1).model.get(TabProperties.IS_SELECTED), equalTo(false)); @@ -3413,7 +3429,6 @@ mCurrentTabModelFilterSupplier, () -> mTabModel, getTabThumbnailCallback(), - mTitleProvider, mTabListFaviconProvider, mTabGroupColorFaviconProvider, true, @@ -3432,7 +3447,7 @@ Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL); when(mSelectionDelegate.isItemSelected(TAB1_ID)).thenReturn(false); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2, tab3)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(3)); assertThat(mModel.get(0).model.get(TabProperties.IS_SELECTED), equalTo(false)); assertThat(mModel.get(1).model.get(TabProperties.IS_SELECTED), equalTo(false)); @@ -3459,7 +3474,6 @@ mCurrentTabModelFilterSupplier, () -> mTabModel, getTabThumbnailCallback(), - mTitleProvider, mTabListFaviconProvider, mTabGroupColorFaviconProvider, true, @@ -3487,7 +3501,7 @@ when(mTabGroupModelFilter.isTabInTabGroup(tab3)).thenReturn(false); List<Tab> tabs = Arrays.asList(mTab1, mTab2, tab3); when(mSelectionDelegate.isItemSelected(TAB1_ID)).thenReturn(false); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(3)); assertThat(mModel.get(0).model.get(TabProperties.IS_SELECTED), equalTo(false)); assertThat(mModel.get(1).model.get(TabProperties.IS_SELECTED), equalTo(false)); @@ -3499,7 +3513,7 @@ ThumbnailFetcher fetcher1 = mModel.get(0).model.get(TabProperties.THUMBNAIL_FETCHER); ThumbnailFetcher fetcher2 = mModel.get(1).model.get(TabProperties.THUMBNAIL_FETCHER); ThumbnailFetcher fetcher3 = mModel.get(2).model.get(TabProperties.THUMBNAIL_FETCHER); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), true); + mMediator.resetWithListOfTabs(tabs, true); assertThat(mModel.get(0).model.get(TabProperties.IS_SELECTED), equalTo(true)); assertThat(mModel.get(1).model.get(TabProperties.IS_SELECTED), equalTo(true)); @@ -3543,7 +3557,7 @@ List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, tab3)); createTabGroup(tabs, TAB1_ID, TAB_GROUP_ID); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(List.of(mTab1, mTab2)), true); + mMediator.resetWithListOfTabs(List.of(mTab1, mTab2), true); ThumbnailFetcher fetcherBefore = mModel.get(0).model.get(TabProperties.THUMBNAIL_FETCHER); assertEquals(2, mModel.size()); @@ -3568,7 +3582,7 @@ List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, tab3)); createTabGroup(tabs, TAB1_ID, TAB_GROUP_ID); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(List.of(mTab1, mTab2)), true); + mMediator.resetWithListOfTabs(List.of(mTab1, mTab2), true); ThumbnailFetcher fetcherBefore = mModel.get(0).model.get(TabProperties.THUMBNAIL_FETCHER); assertEquals(2, mModel.size()); @@ -3627,7 +3641,7 @@ Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL); List<Tab> group1 = new ArrayList<>(Arrays.asList(mTab1, tab3)); createTabGroup(group1, TAB1_ID, TAB_GROUP_ID); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); // Assert that a tab group status was recorded. assertTrue(mModel.get(POSITION1).model.get(TabProperties.TAB_GROUP_INFO).getIsTabGroup()); @@ -3643,7 +3657,7 @@ // Create tab group. List<Tab> group1 = new ArrayList<>(Arrays.asList(mTab1, mTab2)); createTabGroup(group1, TAB1_ID, TAB_GROUP_ID); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); // Assert that the callback performs as expected. assertNotNull(mModel.get(POSITION1).model.get(TabProperties.ON_MENU_ITEM_CLICKED_CALLBACK)); @@ -3697,7 +3711,7 @@ when(mTabListRecyclerView.getRectOfCurrentThumbnail(4, TAB7_ID)).thenReturn(null); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2, tab3, tab5, tab7)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(5)); TreeMap<Integer, List<Integer>> resultMap = new TreeMap<>(); @@ -3787,7 +3801,7 @@ for (int i = 0; i < mTabModel.getCount(); i++) { tabs.add(mTabModel.getTabAt(i)); } - mediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mediator.resetWithListOfTabs(tabs, false); for (Callback<TabFavicon> callback : mCallbackCaptor.getAllValues()) { callback.onResult(mFavicon); } @@ -3797,8 +3811,12 @@ assertThat(mModel.get(0).model.get(TabProperties.TAB_ID), equalTo(TAB1_ID)); assertThat(mModel.get(1).model.get(TabProperties.TAB_ID), equalTo(TAB2_ID)); - assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(TAB1_TITLE)); - assertThat(mModel.get(1).model.get(TabProperties.TITLE), equalTo(TAB2_TITLE)); + if (!mTabGroupModelFilter.isTabInTabGroup(mTab1)) { + assertThat(mModel.get(0).model.get(TabProperties.TITLE), equalTo(TAB1_TITLE)); + } + if (!mTabGroupModelFilter.isTabInTabGroup(mTab2)) { + assertThat(mModel.get(1).model.get(TabProperties.TITLE), equalTo(TAB2_TITLE)); + } assertNotNull(mModel.get(0).model.get(TabProperties.FAVICON_FETCHER)); assertNotNull(mModel.get(1).model.get(TabProperties.FAVICON_FETCHER)); @@ -3833,7 +3851,7 @@ Tab tab = TabUiUnitTestUtils.prepareTab(id, title, url); when(tab.getView()).thenReturn(mock(View.class)); doReturn(true).when(tab).isIncognito(); - when(mTitleProvider.getTitle(mActivity, PseudoTab.fromTab(tab))).thenReturn(title); + when(tab.getTitle()).thenReturn(title); int count = mTabModel.getCount(); doReturn(tab).when(mTabModel).getTabAt(count); doReturn(count).when(mTabModel).getCount(); @@ -3895,7 +3913,6 @@ mCurrentTabModelFilterSupplier, () -> mTabModel, getTabThumbnailCallback(), - mTitleProvider, mTabListFaviconProvider, mTabGroupColorFaviconProvider, actionOnRelatedTabs, @@ -3984,7 +4001,7 @@ private void initWithThreeTabs() { Tab tab3 = prepareTab(TAB3_ID, TAB3_TITLE, TAB3_URL); List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2, tab3)); - mMediator.resetWithListOfTabs(PseudoTab.getListOfPseudoTab(tabs), false); + mMediator.resetWithListOfTabs(tabs, false); assertThat(mModel.size(), equalTo(3)); assertThat(mModel.get(0).model.get(TabProperties.IS_SELECTED), equalTo(true)); assertThat(mModel.get(1).model.get(TabProperties.IS_SELECTED), equalTo(false));
diff --git a/chrome/android/features/tab_ui/tab_management_java_sources.gni b/chrome/android/features/tab_ui/tab_management_java_sources.gni index bcf5d5c..f4d541e 100644 --- a/chrome/android/features/tab_ui/tab_management_java_sources.gni +++ b/chrome/android/features/tab_ui/tab_management_java_sources.gni
@@ -5,8 +5,6 @@ # These should reside within the public/ subdirectory, but cannot due to # dependency issues. public_tab_management_java_sources = [ - "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java", - "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCache.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ActionConfirmationDialog.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ActionConfirmationManager.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/CloseAllTabsDialog.java", @@ -210,8 +208,6 @@ "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneUnitTest.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabsSettingsUnitTest.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/WasPositiveControllerUnitTest.java", - "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTabUnitTest.java", - "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/pseudotab/TabAttributeCacheUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtilsUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/CloseAllTabsDialogUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ColorPickerItemViewBinderUnitTest.java",
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java index 8882e94f..01adb05 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
@@ -64,7 +64,6 @@ import org.chromium.chrome.browser.xsurface.feed.FeedSurfaceScope; import org.chromium.chrome.browser.xsurface.feed.FeedUserInteractionReliabilityLogger; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; -import org.chromium.components.browser_ui.styles.SemanticColorUtils; import org.chromium.components.browser_ui.widget.displaystyle.UiConfig; import org.chromium.components.feature_engagement.EventConstants; import org.chromium.components.feature_engagement.Tracker; @@ -849,13 +848,8 @@ return AppCompatResources.getDrawable(mActivity, resId); })); } - if (ChromeFeatureList.sSurfacePolish.isEnabled()) { - view.setBackground( - AppCompatResources.getDrawable( - mActivity, R.drawable.home_surface_background)); - } else { - view.setBackgroundColor(SemanticColorUtils.getDefaultBgColor(mActivity)); - } + view.setBackground( + AppCompatResources.getDrawable(mActivity, R.drawable.home_surface_background)); // Work around https://crbug.com/943873 where default focus highlight shows up after // toggling dark mode. @@ -964,27 +958,23 @@ for (View header : headerViews) { // Feed header view in multi does not need padding added. int lateralPaddingsPx = getLateralPaddingsPx(); - if (header == mSectionHeaderView) { - lateralPaddingsPx = 0; - } - if (ChromeFeatureList.sSurfacePolish.isEnabled()) { - if (header instanceof NewTabPageLayout) { - lateralPaddingsPx = 0; - } else if (header == mSectionHeaderView) { - if (!ChromeFeatureList.isEnabled(ChromeFeatureList.FEED_CONTAINMENT)) { - mSectionHeaderView.setBackground( - AppCompatResources.getDrawable( - mActivity, R.drawable.home_surface_background)); - } - } else if (header == mSigninPromoView) { - lateralPaddingsPx = - mActivity - .getResources() - .getDimensionPixelSize(R.dimen.signin_promo_lateral_paddings); - ((PersonalizedSigninPromoView) mSigninPromoView) - .setCardBackgroundResource(R.drawable.home_surface_ui_background); + if (header instanceof NewTabPageLayout) { + lateralPaddingsPx = 0; + } else if (header == mSectionHeaderView) { + lateralPaddingsPx = 0; + if (!ChromeFeatureList.isEnabled(ChromeFeatureList.FEED_CONTAINMENT)) { + mSectionHeaderView.setBackground( + AppCompatResources.getDrawable( + mActivity, R.drawable.home_surface_background)); } + } else if (header == mSigninPromoView) { + lateralPaddingsPx = + mActivity + .getResources() + .getDimensionPixelSize(R.dimen.signin_promo_lateral_paddings); + ((PersonalizedSigninPromoView) mSigninPromoView) + .setCardBackgroundResource(R.drawable.home_surface_ui_background); } FeedListContentManager.NativeViewContent content =
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml index 81532c9..329f11b 100644 --- a/chrome/android/java/res/layout/new_tab_page_layout.xml +++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -11,6 +11,7 @@ android:id="@+id/ntp_content" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="@drawable/home_surface_background" android:layout_gravity="center_horizontal" android:orientation="vertical" android:gravity="center"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalIbanEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalIbanEditor.java index 98b0ae6..b7122a9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalIbanEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalIbanEditor.java
@@ -25,7 +25,6 @@ import org.chromium.chrome.browser.autofill.PersonalDataManager; import org.chromium.chrome.browser.autofill.PersonalDataManager.Iban; import org.chromium.chrome.browser.autofill.PersonalDataManagerFactory; -import org.chromium.components.autofill.IbanRecordType; /** * This class creates a view for adding and editing a local IBAN. A local IBAN gets saved to the @@ -84,14 +83,16 @@ // case of a new IBAN, these values are set right before being written to the autofill // table. Iban iban = - Iban.createLocal( - /* guid= */ mGUID, - /* label= */ "", - /* nickname= */ mNickname.getText().toString().trim(), - /* recordType= */ mGUID.isEmpty() - ? IbanRecordType.UNKNOWN - : IbanRecordType.LOCAL_IBAN, - /* value= */ mValue.getText().toString()); + mGUID.isEmpty() + ? Iban.createEphemeral( + /* label= */ "", + /* nickname= */ mNickname.getText().toString().trim(), + /* value= */ mValue.getText().toString()) + : Iban.createLocal( + /* guid= */ mGUID, + /* label= */ "", + /* nickname= */ mNickname.getText().toString().trim(), + /* value= */ mValue.getText().toString()); PersonalDataManager personalDataManager = PersonalDataManagerFactory.getForProfile(getProfile()); String guid = personalDataManager.addOrUpdateLocalIban(iban);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java index dabcb2bf..4e9bd38 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -72,6 +72,7 @@ import org.chromium.chrome.browser.theme.TopUiThemeColorProvider; import org.chromium.chrome.browser.ui.RootUiCoordinator; import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate; +import org.chromium.chrome.browser.ui.google_bottom_bar.GoogleBottomBarCoordinator; import org.chromium.chrome.browser.usage_stats.UsageStatsService; import org.chromium.chrome.browser.webapps.SameTaskWebApkActivity; import org.chromium.chrome.browser.webapps.WebappActivityCoordinator; @@ -657,6 +658,13 @@ @Override public int getBaseStatusBarColor(Tab tab) { + // TODO(b/300419189): Pass the CCT Top Bar Color in AGSA intent after Google Bottom Bar is + // launched + if (GoogleBottomBarCoordinator.isFeatureEnabled() + && CustomTabsConnection.getInstance() + .shouldEnableGoogleBottomBarForIntent(mIntentDataProvider)) { + return getWindow().getContext().getColor(R.color.google_bottom_bar_background_color); + } // TODO(b/300419189): Pass the CCT Top Bar Color in AGSA intent after the Chrome side LE for // Page Insights Hub if (PageInsightsCoordinator.isFeatureEnabled()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java index 3e34b583..ad21de74 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -426,13 +426,9 @@ mTitle = activity.getResources().getString(R.string.new_tab_title); mIsSurfacePolishEnabled = ChromeFeatureList.sSurfacePolish.isEnabled(); - if (mIsSurfacePolishEnabled) { - mBackgroundColor = - ChromeColors.getSurfaceColor( - mContext, R.dimen.home_surface_background_color_elevation); - } else { - mBackgroundColor = SemanticColorUtils.getDefaultBgColor(mContext); - } + mBackgroundColor = + ChromeColors.getSurfaceColor( + mContext, R.dimen.home_surface_background_color_elevation); mIsTablet = isTablet; mTemplateUrlService = TemplateUrlServiceFactory.getForProfile(profile); mTemplateUrlService.addObserver(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java index f658472..227012f1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -317,11 +317,6 @@ mInitialized = true; TraceEvent.end(TAG + ".initialize()"); - - if (mIsSurfacePolishEnabled) { - setBackground( - AppCompatResources.getDrawable(mContext, R.drawable.home_surface_background)); - } } public void reload() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java index fb412d1..07a5476 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
@@ -394,7 +394,9 @@ private boolean showTrackingProtectionUI() { return UserPrefs.get(getProfile()).getBoolean(Pref.TRACKING_PROTECTION3PCD_ENABLED) - || ChromeFeatureList.isEnabled(ChromeFeatureList.TRACKING_PROTECTION_3PCD); + || ChromeFeatureList.isEnabled(ChromeFeatureList.TRACKING_PROTECTION_3PCD) + || ChromeFeatureList.isEnabled( + ChromeFeatureList.TRACKING_PROTECTION_SETTINGS_LAUNCH); } private boolean shouldShowIpProtectionUI() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy_sandbox/ChromeTrackingProtectionDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/privacy_sandbox/ChromeTrackingProtectionDelegate.java index 52432d6..0d006a79 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/privacy_sandbox/ChromeTrackingProtectionDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy_sandbox/ChromeTrackingProtectionDelegate.java
@@ -43,6 +43,12 @@ } @Override + public boolean shouldDisplayIpProtection() { + return ChromeFeatureList.isEnabled(ChromeFeatureList.TRACKING_PROTECTION_SETTINGS_LAUNCH) + && ChromeFeatureList.isEnabled(ChromeFeatureList.IP_PROTECTION_V1); + } + + @Override public boolean isIpProtectionEnabled() { return UserPrefs.get(mProfile).getBoolean(Pref.IP_PROTECTION_ENABLED) && ChromeFeatureList.isEnabled(ChromeFeatureList.IP_PROTECTION_V1); @@ -55,6 +61,12 @@ } @Override + public boolean shouldDisplayFingerprintingProtection() { + return ChromeFeatureList.isEnabled(ChromeFeatureList.TRACKING_PROTECTION_SETTINGS_LAUNCH) + && ChromeFeatureList.isEnabled(ChromeFeatureList.FINGERPRINTING_PROTECTION_SETTING); + } + + @Override public boolean isFingerprintingProtectionEnabled() { return UserPrefs.get(mProfile).getBoolean(Pref.FINGERPRINTING_PROTECTION_ENABLED) && ChromeFeatureList.isEnabled(ChromeFeatureList.FINGERPRINTING_PROTECTION_SETTING);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java index e8e9951..840a7ea 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
@@ -49,6 +49,10 @@ // This shared prefs file was used for storing tab group session counts. It is no longer in use. private static final String LEGACY_TAB_GROUP_PREFS_FILE = "tab_group_pref"; + // This shared prefs file was used for storing tab properties to use before tabs had loaded for + // tab switching surfaces. + private static final String LEGACY_TAB_ATTRIBUTE_CACHE_FILE = "tab_attribute_cache"; + /** <M53 The name of the file where the old tab metadata file is saved per directory. */ @VisibleForTesting static final String LEGACY_SAVED_STATE_FILE = "tab_state"; @@ -477,6 +481,8 @@ ContextUtils.getApplicationContext() .deleteSharedPreferences(LEGACY_TAB_GROUP_PREFS_FILE); + ContextUtils.getApplicationContext() + .deleteSharedPreferences(LEGACY_TAB_ATTRIBUTE_CACHE_FILE); return null; }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivitySigninAndSyncTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivitySigninAndSyncTest.java index 5f0c2621..a142053 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivitySigninAndSyncTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunActivitySigninAndSyncTest.java
@@ -40,7 +40,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; @@ -48,7 +47,6 @@ import org.chromium.base.BuildInfo; import org.chromium.base.test.util.ApplicationTestUtils; -import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisabledTest; @@ -90,8 +88,6 @@ private static final String CHILD_EMAIL = "child.account@gmail.com"; private static final String TEST_URL = "https://foo.com"; - @Rule public final TestRule mCommandLineFlagRule = CommandLineFlags.getTestRule(); - @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); // TODO(crbug.com/40234741): Use IdentityIntegrationTestRule instead.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java index 211832f..672b9108 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
@@ -38,7 +38,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; @@ -52,12 +51,10 @@ import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; -import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.DoNotBatch; -import org.chromium.base.test.util.Features; import org.chromium.base.test.util.HistogramWatcher; import org.chromium.base.test.util.JniMocker; import org.chromium.base.test.util.ScalableTimeout; @@ -113,12 +110,8 @@ private static final long ACTIVITY_WAIT_LONG_MS = TimeUnit.SECONDS.toMillis(10); private static final String TEST_ENROLLMENT_TOKEN = "enrollment-token"; - @Rule public TestRule mProcessor = new Features.JUnitProcessor(); - @Rule public JniMocker mJniMocker = new JniMocker(); - @Rule public TestRule mCommandLineFlagsRule = CommandLineFlags.getTestRule(); - @Rule public BasePartnerBrowserCustomizationIntegrationTestRule mCustomizationRule = new BasePartnerBrowserCustomizationIntegrationTestRule();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelperTest.java index ab791fe9..3a4c64e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelperTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelperTest.java
@@ -16,9 +16,11 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.Features.DisableFeatures; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.base.ColdStartTracker; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.metrics.SimpleStartupForegroundSessionDetector; import org.chromium.chrome.browser.paint_preview.services.PaintPreviewTabServiceFactory; @@ -91,11 +93,16 @@ */ @Test @MediumTest + @DisableFeatures({ChromeFeatureList.ANDROID_TAB_DECLUTTER}) @Restriction(StartupPaintPreviewHelperTestRunner.RESTRICTION_TYPE_KEEP_ACTIVITIES) - @DisabledTest(message = "Very flaky. See crbug.com/333779543.") + @DisabledTest(message = "Pending revival. See crbug.com/333779543.") public void testDisplayOnStartup() throws ExecutionException { mActivityTestRule.startMainActivityWithURL( mActivityTestRule.getTestServer().getURL(TEST_URL)); + final ChromeTabbedActivity activity = mActivityTestRule.getActivity(); + CriteriaHelper.pollUiThread( + () -> activity.getTabModelSelector().isTabStateInitialized(), + "Tab state never initialized."); final Tab tab = mActivityTestRule.getActivity().getActivityTab(); CriteriaHelper.pollUiThread( () -> @@ -119,12 +126,15 @@ // Emulate browser cold start. Paint preview should be shown on startup. pretendColdStartBeforeForegrounded(); - ChromeTabbedActivity activity = mActivityTestRule.getActivity(); TestThreadUtils.runOnUiThreadBlocking(activity::finish); CriteriaHelper.pollUiThread(activity::isDestroyed, "Activity didn't get destroyed."); mActivityTestRule.startMainActivityFromLauncher(); - final Tab previewTab = mActivityTestRule.getActivity().getActivityTab(); + final ChromeTabbedActivity newActivity = mActivityTestRule.getActivity(); + CriteriaHelper.pollUiThread( + () -> newActivity.getTabModelSelector().isTabStateInitialized(), + "Tab state never initialized."); + final Tab previewTab = newActivity.getActivityTab(); tabbedPaintPreview = TestThreadUtils.runOnUiThreadBlocking(() -> TabbedPaintPreview.get(previewTab));
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index dadf62f..b5d4941 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -13249,7 +13249,7 @@ {NUM_TABS, plural, =1 {<ph name="GROUP_TITLE">$1<ex>MyGroup</ex></ph> - 1 Tab} other {<ph name="GROUP_TITLE">$1<ex>MyGroup</ex></ph> - # Tabs}} </message> <message name="IDS_RECENTLY_CLOSED_GROUP_UNNAMED" desc="In Title Case: Title of recently closed group that does not have a name, in Recent Tabs menu. [ICU_Syntax]"> - {NUM_TABS, plural, =1 {Unnamed Group - 1 Tab} other {Unnamed Group - # Tabs}} + {NUM_TABS, plural, =1 {1 Tab} other {# Tabs}} </message> <message name="IDS_RECENT_TABS_NO_DEVICE_TABS" desc="In Title Case: The label in the Recent Tabs menu in the wrench menu when there's no tabs from other devices."> No Tabs From Other Devices @@ -13269,7 +13269,7 @@ {NUM_TABS, plural, =1 {<ph name="GROUP_TITLE">$1<ex>MyGroup</ex></ph> - 1 tab} other {<ph name="GROUP_TITLE">$1<ex>MyGroup</ex></ph> - # tabs}} </message> <message name="IDS_RECENTLY_CLOSED_GROUP_UNNAMED" desc="Title of recently closed group that does not have a name, in Recent Tabs menu. [ICU_Syntax]"> - {NUM_TABS, plural, =1 {Unnamed group - 1 tab} other {Unnamed group - # tabs}} + {NUM_TABS, plural, =1 {1 tab} other {# tabs}} </message> <message name="IDS_RECENT_TABS_NO_DEVICE_TABS" desc="The label in the Recent Tabs menu in the wrench menu when there's no tabs from other devices."> No tabs from other devices
diff --git a/chrome/app/generated_resources_grd/IDS_RECENTLY_CLOSED_GROUP_UNNAMED.png.sha1 b/chrome/app/generated_resources_grd/IDS_RECENTLY_CLOSED_GROUP_UNNAMED.png.sha1 index a96cca59..400bd7a8 100644 --- a/chrome/app/generated_resources_grd/IDS_RECENTLY_CLOSED_GROUP_UNNAMED.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_RECENTLY_CLOSED_GROUP_UNNAMED.png.sha1
@@ -1 +1 @@ -d88b233d7a8c0e8acb3f39bd2c7a66e73204ee93 \ No newline at end of file +7b11c1f844b6de239215cf3bf35887e52b480116 \ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 0c363bea..b1c0ac6 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -307,6 +307,7 @@ #endif #if BUILDFLAG(IS_MAC) +#include "chrome/browser/enterprise/platform_auth/platform_auth_features.h" #include "chrome/browser/ui/browser_dialogs.h" #endif // BUILDFLAG(IS_MAC) @@ -3850,6 +3851,14 @@ std::size(kLocationProviderManagerModeHybridPlatform), nullptr}}; #endif // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) +const FeatureEntry::FeatureParam kWebAuthnEnclaveAuthenticatorEnabledParam = { + device::kWebAuthnGpmPinFeatureParameterName, "true"}; +const FeatureEntry::FeatureVariation kWebAuthnEnclaveAuthenticatorVariations[] = + {{"with GPM PIN enabled", &kWebAuthnEnclaveAuthenticatorEnabledParam, 1, + nullptr}}; +#endif + // RECORDING USER METRICS FOR FLAGS: // ----------------------------------------------------------------------------- // The first line of the entry is the internal name. @@ -5610,9 +5619,6 @@ {"enable-federated-service", flag_descriptions::kFederatedServiceName, flag_descriptions::kFederatedServiceDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kFederatedService)}, - {"screencast-v2", flag_descriptions::kScreencastV2Name, - flag_descriptions::kScreencastV2Description, kOsCrOS, - FEATURE_VALUE_TYPE(ash::features::kProjectorV2)}, #endif // BUILDFLAG(IS_CHROMEOS_ASH) {"enable-cros-touch-text-editing-redesign", flag_descriptions::kTouchTextEditingRedesignName, @@ -5626,12 +5632,14 @@ FEATURE_VALUE_TYPE(features::kQuickOfficeForceFileDownload)}, #endif // BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_MAC) + {"enable-extensible-enterprise-sso", + flag_descriptions::kEnableExtensibleEnterpriseSSOName, + flag_descriptions::kEnableExtensibleEnterpriseSSODescription, kOsMac, + FEATURE_VALUE_TYPE(enterprise_auth::kEnableExtensibleEnterpriseSSO)}, {"enable-retry-capture-device-enumeration-on-crash", flag_descriptions::kRetryGetVideoCaptureDeviceInfosName, flag_descriptions::kRetryGetVideoCaptureDeviceInfosDescription, kOsMac, FEATURE_VALUE_TYPE(features::kRetryGetVideoCaptureDeviceInfos)}, -#endif // BUILDFLAG(IS_MAC) -#if BUILDFLAG(IS_MAC) {"enable-immersive-fullscreen-toolbar", flag_descriptions::kImmersiveFullscreenName, flag_descriptions::kImmersiveFullscreenDescription, kOsMac, @@ -11363,6 +11371,16 @@ SINGLE_VALUE_TYPE( optimization_guide::switches::kEnableModelQualityDogfoodLogging)}, +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) + {"web-authentication-enclave-authenticator", + flag_descriptions::kWebAuthnEnclaveAuthenticatorName, + flag_descriptions::kWebAuthnEnclaveAuthenticatorDescription, + kOsMac | kOsWin | kOsLinux, + FEATURE_WITH_PARAMS_VALUE_TYPE(device::kWebAuthnEnclaveAuthenticator, + kWebAuthnEnclaveAuthenticatorVariations, + "WebAuthenticationEnclaveAuthenticator")}, +#endif + // NOTE: Adding a new flag requires adding a corresponding entry to enum // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/browsing_data/browsing_data_bridge.cc b/chrome/browser/android/browsing_data/browsing_data_bridge.cc index 8bac2bc..2e2171a 100644 --- a/chrome/browser/android/browsing_data/browsing_data_bridge.cc +++ b/chrome/browser/android/browsing_data/browsing_data_bridge.cc
@@ -26,7 +26,7 @@ #include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h" #include "chrome/browser/engagement/important_sites_util.h" #include "chrome/browser/history/web_history_service_factory.h" -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/sync_service_factory.h" #include "chrome/common/channel_info.h" #include "components/browsing_data/content/android/browsing_data_model_android.h" @@ -60,7 +60,7 @@ } PrefService* GetPrefService(const JavaParamRef<jobject>& jprofile) { - Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); + Profile* profile = Profile::FromJavaObject(jprofile); return profile->GetOriginalProfile()->GetPrefs(); } @@ -97,7 +97,7 @@ const JavaParamRef<jintArray>& jignoring_domain_reasons) { TRACE_EVENT0("browsing_data", "BrowsingDataBridge_ClearBrowsingData"); - Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); + Profile* profile = Profile::FromJavaObject(jprofile); BrowsingDataRemover* browsing_data_remover = profile->GetBrowsingDataRemover(); @@ -191,7 +191,7 @@ "browsing_data", "BrowsingDataBridge_RequestInfoAboutOtherFormsOfBrowsingHistory"); // The one-time notice in the dialog. - Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); + Profile* profile = Profile::FromJavaObject(jprofile); browsing_data::ShouldPopupDialogAboutOtherFormsOfBrowsingHistory( SyncServiceFactory::GetForProfile(profile), WebHistoryServiceFactory::GetForProfile(profile), chrome::GetChannel(), @@ -204,7 +204,7 @@ const JavaParamRef<jobject>& jprofile, const JavaParamRef<jobject>& java_callback) { TRACE_EVENT0("browsing_data", "BrowsingDataBridge_FetchImportantSites"); - Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); + Profile* profile = Profile::FromJavaObject(jprofile); std::vector<site_engagement::ImportantSitesUtil::ImportantDomainInfo> important_sites = site_engagement::ImportantSitesUtil::GetImportantRegisterableDomains( @@ -246,7 +246,7 @@ GURL origin(base::android::ConvertJavaStringToUTF8(jorigin)); CHECK(origin.is_valid()); site_engagement::ImportantSitesUtil::MarkOriginAsImportantForTesting( - ProfileAndroid::FromProfileAndroid(jprofile), origin); + Profile::FromJavaObject(jprofile), origin); } static jboolean JNI_BrowsingDataBridge_GetBrowsingDataDeletionPreference( @@ -347,7 +347,7 @@ JNIEnv* env, const JavaParamRef<jobject>& jprofile, const JavaParamRef<jobject>& java_callback) { - Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); + Profile* profile = Profile::FromJavaObject(jprofile); BrowsingDataModel::BuildFromDisk( profile, ChromeBrowsingDataModelDelegate::CreateForProfile(profile), base::BindOnce(&OnBrowsingDataModelBuilt, env,
diff --git a/chrome/browser/android/content/web_contents_factory.cc b/chrome/browser/android/content/web_contents_factory.cc index de4ddad..a4461ca 100644 --- a/chrome/browser/android/content/web_contents_factory.cc +++ b/chrome/browser/android/content/web_contents_factory.cc
@@ -6,7 +6,6 @@ #include "chrome/browser/android/content/web_contents_factory_data_deleter.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/storage_partition_config.h" #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc index b36d1d1e..c1e546634 100644 --- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc +++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -7,6 +7,7 @@ #include <jni.h> #include <stddef.h> #include <stdint.h> + #include <memory> #include <string> #include <vector> @@ -37,7 +38,6 @@ #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.h" #include "chrome/browser/preloading/prerender/prerender_manager.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/common/webui_url_constants.h" #include "components/browser_ui/util/android/url_constants.h" @@ -133,7 +133,7 @@ : profile_{profile}, java_controller_{Java_AutocompleteController_Constructor( AttachCurrentThread(), - ProfileAndroid::FromProfile(profile)->GetJavaObject(), + profile->GetJavaObject(), reinterpret_cast<intptr_t>(this))}, autocomplete_controller_{std::make_unique<AutocompleteController>( std::move(client),
diff --git a/chrome/browser/android/omnibox/geolocation_header.cc b/chrome/browser/android/omnibox/geolocation_header.cc index 82bcb2c..b8636f9 100644 --- a/chrome/browser/android/omnibox/geolocation_header.cc +++ b/chrome/browser/android/omnibox/geolocation_header.cc
@@ -7,7 +7,6 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/ui/android/omnibox/jni_headers/GeolocationHeader_jni.h" #include "url/android/gurl_android.h" #include "url/gurl.h" @@ -20,12 +19,9 @@ std::optional<std::string> GetGeolocationHeaderIfAllowed(const GURL& url, Profile* profile) { JNIEnv* env = base::android::AttachCurrentThread(); - ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile); - DCHECK(profile_android); base::android::ScopedJavaLocalRef<jobject> j_profile_android = - profile_android->GetJavaObject(); - DCHECK(!j_profile_android.is_null()); + profile->GetJavaObject(); base::android::ScopedJavaLocalRef<jstring> geo_header = Java_GeolocationHeader_getGeoHeader(
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc index 68dd0164..e564fb6 100644 --- a/chrome/browser/android/signin/signin_manager_android.cc +++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -23,7 +23,6 @@ #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h" #include "chrome/browser/policy/cloud/user_policy_signin_service_mobile.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/signin/account_id_from_account_info.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/sync/sync_service_factory.h" @@ -171,7 +170,7 @@ java_signin_manager_ = Java_SigninManagerImpl_create( base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this), - ProfileAndroid::FromProfile(profile_)->GetJavaObject(), + profile_->GetJavaObject(), identity_manager_->LegacyGetAccountTrackerServiceJavaObject(), identity_manager_->GetJavaObject(), identity_manager_->GetIdentityMutatorJavaObject(),
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc b/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc index 45584701..2cb09e1 100644 --- a/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc +++ b/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
@@ -12,13 +12,13 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/raw_ptr.h" -#include "base/run_loop.h" #include "base/strings/string_piece.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_command_line.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" +#include "base/test/test_future.h" #include "base/version.h" #include "chrome/browser/ash/crosapi/browser_data_migrator_util.h" #include "chrome/browser/ash/crosapi/browser_util.h" @@ -83,17 +83,12 @@ ash::standalone_browser::migrator_util::UpdateMigrationAttemptCountForUser( &pref_service_, user_id_hash); - base::RunLoop run_loop; + base::test::TestFuture<BrowserDataMigrator::Result> future; std::unique_ptr<BrowserDataMigratorImpl> migrator = std::make_unique<BrowserDataMigratorImpl>( from_dir_, user_id_hash, base::DoNothing(), &pref_service_); - std::optional<BrowserDataMigrator::Result> result; - migrator->Migrate(base::BindLambdaForTesting( - [&out_result = result, &run_loop](BrowserDataMigrator::Result result) { - run_loop.Quit(); - out_result = result; - })); - run_loop.Run(); + migrator->Migrate(future.GetCallback()); + BrowserDataMigrator::Result result = future.Take(); const base::FilePath new_user_data_dir = from_dir_.Append(browser_data_migrator_util::kLacrosDir); @@ -105,8 +100,7 @@ EXPECT_TRUE( ash::standalone_browser::migrator_util:: IsProfileMigrationCompletedForUser(&pref_service_, user_id_hash)); - ASSERT_TRUE(result.has_value()); - EXPECT_EQ(BrowserDataMigrator::ResultKind::kSucceeded, result->kind); + EXPECT_EQ(BrowserDataMigrator::ResultKind::kSucceeded, result.kind); EXPECT_EQ(BrowserDataMigratorImpl::GetMigrationStep(&pref_service_), BrowserDataMigratorImpl::MigrationStep::kEnded); // Successful migration should clear the migration attempt count. @@ -131,18 +125,13 @@ ash::standalone_browser::migrator_util::UpdateMigrationAttemptCountForUser( &pref_service_, user_id_hash); - base::RunLoop run_loop; + base::test::TestFuture<BrowserDataMigrator::Result> future; std::unique_ptr<BrowserDataMigratorImpl> migrator = std::make_unique<BrowserDataMigratorImpl>( from_dir_, user_id_hash, base::DoNothing(), &pref_service_); - std::optional<BrowserDataMigrator::Result> result; - migrator->Migrate(base::BindLambdaForTesting( - [&out_result = result, &run_loop](BrowserDataMigrator::Result result) { - run_loop.Quit(); - out_result = result; - })); + migrator->Migrate(future.GetCallback()); migrator->Cancel(); - run_loop.Run(); + BrowserDataMigrator::Result result = future.Take(); const base::FilePath new_user_data_dir = from_dir_.Append(browser_data_migrator_util::kLacrosDir); @@ -152,8 +141,7 @@ EXPECT_FALSE( ash::standalone_browser::migrator_util:: IsProfileMigrationCompletedForUser(&pref_service_, user_id_hash)); - ASSERT_TRUE(result.has_value()); - EXPECT_EQ(BrowserDataMigrator::ResultKind::kCancelled, result->kind); + EXPECT_EQ(BrowserDataMigrator::ResultKind::kCancelled, result.kind); EXPECT_EQ(BrowserDataMigratorImpl::GetMigrationStep(&pref_service_), BrowserDataMigratorImpl::MigrationStep::kEnded); // If migration fails, migration attempt count should not be cleared thus @@ -179,22 +167,16 @@ BrowserDataMigratorImpl::SetMigrationStep( &pref_service_, BrowserDataMigratorImpl::MigrationStep::kRestartCalled); - base::RunLoop run_loop; + base::test::TestFuture<BrowserDataMigrator::Result> future; std::unique_ptr<BrowserDataMigratorImpl> migrator = std::make_unique<BrowserDataMigratorImpl>( from_dir_, user_id_hash, base::DoNothing(), &pref_service_); - std::optional<BrowserDataMigrator::Result> result; - migrator->Migrate(base::BindLambdaForTesting( - [&out_result = result, &run_loop](BrowserDataMigrator::Result result) { - run_loop.Quit(); - out_result = result; - })); - run_loop.Run(); + migrator->Migrate(future.GetCallback()); + BrowserDataMigrator::Result result = future.Take(); - ASSERT_TRUE(result.has_value()); - EXPECT_EQ(BrowserDataMigrator::ResultKind::kFailed, result->kind); + EXPECT_EQ(BrowserDataMigrator::ResultKind::kFailed, result.kind); // |required_size| should carry the data. - EXPECT_EQ(100u, result->required_size); + EXPECT_EQ(100u, result.required_size); } class BrowserDataMigratorRestartTest : public ::testing::Test { @@ -297,16 +279,12 @@ base::test::ScopedCommandLine command_line; command_line.GetProcessCommandLine()->AppendSwitchASCII( switches::kForceBrowserDataMigrationForTesting, "force-skip"); - std::optional<bool> result; + base::test::TestFuture<bool, const std::optional<uint64_t>&> future; BrowserDataMigratorImpl::MaybeRestartToMigrateWithDiskCheck( - user->GetAccountId(), user->username_hash(), - base::BindLambdaForTesting( - [&out_result = result](bool result, - const std::optional<uint64_t>& size) { - out_result = result; - })); - EXPECT_TRUE(result.has_value()); - EXPECT_FALSE(result.value()); + user->GetAccountId(), user->username_hash(), future.GetCallback()); + + bool success = future.Get<0>(); + EXPECT_FALSE(success); EXPECT_FALSE(restart_called); } @@ -321,21 +299,15 @@ browser_data_migrator_util::ScopedExtraBytesRequiredToBeFreedForTesting scoped_extra_bytes(1024 * 1024); - std::optional<bool> result; - std::optional<uint64_t> out_size; - base::RunLoop run_loop; + base::test::TestFuture<bool, const std::optional<uint64_t>> future; BrowserDataMigratorImpl::MaybeRestartToMigrateWithDiskCheck( user->GetAccountId(), user->username_hash(), - base::BindLambdaForTesting( - [&out_result = result, &out_size, &run_loop]( - bool result, const std::optional<uint64_t>& size) { - run_loop.Quit(); - out_result = result; - out_size = size; - })); - run_loop.Run(); - ASSERT_TRUE(result.has_value()); - EXPECT_FALSE(result.value()); + future.GetCallback<bool, const std::optional<uint64_t>&>()); + + bool success = future.Get<0>(); + std::optional<uint64_t> out_size = future.Get<1>(); + + EXPECT_FALSE(success); EXPECT_EQ(1024u * 1024u, out_size); EXPECT_FALSE(restart_called); } @@ -349,19 +321,14 @@ browser_data_migrator_util::ScopedExtraBytesRequiredToBeFreedForTesting scoped_extra_bytes(0); - std::optional<bool> result; - base::RunLoop run_loop; + base::test::TestFuture<bool, const std::optional<uint64_t>> future; BrowserDataMigratorImpl::MaybeRestartToMigrateWithDiskCheck( user->GetAccountId(), user->username_hash(), - base::BindLambdaForTesting( - [&out_result = result, &run_loop]( - bool result, const std::optional<uint64_t>& size) { - run_loop.Quit(); - out_result = result; - })); - run_loop.Run(); - ASSERT_TRUE(result.has_value()); - EXPECT_TRUE(result.value()); + future.GetCallback<bool, const std::optional<uint64_t>&>()); + + bool success = future.Get<0>(); + + EXPECT_TRUE(success); EXPECT_TRUE(restart_called); } }
diff --git a/chrome/browser/ash/crosapi/crosapi_util.cc b/chrome/browser/ash/crosapi/crosapi_util.cc index 5660927..0e95754 100644 --- a/chrome/browser/ash/crosapi/crosapi_util.cc +++ b/chrome/browser/ash/crosapi/crosapi_util.cc
@@ -956,6 +956,8 @@ params->is_cros_mall_enabled = chromeos::features::IsCrosMallEnabled(); + params->is_magic_boost_enabled = chromeos::features::IsMagicBoostEnabled(); + params->is_mahi_enabled = chromeos::features::IsMahiEnabled(); params->is_container_app_preinstall_enabled =
diff --git a/chrome/browser/ash/crosapi/screen_manager_ash_browsertest.cc b/chrome/browser/ash/crosapi/screen_manager_ash_browsertest.cc index 5b9f09e..7cda949 100644 --- a/chrome/browser/ash/crosapi/screen_manager_ash_browsertest.cc +++ b/chrome/browser/ash/crosapi/screen_manager_ash_browsertest.cc
@@ -2,14 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/ash/crosapi/screen_manager_ash.h" + #include <memory> #include "ash/public/cpp/test/shell_test_api.h" +#include "base/functional/callback_forward.h" +#include "base/location.h" #include "base/memory/scoped_refptr.h" #include "base/task/sequenced_task_runner.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" -#include "chrome/browser/ash/crosapi/screen_manager_ash.h" +#include "base/test/test_future.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/test/base/in_process_browser_test.h" @@ -70,6 +74,13 @@ background_sequence_->PostTask(FROM_HERE, std::move(bind_background)); } + void PostTaskAndWait(base::OnceClosure closure) { + base::test::TestFuture<void> future; + background_sequence_->PostTaskAndReply(FROM_HERE, std::move(closure), + future.GetCallback()); + EXPECT_TRUE(future.Wait()); + } + // Affine to main sequence. std::unique_ptr<ScreenManagerAsh> screen_manager_; @@ -81,7 +92,6 @@ }; IN_PROC_BROWSER_TEST_F(ScreenManagerAshBrowserTest, ScreenCapturer) { - base::RunLoop run_loop; bool success; SkBitmap snapshot; @@ -105,9 +115,7 @@ } }, screen_manager_remote_.get(), &success, &snapshot); - background_sequence_->PostTaskAndReply( - FROM_HERE, std::move(take_snapshot_background), run_loop.QuitClosure()); - run_loop.Run(); + PostTaskAndWait(std::move(take_snapshot_background)); // Check that the IPC succeeded. ASSERT_TRUE(success); @@ -121,7 +129,6 @@ IN_PROC_BROWSER_TEST_F(ScreenManagerAshBrowserTest, ScreenCapturer_MultipleDisplays) { - base::RunLoop run_loop; bool success[2]; SkBitmap snapshot[2]; @@ -149,9 +156,7 @@ } }, screen_manager_remote_.get(), success, snapshot); - background_sequence_->PostTaskAndReply( - FROM_HERE, std::move(take_snapshot_background), run_loop.QuitClosure()); - run_loop.Run(); + PostTaskAndWait(std::move(take_snapshot_background)); // Check that the IPCs succeeded. ASSERT_TRUE(success[0]); @@ -165,7 +170,6 @@ } IN_PROC_BROWSER_TEST_F(ScreenManagerAshBrowserTest, WindowCapturer) { - base::RunLoop run_loop; bool success; SkBitmap snapshot; @@ -189,9 +193,7 @@ } }, screen_manager_remote_.get(), &success, &snapshot); - background_sequence_->PostTaskAndReply( - FROM_HERE, std::move(take_snapshot_background), run_loop.QuitClosure()); - run_loop.Run(); + PostTaskAndWait(std::move(take_snapshot_background)); // Check that the IPC succeeded. ASSERT_TRUE(success);
diff --git a/chrome/browser/ash/crosapi/search_controller_ash_unittest.cc b/chrome/browser/ash/crosapi/search_controller_ash_unittest.cc index c666689..2619f83 100644 --- a/chrome/browser/ash/crosapi/search_controller_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/search_controller_ash_unittest.cc
@@ -47,10 +47,10 @@ } void RunUntilSearch() { - base::RunLoop loop; - base::AutoReset<base::RepeatingClosure> quit_loop(&search_callback_, - loop.QuitClosure()); - loop.Run(); + base::test::TestFuture<void> future; + base::AutoReset<base::RepeatingClosure> quit_loop( + &search_callback_, future.GetRepeatingCallback()); + EXPECT_TRUE(future.Wait()); } void ProduceResults( @@ -96,11 +96,9 @@ std::make_unique<SearchControllerAsh>(mojom_controller.BindToRemote()); } { - base::RunLoop loop; - controller->AddDisconnectHandler( - SearchControllerAsh::DisconnectCallback(base::DoNothing()) - .Then(loop.QuitClosure())); - loop.Run(); + DisconnectTestFuture future1; + controller->AddDisconnectHandler(future1.GetCallback()); + EXPECT_TRUE(future1.Wait()); } controller->Search(u"cat", future.GetRepeatingCallback()); @@ -345,11 +343,9 @@ SearchControllerAsh controller(mojom_controller->BindToRemote()); mojom_controller.reset(); { - base::RunLoop loop; - controller.AddDisconnectHandler( - SearchControllerAsh::DisconnectCallback(base::DoNothing()) - .Then(loop.QuitClosure())); - loop.Run(); + DisconnectTestFuture future1; + controller.AddDisconnectHandler(future1.GetCallback()); + EXPECT_TRUE(future1.Wait()); } ASSERT_FALSE(controller.IsConnected());
diff --git a/chrome/browser/ash/crosapi/video_conference_ash_browsertest.cc b/chrome/browser/ash/crosapi/video_conference_ash_browsertest.cc index 3c50aa0..991856b0 100644 --- a/chrome/browser/ash/crosapi/video_conference_ash_browsertest.cc +++ b/chrome/browser/ash/crosapi/video_conference_ash_browsertest.cc
@@ -2,20 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ash/video_conference/video_conference_manager_ash.h" - #include <utility> #include <vector> #include "ash/constants/ash_features.h" #include "ash/constants/ash_switches.h" #include "base/command_line.h" -#include "base/run_loop.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" +#include "base/test/test_future.h" #include "base/unguessable_token.h" #include "chrome/browser/ash/crosapi/crosapi_ash.h" #include "chrome/browser/ash/crosapi/crosapi_manager.h" +#include "chrome/browser/ash/video_conference/video_conference_manager_ash.h" #include "chrome/test/base/in_process_browser_test.h" #include "chromeos/crosapi/mojom/video_conference.mojom.h" #include "content/public/test/browser_test.h" @@ -82,47 +81,35 @@ // Calls all crosapi::mojom::VideoConference methods over mojo. void CallVcManagerAshMethods(FakeVcManagerMojoClient& client) { - base::RunLoop run_loop1; + base::test::TestFuture<bool> future1; client.remote_->NotifyMediaUsageUpdate( crosapi::mojom::VideoConferenceMediaUsageStatus::New( client.id_, true, false, true, false, true, false), - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); - run_loop1.Quit(); - })); - run_loop1.Run(); + future1.GetCallback()); + EXPECT_TRUE(future1.Take()); - base::RunLoop run_loop2; + base::test::TestFuture<bool> future2; client.remote_->NotifyDeviceUsedWhileDisabled( crosapi::mojom::VideoConferenceMediaDevice::kCamera, u"Test App", - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); - run_loop2.Quit(); - })); - run_loop2.Run(); + future2.GetCallback()); + EXPECT_TRUE(future2.Take()); } // Calls all crosapi::mojom::VideoConference methods directly. void CallVcManagerAshMethods(FakeVcManagerCppClient& client, ash::VideoConferenceManagerAsh* vc_manager) { - base::RunLoop run_loop1; + base::test::TestFuture<bool> future1; vc_manager->NotifyMediaUsageUpdate( crosapi::mojom::VideoConferenceMediaUsageStatus::New( client.id_, true, true, false, false, true, true), - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); - run_loop1.Quit(); - })); - run_loop1.Run(); + future1.GetCallback()); + EXPECT_TRUE(future1.Take()); - base::RunLoop run_loop2; + base::test::TestFuture<bool> future2; vc_manager->NotifyDeviceUsedWhileDisabled( crosapi::mojom::VideoConferenceMediaDevice::kCamera, u"Test App", - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); - run_loop2.Quit(); - })); - run_loop2.Run(); + future2.GetCallback()); + EXPECT_TRUE(future2.Take()); } class VideoConferenceAshBrowserTest : public InProcessBrowserTest { @@ -157,14 +144,11 @@ FakeVcManagerMojoClient mojo_client1; vc_manager->BindReceiver(mojo_client1.remote_.BindNewPipeAndPassReceiver()); - base::RunLoop run_loop1; + base::test::TestFuture<bool> future1; mojo_client1.remote_->RegisterMojoClient( mojo_client1.receiver_.BindNewPipeAndPassRemote(), mojo_client1.id_, - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); - run_loop1.Quit(); - })); - run_loop1.Run(); + future1.GetCallback()); + EXPECT_TRUE(future1.Take()); FakeVcManagerCppClient cpp_client1; vc_manager->RegisterCppClient(&cpp_client1, cpp_client1.id_); @@ -178,14 +162,11 @@ FakeVcManagerMojoClient mojo_client2; vc_manager->BindReceiver(mojo_client2.remote_.BindNewPipeAndPassReceiver()); - base::RunLoop run_loop1; + base::test::TestFuture<bool> future2; mojo_client2.remote_->RegisterMojoClient( mojo_client2.receiver_.BindNewPipeAndPassRemote(), mojo_client2.id_, - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); - run_loop1.Quit(); - })); - run_loop1.Run(); + future2.GetCallback()); + EXPECT_TRUE(future2.Take()); FakeVcManagerCppClient cpp_client2; vc_manager->RegisterCppClient(&cpp_client2, cpp_client2.id_);
diff --git a/chrome/browser/ash/crosapi/wallpaper_ash_unittest.cc b/chrome/browser/ash/crosapi/wallpaper_ash_unittest.cc index 4d8dab0b..c6e804b 100644 --- a/chrome/browser/ash/crosapi/wallpaper_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/wallpaper_ash_unittest.cc
@@ -9,6 +9,7 @@ #include "base/memory/ptr_util.h" #include "base/memory/raw_ptr.h" #include "base/test/bind.h" +#include "base/test/test_future.h" #include "chrome/browser/ash/crosapi/wallpaper_ash.h" #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" #include "chrome/browser/ash/profiles/profile_helper.h" @@ -20,6 +21,7 @@ #include "chrome/test/base/testing_profile_manager.h" #include "chromeos/ash/components/browser_context_helper/annotated_account_id.h" #include "chromeos/ash/components/login/login_state/login_state.h" +#include "chromeos/crosapi/mojom/wallpaper.mojom-forward.h" #include "chromeos/crosapi/mojom/wallpaper.mojom.h" #include "components/crash/core/common/crash_key.h" #include "components/user_manager/scoped_user_manager.h" @@ -52,6 +54,8 @@ return jpg_data; } +using crosapi::mojom::SetWallpaperResultPtr; + class WallpaperAshTest : public testing::Test { public: WallpaperAshTest() @@ -86,6 +90,16 @@ ash::LoginState::Shutdown(); } + SetWallpaperResultPtr SetWallpaper( + mojom::WallpaperSettingsPtr wallpaper_settings, + const std::string& extension_id, + const std::string& extension_name) { + base::test::TestFuture<SetWallpaperResultPtr> future; + wallpaper_ash_.SetWallpaper(std::move(wallpaper_settings), extension_id, + extension_name, future.GetCallback()); + return future.Take(); + } + protected: // We need to satisfy DCHECK_CURRENTLY_ON(BrowserThread::UI). content::BrowserTaskEnvironment task_environment_; @@ -105,16 +119,11 @@ settings->data = CreateJpeg(); test_wallpaper_controller_.SetCurrentUser(user_manager::StubAccountId()); - base::RunLoop loop; - wallpaper_ash_.SetWallpaper( - std::move(settings), "extension_id", "extension_name", - base::BindLambdaForTesting( - [&loop](const crosapi::mojom::SetWallpaperResultPtr result) { - ASSERT_TRUE(result->is_thumbnail_data()); - ASSERT_FALSE(result->get_thumbnail_data().empty()); - loop.Quit(); - })); - loop.Run(); + const SetWallpaperResultPtr result = + SetWallpaper(std::move(settings), "extension_id", "extension_name"); + + ASSERT_TRUE(result->is_thumbnail_data()); + ASSERT_FALSE(result->get_thumbnail_data().empty()); ASSERT_EQ(1, test_wallpaper_controller_.get_third_party_wallpaper_count()); } @@ -125,16 +134,11 @@ settings->data = CreateJpeg(1, 1); test_wallpaper_controller_.SetCurrentUser(user_manager::StubAccountId()); - base::RunLoop loop; - wallpaper_ash_.SetWallpaper( - std::move(settings), "extension_id", "extension_name", - base::BindLambdaForTesting( - [&loop](const crosapi::mojom::SetWallpaperResultPtr result) { - ASSERT_TRUE(result->is_thumbnail_data()); - ASSERT_FALSE(result->get_thumbnail_data().empty()); - loop.Quit(); - })); - loop.Run(); + const SetWallpaperResultPtr result = + SetWallpaper(std::move(settings), "extension_id", "extension_name"); + + ASSERT_TRUE(result->is_thumbnail_data()); + ASSERT_FALSE(result->get_thumbnail_data().empty()); ASSERT_EQ(1, test_wallpaper_controller_.get_third_party_wallpaper_count()); } @@ -145,17 +149,11 @@ test_wallpaper_controller_.SetCurrentUser(user_manager::StubAccountId()); // Created invalid data by not adding a wallpaper image to the settings data. - base::RunLoop loop; - wallpaper_ash_.SetWallpaper( - std::move(settings), "extension_id", "extension_name", - base::BindLambdaForTesting( - [&loop](const crosapi::mojom::SetWallpaperResultPtr result) { - ASSERT_TRUE(result->is_error_message()); - ASSERT_EQ("Decoding wallpaper data failed.", - result->get_error_message()); - loop.Quit(); - })); - loop.Run(); + const SetWallpaperResultPtr result = + SetWallpaper(std::move(settings), "extension_id", "extension_name"); + + ASSERT_TRUE(result->is_error_message()); + ASSERT_EQ("Decoding wallpaper data failed.", result->get_error_message()); ASSERT_EQ(0, test_wallpaper_controller_.get_third_party_wallpaper_count()); } @@ -166,17 +164,12 @@ settings->data = CreateJpeg(); // Setting the wallpaper fails because we haven't set the current user. - base::RunLoop loop; - wallpaper_ash_.SetWallpaper( - std::move(settings), "extension_id", "extension_name", - base::BindLambdaForTesting( - [&loop](const crosapi::mojom::SetWallpaperResultPtr result) { - ASSERT_TRUE(result->is_error_message()); - ASSERT_EQ("Setting the wallpaper failed due to user permissions.", - result->get_error_message()); - loop.Quit(); - })); - loop.Run(); + const SetWallpaperResultPtr result = + SetWallpaper(std::move(settings), "extension_id", "extension_name"); + + ASSERT_TRUE(result->is_error_message()); + ASSERT_EQ("Setting the wallpaper failed due to user permissions.", + result->get_error_message()); ASSERT_EQ(0, test_wallpaper_controller_.get_third_party_wallpaper_count()); } @@ -190,21 +183,17 @@ settings->data = CreateJpeg(); // Invoke SetWallpaper(). It will respond with success. - base::RunLoop loop; - wallpaper_ash_.SetWallpaper( - std::move(settings), "extension_id", "extension_name", - base::BindLambdaForTesting( - [&loop](const crosapi::mojom::SetWallpaperResultPtr result) { - ASSERT_FALSE(result->is_error_message()); - loop.Quit(); - })); + base::test::TestFuture<SetWallpaperResultPtr> future; + wallpaper_ash_.SetWallpaper(std::move(settings), "extension_id", + "extension_name", future.GetCallback()); // Crash key is set when function starts running. using crash_reporter::GetCrashKeyValue; EXPECT_EQ(GetCrashKeyValue("extension-function-caller-1"), "extension_id"); // Crash key is cleared after function completes. - loop.Run(); + const SetWallpaperResultPtr result = future.Take(); + ASSERT_FALSE(result->is_error_message()); EXPECT_EQ(GetCrashKeyValue("extension-function-caller-1"), ""); } @@ -216,21 +205,17 @@ crosapi::mojom::WallpaperSettings::New(); // Invoke SetWallpaper(). It will respond with an error. - base::RunLoop loop; - wallpaper_ash_.SetWallpaper( - std::move(settings), "extension_id", "extension_name", - base::BindLambdaForTesting( - [&loop](const crosapi::mojom::SetWallpaperResultPtr result) { - ASSERT_TRUE(result->is_error_message()); - loop.Quit(); - })); + base::test::TestFuture<SetWallpaperResultPtr> future; + wallpaper_ash_.SetWallpaper(std::move(settings), "extension_id", + "extension_name", future.GetCallback()); // Crash key is set when function starts running. using crash_reporter::GetCrashKeyValue; EXPECT_EQ(GetCrashKeyValue("extension-function-caller-1"), "extension_id"); // Crash key is cleared after function completes. - loop.Run(); + const SetWallpaperResultPtr result = future.Take(); + ASSERT_TRUE(result->is_error_message()); EXPECT_EQ(GetCrashKeyValue("extension-function-caller-1"), ""); }
diff --git a/chrome/browser/ash/login/app_mode/test/web_kiosk_browsertest.cc b/chrome/browser/ash/login/app_mode/test/web_kiosk_browsertest.cc index 996699ee..56335714 100644 --- a/chrome/browser/ash/login/app_mode/test/web_kiosk_browsertest.cc +++ b/chrome/browser/ash/login/app_mode/test/web_kiosk_browsertest.cc
@@ -39,6 +39,7 @@ #include "chrome/browser/web_applications/web_app_install_info.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/common/chrome_features.h" +#include "chrome/common/pref_names.h" #include "components/webapps/browser/install_result_code.h" #include "content/public/test/browser_test.h" #include "content/public/test/url_loader_interceptor.h" @@ -98,6 +99,26 @@ return success_future.Wait(); } +Browser::CreateParams CreateNewBrowserParams(Browser* initial_kiosk_browser, + bool is_popup_browser) { + return is_popup_browser + ? Browser::CreateParams::CreateForAppPopup( + initial_kiosk_browser->app_name(), /*trusted_source=*/true, + /*window_bounds=*/gfx::Rect(), + initial_kiosk_browser->profile(), + /*user_gesture=*/true) + : Browser::CreateParams(initial_kiosk_browser->profile(), + /*user_gesture=*/true); +} + +Browser* OpenNewBrowser(Browser* initial_kiosk_browser, bool is_popup_browser) { + Browser::CreateParams params = + CreateNewBrowserParams(initial_kiosk_browser, is_popup_browser); + Browser* new_browser = Browser::Create(params); + new_browser->window()->Show(); + return new_browser; +} + class WebKioskTest : public WebKioskBaseTest { public: WebKioskTest() = default; @@ -361,5 +382,73 @@ EXPECT_FALSE(session->is_shutting_down()); } +IN_PROC_BROWSER_TEST_F(WebKioskTest, + NewPopupBrowserInKioskNotAllowedByDefault) { + InitializeRegularOnlineKiosk(); + // The initial browser should exist in the web kiosk session. + ASSERT_EQ(BrowserList::GetInstance()->size(), 1u); + Browser* initial_browser = BrowserList::GetInstance()->get(0); + EXPECT_FALSE(initial_browser->profile()->GetPrefs()->GetBoolean( + prefs::kNewWindowsInKioskAllowed)); + + Browser* new_popup_browser = + OpenNewBrowser(initial_browser, /*is_popup_browser=*/true); + + TestBrowserClosedWaiter browser_closed_waiter{new_popup_browser}; + ASSERT_TRUE(browser_closed_waiter.WaitUntilClosed()); + EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); +} + +IN_PROC_BROWSER_TEST_F(WebKioskTest, + NewRegularBrowserInKioskNotAllowedByDefault) { + InitializeRegularOnlineKiosk(); + // The initial browser should exist in the web kiosk session. + ASSERT_EQ(BrowserList::GetInstance()->size(), 1u); + Browser* initial_browser = BrowserList::GetInstance()->get(0); + EXPECT_FALSE(initial_browser->profile()->GetPrefs()->GetBoolean( + prefs::kNewWindowsInKioskAllowed)); + + Browser* new_browser = + OpenNewBrowser(initial_browser, /*is_popup_browser=*/false); + + TestBrowserClosedWaiter browser_closed_waiter{new_browser}; + ASSERT_TRUE(browser_closed_waiter.WaitUntilClosed()); + EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); +} + +IN_PROC_BROWSER_TEST_F(WebKioskTest, NewPopupBrowserInKioskAllowedByPolicy) { + InitializeRegularOnlineKiosk(); + // The initial browser should exist in the web kiosk session. + ASSERT_EQ(BrowserList::GetInstance()->size(), 1u); + Browser* initial_browser = BrowserList::GetInstance()->get(0); + KioskSystemSession* session = KioskController::Get().GetKioskSystemSession(); + + initial_browser->profile()->GetPrefs()->SetBoolean( + prefs::kNewWindowsInKioskAllowed, true); + Browser* new_popup_browser = + OpenNewBrowser(initial_browser, /*is_popup_browser=*/true); + + EXPECT_FALSE(DidSessionCloseNewWindow(session)); + ASSERT_NE(new_popup_browser, nullptr); + EXPECT_EQ(BrowserList::GetInstance()->size(), 2u); +} + +IN_PROC_BROWSER_TEST_F(WebKioskTest, + NewRegularBrowserInKioskNotAllowedEvenByPolicy) { + InitializeRegularOnlineKiosk(); + // The initial browser should exist in the web kiosk session. + ASSERT_EQ(BrowserList::GetInstance()->size(), 1u); + Browser* initial_browser = BrowserList::GetInstance()->get(0); + + initial_browser->profile()->GetPrefs()->SetBoolean( + prefs::kNewWindowsInKioskAllowed, true); + Browser* new_browser = + OpenNewBrowser(initial_browser, /*is_popup_browser=*/false); + + TestBrowserClosedWaiter browser_closed_waiter{new_browser}; + ASSERT_TRUE(browser_closed_waiter.WaitUntilClosed()); + EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); +} + } // namespace } // namespace ash
diff --git a/chrome/browser/ash/login/oobe_apps_service/oobe_apps_discovery_service.cc b/chrome/browser/ash/login/oobe_apps_service/oobe_apps_discovery_service.cc index b38fe99..4910f87 100644 --- a/chrome/browser/ash/login/oobe_apps_service/oobe_apps_discovery_service.cc +++ b/chrome/browser/ash/login/oobe_apps_service/oobe_apps_discovery_service.cc
@@ -64,6 +64,7 @@ for (oobe::proto::OOBEListResponse::Tag usecase : response->tags()) { use_cases_.emplace_back(std::move(usecase)); } + std::sort(use_cases_.begin(), use_cases_.end()); PropagateResult(std::move(callback_), AppsFetchingResult::kSuccess); }
diff --git a/chrome/browser/ash/login/oobe_apps_service/oobe_apps_types.h b/chrome/browser/ash/login/oobe_apps_service/oobe_apps_types.h index dfcf35b1..53451ce 100644 --- a/chrome/browser/ash/login/oobe_apps_service/oobe_apps_types.h +++ b/chrome/browser/ash/login/oobe_apps_service/oobe_apps_types.h
@@ -33,6 +33,11 @@ const std::string& GetDescription() const; + // Overloading < operator for sorting. + bool operator<(const OOBEDeviceUseCase& obj) const { + return order_ < obj.order_; + } + private: std::string id_;
diff --git a/chrome/browser/ash/login/screens/categories_selection_screen.cc b/chrome/browser/ash/login/screens/categories_selection_screen.cc index fd05a7b..fe74dde53 100644 --- a/chrome/browser/ash/login/screens/categories_selection_screen.cc +++ b/chrome/browser/ash/login/screens/categories_selection_screen.cc
@@ -20,6 +20,18 @@ constexpr const char kUserActionNext[] = "next"; constexpr const char kUserActionSkip[] = "skip"; +bool HasBeenSelected(std::string category_id) { + PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs(); + const base::Value::List& selected_categories = + prefs->GetList(prefs::kOobeCategoriesSelected); + for (const auto& category : selected_categories) { + if (category.GetString() == category_id) { + return true; + } + } + return false; +} + } // namespace // static @@ -92,24 +104,23 @@ exit_callback_.Run(Result::kError); } - // PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs(); - // const base::Value::List& selected_categories = - // prefs->GetList(prefs::kOobeCategoriesSelected); - base::Value::List categories_list; for (OOBEDeviceUseCase category : categories) { + // Disregard the category with order 0, as it relates to a general, + // non-specific use case (oobe_otheres). + if (category.GetOrder() == 0) { + continue; + } base::Value::Dict category_dict; category_dict.Set("categoryId", base::Value(std::move(category.GetID()))); category_dict.Set("title", base::Value(std::move(category.GetLabel()))); category_dict.Set("subtitle", base::Value(std::move(category.GetDescription()))); category_dict.Set("icon", base::Value(std::move(category.GetImageURL()))); - category_dict.Set("selected", false); - category_dict.Set("order", base::Value(category.GetOrder())); + category_dict.Set("selected", HasBeenSelected(category.GetID())); categories_list.Append(std::move(category_dict)); } - // TODO(b/337674429) : need to sort with order as well as pre select old - // value. + base::Value::Dict data; data.Set("categories", std::move(categories_list)); if (view_) {
diff --git a/chrome/browser/ash/policy/login/signin_profile_extensions_policy_browsertest.cc b/chrome/browser/ash/policy/login/signin_profile_extensions_policy_browsertest.cc index 4d4514dd..1adf434 100644 --- a/chrome/browser/ash/policy/login/signin_profile_extensions_policy_browsertest.cc +++ b/chrome/browser/ash/policy/login/signin_profile_extensions_policy_browsertest.cc
@@ -30,7 +30,6 @@ #include "content/public/test/browser_test.h" #include "content/public/test/test_launcher.h" #include "content/public/test/test_utils.h" -#include "extensions/browser/extension_host_test_helper.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/extension_util.h" @@ -321,7 +320,7 @@ EXPECT_TRUE(extension_force_install_mixin_.ForceInstallFromCrx( base::PathService::CheckedGet(chrome::DIR_TEST_DATA) .AppendASCII(kAllowlistedExtensionCrxPath), - ExtensionForceInstallMixin::WaitMode::kBackgroundPageFirstLoad)); + ExtensionForceInstallMixin::WaitMode::kLoad)); content::StoragePartition* storage_partition_for_app = extensions::util::GetStoragePartitionForExtensionId(
diff --git a/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc b/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc index a61deaa9..2f4739c4 100644 --- a/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc +++ b/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc
@@ -71,7 +71,6 @@ #include "content/public/test/browser_test.h" #include "content/public/test/test_utils.h" #include "crypto/scoped_test_nss_db.h" -#include "extensions/browser/extension_host_test_helper.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_util.h" #include "extensions/browser/test_extension_registry_observer.h" @@ -638,22 +637,20 @@ signin_profile_ = GetInitialProfile(); ASSERT_TRUE(ash::ProfileHelper::IsSigninProfile(signin_profile_)); - extensions::ExtensionHostTestHelper extension_1_observer( - signin_profile_, kSigninScreenExtension1); - extension_1_observer.RestrictToType( - extensions::mojom::ViewType::kExtensionBackgroundPage); - extensions::ExtensionHostTestHelper extension_2_observer( - signin_profile_, kSigninScreenExtension2); - extension_2_observer.RestrictToType( - extensions::mojom::ViewType::kExtensionBackgroundPage); + extensions::ExtensionRegistry* extension_registry = + extensions::ExtensionRegistry::Get(signin_profile_); + extensions::TestExtensionRegistryObserver extension_1_observer( + extension_registry, kSigninScreenExtension1); + extensions::TestExtensionRegistryObserver extension_2_observer( + extension_registry, kSigninScreenExtension2); AddExtensionForForceInstallation(kSigninScreenExtension1, kSigninScreenExtension1UpdateManifestPath); AddExtensionForForceInstallation(kSigninScreenExtension2, kSigninScreenExtension2UpdateManifestPath); - extension_1_observer.WaitForHostCompletedFirstLoad(); - extension_2_observer.WaitForHostCompletedFirstLoad(); + extension_1_observer.WaitForExtensionLoaded(); + extension_2_observer.WaitForExtensionLoaded(); } content::StoragePartition* GetStoragePartitionForSigninExtension(
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java index 1c33654..89d78af2e 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
@@ -459,19 +459,27 @@ mValue = value; } + // Creates an Iban instance that is not stored on a server nor locally, + // yet. This Iban has type IbanRecordType.UNKNOWN and has neither a + // Guid nor an instrumentId. @CalledByNative("Iban") - public static Iban createLocal( - String guid, - String label, - String nickname, - @IbanRecordType int recordType, - String value) { - assert recordType != IbanRecordType.SERVER_IBAN; + public static Iban createEphemeral(String label, String nickname, String value) { + return new Iban.Builder() + .setGuid("") + .setLabel(label) + .setNickname(nickname) + .setRecordType(IbanRecordType.UNKNOWN) + .setValue(value) + .build(); + } + + @CalledByNative("Iban") + public static Iban createLocal(String guid, String label, String nickname, String value) { return new Iban.Builder() .setGuid(guid) .setLabel(label) .setNickname(nickname) - .setRecordType(recordType) + .setRecordType(IbanRecordType.LOCAL_IBAN) .setValue(value) .build(); } @@ -490,6 +498,7 @@ @CalledByNative("Iban") public String getGuid() { + assert mRecordType != IbanRecordType.SERVER_IBAN; return mGuid; } @@ -534,12 +543,13 @@ Iban otherIban = (Iban) obj; - return Objects.equals(mGuid, otherIban.getGuid()) - && Objects.equals(mLabel, otherIban.getLabel()) + return Objects.equals(mLabel, otherIban.getLabel()) && Objects.equals(mNickname, otherIban.getNickname()) && mRecordType == otherIban.getRecordType() && (mRecordType != IbanRecordType.SERVER_IBAN || Objects.equals(mInstrumentId, otherIban.getInstrumentId())) + && (mRecordType != IbanRecordType.LOCAL_IBAN + || Objects.equals(mGuid, otherIban.getGuid())) && Objects.equals(mValue, otherIban.getValue()); }
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc index 269dee21..22066d5 100644 --- a/chrome/browser/autofill/android/personal_data_manager_android.cc +++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -728,21 +728,28 @@ ScopedJavaLocalRef<jobject> PersonalDataManagerAndroid::CreateJavaIbanFromNative(JNIEnv* env, const Iban& iban) { - if (iban.record_type() == Iban::kServerIban) { - return Java_Iban_createServer( - env, iban.instrument_id(), - ConvertUTF16ToJavaString(env, - iban.GetIdentifierStringForAutofillDisplay()), - ConvertUTF16ToJavaString(env, iban.nickname()), - ConvertUTF16ToJavaString(env, iban.GetRawInfo(IBAN_VALUE))); - } else { - return Java_Iban_createLocal( - env, ConvertUTF8ToJavaString(env, iban.guid()), - ConvertUTF16ToJavaString(env, - iban.GetIdentifierStringForAutofillDisplay()), - ConvertUTF16ToJavaString(env, iban.nickname()), - static_cast<jint>(iban.record_type()), - ConvertUTF16ToJavaString(env, iban.GetRawInfo(IBAN_VALUE))); + switch (iban.record_type()) { + case Iban::kLocalIban: + return Java_Iban_createLocal( + env, ConvertUTF8ToJavaString(env, iban.guid()), + ConvertUTF16ToJavaString( + env, iban.GetIdentifierStringForAutofillDisplay()), + ConvertUTF16ToJavaString(env, iban.nickname()), + ConvertUTF16ToJavaString(env, iban.GetRawInfo(IBAN_VALUE))); + case Iban::kServerIban: + return Java_Iban_createServer( + env, iban.instrument_id(), + ConvertUTF16ToJavaString( + env, iban.GetIdentifierStringForAutofillDisplay()), + ConvertUTF16ToJavaString(env, iban.nickname()), + ConvertUTF16ToJavaString(env, iban.GetRawInfo(IBAN_VALUE))); + case Iban::kUnknown: + return Java_Iban_createEphemeral( + env, + ConvertUTF16ToJavaString( + env, iban.GetIdentifierStringForAutofillDisplay()), + ConvertUTF16ToJavaString(env, iban.nickname()), + ConvertUTF16ToJavaString(env, iban.GetRawInfo(IBAN_VALUE))); } }
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc index a036fb7..7d0b4b30 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -156,7 +156,7 @@ #include "chrome/browser/android/oom_intervention/oom_intervention_decider.h" #include "chrome/browser/android/webapps/webapp_registry.h" #include "chrome/browser/offline_pages/offline_page_model_factory.h" -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/android/tab_model/tab_model.h" #include "chrome/browser/ui/android/tab_model/tab_model_list.h" #include "components/cdm/browser/media_drm_storage_impl.h" // nogncheck crbug.com/1125897 @@ -664,8 +664,7 @@ ->OnCookiesDeleted(); } - if (filter_builder->GetMode() == - BrowsingDataFilterBuilder::Mode::kPreserve) { + if (filter_builder->MatchesMostOriginsAndDomains()) { auto* privacy_sandbox_settings = PrivacySandboxSettingsFactory::GetForProfile(profile_); if (privacy_sandbox_settings) { @@ -678,9 +677,8 @@ } #if BUILDFLAG(IS_ANDROID) - Java_PackageHash_onCookiesDeleted( - base::android::AttachCurrentThread(), - ProfileAndroid::FromProfile(profile_)->GetJavaObject()); + Java_PackageHash_onCookiesDeleted(base::android::AttachCurrentThread(), + profile_->GetJavaObject()); #endif } @@ -1326,8 +1324,7 @@ #if BUILDFLAG(ENABLE_DOWNGRADE_PROCESSING) ////////////////////////////////////////////////////////////////////////////// // Remove data for this profile contained in any snapshots. - if (remove_mask && - filter_builder->GetMode() == BrowsingDataFilterBuilder::Mode::kPreserve) { + if (remove_mask && filter_builder->MatchesMostOriginsAndDomains()) { base::ThreadPool::PostTaskAndReply( FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, base::BindOnce(&downgrade::RemoveDataForProfile, delete_begin_,
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc index 4fd6743..4064b92 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -23,6 +23,7 @@ #include "base/memory/raw_ref.h" #include "base/memory/weak_ptr.h" #include "base/run_loop.h" +#include "base/scoped_observation.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -149,6 +150,7 @@ #include "components/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations.h" #include "components/privacy_sandbox/privacy_sandbox_attestations/scoped_privacy_sandbox_attestations.h" #include "components/privacy_sandbox/privacy_sandbox_settings.h" +#include "components/privacy_sandbox/privacy_sandbox_test_util.h" #include "components/reading_list/core/mock_reading_list_model_observer.h" #include "components/reading_list/core/reading_list_model.h" #include "components/safe_browsing/core/browser/verdict_cache_manager.h" @@ -181,6 +183,7 @@ #include "net/base/network_anonymization_key.h" #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_access_result.h" +#include "net/cookies/cookie_partition_key_collection.h" #include "net/http/http_auth.h" #include "net/http/http_auth_cache.h" #include "net/http/http_transaction_factory.h" @@ -4300,6 +4303,56 @@ } #endif // !BUILDFLAG(IS_ANDROID) +// When most cookies are cleared, PrivacySandboxSettings should call the +// OnTopicsDataAccessibleSinceUpdated() method of its observers. +TEST_F(ChromeBrowsingDataRemoverDelegateTest, + Call_OnTopicsDataAccessibleSinceUpdated_WhenClearingMostCookies) { + privacy_sandbox::PrivacySandboxSettings* settings = + PrivacySandboxSettingsFactory::GetForProfile(GetProfile()); + privacy_sandbox_test_util::MockPrivacySandboxObserver observer; + base::ScopedObservation<privacy_sandbox::PrivacySandboxSettings, + privacy_sandbox::PrivacySandboxSettings::Observer> + obs(&observer); + obs.Observe(settings); + + EXPECT_CALL(observer, OnTopicsDataAccessibleSinceUpdated()).Times(1); + + std::unique_ptr<BrowsingDataFilterBuilder> filter_builder = + BrowsingDataFilterBuilder::Create( + BrowsingDataFilterBuilder::Mode::kPreserve); + filter_builder->AddRegisterableDomain("example.test"); + ASSERT_TRUE(filter_builder->MatchesMostOriginsAndDomains()); + BlockUntilOriginDataRemoved(base::Time::Min(), base::Time::Max(), + content::BrowsingDataRemover::DATA_TYPE_COOKIES, + std::move(filter_builder)); +} + +// If only some cookies are cleared, PrivacySandboxSettings should NOT call the +// OnTopicsDataAccessibleSinceUpdated() method of its observers. +TEST_F( + ChromeBrowsingDataRemoverDelegateTest, + DontCall_OnTopicsDataAccessibleSinceUpdated_WhenOnlyClearingPartitionedCookies) { + privacy_sandbox::PrivacySandboxSettings* settings = + PrivacySandboxSettingsFactory::GetForProfile(GetProfile()); + privacy_sandbox_test_util::MockPrivacySandboxObserver observer; + base::ScopedObservation<privacy_sandbox::PrivacySandboxSettings, + privacy_sandbox::PrivacySandboxSettings::Observer> + obs(&observer); + obs.Observe(settings); + + EXPECT_CALL(observer, OnTopicsDataAccessibleSinceUpdated()).Times(0); + + // Create a filter builder that deletes only partitioned cookies. + std::unique_ptr<BrowsingDataFilterBuilder> filter_builder = + BrowsingDataFilterBuilder::Create( + BrowsingDataFilterBuilder::Mode::kPreserve); + filter_builder->SetPartitionedCookiesOnly(true); + ASSERT_FALSE(filter_builder->MatchesMostOriginsAndDomains()); + BlockUntilOriginDataRemoved(base::Time::Min(), base::Time::Max(), + content::BrowsingDataRemover::DATA_TYPE_COOKIES, + std::move(filter_builder)); +} + class ChromeBrowsingDataRemoverDelegateOriginTrialsTest : public ChromeBrowsingDataRemoverDelegateTest { public: @@ -4572,7 +4625,8 @@ } } -TEST_F(ChromeBrowsingDataRemoverDelegateTpcdMetadataTest, ResetAllCohort_PreserveMode) { +TEST_F(ChromeBrowsingDataRemoverDelegateTpcdMetadataTest, + ResetAllCohort_PreserveSome) { auto tester = RemoveTpcdMetadataCohortsTester(GetProfile()); const std::string primary_pattern_spec = "https://example1.com"; @@ -4627,12 +4681,12 @@ content_settings::mojom::TpcdMetadataCohort::GRACE_PERIOD_FORCED_ON); } - // Apply deletion of cookies with preservation of select URL. - // NOTE: This is still expected to reset all cohorts. + // Apply deletion of all cookies. std::unique_ptr<BrowsingDataFilterBuilder> filter( BrowsingDataFilterBuilder::Create( BrowsingDataFilterBuilder::Mode::kPreserve)); filter->AddRegisterableDomain(GURL(primary_pattern_spec).host()); + ASSERT_TRUE(filter->MatchesMostOriginsAndDomains()); BlockUntilOriginDataRemoved(base::Time(), base::Time::Max(), content::BrowsingDataRemover::DATA_TYPE_COOKIES, std::move(filter));
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 8e02930..498fa45 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -4136,10 +4136,8 @@ web_prefs->always_show_focus = prefs->GetBoolean(ash::prefs::kAccessibilityFocusHighlightEnabled); #else - if (features::IsAccessibilityFocusHighlightEnabled()) { - web_prefs->always_show_focus = - prefs->GetBoolean(prefs::kAccessibilityFocusHighlightEnabled); - } + web_prefs->always_show_focus = + prefs->GetBoolean(prefs::kAccessibilityFocusHighlightEnabled); #endif #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/commerce/price_tracking/android/price_tracking_notification_bridge.cc b/chrome/browser/commerce/price_tracking/android/price_tracking_notification_bridge.cc index f9b0f16..de1e663 100644 --- a/chrome/browser/commerce/price_tracking/android/price_tracking_notification_bridge.cc +++ b/chrome/browser/commerce/price_tracking/android/price_tracking_notification_bridge.cc
@@ -8,7 +8,6 @@ #include "base/memory/ptr_util.h" #include "chrome/browser/commerce/price_tracking/android/jni_headers/PriceTrackingNotificationBridge_jni.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "content/public/browser/browser_context.h" using OptimizationType = optimization_guide::proto::OptimizationType; @@ -31,11 +30,10 @@ PriceTrackingNotificationBridge::PriceTrackingNotificationBridge( Profile* profile) { JNIEnv* env = jni_zero::AttachCurrentThread(); - java_obj_.Reset(env, - Java_PriceTrackingNotificationBridge_create( - env, reinterpret_cast<intptr_t>(this), - ProfileAndroid::FromProfile(profile)->GetJavaObject()) - .obj()); + java_obj_.Reset( + env, Java_PriceTrackingNotificationBridge_create( + env, reinterpret_cast<intptr_t>(this), profile->GetJavaObject()) + .obj()); } PriceTrackingNotificationBridge::~PriceTrackingNotificationBridge() = default;
diff --git a/chrome/browser/component_updater/recovery_component_installer.cc b/chrome/browser/component_updater/recovery_component_installer.cc index 74c3e5f7..1ee83f7 100644 --- a/chrome/browser/component_updater/recovery_component_installer.cc +++ b/chrome/browser/component_updater/recovery_component_installer.cc
@@ -314,9 +314,7 @@ RecoveryComponentInstaller::RecoveryComponentInstaller( const base::Version& version, PrefService* prefs) - : current_version_(version), prefs_(prefs) { - DCHECK(version.IsValid()); -} + : current_version_(version), prefs_(prefs) {} void RecoveryComponentInstaller::OnUpdateError(int error) { NOTREACHED_IN_MIGRATION() << "Recovery component update error: " << error;
diff --git a/chrome/browser/component_updater/recovery_improved_component_installer.cc b/chrome/browser/component_updater/recovery_improved_component_installer.cc index 4369abfb..f0f40b5 100644 --- a/chrome/browser/component_updater/recovery_improved_component_installer.cc +++ b/chrome/browser/component_updater/recovery_improved_component_installer.cc
@@ -86,7 +86,6 @@ void RecoveryComponentActionHandler::UnpackComplete( const update_client::Unpacker::Result& result) { if (result.error != update_client::UnpackerError::kNone) { - DCHECK(!base::DirectoryExists(result.unpack_path)); main_task_runner_->PostTask( FROM_HERE, base::BindOnce(std::move(callback_), false,
diff --git a/chrome/browser/component_updater/updater_state.cc b/chrome/browser/component_updater/updater_state.cc index fd55a4b..96e44c5e 100644 --- a/chrome/browser/component_updater/updater_state.cc +++ b/chrome/browser/component_updater/updater_state.cc
@@ -144,7 +144,7 @@ state.is_autoupdate_check_enabled = IsAutoupdateCheckEnabled(); state.update_policy = [this] { const int update_policy = GetUpdatePolicy(); - DCHECK((update_policy >= 0 && update_policy <= 3) || update_policy == -1); + CHECK((update_policy >= 0 && update_policy <= 3) || update_policy == -1); return update_policy; }(); return state; @@ -216,7 +216,7 @@ val = "1344"; // 2*28 days in hours. } - DCHECK(!val.empty()); + CHECK(!val.empty()); return val; }
diff --git a/chrome/browser/component_updater/updater_state_mac.mm b/chrome/browser/component_updater/updater_state_mac.mm index 4b73439..b2fa863 100644 --- a/chrome/browser/component_updater/updater_state_mac.mm +++ b/chrome/browser/component_updater/updater_state_mac.mm
@@ -73,17 +73,15 @@ base::Version UpdaterState::StateReaderKeystone::GetUpdaterVersion( bool /*is_machine*/) const { - // System Keystone trumps user one, so check this one first + // System Keystone takes precedence over user one, so check this one first. base::FilePath local_library; - bool success = - base::apple::GetLocalDirectory(NSLibraryDirectory, &local_library); - DCHECK(success); - base::FilePath system_bundle_plist = local_library.Append(kKeystonePlist); - base::Version system_keystone = GetVersionFromPlist(system_bundle_plist); - if (system_keystone.IsValid()) { - return system_keystone; + if (base::apple::GetLocalDirectory(NSLibraryDirectory, &local_library)) { + base::FilePath system_bundle_plist = local_library.Append(kKeystonePlist); + base::Version system_keystone = GetVersionFromPlist(system_bundle_plist); + if (system_keystone.IsValid()) { + return system_keystone; + } } - base::FilePath user_bundle_plist = base::apple::GetUserLibraryPath().Append(kKeystonePlist); return GetVersionFromPlist(user_bundle_plist);
diff --git a/chrome/browser/data_sharing/data_sharing_ui_delegate_android.cc b/chrome/browser/data_sharing/data_sharing_ui_delegate_android.cc index 6e0989e7..9c97316 100644 --- a/chrome/browser/data_sharing/data_sharing_ui_delegate_android.cc +++ b/chrome/browser/data_sharing/data_sharing_ui_delegate_android.cc
@@ -6,7 +6,7 @@ #include "base/android/jni_string.h" #include "chrome/browser/data_sharing/jni_headers/DataSharingUIDelegateAndroid_jni.h" -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" #include "url/android/gurl_android.h" #include "url/gurl.h" @@ -14,7 +14,7 @@ DataSharingUIDelegateAndroid::DataSharingUIDelegateAndroid(Profile* profile) { JNIEnv* env = base::android::AttachCurrentThread(); - auto j_profile = ProfileAndroid::FromProfile(profile)->GetJavaObject(); + auto j_profile = profile->GetJavaObject(); java_obj_.Reset( env, Java_DataSharingUIDelegateAndroid_create(env, j_profile).obj()); }
diff --git a/chrome/browser/download/android/download_controller.cc b/chrome/browser/download/android/download_controller.cc index 658c112..600264144 100644 --- a/chrome/browser/download/android/download_controller.cc +++ b/chrome/browser/download/android/download_controller.cc
@@ -33,7 +33,6 @@ #include "chrome/browser/offline_pages/android/offline_page_bridge.h" #include "chrome/browser/permissions/permission_update_message_controller_android.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/ui/android/tab_model/tab_model.h" #include "chrome/browser/ui/android/tab_model/tab_model_list.h" #include "chrome/grit/branded_strings.h"
diff --git a/chrome/browser/download/android/download_dialog_bridge.cc b/chrome/browser/download/android/download_dialog_bridge.cc index 7ead77b..31ab760d 100644 --- a/chrome/browser/download/android/download_dialog_bridge.cc +++ b/chrome/browser/download/android/download_dialog_bridge.cc
@@ -11,7 +11,6 @@ #include "chrome/browser/download/android/download_controller.h" #include "chrome/browser/download/android/jni_headers/DownloadDialogBridge_jni.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/pref_names.h" #include "components/download/public/common/download_features.h" @@ -86,7 +85,7 @@ static_cast<int>(dialog_type), base::android::ConvertUTF8ToJavaString(env, suggested_path.AsUTF8Unsafe()), - ProfileAndroid::FromProfile(profile)->GetJavaObject()); + profile->GetJavaObject()); } void DownloadDialogBridge::OnComplete(
diff --git a/chrome/browser/download/android/items/offline_content_aggregator_factory_android.cc b/chrome/browser/download/android/items/offline_content_aggregator_factory_android.cc index d4a2be8..9811d6e 100644 --- a/chrome/browser/download/android/items/offline_content_aggregator_factory_android.cc +++ b/chrome/browser/download/android/items/offline_content_aggregator_factory_android.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h" + #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" #include "chrome/browser/android/profile_key_util.h" #include "chrome/browser/download/android/jni_headers/OfflineContentAggregatorFactory_jni.h" -#include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/profiles/profile_key.h" #include "components/offline_items_collection/core/android/offline_content_aggregator_bridge.h" #include "components/offline_items_collection/core/offline_content_aggregator.h"
diff --git a/chrome/browser/download/android/open_download_dialog_bridge.cc b/chrome/browser/download/android/open_download_dialog_bridge.cc index 21304b40..c988897 100644 --- a/chrome/browser/download/android/open_download_dialog_bridge.cc +++ b/chrome/browser/download/android/open_download_dialog_bridge.cc
@@ -18,7 +18,6 @@ #include "chrome/browser/download/android/download_dialog_utils.h" #include "chrome/browser/download/android/open_download_dialog_bridge_delegate.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/download_item_utils.h" @@ -44,8 +43,7 @@ const std::string& download_guid) { JNIEnv* env = base::android::AttachCurrentThread(); Java_OpenDownloadDialogBridge_showDialog( - env, java_object_, ProfileAndroid::FromProfile(profile)->GetJavaObject(), - download_guid); + env, java_object_, profile->GetJavaObject(), download_guid); } void OpenDownloadDialogBridge::OnConfirmed(JNIEnv* env,
diff --git a/chrome/browser/enterprise/data_controls/chrome_rules_service_unittest.cc b/chrome/browser/enterprise/data_controls/chrome_rules_service_unittest.cc index ddac0d70..5569eff 100644 --- a/chrome/browser/enterprise/data_controls/chrome_rules_service_unittest.cc +++ b/chrome/browser/enterprise/data_controls/chrome_rules_service_unittest.cc
@@ -24,13 +24,26 @@ class DataControlsRulesServiceTest : public testing::Test { public: - explicit DataControlsRulesServiceTest(bool feature_enabled = true) + explicit DataControlsRulesServiceTest(bool desktop_feature_enabled = true, + bool screenshot_feature_enabled = true) : profile_manager_(TestingBrowserProcess::GetGlobal()) { - if (feature_enabled) { - scoped_features_.InitAndEnableFeature(kEnableDesktopDataControls); + std::vector<base::test::FeatureRef> enabled_features; + std::vector<base::test::FeatureRef> disabled_features; + + if (desktop_feature_enabled) { + enabled_features.push_back(kEnableDesktopDataControls); } else { - scoped_features_.InitAndDisableFeature(kEnableDesktopDataControls); + disabled_features.push_back(kEnableDesktopDataControls); } + + if (screenshot_feature_enabled) { + enabled_features.push_back(kEnableScreenshotProtection); + } else { + disabled_features.push_back(kEnableScreenshotProtection); + } + + scoped_features_.InitWithFeatures(enabled_features, disabled_features); + EXPECT_TRUE(profile_manager_.SetUp()); profile_ = profile_manager_.CreateTestingProfile("test-user-1"); other_profile_ = profile_manager_.CreateTestingProfile("test-user-2"); @@ -137,16 +150,102 @@ std::unique_ptr<content::WebContents> incognito_web_contents_; }; -class DataControlsRulesServiceFeatureDisabledTest +class DataControlsRulesServiceDesktopFeatureDisabledTest : public DataControlsRulesServiceTest { public: - DataControlsRulesServiceFeatureDisabledTest() - : DataControlsRulesServiceTest(false) {} + DataControlsRulesServiceDesktopFeatureDisabledTest() + : DataControlsRulesServiceTest(false, true) {} +}; + +class DataControlsRulesServiceScreenshotFeatureDisabledTest + : public DataControlsRulesServiceTest { + public: + DataControlsRulesServiceScreenshotFeatureDisabledTest() + : DataControlsRulesServiceTest(true, false) {} +}; + +class DataControlsRulesServiceAllFeaturesDisabledTest + : public DataControlsRulesServiceTest { + public: + DataControlsRulesServiceAllFeaturesDisabledTest() + : DataControlsRulesServiceTest(false, false) {} }; } // namespace -TEST_F(DataControlsRulesServiceFeatureDisabledTest, NoVerdicts) { +TEST_F(DataControlsRulesServiceDesktopFeatureDisabledTest, + NoVerdictsForDesktopRestrictions) { + SetDataControls(profile()->GetPrefs(), {R"({ + "name": "block", + "rule_id": "1234", + "sources": { + "urls": ["google.com"] + }, + "restrictions": [ + {"class": "PRINTING", "level": "BLOCK"}, + {"class": "CLIPBOARD", "level": "BLOCK"}, + {"class": "SCREENSHOT", "level": "BLOCK"} + ] + })"}); + ExpectNoVerdict(ChromeRulesServiceFactory::GetInstance() + ->GetForBrowserContext(profile()) + ->GetPrintVerdict(google_url())); + ExpectNoVerdict(ChromeRulesServiceFactory::GetInstance() + ->GetForBrowserContext(profile()) + ->GetPasteVerdict( + /*source*/ google_url_endpoint(), + /*destination*/ empty_endpoint(), + /*metadata*/ {})); + ExpectNoVerdict(ChromeRulesServiceFactory::GetInstance() + ->GetForBrowserContext(profile()) + ->GetCopyToOSClipboardVerdict( + /*source*/ google_url())); + ExpectNoVerdict(ChromeRulesServiceFactory::GetInstance() + ->GetForBrowserContext(profile()) + ->GetCopyRestrictedBySourceVerdict( + /*source*/ google_url())); + EXPECT_TRUE(ChromeRulesServiceFactory::GetInstance() + ->GetForBrowserContext(profile()) + ->BlockScreenshots(google_url())); +} + +TEST_F(DataControlsRulesServiceScreenshotFeatureDisabledTest, + NoVerdictsForScreenshotRestriction) { + SetDataControls(profile()->GetPrefs(), {R"({ + "name": "block", + "rule_id": "1234", + "sources": { + "urls": ["google.com"] + }, + "restrictions": [ + {"class": "PRINTING", "level": "BLOCK"}, + {"class": "CLIPBOARD", "level": "BLOCK"}, + {"class": "SCREENSHOT", "level": "BLOCK"} + ] + })"}); + ExpectBlockVerdict(ChromeRulesServiceFactory::GetInstance() + ->GetForBrowserContext(profile()) + ->GetPrintVerdict(google_url())); + ExpectBlockVerdict(ChromeRulesServiceFactory::GetInstance() + ->GetForBrowserContext(profile()) + ->GetPasteVerdict( + /*source*/ google_url_endpoint(), + /*destination*/ empty_endpoint(), + /*metadata*/ {})); + ExpectBlockVerdict(ChromeRulesServiceFactory::GetInstance() + ->GetForBrowserContext(profile()) + ->GetCopyToOSClipboardVerdict( + /*source*/ google_url())); + ExpectBlockVerdict(ChromeRulesServiceFactory::GetInstance() + ->GetForBrowserContext(profile()) + ->GetCopyRestrictedBySourceVerdict( + /*source*/ google_url())); + EXPECT_FALSE(ChromeRulesServiceFactory::GetInstance() + ->GetForBrowserContext(profile()) + ->BlockScreenshots(google_url())); +} + +TEST_F(DataControlsRulesServiceAllFeaturesDisabledTest, NoVerdicts) { SetDataControls(profile()->GetPrefs(), {R"({ "name": "block", "rule_id": "1234",
diff --git a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc index bef1d82..d28601a 100644 --- a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc +++ b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc
@@ -153,13 +153,13 @@ sessions::SessionTabHelper::IdForTab(web_contents)); } -bool IsDesktopDataControlsEnabled() { +bool IsScreenshotProtectionEnabled() { return base::FeatureList::IsEnabled( - data_controls::kEnableDesktopDataControls); + data_controls::kEnableScreenshotProtection); } bool IsDataProtectionEnabled(Profile* profile) { - return IsEnterpriseLookupEnabled(profile) || IsDesktopDataControlsEnabled(); + return IsEnterpriseLookupEnabled(profile) || IsScreenshotProtectionEnabled(); } std::string GetIdentifier(content::BrowserContext* browser_context) { @@ -239,7 +239,7 @@ std::string identifier = GetIdentifier(profile); - if (IsDesktopDataControlsEnabled()) { + if (IsScreenshotProtectionEnabled()) { DataProtectionPageUserData::UpdateScreenshotState( GetPageFromWebContents(web_contents), identifier, IsScreenshotAllowedByDataControls(profile,
diff --git a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc index f7420dd..6d1de36 100644 --- a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc +++ b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc
@@ -148,7 +148,7 @@ content::RenderViewHostTestHarness::SetUp(); scoped_features_.InitAndEnableFeature( - data_controls::kEnableDesktopDataControls); + data_controls::kEnableScreenshotProtection); profile_manager_ = std::make_unique<TestingProfileManager>( TestingBrowserProcess::GetGlobal());
diff --git a/chrome/browser/enterprise/platform_auth/platform_auth_features.cc b/chrome/browser/enterprise/platform_auth/platform_auth_features.cc index c29077c..5bda314b 100644 --- a/chrome/browser/enterprise/platform_auth/platform_auth_features.cc +++ b/chrome/browser/enterprise/platform_auth/platform_auth_features.cc
@@ -8,4 +8,8 @@ namespace enterprise_auth { +BASE_FEATURE(kEnableExtensibleEnterpriseSSO, + "EnableExtensibleEnterpriseSSO", + base::FEATURE_DISABLED_BY_DEFAULT); + } // namespace enterprise_auth
diff --git a/chrome/browser/enterprise/platform_auth/platform_auth_features.h b/chrome/browser/enterprise/platform_auth/platform_auth_features.h index d956e967..4439e05 100644 --- a/chrome/browser/enterprise/platform_auth/platform_auth_features.h +++ b/chrome/browser/enterprise/platform_auth/platform_auth_features.h
@@ -10,6 +10,8 @@ namespace enterprise_auth { +BASE_DECLARE_FEATURE(kEnableExtensibleEnterpriseSSO); + } // namespace enterprise_auth #endif // CHROME_BROWSER_ENTERPRISE_PLATFORM_AUTH_PLATFORM_AUTH_FEATURES_H_
diff --git a/chrome/browser/feedback/android/family_info_feedback_source_unittest.cc b/chrome/browser/feedback/android/family_info_feedback_source_unittest.cc index 2e83937..e16b8dc8 100644 --- a/chrome/browser/feedback/android/family_info_feedback_source_unittest.cc +++ b/chrome/browser/feedback/android/family_info_feedback_source_unittest.cc
@@ -15,7 +15,6 @@ #include "base/notreached.h" #include "chrome/browser/flags/android/chrome_feature_list.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h" #include "chrome/browser/signin/test_signin_client_builder.h" @@ -119,11 +118,8 @@ private: // Creates a Java instance of FamilyInfoFeedbackSource. base::android::ScopedJavaLocalRef<jobject> CreateJavaObjectForTesting() { - ProfileAndroid* profile_android = - ProfileAndroid::FromProfile(profile_.get()); return Java_FamilyInfoFeedbackSourceTestBridge_createFamilyInfoFeedbackSource( - env_, base::android::JavaParamRef<jobject>( - env_, profile_android->GetJavaObject().Release())); + env_, profile_.get()->GetJavaObject()); } content::BrowserTaskEnvironment task_environment_; @@ -251,11 +247,8 @@ private: // Creates a Java instance of FamilyInfoFeedbackSource. base::android::ScopedJavaLocalRef<jobject> CreateJavaObjectForTesting() { - ProfileAndroid* profile_android = - ProfileAndroid::FromProfile(profile_.get()); return Java_FamilyInfoFeedbackSourceTestBridge_createFamilyInfoFeedbackSource( - env_, base::android::JavaParamRef<jobject>( - env_, profile_android->GetJavaObject().Release())); + env_, profile_.get()->GetJavaObject()); } content::BrowserTaskEnvironment task_environment_;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 14c6c8d..0a316671 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -2959,6 +2959,11 @@ "expiry_milestone": 130 }, { + "name": "enable-extensible-enterprise-sso", + "owners": [ "ydago@chromium.org", "cbe-magic@google.com" ], + "expiry_milestone": 130 + }, + { "name": "enable-external-display-hdr10", "owners": [ "sashamcintosh@chromium.org", "chromeos-gfx@google.com" ], "expiry_milestone": 140 @@ -7570,11 +7575,6 @@ "expiry_milestone": 92 }, { - "name": "screencast-v2", - "owners": [ "dorianbrandon@google.com","cros-edu-team@google.com"], - "expiry_milestone": 123 - }, - { "name": "screenshots-for-android-v2", "owners": [ "kenok@google.com", "addisonphelps@google.com", "jeffreycohen@chromium.org" ], "expiry_milestone": 115 @@ -8660,7 +8660,7 @@ "etuck@google.com", "cros-status-area-eng@google.com" ], - "expiry_milestone": 126 + "expiry_milestone": 130 }, { "name": "vc-light-intensity", @@ -8792,6 +8792,11 @@ "expiry_milestone": 129 }, { + "name": "web-authentication-enclave-authenticator", + "owners": [ "kenrb@chromium.org", "chrome-webauthn@google.com" ], + "expiry_milestone": 129 + }, + { "name": "web-authentication-permit-enterprise-attestation", "owners": [ "chrome-webauthn@google.com" ], // This flag lets end users enroll security keys with an enterprise that
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index b2c8c50..572c2fc 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -3637,6 +3637,14 @@ const char kWallpaperPerDeskDescription[] = "Allow users to set different wallpapers on each of their active desks"; +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) +const char kWebAuthnEnclaveAuthenticatorName[] = + "Enable the cloud enclave authenticator for GPM passkeys"; +const char kWebAuthnEnclaveAuthenticatorDescription[] = + "Allow users to create and use Google Password Manager passkeys using a " + "cloud-based authenticator service."; +#endif + const char kWebBluetoothName[] = "Web Bluetooth"; const char kWebBluetoothDescription[] = "Enables the Web Bluetooth API on platforms without official support"; @@ -5424,6 +5432,10 @@ "that calls the PPD API."; #endif // BUILDFLAG(ENABLE_PRINTING) +const char kEnableExtensibleEnterpriseSSOName[] = "Extensible Enterprise SSO"; +const char kEnableExtensibleEnterpriseSSODescription[] = + "Enables support for extensible enterprise SSO in Chrome"; + const char kImmersiveFullscreenName[] = "Immersive Fullscreen Toolbar"; const char kImmersiveFullscreenDescription[] = "Automatically hide and show the toolbar in fullscreen."; @@ -7174,9 +7186,6 @@ const char kScalableIphDebugDescription[] = "Enables debug feature of Scalable Iph"; -const char kScreencastV2Name[] = "Screencast V2"; -const char kScreencastV2Description[] = "Enable V2 features for Screencast app"; - const char kSeaPenName[] = "SeaPen"; const char kSeaPenDescription[] = "Enable SeaPen Wallpaper";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 2c71438..2e5a394 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -2114,6 +2114,11 @@ extern const char kWallpaperPerDeskName[]; extern const char kWallpaperPerDeskDescription[]; +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) +extern const char kWebAuthnEnclaveAuthenticatorName[]; +extern const char kWebAuthnEnclaveAuthenticatorDescription[]; +#endif + extern const char kWebBluetoothName[]; extern const char kWebBluetoothDescription[]; @@ -3154,6 +3159,9 @@ extern const char kCupsIppPrintingBackendDescription[]; #endif // BUILDFLAG(ENABLE_PRINTING) +extern const char kEnableExtensibleEnterpriseSSOName[]; +extern const char kEnableExtensibleEnterpriseSSODescription[]; + extern const char kImmersiveFullscreenName[]; extern const char kImmersiveFullscreenDescription[]; @@ -4156,9 +4164,6 @@ extern const char kScalableIphDebugName[]; extern const char kScalableIphDebugDescription[]; -extern const char kScreencastV2Name[]; -extern const char kScreencastV2Description[]; - extern const char kSealKeyName[]; extern const char kSealKeyDescription[];
diff --git a/chrome/browser/language/android/language_bridge.cc b/chrome/browser/language/android/language_bridge.cc index 4359cc9c3d..2c18282 100644 --- a/chrome/browser/language/android/language_bridge.cc +++ b/chrome/browser/language/android/language_bridge.cc
@@ -9,7 +9,6 @@ #include "chrome/browser/language/android/jni_headers/LanguageBridge_jni.h" #include "chrome/browser/language/language_model_manager_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "components/language/core/browser/language_model.h" #include "components/language/core/browser/language_model_manager.h" #include "components/language/core/browser/language_prefs.h" @@ -22,7 +21,7 @@ namespace { PrefService* GetPrefService(const base::android::JavaRef<jobject>& j_profile) { - return ProfileAndroid::FromProfileAndroid(j_profile)->GetPrefs(); + return Profile::FromJavaObject(j_profile)->GetPrefs(); } } // namespace
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc index 60320e94..82fbfafb 100644 --- a/chrome/browser/net/profile_network_context_service.cc +++ b/chrome/browser/net/profile_network_context_service.cc
@@ -348,11 +348,6 @@ base::BindRepeating(&ProfileNetworkContextService:: UpdateCorsNonWildcardRequestHeadersSupport, base::Unretained(this))); - pref_change_registrar_.Add( - prefs::kBlockTruncatedCookies, - base::BindRepeating( - &ProfileNetworkContextService::OnTruncatedCookieBlockingChanged, - base::Unretained(this))); } ProfileNetworkContextService::~ProfileNetworkContextService() = default; @@ -462,20 +457,6 @@ }); } -void ProfileNetworkContextService::OnTruncatedCookieBlockingChanged() { - const bool block_truncated_cookies = - profile_->GetPrefs()->GetBoolean(prefs::kBlockTruncatedCookies); - - profile_->ForEachLoadedStoragePartition( - [&](content::StoragePartition* storage_partition) { - // Update the main CookieManager's CookieSettings object to block - // truncated cookies, and since this is shared with all of the - // RestrictedCookieManager instances, those will get the change as well. - storage_partition->GetCookieManagerForBrowserProcess() - ->BlockTruncatedCookies(block_truncated_cookies); - }); -} - std::string ProfileNetworkContextService::ComputeAcceptLanguage() const { // If reduce accept language is enabled, only return the first language // without expanding the language list. @@ -818,9 +799,6 @@ out->cookie_access_delegate_type = network::mojom::CookieAccessDelegateType::USE_CONTENT_SETTINGS; - out->block_truncated_cookies = - profile->GetPrefs()->GetBoolean(prefs::kBlockTruncatedCookies); - out->mitigations_enabled_for_3pcd = cookie_settings.MitigationsEnabledFor3pcd();
diff --git a/chrome/browser/net/profile_network_context_service.h b/chrome/browser/net/profile_network_context_service.h index b11868c..76e8a50f 100644 --- a/chrome/browser/net/profile_network_context_service.h +++ b/chrome/browser/net/profile_network_context_service.h
@@ -167,8 +167,6 @@ void UpdateCorsNonWildcardRequestHeadersSupport(); - void OnTruncatedCookieBlockingChanged(); - // Creates parameters for the NetworkContext. Use |in_memory| instead of // |profile_->IsOffTheRecord()| because sometimes normal profiles want off the // record partitions (e.g. for webview tag).
diff --git a/chrome/browser/notifications/notification_platform_bridge_android.cc b/chrome/browser/notifications/notification_platform_bridge_android.cc index f82ea6a..20a7db4 100644 --- a/chrome/browser/notifications/notification_platform_bridge_android.cc +++ b/chrome/browser/notifications/notification_platform_bridge_android.cc
@@ -22,7 +22,7 @@ #include "chrome/browser/notifications/notification_common.h" #include "chrome/browser/notifications/notification_display_service_impl.h" #include "chrome/browser/notifications/platform_notification_service_impl.h" -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/notifications/notification_constants.h" @@ -281,8 +281,7 @@ if (!scope_url.is_valid()) scope_url = origin_url; - ScopedJavaLocalRef<jobject> android_profile = - ProfileAndroid::FromProfile(profile)->GetJavaObject(); + ScopedJavaLocalRef<jobject> android_profile = profile->GetJavaObject(); SkBitmap image_bitmap = notification.image().AsBitmap();
diff --git a/chrome/browser/notifications/scheduler/display_agent_android.cc b/chrome/browser/notifications/scheduler/display_agent_android.cc index c6f7ca0..ad012eb 100644 --- a/chrome/browser/notifications/scheduler/display_agent_android.cc +++ b/chrome/browser/notifications/scheduler/display_agent_android.cc
@@ -14,7 +14,7 @@ #include "chrome/browser/notifications/scheduler/notification_schedule_service_factory.h" #include "chrome/browser/notifications/scheduler/public/notification_schedule_service.h" #include "chrome/browser/notifications/scheduler/public/user_action_handler.h" -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_key.h" #include "ui/gfx/android/java_bitmap.h"
diff --git a/chrome/browser/notifications/scheduler/notification_background_task_scheduler_android.cc b/chrome/browser/notifications/scheduler/notification_background_task_scheduler_android.cc index 83cf8b2..3260d41 100644 --- a/chrome/browser/notifications/scheduler/notification_background_task_scheduler_android.cc +++ b/chrome/browser/notifications/scheduler/notification_background_task_scheduler_android.cc
@@ -14,7 +14,6 @@ #include "chrome/browser/notifications/scheduler/public/notification_background_task_scheduler.h" #include "chrome/browser/notifications/scheduler/public/notification_schedule_service.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/profiles/profile_key.h" // static
diff --git a/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc b/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc index 9831309..add27aab 100644 --- a/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc +++ b/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc
@@ -23,7 +23,6 @@ #include "chrome/browser/offline_pages/offline_page_model_factory.h" #include "chrome/browser/offline_pages/request_coordinator_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/common/chrome_constants.h" #include "components/offline_pages/core/background/offliner.h" #include "components/offline_pages/core/background/offliner_policy.h"
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.cc b/chrome/browser/offline_pages/android/offline_page_bridge.cc index 8e90738..a2ae035 100644 --- a/chrome/browser/offline_pages/android/offline_page_bridge.cc +++ b/chrome/browser/offline_pages/android/offline_page_bridge.cc
@@ -31,7 +31,6 @@ #include "chrome/browser/offline_pages/offline_page_utils.h" #include "chrome/browser/offline_pages/recent_tab_helper.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/profiles/profile_key.h" #include "chrome/browser/profiles/profile_key_android.h" #include "components/offline_pages/core/archive_validator.h"
diff --git a/chrome/browser/offline_pages/android/offline_test_util_jni.cc b/chrome/browser/offline_pages/android/offline_test_util_jni.cc index fea88c9..b7feeaa5 100644 --- a/chrome/browser/offline_pages/android/offline_test_util_jni.cc +++ b/chrome/browser/offline_pages/android/offline_test_util_jni.cc
@@ -18,7 +18,7 @@ #include "chrome/browser/offline_pages/android/request_coordinator_bridge.h" #include "chrome/browser/offline_pages/offline_page_model_factory.h" #include "chrome/browser/offline_pages/request_coordinator_factory.h" -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_key.h" #include "chrome/browser/profiles/profile_manager.h" #include "components/offline_pages/core/background/request_coordinator.h"
diff --git a/chrome/browser/optimization_guide/model_execution/model_execution_validation_browsertest.cc b/chrome/browser/optimization_guide/model_execution/model_execution_validation_browsertest.cc index 0359f2f..76ecee1 100644 --- a/chrome/browser/optimization_guide/model_execution/model_execution_validation_browsertest.cc +++ b/chrome/browser/optimization_guide/model_execution/model_execution_validation_browsertest.cc
@@ -156,8 +156,8 @@ } }; -// TODO(b/318433299, crbug.com/1520214): Flaky on linux-chromeos and win -#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) +// TODO(b/318433299, crbug.com/1520214): Flaky on linux-chromeos, Win and Mac. +#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) #define MAYBE_ModelExecutionSuccess DISABLED_ModelExecutionSuccess #else #define MAYBE_ModelExecutionSuccess ModelExecutionSuccess
diff --git a/chrome/browser/password_manager/android/local_passwords_migration_warning_util.cc b/chrome/browser/password_manager/android/local_passwords_migration_warning_util.cc index be43796..49238d3 100644 --- a/chrome/browser/password_manager/android/local_passwords_migration_warning_util.cc +++ b/chrome/browser/password_manager/android/local_passwords_migration_warning_util.cc
@@ -9,7 +9,7 @@ #include "base/metrics/histogram_functions.h" #include "base/time/time.h" #include "chrome/android/chrome_jni_headers/PasswordMigrationWarningBridge_jni.h" -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/sync_service_factory.h" #include "components/password_manager/core/browser/features/password_features.h" #include "components/password_manager/core/browser/password_store/split_stores_and_local_upm.h" @@ -55,8 +55,7 @@ SaveWarningShownTimestamp(profile->GetPrefs()); Java_PasswordMigrationWarningBridge_showWarning( - AttachCurrentThread(), window->GetJavaObject(), - ProfileAndroid::FromProfile(profile)->GetJavaObject(), + AttachCurrentThread(), window->GetJavaObject(), profile->GetJavaObject(), static_cast<int>(trigger_source)); RecordPasswordMigrationWarningTriggerSource(trigger_source); @@ -75,8 +74,7 @@ Java_PasswordMigrationWarningBridge_showWarningWithActivity( AttachCurrentThread(), activity, bottom_sheet_controller, - ProfileAndroid::FromProfile(profile)->GetJavaObject(), - static_cast<int>(trigger_source)); + profile->GetJavaObject(), static_cast<int>(trigger_source)); RecordPasswordMigrationWarningTriggerSource(trigger_source); } @@ -146,8 +144,7 @@ } Java_PasswordMigrationWarningBridge_maybeShowPostMigrationSheet( - AttachCurrentThread(), window->GetJavaObject(), - ProfileAndroid::FromProfile(profile)->GetJavaObject()); + AttachCurrentThread(), window->GetJavaObject(), profile->GetJavaObject()); } bool ShouldShowPostMigrationSheet(Profile* profile) {
diff --git a/chrome/browser/password_manager/android/password_checkup_launcher_helper_impl.cc b/chrome/browser/password_manager/android/password_checkup_launcher_helper_impl.cc index d7ace93..cdbccc0 100644 --- a/chrome/browser/password_manager/android/password_checkup_launcher_helper_impl.cc +++ b/chrome/browser/password_manager/android/password_checkup_launcher_helper_impl.cc
@@ -6,7 +6,6 @@ #include "chrome/android/chrome_jni_headers/PasswordCheckupLauncher_jni.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" PasswordCheckupLauncherHelperImpl::~PasswordCheckupLauncherHelperImpl() = default; @@ -29,8 +28,8 @@ return; } Java_PasswordCheckupLauncher_launchCheckupOnDevice( - env, ProfileAndroid::FromProfile(profile)->GetJavaObject(), - windowAndroid->GetJavaObject(), static_cast<int>(passwordCheckReferrer), + env, profile->GetJavaObject(), windowAndroid->GetJavaObject(), + static_cast<int>(passwordCheckReferrer), account_email.empty() ? nullptr : base::android::ConvertUTF8ToJavaString(env, account_email));
diff --git a/chrome/browser/password_manager/android/password_manager_error_message_helper_bridge_impl.cc b/chrome/browser/password_manager/android/password_manager_error_message_helper_bridge_impl.cc index 4548d26..9ff7e29 100644 --- a/chrome/browser/password_manager/android/password_manager_error_message_helper_bridge_impl.cc +++ b/chrome/browser/password_manager/android/password_manager_error_message_helper_bridge_impl.cc
@@ -6,7 +6,6 @@ #include "chrome/android/chrome_jni_headers/PasswordManagerErrorMessageHelperBridge_jni.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "ui/android/view_android.h" #include "ui/android/window_android.h" @@ -24,7 +23,7 @@ Java_PasswordManagerErrorMessageHelperBridge_startUpdateAccountCredentialsFlow( base::android::AttachCurrentThread(), window_android->GetJavaObject(), - ProfileAndroid::FromProfile(profile)->GetJavaObject()); + profile->GetJavaObject()); } void PasswordManagerErrorMessageHelperBridgeImpl:: @@ -39,7 +38,7 @@ Java_PasswordManagerErrorMessageHelperBridge_startTrustedVaultKeyRetrievalFlow( base::android::AttachCurrentThread(), window_android->GetJavaObject(), - ProfileAndroid::FromProfile(profile)->GetJavaObject()); + profile->GetJavaObject()); } bool PasswordManagerErrorMessageHelperBridgeImpl::ShouldShowSignInErrorUI( @@ -47,8 +46,7 @@ Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); return Java_PasswordManagerErrorMessageHelperBridge_shouldShowSignInErrorUI( - base::android::AttachCurrentThread(), - ProfileAndroid::FromProfile(profile)->GetJavaObject()); + base::android::AttachCurrentThread(), profile->GetJavaObject()); } bool PasswordManagerErrorMessageHelperBridgeImpl:: @@ -56,8 +54,7 @@ Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); return Java_PasswordManagerErrorMessageHelperBridge_shouldShowUpdateGMSCoreErrorUI( - base::android::AttachCurrentThread(), - ProfileAndroid::FromProfile(profile)->GetJavaObject()); + base::android::AttachCurrentThread(), profile->GetJavaObject()); } void PasswordManagerErrorMessageHelperBridgeImpl::SaveErrorUIShownTimestamp( @@ -65,8 +62,7 @@ Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); Java_PasswordManagerErrorMessageHelperBridge_saveErrorUiShownTimestamp( - base::android::AttachCurrentThread(), - ProfileAndroid::FromProfile(profile)->GetJavaObject()); + base::android::AttachCurrentThread(), profile->GetJavaObject()); } void PasswordManagerErrorMessageHelperBridgeImpl::LaunchGmsUpdate(
diff --git a/chrome/browser/password_manager/android/password_manager_launcher_android.cc b/chrome/browser/password_manager/android/password_manager_launcher_android.cc index cb813305..962061b 100644 --- a/chrome/browser/password_manager/android/password_manager_launcher_android.cc +++ b/chrome/browser/password_manager/android/password_manager_launcher_android.cc
@@ -7,7 +7,6 @@ #include "base/android/jni_android.h" #include "chrome/android/chrome_jni_headers/PasswordManagerLauncher_jni.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "components/password_manager/core/browser/manage_passwords_referrer.h" #include "content/public/browser/web_contents.h" @@ -33,8 +32,7 @@ return g_manage_password_when_passkeys_present_override; } return Java_PasswordManagerLauncher_canManagePasswordsWhenPasskeysPresent( - base::android::AttachCurrentThread(), - ProfileAndroid::FromProfile(profile)->GetJavaObject()); + base::android::AttachCurrentThread(), profile->GetJavaObject()); } void OverrideManagePasswordWhenPasskeysPresentForTesting(bool can_manage) {
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate.h b/chrome/browser/password_manager/android/save_update_password_message_delegate.h index bbf2ca8..5f4823a 100644 --- a/chrome/browser/password_manager/android/save_update_password_message_delegate.h +++ b/chrome/browser/password_manager/android/save_update_password_message_delegate.h
@@ -13,7 +13,7 @@ #include "base/memory/raw_ptr.h" #include "chrome/browser/password_edit_dialog/android/password_edit_dialog_bridge.h" #include "chrome/browser/password_manager/android/local_passwords_migration_warning_util.h" -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/passwords/manage_passwords_state.h" #include "components/browser_ui/device_lock/android/device_lock_bridge.h" #include "components/messages/android/message_enums.h"
diff --git a/chrome/browser/platform_experience/win b/chrome/browser/platform_experience/win index 3d27dce..203bb99 160000 --- a/chrome/browser/platform_experience/win +++ b/chrome/browser/platform_experience/win
@@ -1 +1 @@ -Subproject commit 3d27dce9761364362fb066b34eca50b767ab53d4 +Subproject commit 203bb990e01a33360e543edbf03db386355a4d26
diff --git a/chrome/browser/policy/BUILD.gn b/chrome/browser/policy/BUILD.gn index 58a3a2d1..2ecfc8e 100644 --- a/chrome/browser/policy/BUILD.gn +++ b/chrome/browser/policy/BUILD.gn
@@ -244,7 +244,6 @@ sources += [ "test/autofill_policy_browsertest.cc", "test/autoplay_policy_browsertest.cc", - "test/block_truncated_cookies_policy_browsertest.cc", "test/bookmark_bar_enabled_browsertest.cc", "test/component_updater_policy_browsertest.cc", "test/developer_tools_policy_browsertest.cc",
diff --git a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc index 7767e3a..d7d5e1a 100644 --- a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc +++ b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
@@ -367,7 +367,13 @@ std::unique_ptr<signin::IdentityTestEnvironment> identity_test_env_; }; -IN_PROC_BROWSER_TEST_F(CloudPolicyTest, FetchPolicy) { +// TODO(crbug.com/40187980): The test fails on Windows. +#if BUILDFLAG(IS_WIN) +#define MAYBE_FetchPolicy DISABLED_FetchPolicy +#else +#define MAYBE_FetchPolicy FetchPolicy +#endif +IN_PROC_BROWSER_TEST_F(CloudPolicyTest, MAYBE_FetchPolicy) { PolicyService* policy_service = GetPolicyService(); { base::RunLoop run_loop; @@ -422,8 +428,9 @@ } #endif -// crbug.com/1230268 not working on Lacros. -#if BUILDFLAG(IS_CHROMEOS_LACROS) +// TODO(crbug.com/40187980, crbug.com/1230268): The test fails on Lacros and +// Windows. +#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_WIN) #define MAYBE_InvalidatePolicy DISABLED_InvalidatePolicy #else #define MAYBE_InvalidatePolicy InvalidatePolicy
diff --git a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc index e77b311..bec224cd 100644 --- a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc +++ b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
@@ -265,7 +265,13 @@ #endif }; -IN_PROC_BROWSER_TEST_F(CloudPolicyManagerTest, Register) { +// TODO(crbug.com/40187980): The test fails on Windows. +#if BUILDFLAG(IS_WIN) +#define MAYBE_Register DISABLED_Register +#else +#define MAYBE_Register Register +#endif +IN_PROC_BROWSER_TEST_F(CloudPolicyManagerTest, MAYBE_Register) { test_url_loader_factory_->SetInterceptor( base::BindLambdaForTesting([&](const network::ResourceRequest& request) { // Accept one register request. The initial request should not include @@ -285,7 +291,13 @@ EXPECT_TRUE(policy_manager()->core()->client()->is_registered()); } -IN_PROC_BROWSER_TEST_F(CloudPolicyManagerTest, RegisterFails) { +// TODO(crbug.com/40187980): The test fails on Windows. +#if BUILDFLAG(IS_WIN) +#define MAYBE_RegisterFails DISABLED_RegisterFails +#else +#define MAYBE_RegisterFails RegisterFails +#endif +IN_PROC_BROWSER_TEST_F(CloudPolicyManagerTest, MAYBE_RegisterFails) { test_url_loader_factory_->SetInterceptor( base::BindLambdaForTesting([&](const network::ResourceRequest& request) { test_url_loader_factory_->AddResponse(request.url.spec(), std::string(), @@ -317,7 +329,13 @@ EXPECT_EQ(4, count); } -IN_PROC_BROWSER_TEST_F(CloudPolicyManagerTest, RegisterWithRetry) { +// TODO(crbug.com/40187980): The test fails on Windows. +#if BUILDFLAG(IS_WIN) +#define MAYBE_RegisterWithRetry DISABLED_RegisterWithRetry +#else +#define MAYBE_RegisterWithRetry RegisterWithRetry +#endif +IN_PROC_BROWSER_TEST_F(CloudPolicyManagerTest, MAYBE_RegisterWithRetry) { test_url_loader_factory_->SetInterceptor( base::BindLambdaForTesting([&](const network::ResourceRequest& request) { em::DeviceRegisterRequest::Type expected_type =
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc index 1e4fa51..b1efc7d7 100644 --- a/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc +++ b/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc
@@ -306,8 +306,9 @@ EXPECT_TRUE(policy_listener2.WaitUntilSatisfied()); } -// crbug.com/1230268 not working on Lacros. -#if BUILDFLAG(IS_CHROMEOS_LACROS) +// TODO(crbug.com/40187980, crbug.com/1230268): The test is flaky on Windows and +// Lacros. +#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_WIN) #define MAYBE_InstallNewExtension DISABLED_InstallNewExtension #else #define MAYBE_InstallNewExtension InstallNewExtension @@ -346,7 +347,14 @@ // get policy for components working again. // Signing out on Lacros is not possible. #if !BUILDFLAG(IS_CHROMEOS) -IN_PROC_BROWSER_TEST_F(ComponentCloudPolicyTest, SignOutAndBackIn) { + +// TODO(crbug.com/40187980, crbug.com/1230268): The test is flaky on Windows. +#if BUILDFLAG(IS_WIN) +#define MAYBE_SignOutAndBackIn DISABLED_SignOutAndBackIn +#else +#define MAYBE_SignOutAndBackIn SignOutAndBackIn +#endif +IN_PROC_BROWSER_TEST_F(ComponentCloudPolicyTest, MAYBE_SignOutAndBackIn) { // Signout is not enabled when this feature is enabled. if (base::FeatureList::IsEnabled(kDisallowManagedProfileSignout)) { event_listener_->Reply("idle");
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index cc4517b6..a83d1b44 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -352,9 +352,6 @@ { key::kAllowWebAuthnWithBrokenTlsCerts, webauthn::pref_names::kAllowWithBrokenCerts, base::Value::Type::BOOLEAN }, - { key::kBlockTruncatedCookies, - prefs::kBlockTruncatedCookies, - base::Value::Type::BOOLEAN }, { key::kHttpAllowlist, prefs::kHttpAllowlist, base::Value::Type::LIST },
diff --git a/chrome/browser/policy/policy_prefs_browsertest.cc b/chrome/browser/policy/policy_prefs_browsertest.cc index a2bd8ab..20a7f80 100644 --- a/chrome/browser/policy/policy_prefs_browsertest.cc +++ b/chrome/browser/policy/policy_prefs_browsertest.cc
@@ -79,7 +79,14 @@ typedef PlatformBrowserTest PolicyPrefsTestCoverageTest; -IN_PROC_BROWSER_TEST_F(PolicyPrefsTestCoverageTest, AllPoliciesHaveATestCase) { +// TODO(crbug.com/341097718): Flaky on Mac. +#if BUILDFLAG(IS_MAC) +#define MAYBE_AllPoliciesHaveATestCase DISABLED_AllPoliciesHaveATestCase +#else +#define MAYBE_AllPoliciesHaveATestCase AllPoliciesHaveATestCase +#endif +IN_PROC_BROWSER_TEST_F(PolicyPrefsTestCoverageTest, + MAYBE_AllPoliciesHaveATestCase) { VerifyAllPoliciesHaveATestCase(GetTestCaseDir()); }
diff --git a/chrome/browser/policy/test/block_truncated_cookies_policy_browsertest.cc b/chrome/browser/policy/test/block_truncated_cookies_policy_browsertest.cc deleted file mode 100644 index 3232e364..0000000 --- a/chrome/browser/policy/test/block_truncated_cookies_policy_browsertest.cc +++ /dev/null
@@ -1,111 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/scoped_feature_list.h" -#include "base/values.h" -#include "chrome/browser/policy/policy_test_utils.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/test/base/ui_test_utils.h" -#include "components/policy/core/common/policy_map.h" -#include "components/policy/policy_constants.h" -#include "content/public/browser/storage_partition.h" -#include "content/public/browser/web_contents.h" -#include "content/public/test/browser_test.h" -#include "content/public/test/browser_test_utils.h" -#include "net/base/features.h" -#include "net/dns/mock_host_resolver.h" -#include "net/test/embedded_test_server/embedded_test_server.h" - -namespace policy { - -class BlockTruncatedCookiesPolicyTest - : public PolicyTest, - public testing::WithParamInterface<bool> { - public: - BlockTruncatedCookiesPolicyTest() { - // Ensure that the feature is always enabled so that the behavior is only - // controlled by the enterprise policy. - feature_list_.InitAndEnableFeature(net::features::kBlockTruncatedCookies); - } - - void SetUpInProcessBrowserTestFixture() override { - PolicyTest::SetUpInProcessBrowserTestFixture(); - UpdateBlockTruncatedCookiesPolicy(is_enabled()); - } - - void SetUpOnMainThread() override { - host_resolver()->AddRule("*", "127.0.0.1"); - } - - void UpdateBlockTruncatedCookiesPolicy(bool enable) { - PolicyMap policies; - policies.Set(key::kBlockTruncatedCookies, POLICY_LEVEL_RECOMMENDED, - POLICY_SCOPE_USER, POLICY_SOURCE_COMMAND_LINE, - base::Value(enable), nullptr); - provider_.UpdateChromePolicy(policies); - } - - bool is_enabled() const { return GetParam(); } - - private: - base::test::ScopedFeatureList feature_list_; -}; - -IN_PROC_BROWSER_TEST_P(BlockTruncatedCookiesPolicyTest, RunTest) { - ASSERT_TRUE(embedded_test_server()->Start()); - - ASSERT_TRUE(ui_test_utils::NavigateToURL( - browser(), embedded_test_server()->GetURL("a.com", "/empty.html"))); - - content::WebContents* contents = - browser()->tab_strip_model()->GetActiveWebContents(); - - std::string cookie_js = "document.cookie = 'foo=ba\\x00r'; document.cookie;"; - - std::string cookie_string = EvalJs(contents, cookie_js).ExtractString(); - - if (is_enabled()) { - EXPECT_EQ("", cookie_string); - } else { - EXPECT_EQ("foo=ba", cookie_string); - } - - // Now change the policy and verify that it takes affect. The change should - // cause the ProfileNetworkContextService pref change handler to fire, so - // use `RunUntilIdle()` to hopefully ensure that that happens. That will - // queue a message to Profile's NetworkContext's CookieManager that will - // update its CookieSettings. To ensure that actually gets sent we'll flush - // the corresponding message pipe. That CookieSettings should be shared by all - // the per-renderer RestrictedCookieManagers, but just in case there's some - // delay in that value propagating we will navigate to a new origin, which - // should create a new RestrictedCookieManager and should reliably use the - // updated setting. Using a new domain also means that we don't have to worry - // about deleting any cookies that were set above. - UpdateBlockTruncatedCookiesPolicy(!is_enabled()); - base::RunLoop().RunUntilIdle(); - browser() - ->profile() - ->GetDefaultStoragePartition() - ->FlushNetworkInterfaceForTesting(); - - ASSERT_TRUE(ui_test_utils::NavigateToURL( - browser(), embedded_test_server()->GetURL("b.com", "/empty.html"))); - - contents = browser()->tab_strip_model()->GetActiveWebContents(); - - cookie_string = EvalJs(contents, cookie_js).ExtractString(); - - // Check for the opposite behavior from above. - if (is_enabled()) { - EXPECT_EQ("foo=ba", cookie_string); - } else { - EXPECT_EQ("", cookie_string); - } -} - -INSTANTIATE_TEST_SUITE_P(BlockTruncatedCookiesPolicyTestP, - BlockTruncatedCookiesPolicyTest, - testing::Values(true, false)); -} // namespace policy
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index e7e44318..7c0b8d4 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -1088,6 +1088,9 @@ "settings.a11y.mouse_keys.disable_in_text_fields"; #endif // BUILDFLAG(IS_CHROMEOS_ASH) +// Deprecated 05/2024. +constexpr char kBlockTruncatedCookies[] = "profile.cookie_block_truncated"; + // Register local state used only for migration (clearing or moving to a new // key). void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) { @@ -1561,6 +1564,9 @@ registry->RegisterBooleanPref(kAccessibilityMouseKeysDisableInTextFields, true); #endif // BUILDFLAG(IS_CHROMEOS_ASH) + + // Deprecated 05/2024. + registry->RegisterBooleanPref(kBlockTruncatedCookies, true); } void ClearSyncRequestedPrefAndMaybeMigrate(PrefService* profile_prefs) { @@ -2287,7 +2293,6 @@ registry->RegisterBooleanPref(kClearUserDataDir1Pref, false); #endif - registry->RegisterBooleanPref(prefs::kBlockTruncatedCookies, true); registry->RegisterBooleanPref( prefs::kManagedPrivateNetworkAccessRestrictionsEnabled, false); @@ -2920,6 +2925,9 @@ profile_prefs->ClearPref(kAccessibilityMouseKeysDisableInTextFields); #endif // BUILDFLAG(IS_CHROMEOS_ASH) + // Added 05/2024. + profile_prefs->ClearPref(kBlockTruncatedCookies); + // Please don't delete the following line. It is used by PRESUBMIT.py. // END_MIGRATE_OBSOLETE_PROFILE_PREFS
diff --git a/chrome/browser/privacy_sandbox/android/privacy_sandbox_bridge.cc b/chrome/browser/privacy_sandbox/android/privacy_sandbox_bridge.cc index 8a1dafe3..2c01275 100644 --- a/chrome/browser/privacy_sandbox/android/privacy_sandbox_bridge.cc +++ b/chrome/browser/privacy_sandbox/android/privacy_sandbox_bridge.cc
@@ -17,7 +17,6 @@ #include "chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.h" #include "chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "components/privacy_sandbox/canonical_topic.h" #include "components/privacy_sandbox/privacy_sandbox_settings.h" #include "components/strings/grit/components_strings.h" @@ -35,7 +34,7 @@ PrivacySandboxService* GetPrivacySandboxService( const base::android::JavaRef<jobject>& j_profile) { return PrivacySandboxServiceFactory::GetForProfile( - ProfileAndroid::FromProfileAndroid(j_profile)); + Profile::FromJavaObject(j_profile)); } std::vector<jni_zero::ScopedJavaLocalRef<jobject>> ToJavaTopicsArray( @@ -227,6 +226,6 @@ JNIEnv* env, const JavaParamRef<jobject>& j_profile) { PrivacySandboxSettingsFactory::GetForProfile( - ProfileAndroid::FromProfileAndroid(j_profile)) + Profile::FromJavaObject(j_profile)) ->SetAllPrivacySandboxAllowedForTesting(); // IN-TEST }
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.cc index b9699dc8c..a2ef1dd1 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/first_party_sets/first_party_sets_policy_service_factory.h" #include "chrome/browser/privacy_sandbox/privacy_sandbox_service_impl.h" #include "chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h" +#include "chrome/browser/privacy_sandbox/tracking_protection_settings_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/tpcd/experiment/eligibility_service_factory.h" #include "components/content_settings/core/browser/cookie_settings.h" @@ -72,6 +73,7 @@ DependsOn(CookieSettingsFactory::GetInstance()); DependsOn(HostContentSettingsMapFactory::GetInstance()); DependsOn(browsing_topics::BrowsingTopicsServiceFactory::GetInstance()); + DependsOn(TrackingProtectionSettingsFactory::GetInstance()); #if !BUILDFLAG(IS_ANDROID) DependsOn(TrustSafetySentimentServiceFactory::GetInstance()); #endif @@ -90,6 +92,7 @@ Profile* profile = Profile::FromBrowserContext(context); return std::make_unique<PrivacySandboxServiceImpl>( PrivacySandboxSettingsFactory::GetForProfile(profile), + TrackingProtectionSettingsFactory::GetForProfile(profile), CookieSettingsFactory::GetForProfile(profile), profile->GetPrefs(), profile->GetDefaultStoragePartition()->GetInterestGroupManager(), GetProfileType(profile),
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl.cc index 8799d2bd..31bae548 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl.cc
@@ -70,7 +70,8 @@ // Returns whether 3P cookies are blocked by |cookie_settings|. This can be // either through blocking 3P cookies directly, or blocking all cookies. -bool AreThirdPartyCookiesBlocked( +// Blocking in this case also covers the "3P cookies limited" state. +bool ShouldBlockThirdPartyOrFirstPartyCookies( content_settings::CookieSettings* cookie_settings) { const auto default_content_setting = cookie_settings->GetDefaultCookieSetting(); @@ -78,6 +79,25 @@ default_content_setting == ContentSetting::CONTENT_SETTING_BLOCK; } +// Similar to the function above, but checks for ALL 3P cookies to be blocked +// pre and post 3PCD. +bool AreAllThirdPartyCookiesBlocked( + content_settings::CookieSettings* cookie_settings, + PrefService* prefs, + privacy_sandbox::TrackingProtectionSettings* tracking_protection_settings) { + // Check if 1PCs are blocked. + if (cookie_settings->GetDefaultCookieSetting() == + ContentSetting::CONTENT_SETTING_BLOCK) { + return true; + } + // Check if all 3PCs are blocked. + return tracking_protection_settings->AreAllThirdPartyCookiesBlocked() || + (!tracking_protection_settings->IsTrackingProtection3pcdEnabled() && + prefs->GetInteger(prefs::kCookieControlsMode) == + static_cast<int>( + content_settings::CookieControlsMode::kBlockThirdParty)); +} + // Sorts |topics| alphabetically by topic display name for display. // In addition, removes duplicate topics. void SortAndDeduplicateTopicsForDisplay( @@ -240,6 +260,7 @@ PrivacySandboxServiceImpl::PrivacySandboxServiceImpl( privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings, + privacy_sandbox::TrackingProtectionSettings* tracking_protection_settings, scoped_refptr<content_settings::CookieSettings> cookie_settings, PrefService* pref_service, content::InterestGroupManager* interest_group_manager, @@ -252,6 +273,7 @@ browsing_topics::BrowsingTopicsService* browsing_topics_service, first_party_sets::FirstPartySetsPolicyService* first_party_sets_service) : privacy_sandbox_settings_(privacy_sandbox_settings), + tracking_protection_settings_(tracking_protection_settings), cookie_settings_(cookie_settings), pref_service_(pref_service), interest_group_manager_(interest_group_manager), @@ -266,6 +288,7 @@ DCHECK(privacy_sandbox_settings_); DCHECK(pref_service_); DCHECK(cookie_settings_); + CHECK(tracking_protection_settings_); // Register observers for the Privacy Sandbox preferences. user_prefs_registrar_.Init(pref_service_); @@ -326,8 +349,15 @@ PrivacySandboxService::PromptType PrivacySandboxServiceImpl::GetRequiredPromptType() { - const auto third_party_cookies_blocked = - AreThirdPartyCookiesBlocked(cookie_settings_.get()); + bool third_party_cookies_blocked; + if (base::FeatureList::IsEnabled( + privacy_sandbox::kPrivacySandboxAdsDialogDisabledOnAll3PCBlock)) { + third_party_cookies_blocked = AreAllThirdPartyCookiesBlocked( + cookie_settings_.get(), pref_service_, tracking_protection_settings_); + } else { + third_party_cookies_blocked = + ShouldBlockThirdPartyOrFirstPartyCookies(cookie_settings_.get()); + } return GetRequiredPromptTypeInternal( pref_service_, profile_type_, privacy_sandbox_settings_, third_party_cookies_blocked, @@ -1160,7 +1190,7 @@ // side of privacy, this init logic is run per-device (the pref recording that // init has been run is not synced). If any of the user's devices local state // would disable the pref, it is disabled across all devices. - if (AreThirdPartyCookiesBlocked(cookie_settings_.get())) { + if (ShouldBlockThirdPartyOrFirstPartyCookies(cookie_settings_.get())) { pref_service_->SetBoolean(prefs::kPrivacySandboxRelatedWebsiteSetsEnabled, false); }
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl.h b/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl.h index c876b2f0..c40364b 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl.h +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl.h
@@ -5,7 +5,9 @@ #ifndef CHROME_BROWSER_PRIVACY_SANDBOX_PRIVACY_SANDBOX_SERVICE_IMPL_H_ #define CHROME_BROWSER_PRIVACY_SANDBOX_PRIVACY_SANDBOX_SERVICE_IMPL_H_ +// clang-format off #include "chrome/browser/privacy_sandbox/privacy_sandbox_service.h" +// clang-format on #include <set> @@ -17,6 +19,7 @@ #include "components/privacy_sandbox/canonical_topic.h" #include "components/privacy_sandbox/privacy_sandbox_prefs.h" #include "components/privacy_sandbox/privacy_sandbox_settings.h" +#include "components/privacy_sandbox/tracking_protection_settings.h" #include "components/profile_metrics/browser_profile_type.h" #include "content/public/browser/interest_group_manager.h" #include "net/base/schemeful_site.h" @@ -47,6 +50,7 @@ public: PrivacySandboxServiceImpl( privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings, + privacy_sandbox::TrackingProtectionSettings* tracking_protection_settings, scoped_refptr<content_settings::CookieSettings> cookie_settings, PrefService* pref_service, content::InterestGroupManager* interest_group_manager, @@ -337,6 +341,8 @@ private: raw_ptr<privacy_sandbox::PrivacySandboxSettings, DanglingUntriaged> privacy_sandbox_settings_; + raw_ptr<privacy_sandbox::TrackingProtectionSettings> + tracking_protection_settings_; scoped_refptr<content_settings::CookieSettings> cookie_settings_; raw_ptr<PrefService> pref_service_; raw_ptr<content::InterestGroupManager> interest_group_manager_;
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl_unittest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl_unittest.cc index f92458d..d753816 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl_unittest.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service_impl_unittest.cc
@@ -347,9 +347,9 @@ profile()); #endif privacy_sandbox_service_ = std::make_unique<PrivacySandboxServiceImpl>( - privacy_sandbox_settings(), cookie_settings(), profile()->GetPrefs(), - test_interest_group_manager(), GetProfileType(), - browsing_data_remover(), host_content_settings_map(), + privacy_sandbox_settings(), tracking_protection_settings(), + cookie_settings(), profile()->GetPrefs(), test_interest_group_manager(), + GetProfileType(), browsing_data_remover(), host_content_settings_map(), #if !BUILDFLAG(IS_ANDROID) mock_sentiment_service(), #endif @@ -969,6 +969,24 @@ EXPECT_THAT(service->GetBlockedTopics(), ElementsAre(topic3, topic4)); } } +using PrivacySandboxServiceDeathTest = PrivacySandboxServiceTest; + +TEST_F(PrivacySandboxServiceDeathTest, TPSettingsNullExpectDeath) { + ASSERT_DEATH( + { + PrivacySandboxServiceImpl( + privacy_sandbox_settings(), + /*tracking_protection_settings=*/nullptr, cookie_settings(), + profile()->GetPrefs(), test_interest_group_manager(), + GetProfileType(), browsing_data_remover(), + host_content_settings_map(), +#if !BUILDFLAG(IS_ANDROID) + mock_sentiment_service(), +#endif + mock_browsing_topics_service(), first_party_sets_policy_service()); + }, + ""); +} TEST_F(PrivacySandboxServiceTest, FirstPartySetsNotRelevantMetricAllowedCookies) { @@ -2054,14 +2072,30 @@ } #endif -TEST_F(PrivacySandboxServiceM1PromptTest, ThirdPartyCookiesBlocked) { +TEST_F(PrivacySandboxServiceM1PromptTest, ThirdPartyCookiesBlockedPostTP3PC) { + // If third party cookies are blocked, set the suppressed reason as + // kThirdPartyCookiesBlocked and return kNone. + RunTestCase( + TestState{{kM1PromptPreviouslySuppressedReason, + static_cast<int>(PromptSuppressedReason::kNone)}, + {kBlockAll3pcToggleEnabledUserPrefValue, true}, + {kTrackingProtection3pcdEnabledUserPrefValue, true}}, + TestInput{{kForceChromeBuild, true}}, + TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)}, + {kM1PromptSuppressedReason, + static_cast<int>( + PromptSuppressedReason::kThirdPartyCookiesBlocked)}}); +} + +TEST_F(PrivacySandboxServiceM1PromptTest, ThirdPartyCookiesBlockedPreTP3PC) { // If third party cookies are blocked, set the suppressed reason as // kThirdPartyCookiesBlocked and return kNone. RunTestCase( TestState{{kM1PromptPreviouslySuppressedReason, static_cast<int>(PromptSuppressedReason::kNone)}, {kCookieControlsModeUserPrefValue, - content_settings::CookieControlsMode::kBlockThirdParty}}, + content_settings::CookieControlsMode::kBlockThirdParty}, + {kTrackingProtection3pcdEnabledUserPrefValue, false}}, TestInput{{kForceChromeBuild, true}}, TestOutput{{kPromptType, static_cast<int>(PromptType::kNone)}, {kM1PromptSuppressedReason,
diff --git a/chrome/browser/profiles/BUILD.gn b/chrome/browser/profiles/BUILD.gn index 0b5e4239..37b29bf0 100644 --- a/chrome/browser/profiles/BUILD.gn +++ b/chrome/browser/profiles/BUILD.gn
@@ -19,7 +19,6 @@ if (is_android) { sources += [ "profile_android.cc", - "profile_android.h", "profile_key_android.cc", "profile_key_android.h", ]
diff --git a/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java b/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java index d8684b0a..a02b1407 100644 --- a/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java +++ b/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java
@@ -17,14 +17,14 @@ /** Wrapper that allows passing a Profile reference around in the Java layer. */ public class Profile implements BrowserContextHandle { - /** Pointer to the Native-side ProfileAndroid. */ - private long mNativeProfileAndroid; + /** Pointer to the Native-side Profile. */ + private long mNativeProfile; private final @Nullable OTRProfileID mOtrProfileId; @CalledByNative - private Profile(long nativeProfileAndroid, @Nullable OTRProfileID otrProfileId) { - mNativeProfileAndroid = nativeProfileAndroid; + private Profile(long nativeProfile, @Nullable OTRProfileID otrProfileId) { + mNativeProfile = nativeProfile; mOtrProfileId = otrProfileId; } @@ -61,7 +61,7 @@ } public Profile getOriginalProfile() { - return ProfileJni.get().getOriginalProfile(mNativeProfileAndroid); + return ProfileJni.get().getOriginalProfile(mNativeProfile); } /** @@ -73,8 +73,7 @@ */ public Profile getOffTheRecordProfile(OTRProfileID profileID, boolean createIfNeeded) { assert profileID != null; - return ProfileJni.get() - .getOffTheRecordProfile(mNativeProfileAndroid, profileID, createIfNeeded); + return ProfileJni.get().getOffTheRecordProfile(mNativeProfile, profileID, createIfNeeded); } /** @@ -84,7 +83,7 @@ * @param createIfNeeded Boolean indicating the profile should be created if doesn't exist. */ public Profile getPrimaryOTRProfile(boolean createIfNeeded) { - return ProfileJni.get().getPrimaryOTRProfile(mNativeProfileAndroid, createIfNeeded); + return ProfileJni.get().getPrimaryOTRProfile(mNativeProfile, createIfNeeded); } /** @@ -101,12 +100,12 @@ */ public boolean hasOffTheRecordProfile(OTRProfileID profileID) { assert profileID != null; - return ProfileJni.get().hasOffTheRecordProfile(mNativeProfileAndroid, profileID); + return ProfileJni.get().hasOffTheRecordProfile(mNativeProfile, profileID); } /** Returns if primary OffTheRecord profile exists. */ public boolean hasPrimaryOTRProfile() { - return ProfileJni.get().hasPrimaryOTRProfile(mNativeProfileAndroid); + return ProfileJni.get().hasPrimaryOTRProfile(mNativeProfile); } /** Returns if the profile is a primary OTR Profile. */ @@ -115,7 +114,7 @@ } public ProfileKey getProfileKey() { - return ProfileJni.get().getProfileKey(mNativeProfileAndroid); + return ProfileJni.get().getProfileKey(mNativeProfile); } public boolean isOffTheRecord() { @@ -130,12 +129,12 @@ */ @Deprecated public boolean isChild() { - return ProfileJni.get().isChild(mNativeProfileAndroid); + return ProfileJni.get().isChild(mNativeProfile); } /** Wipes all data for this profile. */ public void wipe() { - ProfileJni.get().wipe(mNativeProfileAndroid); + ProfileJni.get().wipe(mNativeProfile); } /** @@ -143,7 +142,7 @@ */ @VisibleForTesting public boolean isNativeInitialized() { - return mNativeProfileAndroid != 0; + return mNativeProfile != 0; } /** @@ -151,19 +150,19 @@ * get a more debuggable stacktrace than failing on native-side when dereferencing. */ public void ensureNativeInitialized() { - if (mNativeProfileAndroid == 0) { + if (mNativeProfile == 0) { throw new RuntimeException("Native profile pointer not initialized."); } } @Override public long getNativeBrowserContextPointer() { - return mNativeProfileAndroid; + return mNativeProfile; } @CalledByNative private void onNativeDestroyed() { - mNativeProfileAndroid = 0; + mNativeProfile = 0; if (isPrimaryOTRProfile()) { CookiesFetcher.scheduleDeleteCookies(); @@ -174,7 +173,7 @@ @CalledByNative private long getNativePointer() { - return mNativeProfileAndroid; + return mNativeProfile; } @NativeMethods
diff --git a/chrome/browser/profiles/android/profile_resolver.cc b/chrome/browser/profiles/android/profile_resolver.cc index 7f077f9..f1e3d8c 100644 --- a/chrome/browser/profiles/android/profile_resolver.cc +++ b/chrome/browser/profiles/android/profile_resolver.cc
@@ -17,7 +17,6 @@ #include "chrome/browser/android/proto/profile_token.pb.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/profiles/profile_key.h" #include "chrome/browser/profiles/profile_key_android.h" #include "chrome/browser/profiles/profile_manager.h" @@ -85,8 +84,7 @@ void OnResolvedProfile(const JavaRef<jobject>& j_callback, Profile* profile) { ScopedJavaLocalRef<jobject> j_profile; if (profile) { - ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile); - j_profile = profile_android->GetJavaObject(); + j_profile = profile->GetJavaObject(); } base::android::RunObjectCallbackAndroid(j_callback, j_profile); }
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h index 71bc4e6..d31f74e 100644 --- a/chrome/browser/profiles/profile.h +++ b/chrome/browser/profiles/profile.h
@@ -516,9 +516,7 @@ } #if BUILDFLAG(IS_ANDROID) - // TODO(agrieve): Delete this no-op. - static Profile* FromProfile(Profile* profile) { return profile; } - static Profile* FromProfileAndroid(const jni_zero::JavaRef<jobject>& obj); + static Profile* FromJavaObject(const jni_zero::JavaRef<jobject>& obj); jni_zero::ScopedJavaLocalRef<jobject> GetJavaObject() const; #endif // BUILDFLAG(IS_ANDROID) protected:
diff --git a/chrome/browser/profiles/profile_android.cc b/chrome/browser/profiles/profile_android.cc index 0e50294..c014303 100644 --- a/chrome/browser/profiles/profile_android.cc +++ b/chrome/browser/profiles/profile_android.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" #include "base/android/jni_android.h" #include "base/android/jni_string.h" @@ -23,7 +23,7 @@ template <> Profile* FromJniType<Profile*>(JNIEnv* env, const JavaRef<jobject>& j_profile) { - return Profile::FromProfileAndroid(j_profile); + return Profile::FromJavaObject(j_profile); } template <> @@ -38,7 +38,7 @@ } // namespace jni_zero // static -Profile* Profile::FromProfileAndroid(const JavaRef<jobject>& obj) { +Profile* Profile::FromJavaObject(const JavaRef<jobject>& obj) { if (!obj) { return nullptr; }
diff --git a/chrome/browser/profiles/profile_android.h b/chrome/browser/profiles/profile_android.h deleted file mode 100644 index b2cbc2f..0000000 --- a/chrome/browser/profiles/profile_android.h +++ /dev/null
@@ -1,12 +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 CHROME_BROWSER_PROFILES_PROFILE_ANDROID_H_ -#define CHROME_BROWSER_PROFILES_PROFILE_ANDROID_H_ - -#include "chrome/browser/profiles/profile.h" - -using ProfileAndroid = Profile; - -#endif // CHROME_BROWSER_PROFILES_PROFILE_ANDROID_H_
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index 3dc734a..0a64906 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -97,6 +97,7 @@ #include "chrome/browser/ui/exclusive_access/keyboard_lock_controller.h" #include "chrome/browser/ui/lens/lens_overlay_controller.h" #include "chrome/browser/ui/lens/lens_overlay_image_helper.h" +#include "chrome/browser/ui/lens/lens_overlay_invocation_source.h" #include "chrome/browser/ui/passwords/ui_utils.h" #include "chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller.h" #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble.h" @@ -4279,7 +4280,7 @@ LensOverlayController::GetController(source_web_contents_); CHECK(controller); controller->ShowUIWithPendingRegion( - LensOverlayController::InvocationSource::kContentAreaContextMenuPage, + lens::LensOverlayInvocationSource::kContentAreaContextMenuImage, lens::GetCenterRotatedBoxFromViewAndImageBounds(view_bounds, image_bounds)); } @@ -4300,7 +4301,7 @@ LensOverlayController::GetController(source_web_contents_); CHECK(controller); controller->ShowUI( - LensOverlayController::InvocationSource::kContentAreaContextMenuPage); + lens::LensOverlayInvocationSource::kContentAreaContextMenuPage); UserEducationService::MaybeNotifyPromoFeatureUsed( GetBrowserContext(), lens::features::kLensOverlay); return;
diff --git a/chrome/browser/resources/ash/settings/os_people_page/os_sync_browser_proxy.ts b/chrome/browser/resources/ash/settings/os_people_page/os_sync_browser_proxy.ts index 20ff4f9..56ac877d 100644 --- a/chrome/browser/resources/ash/settings/os_people_page/os_sync_browser_proxy.ts +++ b/chrome/browser/resources/ash/settings/os_people_page/os_sync_browser_proxy.ts
@@ -69,6 +69,6 @@ } setOsSyncDatatypes(osSyncPrefs: OsSyncPrefs): void { - return chrome.send('SetOsSyncDatatypes', [osSyncPrefs]); + chrome.send('SetOsSyncDatatypes', [osSyncPrefs]); } } \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn index 6f122e8..10d0b2e 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -81,6 +81,7 @@ "common/key_sequence.ts", "common/key_util.ts", "common/msgs.ts", + "common/spannable.ts", "common/tts_types.ts", "learn_mode/learn_mode.ts", "log_page/log.ts", @@ -168,7 +169,6 @@ "common/panel_menu_data.js", "common/permission_checker.js", "common/role_type.js", - "common/spannable.js", "common/settings_manager.js", "common/tree_dumper.js", ]
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/spannable.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/spannable.js deleted file mode 100644 index b627837..0000000 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/spannable.js +++ /dev/null
@@ -1,508 +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. - -/** - * @fileoverview Class which allows construction of annotated strings. - */ -import {TestImportManager} from '/common/testing/test_import_manager.js'; - -export class Spannable { - /** - * @param {string|!Spannable=} opt_string Initial value of the spannable. - * @param {*=} opt_annotation Initial annotation for the entire string. - */ - constructor(opt_string, opt_annotation) { - /** - * Underlying string. - * @type {string} - * @private - */ - this.string_ = opt_string instanceof Spannable ? '' : opt_string || ''; - - /** - * Spans (annotations). - * @type {!Array<!SpanStruct>} - * @private - */ - this.spans_ = []; - - // Append the initial spannable. - if (opt_string instanceof Spannable) { - this.append(opt_string); - } - - // Optionally annotate the entire string. - if (goog.isDef(opt_annotation)) { - const len = this.string_.length; - this.spans_.push({value: opt_annotation, start: 0, end: len}); - } - } - - /** @override */ - toString() { - return this.string_; - } - - /** @return {number} The length of the string */ - get length() { - return this.string_.length; - } - - /** - * Adds a span to some region of the string. - * @param {*} value Annotation. - * @param {number} start Starting index (inclusive). - * @param {number} end Ending index (exclusive). - */ - setSpan(value, start, end) { - this.removeSpan(value); - this.setSpanInternal(value, start, end); - } - - /** - * @param {*} value Annotation. - * @param {number} start Starting index (inclusive). - * @param {number} end Ending index (exclusive). - * @protected - */ - setSpanInternal(value, start, end) { - if (0 <= start && start <= end && end <= this.string_.length) { - // Zero-length spans are explicitly allowed, because it is possible to - // query for position by annotation as well as the reverse. - this.spans_.push({value, start, end}); - this.spans_.sort(function(a, b) { - let ret = a.start - b.start; - if (ret === 0) { - ret = a.end - b.end; - } - return ret; - }); - } else { - throw new RangeError( - 'span out of range (start=' + start + ', end=' + end + - ', len=' + this.string_.length + ')'); - } - } - - /** - * Removes a span. - * @param {*} value Annotation. - */ - removeSpan(value) { - for (let i = this.spans_.length - 1; i >= 0; i--) { - if (this.spans_[i].value === value) { - this.spans_.splice(i, 1); - } - } - } - - /** - * Appends another Spannable or string to this one. - * @param {string|!Spannable} other String or spannable to concatenate. - */ - append(other) { - if (other instanceof Spannable) { - const otherSpannable = /** @type {!Spannable} */ (other); - const originalLength = this.length; - this.string_ += otherSpannable.string_; - other.spans_.forEach( - span => this.setSpan( - span.value, span.start + originalLength, - span.end + originalLength)); - } else if (typeof other === 'string') { - this.string_ += /** @type {string} */ (other); - } - } - - /** - * Returns the first value matching a position. - * @param {number} position Position to query. - * @return {*} Value annotating that position, or undefined if none is - * found. - */ - getSpan(position) { - return valueOfSpan(this.spans_.find(spanCoversPosition(position))); - } - - /** - * Returns the first span value which is an instance of a given constructor. - * @param {!Function} constructor Constructor. - * @return {*} Object if found; undefined otherwise. - */ - getSpanInstanceOf(constructor) { - return valueOfSpan(this.spans_.find(spanInstanceOf(constructor))); - } - - /** - * Returns all span values which are an instance of a given constructor. - * Spans are returned in the order of their starting index and ending index - * for spans with equals tarting indices. - * @param {!Function} constructor Constructor. - * @return {!Array<Object>} Array of object. - */ - getSpansInstanceOf(constructor) { - return (this.spans_.filter(spanInstanceOf(constructor)).map(valueOfSpan)); - } - - /** - * Returns all spans matching a position. - * @param {number} position Position to query. - * @return {!Array} Values annotating that position. - */ - getSpans(position) { - return (this.spans_.filter(spanCoversPosition(position)).map(valueOfSpan)); - } - - /** - * Returns whether a span is contained in this object. - * @param {*} value Annotation. - * @return {boolean} - */ - hasSpan(value) { - return this.spans_.some(spanValueIs(value)); - } - - /** - * Returns the start of the requested span. Throws if the span doesn't exist - * in this object. - * @param {*} value Annotation. - * @return {number} - */ - getSpanStart(value) { - return this.getSpanByValueOrThrow_(value).start; - } - - /** - * Returns the end of the requested span. Throws if the span doesn't exist - * in this object. - * @param {*} value Annotation. - * @return {number} - */ - getSpanEnd(value) { - return this.getSpanByValueOrThrow_(value).end; - } - - /** - * @param {*} value Annotation. - * @return {!Array<{start: number, end: number}>} - */ - getSpanIntervals(value) { - return this.spans_.filter(span => span.value === value).map(span => { - return {start: span.start, end: span.end}; - }); - } - - /** - * Returns the number of characters covered by the given span. Throws if - * the span is not in this object. - * @param {*} value - * @return {number} - */ - getSpanLength(value) { - const span = this.getSpanByValueOrThrow_(value); - return span.end - span.start; - } - - /** - * Gets the internal object for a span or throws if the span doesn't exist. - * @param {*} value The annotation. - * @return {!SpanStruct} - * @private - */ - getSpanByValueOrThrow_(value) { - const span = this.spans_.find(spanValueIs(value)); - if (span) { - return span; - } - throw new Error('Span ' + value + ' doesn\'t exist in spannable'); - } - - /** - * Returns a substring of this spannable. - * Note that while similar to String#substring, this function is much less - * permissive about its arguments. It does not accept arguments in the wrong - * order or out of bounds. - * - * @param {number} start Start index, inclusive. - * @param {number=} opt_end End index, exclusive. - * If excluded, the length of the string is used instead. - * @return {!Spannable} Substring requested. - */ - substring(start, opt_end) { - const end = goog.isDef(opt_end) ? opt_end : this.string_.length; - - if (start < 0 || end > this.string_.length || start > end) { - throw new RangeError('substring indices out of range'); - } - - const result = new Spannable(this.string_.substring(start, end)); - this.spans_.forEach(span => { - if (span.start <= end && span.end >= start) { - const newStart = Math.max(0, span.start - start); - const newEnd = Math.min(end - start, span.end - start); - result.spans_.push({value: span.value, start: newStart, end: newEnd}); - } - }); - return result; - } - - /** - * Trims whitespace from the beginning. - * @return {!Spannable} String with whitespace removed. - */ - trimLeft() { - return this.trim_(true, false); - } - - /** - * Trims whitespace from the end. - * @return {!Spannable} String with whitespace removed. - */ - trimRight() { - return this.trim_(false, true); - } - - /** - * Trims whitespace from the beginning and end. - * @return {!Spannable} String with whitespace removed. - */ - trim() { - return this.trim_(true, true); - } - - /** - * Trims whitespace from either the beginning and end or both. - * @param {boolean} trimStart Trims whitespace from the start of a string. - * @param {boolean} trimEnd Trims whitespace from the end of a string. - * @return {!Spannable} String with whitespace removed. - * @private - */ - trim_(trimStart, trimEnd) { - if (!trimStart && !trimEnd) { - return this; - } - - // Special-case whitespace-only strings, including the empty string. - // As an arbitrary decision, we treat this as trimming the whitespace off - // the end, rather than the beginning, of the string. - // This choice affects which spans are kept. - if (/^\s*$/.test(this.string_)) { - return this.substring(0, 0); - } - - // Otherwise, we have at least one non-whitespace character to use as an - // anchor when trimming. - const trimmedStart = trimStart ? this.string_.match(/^\s*/)[0].length : 0; - const trimmedEnd = - trimEnd ? this.string_.match(/\s*$/).index : this.string_.length; - return this.substring(trimmedStart, trimmedEnd); - } - - /** - * Returns this spannable to a json serializable form, including the text - * and span objects whose types have been registered with - * registerSerializableSpan or registerStatelessSerializableSpan. - * @return {!SerializedSpannable} the json serializable form. - */ - toJson() { - const result = {}; - result.string = this.string_; - result.spans = []; - this.spans_.forEach(span => { - const serializeInfo = - serializableSpansByConstructor.get(span.value.constructor); - if (serializeInfo) { - const spanObj = { - type: serializeInfo.name, - start: span.start, - end: span.end, - }; - if (serializeInfo.toJson) { - spanObj.value = serializeInfo.toJson.apply(span.value); - } - result.spans.push(spanObj); - } - }); - return result; - } - - /** - * Creates a spannable from a json serializable representation. - * @param {!SerializedSpannable} obj object containing the serializable - * representation. - * @return {!Spannable} - */ - static fromJson(obj) { - if (typeof obj.string !== 'string') { - throw new Error( - 'Invalid spannable json object: string field not a string'); - } - if (!(obj.spans instanceof Array)) { - throw new Error('Invalid spannable json object: no spans array'); - } - const result = new Spannable(obj.string); - result.spans_ = obj.spans.map(span => { - if (typeof span.type !== 'string') { - throw new Error( - 'Invalid span in spannable json object: type not a string'); - } - if (typeof span.start !== 'number' || typeof span.end !== 'number') { - throw new Error( - 'Invalid span in spannable json object: start or end not a number'); - } - const serializeInfo = serializableSpansByName.get(span.type); - const value = serializeInfo.fromJson(span.value); - return {value, start: span.start, end: span.end}; - }); - return result; - } - - /** - * Registers a type that can be converted to a json serializable format. - * @param {!Function} constructor The type of object that can be converted. - * @param {string} name String identifier used in the serializable format. - * @param {function(!Object): !Object} fromJson A function that converts - * the serializable object to an actual object of this type. - * @param {function(): !Object} toJson A function that converts this object - * to a json serializable object. The function will be called with - * |this| set to the object to convert. - */ - static registerSerializableSpan(constructor, name, fromJson, toJson) { - const obj = {name, fromJson, toJson}; - serializableSpansByName.set(name, obj); - serializableSpansByConstructor.set(constructor, obj); - } - - /** - * Registers an object type that can be converted to/from a json - * serializable form. Objects of this type carry no state that will be - * preserved when serialized. - * @param {!Function} constructor The type of the object that can be - * converted. This constructor will be called with no arguments to - * construct new objects. - * @param {string} name Name of the type used in the serializable object. - */ - static registerStatelessSerializableSpan(constructor, name) { - const obj = {name, toJson: undefined}; - /** - * @param {!Object} obj - * @return {!Object} - */ - obj.fromJson = function(obj) { - return new constructor(); - }; - serializableSpansByName.set(name, obj); - serializableSpansByConstructor.set(constructor, obj); - } -} - - -/** - * A spannable that allows a span value to annotate discontinuous regions of the - * string. In effect, a span value can be set multiple times. - * Note that most methods that assume a span value is unique such as - * |getSpanStart| will use the first span value. - */ -export class MultiSpannable extends Spannable { - /** - * @param {string|!Spannable=} opt_string Initial value of the spannable. - * @param {*=} opt_annotation Initial annotation for the entire string. - */ - constructor(opt_string, opt_annotation) { - super(opt_string, opt_annotation); - } - - /** @override */ - setSpan(value, start, end) { - this.setSpanInternal(value, start, end); - } - - /** @override */ - substring(start, opt_end) { - const ret = Spannable.prototype.substring.call(this, start, opt_end); - return new MultiSpannable(ret); - } -} - - -/** - * An annotation with its start and end points. - * @typedef {{value: *, start: number, end: number}} - */ -let SpanStruct; - -/** - * Describes how to convert a span type to/from serializable json. - * @typedef {{name: string, - * fromJson: function(!Object): !Object, - * toJson: ((function(): !Object)|undefined)}} - */ -let SerializeInfo; - -/** - * The serialized format of a spannable. - * @typedef {{string: string, spans: Array<SerializedSpan>}} - * @private - */ -let SerializedSpannable; - -/** - * The format of a single annotation in a serialized spannable. - * @typedef {{type: string, value: !Object, start: number, end: number}} - */ -let SerializedSpan; - -/** - * Maps type names to serialization info objects. - * @type {Map<string, SerializeInfo>} - */ -const serializableSpansByName = new Map(); - -/** - * Maps constructors to serialization info objects. - * @type {Map<Function, SerializeInfo>} - */ -const serializableSpansByConstructor = new Map(); - -// Helpers for implementing the various |get*| methods of |Spannable|. - -/** - * @param {Function} constructor - * @return {function(SpanStruct): boolean} - */ -function spanInstanceOf(constructor) { - return function(span) { - return span.value instanceof constructor; - }; -} - -/** - * @param {number} position - * @return {function(SpanStruct): boolean} - */ -function spanCoversPosition(position) { - return function(span) { - return span.start <= position && position < span.end; - }; -} - -/** - * @param {*} value - * @return {function(SpanStruct): boolean} - */ -function spanValueIs(value) { - return function(span) { - return span.value === value; - }; -} - -/** - * @param {!SpanStruct|undefined} span - * @return {*} - */ -function valueOfSpan(span) { - return span ? span.value : undefined; -} - -TestImportManager.exportForTesting(Spannable, MultiSpannable);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/spannable.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/common/spannable.ts new file mode 100644 index 0000000..8cc17d7 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/spannable.ts
@@ -0,0 +1,476 @@ +// 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. + +/** + * @fileoverview Class which allows construction of annotated strings. + */ +import {TestImportManager} from '/common/testing/test_import_manager.js'; + +type Annotation = any; + +interface Interval { + start: number; + end: number; +} + +export class Spannable { + /** Underlying string. */ + private string_: string; + /** Spans (annotations). */ + private spans_: SpanStruct[] = []; + + /** + * @param stringValue Initial value of the spannable. + * @param annotation Initial annotation for the entire string. + */ + constructor(stringValue?: string|Spannable, annotation?: Annotation) { + this.string_ = stringValue instanceof Spannable ? '' : stringValue || ''; + + // Append the initial spannable. + if (stringValue instanceof Spannable) { + this.append(stringValue); + } + + // Optionally annotate the entire string. + if (annotation !== undefined) { + const len = this.string_.length; + this.spans_.push({value: annotation, start: 0, end: len}); + } + } + + toString(): string { + return this.string_; + } + + /** @return The length of the string */ + get length(): number { + return this.string_.length; + } + + /** + * Adds a span to some region of the string. + * @param value Annotation. + * @param start Starting index (inclusive). + * @param end Ending index (exclusive). + */ + setSpan(value: Annotation, start: number, end: number): void { + this.removeSpan(value); + this.setSpanInternal(value, start, end); + } + + /** + * @param value Annotation. + * @param start Starting index (inclusive). + * @param end Ending index (exclusive). + */ + protected setSpanInternal( + value: Annotation, start: number, end: number): void { + if (0 <= start && start <= end && end <= this.string_.length) { + // Zero-length spans are explicitly allowed, because it is possible to + // query for position by annotation as well as the reverse. + this.spans_.push({value, start, end}); + this.spans_.sort(function(a, b) { + let ret = a.start - b.start; + if (ret === 0) { + ret = a.end - b.end; + } + return ret; + }); + } else { + throw new RangeError( + 'span out of range (start=' + start + ', end=' + end + + ', len=' + this.string_.length + ')'); + } + } + + /** + * Removes a span. + * @param value Annotation. + */ + removeSpan(value: Annotation): void { + for (let i = this.spans_.length - 1; i >= 0; i--) { + if (this.spans_[i].value === value) { + this.spans_.splice(i, 1); + } + } + } + + /** + * Appends another Spannable or string to this one. + * @param other String or spannable to concatenate. + */ + append(other: string | Spannable): void { + if (other instanceof Spannable) { + const otherSpannable = other as Spannable; + const originalLength = this.length; + this.string_ += otherSpannable.string_; + other.spans_.forEach( + span => this.setSpan( + span.value, span.start + originalLength, + span.end + originalLength)); + } else if (typeof other === 'string') { + this.string_ += other; + } + } + + /** + * Returns the first value matching a position. + * @param position Position to query. + * @return Value annotating that position, or undefined if none is + * found. + */ + getSpan(position: number): Annotation { + return valueOfSpan(this.spans_.find(spanCoversPosition(position))); + } + + /** + * Returns the first span value which is an instance of a given constructor. + * @param constructor Constructor. + * @return Object if found; undefined otherwise. + */ + getSpanInstanceOf(constructor: Function): Annotation { + return valueOfSpan(this.spans_.find(spanInstanceOf(constructor))); + } + + /** + * Returns all span values which are an instance of a given constructor. + * Spans are returned in the order of their starting index and ending index + * for spans with equals tarting indices. + * @param constructor Constructor. + * @return Array of object. + */ + getSpansInstanceOf(constructor: Function): Annotation[] { + return (this.spans_.filter(spanInstanceOf(constructor)).map(valueOfSpan)); + } + + /** + * Returns all spans matching a position. + * @param position Position to query. + * @return Values annotating that position. + */ + getSpans(position: number): Annotation[] { + return (this.spans_.filter(spanCoversPosition(position)).map(valueOfSpan)); + } + + /** + * Returns whether a span is contained in this object. + * @param value Annotation. + */ + hasSpan(value: Annotation): boolean { + return this.spans_.some(spanValueIs(value)); + } + + /** + * Returns the start of the requested span. Throws if the span doesn't exist + * in this object. + * @param value Annotation. + */ + getSpanStart(value: Annotation): number { + return this.getSpanByValueOrThrow_(value).start; + } + + /** + * Returns the end of the requested span. Throws if the span doesn't exist + * in this object. + * @param value Annotation. + */ + getSpanEnd(value: Annotation): number { + return this.getSpanByValueOrThrow_(value).end; + } + + /** + * @param value Annotation. + */ + getSpanIntervals(value: Annotation): Interval[] { + return this.spans_.filter(span => span.value === value).map(span => { + return {start: span.start, end: span.end}; + }); + } + + /** + * Returns the number of characters covered by the given span. Throws if + * the span is not in this object. + */ + getSpanLength(value: Annotation): number { + const span = this.getSpanByValueOrThrow_(value); + return span.end - span.start; + } + + /** + * Gets the internal object for a span or throws if the span doesn't exist. + * @param value The annotation. + */ + private getSpanByValueOrThrow_(value: Annotation): SpanStruct { + const span = this.spans_.find(spanValueIs(value)); + if (span) { + return span; + } + throw new Error('Span ' + value + ' doesn\'t exist in spannable'); + } + + /** + * Returns a substring of this spannable. + * Note that while similar to String#substring, this function is much less + * permissive about its arguments. It does not accept arguments in the wrong + * order or out of bounds. + * + * @param start Start index, inclusive. + * @param end End index, exclusive. + * If excluded, the length of the string is used instead. + * @return Substring requested. + */ + substring(start: number, end?: number): Spannable { + end = end !== undefined ? end : this.string_.length; + + if (start < 0 || end > this.string_.length || start > end) { + throw new RangeError('substring indices out of range'); + } + + const result = new Spannable(this.string_.substring(start, end)); + this.spans_.forEach(span => { + if (span.start <= end && span.end >= start) { + const newStart = Math.max(0, span.start - start); + const newEnd = Math.min(end - start, span.end - start); + result.spans_.push({value: span.value, start: newStart, end: newEnd}); + } + }); + return result; + } + + /** + * Trims whitespace from the beginning. + * @return String with whitespace removed. + */ + trimLeft(): Spannable { + return this.trim_(true, false); + } + + /** + * Trims whitespace from the end. + * @return String with whitespace removed. + */ + trimRight(): Spannable { + return this.trim_(false, true); + } + + /** + * Trims whitespace from the beginning and end. + * @return String with whitespace removed. + */ + trim(): Spannable { + return this.trim_(true, true); + } + + /** + * Trims whitespace from either the beginning and end or both. + * @param trimStart Trims whitespace from the start of a string. + * @param trimEnd Trims whitespace from the end of a string. + * @return String with whitespace removed. + */ + private trim_(trimStart: boolean, trimEnd: boolean): Spannable { + if (!trimStart && !trimEnd) { + return this; + } + + // Special-case whitespace-only strings, including the empty string. + // As an arbitrary decision, we treat this as trimming the whitespace off + // the end, rather than the beginning, of the string. + // This choice affects which spans are kept. + if (/^\s*$/.test(this.string_)) { + return this.substring(0, 0); + } + + // Otherwise, we have at least one non-whitespace character to use as an + // anchor when trimming. + // TODO(b/314203187): Not null asserted, check that this is correct. + const trimmedStart = trimStart ? this.string_.match(/^\s*/)![0].length : 0; + const trimmedEnd = + trimEnd ? this.string_.match(/\s*$/)!.index : this.string_.length; + return this.substring(trimmedStart, trimmedEnd); + } + + /** + * Returns this spannable to a json serializable form, including the text + * and span objects whose types have been registered with + * registerSerializableSpan or registerStatelessSerializableSpan. + * @return the json serializable form. + */ + toJson(): SerializedSpannable { + const spans: SerializedSpan[] = []; + this.spans_.forEach(span => { + const serializeInfo = + serializableSpansByConstructor.get(span.value.constructor); + if (serializeInfo) { + const spanObj: SerializedSpan = { + type: serializeInfo.name, + start: span.start, + end: span.end, + value: undefined, + }; + if (serializeInfo.toJson) { + spanObj.value = serializeInfo.toJson.apply(span.value); + } + spans.push(spanObj); + } + }); + return {string: this.string_, spans}; + } + + /** + * Creates a spannable from a json serializable representation. + * @param obj object containing the serializable representation. + */ + static fromJson(obj: SerializedSpannable): Spannable { + if (typeof obj.string !== 'string') { + throw new Error( + 'Invalid spannable json object: string field not a string'); + } + if (!(obj.spans instanceof Array)) { + throw new Error('Invalid spannable json object: no spans array'); + } + const result = new Spannable(obj.string); + result.spans_ = obj.spans.map(span => { + if (typeof span.type !== 'string') { + throw new Error( + 'Invalid span in spannable json object: type not a string'); + } + if (typeof span.start !== 'number' || typeof span.end !== 'number') { + throw new Error( + 'Invalid span in spannable json object: start or end not a number'); + } + // TODO(b/314203187): Not null asserted, check that this is correct. + const serializeInfo = serializableSpansByName.get(span.type)!; + const value = serializeInfo.fromJson(span.value); + return {value, start: span.start, end: span.end}; + }); + return result; + } + + /** + * Registers a type that can be converted to a json serializable format. + * @param constructor The type of object that can be converted. + * @param name String identifier used in the serializable format. + * @param fromJson A function that converts the serializable object to an + * actual object of this type. + * @param toJson A function that converts this object to a json serializable + * object. The function will be called with |this| set to the object to + * convert. + */ + static registerSerializableSpan( + constructor: Function, name: string, + fromJson: (json: SerializedSpan) => Annotation, + toJson: () => SerializedSpan): void { + const obj: SerializeInfo = {name, fromJson, toJson}; + serializableSpansByName.set(name, obj); + serializableSpansByConstructor.set(constructor, obj); + } + + /** + * Registers an object type that can be converted to/from a json + * serializable form. Objects of this type carry no state that will be + * preserved when serialized. + * @param constructor The type of the object that can be converted. This + * constructor will be called with no arguments to construct new objects. + * @param name Name of the type used in the serializable object. + */ + static registerStatelessSerializableSpan( + constructor: Function, name: string): void { + const fromJson = function(_obj: SerializedSpan): Annotation { + return new (constructor as FunctionConstructor)(); + }; + const obj: SerializeInfo = {name, toJson: undefined, fromJson}; + serializableSpansByName.set(name, obj); + serializableSpansByConstructor.set(constructor, obj); + } +} + + +/** + * A spannable that allows a span value to annotate discontinuous regions of the + * string. In effect, a span value can be set multiple times. + * Note that most methods that assume a span value is unique such as + * |getSpanStart| will use the first span value. + */ +export class MultiSpannable extends Spannable { + /** + * @param string Initial value of the spannable. + * @param annotation Initial annotation for the entire string. + */ + constructor(string?: string | Spannable, annotation?: Annotation) { + super(string, annotation); + } + + override setSpan(value: Annotation, start: number, end: number): void { + this.setSpanInternal(value, start, end); + } + + override substring(start: number, end: number): MultiSpannable { + const ret = Spannable.prototype.substring.call(this, start, end); + return new MultiSpannable(ret); + } +} + +// Local to module. + +/** An annotation with its start and end points. */ +interface SpanStruct { + value: Annotation; + start: number; + end: number; +} + +/** Describes how to convert a span type to/from serializable json. */ +interface SerializeInfo { + name: string; + fromJson: (json: SerializedSpan) => Annotation; + toJson?: () => SerializedSpan; +} + +/** The serialized format of a spannable. */ +interface SerializedSpannable { + string: string; + spans: SerializedSpan[]; +} + +/** The format of a single annotation in a serialized spannable. */ +interface SerializedSpan { + type: string; + value: Annotation; + start: number; + end: number; +} + +type SpanPredicate = (span: SpanStruct) => boolean; + +/** Maps type names to serialization info objects. */ +const serializableSpansByName: Map<string, SerializeInfo> = new Map(); + +/** Maps constructors to serialization info objects. */ +const serializableSpansByConstructor: Map<Function, SerializeInfo> = new Map(); + +// Helpers for implementing the various |get*| methods of |Spannable|. + +function spanInstanceOf(constructor: Function): SpanPredicate { + return function(span) { + return span.value instanceof constructor; + }; +} + +function spanCoversPosition(position: number): SpanPredicate { + return function(span) { + return span.start <= position && position < span.end; + }; +} + +function spanValueIs(value: Annotation): SpanPredicate { + return function(span) { + return span.value === value; + }; +} + +function valueOfSpan(span?: SpanStruct): Annotation { + return span ? span.value : undefined; +} + +TestImportManager.exportForTesting(Spannable, MultiSpannable);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/menu_manager.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/menu_manager.ts index b76cfd05..51d9c91 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/menu_manager.ts +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/menu_manager.ts
@@ -343,15 +343,16 @@ // commands for touch). const keymap = KeyMap.get(); - const sortedBindings = keymap.bindings().slice(); + // A shallow copy of the bindings is returned, so re-ordering the elements + // does not change the original. + const sortedBindings = keymap.bindings(); for (const binding of sortedBindings) { const command = binding.command; const keySeq = binding.sequence; binding.keySeq = await KeyUtil.keySequenceToString(keySeq, true); const titleMsgId = CommandStore.messageForCommand(command); if (!titleMsgId) { - // Title messages are intentionally missing for some keyboard - // shortcuts. + // Title messages are intentionally missing for some keyboard shortcuts. if (!(command in COMMANDS_WITH_NO_MSG_ID) && !MenuManager.disableMissingMsgsErrorsForTesting) { console.error('No localization for: ' + command); @@ -368,9 +369,17 @@ return sortedBindings; } + makeBindingMap(sortedBindings: KeyBinding[]): Map<Command, KeyBinding> { + const bindingMap = new Map(); + for (const binding of sortedBindings) { + bindingMap.set(binding.command, binding); + } + return bindingMap; + } + makeCategoryMapping( actionsMenu: PanelMenu, chromevoxMenu: PanelMenu, jumpMenu: PanelMenu, - speechMenu: PanelMenu): Record<CommandCategory, PanelMenu | null> { + speechMenu: PanelMenu): Record<CommandCategory, PanelMenu|null> { return { [CommandCategory.ACTIONS]: actionsMenu, [CommandCategory.BRAILLE]: null, @@ -387,12 +396,34 @@ }; } - makeBindingMap(sortedBindings: KeyBinding[]): Map<Command, KeyBinding> { - const bindingMap = new Map(); - for (const binding of sortedBindings) { - bindingMap.set(binding.command, binding); + /** + * Called when the user releases the mouse button. If it's anywhere other + * than on the menus button, close the menus and return focus to the page, + * and if the mouse was released over a menu item, execute that item's + * callback. + */ + onMouseUp(event: MouseEvent): void { + if (!this.activeMenu_) { + return; } - return bindingMap; + + let target: HTMLElement|null = event.target as HTMLElement; + while (target && !target.classList.contains('menu-item')) { + // Allow the user to click and release on the menu button and leave + // the menu button. + if (target.id === 'menus_button') { + return; + } + + target = target.parentElement; + } + + // TODO(b/314203187): Not null asserted, check that this is correct. + if (target && this.activeMenu_) { + PanelInterface.instance!.setPendingCallback( + this.activeMenu_.getCallbackForElement(target)); + } + PanelInterface.instance!.closeMenusAndRestoreFocus(); } /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts index 0889675..7cad9434 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.ts
@@ -76,7 +76,8 @@ document.addEventListener( 'keydown', (event: KeyboardEvent) => this.onKeyDown_(event), false); document.addEventListener( - 'mouseup', (event: MouseEvent) => this.onMouseUp_(event), false); + 'mouseup', (event: MouseEvent) => this.menuManager_.onMouseUp(event), + false); window.addEventListener( 'storage', (event: StorageEvent) => this.onStorageChanged_(event), false); @@ -416,35 +417,6 @@ } /** - * Called when the user releases the mouse button. If it's anywhere other - * than on the menus button, close the menus and return focus to the page, - * and if the mouse was released over a menu item, execute that item's - * callback. - */ - private onMouseUp_(event: Event): void { - if (!this.menuManager_.activeMenu) { - return; - } - - let target = event.target as HTMLElement | null; - while (target && !target.classList.contains('menu-item')) { - // Allow the user to click and release on the menu button and leave - // the menu button. - if (target.id === 'menus_button') { - return; - } - - target = target.parentElement; - } - - if (target && this.menuManager_.activeMenu) { - this.pendingCallback_ = - this.menuManager_.activeMenu.getCallbackForElement(target); - } - this.closeMenusAndRestoreFocus(); - } - - /** * Called when a key is pressed. Handle arrow keys to navigate the menus, * Esc to close, and Enter/Space to activate an item. */
diff --git a/chrome/browser/resources/chromeos/login/components/oobe_categories_list.ts b/chrome/browser/resources/chromeos/login/components/oobe_categories_list.ts index f5a66750..e1ada9b 100644 --- a/chrome/browser/resources/chromeos/login/components/oobe_categories_list.ts +++ b/chrome/browser/resources/chromeos/login/components/oobe_categories_list.ts
@@ -104,6 +104,12 @@ this.selectedCategoriesCount = 0; this.loadedIconsCount = 0; this.itemRendered = 0; + this.categoriesList.forEach((category) => { + if (category.selected) { + this.selectedCategoriesCount++; + this.categoriesSelected.push(category.categoryId); + } + }); } itemRenderedChanged(): void {
diff --git a/chrome/browser/resources/chromeos/password_change/BUILD.gn b/chrome/browser/resources/chromeos/password_change/BUILD.gn index 78e8f024..c17b8f2 100644 --- a/chrome/browser/resources/chromeos/password_change/BUILD.gn +++ b/chrome/browser/resources/chromeos/password_change/BUILD.gn
@@ -50,6 +50,8 @@ in_files = [ "confirm_password_change.html", "confirm_password_change.js", + "confirm_password_change_app.html", + "confirm_password_change_app.js", "password_change.js", "password_change_app.html", "password_change_app.js", @@ -64,6 +66,7 @@ out_folder = preprocess_folder out_manifest = gen_files_manifest in_files = [ + "confirm_password_change.html.js", "password_change.html.js", "urgent_password_expiry_notification_app.html.js", ] @@ -71,6 +74,7 @@ html_to_wrapper("html_wrapper_files") { in_files = [ + "confirm_password_change.html", "password_change.html", "urgent_password_expiry_notification_app.html", ]
diff --git a/chrome/browser/resources/chromeos/password_change/confirm_password_change.html b/chrome/browser/resources/chromeos/password_change/confirm_password_change.html index 60b963d..26481a6 100644 --- a/chrome/browser/resources/chromeos/password_change/confirm_password_change.html +++ b/chrome/browser/resources/chromeos/password_change/confirm_password_change.html
@@ -1,105 +1,84 @@ -<!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> -<head> - <meta charset="utf-8"> +<style> + ::part(dialog) { + /* The HTML dialog should fill the entire system dialog. */ + height: 100%; + width: 100%; + } - <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> + [slot='title'] { + color: black; + font-family: Roboto, sans-serif; + font-size: 15px; + padding: 24px 24px 16px; + } + [slot='body'] { + color: var(--google-grey-900); + font-family: Roboto, sans-serif; + font-size: 13px; + padding: 0 48px 0 24px; + } - <script type="module" src="confirm_password_change.js"></script> + [slot='button-container'] { + bottom: 0; + box-sizing: border-box; + margin: 0; + padding: 16px; + position: fixed; + width: 100%; + } - <dom-module id="confirm-password-change"> - <template> - <style> - ::part(dialog) { - /* The HTML dialog should fill the entire system dialog. */ - height: 100%; - width: 100%; - } + #prompt { + margin-bottom: 20px; + } - [slot='title'] { - color: black; - font-family: Roboto, sans-serif; - font-size: 15px; - padding: 24px 24px 16px; - } + cr-input[type='password'] { + font-size: 20px; + } - [slot='body'] { - color: var(--google-grey-900); - font-family: Roboto, sans-serif; - font-size: 13px; - padding: 0 48px 0 24px; - } + paper-spinner-lite { + height: 44px; + left: 50%; + margin: -22px; + position: fixed; + top: 50%; + width: 44px; + } +</style> - [slot='button-container'] { - bottom: 0; - box-sizing: border-box; - margin: 0; - padding: 16px; - position: fixed; - width: 100%; - } +<paper-spinner-lite active></paper-spinner-lite> - #prompt { - margin-bottom: 20px; - } +<cr-dialog id="dialog" exportparts="dialog"> + <div slot="title">[[i18n('title')]]</div> - cr-input[type='password'] { - font-size: 20px; - } + <div slot="body" spellcheck="false"> + <div id="prompt">[[promptString_]]</div> - paper-spinner-lite { - height: 44px; - left: 50%; - margin: -22px; - position: fixed; - top: 50%; - width: 44px; - } - </style> + <div hidden="[[!showOldPasswordPrompt_]]"> + <cr-input type="password" value="{{oldPassword_}}" + label="[[i18n('oldPassword')]]" + invalid="[[invalidOldPassword_(currentValidationError_)]]" + error-message="[[errorString_]]"> + </cr-input> + </div> - <paper-spinner-lite active></paper-spinner-lite> + <div hidden="[[!showNewPasswordPrompt_]]"> + <cr-input type="password" value="{{newPassword_}}" + label="[[i18n('newPassword')]]" + invalid="[[invalidNewPassword_(currentValidationError_)]]" + error-message="[[errorString_]]"> + </cr-input> + <cr-input type="password" value="{{confirmNewPassword_}}" + label="[[i18n('confirmNewPassword')]]" + invalid="[[invalidConfirmNewPassword_(currentValidationError_)]]" + error-message="[[errorString_]]"> + </cr-input> + </div> + </div> - <cr-dialog id="dialog" exportparts="dialog"> - <div slot="title">[[i18n('title')]]</div> - - <div slot="body" spellcheck="false"> - <div id="prompt">[[promptString_]]</div> - - <div hidden="[[!showOldPasswordPrompt_]]"> - <cr-input type="password" value="{{oldPassword_}}" - label="[[i18n('oldPassword')]]" - invalid="[[invalidOldPassword_(currentValidationError_)]]" - error-message="[[errorString_]]"> - </cr-input> - </div> - - <div hidden="[[!showNewPasswordPrompt_]]"> - <cr-input type="password" value="{{newPassword_}}" - label="[[i18n('newPassword')]]" - invalid="[[invalidNewPassword_(currentValidationError_)]]" - error-message="[[errorString_]]"> - </cr-input> - <cr-input type="password" value="{{confirmNewPassword_}}" - label="[[i18n('confirmNewPassword')]]" - invalid= - "[[invalidConfirmNewPassword_(currentValidationError_)]]" - error-message="[[errorString_]]"> - </cr-input> - </div> - </div> - - <div slot="button-container"> - <cr-button class="action-button" on-click="onSaveTap_"> - [[i18n('save')]] - </cr-button> - </div> - </cr-dialog> - </template> - </dom-module> -</head> - -<body> - <confirm-password-change id="main-element"></confirm-password-change> -</body> -</html> + <div slot="button-container"> + <cr-button class="action-button" on-click="onSaveTap_"> + [[i18n('save')]] + </cr-button> + </div> +</cr-dialog>
diff --git a/chrome/browser/resources/chromeos/password_change/confirm_password_change.js b/chrome/browser/resources/chromeos/password_change/confirm_password_change.js index 7e622d9..0737e7d 100644 --- a/chrome/browser/resources/chromeos/password_change/confirm_password_change.js +++ b/chrome/browser/resources/chromeos/password_change/confirm_password_change.js
@@ -17,16 +17,18 @@ import 'chrome://confirm-password-change/strings.m.js'; import 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js'; -import 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js'; import 'chrome://resources/ash/common/cr_elements/cr_input/cr_input.js'; import 'chrome://resources/ash/common/cr_elements/cr_shared_vars.css.js'; import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; import {sendWithPromise} from 'chrome://resources/ash/common/cr.m.js'; -import {I18nBehavior} from 'chrome://resources/ash/common/i18n_behavior.js'; +import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; import {WebUIListenerBehavior} from 'chrome://resources/ash/common/web_ui_listener_behavior.js'; -import {Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {getTemplate} from './confirm_password_change.html.js'; /** @enum{number} */ const ValidationErrorType = { @@ -38,62 +40,91 @@ INCORRECT_OLD_PASSWORD: 5, }; -Polymer({ - is: 'confirm-password-change', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ConfirmPasswordChangeElementBase = + mixinBehaviors([I18nBehavior, WebUIListenerBehavior], PolymerElement); - behaviors: [I18nBehavior, WebUIListenerBehavior], +/** + * @typedef {{ + * dialog: CrDialogElement, + * }} + */ +ConfirmPasswordChangeElementBase.$; - properties: { - /** @private {boolean} */ - showSpinner_: - {type: Boolean, value: true, observer: 'onShowSpinnerChanged_'}, +/** @polymer */ +class ConfirmPasswordChangeElement extends ConfirmPasswordChangeElementBase { + static get is() { + return 'confirm-password-change'; + } - /** @private {boolean} */ - showOldPasswordPrompt_: {type: Boolean, value: true}, + static get template() { + return getTemplate(); + } - /** @private {string} */ - oldPassword_: {type: String, value: ''}, + static get properties() { + return { + /** @private {boolean} */ + showSpinner_: + {type: Boolean, value: true, observer: 'onShowSpinnerChanged_'}, - /** @private {boolean} */ - showNewPasswordPrompt_: {type: Boolean, value: true}, + /** @private {boolean} */ + showOldPasswordPrompt_: {type: Boolean, value: true}, - /** @private {string} */ - newPassword_: {type: String, value: ''}, + /** @private {string} */ + oldPassword_: {type: String, value: ''}, - /** @private {string} */ - confirmNewPassword_: {type: String, value: ''}, + /** @private {boolean} */ + showNewPasswordPrompt_: {type: Boolean, value: true}, - /** @private {!ValidationErrorType} */ - currentValidationError_: { - type: Number, - value: ValidationErrorType.NO_ERROR, - observer: 'onErrorChanged_', - }, + /** @private {string} */ + newPassword_: {type: String, value: ''}, - /** @private {string} */ - promptString_: { - type: String, - computed: - 'getPromptString_(showOldPasswordPrompt_, showNewPasswordPrompt_)', - }, + /** @private {string} */ + confirmNewPassword_: {type: String, value: ''}, - /** @private {string} */ - errorString_: - {type: String, computed: 'getErrorString_(currentValidationError_)'}, - }, + /** @private {!ValidationErrorType} */ + currentValidationError_: { + type: Number, + value: ValidationErrorType.NO_ERROR, + observer: 'onErrorChanged_', + }, - observers: [ - 'onShowPromptChanged_(showOldPasswordPrompt_, showNewPasswordPrompt_)', - ], + /** @private {string} */ + promptString_: { + type: String, + computed: + 'getPromptString_(showOldPasswordPrompt_, showNewPasswordPrompt_)', + }, + + /** @private {string} */ + errorString_: + {type: String, computed: 'getErrorString_(currentValidationError_)'}, + + }; + } + + static get observers() { + return [ + 'onShowPromptChanged_(showOldPasswordPrompt_, showNewPasswordPrompt_)', + + ]; + } + /** @override */ - attached() { + connectedCallback() { + super.connectedCallback(); + this.addWebUIListener('incorrect-old-password', () => { this.onIncorrectOldPassword_(); }); this.getInitialState_(); - }, + } /** @private */ getInitialState_() { @@ -102,7 +133,7 @@ this.showNewPasswordPrompt_ = result.showNewPasswordPrompt; this.showSpinner_ = result.showSpinner; }); - }, + } /** @private */ @@ -113,7 +144,7 @@ } else { this.$.dialog.showModal(); } - }, + } /** @private */ onShowPromptChanged_() { @@ -123,14 +154,14 @@ const height = loadTimeData.getInteger('height' + suffix); window.resizeTo(width, height); - }, + } /** @private */ onErrorChanged_() { if (this.currentValidationError_ !== ValidationErrorType.NO_ERROR) { this.showSpinner_ = false; } - }, + } /** @private */ onSaveTap_() { @@ -139,7 +170,7 @@ chrome.send('changePassword', [this.oldPassword_, this.newPassword_]); this.showSpinner_ = true; } - }, + } /** @private */ onIncorrectOldPassword_() { @@ -154,7 +185,7 @@ this.showOldPasswordPrompt_ = true; this.currentValidationError_ = ValidationErrorType.MISSING_OLD_PASSWORD; } - }, + } /** * @return {!ValidationErrorType} @@ -178,7 +209,7 @@ } } return ValidationErrorType.NO_ERROR; - }, + } /** * @return {boolean} @@ -188,7 +219,7 @@ const err = this.currentValidationError_; return err === ValidationErrorType.MISSING_OLD_PASSWORD || err === ValidationErrorType.INCORRECT_OLD_PASSWORD; - }, + } /** * @return {boolean} @@ -197,7 +228,7 @@ invalidNewPassword_() { return this.currentValidationError_ === ValidationErrorType.MISSING_NEW_PASSWORD; - }, + } /** * @return {boolean} @@ -207,7 +238,7 @@ const err = this.currentValidationError_; return err === ValidationErrorType.MISSING_CONFIRM_NEW_PASSWORD || err === ValidationErrorType.PASSWORDS_DO_NOT_MATCH; - }, + } /** * @return {string} @@ -224,7 +255,7 @@ return this.i18n('newPasswordPrompt'); } return ''; - }, + } /** * @return {string} @@ -239,5 +270,8 @@ default: return ''; } - }, -}); + } +} + +customElements.define( + ConfirmPasswordChangeElement.is, ConfirmPasswordChangeElement);
diff --git a/chrome/browser/resources/chromeos/password_change/confirm_password_change_app.html b/chrome/browser/resources/chromeos/password_change/confirm_password_change_app.html new file mode 100644 index 0000000..2ab818f --- /dev/null +++ b/chrome/browser/resources/chromeos/password_change/confirm_password_change_app.html
@@ -0,0 +1,11 @@ +<!doctype html> +<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<head> + <meta charset="utf-8"> + <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> +</head> +<body> + <script type="module" src="confirm_password_change.js"></script> + <confirm-password-change id="main-element"></confirm-password-change> +</body> +</html>
diff --git a/chrome/browser/resources/chromeos/password_change/confirm_password_change_app.js b/chrome/browser/resources/chromeos/password_change/confirm_password_change_app.js new file mode 100644 index 0000000..2b7d3b4 --- /dev/null +++ b/chrome/browser/resources/chromeos/password_change/confirm_password_change_app.js
@@ -0,0 +1,18 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import './strings.m.js'; +import './confirm_password_change.js'; + +import {$} from 'chrome://resources/ash/common/util.js'; + +function initialize() { + // '$(id)' is an alias for 'document.getElementById(id)'. It is defined + // in chrome://resources/ash/common/util.js. If this function is not exposed + // via the global object, it would not be available to tests that inject + // JavaScript directly into the renderer. + window.$ = $; +} + +initialize();
diff --git a/chrome/browser/resources/compose/app.ts b/chrome/browser/resources/compose/app.ts index 7cdd75a..9e50910 100644 --- a/chrome/browser/resources/compose/app.ts +++ b/chrome/browser/resources/compose/app.ts
@@ -67,6 +67,7 @@ redoButton: CrButtonElement, refreshButton: HTMLElement, resultContainer: HTMLElement, + resultTextContainer: HTMLElement, resultFooter: HTMLElement, submitButton: CrButtonElement, submitEditButton: CrButtonElement,
diff --git a/chrome/browser/resources/management/management_browser_proxy.ts b/chrome/browser/resources/management/management_browser_proxy.ts index 704aad9..f06ba403 100644 --- a/chrome/browser/resources/management/management_browser_proxy.ts +++ b/chrome/browser/resources/management/management_browser_proxy.ts
@@ -124,6 +124,11 @@ * @return The list of browser reporting info messages. */ initBrowserReportingInfo(): Promise<BrowserReportingResponse[]>; + + /** + * @return The list of profile reporting info messages. + */ + initProfileReportingInfo(): Promise<BrowserReportingResponse[]>; } export class ManagementBrowserProxyImpl implements ManagementBrowserProxy { @@ -165,6 +170,10 @@ return sendWithPromise('initBrowserReportingInfo'); } + initProfileReportingInfo() { + return sendWithPromise('initProfileReportingInfo'); + } + static getInstance(): ManagementBrowserProxy { return instance || (instance = new ManagementBrowserProxyImpl()); }
diff --git a/chrome/browser/resources/management/management_ui.html b/chrome/browser/resources/management/management_ui.html index 8c169dc..a4653318 100644 --- a/chrome/browser/resources/management/management_ui.html +++ b/chrome/browser/resources/management/management_ui.html
@@ -67,7 +67,7 @@ width: 40px; } - .eol-section iron-icon { + .eol-section cr-icon { --iron-icon-fill-color: #E8710A; height: var(--cr-icon-size); width: var(--cr-icon-size); @@ -130,7 +130,7 @@ margin: 0; } - .report iron-icon { + .report cr-icon { height: 20px; margin-inline-end: 16px; width: 20px; @@ -196,11 +196,12 @@ .extension-permissions ul, .application-permissions ul, - .report ul { + .report ul.browser { list-style: none; margin: 0; padding: 0; } + </style> <cr-toolbar page-name="$i18n{toolbarTitle}" role="banner" autofocus @@ -223,7 +224,7 @@ <if expr="chromeos_ash"> <section class="eol-section" hidden="[[!eolMessage_]]"> <div class="eol-warning-icon"> - <iron-icon icon="cr20:banner-warning"></iron-icon> + <cr-icon icon="cr20:banner-warning"></cr-icon> </div> <div class="eol-message"> <div>[[eolMessage_]]</div> @@ -297,8 +298,8 @@ <div class="content-indented"> <template is="dom-repeat" items="[[deviceReportingInfo_]]"> <div class="report"> - <iron-icon icon="[[getIconForDeviceReportingType_( - item.reportingType)]]"></iron-icon> + <cr-icon icon="[[getIconForDeviceReportingType_( + item.reportingType)]]"></cr-icon> <div inner-h-t-m-l="[[getDeviceReportingHtmlContent_(item)]]"> </div> @@ -323,8 +324,8 @@ <div> <template is="dom-repeat" items="[[browserReportingInfo_]]"> <div class="report"> - <iron-icon icon="[[item.icon]]"></iron-icon> - <ul> + <cr-icon icon="[[item.icon]]"></cr-icon> + <ul class="browser"> <template is="dom-repeat" items="[[item.messageIds]]" as="messageId"> <li inner-h-t-m-l="[[i18nAdvanced(messageId)]]"></li> @@ -335,6 +336,26 @@ </div> </section> </template> + + <template is="dom-if" + if="[[showProfileReportingInfo_(profileReportingInfo_)]]"> + <section> + <h2 class="cr-title-text">$i18n{browserReporting}</h2> + <div class="subtitle"> + $i18n{profileReportingExplanation} + </div> + <div> + <div class="report"> + <ul class="profile"> + <template is="dom-repeat" items="[[profileReportingInfo_]]"> + <li inner-h-t-m-l="[[i18nAdvanced(item.messageIds.0)]]"> + </li> + </template> + </ul> + </div> + </div> + </section> + </template> </if> <template is="dom-if" if="[[showExtensionReportingInfo_(extensions_)]]">
diff --git a/chrome/browser/resources/management/management_ui.ts b/chrome/browser/resources/management/management_ui.ts index c5124f6..a66ab93f 100644 --- a/chrome/browser/resources/management/management_ui.ts +++ b/chrome/browser/resources/management/management_ui.ts
@@ -5,9 +5,10 @@ import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import 'chrome://resources/cr_elements/cr_icons.css.js'; import 'chrome://resources/cr_elements/cr_page_host_style.css.js'; +import 'chrome://resources/cr_elements/cr_icon/cr_icon.js'; import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; import 'chrome://resources/cr_elements/cr_hidden_style.css.js'; -import 'chrome://resources/cr_elements/icons.html.js'; +import 'chrome://resources/cr_elements/icons_lit.html.js'; import 'chrome://resources/cr_elements/cr_shared_style.css.js'; import './icons.html.js'; import './strings.m.js'; @@ -30,7 +31,7 @@ interface BrowserReportingData { messageIds: string[]; - icon: string; + icon?: string; } const ManagementUiElementBase = WebUiListenerMixin(I18nMixin(PolymerElement)); @@ -62,6 +63,11 @@ browserReportingInfo_: Array, /** + * List of messages related to profile reporting. + */ + profileReportingInfo_: Array, + + /** * List of messages related to extension reporting. */ extensions_: Array, @@ -110,6 +116,8 @@ private applications_: Application[]|null; private browserReportingInfo_: BrowserReportingData[]|null; + private profileReportingInfo_: BrowserReportingData[]|null; + private reportingInfo_: BrowserReportingData[]|null; private extensions_: Extension[]|null; private managedWebsites_: string[]|null; private managedWebsitesSubtitle_: string; @@ -144,7 +152,7 @@ document.documentElement.classList.remove('loading'); this.browserProxy_ = ManagementBrowserProxyImpl.getInstance(); this.updateManagedFields_(); - this.initBrowserReportingInfo_(); + this.initReportingInfo_(); this.getThreatProtectionInfo_(); this.addWebUiListener( @@ -152,6 +160,11 @@ (reportingInfo: BrowserReportingResponse[]) => this.onBrowserReportingInfoReceived_(reportingInfo)); + this.addWebUiListener( + 'profile-reporting-info-updated', + (reportingInfo: BrowserReportingResponse[]) => + this.onProfileReportingInfoReceived_(reportingInfo)); + // <if expr="is_chromeos"> this.addWebUiListener( 'plugin-vm-data-collection-updated', @@ -176,9 +189,11 @@ // </if> } - private initBrowserReportingInfo_() { + private initReportingInfo_() { this.browserProxy_!.initBrowserReportingInfo().then( reportingInfo => this.onBrowserReportingInfoReceived_(reportingInfo)); + this.browserProxy_!.initProfileReportingInfo().then( + reportingInfo => this.onProfileReportingInfoReceived_(reportingInfo)); } private onBrowserReportingInfoReceived_(reportingInfo: @@ -207,6 +222,14 @@ .map(reportingType => reportingInfoMap[reportingType]); } + + private onProfileReportingInfoReceived_(reportingInfo: + BrowserReportingResponse[]) { + this.profileReportingInfo_ = + reportingInfo.map((info) => ({ + messageIds: [info.messageId], + })); + } private getExtensions_() { this.browserProxy_!.getExtensions().then(extensions => { this.extensions_ = extensions; @@ -342,6 +365,15 @@ } /** + * @return Whether there are profile reporting info to show with new format. + */ + private showProfileReportingInfo_(): boolean { + return !!this.profileReportingInfo_ && + this.profileReportingInfo_.length > 0; + } + + + /** * @return Whether there are extension reporting info to show. */ private showExtensionReportingInfo_(): boolean {
diff --git a/chrome/browser/resources/password_manager/passkeys_browser_proxy.ts b/chrome/browser/resources/password_manager/passkeys_browser_proxy.ts index 7182975..e29b8faa 100644 --- a/chrome/browser/resources/password_manager/passkeys_browser_proxy.ts +++ b/chrome/browser/resources/password_manager/passkeys_browser_proxy.ts
@@ -24,7 +24,7 @@ } managePasskeys() { - return chrome.send('passkeysManagePasskeys'); + chrome.send('passkeysManagePasskeys'); } static getInstance(): PasskeysBrowserProxy {
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts index b242ae4..1d64193 100644 --- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts +++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_browser_proxy.ts
@@ -77,8 +77,7 @@ } restartCounters(isBasic: boolean, timePeriod: number) { - return chrome.send('restartClearBrowsingDataCounters', - [isBasic, timePeriod]); + chrome.send('restartClearBrowsingDataCounters', [isBasic, timePeriod]); } static getInstance(): ClearBrowsingDataBrowserProxy {
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.ts b/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.ts index 242b8b8..f8727834 100644 --- a/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.ts +++ b/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.ts
@@ -344,7 +344,7 @@ } close() { - return chrome.send('securityKeyPINClose'); + chrome.send('securityKeyPINClose'); } static getInstance(): SecurityKeysPinBrowserProxy { @@ -386,7 +386,7 @@ } close() { - return chrome.send('securityKeyCredentialManagementClose'); + chrome.send('securityKeyCredentialManagementClose'); } static getInstance(): SecurityKeysCredentialBrowserProxy { @@ -414,7 +414,7 @@ } close() { - return chrome.send('securityKeyResetClose'); + chrome.send('securityKeyResetClose'); } static getInstance(): SecurityKeysResetBrowserProxy { @@ -452,7 +452,7 @@ } cancelEnrollment() { - return chrome.send('securityKeyBioEnrollCancel'); + chrome.send('securityKeyBioEnrollCancel'); } deleteEnrollment(id: string) { @@ -464,7 +464,7 @@ } close() { - return chrome.send('securityKeyBioEnrollClose'); + chrome.send('securityKeyBioEnrollClose'); } static getInstance(): SecurityKeysBioEnrollProxy {
diff --git a/chrome/browser/resources/settings_shared/people_page/sync_browser_proxy.ts b/chrome/browser/resources/settings_shared/people_page/sync_browser_proxy.ts index ad312f8..2f41fb0 100644 --- a/chrome/browser/resources/settings_shared/people_page/sync_browser_proxy.ts +++ b/chrome/browser/resources/settings_shared/people_page/sync_browser_proxy.ts
@@ -331,15 +331,15 @@ // <if expr="chromeos_ash"> attemptUserExit() { - return chrome.send('AttemptUserExit'); + chrome.send('AttemptUserExit'); } turnOnSync() { - return chrome.send('TurnOnSync'); + chrome.send('TurnOnSync'); } turnOffSync() { - return chrome.send('TurnOffSync'); + chrome.send('TurnOffSync'); } // </if>
diff --git a/chrome/browser/resources/side_panel/history_clusters/BUILD.gn b/chrome/browser/resources/side_panel/history_clusters/BUILD.gn index 8dad0a79..2475ea6 100644 --- a/chrome/browser/resources/side_panel/history_clusters/BUILD.gn +++ b/chrome/browser/resources/side_panel/history_clusters/BUILD.gn
@@ -11,11 +11,15 @@ static_files = [ "history_clusters.html" ] - web_component_files = [ "app.ts" ] + non_web_component_files = [ + "app.ts", + "app.html.ts", + ] + css_files = [ "app.css" ] ts_deps = [ "../shared:build_ts", - "//third_party/polymer/v3_0:library", + "//third_party/lit/v3_0:build_ts", "//ui/webui/resources/cr_components/color_change_listener:build_ts", "//ui/webui/resources/cr_components/history_clusters:build_ts", "//ui/webui/resources/cr_elements:build_ts",
diff --git a/chrome/browser/resources/side_panel/history_clusters/app.css b/chrome/browser/resources/side_panel/history_clusters/app.css new file mode 100644 index 0000000..f07a1e4 --- /dev/null +++ b/chrome/browser/resources/side_panel/history_clusters/app.css
@@ -0,0 +1,28 @@ +/* Copyright 2024 The Chromium Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +/* #css_wrapper_metadata_start + * #type=style-lit + * #import=chrome://history-clusters-side-panel.top-chrome/shared/sp_shared_style_lit.css.js + * #scheme=relative + * #include=sp-shared-style-lit + * #css_wrapper_metadata_end */ + +:host { + display: flex; + flex-direction: column; + height: 100%; +} + +#searchbox { + margin: var(--sp-body-padding); + flex-shrink: 0; + width: auto; +} + +#historyClusters { + flex: 1; + margin-inline-start: var(--sp-body-padding); + padding-bottom: var(--sp-body-padding); +}
diff --git a/chrome/browser/resources/side_panel/history_clusters/app.html b/chrome/browser/resources/side_panel/history_clusters/app.html deleted file mode 100644 index ddf30c0..0000000 --- a/chrome/browser/resources/side_panel/history_clusters/app.html +++ /dev/null
@@ -1,31 +0,0 @@ -<style include="sp-shared-style"> - :host { - display: flex; - flex-direction: column; - height: 100%; - } - - #searchbox { - margin: var(--sp-body-padding); - flex-shrink: 0; - width: auto; - } - - #historyClusters { - flex: 1; - margin-inline-start: var(--sp-body-padding); - padding-bottom: var(--sp-body-padding); - } -</style> -<cr-toolbar-search-field id="searchbox" on-search-changed="onSearchChanged_" - label="$i18n{historyClustersSearchPrompt}" - clear-label="$i18n{clearSearch}" - on-contextmenu="onContextMenu_"> -</cr-toolbar-search-field> -<history-clusters id="historyClusters" - query="[[query]]" - path="journeys" - on-query-changed-by-user="onQueryChangedByUser_" - class="sp-scroller sp-scroller-bottom-of-page" - scroll-target="[[scrollTarget_]]"> -</history-clusters>
diff --git a/chrome/browser/resources/side_panel/history_clusters/app.html.ts b/chrome/browser/resources/side_panel/history_clusters/app.html.ts new file mode 100644 index 0000000..0ea22bd --- /dev/null +++ b/chrome/browser/resources/side_panel/history_clusters/app.html.ts
@@ -0,0 +1,25 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {html} from '//resources/lit/v3_0/lit.rollup.js'; + +import type {HistoryClustersAppElement} from './app.js'; + +export function getHtml(this: HistoryClustersAppElement) { + return html`<!--_html_template_start_--> +<cr-toolbar-search-field id="searchbox" + @search-changed="${this.onSearchChanged_}" + label="$i18n{historyClustersSearchPrompt}" + clear-label="$i18n{clearSearch}" + @contextmenu="${this.onContextMenu_}"> +</cr-toolbar-search-field> +<history-clusters id="historyClusters" + query="${this.query}" + path="journeys" + @query-changed-by-user="${this.onQueryChangedByUser_}" + class="sp-scroller sp-scroller-bottom-of-page" + .scrollTarget="${this.scrollTarget_}"> +</history-clusters> +<!--_html_template_end_-->`; +}
diff --git a/chrome/browser/resources/side_panel/history_clusters/app.ts b/chrome/browser/resources/side_panel/history_clusters/app.ts index f2f0b14..6efe1ed 100644 --- a/chrome/browser/resources/side_panel/history_clusters/app.ts +++ b/chrome/browser/resources/side_panel/history_clusters/app.ts
@@ -3,7 +3,6 @@ // found in the LICENSE file. import '../strings.m.js'; -import 'chrome://history-clusters-side-panel.top-chrome/shared/sp_shared_style.css.js'; import 'chrome://resources/cr_components/history_clusters/browser_proxy.js'; import 'chrome://resources/cr_components/history_clusters/clusters.js'; import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; @@ -11,9 +10,10 @@ import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js'; import {BrowserProxyImpl} from 'chrome://resources/cr_components/history_clusters/browser_proxy.js'; import type {CrToolbarSearchFieldElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; -import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js'; -import {getTemplate} from './app.html.js'; +import {getCss} from './app.css.js'; +import {getHtml} from './app.html.js'; export interface HistoryClustersAppElement { $: { @@ -22,26 +22,27 @@ }; } -export class HistoryClustersAppElement extends PolymerElement { +export class HistoryClustersAppElement extends CrLitElement { static get is() { return 'history-clusters-app'; } - static get template() { - return getTemplate(); + static override get styles() { + return getCss(); } - static get properties() { + override render() { + return getHtml.bind(this)(); + } + + static override get properties() { return { /** * The current query for which related clusters are requested and shown. */ - query: { - type: String, - value: '', - }, + query: {type: String}, - scrollContainer: HTMLElement, + scrollTarget_: {type: Object}, }; } @@ -54,14 +55,14 @@ // Properties //============================================================================ - query: string; - private scrollTarget_: HTMLElement; + query: string = ''; + protected scrollTarget_?: HTMLElement; //============================================================================ // Event Handlers //============================================================================ - private onContextMenu_(event: MouseEvent) { + protected onContextMenu_(event: MouseEvent) { BrowserProxyImpl.getInstance().handler.showContextMenuForSearchbox( this.query, {x: event.clientX, y: event.clientY}); } @@ -86,7 +87,7 @@ /** * Called when the value of the search field changes. */ - private onSearchChanged_(event: CustomEvent<string>) { + protected onSearchChanged_(event: CustomEvent<string>) { // Update the query based on the value of the search field, if necessary. this.query = event.detail; } @@ -94,7 +95,7 @@ /** * Called when the browser handler forces us to change our query. */ - private onQueryChangedByUser_(event: CustomEvent<string>) { + protected onQueryChangedByUser_(event: CustomEvent<string>) { // This will in turn fire `onSearchChanged_()`. if (this.$.searchbox) { this.$.searchbox.setValue(event.detail);
diff --git a/chrome/browser/resources/welcome/ntp_background/ntp_background_proxy.ts b/chrome/browser/resources/welcome/ntp_background/ntp_background_proxy.ts index 7a57cb2..a241f2b 100644 --- a/chrome/browser/resources/welcome/ntp_background/ntp_background_proxy.ts +++ b/chrome/browser/resources/welcome/ntp_background/ntp_background_proxy.ts
@@ -24,7 +24,7 @@ export class NtpBackgroundProxyImpl implements NtpBackgroundProxy { clearBackground() { - return chrome.send('clearBackground'); + chrome.send('clearBackground'); } getBackgrounds() {
diff --git a/chrome/browser/safe_browsing/android/safe_browsing_bridge.cc b/chrome/browser/safe_browsing/android/safe_browsing_bridge.cc index b02d42ad..788bbbd 100644 --- a/chrome/browser/safe_browsing/android/safe_browsing_bridge.cc +++ b/chrome/browser/safe_browsing/android/safe_browsing_bridge.cc
@@ -8,7 +8,6 @@ // NOTE: This target is transitively depended on by //chrome/browser and thus // can't depend on it. #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/safe_browsing/advanced_protection_status_manager.h" #include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" // nogncheck @@ -23,7 +22,7 @@ namespace { PrefService* GetPrefService(const base::android::JavaRef<jobject>& j_profile) { - return ProfileAndroid::FromProfileAndroid(j_profile)->GetPrefs(); + return Profile::FromJavaObject(j_profile)->GetPrefs(); } } // namespace @@ -86,7 +85,7 @@ static jboolean JNI_SafeBrowsingBridge_IsUnderAdvancedProtection( JNIEnv* env, const JavaParamRef<jobject>& j_profile) { - Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); + Profile* profile = Profile::FromJavaObject(j_profile); return profile && safe_browsing::AdvancedProtectionStatusManagerFactory::GetForProfile( profile)
diff --git a/chrome/browser/search_resumption/start_suggest_service_factory.cc b/chrome/browser/search_resumption/start_suggest_service_factory.cc index 01ca533b..859c1a1 100644 --- a/chrome/browser/search_resumption/start_suggest_service_factory.cc +++ b/chrome/browser/search_resumption/start_suggest_service_factory.cc
@@ -2,13 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <utility> - #include "start_suggest_service_factory.h" +#include <utility> + #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/common/webui_url_constants.h" #include "components/search/start_suggest_service.h"
diff --git a/chrome/browser/share/share_history.cc b/chrome/browser/share/share_history.cc index 282ad48e..83c2e43 100644 --- a/chrome/browser/share/share_history.cc +++ b/chrome/browser/share/share_history.cc
@@ -18,7 +18,7 @@ #if BUILDFLAG(IS_ANDROID) #include "base/android/jni_string.h" -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" // Must come after other includes, because FromJniType() uses Profile. #include "chrome/browser/share/jni_headers/ShareHistoryBridge_jni.h"
diff --git a/chrome/browser/shortcuts/OWNERS b/chrome/browser/shortcuts/OWNERS index fead5da..5eb3421b 100644 --- a/chrome/browser/shortcuts/OWNERS +++ b/chrome/browser/shortcuts/OWNERS
@@ -2,4 +2,4 @@ dmurph@chromium.org mek@chromium.org -per-file *_windows=davidbienvenu@chromium.org \ No newline at end of file +per-file *_win*=davidbienvenu@chromium.org \ No newline at end of file
diff --git a/chrome/browser/shortcuts/shortcut_creator_win.cc b/chrome/browser/shortcuts/shortcut_creator_win.cc index 01427d6..f479fe9 100644 --- a/chrome/browser/shortcuts/shortcut_creator_win.cc +++ b/chrome/browser/shortcuts/shortcut_creator_win.cc
@@ -87,8 +87,10 @@ bool res = CreateOrUpdateShortcutLink(shortcut_path, target_and_args_properties, base::win::ShortcutOperation::kCreateAlways); - std::move(complete).Run(res ? ShortcutCreatorResult::kSuccess - : ShortcutCreatorResult::kError); + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, + base::BindOnce(std::move(complete), res ? ShortcutCreatorResult::kSuccess + : ShortcutCreatorResult::kError)); } scoped_refptr<base::SequencedTaskRunner> GetShortcutsTaskRunner() {
diff --git a/chrome/browser/shortcuts/shortcut_creator_win_unittest.cc b/chrome/browser/shortcuts/shortcut_creator_win_unittest.cc index 95e39a6a..589c1a0 100644 --- a/chrome/browser/shortcuts/shortcut_creator_win_unittest.cc +++ b/chrome/browser/shortcuts/shortcut_creator_win_unittest.cc
@@ -16,6 +16,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_path_override.h" +#include "base/test/task_environment.h" #include "base/test/test_future.h" #include "base/test/test_shortcut_win.h" #include "base/win/scoped_com_initializer.h" @@ -68,6 +69,7 @@ base::ScopedTempDir default_profile_path_; base::ScopedPathOverride desktop_override_{base::DIR_USER_DESKTOP}; base::win::ScopedCOMInitializer com_initializer_; + base::test::SingleThreadTaskEnvironment task_environment_; }; void ShortcutCreatorWinTest::VerifyShortcut() const {
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.cc b/chrome/browser/signin/dice_web_signin_interceptor.cc index 0dc075e..3376a91d 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor.cc
@@ -48,11 +48,13 @@ #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h" #include "chrome/browser/ui/profiles/profile_colors_util.h" #include "chrome/common/channel_info.h" #include "chrome/common/pref_names.h" #include "chrome/common/themes/autogenerated_theme_util.h" +#include "components/feature_engagement/public/feature_constants.h" #include "components/password_manager/core/browser/password_manager.h" #include "components/password_manager/core/common/password_manager_ui.h" #include "components/policy/core/browser/signin/profile_separation_policies.h" @@ -1035,6 +1037,17 @@ return processed_result; } +void DiceWebSigninInterceptor:: + MaybeShowExplicitBrowserSigninPreferenceRememberedIPH( + const AccountInfo& account_info) { + Browser* browser = chrome::FindBrowserWithProfile(profile_); + user_education::FeaturePromoParams params( + feature_engagement::kIPHExplicitBrowserSigninPreferenceRememberedFeature, + account_info.gaia); + params.title_params = base::UTF8ToUTF16(account_info.given_name); + browser->window()->MaybeShowFeaturePromo(std::move(params)); +} + void DiceWebSigninInterceptor::OnChromeSigninChoice( const AccountInfo& account_info, SigninInterceptionResult result) { @@ -1043,7 +1056,7 @@ switch (processed_result) { case SigninInterceptionResult::kIgnored: - // Can happen if the browser isclosed while the bubble is still opened. + // Can happen if the browser is closed while the bubble is still opened. case SigninInterceptionResult::kNotDisplayed: // Can happen if the web contents is destroyed between the time the bubble // was requested to be displayed and actually being displayed. @@ -1067,6 +1080,7 @@ signin_metrics::LogSignInStarted(access_point); identity_manager_->GetPrimaryAccountMutator()->SetPrimaryAccount( account_info.account_id, signin::ConsentLevel::kSignin, access_point); + MaybeShowExplicitBrowserSigninPreferenceRememberedIPH(account_info); } // In all cases we want to close the bubble after the choice is taken.
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.h b/chrome/browser/signin/dice_web_signin_interceptor.h index b19e52ef..8a22434 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor.h +++ b/chrome/browser/signin/dice_web_signin_interceptor.h
@@ -235,6 +235,11 @@ const WebSigninInterceptor::Delegate::BubbleParameters& bubble_parameters, base::OnceCallback<void(SigninInterceptionResult)> callback); + // Attempts showing the In-Product-Help for remembering the explicit browser + // sign-in preference. + void MaybeShowExplicitBrowserSigninPreferenceRememberedIPH( + const AccountInfo& account_info); + // Ensure that we are observing changes in extended account info. Idempotent. void EnsureObservingExtendedAccountInfo();
diff --git a/chrome/browser/supervised_user/android/website_parent_approval.cc b/chrome/browser/supervised_user/android/website_parent_approval.cc index a90fc87..bfbf7cf 100644 --- a/chrome/browser/supervised_user/android/website_parent_approval.cc +++ b/chrome/browser/supervised_user/android/website_parent_approval.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/supervised_user/android/website_parent_approval.h" #include <jni.h> + #include <memory> #include "base/android/callback_android.h" @@ -15,7 +16,6 @@ #include "base/no_destructor.h" #include "chrome/browser/favicon/large_icon_service_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/supervised_user/android/favicon_fetcher.h" #include "chrome/browser/supervised_user/website_parent_approval_jni_headers/WebsiteParentApproval_jni.h" @@ -67,8 +67,7 @@ JNIEnv* env = base::android::AttachCurrentThread(); Java_WebsiteParentApproval_requestLocalApproval( env, window_android->GetJavaObject(), - url::GURLAndroid::FromNativeGURL(env, url), - ProfileAndroid::FromProfile(&profile)->GetJavaObject()); + url::GURLAndroid::FromNativeGURL(env, url), profile.GetJavaObject()); } void JNI_WebsiteParentApproval_OnCompletion(JNIEnv* env,
diff --git a/chrome/browser/tab_group_sync/feature_utils.cc b/chrome/browser/tab_group_sync/feature_utils.cc index 23351de..e5aa1a0 100644 --- a/chrome/browser/tab_group_sync/feature_utils.cc +++ b/chrome/browser/tab_group_sync/feature_utils.cc
@@ -11,7 +11,6 @@ #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/tab_group_sync/utils_jni_headers/TabGroupSyncFeatures_jni.h" #include "components/saved_tab_groups/features.h" #include "components/saved_tab_groups/pref_names.h"
diff --git a/chrome/browser/tab_resumption/visited_url_ranking_backend.cc b/chrome/browser/tab_resumption/visited_url_ranking_backend.cc index ae75979..25772902 100644 --- a/chrome/browser/tab_resumption/visited_url_ranking_backend.cc +++ b/chrome/browser/tab_resumption/visited_url_ranking_backend.cc
@@ -39,7 +39,11 @@ using visited_url_ranking::URLVisitAggregate; using visited_url_ranking::VisitedURLRankingService; +// FetchOptions::CreateDefaultFetchOptionsForTabResumption() specifies data +// sources that are currently unavailable. This function returns a simplified +// FetchOptions instance. FetchOptions CreateFetchOptionsForTabResumption(base::Time current_time) { + // TODO(crbug.com/337858147): Incorporate Fetcher::kHistory when ready. return FetchOptions( { {Fetcher::kSession, FetchOptions::kOriginSources}, @@ -85,14 +89,9 @@ return; } - PassResults(std::move(aggregates)); - - // TODO(crbug.com/337858147): Uncomment to use ranking, once implemented. - - // ranking_service_->RankVisitAggregates( - // config_, std::move(aggregates), - // base::BindOnce(&FetchAndRankFlow::OnRanked, - // base::RetainedRef(this))); + ranking_service_->RankURLVisitAggregates( + config_, std::move(aggregates), + base::BindOnce(&FetchAndRankFlow::OnRanked, base::RetainedRef(this))); } // Continuing after OnFetched()'s call to RankVisitAggregates(). @@ -115,19 +114,23 @@ if (aggregate.fetcher_data_map.empty()) { continue; } - const URLVisitAggregate::TabData& tab_data = - std::get<URLVisitAggregate::TabData>( - aggregate.fetcher_data_map.begin()->second); - Java_VisitedUrlRankingBackend_addSuggestionEntry( - env_, - base::android::ConvertUTF8ToJavaString( - env_, tab_data.last_active_tab.session_name.value_or("?")), - url::GURLAndroid::FromNativeGURL(env_, - tab_data.last_active_tab.visit.url), - base::android::ConvertUTF16ToJavaString( - env_, tab_data.last_active_tab.visit.title), - tab_data.last_active.InMillisecondsSinceUnixEpoch(), - tab_data.last_active_tab.id, j_suggestions_); + const URLVisitAggregate::TabData* tab_data = + std::get_if<URLVisitAggregate::TabData>( + &(aggregate.fetcher_data_map.begin()->second)); + if (tab_data) { + Java_VisitedUrlRankingBackend_addSuggestionEntry( + env_, + base::android::ConvertUTF8ToJavaString( + env_, tab_data->last_active_tab.session_name.value_or("?")), + url::GURLAndroid::FromNativeGURL( + env_, tab_data->last_active_tab.visit.url), + base::android::ConvertUTF16ToJavaString( + env_, tab_data->last_active_tab.visit.title), + tab_data->last_active.InMillisecondsSinceUnixEpoch(), + tab_data->last_active_tab.id, j_suggestions_); + } + + // TODO(crbug.com/337858147): Handle URLVisitAggregate::HistoryData case. } Java_VisitedUrlRankingBackend_onSuggestions(env_, j_suggestions_,
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelUtils.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelUtils.java index 54f6e54..34ad79d 100644 --- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelUtils.java +++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelUtils.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.tabmodel; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.chromium.base.Callback; import org.chromium.base.supplier.ObservableSupplier; @@ -14,6 +15,9 @@ import org.chromium.content_public.browser.WebContents; import org.chromium.ui.base.WindowAndroid; +import java.util.ArrayList; +import java.util.List; + /** * A set of convenience methods used for interacting with {@link TabList}s and {@link TabModel}s. */ @@ -23,7 +27,7 @@ /** * @param model The {@link TabModel} to act on. * @param index The index of the {@link Tab} to close. - * @return {@code true} if the {@link Tab} was found. + * @return {@code true} if the {@link Tab} was found. */ public static boolean closeTabByIndex(TabModel model, int index) { Tab tab = model.getTabAt(index); @@ -259,4 +263,15 @@ return selector.getTabModelFilterProvider().getTabModelFilter(tab.isIncognito()); } + + /** Converts a {@link TabList} to a {@link List<Tab>}. A null input returns an empty list. */ + public static @Nullable List<Tab> convertTabListToListOfTabs(@Nullable TabList tabList) { + ArrayList<Tab> list = new ArrayList<>(); + if (tabList == null) return list; + + for (int i = 0; i < tabList.getCount(); i++) { + list.add(tabList.getTabAt(i)); + } + return list; + } }
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java index d004cfed..30a6920 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java
@@ -66,7 +66,6 @@ import org.chromium.chrome.browser.touch_to_fill.common.BottomSheetFocusHelper; import org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodMediator.TouchToFillCreditCardOutcome; import org.chromium.components.autofill.AutofillFeatures; -import org.chromium.components.autofill.IbanRecordType; import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason; @@ -141,7 +140,6 @@ /* guid= */ "000000111111", /* label= */ "CH56 **** **** **** *800 9", /* nickname= */ "My brother's IBAN", - /* recordType= */ IbanRecordType.LOCAL_IBAN, /* value= */ "CH5604835012345678009"); private static final Iban LOCAL_IBAN_NO_NICKNAME = @@ -149,7 +147,6 @@ /* guid= */ "000000222222", /* label= */ "FR76 **** **** **** **** ***0 189", /* nickname= */ "", - /* recordType= */ IbanRecordType.LOCAL_IBAN, /* value= */ "FR7630006000011234567890189"); @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodRenderTest.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodRenderTest.java index e30423c2..1856744c 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodRenderTest.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodRenderTest.java
@@ -42,7 +42,6 @@ import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.util.ChromeRenderTestRule; -import org.chromium.components.autofill.IbanRecordType; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetTestSupport; import org.chromium.ui.test.util.RenderTestRule.Component; @@ -152,7 +151,6 @@ /* guid= */ "000000111111", /* label= */ "CH56 •••• •••• •••• •800 9", /* nickname= */ "My brother's IBAN", - /* recordType= */ IbanRecordType.LOCAL_IBAN, /* value= */ "CH5604835012345678009"); private static final Iban LOCAL_IBAN_NO_NICKNAME = @@ -160,7 +158,6 @@ /* guid= */ "000000222222", /* label= */ "FR76 •••• •••• •••• •••• •••0 189", /* nickname= */ "", - /* recordType= */ IbanRecordType.LOCAL_IBAN, /* value= */ "FR7630006000011234567890189"); private BottomSheetController mBottomSheetController;
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java index 1479bb30..1da7161 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java
@@ -57,7 +57,6 @@ import org.chromium.chrome.browser.touch_to_fill.common.FillableItemCollectionInfo; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; -import org.chromium.components.autofill.IbanRecordType; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState; import org.chromium.components.browser_ui.bottomsheet.BottomSheetTestSupport; @@ -123,7 +122,6 @@ /* guid= */ "000000111111", /* label= */ "CH56 **** **** **** *800 9", /* nickname= */ "My brother's IBAN", - /* recordType= */ IbanRecordType.LOCAL_IBAN, /* value= */ "CH5604835012345678009"); @Rule
diff --git a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc index 28fff45..c85d9cc3 100644 --- a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc +++ b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_impl.cc
@@ -7,7 +7,6 @@ #include "base/android/scoped_java_ref.h" #include "chrome/browser/autofill/android/personal_data_manager_android.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/touch_to_fill/autofill/android/internal/jni/TouchToFillPaymentMethodViewBridge_jni.h" #include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_controller.h" #include "components/autofill/core/common/autofill_features.h" @@ -46,8 +45,7 @@ java_object_.Reset(Java_TouchToFillPaymentMethodViewBridge_create( env, java_controller, - ProfileAndroid::FromProfile( - Profile::FromBrowserContext(web_contents_->GetBrowserContext())) + Profile::FromBrowserContext(web_contents_->GetBrowserContext()) ->GetJavaObject(), web_contents_->GetTopLevelNativeWindow()->GetJavaObject())); if (!java_object_)
diff --git a/chrome/browser/touch_to_fill/password_manager/android/touch_to_fill_view_impl.cc b/chrome/browser/touch_to_fill/password_manager/android/touch_to_fill_view_impl.cc index f613207..9403695 100644 --- a/chrome/browser/touch_to_fill/password_manager/android/touch_to_fill_view_impl.cc +++ b/chrome/browser/touch_to_fill/password_manager/android/touch_to_fill_view_impl.cc
@@ -14,7 +14,6 @@ #include "base/android/jni_string.h" #include "base/time/time.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/touch_to_fill/password_manager/android/internal/jni/TouchToFillBridge_jni.h" #include "chrome/browser/touch_to_fill/password_manager/android/jni_headers/Credential_jni.h" #include "chrome/browser/touch_to_fill/password_manager/android/jni_headers/WebauthnCredential_jni.h" @@ -200,7 +199,7 @@ } java_object_internal_ = Java_TouchToFillBridge_create( AttachCurrentThread(), reinterpret_cast<intptr_t>(this), - ProfileAndroid::FromProfile(controller_->GetProfile())->GetJavaObject(), + controller_->GetProfile()->GetJavaObject(), controller_->GetNativeView()->GetWindowAndroid()->GetJavaObject()); return !!java_object_internal_; }
diff --git a/chrome/browser/translate/android/translate_bridge.cc b/chrome/browser/translate/android/translate_bridge.cc index 037cb77..f2f467a 100644 --- a/chrome/browser/translate/android/translate_bridge.cc +++ b/chrome/browser/translate/android/translate_bridge.cc
@@ -14,7 +14,6 @@ #include "chrome/browser/language/android/jni_headers/TranslationObserver_jni.h" #include "chrome/browser/language/language_model_manager_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/translate/chrome_translate_client.h" #include "chrome/browser/translate/translate_service.h" #include "components/language/core/browser/language_model.h" @@ -42,7 +41,7 @@ namespace { PrefService* GetPrefService(const base::android::JavaRef<jobject>& j_profile) { - return ProfileAndroid::FromProfileAndroid(j_profile)->GetPrefs(); + return Profile::FromJavaObject(j_profile)->GetPrefs(); } class TranslationObserver @@ -147,7 +146,7 @@ static base::android::ScopedJavaLocalRef<jstring> JNI_TranslateBridge_GetTargetLanguage(JNIEnv* env, const JavaParamRef<jobject>& j_profile) { - Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); + Profile* profile = Profile::FromJavaObject(j_profile); language::LanguageModel* language_model = LanguageModelManagerFactory::GetForBrowserContext(profile) ->GetPrimaryModel();
diff --git a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc index 5684f9c5..2d0b095d 100644 --- a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc +++ b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
@@ -7,7 +7,6 @@ #include "chrome/android/chrome_jni_headers/CardUnmaskBridge_jni.h" #include "chrome/browser/android/resource_mapper.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/ui/autofill/payments/create_card_unmask_prompt_view.h" #include "components/autofill/core/browser/ui/autofill_resource_utils.h" #include "components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h" @@ -168,9 +167,7 @@ return java_object_internal_ = Java_CardUnmaskBridge_create( env, reinterpret_cast<intptr_t>(this), - ProfileAndroid::FromProfile( - Profile::FromBrowserContext( - web_contents_->GetBrowserContext())) + Profile::FromBrowserContext(web_contents_->GetBrowserContext()) ->GetJavaObject(), dialog_title, instructions, ResourceMapper::MapToJavaDrawableId(
diff --git a/chrome/browser/ui/android/autofill/save_update_address_profile_prompt_view_android.cc b/chrome/browser/ui/android/autofill/save_update_address_profile_prompt_view_android.cc index c7d4154..7b95c9a3 100644 --- a/chrome/browser/ui/android/autofill/save_update_address_profile_prompt_view_android.cc +++ b/chrome/browser/ui/android/autofill/save_update_address_profile_prompt_view_android.cc
@@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/ui/android/autofill/save_update_address_profile_prompt_view_android.h" + #include <memory> #include <utility> -#include "chrome/browser/ui/android/autofill/save_update_address_profile_prompt_view_android.h" - #include "base/android/jni_string.h" #include "chrome/android/chrome_jni_headers/SaveUpdateAddressProfilePrompt_jni.h" #include "chrome/browser/autofill/android/personal_data_manager_android.h" #include "chrome/browser/autofill/android/save_update_address_profile_prompt_controller.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "content/public/browser/web_contents.h" @@ -56,10 +56,6 @@ Profile* browser_profile = Profile::FromBrowserContext(web_contents_->GetBrowserContext()); - ProfileAndroid* browser_profile_android = - ProfileAndroid::FromProfile(browser_profile); - if (!browser_profile_android) - return false; JNIEnv* env = base::android::AttachCurrentThread(); base::android::ScopedJavaLocalRef<jobject> java_autofill_profile = @@ -67,8 +63,8 @@ g_browser_process->GetApplicationLocale()); java_object_.Reset(Java_SaveUpdateAddressProfilePrompt_create( env, web_contents_->GetTopLevelNativeWindow()->GetJavaObject(), - java_controller, browser_profile_android->GetJavaObject(), - java_autofill_profile, static_cast<jboolean>(is_update), + java_controller, browser_profile->GetJavaObject(), java_autofill_profile, + static_cast<jboolean>(is_update), static_cast<jboolean>(is_migration_to_account))); if (!java_object_) return false;
diff --git a/chrome/browser/ui/android/device_dialog/chrome_bluetooth_chooser_android_delegate.cc b/chrome/browser/ui/android/device_dialog/chrome_bluetooth_chooser_android_delegate.cc index 1e97cbc..8cb5479 100644 --- a/chrome/browser/ui/android/device_dialog/chrome_bluetooth_chooser_android_delegate.cc +++ b/chrome/browser/ui/android/device_dialog/chrome_bluetooth_chooser_android_delegate.cc
@@ -7,14 +7,13 @@ #include "base/android/jni_android.h" #include "chrome/android/chrome_jni_headers/ChromeBluetoothChooserAndroidDelegate_jni.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/ssl/security_state_tab_helper.h" ChromeBluetoothChooserAndroidDelegate::ChromeBluetoothChooserAndroidDelegate( Profile* profile) { JNIEnv* env = base::android::AttachCurrentThread(); java_delegate_.Reset(Java_ChromeBluetoothChooserAndroidDelegate_Constructor( - env, ProfileAndroid::FromProfile(profile)->GetJavaObject())); + env, profile->GetJavaObject())); } ChromeBluetoothChooserAndroidDelegate::
diff --git a/chrome/browser/ui/android/device_dialog/chrome_bluetooth_scanning_prompt_android_delegate.cc b/chrome/browser/ui/android/device_dialog/chrome_bluetooth_scanning_prompt_android_delegate.cc index 7065235..f9a6eb6 100644 --- a/chrome/browser/ui/android/device_dialog/chrome_bluetooth_scanning_prompt_android_delegate.cc +++ b/chrome/browser/ui/android/device_dialog/chrome_bluetooth_scanning_prompt_android_delegate.cc
@@ -7,7 +7,6 @@ #include "base/android/jni_android.h" #include "chrome/android/chrome_jni_headers/ChromeBluetoothScanningPromptAndroidDelegate_jni.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/ssl/security_state_tab_helper.h" ChromeBluetoothScanningPromptAndroidDelegate:: @@ -15,7 +14,7 @@ JNIEnv* env = base::android::AttachCurrentThread(); java_delegate_.Reset( Java_ChromeBluetoothScanningPromptAndroidDelegate_Constructor( - env, ProfileAndroid::FromProfile(profile)->GetJavaObject())); + env, profile->GetJavaObject())); } ChromeBluetoothScanningPromptAndroidDelegate::
diff --git a/chrome/browser/ui/android/device_dialog/usb_chooser_dialog_android.cc b/chrome/browser/ui/android/device_dialog/usb_chooser_dialog_android.cc index 386cf31..2a1446c1 100644 --- a/chrome/browser/ui/android/device_dialog/usb_chooser_dialog_android.cc +++ b/chrome/browser/ui/android/device_dialog/usb_chooser_dialog_android.cc
@@ -15,7 +15,6 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/android/chrome_jni_headers/UsbChooserDialog_jni.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/ssl/security_state_tab_helper.h" #include "chrome/common/url_constants.h" #include "components/permissions/permission_util.h" @@ -89,7 +88,7 @@ DCHECK(profile); base::android::ScopedJavaLocalRef<jobject> j_profile_android = - ProfileAndroid::FromProfile(profile)->GetJavaObject(); + profile->GetJavaObject(); DCHECK(!j_profile_android.is_null()); auto dialog = std::make_unique<UsbChooserDialogAndroid>(std::move(controller),
diff --git a/chrome/browser/ui/android/hats/survey_client_android.cc b/chrome/browser/ui/android/hats/survey_client_android.cc index 52b9c4c..8e8c1c41 100644 --- a/chrome/browser/ui/android/hats/survey_client_android.cc +++ b/chrome/browser/ui/android/hats/survey_client_android.cc
@@ -12,7 +12,6 @@ #include "base/android/scoped_java_ref.h" #include "base/ranges/algorithm.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/ui/android/hats/internal/jni_headers/SurveyClientBridge_jni.h" #include "chrome/browser/ui/android/hats/survey_config_android.h" #include "ui/android/window_android.h" @@ -38,8 +37,7 @@ : std::string_view()); jobj_ = Java_SurveyClientBridge_create( env, reinterpret_cast<int64_t>(this), java_trigger, - ui_delegate->GetJavaObject(env), - ProfileAndroid::FromProfile(profile)->GetJavaObject(), + ui_delegate->GetJavaObject(env), profile->GetJavaObject(), java_supplied_trigger_id); }
diff --git a/chrome/browser/ui/android/page_insights/DEPS b/chrome/browser/ui/android/page_insights/DEPS index c211777..152a5629 100644 --- a/chrome/browser/ui/android/page_insights/DEPS +++ b/chrome/browser/ui/android/page_insights/DEPS
@@ -1,7 +1,7 @@ include_rules = [ "+chrome/browser/browser_controls/android", "+chrome/browser/history/web_history_service_factory.h", - "+chrome/browser/profiles/profile_android.h", + "+chrome/browser/profiles/profile.h", "+chrome/browser/tab", "+chrome/browser/tabmodel", "+components/browser_ui/bottomsheet/android",
diff --git a/chrome/browser/ui/android/passwords/all_passwords_bottom_sheet_view_impl.cc b/chrome/browser/ui/android/passwords/all_passwords_bottom_sheet_view_impl.cc index f079e47..e029acee 100644 --- a/chrome/browser/ui/android/passwords/all_passwords_bottom_sheet_view_impl.cc +++ b/chrome/browser/ui/android/passwords/all_passwords_bottom_sheet_view_impl.cc
@@ -9,7 +9,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/android/features/keyboard_accessory/internal/jni/AllPasswordsBottomSheetBridge_jni.h" #include "chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.h" -#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/passwords/ui_utils.h" #include "chrome/grit/generated_resources.h" #include "components/affiliations/core/browser/affiliation_utils.h" @@ -101,8 +101,7 @@ } return java_object_internal_ = Java_AllPasswordsBottomSheetBridge_create( AttachCurrentThread(), reinterpret_cast<intptr_t>(this), - ProfileAndroid::FromProfile(controller_->GetProfile()) - ->GetJavaObject(), + controller_->GetProfile()->GetJavaObject(), controller_->GetNativeView()->GetWindowAndroid()->GetJavaObject(), controller_->GetFrameUrl().spec()); }
diff --git a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc index f40e0156..ce26dff 100644 --- a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc +++ b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.cc
@@ -14,7 +14,6 @@ #include "chrome/browser/android/tab_android.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/tab_contents/tab_util.h" #include "chrome/browser/ui/android/tab_model/tab_model_list.h" #include "chrome/browser/ui/android/tab_model/tab_model_observer_jni_bridge.h" @@ -85,8 +84,7 @@ Java_TabModelJniBridge_createTabWithWebContents( env, java_object_.get(env), (parent ? parent->GetJavaObject() : nullptr), - ProfileAndroid::FromProfile(profile)->GetJavaObject(), - web_contents->GetJavaWebContents()); + profile->GetJavaObject(), web_contents->GetJavaWebContents()); } void TabModelJniBridge::HandlePopupNavigation(TabAndroid* parent,
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java index 3ae6d7e..8473914 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
@@ -492,12 +492,12 @@ } /** - * Update the background color of the toolbar based on whether it is in the Grid tab switcher - * or in the Start surface with either incognito mode or non-incognito mode. + * Update the background color of the toolbar based on whether it is in the Grid tab switcher or + * in the Start surface with either incognito mode or non-incognito mode. */ private void updateBackgroundColor() { @ColorInt int backgroundColor; - if (mIsSurfacePolished && isOnHomepage() && !mIsIncognito) { + if (isOnHomepage() && !mIsIncognito) { backgroundColor = ChromeColors.getSurfaceColor( mContext,
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java index 217a16b..f38ca1a 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java
@@ -373,9 +373,9 @@ // clears out, #onTokenUpdated will route into this method again. if (mDeferTransitionTokenHolder.hasTokens()) return; - // Invalid width will be ignored. This can happen when the mControlContainer is created - // hidden after theme changes. See crbug.com/1511599. - if (tabStripWidth <= 0) return; + // Invalid width / height will be ignored. This can happen when the mControlContainer is + // created hidden after theme changes. See crbug.com/1511599. + if (tabStripWidth <= 0 || controlContainerView().getHeight() == 0) return; boolean showTabStrip; if (ToolbarFeatures.isTabStripWindowLayoutOptimizationEnabled(/* isTablet= */ true)) {
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinatorUnitTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinatorUnitTest.java index 84a6b07..fd6b761 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinatorUnitTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinatorUnitTest.java
@@ -280,6 +280,19 @@ } @Test + public void hideTabStripBeforeLayout() { + // Simulate the control container hasn't been measured yet. + doReturn(0).when(mSpyControlContainer).getWidth(); + doReturn(0).when(mSpyControlContainer).getHeight(); + + setDeviceWidthDp(NARROW_WINDOW_WIDTH); + Assert.assertEquals( + "Height request should be ignored if control container hasn't been measured.", + NOTHING_OBSERVED, + mObserver.heightRequested); + } + + @Test @Config(qualifiers = "w320dp") public void showTabStrip() { settleTransitionDuringInitForNarrowWindow(); @@ -463,6 +476,22 @@ } @Test + @Config(qualifiers = "w320dp") + public void showTabStripBeforeLayout() { + settleTransitionDuringInitForNarrowWindow(); + + // Simulate the control container hasn't been measured yet. + doReturn(0).when(mSpyControlContainer).getWidth(); + doReturn(0).when(mSpyControlContainer).getHeight(); + + setDeviceWidthDp(600); + Assert.assertEquals( + "Height request should be ignored if control container hasn't been measured.", + NOTHING_OBSERVED, + mObserver.heightRequested); + } + + @Test public void configurationChangedDuringDelayedTask() { setConfigurationWithNewWidth(NARROW_WINDOW_WIDTH); simulateLayoutChange(NARROW_WINDOW_WIDTH); @@ -639,6 +668,28 @@ } @Test + public void useDesktopWindowStateProvider_WithouControlContainerLayout() { + ToolbarFeatures.setIsTabStripLayoutOptimizationEnabledForTesting(true); + // Simulate a rect update that has a smaller width. + int newHeight = TEST_TAB_STRIP_HEIGHT + 10; + Rect appHeaderRect = new Rect(0, 0, NARROW_WINDOW_WIDTH, newHeight); + mAppHeaderState = new AppHeaderState(appHeaderRect, appHeaderRect, true); + + // Set the height as if the first measure pass hasn't happened yet. + doReturn(0).when(mSpyControlContainer).getHeight(); + doReturn(0).when(mSpyControlContainer).getWidth(); + + // Create the transition coordinator again with initial value of AppHeaderState. + setUpTabStripTransitionCoordinator(); + ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); + + Assert.assertEquals( + "Height request should be ignored if control container hasn't been measured.", + NOTHING_OBSERVED, + mObserver.heightRequested); + } + + @Test public void recordHistogramWindowResize_LayoutChangeInDesktopWindow() { // Simulate desktop windowing mode. mAppHeaderState = new AppHeaderState(new Rect(), new Rect(), /* isInDesktopWindow= */ true); @@ -846,6 +897,10 @@ doAnswer(args -> context.getResources().getDisplayMetrics().widthPixels) .when(controlContainer) .getWidth(); + // Set a test height for the control container as if it's already being measured. + doReturn(TEST_TOOLBAR_HEIGHT + TEST_TAB_STRIP_HEIGHT) + .when(controlContainer) + .getHeight(); doAnswer( args -> { controlContainer.onLayoutChangeListener = args.getArgument(0);
diff --git a/chrome/browser/ui/bookmarks/bookmark_utils.cc b/chrome/browser/ui/bookmarks/bookmark_utils.cc index 5a6446a..e7858be 100644 --- a/chrome/browser/ui/bookmarks/bookmark_utils.cc +++ b/chrome/browser/ui/bookmarks/bookmark_utils.cc
@@ -292,17 +292,9 @@ const gfx::VectorIcon* id; gfx::ImageSkia folder; if (icon_type == BookmarkFolderIconType::kNormal) { - id = features::IsChromeRefresh2023() - ? &vector_icons::kFolderChromeRefreshIcon - : (ui::TouchUiController::Get()->touch_ui() - ? &vector_icons::kFolderTouchIcon - : &vector_icons::kFolderIcon); + id = &vector_icons::kFolderChromeRefreshIcon; } else { - id = features::IsChromeRefresh2023() - ? &vector_icons::kFolderManagedRefreshIcon - : (ui::TouchUiController::Get()->touch_ui() - ? &vector_icons::kFolderManagedTouchIcon - : &vector_icons::kFolderManagedIcon); + id = &vector_icons::kFolderManagedRefreshIcon; } const ui::ThemedVectorIcon icon = absl::holds_alternative<SkColor>(color) @@ -326,35 +318,8 @@ absl::variant<ui::ColorId, SkColor> color, const ui::ColorProvider* color_provider) { gfx::ImageSkia folder; - if (features::IsChromeRefresh2023()) { - folder = GetBookmarkFolderImageFromVectorIcon(icon_type, color, - color_provider); - } else { -#if BUILDFLAG(IS_WIN) - // TODO(bsep): vectorize the Windows versions: crbug.com/564112 - folder = *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( - default_id); -#elif BUILDFLAG(IS_MAC) - SkColor sk_color; - if (absl::holds_alternative<SkColor>(color)) { - sk_color = absl::get<SkColor>(color); - } else { - DCHECK(color_provider); - sk_color = color_provider->GetColor(absl::get<ui::ColorId>(color)); - } - const int white_id = (icon_type == BookmarkFolderIconType::kNormal) - ? IDR_FOLDER_CLOSED_WHITE - : IDR_BOOKMARK_BAR_FOLDER_MANAGED_WHITE; - const int resource_id = - color_utils::IsDark(sk_color) ? default_id : white_id; - folder = *ui::ResourceBundle::GetSharedInstance() - .GetNativeImageNamed(resource_id) - .ToImageSkia(); -#else - folder = GetBookmarkFolderImageFromVectorIcon(icon_type, color, - color_provider); -#endif - } + folder = + GetBookmarkFolderImageFromVectorIcon(icon_type, color, color_provider); return gfx::ImageSkia(std::make_unique<RTLFlipSource>(folder), folder.size()); };
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc index 3cbc922e..66b78ef 100644 --- a/chrome/browser/ui/browser_commands.cc +++ b/chrome/browser/ui/browser_commands.cc
@@ -78,6 +78,7 @@ #include "chrome/browser/ui/find_bar/find_bar_controller.h" #include "chrome/browser/ui/intent_picker_tab_helper.h" #include "chrome/browser/ui/lens/lens_overlay_controller.h" +#include "chrome/browser/ui/lens/lens_overlay_invocation_source.h" #include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h" #include "chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller.h" @@ -2233,7 +2234,7 @@ LensOverlayController* const controller = LensOverlayController::GetController(web_contents); CHECK(controller); - controller->ShowUI(LensOverlayController::InvocationSource::kAppMenu); + controller->ShowUI(lens::LensOverlayInvocationSource::kAppMenu); browser->window()->NotifyPromoFeatureUsed(lens::features::kLensOverlay); }
diff --git a/chrome/browser/ui/chromeos/magic_boost/BUILD.gn b/chrome/browser/ui/chromeos/magic_boost/BUILD.gn index d41c7e5..96b9957 100644 --- a/chrome/browser/ui/chromeos/magic_boost/BUILD.gn +++ b/chrome/browser/ui/chromeos/magic_boost/BUILD.gn
@@ -24,3 +24,18 @@ "//ui/views", ] } + +source_set("test_support") { + testonly = true + + sources = [ + "test/mock_magic_boost_controller.cc", + "test/mock_magic_boost_controller.h", + ] + + deps = [ + ":magic_boost", + "//base", + "//testing/gmock", + ] +}
diff --git a/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.cc b/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.cc index 963a8ff..112022cb 100644 --- a/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.cc +++ b/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.cc
@@ -10,8 +10,17 @@ namespace chromeos { +namespace { + +MagicBoostController* g_magic_boost_controller_for_testing = nullptr; + +} // namespace + // static MagicBoostController* MagicBoostController::Get() { + if (g_magic_boost_controller_for_testing) { + return g_magic_boost_controller_for_testing; + } static base::NoDestructor<MagicBoostController> instance; return instance.get(); } @@ -28,4 +37,27 @@ disclaimer_widget_->Show(); } +bool MagicBoostController::ShouldQuickAnswersAndMahiShowOptIn() { + // TODO(b/339043693): Implement this function. + return false; +} + +void MagicBoostController::SetAllFeaturesState(bool enabled) { + SetQuickAnswersAndMahiFeaturesState(enabled); + SetOrcaFeatureState(enabled); +} + +void MagicBoostController::SetQuickAnswersAndMahiFeaturesState(bool enabled) { + // TODO(b/339043693): Implement this function. +} + +ScopedMagicBoostControllerForTesting::ScopedMagicBoostControllerForTesting( + MagicBoostController* controller_for_testing) { + g_magic_boost_controller_for_testing = controller_for_testing; +} + +ScopedMagicBoostControllerForTesting::~ScopedMagicBoostControllerForTesting() { + g_magic_boost_controller_for_testing = nullptr; +} + } // namespace chromeos
diff --git a/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h b/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h index 075b226..eb173fd 100644 --- a/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h +++ b/chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_UI_CHROMEOS_MAGIC_BOOST_MAGIC_BOOST_CONTROLLER_H_ #define CHROME_BROWSER_UI_CHROMEOS_MAGIC_BOOST_MAGIC_BOOST_CONTROLLER_H_ +#include "base/no_destructor.h" #include "ui/views/widget/unique_widget_ptr.h" namespace views { @@ -14,6 +15,7 @@ namespace chromeos { // The controller that manages the lifetime of opt-in and disclaimer widgets. +// Some functions in this controller are virtual for testing. class MagicBoostController { public: MagicBoostController(const MagicBoostController&) = delete; @@ -22,7 +24,10 @@ static MagicBoostController* Get(); // Shows Magic Boost opt-in widget. - void ShowOptInUi() {} + virtual void ShowOptInUi() {} + + // Closes Magic Boost opt-in widget. + virtual void CloseOptInUi() {} // Shows Magic Boost disclaimer widget. void ShowDisclaimerUi(); @@ -32,6 +37,22 @@ return disclaimer_widget_.get(); } + // Closes Magic Boost disclaimer widget. + void CloseDisclaimerUi() {} + + // Whether the Quick Answers and Mahi features should show the opt in UI. + virtual bool ShouldQuickAnswersAndMahiShowOptIn(); + + // Enables or disables all the features (including Quick Answers, Orca, and + // Mahi). + void SetAllFeaturesState(bool enabled); + + // Enables or disables Quick Answers and Mahi. + void SetQuickAnswersAndMahiFeaturesState(bool enabled); + + // Enables or disables Orca. + void SetOrcaFeatureState(bool enabled) {} + protected: friend class base::NoDestructor<MagicBoostController>; @@ -42,6 +63,15 @@ views::UniqueWidgetPtr disclaimer_widget_; }; +// Helper class to automatically set and reset the `MagicBoostController` global +// instance for testing. +class ScopedMagicBoostControllerForTesting { + public: + explicit ScopedMagicBoostControllerForTesting( + MagicBoostController* controller_for_testing); + ~ScopedMagicBoostControllerForTesting(); +}; + } // namespace chromeos #endif // CHROME_BROWSER_UI_CHROMEOS_MAGIC_BOOST_MAGIC_BOOST_CONTROLLER_H_
diff --git a/chrome/browser/ui/chromeos/magic_boost/test/mock_magic_boost_controller.cc b/chrome/browser/ui/chromeos/magic_boost/test/mock_magic_boost_controller.cc new file mode 100644 index 0000000..56a31081 --- /dev/null +++ b/chrome/browser/ui/chromeos/magic_boost/test/mock_magic_boost_controller.cc
@@ -0,0 +1,13 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/chromeos/magic_boost/test/mock_magic_boost_controller.h" + +namespace chromeos { + +MockMagicBoostController::MockMagicBoostController() = default; + +MockMagicBoostController::~MockMagicBoostController() = default; + +} // namespace chromeos
diff --git a/chrome/browser/ui/chromeos/magic_boost/test/mock_magic_boost_controller.h b/chrome/browser/ui/chromeos/magic_boost/test/mock_magic_boost_controller.h new file mode 100644 index 0000000..2ed47df --- /dev/null +++ b/chrome/browser/ui/chromeos/magic_boost/test/mock_magic_boost_controller.h
@@ -0,0 +1,29 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_CHROMEOS_MAGIC_BOOST_TEST_MOCK_MAGIC_BOOST_CONTROLLER_H_ +#define CHROME_BROWSER_UI_CHROMEOS_MAGIC_BOOST_TEST_MOCK_MAGIC_BOOST_CONTROLLER_H_ + +#include "chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromeos { + +// A mock class for testing. +class MockMagicBoostController : public MagicBoostController { + public: + MockMagicBoostController(); + MockMagicBoostController(const MockMagicBoostController&) = delete; + MockMagicBoostController& operator=(const MockMagicBoostController&) = delete; + ~MockMagicBoostController(); + + // chromeos::MahiManager: + MOCK_METHOD(void, ShowOptInUi, (), (override)); + MOCK_METHOD(void, CloseOptInUi, (), (override)); + MOCK_METHOD(bool, ShouldQuickAnswersAndMahiShowOptIn, (), (override)); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_UI_CHROMEOS_MAGIC_BOOST_TEST_MOCK_MAGIC_BOOST_CONTROLLER_H_
diff --git a/chrome/browser/ui/commerce/product_specifications_entry_point_controller_browsertest.cc b/chrome/browser/ui/commerce/product_specifications_entry_point_controller_browsertest.cc index e88aee1e..a6c5a27e5 100644 --- a/chrome/browser/ui/commerce/product_specifications_entry_point_controller_browsertest.cc +++ b/chrome/browser/ui/commerce/product_specifications_entry_point_controller_browsertest.cc
@@ -128,8 +128,15 @@ ASSERT_TRUE(controller_->entry_point_info_for_testing().has_value()); } +// TODO(b/341091285): Flaky on Win. +#if BUILDFLAG(IS_WIN) +#define MAYBE_TriggerEntryPointWithNavigation \ + DISABLED_TriggerEntryPointWithNavigation +#else +#define MAYBE_TriggerEntryPointWithNavigation TriggerEntryPointWithNavigation +#endif IN_PROC_BROWSER_TEST_F(ProductSpecificationsEntryPointControllerBrowserTest, - TriggerEntryPointWithNavigation) { + MAYBE_TriggerEntryPointWithNavigation) { // Mock EntryPointInfo returned by ShoppingService. std::set<GURL> urls = {GURL(kTestUrl2), GURL(kTestUrl3), GURL(kTestUrl4)}; auto info = std::make_optional<commerce::EntryPointInfo>(kTitle, urls);
diff --git a/chrome/browser/ui/lens/BUILD.gn b/chrome/browser/ui/lens/BUILD.gn index 2a7edad..4b2f1db 100644 --- a/chrome/browser/ui/lens/BUILD.gn +++ b/chrome/browser/ui/lens/BUILD.gn
@@ -7,8 +7,10 @@ static_library("lens") { sources = [ + "lens_overlay_dismissal_source.h", "lens_overlay_image_helper.cc", "lens_overlay_image_helper.h", + "lens_overlay_invocation_source.h", "lens_overlay_permission_utils.cc", "lens_overlay_permission_utils.h", "lens_overlay_proto_converter.cc",
diff --git a/chrome/browser/ui/lens/lens_overlay_controller.cc b/chrome/browser/ui/lens/lens_overlay_controller.cc index 0ea550f..11c1ab2 100644 --- a/chrome/browser/ui/lens/lens_overlay_controller.cc +++ b/chrome/browser/ui/lens/lens_overlay_controller.cc
@@ -248,13 +248,14 @@ } void LensOverlayController::ShowUIWithPendingRegion( - InvocationSource invocation_source, + lens::LensOverlayInvocationSource invocation_source, lens::mojom::CenterRotatedBoxPtr region) { pending_region_ = std::move(region); ShowUI(invocation_source); } -void LensOverlayController::ShowUI(InvocationSource invocation_source) { +void LensOverlayController::ShowUI( + lens::LensOverlayInvocationSource invocation_source) { // If UI is already showing or in the process of showing, do nothing. if (state_ != State::kOff) { return; @@ -306,7 +307,7 @@ weak_factory_.GetWeakPtr()), base::BindRepeating(&LensOverlayController::HandleThumbnailCreated, weak_factory_.GetWeakPtr()), - variations_client_, identity_manager_); + variations_client_, identity_manager_, invocation_source); side_panel_coordinator_ = SidePanelUtil::GetSidePanelCoordinatorForBrowser(tab_browser); @@ -328,7 +329,8 @@ base::UmaHistogramEnumeration("Lens.Overlay.Invoked", invocation_source); } -void LensOverlayController::CloseUIAsync(DismissalSource dismissal_source) { +void LensOverlayController::CloseUIAsync( + lens::LensOverlayDismissalSource dismissal_source) { if (state_ == State::kOff || state_ == State::kClosing) { return; } @@ -528,7 +530,8 @@ auto loaded_search_query = initialization_data_->currently_loaded_search_query_; if (loaded_search_query && - loaded_search_query->search_query_url_ == search_url) { + lens::RemoveUrlViewportParams(loaded_search_query->search_query_url_) == + lens::RemoveUrlViewportParams(search_url)) { return; } @@ -600,7 +603,7 @@ last_dismissal_source_.reset(); return; } - CloseUIAsync(DismissalSource::kSidePanelCloseButton); + CloseUIAsync(lens::LensOverlayDismissalSource::kSidePanelCloseButton); } void LensOverlayController::IssueTextSelectionRequestForTesting( @@ -635,12 +638,13 @@ lens::LensOverlayInteractionResponseCallback interaction_data_callback, lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback, variations::VariationsClient* variations_client, - signin::IdentityManager* identity_manager) { + signin::IdentityManager* identity_manager, + lens::LensOverlayInvocationSource invocation_source) { return std::make_unique<lens::LensOverlayQueryController>( std::move(full_image_callback), std::move(url_callback), std::move(interaction_data_callback), std::move(thumbnail_created_callback), variations_client, - identity_manager); + identity_manager, invocation_source); } LensOverlayController::OverlayInitializationData::OverlayInitializationData( @@ -688,7 +692,8 @@ // content::WebContentsObserver void PrimaryPageChanged(content::Page& page) override { - lens_overlay_controller_->CloseUIAsync(DismissalSource::kPageChanged); + lens_overlay_controller_->CloseUIAsync( + lens::LensOverlayDismissalSource::kPageChanged); } private: @@ -705,7 +710,8 @@ // During initialization and shutdown a capture may not be possible. if (!view || !view->IsSurfaceAvailableForCopy()) { - CloseUIAsync(DismissalSource::kErrorScreenshotCreationFailed); + CloseUIAsync( + lens::LensOverlayDismissalSource::kErrorScreenshotCreationFailed); } state_ = State::kScreenshot; @@ -737,7 +743,8 @@ // this is a multi-process, multi-threaded environment so there may be a // TOCTTOU race condition. if (bitmap.drawsNothing()) { - CloseUIAsync(DismissalSource::kErrorScreenshotCreationFailed); + CloseUIAsync( + lens::LensOverlayDismissalSource::kErrorScreenshotCreationFailed); return; } @@ -747,7 +754,8 @@ bitmap, lens::features::GetLensOverlayScreenshotRenderQuality(), &data)) { // TODO(b/334185985): Handle case when screenshot data URI encoding fails. - CloseUIAsync(DismissalSource::kErrorScreenshotEncodingFailed); + CloseUIAsync( + lens::LensOverlayDismissalSource::kErrorScreenshotEncodingFailed); return; } @@ -863,7 +871,8 @@ SetWebViewCornerRadii(corner_radii_); } -void LensOverlayController::CloseUIPart2(DismissalSource dismissal_source) { +void LensOverlayController::CloseUIPart2( + lens::LensOverlayDismissalSource dismissal_source) { if (state_ == State::kOff) { return; } @@ -939,7 +948,7 @@ } void LensOverlayController::OnBackgroundUnblurred( - DismissalSource dismissal_source, + lens::LensOverlayDismissalSource dismissal_source, const viz::FrameTimingDetails& details) { // We only finish the closing process once the background has been unblurred. CloseUIPart2(dismissal_source); @@ -1106,7 +1115,7 @@ // If a side panel opens that is not ours, we must close the overlay. if (side_panel_coordinator_->GetCurrentEntryId() != SidePanelEntry::Id::kLensOverlayResults) { - CloseUIAsync(DismissalSource::kUnexpectedSidePanelOpen); + CloseUIAsync(lens::LensOverlayDismissalSource::kUnexpectedSidePanelOpen); } } @@ -1115,7 +1124,7 @@ // opened in the process, we need to close the overlay to not show next to the // unwanted side panel. if (state_ == State::kClosingOpenedSidePanel) { - CloseUIAsync(DismissalSource::kUnexpectedSidePanelOpen); + CloseUIAsync(lens::LensOverlayDismissalSource::kUnexpectedSidePanelOpen); } } @@ -1154,7 +1163,8 @@ // This is still possible when the controller is in state kScreenshot and the // tab was backgrounded. We should close the UI as the overlay has not been // created yet. - CloseUIAsync(DismissalSource::kTabBackgroundedWhileScreenshotting); + CloseUIAsync( + lens::LensOverlayDismissalSource::kTabBackgroundedWhileScreenshotting); } void LensOverlayController::WillDiscardContents( @@ -1162,7 +1172,7 @@ content::WebContents* old_contents, content::WebContents* new_contents) { // Background tab contents discarded. - CloseUIAsync(DismissalSource::kTabContentsDiscarded); + CloseUIAsync(lens::LensOverlayDismissalSource::kTabContentsDiscarded); old_contents->RemoveUserData(LensOverlayControllerTabLookup::UserDataKey()); LensOverlayControllerTabLookup::CreateForWebContents(new_contents, this); } @@ -1202,19 +1212,19 @@ } void LensOverlayController::CloseRequestedByOverlayCloseButton() { - CloseUIAsync(DismissalSource::kOverlayCloseButton); + CloseUIAsync(lens::LensOverlayDismissalSource::kOverlayCloseButton); } void LensOverlayController::CloseRequestedByOverlayBackgroundClick() { - CloseUIAsync(DismissalSource::kOverlayBackgroundClick); + CloseUIAsync(lens::LensOverlayDismissalSource::kOverlayBackgroundClick); } void LensOverlayController::CloseRequestedByOverlayEscapeKeyPress() { - CloseUIAsync(DismissalSource::kEscapeKeyPress); + CloseUIAsync(lens::LensOverlayDismissalSource::kEscapeKeyPress); } void LensOverlayController::CloseRequestedBySidePanelEscapeKeyPress() { - CloseUIAsync(DismissalSource::kEscapeKeyPress); + CloseUIAsync(lens::LensOverlayDismissalSource::kEscapeKeyPress); } void LensOverlayController::FeedbackRequestedByOverlay() {
diff --git a/chrome/browser/ui/lens/lens_overlay_controller.h b/chrome/browser/ui/lens/lens_overlay_controller.h index 154f3a6..575eb11 100644 --- a/chrome/browser/ui/lens/lens_overlay_controller.h +++ b/chrome/browser/ui/lens/lens_overlay_controller.h
@@ -10,6 +10,8 @@ #include "chrome/browser/lens/core/mojom/lens.mojom.h" #include "chrome/browser/lens/core/mojom/overlay_object.mojom.h" #include "chrome/browser/lens/core/mojom/text.mojom.h" +#include "chrome/browser/ui/lens/lens_overlay_dismissal_source.h" +#include "chrome/browser/ui/lens/lens_overlay_invocation_source.h" #include "chrome/browser/ui/lens/lens_overlay_query_controller.h" #include "chrome/browser/ui/tabs/public/tab_interface.h" #include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h" @@ -102,101 +104,21 @@ // Returns whether the lens overlay feature is enabled. static bool IsEnabled(Profile* profile); - // Designates the source of any lens overlay invocation (in other words, any - // call to `ShowUI()`). - // - // These values are persisted to logs. Entries should not be renumbered and - // numeric values should never be reused. - // - // LINT.IfChange(InvocationSource) - enum class InvocationSource { - // The Chrome app ("3-dot") menu entry. - kAppMenu = 0, - - // The content area context menu entry that is available when the user - // right-clicks on any area of the page that doesn't contain text, links or - // media. - kContentAreaContextMenuPage = 1, - - // The content area context menu entry that is available when the user - // right-clicks on an image. - kContentAreaContextMenuImage = 2, - - // The pinned toolbar action button. - kToolbar = 3, - - // The find in page (Ctrl/Cmd-f) dialog button. - kFindInPage = 4, - - // The button in the omnibox (address bar). - kOmnibox = 5, - - kMaxValue = kOmnibox - }; - // LINT.ThenChange(//tools/metrics/histograms/metadata/others/enums.xml:LensOverlayInvocationSource) - // Sets a region to search after the overlay loads, then calls ShowUI(). - void ShowUIWithPendingRegion(InvocationSource invocation_source, - lens::mojom::CenterRotatedBoxPtr region); + void ShowUIWithPendingRegion( + lens::LensOverlayInvocationSource invocation_source, + lens::mojom::CenterRotatedBoxPtr region); // This is entry point for showing the overlay UI. This has no effect if state // is not kOff. This has no effect if the tab is not in the foreground. If the // overlay is successfully invoked, then the value of `invocation_source` will // be recorded in the relevant metrics. - void ShowUI(InvocationSource invocation_source); - - // Designates the source of any lens overlay dismissal (in other words, any - // call to `CloseUI()`). - // - // These values are persisted to logs. Entries should not be renumbered and - // numeric values should never be reused. - // - // LINT.IfChange(DismissalSource) - enum class DismissalSource { - // The overlay close button (shown when in the kOverlay state). - kOverlayCloseButton = 0, - - // A click on the background scrim (shown when in the kOverlayAndResults - // state). - kOverlayBackgroundClick = 1, - - // The close button in the side panel. - kSidePanelCloseButton = 2, - - // The pinned toolbar action button. - kToolbar = 3, - - // The page in the primary web contents changed (link clicked, back button, - // etc.). - kPageChanged = 4, - - // The contents of the associated tab were in the background and discarded - // to save memory. - kTabContentsDiscarded = 5, - - // The current tab was backgrounded before the screenshot was created. - kTabBackgroundedWhileScreenshotting = 6, - - // Creating a screenshot from the view of the web contents failed. - kErrorScreenshotCreationFailed = 7, - - // Encoding the screenshot failed. - kErrorScreenshotEncodingFailed = 8, - - // User pressed the escape key. - kEscapeKeyPress = 9, - - // Another side panel opened forcing our overlay to close. - kUnexpectedSidePanelOpen = 10, - - kMaxValue = kUnexpectedSidePanelOpen - }; - // LINT.ThenChange(//tools/metrics/histograms/metadata/others/enums.xml:LensOverlayDismissalSource) + void ShowUI(lens::LensOverlayInvocationSource invocation_source); // Starts the closing process of the overlay. This is an asynchronous process // because we first must unblur the background, before closing the overlay // whether. Eventually Calls CloseUI() asynchronously. - void CloseUIAsync(DismissalSource dismissal_source); + void CloseUIAsync(lens::LensOverlayDismissalSource dismissal_source); // Given an instance of `web_ui` created by the LensOverlayController, returns // the LensOverlayController. This method is necessary because WebUIController @@ -423,7 +345,8 @@ lens::LensOverlayInteractionResponseCallback interaction_data_callback, lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback, variations::VariationsClient* variations_client, - signin::IdentityManager* identity_manager); + signin::IdentityManager* identity_manager, + lens::LensOverlayInvocationSource invocation_source); private: // Data class for constructing overlay and storing overlay state for @@ -529,11 +452,11 @@ // cleanup of closing the overlay UI and should only be called by // CloseUIAsync. Anyone called trying to close the UI should go through // CloseUIAsync. - void CloseUIPart2(DismissalSource dismissal_source); + void CloseUIPart2(lens::LensOverlayDismissalSource dismissal_source); // Passed into the compositor layer to know when the background is done being // unblurred and it is safe to close the overlay. - void OnBackgroundUnblurred(DismissalSource dismissal_source, + void OnBackgroundUnblurred(lens::LensOverlayDismissalSource dismissal_source, const viz::FrameTimingDetails& details); // Initializes the overlay UI after it has been created with data fetched @@ -692,7 +615,7 @@ // If the side panel needed to be closed before dismissing the overlay, this // stores the original dismissal_source so it is properly recorded when the // side panel is done closing and the callback is invoked. - std::optional<DismissalSource> last_dismissal_source_; + std::optional<lens::LensOverlayDismissalSource> last_dismissal_source_; // Thumbnail URI referencing the data defined by the user image selection on // the overlay. If the user hasn't made any selection or has made a text
diff --git a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc index e32b0a10..3ac2c7c 100644 --- a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc +++ b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
@@ -21,6 +21,8 @@ #include "chrome/browser/sync/sync_service_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_element_identifiers.h" +#include "chrome/browser/ui/lens/lens_overlay_dismissal_source.h" +#include "chrome/browser/ui/lens/lens_overlay_invocation_source.h" #include "chrome/browser/ui/lens/lens_overlay_permission_utils.h" #include "chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.h" #include "chrome/browser/ui/lens/lens_overlay_url_builder.h" @@ -66,8 +68,8 @@ constexpr char kDocumentWithNamedElement[] = "/select.html"; using State = LensOverlayController::State; -using InvocationSource = LensOverlayController::InvocationSource; -using DismissalSource = LensOverlayController::DismissalSource; +using LensOverlayInvocationSource = lens::LensOverlayInvocationSource; +using LensOverlayDismissalSource = lens::LensOverlayDismissalSource; constexpr char kNewTabLinkClickScript[] = "(function() {const anchor = document.createElement('a');anchor.href = " @@ -234,13 +236,15 @@ lens::LensOverlayInteractionResponseCallback interaction_data_callback, lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback, variations::VariationsClient* variations_client, - signin::IdentityManager* identity_manager) + signin::IdentityManager* identity_manager, + LensOverlayInvocationSource invocation_source) : LensOverlayQueryController(full_image_callback, url_callback, interaction_data_callback, thumbnail_created_callback, variations_client, - identity_manager) {} + identity_manager, + invocation_source) {} void StartQueryFlow(const SkBitmap& screenshot, std::optional<GURL> page_url, @@ -282,10 +286,12 @@ lens::LensOverlayInteractionResponseCallback interaction_data_callback, lens::LensOverlayThumbnailCreatedCallback thumbnail_created_callback, variations::VariationsClient* variations_client, - signin::IdentityManager* identity_manager) override { + signin::IdentityManager* identity_manager, + lens::LensOverlayInvocationSource invocation_source) override { return std::make_unique<LensOverlayQueryControllerFake>( full_image_callback, url_callback, interaction_data_callback, - thumbnail_created_callback, variations_client, identity_manager); + thumbnail_created_callback, variations_client, identity_manager, + invocation_source); } void BindOverlay(mojo::PendingReceiver<lens::mojom::LensPageHandler> receiver, @@ -481,7 +487,7 @@ } void CloseOverlayAndWaitForOff(LensOverlayController* controller, - DismissalSource dismissal_source) { + LensOverlayDismissalSource dismissal_source) { controller->CloseUIAsync(dismissal_source); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOff; })); @@ -510,7 +516,7 @@ // Verify attempting to show the UI will show the permission bubble. views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, lens::kLensPermissionDialogName); - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); // State should remain off. ASSERT_EQ(controller->state(), State::kOff); auto* bubble_widget = waiter.WaitIfNeededAndGet(); @@ -521,7 +527,7 @@ ->HasOpenDialogWidget()); // Verify attempting to show the UI again does not close the bubble widget. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); // State should remain off. ASSERT_EQ(controller->state(), State::kOff); ASSERT_TRUE(bubble_widget->IsVisible()); @@ -570,7 +576,7 @@ // Verify attempting to show the UI will show the permission bubble. views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, lens::kLensPermissionDialogName); - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); // State should remain off. ASSERT_EQ(controller->state(), State::kOff); auto* bubble_widget = waiter.WaitIfNeededAndGet(); @@ -581,7 +587,7 @@ ->HasOpenDialogWidget()); // Verify attempting to show the UI again does not close the bubble widget. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); // State should remain off. ASSERT_EQ(controller->state(), State::kOff); ASSERT_TRUE(bubble_widget->IsVisible()); @@ -621,7 +627,7 @@ // Verify attempting to show the UI will show the permission bubble. views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, lens::kLensPermissionDialogName); - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); // State should remain off. ASSERT_EQ(controller->state(), State::kOff); auto* bubble_widget = waiter.WaitIfNeededAndGet(); @@ -632,7 +638,7 @@ ->HasOpenDialogWidget()); // Verify attempting to show the UI again does not close the bubble widget. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); // State should remain off. ASSERT_EQ(controller->state(), State::kOff); ASSERT_TRUE(bubble_widget->IsVisible()); @@ -670,7 +676,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -698,7 +704,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -721,7 +727,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -759,7 +765,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUIWithPendingRegion(InvocationSource::kAppMenu, + controller->ShowUIWithPendingRegion(LensOverlayInvocationSource::kAppMenu, kTestRegion->Clone()); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( @@ -790,7 +796,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -831,7 +837,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -852,7 +858,8 @@ EXPECT_FALSE(observer.request_shown()); // Close overlay - CloseOverlayAndWaitForOff(controller, DismissalSource::kOverlayCloseButton); + CloseOverlayAndWaitForOff(controller, + LensOverlayDismissalSource::kOverlayCloseButton); // Verify a prompt was shown ASSERT_TRUE(base::test::RunUntil([&]() { return observer.request_shown(); })); @@ -880,7 +887,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); EXPECT_TRUE(controller->GetThumbnailForTesting().empty()); EXPECT_EQ(controller->GetPageClassificationForTesting(), @@ -973,7 +980,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -1023,7 +1030,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -1075,7 +1082,7 @@ // Showing UI should change the state to screenshot and eventually to overlay. // When the overlay is bound, it should start the query flow which returns a // response for the full image callback. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -1116,7 +1123,7 @@ // Showing UI should change the state to screenshot and eventually to overlay. // When the overlay is bound, it should start the query flow which returns a // response for the full image callback. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -1150,7 +1157,7 @@ browser()->tab_strip_model()->active_index(); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -1201,7 +1208,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -1256,7 +1263,7 @@ EXPECT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); EXPECT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -1338,7 +1345,7 @@ EXPECT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); EXPECT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -1402,7 +1409,7 @@ EXPECT_EQ(controller->state(), State::kOff); // Showing UI should change the state to screenshot and eventually to overlay. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_EQ(controller->state(), State::kScreenshot); EXPECT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -1467,7 +1474,7 @@ EXPECT_EQ(controller->state(), State::kOff); // Showing UI should eventually result in overlay state. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); EXPECT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); EXPECT_TRUE(content::WaitForLoadStop(GetOverlayWebContents())); @@ -1532,7 +1539,7 @@ // Showing UI should eventually result in overlay state. When the overlay is // bound, it should start the query flow which returns a response for the // interaction data callback. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); ASSERT_TRUE(content::WaitForLoadStop(GetOverlayWebContents())); @@ -1573,7 +1580,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should eventually result in overlay state. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); EXPECT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); EXPECT_TRUE(content::WaitForLoadStop(GetOverlayWebContents())); @@ -1582,7 +1589,8 @@ // Loading a url in the side panel should show the results page. const GURL first_search_url( "https://www.google.com/" - "search?q=oranges&lns_mode=text&gsc=1&masfc=c&hl=en-US"); + "search?source=chrome.cr.menu&q=oranges&lns_mode=text&gsc=1&masfc=c&" + "hl=en-US"); controller->LoadURLInResultsFrame(first_search_url); EXPECT_TRUE(content::WaitForLoadStop( controller->GetSidePanelWebContentsForTesting())); @@ -1603,7 +1611,8 @@ // Loading a second url in the side panel should show the results page. const GURL second_search_url( "https://www.google.com/" - "search?q=kiwi&lns_mode=text&gsc=1&masfc=c&hl=en-US"); + "search?source=chrome.cr.menu&q=kiwi&lns_mode=text&gsc=1&masfc=c&hl=" + "en-US"); // We can't use content::WaitForLoadStop here since the last navigation is // successful. content::TestNavigationObserver observer( @@ -1661,7 +1670,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should eventually result in overlay state. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); EXPECT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); EXPECT_TRUE(content::WaitForLoadStop(GetOverlayWebContents())); @@ -1670,7 +1679,8 @@ // Loading a url in the side panel should show the results page. const GURL first_search_url( "https://www.google.com/" - "search?q=oranges&lns_mode=text&gsc=1&masfc=c&hl=en-US"); + "search?source=chrome.cr.menu&q=oranges&lns_mode=text&gsc=1&masfc=c&" + "hl=en-US"); controller->IssueTextSelectionRequestForTesting("oranges", 20, 200); EXPECT_TRUE(content::WaitForLoadStop( controller->GetSidePanelWebContentsForTesting())); @@ -1693,7 +1703,8 @@ // Loading a second url in the side panel should show the results page. const GURL second_search_url( "https://www.google.com/" - "search?q=kiwi&lns_mode=text&gsc=1&masfc=c&hl=en-US"); + "search?source=chrome.cr.menu&q=kiwi&lns_mode=text&gsc=1&masfc=c&hl=" + "en-US"); // We can't use content::WaitForLoadStop here since the last navigation is // successful. content::TestNavigationObserver observer( @@ -1754,6 +1765,57 @@ } IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest, + AddQueryToHistoryAfterResize) { + WaitForPaint(); + + // State should start in off. + auto* controller = browser() + ->tab_strip_model() + ->GetActiveTab() + ->tab_features() + ->lens_overlay_controller(); + ASSERT_EQ(controller->state(), State::kOff); + + // Showing UI should eventually result in overlay state. + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); + EXPECT_TRUE(base::test::RunUntil( + [&]() { return controller->state() == State::kOverlay; })); + EXPECT_TRUE(content::WaitForLoadStop(GetOverlayWebContents())); + EXPECT_TRUE(controller->GetOverlayWidgetForTesting()->IsVisible()); + + // Loading a url in the side panel should show the results page. + const GURL first_search_url( + "https://www.google.com/search?q=oranges&gsc=1&masfc=c&hl=en-US"); + controller->LoadURLInResultsFrame(first_search_url); + EXPECT_TRUE(content::WaitForLoadStop( + controller->GetSidePanelWebContentsForTesting())); + + // Loading a second url in the side panel should show the results page. + const GURL second_search_url( + "https://www.google.com/search?q=kiwi&gsc=1&masfc=c&hl=en-US"); + // We can't use content::WaitForLoadStop here since the last navigation is + // successful. + content::TestNavigationObserver observer( + controller->GetSidePanelWebContentsForTesting()); + controller->LoadURLInResultsFrame(second_search_url); + observer.WaitForNavigationFinished(); + + // Make the side panel larger. + const int increment = -50; + BrowserView::GetBrowserViewForBrowser(browser()) + ->unified_side_panel() + ->OnResize(increment, true); + // Popping the query should load the previous query into the results frame. + content::TestNavigationObserver pop_observer( + controller->GetSidePanelWebContentsForTesting()); + controller->PopAndLoadQueryFromHistory(); + pop_observer.WaitForNavigationFinished(); + // The search query history stack should be empty and the currently loaded + // query should be set to the previous query. + EXPECT_TRUE(controller->GetSearchQueryHistoryForTesting().empty()); +} + +IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest, RecordInvocationAndDismissalHistograms) { base::HistogramTester histogram_tester; WaitForPaint(); @@ -1769,117 +1831,128 @@ // Showing the UI and then closing it should record an entry in the // appropriate buckets and the total count of invocations and dismissals // should be 1. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); ASSERT_TRUE(content::WaitForLoadStop(GetOverlayWebContents())); histogram_tester.ExpectBucketCount("Lens.Overlay.Invoked", - InvocationSource::kAppMenu, + LensOverlayInvocationSource::kAppMenu, /*expected_count=*/1); histogram_tester.ExpectTotalCount("Lens.Overlay.Invoked", /*expected_count=*/1); - CloseOverlayAndWaitForOff(controller, DismissalSource::kOverlayCloseButton); - histogram_tester.ExpectBucketCount("Lens.Overlay.Dismissed", - DismissalSource::kOverlayCloseButton, - /*expected_count=*/1); + CloseOverlayAndWaitForOff(controller, + LensOverlayDismissalSource::kOverlayCloseButton); + histogram_tester.ExpectBucketCount( + "Lens.Overlay.Dismissed", LensOverlayDismissalSource::kOverlayCloseButton, + /*expected_count=*/1); histogram_tester.ExpectTotalCount("Lens.Overlay.Dismissed", /*expected_count=*/1); // Attempting to invoke the overlay twice without closing it in between // should record only a single new entry. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); histogram_tester.ExpectBucketCount("Lens.Overlay.Invoked", - InvocationSource::kAppMenu, + LensOverlayInvocationSource::kAppMenu, /*expected_count=*/2); histogram_tester.ExpectTotalCount("Lens.Overlay.Invoked", /*expected_count=*/2); - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); histogram_tester.ExpectBucketCount("Lens.Overlay.Invoked", - InvocationSource::kAppMenu, + LensOverlayInvocationSource::kAppMenu, /*expected_count=*/2); histogram_tester.ExpectTotalCount("Lens.Overlay.Invoked", /*expected_count=*/2); // Attempting to close the overlay twice without opening it in between should // only record a single entry. - CloseOverlayAndWaitForOff(controller, DismissalSource::kOverlayCloseButton); - histogram_tester.ExpectBucketCount("Lens.Overlay.Dismissed", - DismissalSource::kOverlayCloseButton, - /*expected_count=*/2); + CloseOverlayAndWaitForOff(controller, + LensOverlayDismissalSource::kOverlayCloseButton); + histogram_tester.ExpectBucketCount( + "Lens.Overlay.Dismissed", LensOverlayDismissalSource::kOverlayCloseButton, + /*expected_count=*/2); histogram_tester.ExpectTotalCount("Lens.Overlay.Dismissed", /*expected_count=*/2); - CloseOverlayAndWaitForOff(controller, DismissalSource::kOverlayCloseButton); - histogram_tester.ExpectBucketCount("Lens.Overlay.Dismissed", - DismissalSource::kOverlayCloseButton, - /*expected_count=*/2); + CloseOverlayAndWaitForOff(controller, + LensOverlayDismissalSource::kOverlayCloseButton); + histogram_tester.ExpectBucketCount( + "Lens.Overlay.Dismissed", LensOverlayDismissalSource::kOverlayCloseButton, + /*expected_count=*/2); histogram_tester.ExpectTotalCount("Lens.Overlay.Dismissed", /*expected_count=*/2); // Each type of invocation and dismissal should record entries in the // appropriate buckets. - controller->ShowUI(InvocationSource::kContentAreaContextMenuPage); + controller->ShowUI(LensOverlayInvocationSource::kContentAreaContextMenuPage); histogram_tester.ExpectBucketCount( - "Lens.Overlay.Invoked", InvocationSource::kContentAreaContextMenuPage, + "Lens.Overlay.Invoked", + LensOverlayInvocationSource::kContentAreaContextMenuPage, /*expected_count=*/1); histogram_tester.ExpectTotalCount("Lens.Overlay.Invoked", /*expected_count=*/3); + CloseOverlayAndWaitForOff( + controller, LensOverlayDismissalSource::kOverlayBackgroundClick); + histogram_tester.ExpectBucketCount( + "Lens.Overlay.Dismissed", + LensOverlayDismissalSource::kOverlayBackgroundClick, + /*expected_count=*/1); + histogram_tester.ExpectTotalCount("Lens.Overlay.Dismissed", + /*expected_count=*/3); + + controller->ShowUI(LensOverlayInvocationSource::kContentAreaContextMenuImage); + histogram_tester.ExpectBucketCount( + "Lens.Overlay.Invoked", + LensOverlayInvocationSource::kContentAreaContextMenuImage, + /*expected_count=*/1); + histogram_tester.ExpectTotalCount("Lens.Overlay.Invoked", + /*expected_count=*/4); CloseOverlayAndWaitForOff(controller, - DismissalSource::kOverlayBackgroundClick); - histogram_tester.ExpectBucketCount("Lens.Overlay.Dismissed", - DismissalSource::kOverlayBackgroundClick, - /*expected_count=*/1); - histogram_tester.ExpectTotalCount("Lens.Overlay.Dismissed", - /*expected_count=*/3); - - controller->ShowUI(InvocationSource::kContentAreaContextMenuImage); + LensOverlayDismissalSource::kSidePanelCloseButton); histogram_tester.ExpectBucketCount( - "Lens.Overlay.Invoked", InvocationSource::kContentAreaContextMenuImage, + "Lens.Overlay.Dismissed", + LensOverlayDismissalSource::kSidePanelCloseButton, /*expected_count=*/1); - histogram_tester.ExpectTotalCount("Lens.Overlay.Invoked", - /*expected_count=*/4); - CloseOverlayAndWaitForOff(controller, DismissalSource::kSidePanelCloseButton); - histogram_tester.ExpectBucketCount("Lens.Overlay.Dismissed", - DismissalSource::kSidePanelCloseButton, - /*expected_count=*/1); histogram_tester.ExpectTotalCount("Lens.Overlay.Dismissed", /*expected_count=*/4); - controller->ShowUI(InvocationSource::kToolbar); + controller->ShowUI(LensOverlayInvocationSource::kToolbar); histogram_tester.ExpectBucketCount("Lens.Overlay.Invoked", - InvocationSource::kToolbar, + LensOverlayInvocationSource::kToolbar, /*expected_count=*/1); histogram_tester.ExpectTotalCount("Lens.Overlay.Invoked", /*expected_count=*/5); - CloseOverlayAndWaitForOff(controller, DismissalSource::kToolbar); + CloseOverlayAndWaitForOff(controller, LensOverlayDismissalSource::kToolbar); histogram_tester.ExpectBucketCount("Lens.Overlay.Dismissed", - DismissalSource::kToolbar, + LensOverlayDismissalSource::kToolbar, /*expected_count=*/1); histogram_tester.ExpectTotalCount("Lens.Overlay.Dismissed", /*expected_count=*/5); - controller->ShowUI(InvocationSource::kFindInPage); + controller->ShowUI(LensOverlayInvocationSource::kFindInPage); histogram_tester.ExpectBucketCount("Lens.Overlay.Invoked", - InvocationSource::kFindInPage, + LensOverlayInvocationSource::kFindInPage, /*expected_count=*/1); histogram_tester.ExpectTotalCount("Lens.Overlay.Invoked", /*expected_count=*/6); - CloseOverlayAndWaitForOff(controller, DismissalSource::kPageChanged); + CloseOverlayAndWaitForOff(controller, + LensOverlayDismissalSource::kPageChanged); histogram_tester.ExpectBucketCount("Lens.Overlay.Dismissed", - DismissalSource::kPageChanged, + LensOverlayDismissalSource::kPageChanged, /*expected_count=*/1); histogram_tester.ExpectTotalCount("Lens.Overlay.Dismissed", /*expected_count=*/6); - controller->ShowUI(InvocationSource::kOmnibox); + controller->ShowUI(LensOverlayInvocationSource::kOmnibox); histogram_tester.ExpectBucketCount("Lens.Overlay.Invoked", - InvocationSource::kOmnibox, + LensOverlayInvocationSource::kOmnibox, /*expected_count=*/1); histogram_tester.ExpectTotalCount("Lens.Overlay.Invoked", /*expected_count=*/7); - CloseOverlayAndWaitForOff(controller, DismissalSource::kTabContentsDiscarded); - histogram_tester.ExpectBucketCount("Lens.Overlay.Dismissed", - DismissalSource::kTabContentsDiscarded, - /*expected_count=*/1); + CloseOverlayAndWaitForOff(controller, + LensOverlayDismissalSource::kTabContentsDiscarded); + histogram_tester.ExpectBucketCount( + "Lens.Overlay.Dismissed", + LensOverlayDismissalSource::kTabContentsDiscarded, + /*expected_count=*/1); histogram_tester.ExpectTotalCount("Lens.Overlay.Dismissed", /*expected_count=*/7); } @@ -1914,7 +1987,7 @@ // Showing UI should eventually result in overlay state. When the overlay is // bound, it should start the query flow which returns a response for the // interaction data callback. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -1937,7 +2010,7 @@ // Showing UI should eventually result in overlay state. When the overlay is // bound, it should start the query flow which returns a response for the // interaction data callback. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -1968,7 +2041,7 @@ // Showing UI should eventually result in overlay state. When the overlay is // bound, it should start the query flow which returns a response for the // interaction data callback. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -2033,7 +2106,7 @@ // Showing UI should eventually result in overlay state. When the overlay is // bound, it should start the query flow which returns a response for the // interaction data callback. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_TRUE(controller->state() == State::kClosingOpenedSidePanel); // Wait for the side panel to start closing. @@ -2049,7 +2122,7 @@ // Secondly, test the flow if the side panel is open with our results, if we // close our UI and request the close the side panel, we gracefully handle a // new side panel opening which prevents our requested close. - controller->ShowUI(InvocationSource::kAppMenu); + controller->ShowUI(LensOverlayInvocationSource::kAppMenu); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; })); @@ -2063,7 +2136,7 @@ [&]() { return controller->state() == State::kOverlayAndResults; })); // Request a close which will start to close the side panel. - controller->CloseUIAsync(DismissalSource::kOverlayBackgroundClick); + controller->CloseUIAsync(LensOverlayDismissalSource::kOverlayBackgroundClick); ASSERT_TRUE(controller->state() == State::kClosingSidePanel); // Reshow the side panel to prevent a the side panel from closing.
diff --git a/chrome/browser/ui/lens/lens_overlay_dismissal_source.h b/chrome/browser/ui/lens/lens_overlay_dismissal_source.h new file mode 100644 index 0000000..f0936bd8 --- /dev/null +++ b/chrome/browser/ui/lens/lens_overlay_dismissal_source.h
@@ -0,0 +1,60 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_LENS_LENS_OVERLAY_DISMISSAL_SOURCE_H_ +#define CHROME_BROWSER_UI_LENS_LENS_OVERLAY_DISMISSAL_SOURCE_H_ + +namespace lens { + +// Designates the source of any lens overlay dismissal (in other words, any +// call to `LensOverlayController:CloseUI()`). +// +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +// +// LINT.IfChange(LensOverlayDismissalSource) +enum class LensOverlayDismissalSource { + // The overlay close button (shown when in the kOverlay state). + kOverlayCloseButton = 0, + + // A click on the background scrim (shown when in the kOverlayAndResults + // state). + kOverlayBackgroundClick = 1, + + // The close button in the side panel. + kSidePanelCloseButton = 2, + + // The pinned toolbar action button. + kToolbar = 3, + + // The page in the primary web contents changed (link clicked, back button, + // etc.). + kPageChanged = 4, + + // The contents of the associated tab were in the background and discarded + // to save memory. + kTabContentsDiscarded = 5, + + // The current tab was backgrounded before the screenshot was created. + kTabBackgroundedWhileScreenshotting = 6, + + // Creating a screenshot from the view of the web contents failed. + kErrorScreenshotCreationFailed = 7, + + // Encoding the screenshot failed. + kErrorScreenshotEncodingFailed = 8, + + // User pressed the escape key. + kEscapeKeyPress = 9, + + // Another side panel opened forcing our overlay to close. + kUnexpectedSidePanelOpen = 10, + + kMaxValue = kUnexpectedSidePanelOpen +}; +// LINT.ThenChange(//tools/metrics/histograms/metadata/others/enums.xml:LensOverlayDismissalSource) + +} // namespace lens + +#endif // CHROME_BROWSER_UI_LENS_LENS_OVERLAY_DISMISSAL_SOURCE_H_
diff --git a/chrome/browser/ui/lens/lens_overlay_invocation_source.h b/chrome/browser/ui/lens/lens_overlay_invocation_source.h new file mode 100644 index 0000000..24b59cd --- /dev/null +++ b/chrome/browser/ui/lens/lens_overlay_invocation_source.h
@@ -0,0 +1,45 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_LENS_LENS_OVERLAY_INVOCATION_SOURCE_H_ +#define CHROME_BROWSER_UI_LENS_LENS_OVERLAY_INVOCATION_SOURCE_H_ + +namespace lens { + +// Designates the source of any lens overlay invocation (in other words, any +// call to `LensOverlayController::ShowUI()`). +// +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +// +// LINT.IfChange(LensOverlayInvocationSource) +enum class LensOverlayInvocationSource { + // The Chrome app ("3-dot") menu entry. + kAppMenu = 0, + + // The content area context menu entry that is available when the user + // right-clicks on any area of the page that doesn't contain text, links or + // media. + kContentAreaContextMenuPage = 1, + + // The content area context menu entry that is available when the user + // right-clicks on an image. + kContentAreaContextMenuImage = 2, + + // The pinned toolbar action button. + kToolbar = 3, + + // The find in page (Ctrl/Cmd-f) dialog button. + kFindInPage = 4, + + // The button in the omnibox (address bar). + kOmnibox = 5, + + kMaxValue = kOmnibox +}; +// LINT.ThenChange(//tools/metrics/histograms/metadata/others/enums.xml:LensOverlayInvocationSource) + +} // namespace lens + +#endif // CHROME_BROWSER_UI_LENS_LENS_OVERLAY_INVOCATION_SOURCE_H_
diff --git a/chrome/browser/ui/lens/lens_overlay_query_controller.cc b/chrome/browser/ui/lens/lens_overlay_query_controller.cc index 61f080f..8091fe8c 100644 --- a/chrome/browser/ui/lens/lens_overlay_query_controller.cc +++ b/chrome/browser/ui/lens/lens_overlay_query_controller.cc
@@ -151,7 +151,8 @@ LensOverlayInteractionResponseCallback interaction_data_callback, LensOverlayThumbnailCreatedCallback thumbnail_created_callback, variations::VariationsClient* variations_client, - signin::IdentityManager* identity_manager) + signin::IdentityManager* identity_manager, + lens::LensOverlayInvocationSource invocation_source) : full_image_callback_(std::move(full_image_callback)), interaction_data_callback_(std::move(interaction_data_callback)), thumbnail_created_callback_(std::move(thumbnail_created_callback)), @@ -159,7 +160,8 @@ std::make_unique<lens::LensOverlayRequestIdGenerator>()), url_callback_(std::move(url_callback)), variations_client_(variations_client), - identity_manager_{identity_manager} {} + identity_manager_(identity_manager), + invocation_source_(invocation_source) {} LensOverlayQueryController::~LensOverlayQueryController() = default; @@ -382,7 +384,8 @@ lens::proto::LensOverlayUrlResponse lens_overlay_url_response; lens_overlay_url_response.set_url( lens::BuildTextOnlySearchURL(query_text, page_url_, page_title_, - additional_search_query_params) + additional_search_query_params, + invocation_source_) .spec()); base::SequencedTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce(url_callback_, lens_overlay_url_response)); @@ -543,9 +546,9 @@ // Generate and send the Lens search url. lens::proto::LensOverlayUrlResponse lens_overlay_url_response; lens_overlay_url_response.set_url( - lens::BuildLensSearchURL(query_text, - request_id_generator_->GetNextRequestId(), - cluster_info, additional_search_query_params) + lens::BuildLensSearchURL( + query_text, request_id_generator_->GetNextRequestId(), cluster_info, + additional_search_query_params, invocation_source_) .spec()); base::SequencedTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce(url_callback_, lens_overlay_url_response));
diff --git a/chrome/browser/ui/lens/lens_overlay_query_controller.h b/chrome/browser/ui/lens/lens_overlay_query_controller.h index d84d95a..f708317 100644 --- a/chrome/browser/ui/lens/lens_overlay_query_controller.h +++ b/chrome/browser/ui/lens/lens_overlay_query_controller.h
@@ -8,6 +8,7 @@ #include "base/functional/callback.h" #include "chrome/browser/lens/core/mojom/overlay_object.mojom.h" #include "chrome/browser/lens/core/mojom/text.mojom.h" +#include "chrome/browser/ui/lens/lens_overlay_invocation_source.h" #include "chrome/browser/ui/lens/lens_overlay_request_id_generator.h" #include "components/endpoint_fetcher/endpoint_fetcher.h" #include "components/lens/proto/server/lens_overlay_response.pb.h" @@ -54,7 +55,8 @@ LensOverlayInteractionResponseCallback interaction_data_callback, LensOverlayThumbnailCreatedCallback thumbnail_created_callback, variations::VariationsClient* variations_client, - signin::IdentityManager* identity_manager); + signin::IdentityManager* identity_manager, + lens::LensOverlayInvocationSource invocation_source); virtual ~LensOverlayQueryController(); // Starts a query flow by sending a request to Lens using the screenshot, @@ -112,7 +114,8 @@ private: enum class QueryControllerState { - // StartQueryFlow has not been called and the query controller is inactive. + // StartQueryFlow has not been called and the query controller is + // inactive. kOff = 0, // The full image response has not been received, or is no longer valid. kAwaitingFullImageResponse = 1, @@ -164,8 +167,8 @@ // Helper to gate interaction fetches on whether or not the cluster // info has been received. If it has not been received, this function // sets the cluster info received callback to fetch the interaction. - // Additionally, invokes `thumbnail_created_callback_` and passes the data in - // `image_crop`. + // Additionally, invokes `thumbnail_created_callback_` and passes the data + // in `image_crop`. void FetchInteractionRequestAndGenerateUrlIfClusterInfoReady( int request_index, lens::mojom::CenterRotatedBoxPtr region, @@ -261,13 +264,17 @@ // incognito profiles. raw_ptr<signin::IdentityManager> identity_manager_; - // The request counter, used to make sure requests are not sent out of order. + // The request counter, used to make sure requests are not sent out of + // order. int request_counter_ = 0; // Whether or not the parent interaction query has been sent. This should // always be the first interaction in a query flow. bool parent_query_sent_ = false; + // The invocation source that triggered the query flow. + lens::LensOverlayInvocationSource invocation_source_; + base::WeakPtrFactory<LensOverlayQueryController> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ui/lens/lens_overlay_query_controller_unittest.cc b/chrome/browser/ui/lens/lens_overlay_query_controller_unittest.cc index b92f29d..6cb0ff9 100644 --- a/chrome/browser/ui/lens/lens_overlay_query_controller_unittest.cc +++ b/chrome/browser/ui/lens/lens_overlay_query_controller_unittest.cc
@@ -102,13 +102,15 @@ base::RepeatingCallback<void(const std::string&)> thumbnail_created_callback, variations::VariationsClient* variations_client, - signin::IdentityManager* identity_manager) + signin::IdentityManager* identity_manager, + lens::LensOverlayInvocationSource invocation_source) : LensOverlayQueryController(full_image_callback, url_callback, interaction_data_callback, thumbnail_created_callback, variations_client, - identity_manager) {} + identity_manager, + invocation_source) {} ~LensOverlayQueryControllerMock() override = default; lens::LensOverlayObjectsResponse fake_objects_response_; @@ -206,7 +208,8 @@ full_image_response_future.GetRepeatingCallback(), base::NullCallback(), base::NullCallback(), base::NullCallback(), profile()->GetVariationsClient(), - IdentityManagerFactory::GetForProfile(profile())); + IdentityManagerFactory::GetForProfile(profile()), + lens::LensOverlayInvocationSource::kAppMenu); SkBitmap bitmap = CreateNonEmptyBitmap(100, 100); query_controller.StartQueryFlow( bitmap, std::make_optional<GURL>(kTestPageUrl), @@ -261,7 +264,8 @@ interaction_data_response_future.GetRepeatingCallback(), thumbnail_created_future.GetRepeatingCallback(), profile()->GetVariationsClient(), - IdentityManagerFactory::GetForProfile(profile())); + IdentityManagerFactory::GetForProfile(profile()), + lens::LensOverlayInvocationSource::kAppMenu); query_controller.fake_objects_response_.mutable_cluster_info() ->set_server_session_id(kTestServerSessionId); query_controller.fake_interaction_response_.set_encoded_response( @@ -360,7 +364,8 @@ interaction_data_response_future.GetRepeatingCallback(), thumbnail_created_future.GetRepeatingCallback(), profile()->GetVariationsClient(), - IdentityManagerFactory::GetForProfile(profile())); + IdentityManagerFactory::GetForProfile(profile()), + lens::LensOverlayInvocationSource::kAppMenu); query_controller.fake_objects_response_.mutable_cluster_info() ->set_server_session_id(kTestServerSessionId); query_controller.fake_interaction_response_.set_encoded_response( @@ -463,7 +468,8 @@ interaction_data_response_future.GetRepeatingCallback(), thumbnail_created_future.GetRepeatingCallback(), profile()->GetVariationsClient(), - IdentityManagerFactory::GetForProfile(profile())); + IdentityManagerFactory::GetForProfile(profile()), + lens::LensOverlayInvocationSource::kAppMenu); query_controller.fake_objects_response_.mutable_cluster_info() ->set_server_session_id(kTestServerSessionId); query_controller.fake_interaction_response_.set_encoded_response( @@ -547,7 +553,8 @@ interaction_data_response_future.GetRepeatingCallback(), thumbnail_created_future.GetRepeatingCallback(), profile()->GetVariationsClient(), - IdentityManagerFactory::GetForProfile(profile())); + IdentityManagerFactory::GetForProfile(profile()), + lens::LensOverlayInvocationSource::kAppMenu); SkBitmap bitmap = CreateNonEmptyBitmap(100, 100); std::map<std::string, std::string> additional_search_query_params; query_controller.StartQueryFlow( @@ -593,7 +600,8 @@ interaction_data_response_future.GetRepeatingCallback(), thumbnail_created_future.GetRepeatingCallback(), profile()->GetVariationsClient(), - IdentityManagerFactory::GetForProfile(profile())); + IdentityManagerFactory::GetForProfile(profile()), + lens::LensOverlayInvocationSource::kAppMenu); query_controller.fake_objects_response_.mutable_cluster_info() ->set_server_session_id(kTestServerSessionId); query_controller.fake_interaction_response_.set_encoded_response(
diff --git a/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc b/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc index 171d7cf..ce31730 100644 --- a/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc +++ b/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc
@@ -8,6 +8,8 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/lens/lens_overlay_controller.h" +#include "chrome/browser/ui/lens/lens_overlay_dismissal_source.h" +#include "chrome/browser/ui/lens/lens_overlay_invocation_source.h" #include "chrome/browser/ui/lens/lens_overlay_url_builder.h" #include "chrome/browser/ui/lens/lens_untrusted_ui.h" #include "chrome/browser/ui/side_panel/side_panel_ui.h" @@ -86,10 +88,9 @@ // Toggle the Lens overlay. There's no need to show or hide the side // panel as the overlay controller will handle that. if (controller->IsOverlayShowing()) { - controller->CloseUIAsync( - LensOverlayController::DismissalSource::kToolbar); + controller->CloseUIAsync(lens::LensOverlayDismissalSource::kToolbar); } else { - controller->ShowUI(LensOverlayController::InvocationSource::kToolbar); + controller->ShowUI(lens::LensOverlayInvocationSource::kToolbar); } }, browser);
diff --git a/chrome/browser/ui/lens/lens_overlay_url_builder.cc b/chrome/browser/ui/lens/lens_overlay_url_builder.cc index 043cb1b2..503ae473 100644 --- a/chrome/browser/ui/lens/lens_overlay_url_builder.cc +++ b/chrome/browser/ui/lens/lens_overlay_url_builder.cc
@@ -56,6 +56,21 @@ inline constexpr char kTliteTargetLanguageParameterKey[] = "tlitetl"; inline constexpr char kTliteQueryParameterKey[] = "tlitetxt"; +// Query parameter for the invocation source. +inline constexpr char kInvocationSourceParameterKey[] = "source"; +inline constexpr char kInvocationSourceAppMenu[] = "chrome.cr.menu"; +inline constexpr char kInvocationSourcePageSearchContextMenu[] = + "chrome.cr.ctxp"; +inline constexpr char kInvocationSourceImageSearchContextMenu[] = + "chrome.cr.ctxi"; +inline constexpr char kInvocationSourceFindInPage[] = "chrome.cr.find"; +inline constexpr char kInvocationSourceToolbarIcon[] = "chrome.cr.tbic"; +inline constexpr char kInvocationSourceOmniboxIcon[] = "chrome.cr.obic"; + +// The url query param for the viewport width and height. +constexpr char kViewportWidthQueryParamKey[] = "biw"; +constexpr char kViewportHeightQueryParamKey[] = "bih"; + // Appends the url params from the map to the url. GURL AppendUrlParamsFromMap( const GURL& url_to_modify, @@ -121,13 +136,44 @@ return new_url; } +GURL AppendInvocationSourceParamToURL( + const GURL& url_to_modify, + lens::LensOverlayInvocationSource invocation_source) { + std::string param_value = ""; + switch (invocation_source) { + case lens::LensOverlayInvocationSource::kAppMenu: + param_value = kInvocationSourceAppMenu; + break; + case lens::LensOverlayInvocationSource::kContentAreaContextMenuPage: + param_value = kInvocationSourcePageSearchContextMenu; + break; + case lens::LensOverlayInvocationSource::kContentAreaContextMenuImage: + param_value = kInvocationSourceImageSearchContextMenu; + break; + case lens::LensOverlayInvocationSource::kToolbar: + param_value = kInvocationSourceToolbarIcon; + break; + case lens::LensOverlayInvocationSource::kFindInPage: + param_value = kInvocationSourceFindInPage; + break; + case lens::LensOverlayInvocationSource::kOmnibox: + param_value = kInvocationSourceOmniboxIcon; + break; + } + return net::AppendOrReplaceQueryParameter( + url_to_modify, kInvocationSourceParameterKey, param_value); +} + GURL BuildTextOnlySearchURL( const std::string& text_query, std::optional<GURL> page_url, std::optional<std::string> page_title, - std::map<std::string, std::string> additional_search_query_params) { + std::map<std::string, std::string> additional_search_query_params, + lens::LensOverlayInvocationSource invocation_source) { GURL url_with_query_params = GURL(lens::features::GetLensOverlayResultsSearchURL()); + url_with_query_params = AppendInvocationSourceParamToURL( + url_with_query_params, invocation_source); url_with_query_params = AppendUrlParamsFromMap( url_with_query_params, additional_search_query_params); url_with_query_params = net::AppendOrReplaceQueryParameter( @@ -146,9 +192,12 @@ std::optional<std::string> text_query, std::unique_ptr<lens::LensOverlayRequestId> request_id, lens::LensOverlayClusterInfo cluster_info, - std::map<std::string, std::string> additional_search_query_params) { + std::map<std::string, std::string> additional_search_query_params, + lens::LensOverlayInvocationSource invocation_source) { GURL url_with_query_params = GURL(lens::features::GetLensOverlayResultsSearchURL()); + url_with_query_params = AppendInvocationSourceParamToURL( + url_with_query_params, invocation_source); url_with_query_params = AppendUrlParamsFromMap( url_with_query_params, additional_search_query_params); url_with_query_params = @@ -209,4 +258,23 @@ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); } +GURL RemoveUrlViewportParams(const GURL& url) { + GURL processed_url = url; + std::string actual_viewport_width; + bool has_viewport_width = net::GetValueForKeyInQuery( + url, kViewportWidthQueryParamKey, &actual_viewport_width); + std::string actual_viewport_height; + bool has_viewport_height = net::GetValueForKeyInQuery( + GURL(url), kViewportHeightQueryParamKey, &actual_viewport_height); + if (has_viewport_width) { + processed_url = net::AppendOrReplaceQueryParameter( + processed_url, kViewportWidthQueryParamKey, std::nullopt); + } + if (has_viewport_height) { + processed_url = net::AppendOrReplaceQueryParameter( + processed_url, kViewportHeightQueryParamKey, std::nullopt); + } + return processed_url; +} + } // namespace lens
diff --git a/chrome/browser/ui/lens/lens_overlay_url_builder.h b/chrome/browser/ui/lens/lens_overlay_url_builder.h index 03b0a73..05854b1 100644 --- a/chrome/browser/ui/lens/lens_overlay_url_builder.h +++ b/chrome/browser/ui/lens/lens_overlay_url_builder.h
@@ -8,6 +8,7 @@ #include <optional> #include <string> +#include "chrome/browser/ui/lens/lens_overlay_invocation_source.h" #include "third_party/lens_server_proto/lens_overlay_cluster_info.pb.h" #include "third_party/lens_server_proto/lens_overlay_request_id.pb.h" #include "url/gurl.h" @@ -23,17 +24,23 @@ std::optional<GURL> page_url, std::optional<std::string> page_title); +GURL AppendInvocationSourceParamToURL( + const GURL& url_to_modify, + lens::LensOverlayInvocationSource invocation_source); + GURL BuildTextOnlySearchURL( const std::string& text_query, std::optional<GURL> page_url, std::optional<std::string> page_title, - std::map<std::string, std::string> additional_search_query_params); + std::map<std::string, std::string> additional_search_query_params, + lens::LensOverlayInvocationSource invocation_source); GURL BuildLensSearchURL( std::optional<std::string> text_query, std::unique_ptr<lens::LensOverlayRequestId> request_id, lens::LensOverlayClusterInfo cluster_info, - std::map<std::string, std::string> additional_search_query_params); + std::map<std::string, std::string> additional_search_query_params, + lens::LensOverlayInvocationSource invocation_source); // Returns the value of the text query parameter value from the provided search // URL if any. Empty string otherwise. @@ -49,6 +56,11 @@ // finch configured flag. bool IsValidSearchResultsUrl(const GURL& url); +// Removes the viewport width (biw) and viewport height (bih) params from the +// search url. This allows us to compare search url's accurately in +// AddQueryToHistory when the side panel is resized. +GURL RemoveUrlViewportParams(const GURL& url); + } // namespace lens #endif // CHROME_BROWSER_UI_LENS_LENS_OVERLAY_URL_BUILDER_H_
diff --git a/chrome/browser/ui/lens/lens_overlay_url_builder_unittest.cc b/chrome/browser/ui/lens/lens_overlay_url_builder_unittest.cc index 98ee0ab..3393d0a 100644 --- a/chrome/browser/ui/lens/lens_overlay_url_builder_unittest.cc +++ b/chrome/browser/ui/lens/lens_overlay_url_builder_unittest.cc
@@ -69,14 +69,15 @@ TEST_F(LensOverlayUrlBuilderTest, BuildTextOnlySearchURL) { std::string text_query = "Apples"; std::map<std::string, std::string> additional_params; - std::string expected_url = - base::StringPrintf("%s?q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s", - kResultsSearchBaseUrl, text_query.c_str(), kLanguage); + std::string expected_url = base::StringPrintf( + "%s?source=chrome.cr.menu&q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s", + kResultsSearchBaseUrl, text_query.c_str(), kLanguage); - EXPECT_EQ(lens::BuildTextOnlySearchURL(text_query, - /*page_url=*/std::nullopt, - /*page_title=*/std::nullopt, - additional_params), + EXPECT_EQ(lens::BuildTextOnlySearchURL( + text_query, + /*page_url=*/std::nullopt, + /*page_title=*/std::nullopt, additional_params, + lens::LensOverlayInvocationSource::kAppMenu), expected_url); } @@ -96,13 +97,14 @@ EncodeSearchContext(std::make_optional<GURL>(kPageUrl), std::make_optional<std::string>(kPageTitle)); - std::string expected_url = - base::StringPrintf("%s?q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s", - kResultsSearchBaseUrl, text_query.c_str(), kLanguage); + std::string expected_url = base::StringPrintf( + "%s?source=chrome.cr.menu&q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s", + kResultsSearchBaseUrl, text_query.c_str(), kLanguage); EXPECT_EQ(lens::BuildTextOnlySearchURL( text_query, std::make_optional<GURL>(kPageUrl), - std::make_optional<std::string>(kPageTitle), additional_params), + std::make_optional<std::string>(kPageTitle), additional_params, + lens::LensOverlayInvocationSource::kAppMenu), expected_url); } @@ -113,14 +115,16 @@ EncodeSearchContext(std::make_optional<GURL>(kPageUrl), std::make_optional<std::string>(kPageTitle)); - std::string expected_url = - base::StringPrintf("%s?q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s&mactx=%s", - kResultsSearchBaseUrl, text_query.c_str(), kLanguage, - expected_search_context.c_str()); + std::string expected_url = base::StringPrintf( + "%s?source=chrome.cr.menu&q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s&" + "mactx=%s", + kResultsSearchBaseUrl, text_query.c_str(), kLanguage, + expected_search_context.c_str()); EXPECT_EQ(lens::BuildTextOnlySearchURL( text_query, std::make_optional<GURL>(kPageUrl), - std::make_optional<std::string>(kPageTitle), additional_params), + std::make_optional<std::string>(kPageTitle), additional_params, + lens::LensOverlayInvocationSource::kAppMenu), expected_url); } @@ -130,14 +134,16 @@ std::string expected_search_context = EncodeSearchContext( std::make_optional<GURL>(kPageUrl), /*page_title=*/std::nullopt); - std::string expected_url = - base::StringPrintf("%s?q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s&mactx=%s", - kResultsSearchBaseUrl, text_query.c_str(), kLanguage, - expected_search_context.c_str()); + std::string expected_url = base::StringPrintf( + "%s?source=chrome.cr.menu&q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s&" + "mactx=%s", + kResultsSearchBaseUrl, text_query.c_str(), kLanguage, + expected_search_context.c_str()); EXPECT_EQ(lens::BuildTextOnlySearchURL( text_query, std::make_optional<GURL>(kPageUrl), - /*page_title=*/std::nullopt, additional_params), + /*page_title=*/std::nullopt, additional_params, + lens::LensOverlayInvocationSource::kAppMenu), expected_url); } @@ -147,29 +153,32 @@ std::string expected_search_context = EncodeSearchContext( /*page_url=*/std::nullopt, std::make_optional<std::string>(kPageTitle)); - std::string expected_url = - base::StringPrintf("%s?q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s&mactx=%s", - kResultsSearchBaseUrl, text_query.c_str(), kLanguage, - expected_search_context.c_str()); + std::string expected_url = base::StringPrintf( + "%s?source=chrome.cr.menu&q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s&" + "mactx=%s", + kResultsSearchBaseUrl, text_query.c_str(), kLanguage, + expected_search_context.c_str()); EXPECT_EQ(lens::BuildTextOnlySearchURL( text_query, /*page_url=*/std::nullopt, - std::make_optional<std::string>(kPageTitle), additional_params), + std::make_optional<std::string>(kPageTitle), additional_params, + lens::LensOverlayInvocationSource::kAppMenu), expected_url); } TEST_F(LensOverlayUrlBuilderTest, BuildTextOnlySearchURLEmpty) { std::string text_query = ""; std::map<std::string, std::string> additional_params; - std::string expected_url = - base::StringPrintf("%s?q=&lns_mode=text&gsc=1&masfc=c&hl=%s", - kResultsSearchBaseUrl, kLanguage); + std::string expected_url = base::StringPrintf( + "%s?source=chrome.cr.menu&q=&lns_mode=text&gsc=1&masfc=c&hl=%s", + kResultsSearchBaseUrl, kLanguage); - EXPECT_EQ(lens::BuildTextOnlySearchURL(text_query, - /*page_url=*/std::nullopt, - /*page_title=*/std::nullopt, - additional_params), + EXPECT_EQ(lens::BuildTextOnlySearchURL( + text_query, + /*page_url=*/std::nullopt, + /*page_title=*/std::nullopt, additional_params, + lens::LensOverlayInvocationSource::kAppMenu), expected_url); } @@ -179,13 +188,14 @@ std::string escaped_text_query = base::EscapeQueryParamValue(text_query, /*use_plus=*/true); std::string expected_url = base::StringPrintf( - "%s?q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s", kResultsSearchBaseUrl, - escaped_text_query.c_str(), kLanguage); + "%s?source=chrome.cr.menu&q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s", + kResultsSearchBaseUrl, escaped_text_query.c_str(), kLanguage); - EXPECT_EQ(lens::BuildTextOnlySearchURL(text_query, - /*page_url=*/std::nullopt, - /*page_title=*/std::nullopt, - additional_params), + EXPECT_EQ(lens::BuildTextOnlySearchURL( + text_query, + /*page_url=*/std::nullopt, + /*page_title=*/std::nullopt, additional_params, + lens::LensOverlayInvocationSource::kAppMenu), expected_url); } @@ -195,13 +205,14 @@ std::string escaped_text_query = base::EscapeQueryParamValue(text_query, /*use_plus=*/true); std::string expected_url = base::StringPrintf( - "%s?q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s", kResultsSearchBaseUrl, - escaped_text_query.c_str(), kLanguage); + "%s?source=chrome.cr.menu&q=%s&lns_mode=text&gsc=1&masfc=c&hl=%s", + kResultsSearchBaseUrl, escaped_text_query.c_str(), kLanguage); - EXPECT_EQ(lens::BuildTextOnlySearchURL(text_query, - /*page_url=*/std::nullopt, - /*page_title=*/std::nullopt, - additional_params), + EXPECT_EQ(lens::BuildTextOnlySearchURL( + text_query, + /*page_url=*/std::nullopt, + /*page_title=*/std::nullopt, additional_params, + lens::LensOverlayInvocationSource::kAppMenu), expected_url); } @@ -222,12 +233,14 @@ request_id->set_image_sequence_id(image_sequence_id); std::string expected_url = base::StringPrintf( - "%s?gsc=1&masfc=c&hl=%s&q=%s&lns_mode=mu&gsessionid=&udm=24&vsrid=%s", + "%s?source=chrome.cr.menu&gsc=1&masfc=c&hl=%s&q=%s&lns_mode=mu&" + "gsessionid=&udm=24&vsrid=%s", kResultsSearchBaseUrl, kLanguage, escaped_text_query.c_str(), EncodeRequestId(request_id.get()).c_str()); - EXPECT_EQ(lens::BuildLensSearchURL(text_query, std::move(request_id), - cluster_info, additional_params), + EXPECT_EQ(lens::BuildLensSearchURL( + text_query, std::move(request_id), cluster_info, + additional_params, lens::LensOverlayInvocationSource::kAppMenu), expected_url); } @@ -250,12 +263,14 @@ request_id->set_image_sequence_id(image_sequence_id); std::string expected_url = base::StringPrintf( - "%s?gsc=1&masfc=c&hl=%s&q=%s&lns_mode=mu&gsessionid=%s&udm=24&vsrid=%s", + "%s?source=chrome.cr.menu&gsc=1&masfc=c&hl=%s&q=%s&lns_mode=mu&" + "gsessionid=%s&udm=24&vsrid=%s", kResultsSearchBaseUrl, kLanguage, escaped_text_query.c_str(), search_session_id.c_str(), EncodeRequestId(request_id.get()).c_str()); - EXPECT_EQ(lens::BuildLensSearchURL(text_query, std::move(request_id), - cluster_info, additional_params), + EXPECT_EQ(lens::BuildLensSearchURL( + text_query, std::move(request_id), cluster_info, + additional_params, lens::LensOverlayInvocationSource::kAppMenu), expected_url); } @@ -282,14 +297,16 @@ &encoded_request_id); std::string expected_url = base::StringPrintf( - "%s?gsc=1&masfc=c&hl=%s&q=&lns_mode=un&gsessionid=%s&udm=26&vsrid=%s", + "%s?source=chrome.cr.menu&gsc=1&masfc=c&hl=%s&q=&lns_mode=un&" + "gsessionid=%s&udm=26&vsrid=%s", kResultsSearchBaseUrl, kLanguage, search_session_id.c_str(), encoded_request_id.c_str()); - EXPECT_EQ(lens::BuildLensSearchURL(/*text_query=*/std::nullopt, - std::move(request_id), cluster_info, - additional_params), - expected_url); + EXPECT_EQ( + lens::BuildLensSearchURL( + /*text_query=*/std::nullopt, std::move(request_id), cluster_info, + additional_params, lens::LensOverlayInvocationSource::kAppMenu), + expected_url); } TEST_F(LensOverlayUrlBuilderTest, BuildLensSearchURLWithAdditionalParams) { @@ -315,15 +332,17 @@ &encoded_request_id); std::string expected_url = base::StringPrintf( - "%s?param=value&gsc=1&masfc=c&hl=%s&q=&lns_mode=un&gsessionid=%s&udm=26&" + "%s?source=chrome.cr.menu¶m=value&gsc=1&masfc=c&hl=%s&q=&lns_" + "mode=un&gsessionid=%s&udm=26&" "vsrid=%s", kResultsSearchBaseUrl, kLanguage, search_session_id.c_str(), encoded_request_id.c_str()); - EXPECT_EQ(lens::BuildLensSearchURL(/*text_query=*/std::nullopt, - std::move(request_id), cluster_info, - additional_params), - expected_url); + EXPECT_EQ( + lens::BuildLensSearchURL( + /*text_query=*/std::nullopt, std::move(request_id), cluster_info, + additional_params, lens::LensOverlayInvocationSource::kAppMenu), + expected_url); } TEST_F(LensOverlayUrlBuilderTest, HasCommonSearchQueryParameters) { @@ -364,6 +383,50 @@ EXPECT_FALSE(lens::HasCommonSearchQueryParameters(failing_url6)); } +TEST_F(LensOverlayUrlBuilderTest, + AppendInvocationSourceParamToUrlAppendsEntryPoints) { + const GURL base_url(kResultsSearchBaseUrl); + + std::string expected_app_menu_url = + base::StringPrintf("%s?source=chrome.cr.menu", kResultsSearchBaseUrl); + EXPECT_EQ(lens::AppendInvocationSourceParamToURL( + base_url, lens::LensOverlayInvocationSource::kAppMenu), + expected_app_menu_url); + + std::string expected_context_menu_page_url = + base::StringPrintf("%s?source=chrome.cr.ctxp", kResultsSearchBaseUrl); + EXPECT_EQ(lens::AppendInvocationSourceParamToURL( + base_url, + lens::LensOverlayInvocationSource::kContentAreaContextMenuPage), + expected_context_menu_page_url); + + std::string expected_context_menu_image_url = + base::StringPrintf("%s?source=chrome.cr.ctxi", kResultsSearchBaseUrl); + EXPECT_EQ( + lens::AppendInvocationSourceParamToURL( + base_url, + lens::LensOverlayInvocationSource::kContentAreaContextMenuImage), + expected_context_menu_image_url); + + std::string expected_toolbar_url = + base::StringPrintf("%s?source=chrome.cr.tbic", kResultsSearchBaseUrl); + EXPECT_EQ(lens::AppendInvocationSourceParamToURL( + base_url, lens::LensOverlayInvocationSource::kToolbar), + expected_toolbar_url); + + std::string expected_find_in_page_url = + base::StringPrintf("%s?source=chrome.cr.find", kResultsSearchBaseUrl); + EXPECT_EQ(lens::AppendInvocationSourceParamToURL( + base_url, lens::LensOverlayInvocationSource::kFindInPage), + expected_find_in_page_url); + + std::string expected_omnibox_url = + base::StringPrintf("%s?source=chrome.cr.obic", kResultsSearchBaseUrl); + EXPECT_EQ(lens::AppendInvocationSourceParamToURL( + base_url, lens::LensOverlayInvocationSource::kOmnibox), + expected_omnibox_url); +} + TEST_F(LensOverlayUrlBuilderTest, HasCommonSearchQueryParametersNoQueryParams) { const GURL url(kResultsSearchBaseUrl); EXPECT_FALSE(lens::HasCommonSearchQueryParameters(url)); @@ -394,4 +457,20 @@ EXPECT_FALSE(lens::IsValidSearchResultsUrl(GURL())); } +TEST_F(LensOverlayUrlBuilderTest, RemoveViewportParamFromURL) { + std::string text_query = "Apples"; + std::string viewport_width = "400"; + std::string viewport_height = "500"; + std::string initial_url = + base::StringPrintf("%s?q=%s&gsc=1&masfc=c&hl=%s&biw=%s&bih=%s", + kResultsSearchBaseUrl, text_query.c_str(), kLanguage, + viewport_width.c_str(), viewport_height.c_str()); + std::string expected_url = + base::StringPrintf("%s?q=%s&gsc=1&masfc=c&hl=%s", kResultsSearchBaseUrl, + text_query.c_str(), kLanguage); + + EXPECT_EQ(lens::RemoveUrlViewportParams(GURL(initial_url)), + GURL(expected_url)); +} + } // namespace lens
diff --git a/chrome/browser/ui/views/accessibility/accessibility_focus_highlight_browsertest.cc b/chrome/browser/ui/views/accessibility/accessibility_focus_highlight_browsertest.cc index 8c379ff4..2ef1c722 100644 --- a/chrome/browser/ui/views/accessibility/accessibility_focus_highlight_browsertest.cc +++ b/chrome/browser/ui/views/accessibility/accessibility_focus_highlight_browsertest.cc
@@ -27,7 +27,6 @@ #include "content/public/test/browser_test_utils.h" #include "content/public/test/focus_changed_observer.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/accessibility/accessibility_features.h" #include "ui/compositor/layer.h" #include "ui/gfx/image/image.h" #include "ui/snapshot/snapshot.h" @@ -58,8 +57,6 @@ // InProcessBrowserTest overrides: void SetUp() override { EnablePixelOutput(); - scoped_feature_list_.InitAndEnableFeature( - features::kAccessibilityFocusHighlight); InProcessBrowserTest::SetUp(); } @@ -125,9 +122,6 @@ return result_image; } } - - private: - base::test::ScopedFeatureList scoped_feature_list_; }; // Smoke test that ensures that when a node gets focus, the layer with the
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc index d37021f9..4665bb6 100644 --- a/chrome/browser/ui/views/find_bar_view.cc +++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/ui/find_bar/find_bar_state.h" #include "chrome/browser/ui/find_bar/find_bar_state_factory.h" #include "chrome/browser/ui/lens/lens_overlay_controller.h" +#include "chrome/browser/ui/lens/lens_overlay_invocation_source.h" #include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/find_bar_host.h" @@ -305,7 +306,7 @@ CHECK(controller); controller->ShowUI( - LensOverlayController::InvocationSource::kFindInPage); + lens::LensOverlayInvocationSource::kFindInPage); UserEducationService::MaybeNotifyPromoFeatureUsed( web_contents->GetBrowserContext(), lens::features::kLensOverlay);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc index 3df8d9e..5d7494c 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
@@ -142,7 +142,10 @@ #if BUILDFLAG(IS_CHROMEOS_LACROS) frame->GetNativeWindow()->SetEventTargeter( - std::make_unique<chromeos::InteriorResizeHandleTargeter>()); + std::make_unique<chromeos::InteriorResizeHandleTargeter>( + base::BindRepeating([](const aura::Window* window) { + return window->GetProperty(chromeos::kWindowStateTypeKey); + }))); #endif // TODO: b/330360595 - Confirm if this is needed in Lacros.
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc index 00039ad..040bfc5b 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc
@@ -215,6 +215,41 @@ EXPECT_EQ(HTCLIENT, frame_view->NonClientHitTest(top_edge)); } +// Regression test for crbug.com/40945061. Asserts that the content window +// accepts input from the edge of the browser frame when the browser is +// maximized. +IN_PROC_BROWSER_TEST_P(BrowserNonClientFrameViewChromeOSTestNoWebUiTabStrip, + ContentWindowAcceptsEdgeInputsWhenMaximized) { + BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); + content::WebContents* web_contents = browser_view->GetActiveWebContents(); + views::Widget* widget = browser_view->GetWidget(); + const BrowserNonClientFrameViewChromeOS* frame_view = + GetFrameViewChromeOS(browser_view); + + // Maximize the widget. + EXPECT_FALSE(widget->IsMaximized()); + const gfx::Rect old_bounds = frame_view->bounds(); + widget->Maximize(); + auto* window = widget->GetNativeWindow(); + ASSERT_TRUE(base::test::RunUntil([&]() { + return window->GetProperty(chromeos::kWindowStateTypeKey) == + chromeos::WindowStateType::kMaximized; + })); + // TODO(crbug.com/40276379): Remove waiting for bounds change when the bug + // is fixed. + ASSERT_TRUE(base::test::RunUntil( + [&]() { return frame_view->bounds() != old_bounds; })); + + // Assert that input events at the edge of the browser are propagated to the + // web contents window. + EXPECT_FALSE(web_contents->GetFocusedFrame()); + ui::test::EventGenerator event_generator(window->GetRootWindow()); + ASSERT_NO_FATAL_FAILURE( + event_generator.GestureTapAt(frame_view->bounds().left_center())); + ASSERT_TRUE(base::test::RunUntil( + [&]() { return !!web_contents->GetFocusedFrame(); })); +} + using BrowserNonClientFrameViewChromeOSTouchTest = TopChromeTouchTest<ChromeOSBrowserUITest>;
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index e4ebca4..e2cec03 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -234,7 +234,6 @@ #include "extensions/common/command.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/permissions/permission_utils.h" -#include "ui/accessibility/accessibility_features.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_mode_observer.h" #include "ui/accessibility/ax_node_data.h" @@ -1343,8 +1342,7 @@ } #if !BUILDFLAG(IS_CHROMEOS_ASH) - if (features::IsAccessibilityFocusHighlightEnabled() && - !accessibility_focus_highlight_) { + if (!accessibility_focus_highlight_) { accessibility_focus_highlight_ = std::make_unique<AccessibilityFocusHighlight>(this); }
diff --git a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc index 636be12..2c97135 100644 --- a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc
@@ -67,6 +67,8 @@ #endif #if BUILDFLAG(IS_CHROMEOS_LACROS) +#include "chromeos/ui/base/window_properties.h" +#include "chromeos/ui/base/window_state_type.h" #include "chromeos/ui/frame/interior_resize_handler_targeter.h" #endif @@ -602,7 +604,10 @@ #if BUILDFLAG(IS_CHROMEOS_LACROS) frame->GetNativeWindow()->SetEventTargeter( - std::make_unique<chromeos::InteriorResizeHandleTargeter>()); + std::make_unique<chromeos::InteriorResizeHandleTargeter>( + base::BindRepeating([](const aura::Window* window) { + return window->GetProperty(chromeos::kWindowStateTypeKey); + }))); #endif }
diff --git a/chrome/browser/ui/views/mahi/BUILD.gn b/chrome/browser/ui/views/mahi/BUILD.gn index fbe5080..44743f2e 100644 --- a/chrome/browser/ui/views/mahi/BUILD.gn +++ b/chrome/browser/ui/views/mahi/BUILD.gn
@@ -20,10 +20,12 @@ deps = [ "//base", "//chrome/browser/chromeos", + "//chrome/browser/ui/chromeos/magic_boost", "//chrome/browser/ui/chromeos/read_write_cards", "//chrome/browser/ui/views/editor_menu:utils", "//chromeos/components/editor_menu/public/cpp", "//chromeos/components/mahi/public/cpp", + "//chromeos/constants:constants", "//chromeos/strings:strings_grit", "//chromeos/ui/vector_icons", "//ui/color",
diff --git a/chrome/browser/ui/views/mahi/mahi_menu_controller.cc b/chrome/browser/ui/views/mahi/mahi_menu_controller.cc index b17b0cb..0704047a 100644 --- a/chrome/browser/ui/views/mahi/mahi_menu_controller.cc +++ b/chrome/browser/ui/views/mahi/mahi_menu_controller.cc
@@ -9,12 +9,14 @@ #include "base/command_line.h" #include "base/metrics/histogram_functions.h" #include "chrome/browser/chromeos/mahi/mahi_web_contents_manager.h" +#include "chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h" #include "chrome/browser/ui/chromeos/read_write_cards/read_write_cards_ui_controller.h" #include "chrome/browser/ui/views/mahi/mahi_condensed_menu_view.h" #include "chrome/browser/ui/views/mahi/mahi_menu_constants.h" #include "chrome/browser/ui/views/mahi/mahi_menu_view.h" #include "chromeos/components/mahi/public/cpp/mahi_manager.h" #include "chromeos/components/mahi/public/cpp/mahi_switches.h" +#include "chromeos/constants/chromeos_features.h" #include "ui/views/view_utils.h" namespace chromeos::mahi { @@ -50,6 +52,12 @@ return; } + if (features::IsMagicBoostEnabled() && + MagicBoostController::Get()->ShouldQuickAnswersAndMahiShowOptIn()) { + MagicBoostController::Get()->ShowOptInUi(); + return; + } + if (selected_text.empty()) { menu_widget_ = MahiMenuView::CreateWidget(anchor_bounds); menu_widget_->ShowInactive(); @@ -76,6 +84,10 @@ menu_widget_.reset(); } + if (features::IsMagicBoostEnabled()) { + MagicBoostController::Get()->CloseOptInUi(); + } + read_write_cards_ui_controller_->RemoveMahiUi(); }
diff --git a/chrome/browser/ui/views/mahi/mahi_menu_controller_unittest.cc b/chrome/browser/ui/views/mahi/mahi_menu_controller_unittest.cc index 78f5bdf..3dee4ec5 100644 --- a/chrome/browser/ui/views/mahi/mahi_menu_controller_unittest.cc +++ b/chrome/browser/ui/views/mahi/mahi_menu_controller_unittest.cc
@@ -13,6 +13,8 @@ #include "build/chromeos_buildflags.h" #include "chrome/browser/chromeos/mahi/test/fake_mahi_web_contents_manager.h" #include "chrome/browser/chromeos/mahi/test/scoped_mahi_web_contents_manager_for_testing.h" +#include "chrome/browser/ui/chromeos/magic_boost/magic_boost_controller.h" +#include "chrome/browser/ui/chromeos/magic_boost/test/mock_magic_boost_controller.h" #include "chrome/browser/ui/chromeos/read_write_cards/read_write_cards_ui_controller.h" #include "chrome/browser/ui/views/editor_menu/utils/utils.h" #include "chrome/browser/ui/views/mahi/mahi_condensed_menu_view.h" @@ -35,10 +37,28 @@ namespace chromeos::mahi { using ::testing::IsNull; +using ::testing::Mock; +using ::testing::NiceMock; +using ::testing::Return; -class MahiMenuControllerTest : public ChromeViewsTestBase { +class MahiMenuControllerTest : public ChromeViewsTestBase, + public testing::WithParamInterface<bool> { public: MahiMenuControllerTest() { + if (IsMagicBoostEnabled()) { + feature_list_.InitWithFeatures( + /*enabled_features=*/{features::kMahi, features::kMagicBoost}, + /*disabled_features=*/{}); + + scoped_magic_boost_controller_ = + std::make_unique<ScopedMagicBoostControllerForTesting>( + &mock_magic_boost_controller_); + } else { + feature_list_.InitWithFeatures( + /*enabled_features=*/{features::kMahi}, + /*disabled_features=*/{features::kMagicBoost}); + } + menu_controller_ = std::make_unique<MahiMenuController>(read_write_cards_ui_controller_); @@ -52,6 +72,8 @@ ChangePrefValue(true); } + bool IsMagicBoostEnabled() const { return GetParam(); } + MahiMenuControllerTest(const MahiMenuControllerTest&) = delete; MahiMenuControllerTest& operator=(const MahiMenuControllerTest&) = delete; @@ -59,6 +81,10 @@ MahiMenuController* menu_controller() { return menu_controller_.get(); } + MockMagicBoostController& mock_magic_boost_controller() { + return mock_magic_boost_controller_; + } + void ChangePageDistillability(bool value) { fake_mahi_web_contents_manager_.set_focused_web_content_is_distillable( value); @@ -72,22 +98,30 @@ ReadWriteCardsUiController read_write_cards_ui_controller_; private: + base::test::ScopedFeatureList feature_list_; + +#if BUILDFLAG(IS_CHROMEOS_ASH) + base::AutoReset<bool> ignore_mahi_secret_key_ = + ash::switches::SetIgnoreMahiSecretKeyForTest(); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + std::unique_ptr<MahiMenuController> menu_controller_; ::mahi::FakeMahiWebContentsManager fake_mahi_web_contents_manager_; std::unique_ptr<::mahi::ScopedMahiWebContentsManagerForTesting> scoped_mahi_web_contents_manager_; - base::test::ScopedFeatureList feature_list_{chromeos::features::kMahi}; -#if BUILDFLAG(IS_CHROMEOS_ASH) - base::AutoReset<bool> ignore_mahi_secret_key_ = - ash::switches::SetIgnoreMahiSecretKeyForTest(); -#endif // BUILDFLAG(IS_CHROMEOS_ASH) + NiceMock<MockMagicBoostController> mock_magic_boost_controller_; + std::unique_ptr<ScopedMagicBoostControllerForTesting> + scoped_magic_boost_controller_; }; // Tests the behavior of the controller when there's no text selected when // `OnTextAvailable()` is triggered. -TEST_F(MahiMenuControllerTest, TextNotSelected) { +TEST_P(MahiMenuControllerTest, TextNotSelected) { + ON_CALL(mock_magic_boost_controller(), ShouldQuickAnswersAndMahiShowOptIn) + .WillByDefault(Return(false)); + EXPECT_FALSE(menu_controller()->menu_widget_for_test()); // Menu widget should show when text is displayed. @@ -115,7 +149,7 @@ // Tests the behavior of the controller when `OnAnchorBoundsChanged()` is // triggered. -TEST_F(MahiMenuControllerTest, BoundsChanged) { +TEST_P(MahiMenuControllerTest, BoundsChanged) { EXPECT_FALSE(menu_controller()->menu_widget_for_test()); gfx::Rect anchor_bounds = gfx::Rect(50, 50, 25, 100); @@ -140,7 +174,10 @@ // Tests the behavior of the controller when there's text selected when // `OnTextAvailable()` is triggered. -TEST_F(MahiMenuControllerTest, TextSelected) { +TEST_P(MahiMenuControllerTest, TextSelected) { + ON_CALL(mock_magic_boost_controller(), ShouldQuickAnswersAndMahiShowOptIn) + .WillByDefault(Return(false)); + EXPECT_FALSE(read_write_cards_ui_controller_.widget_for_test()); // Menu widget should show when text is displayed. @@ -160,8 +197,75 @@ EXPECT_FALSE(read_write_cards_ui_controller_.GetMahiUiForTest()); } +TEST_P(MahiMenuControllerTest, ShowOptInUiTextNotSelected) { + ON_CALL(mock_magic_boost_controller(), ShouldQuickAnswersAndMahiShowOptIn) + .WillByDefault(Return(true)); + + // `ShowOptInUi` should be called when Magic Boost is enabled. + if (IsMagicBoostEnabled()) { + EXPECT_CALL(mock_magic_boost_controller(), ShowOptInUi); + menu_controller()->OnTextAvailable(/*anchor_bounds=*/gfx::Rect(), + /*selected_text=*/"", + /*surrounding_text=*/""); + + EXPECT_CALL(mock_magic_boost_controller(), CloseOptInUi); + menu_controller()->OnDismiss(/*is_other_command_executed=*/false); + + Mock::VerifyAndClear(&mock_magic_boost_controller()); + return; + } + + // Otherwise, no opt in UI is shown and `MahiMenuView` is shown. + EXPECT_CALL(mock_magic_boost_controller(), ShowOptInUi).Times(0); + menu_controller()->OnTextAvailable(/*anchor_bounds=*/gfx::Rect(), + /*selected_text=*/"", + /*surrounding_text=*/""); + + EXPECT_TRUE(menu_controller()->menu_widget_for_test()); + EXPECT_TRUE(menu_controller()->menu_widget_for_test()->IsVisible()); + EXPECT_TRUE(views::IsViewClass<MahiMenuView>( + menu_controller()->menu_widget_for_test()->GetContentsView())); + + EXPECT_CALL(mock_magic_boost_controller(), CloseOptInUi).Times(0); + menu_controller()->OnDismiss(/*is_other_command_executed=*/false); +} + +TEST_P(MahiMenuControllerTest, ShowOptInUiTextSelected) { + ON_CALL(mock_magic_boost_controller(), ShouldQuickAnswersAndMahiShowOptIn) + .WillByDefault(Return(true)); + + // `ShowOptInUi` should be called when Magic Boost is enabled. + if (IsMagicBoostEnabled()) { + EXPECT_CALL(mock_magic_boost_controller(), ShowOptInUi); + menu_controller()->OnTextAvailable(/*anchor_bounds=*/gfx::Rect(), + /*selected_text=*/"test selected text", + /*surrounding_text=*/""); + + EXPECT_CALL(mock_magic_boost_controller(), CloseOptInUi); + menu_controller()->OnDismiss(/*is_other_command_executed=*/false); + + Mock::VerifyAndClear(&mock_magic_boost_controller()); + return; + } + + // Otherwise, no opt in UI is shown and the condense menu view is shown. + EXPECT_CALL(mock_magic_boost_controller(), ShowOptInUi).Times(0); + menu_controller()->OnTextAvailable(/*anchor_bounds=*/gfx::Rect(), + /*selected_text=*/"test selected text", + /*surrounding_text=*/""); + + EXPECT_TRUE(read_write_cards_ui_controller_.widget_for_test()); + EXPECT_TRUE(read_write_cards_ui_controller_.widget_for_test()->IsVisible()); + EXPECT_TRUE(read_write_cards_ui_controller_.GetMahiUiForTest()); + EXPECT_TRUE(views::IsViewClass<MahiCondensedMenuView>( + read_write_cards_ui_controller_.GetMahiUiForTest())); + + EXPECT_CALL(mock_magic_boost_controller(), CloseOptInUi).Times(0); + menu_controller()->OnDismiss(/*is_other_command_executed=*/false); +} + // Tests the behavior of the controller when pref state changed. -TEST_F(MahiMenuControllerTest, PrefChange) { +TEST_P(MahiMenuControllerTest, PrefChange) { EXPECT_FALSE(menu_controller()->menu_widget_for_test()); // Menu widget should show when text is displayed as the default is that Mahi @@ -197,7 +301,7 @@ menu_controller()->menu_widget_for_test()->GetContentsView())); } -TEST_F(MahiMenuControllerTest, DistillableMetrics) { +TEST_P(MahiMenuControllerTest, DistillableMetrics) { base::HistogramTester histogram_tester; histogram_tester.ExpectBucketCount(kMahiContextMenuDistillableHistogram, true, @@ -227,6 +331,10 @@ false, 1); } +INSTANTIATE_TEST_SUITE_P(All, + MahiMenuControllerTest, + /*IsMagicBoostEnabled()=*/testing::Bool()); + #if BUILDFLAG(IS_CHROMEOS_ASH) class MahiMenuControllerFeatureKeyTest : public ChromeViewsTestBase { public:
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index eeb24d2..431c9ed 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -89,7 +89,6 @@ #include "ui/base/models/list_selection_model.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/theme_provider.h" -#include "ui/base/ui_base_features.h" #include "ui/color/color_provider.h" #include "ui/display/display.h" #include "ui/gfx/animation/throb_animation.h" @@ -1260,7 +1259,7 @@ // The Tabstrip in the refreshed style does not meet the contrast ratio // requirements listed below but does not have strokes for Tabs or the bottom // border. - if (features::IsChromeRefresh2023() && !using_system_theme) { + if (!using_system_theme) { return false; }
diff --git a/chrome/browser/ui/views/tabs/tab_strip_control_button.cc b/chrome/browser/ui/views/tabs/tab_strip_control_button.cc index 529be298..d0ee903b5 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_control_button.cc +++ b/chrome/browser/ui/views/tabs/tab_strip_control_button.cc
@@ -12,7 +12,6 @@ #include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h" #include "third_party/skia/include/core/SkPath.h" #include "ui/base/metadata/metadata_impl_macros.h" -#include "ui/base/ui_base_features.h" #include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/gfx/geometry/skia_conversions.h" #include "ui/gfx/vector_icon_types.h" @@ -93,10 +92,6 @@ SetImageCentered(true); SetEventTargeter(std::make_unique<views::ViewTargeter>(this)); - // By default control buttons in the tab strip should be non-transparent for - // the updated Chrome refresh UX. - paint_transparent_for_custom_image_theme_ = !features::IsChromeRefresh2023(); - foreground_frame_active_color_id_ = kColorTabForegroundInactiveFrameActive; foreground_frame_inactive_color_id_ = kColorNewTabButtonCRForegroundFrameInactive; @@ -111,9 +106,7 @@ SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); - if (features::IsChromeRefresh2023()) { - views::InkDrop::Get(this)->SetLayerRegion(views::LayerRegion::kAbove); - } + views::InkDrop::Get(this)->SetLayerRegion(views::LayerRegion::kAbove); views::HighlightPathGenerator::Install( this, std::make_unique<ControlButtonHighlightPathGenerator>(this)); UpdateInkDrop(); @@ -187,22 +180,8 @@ return; } - if (features::IsChromeRefresh2023()) { - CreateToolbarInkdropCallbacks(this, kColorTabStripControlButtonInkDrop, - kColorTabStripControlButtonInkDropRipple); - } else { - const bool frame_active = - (GetWidget() && GetWidget()->ShouldPaintAsActive()); - - // These values are also used in refresh by - // `kColorTabStripControlButtonInkDrop` and - // `kColorTabStripControlButtonInkDropRipple` in case of themes. - views::InkDrop::Get(this)->SetHighlightOpacity(0.16f); - views::InkDrop::Get(this)->SetVisibleOpacity(0.14f); - views::InkDrop::Get(this)->SetBaseColor(color_provider->GetColor( - frame_active ? kColorNewTabButtonInkDropFrameActive - : kColorNewTabButtonInkDropFrameInactive)); - } + CreateToolbarInkdropCallbacks(this, kColorTabStripControlButtonInkDrop, + kColorTabStripControlButtonInkDropRipple); } void TabStripControlButton::UpdateColors() {
diff --git a/chrome/browser/ui/views/tabs/tab_strip_control_button.h b/chrome/browser/ui/views/tabs/tab_strip_control_button.h index fbb2a668..c12fb1d3 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_control_button.h +++ b/chrome/browser/ui/views/tabs/tab_strip_control_button.h
@@ -113,7 +113,7 @@ // Optional icon for the label button. raw_ref<const gfx::VectorIcon> icon_; - bool paint_transparent_for_custom_image_theme_; + bool paint_transparent_for_custom_image_theme_ = false; // Button edge which should render without rounded corners. Edge flat_edge_;
diff --git a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc index abc9fb1..07194e26a 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc +++ b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
@@ -589,11 +589,9 @@ EXPECT_TRUE(second_tab->closing()); } -TEST_P(TabStripTest, ChangingLayoutTypeResizesTabs) { - // TODO (crbug/1520595): Skip for now due to test failing when CR2023 enabled. - if (features::IsChromeRefresh2023()) { - GTEST_SKIP(); - } +// TODO (crbug.com/1520595): Disabled for now due to test failing when CR2023 +// enabled. +TEST_P(TabStripTest, DISABLED_ChangingLayoutTypeResizesTabs) { SetMaxTabStripWidth(1000); controller_->AddTab(0, TabActive::kInactive);
diff --git a/chrome/browser/ui/views/user_education/browser_user_education_service.cc b/chrome/browser/ui/views/user_education/browser_user_education_service.cc index 5738862..d8c343819 100644 --- a/chrome/browser/ui/views/user_education/browser_user_education_service.cc +++ b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
@@ -558,6 +558,40 @@ #endif // !BUILDFLAG(IS_CHROMEOS_ASH) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) + // kIPHExplicitBrowserSigninPreferenceRememberedFeature: + registry.RegisterFeature(std::move( + FeaturePromoSpecification::CreateForCustomAction( + feature_engagement:: + kIPHExplicitBrowserSigninPreferenceRememberedFeature, + kToolbarAvatarButtonElementId, + IDS_SIGNIN_DICE_WEB_INTERCEPT_BUBBLE_CHROME_SIGNIN_IPH_TEXT_SIGNIN, + IDS_SIGNIN_DICE_WEB_INTERCEPT_BUBBLE_CHROME_SIGNIN_IPH_SETTINGS_BUTTON, + base::BindRepeating([](ui::ElementContext ctx, + user_education::FeaturePromoHandle + promo_handle) { + auto* browser = chrome::FindBrowserWithUiElementContext(ctx); + if (!browser) { + return; + } + ShowPromoInPage::Params params; + params.bubble_anchor_id = kToolbarAvatarButtonElementId; + params.bubble_arrow = user_education::HelpBubbleArrow::kTopRight; + params.bubble_text = l10n_util::GetStringUTF16( + IDS_SIGNIN_DICE_WEB_INTERCEPT_BUBBLE_CHROME_SIGNIN_IPH_TEXT_SIGNIN); + ShowPromoInPage::Start(browser, std::move(params)); + chrome::ShowSettingsSubPage(browser, chrome::kSyncSetupSubPage); + base::RecordAction( + base::UserMetricsAction("ExplicitBrowserSigninPreferenceRemembe" + "red_IPHPromo_SettingsPageOpened")); + })) + .SetPromoSubtype(user_education::FeaturePromoSpecification:: + PromoSubtype::kKeyedNotice) + .SetBubbleTitleText( + IDS_SIGNIN_DICE_WEB_INTERCEPT_BUBBLE_CHROME_SIGNIN_IPH_TITLE_SIGNIN) + .SetCustomActionIsDefault(false))); +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) + // kIPHCookieControlsFeature: registry.RegisterFeature(std::move( FeaturePromoSpecification::CreateForCustomAction(
diff --git a/chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.cc b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.cc index 3173ea1a..6f411c7 100644 --- a/chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.cc +++ b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.cc
@@ -157,7 +157,8 @@ source->AddResourcePaths( base::make_span(kPasswordChangeResources, kPasswordChangeResourcesSize)); - source->SetDefaultResource(IDR_PASSWORD_CHANGE_CONFIRM_PASSWORD_CHANGE_HTML); + source->SetDefaultResource( + IDR_PASSWORD_CHANGE_CONFIRM_PASSWORD_CHANGE_APP_HTML); // The ConfirmPasswordChangeHandler is added by the dialog, so no need to add // it here.
diff --git a/chrome/browser/ui/webui/ash/settings/pages/files/files_section.cc b/chrome/browser/ui/webui/ash/settings/pages/files/files_section.cc index 212bb445..792f252 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/files/files_section.cc +++ b/chrome/browser/ui/webui/ash/settings/pages/files/files_section.cc
@@ -286,14 +286,12 @@ if (user && user->GetAccountId().is_valid()) { html_source->AddString( "googleDriveSignedInAs", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_GOOGLE_DRIVE_SIGNED_IN_AS, - base::ASCIIToUTF16(user->GetAccountId().GetUserEmail()))); + l10n_util::GetStringFUTF16(IDS_SETTINGS_GOOGLE_DRIVE_SIGNED_IN_AS, + base::ASCIIToUTF16(user->display_email()))); html_source->AddString( "googleDriveReconnectAs", - l10n_util::GetStringFUTF16( - IDS_SETTINGS_GOOGLE_DRIVE_RECONNECT_AS, - base::ASCIIToUTF16(user->GetAccountId().GetUserEmail()))); + l10n_util::GetStringFUTF16(IDS_SETTINGS_GOOGLE_DRIVE_RECONNECT_AS, + base::ASCIIToUTF16(user->display_email()))); } html_source->AddBoolean(
diff --git a/chrome/browser/ui/webui/history/browsing_history_handler.cc b/chrome/browser/ui/webui/history/browsing_history_handler.cc index 471244b..6435cc3 100644 --- a/chrome/browser/ui/webui/history/browsing_history_handler.cc +++ b/chrome/browser/ui/webui/history/browsing_history_handler.cc
@@ -174,7 +174,8 @@ UrlIdentity::Type::kDefault, UrlIdentity::Type::kFile, UrlIdentity::Type::kIsolatedWebApp, UrlIdentity::Type::kChromeExtension}; constexpr UrlIdentity::FormatOptions url_identity_options{ - .default_options = {UrlIdentity::DefaultFormatOptions::kHostname}}; + .default_options = {UrlIdentity::DefaultFormatOptions:: + kOmitSchemePathAndTrivialSubdomains}}; // Converts `entry` to a base::Value::Dict to be owned by the caller. base::Value::Dict HistoryEntryToValue(
diff --git a/chrome/browser/ui/webui/management/management_ui.cc b/chrome/browser/ui/webui/management/management_ui.cc index a32a79ab..716fee30 100644 --- a/chrome/browser/ui/webui/management/management_ui.cc +++ b/chrome/browser/ui/webui/management/management_ui.cc
@@ -161,6 +161,14 @@ {kManagementOnPageVisitedVisibleData, IDS_MANAGEMENT_PAGE_VISITED_VISIBLE_DATA}, {kManagementLegacyTechReport, IDS_MANAGEMENT_LEGACY_TECH_REPORT}, + // Profile reporting messages + {kProfileReportingExplanation, + IDS_MANAGEMENT_PROFILE_REPORTING_EXPLANATION}, + {kProfileReportingOverview, IDS_MANAGEMENT_PROFILE_REPORTING_OVERVIEW}, + {kProfileReportingUsername, IDS_MANAGEMENT_PROFILE_REPORTING_USERNAME}, + {kProfileReportingBrowser, IDS_MANAGEMENT_PROFILE_REPORTING_BROWSER}, + {kProfileReportingExtension, IDS_MANAGEMENT_PROFILE_REPORTING_EXTENSION}, + {kProfileReportingPolicy, IDS_MANAGEMENT_PROFILE_REPORTING_POLICY}, }; source->AddLocalizedStrings(kLocalizedStrings);
diff --git a/chrome/browser/ui/webui/management/management_ui_constants.cc b/chrome/browser/ui/webui/management/management_ui_constants.cc index 9c425c7..3b667db 100644 --- a/chrome/browser/ui/webui/management/management_ui_constants.cc +++ b/chrome/browser/ui/webui/management/management_ui_constants.cc
@@ -71,6 +71,13 @@ const char kReportingTypeUserActivity[] = "user-activity"; const char kReportingTypeLegacyTech[] = "legacy-tech"; +const char kProfileReportingExplanation[] = "profileReportingExplanation"; +const char kProfileReportingOverview[] = "profileReportingOverview"; +const char kProfileReportingUsername[] = "profileReportingUsername"; +const char kProfileReportingBrowser[] = "profileReportingBrowser"; +const char kProfileReportingExtension[] = "profileReportingExtension"; +const char kProfileReportingPolicy[] = "profileReportingPolicy"; + #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) const char kManagementScreenCaptureEvent[] = "managementScreenCaptureEvent"; const char kManagementScreenCaptureData[] = "managementScreenCaptureData";
diff --git a/chrome/browser/ui/webui/management/management_ui_constants.h b/chrome/browser/ui/webui/management/management_ui_constants.h index b072b0d..6e72ee4 100644 --- a/chrome/browser/ui/webui/management/management_ui_constants.h +++ b/chrome/browser/ui/webui/management/management_ui_constants.h
@@ -92,4 +92,11 @@ extern const char kReportingTypeUserActivity[]; extern const char kReportingTypeLegacyTech[]; +extern const char kProfileReportingExplanation[]; +extern const char kProfileReportingOverview[]; +extern const char kProfileReportingUsername[]; +extern const char kProfileReportingBrowser[]; +extern const char kProfileReportingExtension[]; +extern const char kProfileReportingPolicy[]; + #endif // CHROME_BROWSER_UI_WEBUI_MANAGEMENT_MANAGEMENT_UI_CONSTANTS_H_
diff --git a/chrome/browser/ui/webui/management/management_ui_handler.cc b/chrome/browser/ui/webui/management/management_ui_handler.cc index f0168eca..caddde9 100644 --- a/chrome/browser/ui/webui/management/management_ui_handler.cc +++ b/chrome/browser/ui/webui/management/management_ui_handler.cc
@@ -220,6 +220,10 @@ "initBrowserReportingInfo", base::BindRepeating(&ManagementUIHandler::HandleInitBrowserReportingInfo, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "initProfileReportingInfo", + base::BindRepeating(&ManagementUIHandler::HandleInitProfileReportingInfo, + base::Unretained(this))); } void ManagementUIHandler::OnJavascriptAllowed() { @@ -230,7 +234,8 @@ RemoveObservers(); } -void ManagementUIHandler::AddReportingInfo(base::Value::List* report_sources) { +void ManagementUIHandler::AddReportingInfo(base::Value::List* report_sources, + bool is_browser) { const policy::PolicyService* policy_service = GetPolicyService(); const policy::PolicyNamespace @@ -261,6 +266,9 @@ ->GetPrefs() ->GetList(enterprise_reporting::kCloudLegacyTechReportAllowlist) .empty(); + const bool cloud_profile_reporting_policy_enabled = + Profile::FromWebUI(web_ui())->GetPrefs()->GetBoolean( + enterprise_reporting::kCloudProfileReportingEnabled); if (cloud_legacy_tech_report_enabled) { Profile::FromWebUI(web_ui())->GetPrefs()->GetList( @@ -293,42 +301,58 @@ {kPolicyKeyReportUserBrowsingData, kManagementLegacyTechReport, ReportingType::kLegacyTech, cloud_legacy_tech_report_enabled}}; - std::unordered_set<const char*> enabled_messages; - - for (auto& report_definition : report_definitions) { - if (report_definition.cloud_reporting_enabled) { - enabled_messages.insert(report_definition.message); - } else if (report_definition.reporting_extension_policy_key) { - for (const policy::PolicyMap* policy_map : policy_maps) { - const base::Value* policy_value = policy_map->GetValue( - report_definition.reporting_extension_policy_key, - base::Value::Type::BOOLEAN); - if (policy_value && policy_value->GetBool()) { - enabled_messages.insert(report_definition.message); - break; + if (is_browser) { + std::unordered_set<const char*> enabled_messages; + for (auto& report_definition : report_definitions) { + if (report_definition.cloud_reporting_enabled) { + enabled_messages.insert(report_definition.message); + } else if (report_definition.reporting_extension_policy_key) { + for (const policy::PolicyMap* policy_map : policy_maps) { + const base::Value* policy_value = policy_map->GetValue( + report_definition.reporting_extension_policy_key, + base::Value::Type::BOOLEAN); + if (policy_value && policy_value->GetBool()) { + enabled_messages.insert(report_definition.message); + break; + } } } } - } - // The message with more data collected for kPolicyKeyReportMachineIdData - // trumps the one with less data. - if (enabled_messages.find(kManagementExtensionReportMachineNameAddress) != - enabled_messages.end()) { - enabled_messages.erase(kManagementExtensionReportMachineName); - } - - for (auto& report_definition : report_definitions) { - if (enabled_messages.find(report_definition.message) == + // The message with more data collected for kPolicyKeyReportMachineIdData + // trumps the one with less data. + if (enabled_messages.find(kManagementExtensionReportMachineNameAddress) != enabled_messages.end()) { - continue; + enabled_messages.erase(kManagementExtensionReportMachineName); } - base::Value::Dict data; - data.Set("messageId", report_definition.message); - data.Set("reportingType", - GetReportingTypeValue(report_definition.reporting_type)); - report_sources->Append(std::move(data)); + for (auto& report_definition : report_definitions) { + if (enabled_messages.find(report_definition.message) == + enabled_messages.end()) { + continue; + } + + base::Value::Dict data; + data.Set("messageId", report_definition.message); + data.Set("reportingType", + GetReportingTypeValue(report_definition.reporting_type)); + report_sources->Append(std::move(data)); + } + } else { + if (cloud_reporting_policy_enabled || + !cloud_profile_reporting_policy_enabled) { + return; + } + + const std::string messages[] = { + kProfileReportingOverview, kProfileReportingUsername, + kProfileReportingBrowser, kProfileReportingExtension, + kProfileReportingPolicy}; + for (const auto& message : messages) { + base::Value::Dict data; + data.Set("messageId", message); + report_sources->Append(std::move(data)); + } } #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) // Insert the device signals consent disclosure at the end of browser @@ -620,16 +644,30 @@ const base::Value::List& args) { base::Value::List report_sources; AllowJavascript(); - AddReportingInfo(&report_sources); + AddReportingInfo(&report_sources, /*is_browser=*/true); + ResolveJavascriptCallback(args[0] /* callback_id */, report_sources); +} + +void ManagementUIHandler::HandleInitProfileReportingInfo( + const base::Value::List& args) { + base::Value::List report_sources; + AllowJavascript(); + AddReportingInfo(&report_sources, /*is_browser=*/false); ResolveJavascriptCallback(args[0] /* callback_id */, report_sources); } void ManagementUIHandler::NotifyBrowserReportingInfoUpdated() { base::Value::List report_sources; - AddReportingInfo(&report_sources); + AddReportingInfo(&report_sources, /*is_browser=*/true); FireWebUIListener("browser-reporting-info-updated", report_sources); } +void ManagementUIHandler::NotifyProfileReportingInfoUpdated() { + base::Value::List report_sources; + AddReportingInfo(&report_sources, /*is_browser=*/false); + FireWebUIListener("profile-reporting-info-updated", report_sources); +} + void ManagementUIHandler::NotifyThreatProtectionInfoUpdated() { FireWebUIListener("threat-protection-info-updated", GetThreatProtectionInfo(Profile::FromWebUI(web_ui()))); @@ -660,6 +698,7 @@ const policy::PolicyMap& /*current*/) { UpdateManagedState(); NotifyBrowserReportingInfoUpdated(); + NotifyProfileReportingInfoUpdated(); NotifyThreatProtectionInfoUpdated(); }
diff --git a/chrome/browser/ui/webui/management/management_ui_handler.h b/chrome/browser/ui/webui/management/management_ui_handler.h index 67a6d3a1..d23c7850 100644 --- a/chrome/browser/ui/webui/management/management_ui_handler.h +++ b/chrome/browser/ui/webui/management/management_ui_handler.h
@@ -65,7 +65,7 @@ void OnJavascriptDisallowed() override; protected: - void AddReportingInfo(base::Value::List* report_sources); + void AddReportingInfo(base::Value::List* report_sources, bool is_browser); virtual base::Value::Dict GetContextualManagedData(Profile* profile); base::Value::Dict GetThreatProtectionInfo(Profile* profile); @@ -106,10 +106,12 @@ void HandleGetManagedWebsites(const base::Value::List& args); void HandleGetApplications(const base::Value::List& args); void HandleInitBrowserReportingInfo(const base::Value::List& args); + void HandleInitProfileReportingInfo(const base::Value::List& args); void AsyncUpdateLogo(); void NotifyBrowserReportingInfoUpdated(); + void NotifyProfileReportingInfoUpdated(); // extensions::ExtensionRegistryObserver implementation. void OnExtensionLoaded(content::BrowserContext* browser_context,
diff --git a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc index fa73436..8614a94 100644 --- a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc +++ b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
@@ -133,6 +133,7 @@ using testing::AssertionFailure; using testing::AssertionResult; using testing::AssertionSuccess; +using testing::Mock; using testing::Return; using testing::ReturnRef; @@ -252,7 +253,8 @@ return GetContextualManagedData(profile); } - base::Value::List GetReportingInfo(bool can_collect_signals = true) { + base::Value::List GetReportingInfo(bool can_collect_signals = true, + bool is_browser = true) { #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) EXPECT_CALL(mock_user_permission_service_, CanCollectSignals()) .WillOnce( @@ -261,7 +263,7 @@ : device_signals::UserPermission::kMissingConsent)); #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) base::Value::List report_sources; - AddReportingInfo(&report_sources); + AddReportingInfo(&report_sources, is_browser); return report_sources; } @@ -406,6 +408,7 @@ bool printing_send_username_and_filename; bool crostini_report_usage; bool cloud_reporting_enabled; + bool cloud_profile_reporting_enabled; std::string profile_name; bool override_policy_connector_is_managed; bool managed_account; @@ -439,6 +442,7 @@ setup_config_.printing_send_username_and_filename = default_value; setup_config_.crostini_report_usage = default_value; setup_config_.cloud_reporting_enabled = default_value; + setup_config_.cloud_profile_reporting_enabled = default_value; setup_config_.profile_name = ""; setup_config_.override_policy_connector_is_managed = false; setup_config_.managed_account = true; @@ -1594,6 +1598,28 @@ expected_messages); } +TEST_F(ManagementUIHandlerTests, CloudProfileReportingPolicy) { + ResetTestConfig(false); + SetUpProfileAndHandler(); + profile_->GetTestingPrefService()->SetManagedPref( + enterprise_reporting::kCloudProfileReportingEnabled, + std::make_unique<base::Value>(true)); + + std::set<std::string> expected_messages = { + kProfileReportingOverview, kProfileReportingUsername, + kProfileReportingBrowser, kProfileReportingExtension, + kProfileReportingPolicy}; + + ASSERT_PRED_FORMAT2(MessagesToBeEQ, + handler_.GetReportingInfo(/*can_collect_signals=*/false, + /*is_browser=*/true), + {}); + ASSERT_PRED_FORMAT2(MessagesToBeEQ, + handler_.GetReportingInfo(/*can_collect_signals=*/false, + /*is_browser=*/false), + expected_messages); +} + #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) TEST_F(ManagementUIHandlerTests, CloudReportingPolicyWithoutDeviceSignalsConsent) {
diff --git a/chrome/browser/updates/announcement_notification/announcement_notification_delegate_android.cc b/chrome/browser/updates/announcement_notification/announcement_notification_delegate_android.cc index 54acdb6..d6ea4a8 100644 --- a/chrome/browser/updates/announcement_notification/announcement_notification_delegate_android.cc +++ b/chrome/browser/updates/announcement_notification/announcement_notification_delegate_android.cc
@@ -7,8 +7,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "chrome/android/chrome_jni_headers/AnnouncementNotificationManager_jni.h" -#include "chrome/browser/profiles/profile.h" // nogncheck -#include "chrome/browser/profiles/profile_android.h" // nogncheck +#include "chrome/browser/profiles/profile.h" // nogncheck #include "chrome/browser/updates/announcement_notification/announcement_notification_service_factory.h" AnnouncementNotificationDelegateAndroid::
diff --git a/chrome/browser/visited_url_ranking/visited_url_ranking_service_factory.cc b/chrome/browser/visited_url_ranking/visited_url_ranking_service_factory.cc index 8fc4984c..c7c5aa1 100644 --- a/chrome/browser/visited_url_ranking/visited_url_ranking_service_factory.cc +++ b/chrome/browser/visited_url_ranking/visited_url_ranking_service_factory.cc
@@ -98,8 +98,7 @@ if (hs) { data_fetchers.emplace( Fetcher::kHistory, - std::make_unique<visited_url_ranking::HistoryURLVisitDataFetcher>( - hs->AsWeakPtr())); + std::make_unique<visited_url_ranking::HistoryURLVisitDataFetcher>(hs)); } // TODO(crbug.com/329242209): Add various aggregate transformers (e.g,
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h index 3cee5d2..ff0cc39 100644 --- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h +++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
@@ -57,9 +57,8 @@ // ChromeWebAuthenticationDelegate is the //chrome layer implementation of // content::WebAuthenticationDelegate. -class ChromeWebAuthenticationDelegate - : public content::WebAuthenticationDelegate, - base::SupportsWeakPtr<ChromeWebAuthenticationDelegate> { +class ChromeWebAuthenticationDelegate final + : public content::WebAuthenticationDelegate { public: #if BUILDFLAG(IS_MAC) // Returns a configuration struct for instantiating the macOS WebAuthn
diff --git a/chrome/browser/webauthn/enclave_authenticator_browsertest.cc b/chrome/browser/webauthn/enclave_authenticator_browsertest.cc index 9c9f850..d88663a 100644 --- a/chrome/browser/webauthn/enclave_authenticator_browsertest.cc +++ b/chrome/browser/webauthn/enclave_authenticator_browsertest.cc
@@ -794,8 +794,9 @@ : public EnclaveAuthenticatorBrowserTest { public: EnclaveAuthenticatorWithPinBrowserTest() { - scoped_feature_list_.InitWithFeatures( - {device::kWebAuthnEnclaveAuthenticator, device::kWebAuthnGpmPin}, + scoped_feature_list_.InitWithFeaturesAndParameters( + {{device::kWebAuthnEnclaveAuthenticator, + {{device::kWebAuthnGpmPin.name, "true"}}}}, /*disabled_features=*/{ device::kWebAuthnUseInsecureSoftwareUnexportableKeys}); } @@ -1687,10 +1688,10 @@ : public EnclaveAuthenticatorBrowserTest { public: EnclaveAuthenticatorWithoutPinBrowserTest() { - scoped_feature_list_.InitWithFeatures( - {device::kWebAuthnEnclaveAuthenticator}, + scoped_feature_list_.InitWithFeaturesAndParameters( + {{device::kWebAuthnEnclaveAuthenticator, + {{device::kWebAuthnGpmPin.name, "false"}}}}, /*disabled_features=*/{ - device::kWebAuthnGpmPin, device::kWebAuthnUseInsecureSoftwareUnexportableKeys}); }
diff --git a/chrome/browser/webauthn/gpm_enclave_controller.cc b/chrome/browser/webauthn/gpm_enclave_controller.cc index fc09f9c8..59de311 100644 --- a/chrome/browser/webauthn/gpm_enclave_controller.cc +++ b/chrome/browser/webauthn/gpm_enclave_controller.cc
@@ -449,7 +449,7 @@ return; } - if (base::FeatureList::IsEnabled(device::kWebAuthnGpmPin) && + if (device::kWebAuthnGpmPin.Get() && request_type_ == device::FidoRequestType::kGetAssertion) { // For get() requests, progress the UI now because, with GPM PIN support, // we can handle the account in any state and we'll block the UI if needed @@ -468,8 +468,7 @@ can_make_uv_keys_ = can_make_uv_keys; - if (!can_make_uv_keys && - !base::FeatureList::IsEnabled(device::kWebAuthnGpmPin)) { + if (!can_make_uv_keys && !device::kWebAuthnGpmPin.Get()) { // Without the ability to do user verification, we cannot enroll the current // device. account_state_ = AccountState::kNone; @@ -559,7 +558,7 @@ << ", has PIN: " << result.gpm_pin_metadata.has_value() << ", iCloud Keychain keys: " << result.icloud_keys.size(); - if (!base::FeatureList::IsEnabled(device::kWebAuthnGpmPin) && + if (!device::kWebAuthnGpmPin.Get() && result.state == Result::State::kRecoverable && !result.lskf_expiries.empty() && base::ranges::all_of(result.lskf_expiries, ExpiryTooSoon)) { @@ -596,7 +595,7 @@ } security_domain_icloud_recovery_keys_ = std::move(result.icloud_keys); - if (base::FeatureList::IsEnabled(device::kWebAuthnGpmPin)) { + if (device::kWebAuthnGpmPin.Get()) { SetActive(account_state_ != AccountState::kNone); } else { SetActive(account_state_ == AccountState::kRecoverable);
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index d093b18..941bdab6 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1715860514-1baf47c0c8f87f99314c64d6edcc9aba70513bd3-aa8dbada13804c96f1476e8eb6d3ba4441dc6bd2.profdata +chrome-android32-main-1715882337-e1fe608cb852131bb9ad82f702d2ddbecde71a4a-8aa07a3c65e7242324d8ecc539eb2b7028d754d2.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index d11dedd..5e0f699 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1715831515-709956169f7922d440ccc8289a6c64b5bb460504-a79016b824a0c1e0d8edd2afccb6773cd267d888.profdata +chrome-android64-main-1715867891-a943a0ee6ee28de9b4d9e6ec64c3256555bccb94-95ed18bf2ff0d000a4a04cc2495a40e5d6623d20.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 1e5b3d3..33c6b37 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1715867891-bdc0058c9cdd06a5e6dfb542ba125f25ce91b1d2-95ed18bf2ff0d000a4a04cc2495a40e5d6623d20.profdata +chrome-mac-arm-main-1715882337-67df9c6757cb3969409a0b524ea2ad39a5e3475e-8aa07a3c65e7242324d8ecc539eb2b7028d754d2.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index ff0dbd0..5fa7b25 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1715860514-7a724e7d938a4ce9c812b7431aecc3031ffc85c0-aa8dbada13804c96f1476e8eb6d3ba4441dc6bd2.profdata +chrome-win-arm64-main-1715882337-98a5fc7f293838023e412b552823e54cf10740c6-8aa07a3c65e7242324d8ecc539eb2b7028d754d2.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index cc82715..bc062d59 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1715860514-1f17de3cee22ec4aa76fc405b3e1ce44ca506318-aa8dbada13804c96f1476e8eb6d3ba4441dc6bd2.profdata +chrome-win32-main-1715871577-5bea9a3232aef617fa7fbfe1c27f68f34e9f4437-17025b9a22c8a2d47e89990a872307cc1c3923e8.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 74c9005..129a76b 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1715860514-f8f1b2ca42452b16900647e3da3aec8f52f5c391-aa8dbada13804c96f1476e8eb6d3ba4441dc6bd2.profdata +chrome-win64-main-1715871577-bbe429c630625c6f97b4a233577fc5faa0822b33-17025b9a22c8a2d47e89990a872307cc1c3923e8.profdata
diff --git a/chrome/installer/mac/signing/driver.py b/chrome/installer/mac/signing/driver.py index 2ab9e2d..2fd03817 100644 --- a/chrome/installer/mac/signing/driver.py +++ b/chrome/installer/mac/signing/driver.py
@@ -55,6 +55,13 @@ def inject_get_task_allow_entitlement(self): return True + @property + def main_executable_pinned_geometry(self): + # Pinned geometry is only needed to keep release builds + # consistent over time. Ignore executable geometry when code + # signing for development. + return None + config_class = DevelopmentCodeSignConfig return config_class(**config_args)
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 877d5806..85e1719 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -8820,6 +8820,7 @@ "//chrome/browser/screen_ai/public:test_support", "//chrome/browser/ui/ash/holding_space:test_support", "//chrome/browser/ui/chromeos/magic_boost", + "//chrome/browser/ui/chromeos/magic_boost:test_support", "//chrome/browser/ui/chromeos/read_write_cards", "//chrome/browser/ui/quick_answers", "//chrome/browser/ui/views/editor_menu:utils",
diff --git a/chrome/test/data/extensions/signin_screen_manual_test_extension/README b/chrome/test/data/extensions/signin_screen_manual_test_extension/README index d4d72825..9325504 100644 --- a/chrome/test/data/extensions/signin_screen_manual_test_extension/README +++ b/chrome/test/data/extensions/signin_screen_manual_test_extension/README
@@ -1,5 +1,5 @@ The extension_signed_by_webstore.crx package must be a one signed by WebStore, -in order for the extension to have the expected ID which is whitelisted in +in order for the extension to have the expected ID which is allowlisted in Chrome - "ngjobkbdodapjbbncmagbccommkggmnj". This extension is primarily intended to be used for the manual testing of the
diff --git a/chrome/test/data/extensions/signin_screen_manual_test_extension/extension/manifest.json b/chrome/test/data/extensions/signin_screen_manual_test_extension/extension/manifest.json index a682fd6..04d9908 100644 --- a/chrome/test/data/extensions/signin_screen_manual_test_extension/extension/manifest.json +++ b/chrome/test/data/extensions/signin_screen_manual_test_extension/extension/manifest.json
@@ -1,9 +1,9 @@ { "name": "Sign-in Screen Test Extension", - "version": "2.0", - "manifest_version": 2, + "version": "3.0", + "manifest_version": 3, "description": "The extension for manual testing of the extensions installation in the Chrome OS sign-in profile", "background": { - "scripts": ["background.js"] + "service_worker": "background.js" } }
diff --git a/chrome/test/data/extensions/signin_screen_manual_test_extension/extension_signed_by_webstore.crx b/chrome/test/data/extensions/signin_screen_manual_test_extension/extension_signed_by_webstore.crx index c9fadd51..6c46a223 100644 --- a/chrome/test/data/extensions/signin_screen_manual_test_extension/extension_signed_by_webstore.crx +++ b/chrome/test/data/extensions/signin_screen_manual_test_extension/extension_signed_by_webstore.crx Binary files differ
diff --git a/chrome/test/data/extensions/signin_screen_manual_test_extension/update_manifest.xml b/chrome/test/data/extensions/signin_screen_manual_test_extension/update_manifest.xml index e571080..27d6b2a 100644 --- a/chrome/test/data/extensions/signin_screen_manual_test_extension/update_manifest.xml +++ b/chrome/test/data/extensions/signin_screen_manual_test_extension/update_manifest.xml
@@ -7,6 +7,6 @@ <app appid='ngjobkbdodapjbbncmagbccommkggmnj'> <updatecheck codebase='http://mock.http/extensions/signin_screen_manual_test_extension/extension_signed_by_webstore.crx' - version='2.0' /> + version='3.0' /> </app> </gupdate>
diff --git a/chrome/test/data/webui/chromeos/print_preview_cros/BUILD.gn b/chrome/test/data/webui/chromeos/print_preview_cros/BUILD.gn index 0f13996..68641691 100644 --- a/chrome/test/data/webui/chromeos/print_preview_cros/BUILD.gn +++ b/chrome/test/data/webui/chromeos/print_preview_cros/BUILD.gn
@@ -15,6 +15,7 @@ ] files = [ + "capabilities_manager_test.ts", "destination_dropdown_controller_test.ts", "destination_dropdown_test.ts", "destination_manager_test.ts",
diff --git a/chrome/test/data/webui/chromeos/print_preview_cros/capabilities_manager_test.ts b/chrome/test/data/webui/chromeos/print_preview_cros/capabilities_manager_test.ts new file mode 100644 index 0000000..b7ec6b6d --- /dev/null +++ b/chrome/test/data/webui/chromeos/print_preview_cros/capabilities_manager_test.ts
@@ -0,0 +1,147 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'chrome://os-print/js/data/capabilities_manager.js'; + +import {CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_LOADING, CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_READY, CAPABILITIES_MANAGER_SESSION_INITIALIZED, CapabilitiesManager} from 'chrome://os-print/js/data/capabilities_manager.js'; +import {DESTINATION_MANAGER_ACTIVE_DESTINATION_CHANGED, DestinationManager} from 'chrome://os-print/js/data/destination_manager.js'; +import {getFakeCapabilities} from 'chrome://os-print/js/fakes/fake_data.js'; +import {FakeDestinationProvider} from 'chrome://os-print/js/fakes/fake_destination_provider.js'; +import {FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL} from 'chrome://os-print/js/fakes/fake_print_preview_page_handler.js'; +import {createCustomEvent} from 'chrome://os-print/js/utils/event_utils.js'; +import {setDestinationProviderForTesting} from 'chrome://os-print/js/utils/mojo_data_providers.js'; +import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js'; +import {MockController} from 'chrome://webui-test/chromeos/mock_controller.m.js'; +import {eventToPromise} from 'chrome://webui-test/test_util.js'; + +import {createTestDestination} from './test_utils.js'; + +suite('CapabilitiesManager', () => { + let destinationProvider: FakeDestinationProvider; + let mockController: MockController; + + setup(() => { + CapabilitiesManager.resetInstanceForTesting(); + DestinationManager.resetInstanceForTesting(); + + // Setup fakes for testing. + mockController = new MockController(); + destinationProvider = new FakeDestinationProvider(); + setDestinationProviderForTesting(destinationProvider); + }); + + teardown(() => { + mockController.reset(); + CapabilitiesManager.resetInstanceForTesting(); + DestinationManager.resetInstanceForTesting(); + }); + + // Initialize the DestinationManager and wait for it to send all events. + async function waitForDestinationManagerLoad(): Promise<void> { + const destinationManager = DestinationManager.getInstance(); + const activeDestinationChangedEvent = eventToPromise( + DESTINATION_MANAGER_ACTIVE_DESTINATION_CHANGED, destinationManager); + return activeDestinationChangedEvent; + } + + + test('is a singleton', () => { + const instance1 = CapabilitiesManager.getInstance(); + const instance2 = CapabilitiesManager.getInstance(); + assertEquals(instance1, instance2); + }); + + test('can clear singleton', () => { + const instance1 = CapabilitiesManager.getInstance(); + CapabilitiesManager.resetInstanceForTesting(); + const instance2 = CapabilitiesManager.getInstance(); + assertTrue(instance1 !== instance2); + }); + + // Verify `isSessionInitialized` returns true and triggers + // CAPABILITIES_MANAGER_SESSION_INITIALIZED event after `initializeSession` + // called. + test( + 'initializeSession updates isSessionInitialized and triggers ' + + CAPABILITIES_MANAGER_SESSION_INITIALIZED, + async () => { + await waitForDestinationManagerLoad(); + + const instance = CapabilitiesManager.getInstance(); + assertFalse( + instance.isSessionInitialized(), + 'Before initializeSession, instance should not be initialized'); + + // Set initial context. + const sessionInit = + eventToPromise(CAPABILITIES_MANAGER_SESSION_INITIALIZED, instance); + instance.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL); + await sessionInit; + + assertTrue( + instance.isSessionInitialized(), + 'After initializeSession, instance should be initialized'); + }); + + // Verify when Destination Manager signals the active destination changed, the + // Capabilities Manager fetches capabilities. + test( + 'fetch capabilities on active destination changed and cache response', + async () => { + // Set the active destination. + const activeCapailities = getFakeCapabilities(); + const activeDestination = + createTestDestination(activeCapailities.destinationId); + destinationProvider.setCapabiltiies(activeCapailities); + + await waitForDestinationManagerLoad(); + + const destinationManager = DestinationManager.getInstance(); + const getActiveDestinationFn = mockController.createFunctionMock( + destinationManager, 'getActiveDestination'); + getActiveDestinationFn.returnValue = activeDestination; + + const instance = CapabilitiesManager.getInstance(); + instance.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL); + let providerCallCount = 0; + assertEquals( + providerCallCount, + destinationProvider.getCallCount('fetchCapabilities')); + + // Simulate the active destination change and wait for the capabilities + // manager to signal capabilities are ready. + let capsLoadingEvent = eventToPromise( + CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_LOADING, instance); + let capsReadyEvent = eventToPromise( + CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_READY, instance); + destinationManager.dispatchEvent( + createCustomEvent(DESTINATION_MANAGER_ACTIVE_DESTINATION_CHANGED)); + ++providerCallCount; + await capsLoadingEvent; + await capsReadyEvent; + + assertEquals( + providerCallCount, + destinationProvider.getCallCount('fetchCapabilities')); + assertDeepEquals( + activeCapailities, instance.getActiveDestinationCapabilities()); + + // Simulate the active destination changing again except this time the + // cached capabilities result is returned. + capsLoadingEvent = eventToPromise( + CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_LOADING, instance); + capsReadyEvent = eventToPromise( + CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_READY, instance); + destinationManager.dispatchEvent( + createCustomEvent(DESTINATION_MANAGER_ACTIVE_DESTINATION_CHANGED)); + await capsLoadingEvent; + await capsReadyEvent; + + assertEquals( + providerCallCount, + destinationProvider.getCallCount('fetchCapabilities')); + assertDeepEquals( + activeCapailities, instance.getActiveDestinationCapabilities()); + }); +});
diff --git a/chrome/test/data/webui/chromeos/print_preview_cros/print_preview_cros_app_controller_test.ts b/chrome/test/data/webui/chromeos/print_preview_cros/print_preview_cros_app_controller_test.ts index da63f9c..c16d7d6 100644 --- a/chrome/test/data/webui/chromeos/print_preview_cros/print_preview_cros_app_controller_test.ts +++ b/chrome/test/data/webui/chromeos/print_preview_cros/print_preview_cros_app_controller_test.ts
@@ -4,6 +4,7 @@ import 'chrome://os-print/js/print_preview_cros_app_controller.js'; +import {CAPABILITIES_MANAGER_SESSION_INITIALIZED, CapabilitiesManager} from 'chrome://os-print/js/data/capabilities_manager.js'; import {DESTINATION_MANAGER_SESSION_INITIALIZED, DestinationManager} from 'chrome://os-print/js/data/destination_manager.js'; import {PREVIEW_TICKET_MANAGER_SESSION_INITIALIZED, PreviewTicketManager} from 'chrome://os-print/js/data/preview_ticket_manager.js'; import {PRINT_TICKET_MANAGER_SESSION_INITIALIZED, PrintTicketManager} from 'chrome://os-print/js/data/print_ticket_manager.js'; @@ -25,6 +26,7 @@ mockTimer = new MockTimer(); mockTimer.install(); + CapabilitiesManager.resetInstanceForTesting(); DestinationManager.resetInstanceForTesting(); PrintTicketManager.resetInstanceForTesting(); PreviewTicketManager.resetInstanceForTesting(); @@ -36,6 +38,7 @@ teardown(() => { printPreviewPageHandler.reset(); + CapabilitiesManager.resetInstanceForTesting(); DestinationManager.resetInstanceForTesting(); PreviewTicketManager.resetInstanceForTesting(); PrintTicketManager.resetInstanceForTesting(); @@ -145,4 +148,29 @@ 'After initializeSession PreviewTicketManager instance should be ' + 'initialized'); }); + + // Verify capabilities manager is initialized after start session resolves. + test( + 'on resolve of startSession calls CapabilitiesManager.initializeSession', + async () => { + printPreviewPageHandler.setTestDelay(testDelay); + + const controller = new PrintPreviewCrosAppController(); + assertTrue(!!controller, 'Unable to create controller'); + const capabilitiesManager = CapabilitiesManager.getInstance(); + assertFalse( + capabilitiesManager.isSessionInitialized(), + 'Before initializeSession CapabilitiesManager instance should ' + + 'not be initialized'); + + // Move timer forward to resolve startSession. + mockTimer.tick(testDelay); + await eventToPromise( + CAPABILITIES_MANAGER_SESSION_INITIALIZED, capabilitiesManager); + + assertTrue( + capabilitiesManager.isSessionInitialized(), + 'After initializeSession CapabilitiesManager instance should be ' + + 'initialized'); + }); });
diff --git a/chrome/test/data/webui/chromeos/print_preview_cros/print_preview_cros_browsertest.cc b/chrome/test/data/webui/chromeos/print_preview_cros/print_preview_cros_browsertest.cc index 350a9cc..f459a53 100644 --- a/chrome/test/data/webui/chromeos/print_preview_cros/print_preview_cros_browsertest.cc +++ b/chrome/test/data/webui/chromeos/print_preview_cros/print_preview_cros_browsertest.cc
@@ -36,6 +36,10 @@ base::test::ScopedFeatureList scoped_feature_list_; }; +IN_PROC_BROWSER_TEST_F(PrintPreviewCrosBrowserTest, CapabilitiesManagerTest) { + RunTestAtPath("capabilities_manager_test.js"); +} + IN_PROC_BROWSER_TEST_F(PrintPreviewCrosBrowserTest, DestinationDropdownControllerTest) { RunTestAtPath("destination_dropdown_controller_test.js");
diff --git a/chrome/test/data/webui/chromeos/print_preview_cros/print_ticket_manager_test.ts b/chrome/test/data/webui/chromeos/print_preview_cros/print_ticket_manager_test.ts index ce51feb..022b38c 100644 --- a/chrome/test/data/webui/chromeos/print_preview_cros/print_ticket_manager_test.ts +++ b/chrome/test/data/webui/chromeos/print_preview_cros/print_ticket_manager_test.ts
@@ -149,8 +149,8 @@ assertFalse(instance.isPrintRequestInProgress(), 'Request finished'); }); - // Verify PrintTicketManger ensures that PrintPreviewPageHandler.print is only - // called if print request is not in progress. + // Verify PrintTicketManager ensures that PrintPreviewPageHandler.print is + // only called if print request is not in progress. test('ensure only one print request triggered at a time', async () => { const delay = 1; printPreviewPageHandler.setTestDelay(delay);
diff --git a/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_controller_test.ts b/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_controller_test.ts index b4b36a97..db32e9a5 100644 --- a/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_controller_test.ts +++ b/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_controller_test.ts
@@ -19,8 +19,8 @@ let controller: SummaryPanelController|null = null; let mockController: MockController; let printPreviewPageHandler: FakePrintPreviewPageHandler; - let previewTicketManger: PreviewTicketManager; - let printTicketManger: PrintTicketManager; + let previewTicketManager: PreviewTicketManager; + let printTicketManager: PrintTicketManager; let eventTracker: EventTracker; setup(() => { @@ -31,8 +31,8 @@ // Setup fakes. printPreviewPageHandler = new FakePrintPreviewPageHandler(); setPrintPreviewPageHandlerForTesting(printPreviewPageHandler); - previewTicketManger = PreviewTicketManager.getInstance(); - printTicketManger = PrintTicketManager.getInstance(); + previewTicketManager = PreviewTicketManager.getInstance(); + printTicketManager = PrintTicketManager.getInstance(); controller = new SummaryPanelController(eventTracker); assertTrue(!!controller); @@ -95,10 +95,10 @@ const testEvent = new CustomEvent<void>( PRINT_REQUEST_STARTED_EVENT, {bubbles: true, composed: true}); const startRequest = - eventToPromise(PRINT_REQUEST_STARTED_EVENT, printTicketManger); + eventToPromise(PRINT_REQUEST_STARTED_EVENT, printTicketManager); handlerFn.addExpectation(testEvent); - printTicketManger.dispatchEvent(testEvent); + printTicketManager.dispatchEvent(testEvent); await startRequest; mockController.verifyMocks(); @@ -113,10 +113,10 @@ const testEvent = new CustomEvent<void>( PRINT_REQUEST_FINISHED_EVENT, {bubbles: true, composed: true}); const finishRequest = - eventToPromise(PRINT_REQUEST_FINISHED_EVENT, printTicketManger); + eventToPromise(PRINT_REQUEST_FINISHED_EVENT, printTicketManager); handlerFn.addExpectation(testEvent); - printTicketManger.dispatchEvent(testEvent); + printTicketManager.dispatchEvent(testEvent); await finishRequest; mockController.verifyMocks(); @@ -130,11 +130,11 @@ // Set preview loaded to true since that can also disable the print // button. const previewRequestInProgressFn = mockController.createFunctionMock( - previewTicketManger, 'isPreviewLoaded'); + previewTicketManager, 'isPreviewLoaded'); previewRequestInProgressFn.returnValue = true; const printRequestInProgressFn = mockController.createFunctionMock( - printTicketManger, 'isPrintRequestInProgress'); + printTicketManager, 'isPrintRequestInProgress'); printRequestInProgressFn.returnValue = true; assertTrue(controller!.shouldDisablePrintButton()); }); @@ -147,11 +147,11 @@ // Set preview loaded to true since that can also disable the print // button. const previewRequestInProgressFn = mockController.createFunctionMock( - previewTicketManger, 'isPreviewLoaded'); + previewTicketManager, 'isPreviewLoaded'); previewRequestInProgressFn.returnValue = true; const printRequestInProgressFn = mockController.createFunctionMock( - printTicketManger, 'isPrintRequestInProgress'); + printTicketManager, 'isPrintRequestInProgress'); printRequestInProgressFn.returnValue = false; assertFalse(controller!.shouldDisablePrintButton()); }); @@ -159,7 +159,7 @@ // Verify shouldDisablePrintButton is true when preview isn't loaded. test('shouldDisablePrintButton true while preview is not loaded', () => { const previewRequestInProgressFn = mockController.createFunctionMock( - previewTicketManger, 'isPreviewLoaded'); + previewTicketManager, 'isPreviewLoaded'); previewRequestInProgressFn.returnValue = false; assertTrue(controller!.shouldDisablePrintButton()); });
diff --git a/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_test.ts b/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_test.ts index 751b53a..e08123f 100644 --- a/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_test.ts +++ b/chrome/test/data/webui/chromeos/print_preview_cros/summary_panel_test.ts
@@ -80,10 +80,10 @@ // Initialize the session to request a preview and enable the print button. async function waitForPreviewRequestFinished(delay: number = 1): Promise<void> { - const previewTicketManger = PreviewTicketManager.getInstance(); + const previewTicketManager = PreviewTicketManager.getInstance(); const previewRequestFinishedEvent = - eventToPromise(PREVIEW_REQUEST_FINISHED_EVENT, previewTicketManger); - previewTicketManger.initializeSession( + eventToPromise(PREVIEW_REQUEST_FINISHED_EVENT, previewTicketManager); + previewTicketManager.initializeSession( FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL); mockTimer.tick(delay); await previewRequestFinishedEvent; @@ -201,13 +201,13 @@ assertFalse( printButton.disabled, 'Print should be enabled before request sent'); - const printTicketManger = PrintTicketManager.getInstance(); - printTicketManger.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL); + const printTicketManager = PrintTicketManager.getInstance(); + printTicketManager.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL); printButton.click(); await printDisabledEvent1; assertTrue( - printTicketManger.isPrintRequestInProgress(), + printTicketManager.isPrintRequestInProgress(), 'Print request in progress'); assertTrue( printButton.disabled, @@ -219,7 +219,7 @@ await printDisabledEvent2; assertFalse( - printTicketManger.isPrintRequestInProgress(), + printTicketManager.isPrintRequestInProgress(), 'Print request is complete'); assertFalse( printButton.disabled,
diff --git a/chrome/test/data/webui/compose/compose_app_focus_test.ts b/chrome/test/data/webui/compose/compose_app_focus_test.ts index 76d4639d..d2590d7 100644 --- a/chrome/test/data/webui/compose/compose_app_focus_test.ts +++ b/chrome/test/data/webui/compose/compose_app_focus_test.ts
@@ -4,6 +4,7 @@ import 'chrome-untrusted://compose/app.js'; +import {loadTimeData} from '//resources/js/load_time_data.js'; import type {ComposeAppElement} from 'chrome-untrusted://compose/app.js'; import { StyleModifier, UserFeedback } from 'chrome-untrusted://compose/compose.mojom-webui.js'; import {ComposeApiProxyImpl} from 'chrome-untrusted://compose/compose_api_proxy.js'; @@ -66,6 +67,11 @@ }); test('FocusesRefreshButtonAfterRefreshRewrite', async () => { + // This test is only useful for non-refinement UI. + loadTimeData.overrideValues({ + enableRefinedUi: false, + }); + const app = await createApp(); app.$.textarea.value = 'test value one'; app.$.submitButton.click(); @@ -90,6 +96,11 @@ }); test('FocusesLengthMenuAfterLengthRewrite', async () => { + // This test is only useful for non-refinement UI. + loadTimeData.overrideValues({ + enableRefinedUi: false, + }); + const app = await createApp(); app.$.textarea.value = 'test value'; app.$.submitButton.click();
diff --git a/chrome/test/data/webui/compose/compose_app_test.ts b/chrome/test/data/webui/compose/compose_app_test.ts index 98e0705..a49e230 100644 --- a/chrome/test/data/webui/compose/compose_app_test.ts +++ b/chrome/test/data/webui/compose/compose_app_test.ts
@@ -148,64 +148,6 @@ appWithNoTextSelected.$.acceptButton.textContent!, 'Insert'); }); - test('RefreshesResult', async () => { - // Submit the input once so the refresh button shows up. - mockInput('Input to refresh.'); - app.$.submitButton.click(); - await mockResponse(); - - testProxy.resetResolver('rewrite'); - assertTrue( - isVisible(app.$.refreshButton), 'Refresh button should be visible.'); - - // Click the refresh button and assert compose is called with the same args. - app.$.refreshButton.click(); - assertTrue( - isVisible(app.$.loading), 'Loading indicator should be visible.'); - - const args = await testProxy.whenCalled('rewrite'); - await mockResponse('Refreshed output.'); - - assertEquals(StyleModifier.kRetry, args); - - // Verify UI has updated with refreshed results. - assertFalse(isVisible(app.$.loading)); - assertTrue( - isVisible(app.$.resultContainer), - 'App result container should be visible.'); - assertStringContains( - app.$.resultText.$.root.innerText, 'Refreshed output.'); - }); - - test('UpdatesScrollableBodyAfterResize', async () => { - assertTrue(app.$.body.hasAttribute('scrollable')); - - mockInput('Some fake input.'); - app.$.submitButton.click(); - - // Mock a height on results to get body to scroll. The body should not yet - // be scrollable though because result has not been fetched yet. - app.$.resultContainer.style.minHeight = '500px'; - assertFalse(app.$.body.classList.contains('can-scroll')); - - await testProxy.whenCalled('compose'); - await mockResponse(); - await whenCheck( - app.$.body, () => app.$.body.classList.contains('can-scroll')); - assertEquals(220, app.$.body.offsetHeight); - assertTrue(220 < app.$.body.scrollHeight); - - // Mock resizing result container down to a 50px height. This should result - // in the body changing height, triggering the updates to the CSS classes. - // At this point, 50px is too short to scroll, so it should not have the - // 'can-scroll' class. - app.$.resultContainer.style.minHeight = '50px'; - app.$.resultContainer.style.height = '50px'; - app.$.resultContainer.style.overflow = 'hidden'; - await whenCheck( - app.$.body, () => !app.$.body.classList.contains('can-scroll')); - }); - test('FirstRunAndMsbbStateDetermineViewState', async () => { // Check correct visibility for FRE view state. const appWithFirstRunDialog = @@ -628,41 +570,6 @@ assertStringContains(app.$.resultText.$.root.innerText, 'new response'); }); - test('ComposeWithLengthToneOptionResult', async () => { - // Submit the input once so the refresh button shows up. - mockInput('Input to refresh.'); - app.$.submitButton.click(); - await mockResponse(); - - testProxy.resetResolver('rewrite'); - - assertTrue(isVisible(app.$.lengthMenu), 'Length menu should be visible.'); - assertEquals( - 2, app.$.lengthMenu.querySelectorAll('option:not([disabled])').length); - - app.$.lengthMenu.value = `${StyleModifier.kShorter}`; - app.$.lengthMenu.dispatchEvent(new CustomEvent('change')); - - const args = await testProxy.whenCalled('rewrite'); - await mockResponse(); - - assertEquals(StyleModifier.kShorter, args); - - testProxy.resetResolver('rewrite'); - - assertTrue(isVisible(app.$.toneMenu), 'Tone menu should be visible.'); - assertEquals( - 2, app.$.toneMenu.querySelectorAll('option:not([disabled])').length); - - app.$.toneMenu.value = `${StyleModifier.kCasual}`; - app.$.toneMenu.dispatchEvent(new CustomEvent('change')); - - const args2 = await testProxy.whenCalled('rewrite'); - await mockResponse(); - - assertEquals(StyleModifier.kCasual, args2); - }); - test('Undo', async () => { // Set up initial state to show undo button and mock up a previous state. document.body.innerHTML = window.trustedTypes!.emptyHTML; @@ -828,3 +735,247 @@ assertEquals(app.$.resultText.$.root.innerText.trim(), 'some response'); }); }); + +suite('ComposeAppLegacyUi', () => { + let app: ComposeAppElement; + let testProxy: TestComposeApiProxy; + + suiteSetup(function() { + if (loadTimeData.getBoolean('enableRefinedUi')) { + this.skip(); + } + }); + + setup(async () => { + testProxy = new TestComposeApiProxy(); + ComposeApiProxyImpl.setInstance(testProxy); + + document.body.innerHTML = window.trustedTypes!.emptyHTML; + app = document.createElement('compose-app'); + document.body.appendChild(app); + + await testProxy.whenCalled('requestInitialState'); + return flushTasks(); + }); + + function mockInput(input: string) { + app.$.textarea.value = input; + app.$.textarea.dispatchEvent(new CustomEvent('value-changed')); + } + + function mockResponse( + result: string = 'some response', + status: ComposeStatus = ComposeStatus.kOk, onDeviceEvaluationUsed = false, + triggeredFromModifier = false): Promise<void> { + testProxy.remote.responseReceived({ + status: status, + undoAvailable: false, + redoAvailable: false, + providedByUser: false, + result, + onDeviceEvaluationUsed, + triggeredFromModifier, + }); + return testProxy.remote.$.flushForTesting(); + } + + test('RefreshesResult', async () => { + // Submit the input once so the refresh button shows up. + mockInput('Input to refresh.'); + app.$.submitButton.click(); + await mockResponse(); + + testProxy.resetResolver('rewrite'); + assertTrue( + isVisible(app.$.refreshButton), 'Refresh button should be visible.'); + + // Click the refresh button and assert compose is called with the same args. + app.$.refreshButton.click(); + assertTrue( + isVisible(app.$.loading), 'Loading indicator should be visible.'); + + const args = await testProxy.whenCalled('rewrite'); + await mockResponse('Refreshed output.'); + + assertEquals(StyleModifier.kRetry, args); + + // Verify UI has updated with refreshed results. + assertFalse(isVisible(app.$.loading)); + assertTrue( + isVisible(app.$.resultContainer), + 'App result container should be visible.'); + assertStringContains( + app.$.resultText.$.root.innerText, 'Refreshed output.'); + }); + + test('UpdatesScrollableBodyAfterResize', async () => { + assertTrue(app.$.body.hasAttribute('scrollable')); + + mockInput('Some fake input.'); + app.$.submitButton.click(); + + // Mock a height on results to get body to scroll. The body should not yet + // be scrollable though because result has not been fetched yet. + app.$.resultContainer.style.minHeight = '500px'; + assertFalse(app.$.body.classList.contains('can-scroll')); + + await testProxy.whenCalled('compose'); + await mockResponse(); + await whenCheck( + app.$.body, () => app.$.body.classList.contains('can-scroll')); + assertEquals(220, app.$.body.offsetHeight); + assertTrue(220 < app.$.body.scrollHeight); + + // Mock resizing result container down to a 50px height. This should result + // in the body changing height, triggering the updates to the CSS classes. + // At this point, 50px is too short to scroll, so it should not have the + // 'can-scroll' class. + app.$.resultContainer.style.minHeight = '50px'; + app.$.resultContainer.style.height = '50px'; + app.$.resultContainer.style.overflow = 'hidden'; + await whenCheck( + app.$.body, () => !app.$.body.classList.contains('can-scroll')); + }); + + test('ComposeWithLengthToneOptionResult', async () => { + // Submit the input once so the refresh button shows up. + mockInput('Input to refresh.'); + app.$.submitButton.click(); + await mockResponse(); + + testProxy.resetResolver('rewrite'); + + assertTrue(isVisible(app.$.lengthMenu), 'Length menu should be visible.'); + assertEquals( + 2, app.$.lengthMenu.querySelectorAll('option:not([disabled])').length); + + app.$.lengthMenu.value = `${StyleModifier.kShorter}`; + app.$.lengthMenu.dispatchEvent(new CustomEvent('change')); + + const args = await testProxy.whenCalled('rewrite'); + await mockResponse(); + + assertEquals(StyleModifier.kShorter, args); + + testProxy.resetResolver('rewrite'); + + assertTrue(isVisible(app.$.toneMenu), 'Tone menu should be visible.'); + assertEquals( + 2, app.$.toneMenu.querySelectorAll('option:not([disabled])').length); + + app.$.toneMenu.value = `${StyleModifier.kCasual}`; + app.$.toneMenu.dispatchEvent(new CustomEvent('change')); + + const args2 = await testProxy.whenCalled('rewrite'); + await mockResponse(); + + assertEquals(StyleModifier.kCasual, args2); + }); +}); + + +suite('ComposeAppRefinedUi', () => { + let app: ComposeAppElement; + let testProxy: TestComposeApiProxy; + + suiteSetup(function() { + if (!loadTimeData.getBoolean('enableRefinedUi')) { + this.skip(); + } + }); + + setup(async () => { + testProxy = new TestComposeApiProxy(); + ComposeApiProxyImpl.setInstance(testProxy); + + document.body.innerHTML = window.trustedTypes!.emptyHTML; + app = document.createElement('compose-app'); + document.body.appendChild(app); + + await testProxy.whenCalled('requestInitialState'); + return flushTasks(); + }); + + function mockInput(input: string) { + app.$.textarea.value = input; + app.$.textarea.dispatchEvent(new CustomEvent('value-changed')); + } + + function mockResponse( + result: string = 'some response', + status: ComposeStatus = ComposeStatus.kOk, onDeviceEvaluationUsed = false, + triggeredFromModifier = false): Promise<void> { + testProxy.remote.responseReceived({ + status: status, + undoAvailable: false, + redoAvailable: false, + providedByUser: false, + result, + onDeviceEvaluationUsed, + triggeredFromModifier, + }); + return testProxy.remote.$.flushForTesting(); + } + + test('RefreshesResult', async () => { + // Submit the input once so that modifier menu is visible. + mockInput('Input to retry.'); + app.$.submitButton.click(); + await mockResponse(); + + testProxy.resetResolver('rewrite'); + assertTrue( + isVisible(app.$.modifierMenu), 'Modifier menu should be visible.'); + + // Select the retry option from the modifier menu and assert compose is + // called with the same args. + app.$.modifierMenu.value = `${StyleModifier.kRetry}`; + app.$.modifierMenu.dispatchEvent(new CustomEvent('change')); + assertTrue( + isVisible(app.$.loading), 'Loading indicator should be visible.'); + + const args = await testProxy.whenCalled('rewrite'); + await mockResponse('Refreshed output.'); + + assertEquals(StyleModifier.kRetry, args); + + // Verify UI has updated with refreshed results. + assertFalse(isVisible(app.$.loading)); + assertTrue( + isVisible(app.$.resultContainer), + 'App result container should be visible.'); + assertStringContains( + app.$.resultText.$.root.innerText, 'Refreshed output.'); + }); + + test('UpdatesScrollableResultContainerAfterResize', async () => { + assertTrue(app.$.resultTextContainer.hasAttribute('scrollable')); + mockInput('Some fake input.'); + app.$.submitButton.click(); + + // The results text should not yet be scrollable because the result has not + // been fetched yet. + assertFalse(app.$.resultTextContainer.classList.contains('can-scroll')); + + // Results text should be scrollable when a long response is received. + await testProxy.whenCalled('compose'); + const longResponse = 'x'.repeat(1000); + await mockResponse(longResponse); + await whenCheck( + app.$.resultTextContainer, + () => app.$.resultTextContainer.classList.contains('can-scroll')); + assertEquals(220, app.$.body.offsetHeight); + assertTrue( + 220 < app.$.resultTextContainer.scrollHeight, + 'Scroll height (' + app.$.resultTextContainer.scrollHeight + + ' should be bigger than 220.'); + + // Results text should not be scrollable when a short response is received. + app.$.modifierMenu.value = `${StyleModifier.kRetry}`; + app.$.modifierMenu.dispatchEvent(new CustomEvent('change')); + await testProxy.whenCalled('rewrite'); + await mockResponse('Refreshed output.'); + await whenCheck( + app.$.body, () => !app.$.body.classList.contains('can-scroll')); + }); +});
diff --git a/chrome/test/data/webui/compose/compose_browsertest.cc b/chrome/test/data/webui/compose/compose_browsertest.cc index 3437f1e..96caf31 100644 --- a/chrome/test/data/webui/compose/compose_browsertest.cc +++ b/chrome/test/data/webui/compose/compose_browsertest.cc
@@ -8,36 +8,50 @@ #include "components/compose/core/browser/compose_features.h" #include "content/public/test/browser_test.h" -class ComposeTest : public WebUIMochaBrowserTest { +class ComposeTest : public WebUIMochaBrowserTest, + public testing::WithParamInterface<bool> { + public: + static std::string DescribeParams( + const testing::TestParamInfo<ParamType>& info) { + return info.param ? "RefinedUI" : "LegacyUI"; + } + protected: ComposeTest() { set_test_loader_host(chrome::kChromeUIUntrustedComposeHost); set_test_loader_scheme(content::kChromeUIUntrustedScheme); scoped_compose_enabled_ = ComposeEnabling::ScopedEnableComposeForTesting(); + scoped_feature_list_.InitWithFeatureStates( + {{compose::features::kEnableCompose, true}, + {compose::features::kComposeUiRefinement, GetParam()}}); } private: - base::test::ScopedFeatureList scoped_feature_list_{ - compose::features::kEnableCompose}; + base::test::ScopedFeatureList scoped_feature_list_; ComposeEnabling::ScopedOverride scoped_compose_enabled_; }; -IN_PROC_BROWSER_TEST_F(ComposeTest, App) { +INSTANTIATE_TEST_SUITE_P(/*no prefix*/, + ComposeTest, + ::testing::Bool(), + ComposeTest::DescribeParams); + +IN_PROC_BROWSER_TEST_P(ComposeTest, App) { RunTest("compose/compose_app_test.js", "mocha.run()"); } -IN_PROC_BROWSER_TEST_F(ComposeTest, Textarea) { +IN_PROC_BROWSER_TEST_P(ComposeTest, Textarea) { RunTest("compose/compose_textarea_test.js", "mocha.run()"); } -IN_PROC_BROWSER_TEST_F(ComposeTest, Animator) { +IN_PROC_BROWSER_TEST_P(ComposeTest, Animator) { RunTest("compose/compose_animator_test.js", "mocha.run()"); } -IN_PROC_BROWSER_TEST_F(ComposeTest, WordStreamer) { +IN_PROC_BROWSER_TEST_P(ComposeTest, WordStreamer) { RunTest("compose/word_streamer_test.js", "mocha.run()"); } -IN_PROC_BROWSER_TEST_F(ComposeTest, ResultText) { +IN_PROC_BROWSER_TEST_P(ComposeTest, ResultText) { RunTest("compose/result_text_test.js", "mocha.run()"); }
diff --git a/chrome/test/data/webui/cr_elements/cr_dialog_test.ts b/chrome/test/data/webui/cr_elements/cr_dialog_test.ts index 6a3d9b7..58b11137 100644 --- a/chrome/test/data/webui/cr_elements/cr_dialog_test.ts +++ b/chrome/test/data/webui/cr_elements/cr_dialog_test.ts
@@ -10,8 +10,8 @@ import type {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; import type {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js'; import {keyDownOn, keyEventOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js'; -import {assertEquals, assertFalse, assertNotEquals, assertNotReached, assertTrue} from 'chrome://webui-test/chai_assert.js'; -import {eventToPromise} from 'chrome://webui-test/test_util.js'; +import {assertEquals, assertFalse, assertNotEquals, assertNotReached, assertNull, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {eventToPromise, isVisible} from 'chrome://webui-test/test_util.js'; import {flushTasks} from 'chrome://webui-test/polymer_test_util.js'; // clang-format on @@ -174,7 +174,7 @@ test('enter keys should trigger action buttons once', function() { document.body.innerHTML = getTrustedHTML` - <cr-dialog> + <cr-dialog show-close-button> <div slot="title">title</div> <div slot="body"> <button class="action-button">button</button> @@ -213,7 +213,9 @@ assertEquals(0, clickedCounter); // Enter keys on the close icon in the top-right corner should be ignored. - pressEnter(dialog.$.close); + const close = dialog.shadowRoot!.querySelector<HTMLElement>('#close'); + assertTrue(!!close); + pressEnter(close); assertEquals(0, clickedCounter); }); @@ -449,7 +451,7 @@ assertTrue(dialog.noCancel); dialog.showModal(); - assertTrue(dialog.$.close.hidden); + assertNull(dialog.shadowRoot!.querySelector('#close')); // Hitting escape fires a 'cancel' event. Cancelling that event prevents the // dialog from closing. @@ -475,9 +477,10 @@ dialog.showModal(); assertTrue(dialog.open); - assertFalse(dialog.$.close.hidden); - assertEquals('flex', window.getComputedStyle(dialog.$.close).display); - dialog.$.close.click(); + const close = dialog.shadowRoot!.querySelector<HTMLElement>('#close'); + assertTrue(!!close); + assertTrue(isVisible(close)); + close.click(); assertFalse(dialog.open); }); @@ -490,8 +493,7 @@ const dialog = document.body.querySelector('cr-dialog')!; dialog.showModal(); - assertTrue(dialog.$.close.hidden); - assertEquals('none', window.getComputedStyle(dialog.$.close).display); + assertNull(dialog.shadowRoot!.querySelector('#close')); }); test('keydown should be consumed when the property is true', function() { @@ -553,20 +555,22 @@ test('close-text', async () => { document.body.innerHTML = getTrustedHTML` - <cr-dialog close-text="foo"> + <cr-dialog close-text="foo" show-close-button> <div slot="title">title</div> </cr-dialog>`; const dialog = document.body.querySelector('cr-dialog')!; dialog.showModal(); assertEquals('foo', dialog.closeText); - assertEquals('foo', dialog.$.close.ariaLabel); - assertEquals('foo', dialog.$.close.getAttribute('aria-label')); + const close = dialog.shadowRoot!.querySelector<HTMLElement>('#close'); + assertTrue(!!close); + assertEquals('foo', close.ariaLabel); + assertEquals('foo', close.getAttribute('aria-label')); dialog.closeText = undefined; await dialog.updateComplete; - assertEquals(null, dialog.$.close.ariaLabel); - assertFalse(dialog.$.close.hasAttribute('aria-label')); + assertEquals(null, close.ariaLabel); + assertFalse(close.hasAttribute('aria-label')); }); // Test that when ignoreEnterKey is set, pressing "Enter" does not trigger the
diff --git a/chrome/test/data/webui/cr_elements/cr_url_list_item_test.ts b/chrome/test/data/webui/cr_elements/cr_url_list_item_test.ts index 69340130..fa7f01e9 100644 --- a/chrome/test/data/webui/cr_elements/cr_url_list_item_test.ts +++ b/chrome/test/data/webui/cr_elements/cr_url_list_item_test.ts
@@ -183,6 +183,15 @@ element.$.anchor.getBoundingClientRect()); }); + test('SetsTargetForAnchor', async () => { + element.asAnchor = true; + await element.updateComplete; + assertEquals('_self', element.$.anchor.target); + element.asAnchorTarget = '_blank'; + await element.updateComplete; + assertEquals('_blank', element.$.anchor.target); + }); + test('PassesAriaProperties', async () => { element.title = 'My title'; element.description = 'My description';
diff --git a/chrome/test/data/webui/lens/lens_webui_browsertest.cc b/chrome/test/data/webui/lens/lens_webui_browsertest.cc index a973bbaa..8ae67b0 100644 --- a/chrome/test/data/webui/lens/lens_webui_browsertest.cc +++ b/chrome/test/data/webui/lens/lens_webui_browsertest.cc
@@ -6,6 +6,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/lens/lens_overlay_controller.h" +#include "chrome/browser/ui/lens/lens_overlay_invocation_source.h" #include "chrome/browser/ui/lens/lens_overlay_permission_utils.h" #include "chrome/browser/ui/tabs/tab_features.h" #include "chrome/common/webui_url_constants.h" @@ -75,7 +76,7 @@ ASSERT_EQ(controller->state(), State::kOff); // Showing UI should eventually result in overlay state. - controller->ShowUI(LensOverlayController::InvocationSource::kAppMenu); + controller->ShowUI(lens::LensOverlayInvocationSource::kAppMenu); ASSERT_TRUE(base::test::RunUntil( [&]() { return controller->state() == State::kOverlay; }));
diff --git a/chrome/test/fuzzing/in_process_fuzzer.cc b/chrome/test/fuzzing/in_process_fuzzer.cc index 53d907e..2f3e91f 100644 --- a/chrome/test/fuzzing/in_process_fuzzer.cc +++ b/chrome/test/fuzzing/in_process_fuzzer.cc
@@ -270,13 +270,7 @@ fuzzer->GetChromiumCommandLineArguments(); chromium_arguments.insert(chromium_arguments.begin(), executable_name); chromium_arguments.push_back(FILE_PATH_LITERAL("--single-process-tests")); -#if BUILDFLAG(IS_CENTIPEDE) - // TODO(crbug.com/40051117): make libfuzzer compatible with single-process - // mode. As it stands, single-process mode works with centipede (and is - // probably desirable both in terms of fuzzing speed and correctly gathering - // coverage information) but not yet with libfuzzer. chromium_arguments.push_back(FILE_PATH_LITERAL("--single-process")); -#endif // BUILDFLAG(IS_CENTIPEDE) chromium_arguments.push_back(FILE_PATH_LITERAL("--no-sandbox")); chromium_arguments.push_back(FILE_PATH_LITERAL("--no-zygote")); chromium_arguments.push_back(FILE_PATH_LITERAL("--disable-gpu"));
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn index 2f2bd64e..5b6079b 100644 --- a/chrome/updater/BUILD.gn +++ b/chrome/updater/BUILD.gn
@@ -937,6 +937,7 @@ ":ks_ticket", "//chrome/updater/mac:ksadmin_lib", "//chrome/updater/mac:privileged_helper_sources", + "//chrome/updater/mac/client_lib:test_sources", "//third_party/ocmock", ]
diff --git a/chrome/updater/mac/client_lib/BUILD.gn b/chrome/updater/mac/client_lib/BUILD.gn new file mode 100644 index 0000000..bb703d8e --- /dev/null +++ b/chrome/updater/mac/client_lib/BUILD.gn
@@ -0,0 +1,22 @@ +# Copyright 2024 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//testing/test.gni") + +source_set("public_sources") { + sources = [ + "CRURegistration.h", + "CRURegistration.m", + ] + assert_no_deps = [ "*" ] +} + +source_set("test_sources") { + testonly = true + sources = [ "CRURegistration_unittests.mm" ] + deps = [ + ":public_sources", + "//testing/gtest", + ] +}
diff --git a/chrome/updater/mac/client_lib/CRURegistration.h b/chrome/updater/mac/client_lib/CRURegistration.h new file mode 100644 index 0000000..dddc9239 --- /dev/null +++ b/chrome/updater/mac/client_lib/CRURegistration.h
@@ -0,0 +1,71 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_UPDATER_MAC_CLIENT_LIB_CRUREGISTRATION_H_ +#define CHROME_UPDATER_MAC_CLIENT_LIB_CRUREGISTRATION_H_ + +#import <Foundation/Foundation.h> +#import <dispatch/dispatch.h> + +NS_ASSUME_NONNULL_BEGIN + +/** + * CRURegistration interfaces with Chromium Updater to configure and retrieve + * information about an app, or to install the updater for the current user. Its + * methods can be invoked from any thread or queue. + * + * Do not block CRURegistration's target queue synchronously waiting for a + * callback from CRURegistration; this causes deadlock. Invoking CRURegistration + * methods on this (or any) queue without subsequently synchronously waiting for + * a provided callback to execute is safe. CRURegistration does not block its + * target queue. + */ +@interface CRURegistration : NSObject + +/** + * Initializes a CRURegistration instance to manage Chromium Updater's + * information about the app with the provided ID, using a specified queue + * for execution and callbacks. This queue can be serial or concurrent, but + * typically should not be the main queue. + * + * @param appId The ID of the app this CRURegistration instance operates on. + * @param targetQueue Dispatch queue for callbacks and internal operations. + * If this queue is blocked, CRURegistration will get stuck. + */ +- (instancetype)initWithAppId:(NSString*)appId + targetQueue:(dispatch_queue_t)targetQueue + NS_DESIGNATED_INITIALIZER; + +/** + * Initializes a CRURegistration instance to manage Chromium Updater's + * information about the app with the provided ID, using a global concurrent + * queue for execution (with the specified quality of service). + * + * @param appId The ID of the app this CRURegistration instance operates on. + * @param qos Identifier for the global concurrent queue to use for callbacks + * and internal operations. See Apple's documentation for + * `dispatch_get_global_queue` for more details: + * https://developer.apple.com/documentation/dispatch/1452927-dispatch_get_global_queue + */ +- (instancetype)initWithAppId:(NSString*)appId qos:(dispatch_qos_class_t)qos; + +/** + * Initializes a CRURegistration instance to manage Chromium Updater's + * information about the app with the provided ID, using the `QOS_CLASS_UTILITY` + * global concurrent queue for execution. + * + * @param appId The ID of the app this CRURegistration instance operates on. + */ +- (instancetype)initWithAppId:(NSString*)appId; + +/** + * CRURegistration cannot be initialized without an app ID. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END + +#endif // CHROME_UPDATER_MAC_CLIENT_LIB_CRUREGISTRATION_H_
diff --git a/chrome/updater/mac/client_lib/CRURegistration.m b/chrome/updater/mac/client_lib/CRURegistration.m new file mode 100644 index 0000000..3f1d96c --- /dev/null +++ b/chrome/updater/mac/client_lib/CRURegistration.m
@@ -0,0 +1,38 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "CRURegistration.h" + +#import <Foundation/Foundation.h> +#import <dispatch/dispatch.h> + +@implementation CRURegistration { + // Immutable fields. + NSString* _appId; + + dispatch_queue_t _privateQueue; + dispatch_queue_t _parentQueue; +} + +- (instancetype)initWithAppId:(NSString*)appId + targetQueue:(dispatch_queue_t)targetQueue { + if (self = [super init]) { + _appId = appId; + _parentQueue = targetQueue; + _privateQueue = dispatch_queue_create_with_target( + "CRURegistration", DISPATCH_QUEUE_SERIAL, targetQueue); + } + return self; +} + +- (instancetype)initWithAppId:(NSString*)appId qos:(dispatch_qos_class_t)qos { + return [self initWithAppId:appId + targetQueue:dispatch_get_global_queue(qos, 0)]; +} + +- (instancetype)initWithAppId:(NSString*)appId { + return [self initWithAppId:appId qos:QOS_CLASS_UTILITY]; +} + +@end
diff --git a/chrome/updater/mac/client_lib/CRURegistration_unittests.mm b/chrome/updater/mac/client_lib/CRURegistration_unittests.mm new file mode 100644 index 0000000..9beec2ba --- /dev/null +++ b/chrome/updater/mac/client_lib/CRURegistration_unittests.mm
@@ -0,0 +1,20 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/updater/mac/client_lib/CRURegistration.h" + +#import <Foundation/Foundation.h> + +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +TEST(CRURegistrationTest, SmokeTest) { + CRURegistration* registration = [[CRURegistration alloc] + initWithAppId: + @"org.chromium.ChromiumUpdater.CRURegistrationTest.SmokeTest"]; + ASSERT_TRUE(registration); +} + +} // namespace
diff --git a/chrome/updater/mac/setup/ks_tickets.mm b/chrome/updater/mac/setup/ks_tickets.mm index 0724d70..8fab477 100644 --- a/chrome/updater/mac/setup/ks_tickets.mm +++ b/chrome/updater/mac/setup/ks_tickets.mm
@@ -55,12 +55,12 @@ return nil; } unpacker.requiresSecureCoding = YES; - NSSet* classes = - [NSSet setWithObjects:[NSDictionary class], [KSTicket class], - [KSPathExistenceChecker class], - [KSLaunchServicesExistenceChecker class], - [KSSpotlightExistenceChecker class], - [NSArray class], [NSSet class], [NSURL class], nil]; + NSSet* classes = [NSSet + setWithObjects:[NSDictionary class], [KSTicket class], + [KSPathExistenceChecker class], + [KSLaunchServicesExistenceChecker class], + [KSSpotlightExistenceChecker class], [NSArray class], + [NSSet class], [NSURL class], [NSString class], nil]; store = [unpacker decodeObjectOfClasses:classes forKey:NSKeyedArchiveRootObjectKey]; [unpacker finishDecoding];
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 46a911d..20d415e 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -15889.0.0 \ No newline at end of file +15890.0.0 \ No newline at end of file
diff --git a/chromeos/ash/components/system/statistics_provider.cc b/chromeos/ash/components/system/statistics_provider.cc index 4a9b3e3..cc2f845 100644 --- a/chromeos/ash/components/system/statistics_provider.cc +++ b/chromeos/ash/components/system/statistics_provider.cc
@@ -4,6 +4,7 @@ #include "chromeos/ash/components/system/statistics_provider.h" +#include <array> #include <string_view> #include "base/memory/singleton.h" @@ -29,66 +30,13 @@ // some kevin devices and thus needs to be supported until AUE of these // devices. It's known *not* to be present on caroline. // TODO(tnagel): Remove "Product_S/N" after all devices that have it are AUE. -const char* const kMachineInfoSerialNumberKeys[] = { +constexpr std::array kMachineInfoSerialNumberKeys = { kSerialNumberKey, // VPD v2+ devices (Samsung: caroline and later) kFlexIdKey, // Used by Reven devices kLegacySerialNumberKey, // Samsung legacy }; } // namespace -// Key values for `GetMachineStatistic()`/`GetMachineFlag()` calls. -const char kActivateDateKey[] = "ActivateDate"; -const char kBlockDevModeKey[] = "block_devmode"; -const char kCheckEnrollmentKey[] = "check_enrollment"; -const char kShouldSendRlzPingKey[] = "should_send_rlz_ping"; -const char kShouldSendRlzPingValueFalse[] = "0"; -const char kShouldSendRlzPingValueTrue[] = "1"; -const char kRlzEmbargoEndDateKey[] = "rlz_embargo_end_date"; -const char kEnterpriseManagementEmbargoEndDateKey[] = - "enterprise_management_embargo_end_date"; -const char kCustomizationIdKey[] = "customization_id"; -const char kDevSwitchBootKey[] = "devsw_boot"; -const char kDevSwitchBootValueDev[] = "1"; -const char kDevSwitchBootValueVerified[] = "0"; -const char kDockMacAddressKey[] = "dock_mac"; -const char kEthernetMacAddressKey[] = "ethernet_mac0"; -const char kFirmwareWriteProtectCurrentKey[] = "wpsw_cur"; -const char kFirmwareWriteProtectCurrentValueOn[] = "1"; -const char kFirmwareWriteProtectCurrentValueOff[] = "0"; -const char kFirmwareTypeKey[] = "mainfw_type"; -const char kFirmwareTypeValueDeveloper[] = "developer"; -const char kFirmwareTypeValueNonchrome[] = "nonchrome"; -const char kFirmwareTypeValueNormal[] = "normal"; -const char kHardwareClassKey[] = "hardware_class"; -const char kIsVmKey[] = "is_vm"; -const char kIsVmValueFalse[] = "0"; -const char kIsVmValueTrue[] = "1"; -const char kIsCrosDebugKey[] = "is_cros_debug"; -const char kIsCrosDebugValueFalse[] = "0"; -const char kIsCrosDebugValueTrue[] = "1"; -const char kMachineModelName[] = "model_name"; -const char kMachineOemName[] = "oem_name"; -const char kManufactureDateKey[] = "mfg_date"; -const char kOffersCouponCodeKey[] = "ubind_attribute"; -const char kOffersGroupCodeKey[] = "gbind_attribute"; -const char kRlzBrandCodeKey[] = "rlz_brand_code"; -const char kRegionKey[] = "region"; -const char kSerialNumberKey[] = "serial_number"; -const char kLegacySerialNumberKey[] = "Product_S/N"; -const char kFlexIdKey[] = "flex_id"; -const char kInitialLocaleKey[] = "initial_locale"; -const char kInitialTimezoneKey[] = "initial_timezone"; -const char kKeyboardLayoutKey[] = "keyboard_layout"; -const char kKeyboardMechanicalLayoutKey[] = "keyboard_mechanical_layout"; -const char kAttestedDeviceIdKey[] = "attested_device_id"; -const char kDisplayProfilesKey[] = "display_profiles"; - -// OEM specific statistics. Must be prefixed with "oem_". -const char kOemCanExitEnterpriseEnrollmentKey[] = "oem_can_exit_enrollment"; -const char kOemDeviceRequisitionKey[] = "oem_device_requisition"; -const char kOemIsEnterpriseManagedKey[] = "oem_enterprise_managed"; -const char kOemKeyboardDrivenOobeKey[] = "oem_keyboard_driven_oobe"; - // The StatisticsProvider implementation used in production. class StatisticsProviderSingleton final : public StatisticsProviderImpl { public:
diff --git a/chromeos/ash/components/system/statistics_provider.h b/chromeos/ash/components/system/statistics_provider.h index bcd7f42b..19593d6 100644 --- a/chromeos/ash/components/system/statistics_provider.h +++ b/chromeos/ash/components/system/statistics_provider.h
@@ -14,174 +14,131 @@ namespace ash::system { // Activation date key. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kActivateDateKey[]; +inline constexpr char kActivateDateKey[] = "ActivateDate"; // The key that will be present in VPD if the device was enrolled in a domain // that blocks dev mode. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kBlockDevModeKey[]; +inline constexpr char kBlockDevModeKey[] = "block_devmode"; // The key that will be present in VPD if the device ever was enrolled. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kCheckEnrollmentKey[]; +inline constexpr char kCheckEnrollmentKey[] = "check_enrollment"; // The key and values present in VPD to indicate if RLZ ping should be sent. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kShouldSendRlzPingKey[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kShouldSendRlzPingValueFalse[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kShouldSendRlzPingValueTrue[]; +inline constexpr char kShouldSendRlzPingKey[] = "should_send_rlz_ping"; +inline constexpr char kShouldSendRlzPingValueFalse[] = "0"; +inline constexpr char kShouldSendRlzPingValueTrue[] = "1"; // The key present in VPD that indicates the date after which the RLZ ping is // allowed to be sent. It is in the format of "yyyy-mm-dd". -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kRlzEmbargoEndDateKey[]; +inline constexpr char kRlzEmbargoEndDateKey[] = "rlz_embargo_end_date"; // The key present in VPD that indicates the date after which enterprise // management pings are allowed to be sent. It is in the format of "yyyy-mm-dd". -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kEnterpriseManagementEmbargoEndDateKey[]; +inline constexpr char kEnterpriseManagementEmbargoEndDateKey[] = + "enterprise_management_embargo_end_date"; // Customization ID key. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kCustomizationIdKey[]; +inline constexpr char kCustomizationIdKey[] = "customization_id"; // Developer switch value. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kDevSwitchBootKey[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kDevSwitchBootValueDev[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kDevSwitchBootValueVerified[]; +inline constexpr char kDevSwitchBootKey[] = "devsw_boot"; +inline constexpr char kDevSwitchBootValueDev[] = "1"; +inline constexpr char kDevSwitchBootValueVerified[] = "0"; // Dock MAC address key. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kDockMacAddressKey[]; +inline constexpr char kDockMacAddressKey[] = "dock_mac"; // Ethernet MAC address key. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kEthernetMacAddressKey[]; +inline constexpr char kEthernetMacAddressKey[] = "ethernet_mac0"; // Firmware write protect switch value. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kFirmwareWriteProtectCurrentKey[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kFirmwareWriteProtectCurrentValueOn[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kFirmwareWriteProtectCurrentValueOff[]; +inline constexpr char kFirmwareWriteProtectCurrentKey[] = "wpsw_cur"; +inline constexpr char kFirmwareWriteProtectCurrentValueOn[] = "1"; +inline constexpr char kFirmwareWriteProtectCurrentValueOff[] = "0"; // Firmware type and associated values. The values are from crossystem output // for the mainfw_type key. Normal and developer correspond to Chrome OS // firmware with MP and developer keys respectively, nonchrome indicates the // machine doesn't run on Chrome OS firmware. See crossystem source for more // details. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kFirmwareTypeKey[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kFirmwareTypeValueDeveloper[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kFirmwareTypeValueNonchrome[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kFirmwareTypeValueNormal[]; +inline constexpr char kFirmwareTypeKey[] = "mainfw_type"; +inline constexpr char kFirmwareTypeValueDeveloper[] = "developer"; +inline constexpr char kFirmwareTypeValueNonchrome[] = "nonchrome"; +inline constexpr char kFirmwareTypeValueNormal[] = "normal"; // HWID key. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kHardwareClassKey[]; +inline constexpr char kHardwareClassKey[] = "hardware_class"; // Key/values reporting if Chrome OS is running in a VM or not. These values are // read from crossystem output. See crossystem source for VM detection logic. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) extern const char kIsVmKey[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kIsVmValueFalse[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kIsVmValueTrue[]; +inline constexpr char kIsVmKey[] = "is_vm"; +inline constexpr char kIsVmValueFalse[] = "0"; +inline constexpr char kIsVmValueTrue[] = "1"; // Key/values reporting if ChromeOS is running in debug mode or not. These // values are read from crossystem output. See crossystem source for cros_debug // detection logic. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kIsCrosDebugKey[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kIsCrosDebugValueFalse[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kIsCrosDebugValueTrue[]; +inline constexpr char kIsCrosDebugKey[] = "is_cros_debug"; +inline constexpr char kIsCrosDebugValueFalse[] = "0"; +inline constexpr char kIsCrosDebugValueTrue[] = "1"; // Manufacture date key. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kManufactureDateKey[]; +inline constexpr char kManufactureDateKey[] = "mfg_date"; // OEM customization flag that permits exiting enterprise enrollment flow in // OOBE when 'oem_enterprise_managed' flag is set. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kOemCanExitEnterpriseEnrollmentKey[]; +inline constexpr char kOemCanExitEnterpriseEnrollmentKey[] = + "oem_can_exit_enrollment"; // OEM customization directive that specified intended device purpose. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kOemDeviceRequisitionKey[]; +inline constexpr char kOemDeviceRequisitionKey[] = "oem_device_requisition"; // OEM customization flag that enforces enterprise enrollment flow in OOBE. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kOemIsEnterpriseManagedKey[]; +inline constexpr char kOemIsEnterpriseManagedKey[] = "oem_enterprise_managed"; // OEM customization flag that specifies if OOBE flow should be enhanced for // keyboard driven control. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kOemKeyboardDrivenOobeKey[]; +inline constexpr char kOemKeyboardDrivenOobeKey[] = "oem_keyboard_driven_oobe"; // Offer coupon code key. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kOffersCouponCodeKey[]; +inline constexpr char kOffersCouponCodeKey[] = "ubind_attribute"; // Offer group key. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kOffersGroupCodeKey[]; +inline constexpr char kOffersGroupCodeKey[] = "gbind_attribute"; // Release Brand Code key. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kRlzBrandCodeKey[]; +inline constexpr char kRlzBrandCodeKey[] = "rlz_brand_code"; // Regional data -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) extern const char kRegionKey[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kInitialLocaleKey[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kInitialTimezoneKey[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kKeyboardLayoutKey[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kKeyboardMechanicalLayoutKey[]; +inline constexpr char kRegionKey[] = "region"; +inline constexpr char kInitialLocaleKey[] = "initial_locale"; +inline constexpr char kInitialTimezoneKey[] = "initial_timezone"; +inline constexpr char kKeyboardLayoutKey[] = "keyboard_layout"; +inline constexpr char kKeyboardMechanicalLayoutKey[] = + "keyboard_mechanical_layout"; // The key that will be present in RO VPD to indicate what identifier is used // for attestation-based registration of a device. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kAttestedDeviceIdKey[]; +inline constexpr char kAttestedDeviceIdKey[] = "attested_device_id"; // Serial number key (legacy VPD devices). In most cases, // GetEnterpriseMachineID() is the appropriate way to obtain the serial number. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kLegacySerialNumberKey[]; +inline constexpr char kLegacySerialNumberKey[] = "Product_S/N"; // Serial number key (VPD v2+ devices, Samsung: caroline and later). In most // cases, GetEnterpriseMachineID() is the appropriate way to obtain the serial // number. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kSerialNumberKey[]; +inline constexpr char kSerialNumberKey[] = "serial_number"; // Serial number key for Flex devices. In most cases, GetEnterpriseMachineID() // is the appropriate way to obtain the serial number. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kFlexIdKey[]; +inline constexpr char kFlexIdKey[] = "flex_id"; // Display Profiles key. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kDisplayProfilesKey[]; +inline constexpr char kDisplayProfilesKey[] = "display_profiles"; // Machine model and oem names. -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kMachineModelName[]; -COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) -extern const char kMachineOemName[]; +inline constexpr char kMachineModelName[] = "model_name"; +inline constexpr char kMachineOemName[] = "oem_name"; // This interface provides access to Chrome OS statistics. class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SYSTEM) StatisticsProvider {
diff --git a/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.cc b/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.cc index ea91870..43a2bf8 100644 --- a/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.cc +++ b/chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.cc
@@ -15,7 +15,6 @@ #include "base/task/bind_post_task.h" #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" -#include "base/unguessable_token.h" #include "chromeos/components/cdm_factory_daemon/cdm_storage_adapter.h" #include "chromeos/components/cdm_factory_daemon/content_decryption_module_adapter.h" #include "chromeos/components/cdm_factory_daemon/mojom/content_decryption_module.mojom.h" @@ -159,6 +158,25 @@ }; #endif // BUILDFLAG(IS_CHROMEOS_ASH) +void OnCdmCreated(media::CdmCreatedCB callback, + scoped_refptr<ContentDecryptionModuleAdapter> cdm, + cdm::mojom::CdmFactory::CreateCdmStatus result) { + std::string err; + switch (result) { + case cdm::mojom::CdmFactory::CreateCdmStatus::kSuccess: + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), std::move(cdm), "")); + return; + case cdm::mojom::CdmFactory::CreateCdmStatus::kNoMoreInstances: + err = "Only one instance allowed"; + break; + case cdm::mojom::CdmFactory::CreateCdmStatus::kInsufficientGpuResources: + err = "Insufficient GPU memory available"; + break; + } + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), nullptr, err)); +} } // namespace ChromeOsCdmFactory::ChromeOsCdmFactory( @@ -387,15 +405,15 @@ &GetOutputProtectionOnTaskRunner, output_protection_remote.InitWithNewPipeAndPassReceiver())); - // Now create the remote CDM instance that links everything up. - remote_factory_->CreateCdm(cdm->GetClientInterface(), - std::move(storage_remote), - std::move(output_protection_remote), - base::UnguessableToken::Create().ToString(), - std::move(cros_cdm_pending_receiver)); + url::Origin cdm_origin; + frame_interfaces_->GetCdmOrigin(&cdm_origin); - base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, base::BindOnce(std::move(cdm_created_cb), std::move(cdm), "")); + // Now create the remote CDM instance that links everything up. + remote_factory_->CreateCdm( + cdm->GetClientInterface(), std::move(storage_remote), + std::move(output_protection_remote), cdm_origin.host(), + std::move(cros_cdm_pending_receiver), + base::BindOnce(&OnCdmCreated, std::move(cdm_created_cb), std::move(cdm))); } void ChromeOsCdmFactory::OnFactoryMojoConnectionError() {
diff --git a/chromeos/components/cdm_factory_daemon/mojom/cdm_factory_daemon.mojom b/chromeos/components/cdm_factory_daemon/mojom/cdm_factory_daemon.mojom index cef17c4..bf6d4dd 100644 --- a/chromeos/components/cdm_factory_daemon/mojom/cdm_factory_daemon.mojom +++ b/chromeos/components/cdm_factory_daemon/mojom/cdm_factory_daemon.mojom
@@ -9,7 +9,7 @@ // interface can also be used to connect directly to the OEMCrypto // implementation for ARC. -// Next MinVersion: 9 +// Next MinVersion: 10 module chromeos.cdm.mojom; @@ -26,22 +26,39 @@ interface CdmFactory { // Deprecated, do not use. [MinVersion=1] - CreateCdmDeprecated@1( - pending_associated_remote<ContentDecryptionModuleClient> client, - pending_associated_remote<CdmStorage> storage, - pending_associated_receiver<ContentDecryptionModule> cdm, - pending_remote<OutputProtection> output_protection); + DEPRECATED_1@1( + pending_associated_remote<ContentDecryptionModuleClient> client, + pending_associated_remote<CdmStorage> storage, + pending_associated_receiver<ContentDecryptionModule> cdm, + pending_remote<OutputProtection> output_protection); + + // Deprecated, do not use. + [MinVersion=3] + CreateCdmDeprecated@2( + pending_associated_remote<ContentDecryptionModuleClient> client, + pending_associated_remote<CdmStorage> storage, + pending_remote<OutputProtection> output_protection, + string host, + pending_associated_receiver<ContentDecryptionModule> cdm); + + [Stable, Extensible] + enum CreateCdmStatus { + [Default] kSuccess, + kNoMoreInstances, + kInsufficientGpuResources, + }; // Creates a new ContentDecryptionModule instance for a |host| with the // corresponding |client|, remote |storage| implementation and // |output_protection|. Use an associated interface to ensure ordering and // that all become invalidated at the same time. - [MinVersion=3] - CreateCdm@2(pending_associated_remote<ContentDecryptionModuleClient> client, + [MinVersion=9] + CreateCdm@3(pending_associated_remote<ContentDecryptionModuleClient> client, pending_associated_remote<CdmStorage> storage, pending_remote<OutputProtection> output_protection, string host, - pending_associated_receiver<ContentDecryptionModule> cdm); + pending_associated_receiver<ContentDecryptionModule> cdm) => + (CreateCdmStatus result); }; // Next Method ID: 10
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc index 7549c47..69407c15 100644 --- a/chromeos/constants/chromeos_features.cc +++ b/chromeos/constants/chromeos_features.cc
@@ -200,6 +200,9 @@ "KioskHeartbeatsViaERP", base::FEATURE_DISABLED_BY_DEFAULT); +// Controls enabling / disabling the Magic Boost feature. +BASE_FEATURE(kMagicBoost, "MagicBoost", base::FEATURE_DISABLED_BY_DEFAULT); + // Controls enabling / disabling the mahi feature. BASE_FEATURE(kMahi, "Mahi", base::FEATURE_DISABLED_BY_DEFAULT); #endif // BUILDFLAG(IS_CHROMEOS_ASH) @@ -467,6 +470,14 @@ return IsJellyEnabled() && base::FeatureList::IsEnabled(kJellyroll); } +bool IsMagicBoostEnabled() { +#if BUILDFLAG(IS_CHROMEOS_LACROS) + return chromeos::BrowserParamsProxy::Get()->IsMagicBoostEnabled(); +#else + return base::FeatureList::IsEnabled(kMagicBoost); +#endif +} + bool IsMahiEnabled() { #if BUILDFLAG(IS_CHROMEOS_LACROS) return chromeos::BrowserParamsProxy::Get()->IsMahiEnabled();
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h index 58c11806..ca1a7db 100644 --- a/chromeos/constants/chromeos_features.h +++ b/chromeos/constants/chromeos_features.h
@@ -73,6 +73,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) COMPONENT_EXPORT(CHROMEOS_CONSTANTS) BASE_DECLARE_FEATURE(kKioskHeartbeatsViaERP); +COMPONENT_EXPORT(CHROMEOS_CONSTANTS) BASE_DECLARE_FEATURE(kMagicBoost); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) BASE_DECLARE_FEATURE(kMahi); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) BASE_DECLARE_FEATURE(kSparky); #endif // BUILDFLAG(IS_CHROMEOS_ASH) @@ -141,6 +142,7 @@ bool IsFileSystemProviderContentCacheEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsJellyEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsJellyrollEnabled(); +COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsMagicBoostEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsMahiEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsMahiDebuggingEnabled(); COMPONENT_EXPORT(CHROMEOS_CONSTANTS) bool IsRoundedWindowsEnabled();
diff --git a/chromeos/crosapi/mojom/crosapi.mojom b/chromeos/crosapi/mojom/crosapi.mojom index c508ad4b..a268772 100644 --- a/chromeos/crosapi/mojom/crosapi.mojom +++ b/chromeos/crosapi/mojom/crosapi.mojom
@@ -1152,8 +1152,8 @@ // parameters here. If a new parameter is added and its value is only known // after the user has logged in, please update BrowserPostLoginParams as well. // -// Next version: 89 -// Next id: 89 +// Next version: 90 +// Next id: 90 [Stable, RenamedFrom="crosapi.mojom.LacrosInitParams"] struct BrowserInitParams { // This is ash-chrome's version of the Crosapi interface. This is used by @@ -1659,6 +1659,10 @@ // Set to true when orca internationalization flag is enabled in Ash. [MinVersion=88] bool is_orca_internationalize_enabled@88; + + // If true, "Magic Boost" will be enabled. + [MinVersion=89] + bool is_magic_boost_enabled@89; }; // BrowserPostLoginParams is the subset of parameters in BrowserInitParams
diff --git a/chromeos/startup/browser_params_proxy.cc b/chromeos/startup/browser_params_proxy.cc index 24e8b95..e45f743 100644 --- a/chromeos/startup/browser_params_proxy.cc +++ b/chromeos/startup/browser_params_proxy.cc
@@ -381,6 +381,10 @@ return BrowserInitParams::Get()->is_cros_mall_enabled; } +bool BrowserParamsProxy::IsMagicBoostEnabled() const { + return BrowserInitParams::Get()->is_magic_boost_enabled; +} + bool BrowserParamsProxy::IsMahiEnabled() const { return BrowserInitParams::Get()->is_mahi_enabled; }
diff --git a/chromeos/startup/browser_params_proxy.h b/chromeos/startup/browser_params_proxy.h index 0f2580b..1a69686 100644 --- a/chromeos/startup/browser_params_proxy.h +++ b/chromeos/startup/browser_params_proxy.h
@@ -176,6 +176,8 @@ bool IsCrosMallEnabled() const; + bool IsMagicBoostEnabled() const; + bool IsMahiEnabled() const; bool IsContainerAppPreinstallEnabled() const;
diff --git a/chromeos/ui/frame/interior_resize_handler_targeter.cc b/chromeos/ui/frame/interior_resize_handler_targeter.cc index ea60b3e..5e7c349 100644 --- a/chromeos/ui/frame/interior_resize_handler_targeter.cc +++ b/chromeos/ui/frame/interior_resize_handler_targeter.cc
@@ -9,7 +9,9 @@ namespace chromeos { -InteriorResizeHandleTargeter::InteriorResizeHandleTargeter() { +InteriorResizeHandleTargeter::InteriorResizeHandleTargeter( + WindowStateTypeCallback window_state_type_cb) + : window_state_type_cb_(std::move(window_state_type_cb)) { SetInsets(gfx::Insets(chromeos::kResizeInsideBoundsSize)); } @@ -35,10 +37,12 @@ bool InteriorResizeHandleTargeter::ShouldUseExtendedBounds( const aura::Window* target) const { - // Fullscreen/maximized/pinned windows can't be drag-resized. - // TODO(crbug.com/40143671): Incorporate the check in - // InteriorResizeHandleTargeterAsh::ShouldUseExtendedBounds() override here. - // + // Fullscreen/maximized windows can't be drag-resized. + if (IsMaximizedOrFullscreenOrPinnedWindowStateType( + window_state_type_cb_.Run(window()))) { + return false; + } + // The shrunken hit region only applies to children of |window()|. return target->parent() == window(); }
diff --git a/chromeos/ui/frame/interior_resize_handler_targeter.h b/chromeos/ui/frame/interior_resize_handler_targeter.h index 4cc7362..fdb6ed8 100644 --- a/chromeos/ui/frame/interior_resize_handler_targeter.h +++ b/chromeos/ui/frame/interior_resize_handler_targeter.h
@@ -5,15 +5,22 @@ #ifndef CHROMEOS_UI_FRAME_INTERIOR_RESIZE_HANDLER_TARGETER_H_ #define CHROMEOS_UI_FRAME_INTERIOR_RESIZE_HANDLER_TARGETER_H_ +#include "base/functional/callback.h" +#include "chromeos/ui/base/window_state_type.h" #include "ui/aura/window_targeter.h" namespace chromeos { // This window targeter reserves space for the portion of the resize handles -// that extend within a top level window. +// that extend within a top level window. This targeter is should only be +// installed on frame windows. class InteriorResizeHandleTargeter : public aura::WindowTargeter { public: - InteriorResizeHandleTargeter(); + using WindowStateTypeCallback = + base::RepeatingCallback<WindowStateType(const aura::Window*)>; + + explicit InteriorResizeHandleTargeter( + WindowStateTypeCallback window_state_type_cb); InteriorResizeHandleTargeter(const InteriorResizeHandleTargeter&) = delete; InteriorResizeHandleTargeter& operator=(const InteriorResizeHandleTargeter&) = delete; @@ -24,6 +31,10 @@ gfx::Rect* hit_test_rect_mouse, gfx::Rect* hit_test_rect_touch) const override; bool ShouldUseExtendedBounds(const aura::Window* target) const override; + + private: + // Callback that gets the WindowStateType. + const WindowStateTypeCallback window_state_type_cb_; }; } // namespace chromeos
diff --git a/clank b/clank index fc1c089..96dc252 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit fc1c0897381a14bedb2015ed8d4e0551d2f72088 +Subproject commit 96dc252dcd4740e9bbe8822a8357c5b678cddf01
diff --git a/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc b/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc index 9b6234f8..8886b44 100644 --- a/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc +++ b/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc
@@ -44,87 +44,85 @@ // Parses the `defined_challenge_option` as a 3ds challenge option, and sets the // appropriate fields in `parsed_challenge_option`. void ParseAs3dsChallengeOption( - const base::Value::Dict* defined_challenge_option, - CardUnmaskChallengeOption* parsed_challenge_option) { - parsed_challenge_option->type = + const base::Value::Dict& defined_challenge_option, + CardUnmaskChallengeOption& parsed_challenge_option) { + parsed_challenge_option.type = CardUnmaskChallengeOptionType::kThreeDomainSecure; const auto* challenge_id = - defined_challenge_option->FindString("challenge_id"); + defined_challenge_option.FindString("challenge_id"); if (challenge_id) { - parsed_challenge_option->id = + parsed_challenge_option.id = CardUnmaskChallengeOption::ChallengeOptionId(*challenge_id); } - const auto* url_to_open = - defined_challenge_option->FindString("redirect_url"); + const auto* url_to_open = defined_challenge_option.FindString("redirect_url"); if (url_to_open) { - parsed_challenge_option->url_to_open = GURL(*url_to_open); + parsed_challenge_option.url_to_open = GURL(*url_to_open); } - parsed_challenge_option->challenge_info = l10n_util::GetStringUTF16( + parsed_challenge_option.challenge_info = l10n_util::GetStringUTF16( IDS_AUTOFILL_CARD_UNMASK_AUTHENTICATION_SELECTION_DIALOG_THREE_DOMAIN_SECURE_CHALLENGE_INFO); } // Parses the `defined_challenge_option` as an OTP challenge option, and sets // the appropriate fields in `parsed_challenge_option`. void ParseAsOtpChallengeOption( - const base::Value::Dict* defined_challenge_option, - CardUnmaskChallengeOption* parsed_challenge_option, + const base::Value::Dict& defined_challenge_option, + CardUnmaskChallengeOption& parsed_challenge_option, CardUnmaskChallengeOptionType otp_challenge_option_type) { - parsed_challenge_option->type = otp_challenge_option_type; + parsed_challenge_option.type = otp_challenge_option_type; const auto* challenge_id = - defined_challenge_option->FindString("challenge_id"); + defined_challenge_option.FindString("challenge_id"); DCHECK(challenge_id); - parsed_challenge_option->id = + parsed_challenge_option.id = CardUnmaskChallengeOption::ChallengeOptionId(*challenge_id); const std::string* challenge_info; if (otp_challenge_option_type == CardUnmaskChallengeOptionType::kSmsOtp) { // For SMS OTP challenge, masked phone number is the `challenge_info` for // display. - challenge_info = - defined_challenge_option->FindString("masked_phone_number"); + challenge_info = defined_challenge_option.FindString("masked_phone_number"); } else { CHECK_EQ(otp_challenge_option_type, CardUnmaskChallengeOptionType::kEmailOtp); challenge_info = - defined_challenge_option->FindString("masked_email_address"); + defined_challenge_option.FindString("masked_email_address"); } DCHECK(challenge_info); - parsed_challenge_option->challenge_info = base::UTF8ToUTF16(*challenge_info); + parsed_challenge_option.challenge_info = base::UTF8ToUTF16(*challenge_info); // Get the OTP length for this challenge. This will be displayed to the user // in the OTP input dialog so that the user knows how many digits the OTP // should be. std::optional<int> otp_length = - defined_challenge_option->FindInt("otp_length"); - parsed_challenge_option->challenge_input_length = + defined_challenge_option.FindInt("otp_length"); + parsed_challenge_option.challenge_input_length = otp_length ? *otp_length : kDefaultOtpLength; } // Parses the `defined_challenge_option` as a CVC challenge option, and sets the // appropriate fields in `parsed_challenge_option`. void ParseAsCvcChallengeOption( - const base::Value::Dict* defined_challenge_option, - CardUnmaskChallengeOption* parsed_challenge_option) { - parsed_challenge_option->type = CardUnmaskChallengeOptionType::kCvc; + const base::Value::Dict& defined_challenge_option, + CardUnmaskChallengeOption& parsed_challenge_option) { + parsed_challenge_option.type = CardUnmaskChallengeOptionType::kCvc; // Get the challenge id, which is the unique identifier of this challenge // option. The payments server will need this challenge id to know which // challenge option was selected. const auto* challenge_id = - defined_challenge_option->FindString("challenge_id"); + defined_challenge_option.FindString("challenge_id"); DCHECK(challenge_id); - parsed_challenge_option->id = + parsed_challenge_option.id = CardUnmaskChallengeOption::ChallengeOptionId(*challenge_id); // Get the length of the CVC on the card. In most cases this is 3 digits, // but it is possible for this to be 4 digits, for example in the case of // the Card Identification Number on the front of an American Express card. std::optional<int> cvc_length = - defined_challenge_option->FindInt("cvc_length"); - parsed_challenge_option->challenge_input_length = + defined_challenge_option.FindInt("cvc_length"); + parsed_challenge_option.challenge_input_length = cvc_length ? *cvc_length : kDefaultCvcLength; // Get the position of the CVC on the card. In most cases it will be on the @@ -135,19 +133,19 @@ // end up displaying the authentication selection dialog. std::u16string challenge_info_position_string; const auto* cvc_position = - defined_challenge_option->FindString("cvc_position"); + defined_challenge_option.FindString("cvc_position"); if (cvc_position) { if (*cvc_position == "CVC_POSITION_FRONT") { - parsed_challenge_option->cvc_position = CvcPosition::kFrontOfCard; + parsed_challenge_option.cvc_position = CvcPosition::kFrontOfCard; challenge_info_position_string = l10n_util::GetStringUTF16( IDS_AUTOFILL_CARD_UNMASK_PROMPT_SECURITY_CODE_POSITION_FRONT_OF_CARD); } else if (*cvc_position == "CVC_POSITION_BACK") { - parsed_challenge_option->cvc_position = CvcPosition::kBackOfCard; + parsed_challenge_option.cvc_position = CvcPosition::kBackOfCard; challenge_info_position_string = l10n_util::GetStringUTF16( IDS_AUTOFILL_CARD_UNMASK_PROMPT_SECURITY_CODE_POSITION_BACK_OF_CARD); } else { NOTREACHED_IN_MIGRATION(); - parsed_challenge_option->cvc_position = CvcPosition::kUnknown; + parsed_challenge_option.cvc_position = CvcPosition::kUnknown; } } @@ -156,9 +154,9 @@ // in the authentication selection dialog if we have multiple challenge // options present. if (!challenge_info_position_string.empty()) { - parsed_challenge_option->challenge_info = l10n_util::GetStringFUTF16( + parsed_challenge_option.challenge_info = l10n_util::GetStringFUTF16( IDS_AUTOFILL_CARD_UNMASK_AUTHENTICATION_SELECTION_DIALOG_CVC_CHALLENGE_INFO, - base::NumberToString16(parsed_challenge_option->challenge_input_length), + base::NumberToString16(parsed_challenge_option.challenge_input_length), challenge_info_position_string); } } @@ -173,8 +171,8 @@ // challenge option, and return it. if ((defined_challenge_option = challenge_option.FindDict("sms_otp_challenge_option"))) { - ParseAsOtpChallengeOption(defined_challenge_option, - &parsed_challenge_option, + ParseAsOtpChallengeOption(*defined_challenge_option, + parsed_challenge_option, CardUnmaskChallengeOptionType::kSmsOtp); } // Check if it's an email OTP challenge option, and if it is, set @@ -182,8 +180,8 @@ // challenge option, and return it. else if ((defined_challenge_option = challenge_option.FindDict("email_otp_challenge_option"))) { - ParseAsOtpChallengeOption(defined_challenge_option, - &parsed_challenge_option, + ParseAsOtpChallengeOption(*defined_challenge_option, + parsed_challenge_option, CardUnmaskChallengeOptionType::kEmailOtp); } // Check if it's a CVC challenge option, and if it is, set @@ -191,8 +189,8 @@ // challenge option, and return it. else if ((defined_challenge_option = challenge_option.FindDict("cvc_challenge_option"))) { - ParseAsCvcChallengeOption(defined_challenge_option, - &parsed_challenge_option); + ParseAsCvcChallengeOption(*defined_challenge_option, + parsed_challenge_option); } // Check if it's a 3ds challenge option, and if it is, set // `defined_challenge_option` to the defined challenge option found, parse the @@ -200,8 +198,8 @@ else if ((defined_challenge_option = challenge_option.FindDict("redirect_challenge_option")) && IsVcn3dsEnabled()) { - ParseAs3dsChallengeOption(defined_challenge_option, - &parsed_challenge_option); + ParseAs3dsChallengeOption(*defined_challenge_option, + parsed_challenge_option); } // If it is not a challenge option type that we can parse, return an empty
diff --git a/components/autofill/core/browser/ui/payments/card_unmask_authentication_selection_dialog_controller_impl.cc b/components/autofill/core/browser/ui/payments/card_unmask_authentication_selection_dialog_controller_impl.cc index 4b71109a..fb82012 100644 --- a/components/autofill/core/browser/ui/payments/card_unmask_authentication_selection_dialog_controller_impl.cc +++ b/components/autofill/core/browser/ui/payments/card_unmask_authentication_selection_dialog_controller_impl.cc
@@ -28,6 +28,9 @@ std::move(confirm_unmasking_method_callback)), cancel_unmasking_closure_(std::move(cancel_unmasking_closure)) { CHECK(!challenge_options_.empty()); +#if BUILDFLAG(IS_IOS) + selected_challenge_option_id_ = challenge_options_[0].id; +#endif // BUILDFLAG(IS_IOS) } CardUnmaskAuthenticationSelectionDialogControllerImpl:: @@ -227,7 +230,6 @@ auto selected_challenge_option = base::ranges::find(challenge_options_, selected_challenge_option_id_, &CardUnmaskChallengeOption::id); - switch (selected_challenge_option->type) { case CardUnmaskChallengeOptionType::kSmsOtp: case CardUnmaskChallengeOptionType::kEmailOtp:
diff --git a/components/component_updater/component_installer.cc b/components/component_updater/component_installer.cc index a8cfc85..f84e1dc1 100644 --- a/components/component_updater/component_installer.cc +++ b/components/component_updater/component_installer.cc
@@ -87,7 +87,7 @@ void ComponentInstaller::Register(ComponentUpdateService* cus, base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(cus); + CHECK(cus); std::vector<uint8_t> public_key_hash; installer_policy_->GetHash(&public_key_hash); @@ -183,9 +183,6 @@ } #endif // BUILDFLAG(IS_CHROMEOS_ASH) - DCHECK(!base::PathExists(unpack_path)); - DCHECK(base::PathExists(local_install_path)); - #if BUILDFLAG(IS_APPLE) // Since components can be large and can be re-downloaded when needed, they // are excluded from backups. @@ -453,8 +450,8 @@ const base::Version& max_previous_product_version, scoped_refptr<RegistrationInfo> registration_info) { VLOG(1) << __func__ << " for " << installer_policy_->GetName(); - DCHECK(task_runner_); - DCHECK(task_runner_->RunsTasksInCurrentSequence()); + CHECK(task_runner_); + CHECK(task_runner_->RunsTasksInCurrentSequence()); // First check for an installation set up alongside Chrome itself. base::FilePath root; @@ -483,8 +480,8 @@ } void ComponentInstaller::UninstallOnTaskRunner() { - DCHECK(task_runner_); - DCHECK(task_runner_->RunsTasksInCurrentSequence()); + CHECK(task_runner_); + CHECK(task_runner_->RunsTasksInCurrentSequence()); const std::optional<base::FilePath> base_dir = GetComponentDirectory(); if (!base_dir) {
diff --git a/components/component_updater/component_updater_command_line_config_policy.cc b/components/component_updater/component_updater_command_line_config_policy.cc index 9df7422..8f6a0ef1 100644 --- a/components/component_updater/component_updater_command_line_config_policy.cc +++ b/components/component_updater/component_updater_command_line_config_policy.cc
@@ -71,7 +71,7 @@ ComponentUpdaterCommandLineConfigPolicy:: ComponentUpdaterCommandLineConfigPolicy(const base::CommandLine* cmdline) { - DCHECK(cmdline); + CHECK(cmdline); // Parse comma-delimited debug flags. std::vector<std::string> switch_values = base::SplitString( cmdline->GetSwitchValueASCII(switches::kComponentUpdater), ",", @@ -93,7 +93,6 @@ GetSwitchArgument(switch_values, kSwitchUrlSource); if (!switch_url_source.empty()) { url_source_override_ = GURL(switch_url_source); - DCHECK(url_source_override_.is_valid()); } const std::string initial_delay =
diff --git a/components/component_updater/component_updater_service.cc b/components/component_updater/component_updater_service.cc index e3d4fb6..dbc512c 100644 --- a/components/component_updater/component_updater_service.cc +++ b/components/component_updater/component_updater_service.cc
@@ -331,7 +331,6 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); const auto it = components_.find(id); if (it != components_.end()) { - DCHECK_EQ(it->first, id); if (OnDemandUpdateWithCooldown(id)) { ready_callbacks_.insert(std::make_pair(id, std::move(callback))); return;
diff --git a/components/content_settings/core/browser/cookie_settings.cc b/components/content_settings/core/browser/cookie_settings.cc index 84567ef..fc24e6030 100644 --- a/components/content_settings/core/browser/cookie_settings.cc +++ b/components/content_settings/core/browser/cookie_settings.cc
@@ -192,7 +192,7 @@ } bool CookieSettings::IsStoragePartitioningBypassEnabled( - const GURL& first_party_url) { + const GURL& first_party_url) const { SettingInfo info; ContentSetting setting = host_content_settings_map_->GetContentSetting( GURL(), first_party_url, ContentSettingsType::COOKIES, &info); @@ -354,12 +354,10 @@ CookieSettings::~CookieSettings() = default; +bool CookieSettings::ShouldBlockThirdPartyCookiesInternal() const { #if BUILDFLAG(IS_IOS) -bool CookieSettings::ShouldBlockThirdPartyCookiesInternal() { return false; -} #else -bool CookieSettings::ShouldBlockThirdPartyCookiesInternal() { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(pref_change_registrar_); @@ -385,11 +383,10 @@ case CookieControlsMode::kOff: return false; } - return false; -} #endif +} -bool CookieSettings::MitigationsEnabledFor3pcdInternal() { +bool CookieSettings::MitigationsEnabledFor3pcdInternal() const { if (tracking_protection_settings_ && tracking_protection_settings_->IsTrackingProtection3pcdEnabled()) { // Mitigations should be on iff we are not blocking or allowing all 3PC.
diff --git a/components/content_settings/core/browser/cookie_settings.h b/components/content_settings/core/browser/cookie_settings.h index 62c0edc..04252d0 100644 --- a/components/content_settings/core/browser/cookie_settings.h +++ b/components/content_settings/core/browser/cookie_settings.h
@@ -157,7 +157,7 @@ // - Cases like WebUIs, allowlisted internal apps, and extension iframes are // usually being exempted from storage partitioning or are allowlisted. Thus, // not covered by user bypass at this state of art. - bool IsStoragePartitioningBypassEnabled(const GURL& first_party_url); + bool IsStoragePartitioningBypassEnabled(const GURL& first_party_url) const; const ContentSettingsForOneType GetTpcdMetadataGrants() const { return tpcd_metadata_manager_ ? tpcd_metadata_manager_->GetGrants() @@ -239,11 +239,11 @@ private: // Evaluates if third-party cookies are blocked. Should only be called // when the preference changes to update the internal state. - bool ShouldBlockThirdPartyCookiesInternal(); + bool ShouldBlockThirdPartyCookiesInternal() const; // Evaluates whether third party cookies deprecation mitigations should be // enabled. - bool MitigationsEnabledFor3pcdInternal(); + bool MitigationsEnabledFor3pcdInternal() const; void OnCookiePreferencesChanged();
diff --git a/components/content_settings/core/common/pref_names.h b/components/content_settings/core/common/pref_names.h index 2b76605..bd6ed7ba 100644 --- a/components/content_settings/core/common/pref_names.h +++ b/components/content_settings/core/common/pref_names.h
@@ -17,8 +17,6 @@ // enabled. This will block third-party cookies similar to // kBlockThirdPartyCookies but with a new UI. inline constexpr char kCookieControlsMode[] = "profile.cookie_controls_mode"; -inline constexpr char kBlockTruncatedCookies[] = - "profile.cookie_block_truncated"; // Version of the pattern format used to define content settings. inline constexpr char kContentSettingsVersion[] =
diff --git a/components/cronet/android/cronet_combined_impl_native_proguard_golden.cfg b/components/cronet/android/cronet_combined_impl_native_proguard_golden.cfg index 4bd3e4aa..72042b2 100644 --- a/components/cronet/android/cronet_combined_impl_native_proguard_golden.cfg +++ b/components/cronet/android/cronet_combined_impl_native_proguard_golden.cfg
@@ -10,14 +10,6 @@ # Chromium code. They MUST be scoped appropriately to avoid side effects on app # code that we do not own. -# Use assumevalues block instead of assumenosideeffects block because Google3 -# proguard cannot parse assumenosideeffects blocks which overwrite return -# value. Keep this in shared_with_cronet.flags rather than remove_logging.flags -# so that it's included in cronet. --assumevalues class org.chromium.base.Log { - static boolean isDebug() return false; -} - # Keep all CREATOR fields within Parcelable that are kept. -keepclassmembers class !cr_allowunused,org.chromium.** implements android.os.Parcelable { public static *** CREATOR; @@ -237,4 +229,4 @@ # TODO(crbug.com/315973491): Restrict the broad scope of this rule. -keepclasseswithmembernames,includedescriptorclasses,allowaccessmodification class ** { native <methods>; -} \ No newline at end of file +}
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java index f28673f..c43eccf 100644 --- a/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java +++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java
@@ -111,7 +111,7 @@ private final String mInitialUrl; private final int mInitialPriority; private final String mInitialMethod; - private final String mRequestHeaders[]; + private final String[] mRequestHeaders; private final boolean mDelayRequestHeadersUntilFirstFlush; private final Collection<Object> mRequestAnnotations; private final boolean mTrafficStatsTagSet; @@ -800,7 +800,8 @@ getFinishedReason(), mResponseInfo, mException); - mRequestContext.reportRequestFinished(requestFinishedInfo, mInflightDoneCallbackCount); + mRequestContext.reportRequestFinished( + requestFinishedInfo, mInflightDoneCallbackCount, null); } finally { mInflightDoneCallbackCount.decrement(); } @@ -969,7 +970,7 @@ } private static String[] stringsFromHeaderList(List<Map.Entry<String, String>> headersList) { - String headersArray[] = new String[headersList.size() * 2]; + String[] headersArray = new String[headersList.size() * 2]; int i = 0; for (Map.Entry<String, String> requestHeader : headersList) { headersArray[i++] = requestHeader.getKey();
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java index 205653f11..7c101554 100644 --- a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java +++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java
@@ -1063,38 +1063,8 @@ mFinishedReason, mResponseInfo, mException); - mRequestContext.reportRequestFinished(requestInfo, inflightCallbackCount); - if (mRequestFinishedListener != null) { - inflightCallbackCount.increment(); - try { - mRequestFinishedListener - .getExecutor() - .execute( - new Runnable() { - @Override - public void run() { - try { - mRequestFinishedListener.onRequestFinished( - requestInfo); - } catch (Exception e) { - Log.e( - CronetUrlRequestContext.LOG_TAG, - "Exception thrown from request" - + " finishedlistener", - e); - } finally { - inflightCallbackCount.decrement(); - } - } - }); - } catch (RejectedExecutionException failException) { - Log.e( - CronetUrlRequestContext.LOG_TAG, - "Exception posting task to executor", - failException); - inflightCallbackCount.decrement(); - } - } + mRequestContext.reportRequestFinished( + requestInfo, inflightCallbackCount, mRequestFinishedListener); } finally { inflightCallbackCount.decrement(); }
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java index 838b1e9..35d482d1 100644 --- a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java +++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
@@ -813,12 +813,6 @@ } } - boolean hasRequestFinishedListener() { - synchronized (mFinishedListenerLock) { - return !mFinishedListenerMap.isEmpty(); - } - } - @Override public URLConnection openConnection(URL url) { return openConnection(url, Proxy.NO_PROXY); @@ -974,14 +968,18 @@ } void reportRequestFinished( - final RequestFinishedInfo requestInfo, RefCountDelegate inflightCallbackCount) { - ArrayList<VersionSafeCallbacks.RequestFinishedInfoListener> currentListeners; + final RequestFinishedInfo requestInfo, + RefCountDelegate inflightCallbackCount, + VersionSafeCallbacks.RequestFinishedInfoListener extraRequestFinishedInfoListener) { + List<VersionSafeCallbacks.RequestFinishedInfoListener> currentListeners; synchronized (mFinishedListenerLock) { - if (mFinishedListenerMap.isEmpty()) return; - currentListeners = - new ArrayList<VersionSafeCallbacks.RequestFinishedInfoListener>( - mFinishedListenerMap.values()); + if (mFinishedListenerMap.isEmpty() && extraRequestFinishedInfoListener == null) return; + currentListeners = new ArrayList<>(mFinishedListenerMap.values()); } + if (extraRequestFinishedInfoListener != null) { + currentListeners.add(extraRequestFinishedInfoListener); + } + for (final VersionSafeCallbacks.RequestFinishedInfoListener listener : currentListeners) { Runnable task = new Runnable() {
diff --git a/components/embedder_support/android/util/input_stream.cc b/components/embedder_support/android/util/input_stream.cc index 8cdb9521..54623c4 100644 --- a/components/embedder_support/android/util/input_stream.cc +++ b/components/embedder_support/android/util/input_stream.cc
@@ -5,6 +5,8 @@ #include "components/embedder_support/android/util/input_stream.h" #include "base/android/jni_android.h" +#include "base/feature_list.h" +#include "base/metrics/field_trial_params.h" // Disable "Warnings treated as errors" for input_stream_jni as it's a Java // system class and we have to generate C++ hooks for all methods in the class // even if they're unused. @@ -26,8 +28,21 @@ const int kExceptionThrownStatusCode = -2; } // namespace -// Maximum number of bytes to be read in a single read. -const int InputStream::kBufferSize = 4096; +// Experiment to control the size of the intermediate buffer used to copy from +// Java's InputStream into C++'s net::IOBuffer. +BASE_FEATURE(kEnableCustomInputStreamBufferSize, + "EnableCustomInputStreamBufferSize", + base::FEATURE_DISABLED_BY_DEFAULT); + +// Effectively the maximum number of bytes that will be copied during a JNI call +// to Java_InputStreamUtil_read. +const base::FeatureParam<int> kBufferSize{&kEnableCustomInputStreamBufferSize, + "BufferSize", 4096}; + +// static +int InputStream::GetIntermediateBufferSize() { + return kBufferSize.Get(); +} // TODO: Use unsafe version for all Java_InputStream methods in this file // once BUG 157880 is fixed and implement graceful exception handling. @@ -69,7 +84,7 @@ if (!buffer_.obj()) { // Allocate transfer buffer. base::android::ScopedJavaLocalRef<jbyteArray> temp( - env, env->NewByteArray(kBufferSize)); + env, env->NewByteArray(GetIntermediateBufferSize())); buffer_.Reset(temp); if (ClearException(env)) return false; @@ -80,7 +95,8 @@ *bytes_read = 0; while (remaining_length > 0) { - const int max_transfer_length = std::min(remaining_length, kBufferSize); + const int max_transfer_length = + std::min(remaining_length, GetIntermediateBufferSize()); const int transfer_length = Java_InputStreamUtil_read( env, jobject_, buffer_, 0, max_transfer_length); if (transfer_length == kExceptionThrownStatusCode)
diff --git a/components/embedder_support/android/util/input_stream.h b/components/embedder_support/android/util/input_stream.h index 2a9a097..48df69e1 100644 --- a/components/embedder_support/android/util/input_stream.h +++ b/components/embedder_support/android/util/input_stream.h
@@ -9,6 +9,7 @@ #include "base/android/scoped_java_ref.h" #include "base/compiler_specific.h" +#include "base/feature_list.h" namespace net { class IOBuffer; @@ -16,14 +17,17 @@ namespace embedder_support { +BASE_DECLARE_FEATURE(kEnableCustomInputStreamBufferSize); + // Abstract wrapper used to access the InputStream Java class. // This class is safe to pass around between threads (the destructor, // constructor and methods can be called on different threads) but calling // methods concurrently might have undefined results. class InputStream { public: - // Maximum size of |buffer_|. - static const int kBufferSize; + // Returns the size to be used for the intermediate buffer to copy from Java's + // InputStream into C++'s net::IOBuffer. + static int GetIntermediateBufferSize(); // |stream| should be an instance of the InputStream Java class. // |stream| can't be null.
diff --git a/components/embedder_support/android/util/input_stream_unittest.cc b/components/embedder_support/android/util/input_stream_unittest.cc index a01d9bf..67a9917 100644 --- a/components/embedder_support/android/util/input_stream_unittest.cc +++ b/components/embedder_support/android/util/input_stream_unittest.cc
@@ -2,13 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "components/embedder_support/android/util/input_stream.h" + #include <memory> #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" #include "base/memory/raw_ptr.h" +#include "base/strings/string_number_conversions.h" +#include "base/test/scoped_feature_list.h" #include "components/embedder_support/android/native_j_unittests_jni_headers/InputStreamUnittest_jni.h" -#include "components/embedder_support/android/util/input_stream.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/http/http_byte_range.h" @@ -88,7 +91,7 @@ } TEST_F(InputStreamTest, TryReadMoreThanBuffer) { - const int buffer_size = 3 * InputStream::kBufferSize; + const int buffer_size = 3 * InputStream::GetIntermediateBufferSize(); int bytes_read = 0; DoReadCountedStreamTest(buffer_size, buffer_size * 2, &bytes_read); EXPECT_EQ(buffer_size, bytes_read); @@ -106,19 +109,32 @@ } TEST_F(InputStreamTest, ReadLargeStreamPartial) { - const int bytes_requested = 3 * InputStream::kBufferSize; + const int bytes_requested = 3 * InputStream::GetIntermediateBufferSize(); int bytes_read = 0; DoReadCountedStreamTest(bytes_requested + 32, bytes_requested, &bytes_read); EXPECT_EQ(bytes_requested, bytes_read); } TEST_F(InputStreamTest, ReadLargeStreamCompletely) { - const int bytes_requested = 3 * InputStream::kBufferSize; + const int bytes_requested = 3 * InputStream::GetIntermediateBufferSize(); int bytes_read = 0; DoReadCountedStreamTest(bytes_requested, bytes_requested, &bytes_read); EXPECT_EQ(bytes_requested, bytes_read); } +TEST_F(InputStreamTest, CustomInputStreamBufferSize) { + constexpr int custom_buffer_size = 1024; + EXPECT_NE(InputStream::GetIntermediateBufferSize(), custom_buffer_size); + + base::test::ScopedFeatureList feature_list; + base::FieldTrialParams params; + params["BufferSize"] = base::NumberToString(custom_buffer_size); + + feature_list.InitAndEnableFeatureWithParameters( + embedder_support::kEnableCustomInputStreamBufferSize, params); + EXPECT_EQ(InputStream::GetIntermediateBufferSize(), custom_buffer_size); +} + TEST_F(InputStreamTest, DoesNotCrashWhenExceptionThrown) { ScopedJavaLocalRef<jobject> throw_jstream = Java_InputStreamUnittest_getThrowingStream(env_);
diff --git a/components/enterprise/data_controls/BUILD.gn b/components/enterprise/data_controls/BUILD.gn index 0d472135..c4b5096 100644 --- a/components/enterprise/data_controls/BUILD.gn +++ b/components/enterprise/data_controls/BUILD.gn
@@ -70,6 +70,7 @@ ] public_deps = [ ":data_controls", + ":features", "//base", "//components/policy/core/common:common_constants", "//components/prefs",
diff --git a/components/enterprise/data_controls/features.cc b/components/enterprise/data_controls/features.cc index 2eda736..08782ee6 100644 --- a/components/enterprise/data_controls/features.cc +++ b/components/enterprise/data_controls/features.cc
@@ -10,4 +10,8 @@ "EnableDesktopDataControls", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kEnableScreenshotProtection, + "EnableScreenshotProtection", + base::FEATURE_DISABLED_BY_DEFAULT); + } // namespace data_controls
diff --git a/components/enterprise/data_controls/features.h b/components/enterprise/data_controls/features.h index c12e6b5c..bc409df 100644 --- a/components/enterprise/data_controls/features.h +++ b/components/enterprise/data_controls/features.h
@@ -12,8 +12,18 @@ // Controls enabling Data Controls for all desktop browser platforms (Windows, // Mac, Linux, CrOS). Policies controlling cross-platform Data Controls will be // ignored if this feature is disabled. +// +// Use `kEnableScreenshotProtection` to gate the implementation of screenshot +// protection rules instead of this feature. BASE_DECLARE_FEATURE(kEnableDesktopDataControls); +// Controls enabling screenshot blocking Data Controls rules for supported +// desktop browser platforms (Windows, Mac). +// +// Use `kEnableDesktopDataControls` to gate the implementation ofother rule +// types. +BASE_DECLARE_FEATURE(kEnableScreenshotProtection); + } // namespace data_controls #endif // COMPONENTS_ENTERPRISE_DATA_CONTROLS_FEATURES_H_
diff --git a/components/enterprise/data_controls/rule.cc b/components/enterprise/data_controls/rule.cc index a07583a..e588b76 100644 --- a/components/enterprise/data_controls/rule.cc +++ b/components/enterprise/data_controls/rule.cc
@@ -8,10 +8,12 @@ #include <vector> #include "base/containers/fixed_flat_map.h" +#include "base/feature_list.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "components/enterprise/data_controls/and_condition.h" #include "components/enterprise/data_controls/attributes_condition.h" +#include "components/enterprise/data_controls/features.h" #include "components/enterprise/data_controls/not_condition.h" #include "components/enterprise/data_controls/or_condition.h" #include "components/policy/core/browser/policy_error_map.h" @@ -96,6 +98,15 @@ return new_error_path; } +// Helper to check if a restriction is allowed to be applied to a rule given +// the currently enabled features. +bool IgnoreRestriction(Rule::Restriction restriction) { + if (restriction == Rule::Restriction::kScreenshot) { + return !base::FeatureList::IsEnabled(kEnableScreenshotProtection); + } + return !base::FeatureList::IsEnabled(kEnableDesktopDataControls); +} + } // namespace Rule::Rule(Rule&& other) = default; @@ -128,6 +139,15 @@ } auto restrictions = GetRestrictions(value); + + // To avoid create a `Rule` object with restrictions for disabled features, + // `restrictions` is first filtered. This is done here instead of in + // `GetRestrictions()` so that it can still be used by policy handler code to + // parse the policy correctly. + base::EraseIf(restrictions, [](const auto& entry) { + return IgnoreRestriction(entry.first); + }); + if (restrictions.empty()) { return std::nullopt; }
diff --git a/components/enterprise/data_controls/rule.h b/components/enterprise/data_controls/rule.h index eeec092..c2ed7ab 100644 --- a/components/enterprise/data_controls/rule.h +++ b/components/enterprise/data_controls/rule.h
@@ -145,7 +145,7 @@ // } // For compatibility, unrecognized values are ignored and valid values are // still included in the output. - static base::flat_map<Rule::Restriction, Rule::Level> GetRestrictions( + static base::flat_map<Restriction, Level> GetRestrictions( const base::Value::Dict& value); // Helper used to recursively validate a rule. This should only be called by @@ -153,7 +153,7 @@ static bool ValidateRuleSubValues( const char* policy_name, const base::Value::Dict& value, - const base::flat_map<Rule::Restriction, Rule::Level>& restrictions, + const base::flat_map<Restriction, Level>& restrictions, policy::PolicyErrorPath error_path, policy::PolicyErrorMap* errors); @@ -172,7 +172,7 @@ static bool AddUnsupportedAttributeErrors( const std::vector<std::string_view>& oneof_conditions, const std::vector<std::string_view>& anyof_conditions, - base::flat_map<Rule::Restriction, Rule::Level> restrictions, + base::flat_map<Restriction, Level> restrictions, const char* policy_name, policy::PolicyErrorPath error_path, policy::PolicyErrorMap* errors); @@ -182,7 +182,7 @@ // if at least one error was added. static bool AddUnsupportedRestrictionErrors( const char* policy_name, - const base::flat_map<Rule::Restriction, Rule::Level>& restrictions, + const base::flat_map<Restriction, Level>& restrictions, policy::PolicyErrorPath error_path, policy::PolicyErrorMap* errors);
diff --git a/components/enterprise/data_controls/rule_unittest.cc b/components/enterprise/data_controls/rule_unittest.cc index bc21282..f25e3a3 100644 --- a/components/enterprise/data_controls/rule_unittest.cc +++ b/components/enterprise/data_controls/rule_unittest.cc
@@ -7,10 +7,13 @@ #include <tuple> #include <vector> +#include "base/feature_list.h" #include "base/json/json_reader.h" #include "base/logging.h" #include "base/strings/stringprintf.h" +#include "base/test/scoped_feature_list.h" #include "base/values.h" +#include "components/enterprise/data_controls/features.h" #include "testing/gtest/include/gtest/gtest.h" namespace data_controls { @@ -23,6 +26,48 @@ return Rule::Create(*dict); } +class DataControlsRuleTest : public testing::Test { + public: + explicit DataControlsRuleTest(bool desktop_feature_enabled = true, + bool screenshot_feature_enabled = true) { + std::vector<base::test::FeatureRef> enabled_features; + std::vector<base::test::FeatureRef> disabled_features; + + if (desktop_feature_enabled) { + enabled_features.push_back(kEnableDesktopDataControls); + } else { + disabled_features.push_back(kEnableDesktopDataControls); + } + + if (screenshot_feature_enabled) { + enabled_features.push_back(kEnableScreenshotProtection); + } else { + disabled_features.push_back(kEnableScreenshotProtection); + } + + scoped_features_.InitWithFeatures(enabled_features, disabled_features); + } + + protected: + base::test::ScopedFeatureList scoped_features_; +}; + +class DataControlsFeaturesRuleTest + : public DataControlsRuleTest, + public testing::WithParamInterface<std::tuple<bool, bool>> { + public: + DataControlsFeaturesRuleTest() + : DataControlsRuleTest(desktop_feature_enabled(), + screenshot_feature_enabled()) {} + + bool desktop_feature_enabled() const { return std::get<0>(GetParam()); } + bool screenshot_feature_enabled() const { return std::get<1>(GetParam()); } +}; + +INSTANTIATE_TEST_SUITE_P(All, + DataControlsFeaturesRuleTest, + testing::Combine(testing::Bool(), testing::Bool())); + struct AndOrNotTestCase { const char* conditions; ActionContext context; @@ -33,7 +78,8 @@ // attribute. This is parametrized with conditions and a corresponding context // to trigger them. class DataControlsRuleNotTest - : public testing::TestWithParam<AndOrNotTestCase> { + : public DataControlsRuleTest, + public testing::WithParamInterface<AndOrNotTestCase> { public: std::string normal_rule_string() { return base::StringPrintf(R"( @@ -68,7 +114,8 @@ // inserted into an "and" attribute. This is parametrized with conditions and a // corresponding context to trigger them. class DataControlsRuleAndTest - : public testing::TestWithParam<AndOrNotTestCase> { + : public DataControlsRuleTest, + public testing::WithParamInterface<AndOrNotTestCase> { public: std::string rule_string() { return base::StringPrintf(R"( @@ -89,7 +136,9 @@ // Test to validate that a valid set of conditions in a rule will trigger when // inserted into an "or" attribute. This is parametrized with conditions and a // corresponding context to trigger them. -class DataControlsRuleOrTest : public testing::TestWithParam<AndOrNotTestCase> { +class DataControlsRuleOrTest + : public DataControlsRuleTest, + public testing::WithParamInterface<AndOrNotTestCase> { public: std::string rule_string() { return base::StringPrintf(R"( @@ -229,7 +278,7 @@ } // namespace -TEST(DataControlsRuleTest, InvalidValues) { +TEST_F(DataControlsRuleTest, InvalidValues) { ASSERT_FALSE(Rule::Create(base::Value(1))); ASSERT_FALSE(Rule::Create(base::Value(-1))); ASSERT_FALSE(Rule::Create(base::Value(true))); @@ -244,7 +293,7 @@ ASSERT_FALSE(Rule::Create(base::Value(std::vector<char>({1, 2, 3, 4})))); } -TEST(DataControlsRuleTest, InvalidConditions) { +TEST_F(DataControlsRuleTest, InvalidConditions) { // First parameter should be "sources", second one should be "destinations". constexpr char kTemplate[] = R"({ "name": "Block pastes", @@ -298,7 +347,7 @@ kTemplate, "", R"("or": {"sources": {"urls": ["or.is.not.a.dict"]}},)"))); } -TEST(DataControlsRuleTest, ValidSourcesInvalidDestinationsConditions) { +TEST_F(DataControlsRuleTest, ValidSourcesInvalidDestinationsConditions) { // Rules with a valid sources but invalid destinations should be created for // forward compatibility. constexpr char kTemplate[] = R"({ @@ -329,7 +378,7 @@ #endif // BUILDFLAG(IS_CHROMEOS) } -TEST(DataControlsRuleTest, InvalidSourcesValidDestinationsConditions) { +TEST_F(DataControlsRuleTest, InvalidSourcesValidDestinationsConditions) { // Rules with a valid destinations but valid destinations should be created // for forward compatibility. constexpr char kTemplate[] = R"({ @@ -352,7 +401,7 @@ kTemplate, R"("sources": {"urls": ["not_a_real:pattern"]},)"))); } -TEST(DataControlsRuleTest, NoRestrictions) { +TEST_F(DataControlsRuleTest, NoRestrictions) { ASSERT_FALSE(MakeRule(R"({ "name": "Block pastes", "rule_id": "1234", @@ -361,7 +410,7 @@ })")); } -TEST(DataControlsRuleTest, InvalidRestrictions) { +TEST_F(DataControlsRuleTest, InvalidRestrictions) { constexpr char kTemplate[] = R"({ "name": "Block pastes", "rule_id": "1234", @@ -377,7 +426,7 @@ MakeRule(base::StringPrintf(kTemplate, R"(["not_a_real_restriction"])"))); } -TEST(DataControlsRuleTest, Restrictions) { +TEST_F(DataControlsRuleTest, Restrictions) { auto rule = MakeRule(R"({ "name": "Block pastes", "rule_id": "1234", @@ -407,7 +456,7 @@ Rule::Level::kNotSet); } -TEST(DataControlsRuleTest, Accessors) { +TEST_F(DataControlsRuleTest, Accessors) { auto rule = MakeRule(R"({ "name": "Block pastes", "rule_id": "1234", @@ -424,7 +473,7 @@ ASSERT_EQ(rule->description(), "A test rule to block pastes"); } -TEST(DataControlsRuleTest, SourceUrls) { +TEST_F(DataControlsRuleTest, SourceUrls) { auto rule = MakeRule(R"({ "name": "Block pastes", "rule_id": "1234", @@ -444,7 +493,7 @@ Rule::Level::kNotSet); } -TEST(DataControlsRuleTest, DestinationUrls) { +TEST_F(DataControlsRuleTest, DestinationUrls) { auto rule = MakeRule(R"({ "name": "Block pastes", "rule_id": "1234", @@ -466,7 +515,7 @@ Rule::Level::kNotSet); } -TEST(DataControlsRuleTest, SourceAndDestinationUrls) { +TEST_F(DataControlsRuleTest, SourceAndDestinationUrls) { auto rule = MakeRule(R"({ "name": "Block pastes", "rule_id": "1234", @@ -510,7 +559,7 @@ } #if BUILDFLAG(IS_CHROMEOS) -TEST(DataControlsRuleTest, DestinationComponent) { +TEST_F(DataControlsRuleTest, DestinationComponent) { // A "FOO" component is included to validate that compatibility with future // components works and doesn't interfere with the rest of the rule. auto rule = MakeRule(R"({ @@ -548,6 +597,55 @@ } #endif // BUILDFLAG(IS_CHROMEOS) +TEST_P(DataControlsFeaturesRuleTest, ScreenshotRules) { + auto rule = MakeRule(R"({ + "name": "Block screenshots", + "rule_id": "1234", + "description": "A test rule to block screenshots", + "sources": { "urls": ["*"] }, + "restrictions": [ + { "class": "SCREENSHOT", "level": "BLOCK" } + ] + })"); + if (screenshot_feature_enabled()) { + ASSERT_TRUE(rule); + ASSERT_EQ(rule->GetLevel(Rule::Restriction::kScreenshot, + {.source = {.url = GURL("https://google.com")}}), + Rule::Level::kBlock); + } else { + ASSERT_FALSE(rule); + } +} + +TEST_P(DataControlsFeaturesRuleTest, NonScreenshotRules) { + auto rule = MakeRule(R"({ + "name": "Block stuff", + "rule_id": "1234", + "description": "A test rule to block some non-screenshot actions", + "destinations": { "urls": ["*"] }, + "restrictions": [ + { "class": "CLIPBOARD", "level": "BLOCK" }, + { "class": "PRINTING", "level": "ALLOW" }, + { "class": "PRIVACY_SCREEN", "level": "REPORT" } + ] + })"); + if (desktop_feature_enabled()) { + ASSERT_TRUE(rule); + ActionContext context = { + .destination = {.url = GURL("https://google.com")}}; + ASSERT_EQ(rule->GetLevel(Rule::Restriction::kClipboard, context), + Rule::Level::kBlock); + ASSERT_EQ(rule->GetLevel(Rule::Restriction::kPrinting, context), + Rule::Level::kAllow); + ASSERT_EQ(rule->GetLevel(Rule::Restriction::kPrivacyScreen, context), + Rule::Level::kReport); + ASSERT_EQ(rule->GetLevel(Rule::Restriction::kScreenshot, context), + Rule::Level::kNotSet); + } else { + ASSERT_FALSE(rule); + } +} + TEST_P(DataControlsRuleNotTest, TriggeringContext) { auto normal_rule = MakeRule(normal_rule_string()); auto negative_rule = MakeRule(negative_rule_string());
diff --git a/components/enterprise/data_controls/rules_service.cc b/components/enterprise/data_controls/rules_service.cc index 0d8b008e..4bdf650 100644 --- a/components/enterprise/data_controls/rules_service.cc +++ b/components/enterprise/data_controls/rules_service.cc
@@ -10,7 +10,8 @@ namespace data_controls { RulesService::RulesService(PrefService* pref_service) { - if (base::FeatureList::IsEnabled(kEnableDesktopDataControls)) { + if (base::FeatureList::IsEnabled(kEnableDesktopDataControls) || + base::FeatureList::IsEnabled(kEnableScreenshotProtection)) { pref_registrar_.Init(pref_service); pref_registrar_.Add( kDataControlsRulesPref, @@ -24,7 +25,8 @@ Verdict RulesService::GetVerdict(Rule::Restriction restriction, const ActionContext& context) const { - if (!base::FeatureList::IsEnabled(kEnableDesktopDataControls)) { + if (!base::FeatureList::IsEnabled(kEnableDesktopDataControls) && + !base::FeatureList::IsEnabled(kEnableScreenshotProtection)) { return Verdict::NotSet(); } @@ -56,10 +58,6 @@ void RulesService::OnDataControlsRulesUpdate() { DCHECK(pref_registrar_.prefs()); - if (!base::FeatureList::IsEnabled(kEnableDesktopDataControls)) { - return; - } - rules_.clear(); const base::Value::List& rules_list =
diff --git a/components/facilitated_payments/core/browser/network_api/facilitated_payments_initiate_payment_request.cc b/components/facilitated_payments/core/browser/network_api/facilitated_payments_initiate_payment_request.cc index 7805791..998c2f46 100644 --- a/components/facilitated_payments/core/browser/network_api/facilitated_payments_initiate_payment_request.cc +++ b/components/facilitated_payments/core/browser/network_api/facilitated_payments_initiate_payment_request.cc
@@ -124,10 +124,12 @@ } bool FacilitatedPaymentsInitiatePaymentRequest::IsResponseComplete() { - return false; + return !response_details_->action_token_.empty(); } void FacilitatedPaymentsInitiatePaymentRequest::RespondToDelegate( - autofill::AutofillClient::PaymentsRpcResult result) {} + autofill::AutofillClient::PaymentsRpcResult result) { + std::move(response_callback_).Run(result, std::move(response_details_)); +} } // namespace payments::facilitated
diff --git a/components/facilitated_payments/core/browser/network_api/facilitated_payments_initiate_payment_request_unittest.cc b/components/facilitated_payments/core/browser/network_api/facilitated_payments_initiate_payment_request_unittest.cc index dd09f0f574..af35d3ce 100644 --- a/components/facilitated_payments/core/browser/network_api/facilitated_payments_initiate_payment_request_unittest.cc +++ b/components/facilitated_payments/core/browser/network_api/facilitated_payments_initiate_payment_request_unittest.cc
@@ -98,6 +98,9 @@ std::vector<uint8_t> expected_action_token = {'t', 'o', 'k', 'e', 'n'}; EXPECT_EQ(expected_action_token, request->response_details_->action_token_); + + // Verify that the response is considered complete. + EXPECT_TRUE(request->IsResponseComplete()); } TEST_F(FacilitatedPaymentsInitiatePaymentRequestTest, @@ -112,6 +115,9 @@ EXPECT_EQ("Something went wrong!", request->response_details_->error_message_.value()); + + // Verify that the response is considered incomplete. + EXPECT_FALSE(request->IsResponseComplete()); } } // namespace payments::facilitated
diff --git a/components/feature_engagement/public/feature_configurations.cc b/components/feature_engagement/public/feature_configurations.cc index 0d1b8342..ede7bae 100644 --- a/components/feature_engagement/public/feature_configurations.cc +++ b/components/feature_engagement/public/feature_configurations.cc
@@ -289,6 +289,22 @@ return config; } + if (kIPHExplicitBrowserSigninPreferenceRememberedFeature.name == + feature->name) { + std::optional<FeatureConfig> config = FeatureConfig(); + config->valid = true; + config->availability = Comparator(ANY, 0); + config->session_rate = Comparator(ANY, 0); + config->session_rate_impact.type = SessionRateImpact::Type::ALL; + config->trigger = EventConfig( + "iph_explicit_browser_signin_preference_remembered_triggered", + Comparator(ANY, 0), 0, 0); + config->used = + EventConfig("iph_explicit_browser_signin_preference_remembered_used", + Comparator(ANY, 0), 0, 0); + return config; + } + if (kIPHTrackingProtectionOffboardingFeature.name == feature->name) { std::optional<FeatureConfig> config = FeatureConfig(); config->valid = true;
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc index 5b4a9cc..c298a4b3 100644 --- a/components/feature_engagement/public/feature_constants.cc +++ b/components/feature_engagement/public/feature_constants.cc
@@ -61,6 +61,9 @@ BASE_FEATURE(kIPHExperimentalAIPromoFeature, "IPH_ExperimentalAIPromo", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kIPHExplicitBrowserSigninPreferenceRememberedFeature, + "IPH_ExplicitBrowserSigninPreferenceRemembered", + base::FEATURE_ENABLED_BY_DEFAULT); #if BUILDFLAG(ENABLE_EXTENSIONS) BASE_FEATURE(kIPHExtensionsMenuFeature, "IPH_ExtensionsMenu",
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h index 4d12e351..b766ee9a 100644 --- a/components/feature_engagement/public/feature_constants.h +++ b/components/feature_engagement/public/feature_constants.h
@@ -35,6 +35,7 @@ BASE_DECLARE_FEATURE(kIPHDiscardRingFeature); BASE_DECLARE_FEATURE(kIPHDownloadEsbPromoFeature); BASE_DECLARE_FEATURE(kIPHExperimentalAIPromoFeature); +BASE_DECLARE_FEATURE(kIPHExplicitBrowserSigninPreferenceRememberedFeature); #if BUILDFLAG(ENABLE_EXTENSIONS) BASE_DECLARE_FEATURE(kIPHExtensionsMenuFeature); BASE_DECLARE_FEATURE(kIPHExtensionsRequestAccessButtonFeature);
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc index d6ff1891..e33847b 100644 --- a/components/feature_engagement/public/feature_list.cc +++ b/components/feature_engagement/public/feature_list.cc
@@ -162,6 +162,7 @@ &kIPHDiscardRingFeature, &kIPHDownloadEsbPromoFeature, &kIPHExperimentalAIPromoFeature, + &kIPHExplicitBrowserSigninPreferenceRememberedFeature, #if BUILDFLAG(ENABLE_EXTENSIONS) &kIPHExtensionsMenuFeature, &kIPHExtensionsRequestAccessButtonFeature,
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h index dc8c1be..e172dfe 100644 --- a/components/feature_engagement/public/feature_list.h +++ b/components/feature_engagement/public/feature_list.h
@@ -288,6 +288,8 @@ "IPH_DownloadToolbarButton"); DEFINE_VARIATION_PARAM(kIPHExperimentalAIPromoFeature, "IPH_ExperimentalAIPromo"); +DEFINE_VARIATION_PARAM(kIPHExplicitBrowserSigninPreferenceRememberedFeature, + "IPH_ExplicitBrowserSigninPreferenceRemembered"); #if BUILDFLAG(ENABLE_EXTENSIONS) DEFINE_VARIATION_PARAM(kIPHExtensionsMenuFeature, "IPH_ExtensionsMenu"); DEFINE_VARIATION_PARAM(kIPHExtensionsRequestAccessButtonFeature, @@ -618,6 +620,7 @@ VARIATION_ENTRY(kIPHDiscardRingFeature), VARIATION_ENTRY(kIPHDownloadToolbarButtonFeature), VARIATION_ENTRY(kIPHExperimentalAIPromoFeature), + VARIATION_ENTRY(kIPHExplicitBrowserSigninPreferenceRememberedFeature), #if BUILDFLAG(ENABLE_EXTENSIONS) VARIATION_ENTRY(kIPHExtensionsMenuFeature), VARIATION_ENTRY(kIPHExtensionsRequestAccessButtonFeature),
diff --git a/components/heap_profiling/in_process/BUILD.gn b/components/heap_profiling/in_process/BUILD.gn index c68c5712..0018ed9 100644 --- a/components/heap_profiling/in_process/BUILD.gn +++ b/components/heap_profiling/in_process/BUILD.gn
@@ -10,6 +10,14 @@ deps = [ "//mojo/public/mojom/base" ] } +mojom("test_mojom") { + sources = [ "mojom/test_connector.mojom" ] + deps = [ + ":mojom", + "//components/metrics/public/mojom:call_stack_mojo_bindings", + ] +} + source_set("in_process") { # HeapProfilerController's dependencies are not compiled on iOS unless # use_allocator_shim is true. @@ -53,12 +61,14 @@ deps = [ ":in_process", ":mojom", + ":test_mojom", "//base/test:test_support", "//components/metrics", "//components/metrics:child_call_stack_profile_builder", "//components/metrics/public/mojom:call_stack_mojo_bindings", "//components/variations", "//components/version_info", + "//mojo/core/test:test_support", "//mojo/public/cpp/bindings", ] }
diff --git a/components/heap_profiling/in_process/DEPS b/components/heap_profiling/in_process/DEPS index bb01966..62a658e 100644 --- a/components/heap_profiling/in_process/DEPS +++ b/components/heap_profiling/in_process/DEPS
@@ -10,7 +10,8 @@ specific_include_rules = { "heap_profiler_controller_unittest\.cc": [ "+components/metrics/public/mojom/call_stack_profile_collector.mojom.h", - "+third_party/metrics_proto/execution_context.pb.h", - "+third_party/metrics_proto/sampled_profile.pb.h", + "+mojo/core/embedder", + "+mojo/public/cpp", + "+third_party/metrics_proto", ], }
diff --git a/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc b/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc index 2f3478453..66726b4 100644 --- a/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc +++ b/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc
@@ -5,6 +5,7 @@ #include "components/heap_profiling/in_process/heap_profiler_controller.h" #include <atomic> +#include <map> #include <memory> #include <string> #include <utility> @@ -23,11 +24,17 @@ #include "base/memory/scoped_refptr.h" #include "base/metrics/field_trial_params.h" #include "base/notreached.h" +#include "base/process/launch.h" +#include "base/process/process.h" #include "base/sampling_heap_profiler/poisson_allocation_sampler.h" #include "base/sampling_heap_profiler/sampling_heap_profiler.h" +#include "base/strings/string_number_conversions.h" +#include "base/task/bind_post_task.h" #include "base/task/sequenced_task_runner.h" +#include "base/task/single_thread_task_runner.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/multiprocess_test.h" #include "base/test/scoped_command_line.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" @@ -39,16 +46,25 @@ #include "components/heap_profiling/in_process/child_process_snapshot_controller.h" #include "components/heap_profiling/in_process/heap_profiler_parameters.h" #include "components/heap_profiling/in_process/mojom/snapshot_controller.mojom.h" +#include "components/heap_profiling/in_process/mojom/test_connector.mojom.h" #include "components/heap_profiling/in_process/switches.h" #include "components/metrics/call_stacks/call_stack_profile_builder.h" #include "components/metrics/call_stacks/call_stack_profile_params.h" #include "components/metrics/public/mojom/call_stack_profile_collector.mojom.h" #include "components/version_info/channel.h" +#include "mojo/core/embedder/scoped_ipc_support.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" -#include "mojo/public/cpp/bindings/self_owned_receiver.h" +#include "mojo/public/cpp/bindings/remote_set.h" +#include "mojo/public/cpp/bindings/unique_receiver_set.h" +#include "mojo/public/cpp/platform/platform_channel.h" +#include "mojo/public/cpp/system/invitation.h" +#include "mojo/public/cpp/system/message_pipe.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "testing/multiprocess_func_list.h" +#include "third_party/metrics_proto/call_stack_profile.pb.h" #include "third_party/metrics_proto/execution_context.pb.h" #include "third_party/metrics_proto/sampled_profile.pb.h" @@ -56,11 +72,19 @@ namespace { +#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID) +#define ENABLE_MULTIPROCESS_TESTS 0 +#else +#define ENABLE_MULTIPROCESS_TESTS 1 +#endif + using FeatureRef = base::test::FeatureRef; using FeatureRefAndParams = base::test::FeatureRefAndParams; using ProcessType = metrics::CallStackProfileParams::Process; using ProcessTypeSet = base::EnumSet<ProcessType, ProcessType::kUnknown, ProcessType::kMax>; +using ProfileCollectorCallback = + base::RepeatingCallback<void(base::TimeTicks, metrics::SampledProfile)>; using base::allocator::dispatcher::AllocationNotificationData; using base::allocator::dispatcher::AllocationSubsystem; using base::allocator::dispatcher::FreeNotificationData; @@ -69,12 +93,16 @@ using ScopedSuppressRandomnessForTesting = base::PoissonAllocationSampler::ScopedSuppressRandomnessForTesting; +using ::testing::AllOf; +using ::testing::Conditional; +using ::testing::ElementsAre; +using ::testing::IsEmpty; +using ::testing::Property; +using ::testing::UnorderedElementsAre; + constexpr size_t kSamplingRate = 1024; constexpr size_t kAllocationSize = 42 * kSamplingRate; -using ProfileCollectorCallback = - base::RepeatingCallback<void(base::TimeTicks, metrics::SampledProfile)>; - // A fake CallStackProfileCollector that deserializes profiles it receives from // a fake child process, and passes them to the same callback that receives // profiles from the fake browser process. @@ -122,7 +150,7 @@ // expected to be invoked. If not, first_snapshot_callback() returns a // callback that's expected not to run. // - // If `expect_sampled_profile` is true, HeapProfilerController::TakeSnapshot() + // If `expected_sampled_profiles` > 0, HeapProfilerController::TakeSnapshot() // should find a sample to pass to CallStackProfileBuilder, so // collector_callback() returns a callback that's expected to be invoked. It // will also run the given `profile_collector_callback`. If not, @@ -133,7 +161,7 @@ // in another process, so other_process_callback() will return a callback to // invoke for this. ScopedCallbacks(bool expect_take_snapshot, - bool expect_sampled_profile, + size_t expected_sampled_profiles, bool use_other_process_callback, ProfileCollectorCallback profile_collector_callback, base::OnceClosure quit_closure) { @@ -141,9 +169,7 @@ if (expect_take_snapshot) { num_callbacks += 1; } - if (expect_sampled_profile) { - num_callbacks += 1; - } + num_callbacks += expected_sampled_profiles; if (use_other_process_callback) { // The test should invoke other_process_snapshot_callback() to simulate a // snapshot in another process. @@ -172,19 +198,19 @@ }); collector_callback_ = base::BindLambdaForTesting( - [this, expect_sampled_profile, + [this, expected_sampled_profiles, callback = std::move(profile_collector_callback)]( base::TimeTicks time_ticks, metrics::SampledProfile profile) { - if (!expect_sampled_profile) { + if (expected_sampled_profiles == 0) { FAIL() << "ProfileCollectorCallback called unexpectedly."; } collector_count_++; - if (collector_count_ == 1) { + if (collector_count_ <= expected_sampled_profiles) { std::move(callback).Run(time_ticks, profile); barrier_closure_.Run(); return; } - if (collector_count_ == 2) { + if (collector_count_ == expected_sampled_profiles + 1) { FAIL() << "ProfileCollectorCallback invoked too many times."; } }); @@ -240,9 +266,8 @@ class ProfilerSetUpMixin { public: - ProfilerSetUpMixin( - const std::vector<base::test::FeatureRefAndParams>& enabled_features, - const std::vector<base::test::FeatureRef>& disabled_features) { + ProfilerSetUpMixin(const std::vector<FeatureRefAndParams>& enabled_features, + const std::vector<FeatureRef>& disabled_features) { // ScopedFeatureList must be initialized in the constructor, before any // threads are started. feature_list_.InitWithFeaturesAndParameters(enabled_features, @@ -255,9 +280,6 @@ ~ProfilerSetUpMixin() = default; - ProfilerSetUpMixin(const ProfilerSetUpMixin&) = delete; - ProfilerSetUpMixin& operator=(const ProfilerSetUpMixin&) = delete; - base::test::TaskEnvironment& task_env() { return task_environment_; } private: @@ -273,9 +295,224 @@ base::test::ScopedFeatureList feature_list_; base::test::TaskEnvironment task_environment_{ - base::test::TaskEnvironment::TimeSource::MOCK_TIME}; + base::test::TaskEnvironment::TimeSource::MOCK_TIME, + base::test::TaskEnvironment::MainThreadType::IO}; }; +#if ENABLE_MULTIPROCESS_TESTS + +constexpr char kTestChildTypeSwitch[] = "heap-profiler-test-child-type"; +constexpr char kTestNumAllocationsSwitch[] = + "heap-profiler-test-num-allocations"; + +// Runs the heap profiler in a multiprocess test child. This is used instead of +// HeapProfilerControllerTest::CreateHeapProfiler() in tests that create real +// child processes. (Most tests run only in the test main process and pretend +// that it's the Chrome browser process or a Chrome child process.) +class MultiprocessTestChild final : public mojom::TestConnector, + public ProfilerSetUpMixin { + public: + MultiprocessTestChild( + const std::vector<FeatureRefAndParams>& enabled_features, + const std::vector<FeatureRef>& disabled_features) + : ProfilerSetUpMixin(enabled_features, disabled_features), + quit_closure_(task_env().QuitClosure()) {} + + ~MultiprocessTestChild() final = default; + + MultiprocessTestChild(const MultiprocessTestChild&) = delete; + MultiprocessTestChild& operator=(const MultiprocessTestChild&) = delete; + + void RunTestInChild() { + // Get the process type and number of allocations to simulate. + const base::CommandLine* command_line = + base::CommandLine::ForCurrentProcess(); + ASSERT_TRUE(command_line); + int process_type = 0; + ASSERT_TRUE(base::StringToInt( + command_line->GetSwitchValueASCII(kTestChildTypeSwitch), + &process_type)); + int num_allocations = 0; + ASSERT_TRUE(base::StringToInt( + command_line->GetSwitchValueASCII(kTestNumAllocationsSwitch), + &num_allocations)); + + // Set up mojo support and attach to the parent's pipe. + mojo::core::ScopedIPCSupport enable_mojo( + base::SingleThreadTaskRunner::GetCurrentDefault(), + mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN); + mojo::IncomingInvitation invitation = mojo::IncomingInvitation::Accept( + mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine( + *command_line)); + + // Handle the TestConnector::Connect() message that will connect the + // SnapshotController and CallStackProfileCollector interfaces. + mojo::PendingReceiver<mojom::TestConnector> pending_receiver( + invitation.ExtractMessagePipe(0)); + mojo::Receiver<mojom::TestConnector> receiver(this, + std::move(pending_receiver)); + + // Start the heap profiler and wait for TakeSnapshot() messages from the + // parent. + HeapProfilerController controller(version_info::Channel::STABLE, + static_cast<ProcessType>(process_type)); + controller.SuppressRandomnessForTesting(); + ASSERT_TRUE(controller.IsEnabled()); + controller.StartIfEnabled(); + + // Make a fixed number of allocations at different addresses to include in + // snapshots. No need to free since the process will exit after the test. + for (int i = 0; i < num_allocations; ++i) { + base::PoissonAllocationSampler::Get()->OnAllocation( + AllocationNotificationData(reinterpret_cast<void*>(0x1337 + i), + kAllocationSize, nullptr, + AllocationSubsystem::kManualForTesting)); + } + + // Loop until the TestConnector::Disconnect() message. + task_env().RunUntilQuit(); + } + + // mojom::TestConnector: + + void Connect( + mojo::PendingReceiver<mojom::SnapshotController> receiver, + mojo::PendingRemote<metrics::mojom::CallStackProfileCollector> remote, + base::OnceClosure done_callback) final { + // Create full ChildProcessSnapshotController and + // ChildCallStackProfileCollector instances to send snapshots to the parent + // process. + ChildProcessSnapshotController::CreateSelfOwnedReceiver( + std::move(receiver)); + metrics::CallStackProfileBuilder::SetParentProfileCollectorForChildProcess( + std::move(remote)); + std::move(done_callback).Run(); + } + + void Disconnect() final { std::move(quit_closure_).Run(); } + + private: + base::OnceClosure quit_closure_; +}; + +// Manages a set of multiprocess test children and mojo connections to them. +// Created in test cases in the parent process. +class MultiprocessTestParent { + public: + MultiprocessTestParent() = default; + + MultiprocessTestParent(const MultiprocessTestParent&) = delete; + MultiprocessTestParent& operator=(const MultiprocessTestParent&) = delete; + + ~MultiprocessTestParent() { + // Tell all children to stop profiling and wait for them to exit. + for (auto& connector : test_connectors_) { + connector->Disconnect(); + } + for (const auto& process : child_processes_) { + int exit_code = 0; + EXPECT_TRUE(base::WaitForMultiprocessTestChildExit( + process, TestTimeouts::action_timeout(), &exit_code)); + EXPECT_EQ(exit_code, 0); + } + } + + // Waits until `num_children` are connected, then starts profiling the parent + // process with `controller`. + void StartHeapProfilingWhenChildrenConnected( + size_t num_children, + HeapProfilerController* controller) { + // StartIfEnabled() needs to run on the current sequence no matter what + // thread mojo calls `on_child_connected_closure_` from. + on_child_connected_closure_ = base::BarrierClosure( + num_children, base::BindPostTaskToCurrentDefault( + base::BindLambdaForTesting([this, controller] { + // Make sure all children connected successfully. + ASSERT_EQ(test_connectors_.size(), + child_processes_.size()); + EXPECT_TRUE(controller->StartIfEnabled()); + }))); + } + + // Called from HeapProfilerController::AppendCommandLineSwitchForChildProcess + // with `connector_id` and `receiver`, plus a `remote` added by the test. + // `connector_id` is the id of a mojo TestConnector interface for the process. + // In production this parameter is the child process id. + void BindTestConnector( + int connector_id, + mojo::PendingReceiver<mojom::SnapshotController> receiver, + mojo::PendingRemote<metrics::mojom::CallStackProfileCollector> remote) { + // BrowserProcessSnapshotController holds the remote end of the + // mojom::SnapshotController, and the test fixture holds the receiver end of + // the CallStackProfileCollector. Pass the other ends to the test child. + // `on_child_connected_closure_` will be called with the response. + mojom::TestConnector* connector = test_connectors_.Get( + mojo::RemoteSetElementId::FromUnsafeValue(connector_id)); + ASSERT_TRUE(connector); + connector->Connect(std::move(receiver), std::move(remote), + on_child_connected_closure_); + } + + // Launches a multiprocess test child and registers it with `controller`. + // The child will simulate a process of type `process_type` and make + // `num_allocations` memory allocations to report in heap snapshots. + void LaunchTestChild(HeapProfilerController* controller, + ProcessType process_type, + int num_allocations) { + base::LaunchOptions launch_options; + base::CommandLine child_command_line = + base::GetMultiProcessTestChildBaseCommandLine(); + child_command_line.AppendSwitchASCII( + kTestChildTypeSwitch, + base::NumberToString(static_cast<int>(process_type))); + child_command_line.AppendSwitchASCII(kTestNumAllocationsSwitch, + base::NumberToString(num_allocations)); + + // Attach a mojo channel to the child. + mojo::PlatformChannel channel; + channel.PrepareToPassRemoteEndpoint(&launch_options, &child_command_line); + mojo::OutgoingInvitation invitation; + mojo::PendingRemote<mojom::TestConnector> pending_connector( + invitation.AttachMessagePipe(0), 0); + mojo::RemoteSetElementId connector_id = + test_connectors_.Add(std::move(pending_connector)); + + // In production this only connects the parent end of the SnapshotController + // since content::ChildProcessHost brokers the interface with the child. For + // the test, smuggle the id of a TestConnector to broker the interface by + // pretending it's the child process id. + controller->AppendCommandLineSwitchForChildProcess( + &child_command_line, process_type, connector_id.GetUnsafeValue()); + + base::Process child_process = base::SpawnMultiProcessTestChild( + "HeapProfilerControllerChildMain", child_command_line, launch_options); + ASSERT_TRUE(child_process.IsValid()); + + // Finish connecting the mojo channel. This passes the other end of the + // TestConnector message pipe to the child. + channel.RemoteProcessLaunchAttempted(); + mojo::OutgoingInvitation::Send(std::move(invitation), + child_process.Handle(), + channel.TakeLocalEndpoint()); + + child_processes_.push_back(std::move(child_process)); + } + + private: + // All child processes started by the test. If a child dies the process will + // become invalid but remain in this list. + std::vector<base::Process> child_processes_; + + // Test interface for controlling each child process. If a child dies the + // interface will be disconnected and removed from this set. + mojo::RemoteSet<mojom::TestConnector> test_connectors_; + + // Closure to call whenever a child process is finished connecting. + base::RepeatingClosure on_child_connected_closure_; +}; + +#endif // ENABLE_MULTIPROCESS_TESTS + class MockSnapshotController : public mojom::SnapshotController { public: MOCK_METHOD(void, TakeSnapshot, (), (override)); @@ -448,7 +685,7 @@ ResetChildCallStackProfileCollectorForTesting(); } - // Creates a HeapProfilerController and mocks profiling a process of type + // Creates a HeapProfilerController to mock profiling a process of type // `process_type` on `channel`. The test should pass `expect_enabled` as true // if heap profiling should be enabled in this test setup. // @@ -456,13 +693,15 @@ // HeapProfilerController::TakeSnapshot() is called, even if it doesn't // collect a profile. `collector_callback` will be invoked whenever // TakeSnapshot() passes a profile to CallStackProfileBuilder. - void StartHeapProfiling( + // + // The test must call StartIfEnabled() after this to start profiling. + void CreateHeapProfiler( version_info::Channel channel, ProcessType process_type, bool expect_enabled, base::OnceClosure first_snapshot_callback = base::DoNothing(), ProfileCollectorCallback collector_callback = base::DoNothing()) { - ASSERT_FALSE(controller_) << "StartHeapProfiling called twice"; + ASSERT_FALSE(controller_) << "CreateHeapProfiler called twice"; switch (process_type) { case ProcessType::kBrowser: expected_process_ = metrics::Process::BROWSER_PROCESS; @@ -471,13 +710,17 @@ break; case ProcessType::kUtility: expected_process_ = metrics::Process::UTILITY_PROCESS; - ConnectRemoteProfileCollector(std::move(collector_callback)); + metrics::CallStackProfileBuilder:: + SetParentProfileCollectorForChildProcess( + AddTestProfileCollector(std::move(collector_callback))); break; default: // Connect up the profile collector even though we expect the heap // profiler not to start, so that the test environment is complete. expected_process_ = metrics::Process::UNKNOWN_PROCESS; - ConnectRemoteProfileCollector(std::move(collector_callback)); + metrics::CallStackProfileBuilder:: + SetParentProfileCollectorForChildProcess( + AddTestProfileCollector(std::move(collector_callback))); break; } @@ -491,6 +734,19 @@ EXPECT_EQ(HeapProfilerController::GetInstance(), controller_.get()); EXPECT_EQ(controller_->IsEnabled(), expect_enabled); + } + + // Creates a HeapProfilerController with CreateHeapProfiler() and starts + // profiling. + void StartHeapProfiling( + version_info::Channel channel, + ProcessType process_type, + bool expect_enabled, + base::OnceClosure first_snapshot_callback = base::DoNothing(), + ProfileCollectorCallback collector_callback = base::DoNothing()) { + CreateHeapProfiler(channel, process_type, expect_enabled, + std::move(first_snapshot_callback), + std::move(collector_callback)); EXPECT_EQ(controller_->StartIfEnabled(), expect_enabled); } @@ -506,14 +762,17 @@ AllocationSubsystem::kManualForTesting)); } - void ConnectRemoteProfileCollector( - ProfileCollectorCallback collector_callback) { + // Creates a TestCallStackProfileCollector that accepts callstacks from the + // and passes them to `collector_callback`. Returns a remote for the profiler + // to pass the callstacks to. + mojo::PendingRemote<metrics::mojom::CallStackProfileCollector> + AddTestProfileCollector(ProfileCollectorCallback collector_callback) { mojo::PendingRemote<metrics::mojom::CallStackProfileCollector> remote; - mojo::MakeSelfOwnedReceiver(std::make_unique<TestCallStackProfileCollector>( - std::move(collector_callback)), - remote.InitWithNewPipeAndPassReceiver()); - metrics::CallStackProfileBuilder::SetParentProfileCollectorForChildProcess( - std::move(remote)); + profile_collector_receivers_.Add( + std::make_unique<TestCallStackProfileCollector>( + std::move(collector_callback)), + remote.InitWithNewPipeAndPassReceiver()); + return remote; } ScopedCallbacks CreateScopedCallbacks( @@ -521,7 +780,7 @@ bool expect_sampled_profile, bool use_other_process_callback = false) { return ScopedCallbacks( - expect_take_snapshot, expect_sampled_profile, + expect_take_snapshot, expect_sampled_profile ? 1 : 0, use_other_process_callback, base::BindRepeating(&HeapProfilerControllerTest::RecordSampleReceived, base::Unretained(this)), @@ -543,6 +802,11 @@ // background thread, but does not need to be atomic because the write happens // during a scheduled sample and the read happens well after that. bool sample_received_ = false; + + // Receivers for callstack profiles. Each element of the set is a + // TestCallStackProfileCollecter and associated mojo::Receiver. + mojo::UniqueReceiverSet<metrics::mojom::CallStackProfileCollector> + profile_collector_receivers_; }; // Basic tests only use the default feature params. @@ -923,6 +1187,147 @@ EXPECT_EQ(sample_received_, GetParam().include_zero_feature_enabled); } +#if ENABLE_MULTIPROCESS_TESTS + +// End-to-end test of the HeapProfilerCentralControl feature with multiple child +// processes. +constexpr FeatureTestParams kMultipleChildConfigs[] = { + { + .supported_processes = {ProcessType::kBrowser, ProcessType::kUtility, + ProcessType::kRenderer}, + .include_zero_feature_enabled = true, + .central_control_feature_enabled = true, + }, +}; + +using HeapProfilerControllerMultipleChildTest = HeapProfilerControllerTest; + +INSTANTIATE_TEST_SUITE_P(All, + HeapProfilerControllerMultipleChildTest, + ::testing::ValuesIn(kMultipleChildConfigs)); + +MULTIPROCESS_TEST_MAIN(HeapProfilerControllerChildMain) { + MultiprocessTestChild child(kMultipleChildConfigs[0].GetEnabledFeatures(), + kMultipleChildConfigs[0].GetDisabledFeatures()); + child.RunTestInChild(); + return 0; +} + +TEST_P(HeapProfilerControllerMultipleChildTest, EndToEnd) { + // Initialize mojo IPC support. + mojo::core::ScopedIPCSupport enable_mojo( + base::SingleThreadTaskRunner::GetCurrentDefault(), + mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN); + + // Process types to test. Each will make a different + // number of memory allocations so their reports are all different. + const std::map<ProcessType, size_t> kProcessesToTest{ + {ProcessType::kBrowser, 0}, + {ProcessType::kUtility, 1}, + {ProcessType::kRenderer, 2}, + }; + + // Create callbacks that store profiles from all processes in a vector. + std::vector<metrics::SampledProfile> received_profiles; + auto collector_callback = base::BindLambdaForTesting( + [&](base::TimeTicks, metrics::SampledProfile profile) { + received_profiles.push_back(std::move(profile)); + }); + ScopedCallbacks callbacks( + /*expect_take_snapshot=*/true, + /*expected_sampled_profiles=*/kProcessesToTest.size(), + /*use_other_process_callback=*/false, std::move(collector_callback), + task_env().QuitClosure()); + + // Snapshots from the children take real time to be passed back to the parent. + // The mock clock will advance to the next snapshot time while waiting, so + // stop profiling after the first snapshot by deleting the controller. + auto stop_after_first_snapshot_callback = + callbacks.first_snapshot_callback().Then(base::BindLambdaForTesting( + [this, task_runner = base::SequencedTaskRunner::GetCurrentDefault()] { + task_runner->DeleteSoon(FROM_HERE, controller_.release()); + })); + + CreateHeapProfiler(version_info::Channel::STABLE, ProcessType::kBrowser, + /*expect_enabled=*/true, + std::move(stop_after_first_snapshot_callback), + callbacks.collector_callback()); + ASSERT_TRUE(controller_); + + // Start all processes in `kProcessesToTest` except the browser. + MultiprocessTestParent test_parent; + test_parent.StartHeapProfilingWhenChildrenConnected( + kProcessesToTest.size() - 1, controller_.get()); + + // On every process launch, create a TestCallStackProfileCollector to collect + // profiles from the child. BrowserProcessSnapshotController will create a + // SnapshotController to trigger snapshots in the child. + auto* browser_snapshot_controller = + controller_->GetBrowserProcessSnapshotController(); + ASSERT_TRUE(browser_snapshot_controller); + auto binder_callback = base::BindLambdaForTesting( + [&](int id, mojo::PendingReceiver<mojom::SnapshotController> receiver) { + mojo::PendingRemote<metrics::mojom::CallStackProfileCollector> remote = + AddTestProfileCollector(callbacks.collector_callback()); + test_parent.BindTestConnector(id, std::move(receiver), + std::move(remote)); + }); + browser_snapshot_controller->SetBindRemoteForChildProcessCallback( + std::move(binder_callback)); + + for (const auto [process_type, num_allocations] : kProcessesToTest) { + if (process_type != ProcessType::kBrowser) { + test_parent.LaunchTestChild(controller_.get(), process_type, + num_allocations); + } + } + + // Loop until all children are connected and all processes send snapshots. + task_env().RunUntilQuit(); + + // GMock matcher that tests that the given CallStackProfile contains `count` + // stack samples, each with weight `avg_weight`. + auto call_stack_profile_matches = [](size_t count, size_t avg_weight) { + using StackSample = metrics::CallStackProfile::StackSample; + return Property( + "stack_sample", &metrics::CallStackProfile::stack_sample, + Conditional( + count > 0, + // The test makes allocations at addresses without symbols, so + // they're all counted in the same stack frame. + ElementsAre(AllOf( + Property("count", &StackSample::count, count), + Property("weight", &StackSample::weight, count * avg_weight))), + // No allocations means no stack frames. + IsEmpty())); + }; + + // GMock matcher that tests that the given SampledProfile is a heap snapshot + // for the given `process_type` containing `count` stack + // samples, each with weight `avg_weight`. + auto sampled_profile_matches = [&](metrics::Process process_type, + size_t count, size_t avg_weight) { + return AllOf( + Property("trigger_event", &metrics::SampledProfile::trigger_event, + metrics::SampledProfile::PERIODIC_HEAP_COLLECTION), + Property("process", &metrics::SampledProfile::process, process_type), + Property("call_stack_profile", + &metrics::SampledProfile::call_stack_profile, + call_stack_profile_matches(count, avg_weight))); + }; + + EXPECT_THAT( + received_profiles, + UnorderedElementsAre( + sampled_profile_matches(metrics::Process::BROWSER_PROCESS, 0, 0), + sampled_profile_matches(metrics::Process::UTILITY_PROCESS, 1, + kAllocationSize), + sampled_profile_matches(metrics::Process::RENDERER_PROCESS, 2, + kAllocationSize))); +} + +#endif // ENABLE_MULTIPROCESS_TESTS + } // namespace } // namespace heap_profiling
diff --git a/components/heap_profiling/in_process/mojom/test_connector.mojom b/components/heap_profiling/in_process/mojom/test_connector.mojom new file mode 100644 index 0000000..1d5228a --- /dev/null +++ b/components/heap_profiling/in_process/mojom/test_connector.mojom
@@ -0,0 +1,23 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module heap_profiling.mojom; + +import "components/heap_profiling/in_process/mojom/snapshot_controller.mojom"; +import "components/metrics/public/mojom/call_stack_profile_collector.mojom"; + +// Bootstraps heap_profiling.mojom.SnapshotController (browser->child) and +// metrics.mojom.CallStacksProfileCollector (child->browser) connections in a +// multiprocess test. +interface TestConnector { + // Passes interfaces to the child, which should reply once they're bound. + Connect( + pending_receiver<heap_profiling.mojom.SnapshotController> + snapshot_controller, + pending_remote<metrics.mojom.CallStackProfileCollector> + profile_collector) => (); + + // Tells the child the test is over. + Disconnect(); +};
diff --git a/components/management_strings.grdp b/components/management_strings.grdp index c4b2b1a3..8d691cf73 100644 --- a/components/management_strings.grdp +++ b/components/management_strings.grdp
@@ -287,6 +287,29 @@ <message name="IDS_MANAGEMENT_LEGACY_TECH_REPORT" desc="Message explaining that browser will upload a report when a legacy technology is used for a webpage" formatter_data="android_java"> A limited list of URLs of pages you visit where <ph name="BEGIN_LINK"><a target="_blank" href="https://chromestatus.com/features#browsers.chrome.status%3A%22Deprecated%22" ></ph>legacy technology events<ph name="END_LINK"></a></ph> are occuring. </message> + + <!--Profile reporting management message--> + <if expr="not is_android"> + <message name="IDS_MANAGEMENT_PROFILE_REPORTING_EXPLANATION" desc="Message explaining browser reporting" formatter_data="android_java"> + Managed profile, browser, and some device information is accessible to your administrator. They can see information such as the following: + </message> + <message name="IDS_MANAGEMENT_PROFILE_REPORTING_OVERVIEW" desc="Item in a list of information viewable by the enterprise admin, indicating that the admin can view the user's work profile overview." formatter_data="android_java"> + Work profile overview + </message> + <message name="IDS_MANAGEMENT_PROFILE_REPORTING_USERNAME" desc="Item in a list of information viewable by the enterprise admin, indicating that the admin can view the user's work profile username." formatter_data="android_java"> + Work profile information (such as your work profile username) + </message> + <message name="IDS_MANAGEMENT_PROFILE_REPORTING_BROWSER" desc="Item in a list of information viewable by the enterprise admin, indicating that the admin can view the device information that user's work profile belong to" formatter_data="android_java"> + Browser and device OS information (such as the browser & OS versions) + </message> + <message name="IDS_MANAGEMENT_PROFILE_REPORTING_EXTENSION" desc="Item in a list of information viewable by the enterprise admin, indicating that the admin can view user's work profile extensions" formatter_data="android_java"> + Installed apps & extensions in your work profile + </message> + <message name="IDS_MANAGEMENT_PROFILE_REPORTING_POLICY" desc="Item in a list of information viewable by the enterprise admin, indicating that the admin can viewuser's work profile policies" formatter_data="android_java"> + Applied browser policies in your work profile + </message> + </if> + <!-- Strings related to Chrome Enterprise Connectors --> <message name="IDS_MANAGEMENT_THREAT_PROTECTION" desc="Title of the Chrome Enterprise Connectors section of the page"> Chrome Enterprise Connectors
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_BROWSER.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_BROWSER.png.sha1 new file mode 100644 index 0000000..a50355c3 --- /dev/null +++ b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_BROWSER.png.sha1
@@ -0,0 +1 @@ +8394488b80db3c7498de2247695e860f1a8bf731 \ No newline at end of file
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_EXPLANATION.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_EXPLANATION.png.sha1 new file mode 100644 index 0000000..a50355c3 --- /dev/null +++ b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_EXPLANATION.png.sha1
@@ -0,0 +1 @@ +8394488b80db3c7498de2247695e860f1a8bf731 \ No newline at end of file
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_EXTENSION.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_EXTENSION.png.sha1 new file mode 100644 index 0000000..a50355c3 --- /dev/null +++ b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_EXTENSION.png.sha1
@@ -0,0 +1 @@ +8394488b80db3c7498de2247695e860f1a8bf731 \ No newline at end of file
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_OVERVIEW.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_OVERVIEW.png.sha1 new file mode 100644 index 0000000..a50355c3 --- /dev/null +++ b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_OVERVIEW.png.sha1
@@ -0,0 +1 @@ +8394488b80db3c7498de2247695e860f1a8bf731 \ No newline at end of file
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_POLICY.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_POLICY.png.sha1 new file mode 100644 index 0000000..a50355c3 --- /dev/null +++ b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_POLICY.png.sha1
@@ -0,0 +1 @@ +8394488b80db3c7498de2247695e860f1a8bf731 \ No newline at end of file
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_USERNAME.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_USERNAME.png.sha1 new file mode 100644 index 0000000..a50355c3 --- /dev/null +++ b/components/management_strings_grdp/IDS_MANAGEMENT_PROFILE_REPORTING_USERNAME.png.sha1
@@ -0,0 +1 @@ +8394488b80db3c7498de2247695e860f1a8bf731 \ No newline at end of file
diff --git a/components/ml/webnn/graph_validation_utils.h b/components/ml/webnn/graph_validation_utils.h index 818674b..d1e5351 100644 --- a/components/ml/webnn/graph_validation_utils.h +++ b/components/ml/webnn/graph_validation_utils.h
@@ -70,7 +70,7 @@ static constexpr DataTypeConstraintSet kGatherOperatorIndexDataTypes = { Operand::DataType::kInt32, Operand::DataType::kUint32, - Operand::DataType::kInt64}; + Operand::DataType::kInt64, Operand::DataType::kUint64}; } // namespace DataTypeConstraint
diff --git a/components/omnibox/browser/shortcuts_database.cc b/components/omnibox/browser/shortcuts_database.cc index aaf4b79..94f4938 100644 --- a/components/omnibox/browser/shortcuts_database.cc +++ b/components/omnibox/browser/shortcuts_database.cc
@@ -10,7 +10,6 @@ #include "base/functional/bind.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" -#include "base/strings/stringprintf.h" #include "base/time/time.h" #include "base/uuid.h" #include "components/omnibox/browser/autocomplete_match_type.h" @@ -32,32 +31,22 @@ const int kCompatibleVersionNumber = 1; void BindShortcutToStatement(const ShortcutsDatabase::Shortcut& shortcut, - sql::Statement* s) { + sql::Statement& s) { DCHECK(base::Uuid::ParseCaseInsensitive(shortcut.id).is_valid()); - s->BindString(0, shortcut.id); - s->BindString16(1, shortcut.text); - s->BindString16(2, shortcut.match_core.fill_into_edit); - s->BindString(3, shortcut.match_core.destination_url.spec()); - s->BindInt(4, base::checked_cast<int>(shortcut.match_core.document_type)); - s->BindString16(5, shortcut.match_core.contents); - s->BindString(6, shortcut.match_core.contents_class); - s->BindString16(7, shortcut.match_core.description); - s->BindString(8, shortcut.match_core.description_class); - s->BindInt(9, base::checked_cast<int>(shortcut.match_core.transition)); - s->BindInt(10, base::checked_cast<int>(shortcut.match_core.type)); - s->BindString16(11, shortcut.match_core.keyword); - s->BindTime(12, shortcut.last_access_time); - s->BindInt(13, shortcut.number_of_hits); -} - -bool DeleteShortcut(const char* field_name, - const std::string& id, - sql::Database& db) { - sql::Statement s(db.GetUniqueStatement( - base::StringPrintf("DELETE FROM omni_box_shortcuts WHERE %s = ?", - field_name).c_str())); - s.BindString(0, id); - return s.Run(); + s.BindString(0, shortcut.id); + s.BindString16(1, shortcut.text); + s.BindString16(2, shortcut.match_core.fill_into_edit); + s.BindString(3, shortcut.match_core.destination_url.spec()); + s.BindInt(4, base::checked_cast<int>(shortcut.match_core.document_type)); + s.BindString16(5, shortcut.match_core.contents); + s.BindString(6, shortcut.match_core.contents_class); + s.BindString16(7, shortcut.match_core.description); + s.BindString(8, shortcut.match_core.description_class); + s.BindInt(9, base::checked_cast<int>(shortcut.match_core.transition)); + s.BindInt(10, base::checked_cast<int>(shortcut.match_core.type)); + s.BindString16(11, shortcut.match_core.keyword); + s.BindTime(12, shortcut.last_access_time); + s.BindInt(13, shortcut.number_of_hits); } void DatabaseErrorCallback(sql::Database* db, @@ -105,11 +94,9 @@ type(type), keyword(keyword) {} -ShortcutsDatabase::Shortcut::MatchCore::MatchCore(const MatchCore& other) = - default; +ShortcutsDatabase::Shortcut::MatchCore::MatchCore(const MatchCore&) = default; -ShortcutsDatabase::Shortcut::MatchCore::~MatchCore() { -} +ShortcutsDatabase::Shortcut::MatchCore::~MatchCore() = default; // ShortcutsDatabase::Shortcut ------------------------------------------------ @@ -141,11 +128,9 @@ last_access_time(base::Time::Now()), number_of_hits(0) {} -ShortcutsDatabase::Shortcut::Shortcut(const Shortcut& other) = default; +ShortcutsDatabase::Shortcut::Shortcut(const Shortcut&) = default; -ShortcutsDatabase::Shortcut::~Shortcut() { -} - +ShortcutsDatabase::Shortcut::~Shortcut() = default; // ShortcutsDatabase ---------------------------------------------------------- @@ -171,43 +156,65 @@ } bool ShortcutsDatabase::AddShortcut(const Shortcut& shortcut) { - sql::Statement s(db_.GetCachedStatement( - SQL_FROM_HERE, - "INSERT INTO omni_box_shortcuts (id, text, fill_into_edit, url, " - "document_type, contents, contents_class, description, " - "description_class, transition, type, keyword, last_access_time, " - "number_of_hits) " - "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)")); - BindShortcutToStatement(shortcut, &s); + static constexpr char kInsertSql[] = + // clang-format off + "INSERT INTO omni_box_shortcuts(" + "id,text,fill_into_edit,url,document_type,contents,contents_class," + "description,description_class,transition,type,keyword," + "last_access_time,number_of_hits)" + "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + // clang-format on + + sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, kInsertSql)); + BindShortcutToStatement(shortcut, s); return s.Run(); } bool ShortcutsDatabase::UpdateShortcut(const Shortcut& shortcut) { - sql::Statement s(db_.GetCachedStatement( - SQL_FROM_HERE, - "UPDATE omni_box_shortcuts SET id=?, text=?, fill_into_edit=?, url=?, " - "document_type=?, contents=?, contents_class=?, description=?, " - "description_class=?, transition=?, type=?, keyword=?, " - "last_access_time=?, number_of_hits=? WHERE id=?")); - BindShortcutToStatement(shortcut, &s); + static constexpr char kUpdateSql[] = + // clang-format off + "UPDATE omni_box_shortcuts " + "SET " + "id=?,text=?,fill_into_edit=?,url=?," + "document_type=?,contents=?,contents_class=?,description=?," + "description_class=?,transition=?,type=?,keyword=?," + "last_access_time=?,number_of_hits=? " + "WHERE id=?"; + // clang-format on + + sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, kUpdateSql)); + BindShortcutToStatement(shortcut, s); s.BindString(14, shortcut.id); return s.Run(); } bool ShortcutsDatabase::DeleteShortcutsWithIDs( const ShortcutIDs& shortcut_ids) { - bool success = true; - db_.BeginTransaction(); - for (auto it(shortcut_ids.begin()); it != shortcut_ids.end(); ++it) { - success &= DeleteShortcut("id", *it, db_); + sql::Transaction transaction(&db_); + if (!transaction.Begin()) { + return false; } - db_.CommitTransaction(); - return success; + + sql::Statement s( + db_.GetUniqueStatement("DELETE FROM omni_box_shortcuts WHERE id=?")); + + for (const std::string& id : shortcut_ids) { + s.Reset(/*clear_bound_vars=*/true); + s.BindString(0, id); + if (!s.Run()) { + return false; + } + } + + return transaction.Commit(); } bool ShortcutsDatabase::DeleteShortcutsWithURL( const std::string& shortcut_url_spec) { - return DeleteShortcut("url", shortcut_url_spec, db_); + sql::Statement s( + db_.GetUniqueStatement("DELETE FROM omni_box_shortcuts WHERE url=?")); + s.BindString(0, shortcut_url_spec); + return s.Run(); } bool ShortcutsDatabase::DeleteAllShortcuts() { @@ -220,13 +227,18 @@ void ShortcutsDatabase::LoadShortcuts(GuidToShortcutMap* shortcuts) { DCHECK(shortcuts); - sql::Statement s(db_.GetCachedStatement( - SQL_FROM_HERE, - "SELECT id, text, fill_into_edit, url, document_type, contents, " - "contents_class, description, description_class, transition, type, " - "keyword, last_access_time, number_of_hits FROM omni_box_shortcuts")); - shortcuts->clear(); + + static constexpr char kSelectSql[] = + // clang-format off + "SELECT id,text,fill_into_edit,url,document_type,contents,contents_class," + "description,description_class,transition,type,keyword," + "last_access_time,number_of_hits " + "FROM omni_box_shortcuts"; + // clang-format on + + sql::Statement s(db_.GetUniqueStatement(kSelectSql)); + while (s.Step()) { // Some users have corrupt data in their SQL database. That causes crashes. // Therefore, validate the integral values first. https://crbug.com/1024114 @@ -268,8 +280,7 @@ } } -ShortcutsDatabase::~ShortcutsDatabase() { -} +ShortcutsDatabase::~ShortcutsDatabase() = default; bool ShortcutsDatabase::EnsureTable() { if (!db_.DoesTableExist("omni_box_shortcuts")) @@ -296,9 +307,7 @@ } for (int i = current_version + 1; i <= kCurrentVersionNumber; ++i) { - if (!DoMigration(i)) - return false; - if (!meta_table_.SetVersionNumber(i)) { + if (!DoMigration(i)) { return false; } } @@ -307,76 +316,68 @@ } bool ShortcutsDatabase::DoMigration(int version) { - // Perform migrations in transactions to avoid incomplete migrations. + // The migration must be performed transactionally with the meta table + // update, or else one of them can be applied without the other, leading to + // incorrect logic on subsequent use. sql::Transaction transaction(&db_); + if (!transaction.Begin()) { + return false; + } switch (version) { case -1: // When there is no existing table, skip iterative migration; instead, // migrate to the latest version. - return transaction.Begin() && - meta_table_.Init(&db_, kCurrentVersionNumber, + return meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber) && db_.Execute( - "CREATE TABLE omni_box_shortcuts (id VARCHAR PRIMARY KEY, " - "text VARCHAR, fill_into_edit VARCHAR, url VARCHAR, " - "document_type INTEGER, contents VARCHAR, " - "contents_class VARCHAR, description VARCHAR, " - "description_class VARCHAR, transition INTEGER, type INTEGER, " - "keyword VARCHAR, last_access_time INTEGER, " + "CREATE TABLE omni_box_shortcuts(id VARCHAR PRIMARY KEY," + "text VARCHAR,fill_into_edit VARCHAR,url VARCHAR," + "document_type INTEGER,contents VARCHAR," + "contents_class VARCHAR,description VARCHAR," + "description_class VARCHAR,transition INTEGER,type INTEGER," + "keyword VARCHAR,last_access_time INTEGER," "number_of_hits INTEGER)") && transaction.Commit(); case 0: + static_assert(static_cast<int>(ui::PAGE_TRANSITION_TYPED) == 1); + static_assert(static_cast<int>(AutocompleteMatchType::HISTORY_TITLE) == + 2); + // Version pre-0 of the shortcuts table lacked the fill_into_edit, // transition type, and keyword columns. - return transaction.Begin() && - db_.Execute( + return db_.Execute( "ALTER TABLE omni_box_shortcuts " "ADD COLUMN fill_into_edit VARCHAR") && - db_.Execute( - "UPDATE omni_box_shortcuts SET fill_into_edit = url") && + db_.Execute("UPDATE omni_box_shortcuts SET fill_into_edit=url") && db_.Execute( "ALTER TABLE omni_box_shortcuts " "ADD COLUMN transition INTEGER") && - db_.Execute(base::StringPrintf( - "UPDATE omni_box_shortcuts SET transition = %d", - static_cast<int>(ui::PAGE_TRANSITION_TYPED)) - .c_str()) && + db_.Execute("UPDATE omni_box_shortcuts SET transition=1") && db_.Execute( "ALTER TABLE omni_box_shortcuts ADD COLUMN type INTEGER") && + db_.Execute("UPDATE omni_box_shortcuts SET type=2") && db_.Execute( - base::StringPrintf( - "UPDATE omni_box_shortcuts SET type = %d", - static_cast<int>(AutocompleteMatchType::HISTORY_TITLE)) - .c_str()) && - db_.Execute( - "ALTER TABLE omni_box_shortcuts " - "ADD COLUMN keyword VARCHAR") && + "ALTER TABLE omni_box_shortcuts ADD COLUMN keyword VARCHAR") && transaction.Commit(); case 1: - return transaction.Begin() && - // Create the MetaTable. - meta_table_.Init(&db_, 1, kCompatibleVersionNumber) && - // Migrate old SEARCH_OTHER_ENGINE values to the new type value. - db_.Execute( - "UPDATE omni_box_shortcuts SET type = 13 WHERE type = 9") && - // Migrate old EXTENSION_APP values to the new type value. - db_.Execute( - "UPDATE omni_box_shortcuts SET type = 14 WHERE type = 10") && - // Migrate old CONTACT values to the new type value. - db_.Execute( - "UPDATE omni_box_shortcuts SET type = 15 WHERE type = 11") && - // Migrate old BOOKMARK_TITLE values to the new type value. - db_.Execute( - "UPDATE omni_box_shortcuts SET type = 16 WHERE type = 12") && - transaction.Commit(); + return // Create the MetaTable. + meta_table_.Init(&db_, 1, kCompatibleVersionNumber) && + // Migrate old SEARCH_OTHER_ENGINE values to the new type value. + db_.Execute("UPDATE omni_box_shortcuts SET type=13 WHERE type=9") && + // Migrate old EXTENSION_APP values to the new type value. + db_.Execute("UPDATE omni_box_shortcuts SET type=14 WHERE type=10") && + // Migrate old CONTACT values to the new type value. + db_.Execute("UPDATE omni_box_shortcuts SET type=15 WHERE type=11") && + // Migrate old BOOKMARK_TITLE values to the new type value. + db_.Execute("UPDATE omni_box_shortcuts SET type=16 WHERE type=12") && + transaction.Commit(); case 2: // Version 1 of the shortcuts table lacked the document_type column. - return transaction.Begin() && - db_.Execute( + return db_.Execute( "ALTER TABLE omni_box_shortcuts " "ADD COLUMN document_type INTEGER") && - transaction.Commit(); + meta_table_.SetVersionNumber(version) && transaction.Commit(); default: return false; }
diff --git a/components/optimization_guide/core/prediction_manager.cc b/components/optimization_guide/core/prediction_manager.cc index 891b39ec..5b870db 100644 --- a/components/optimization_guide/core/prediction_manager.cc +++ b/components/optimization_guide/core/prediction_manager.cc
@@ -148,7 +148,11 @@ model_metadata.type_url() == "type.googleapis.com/" "google.internal.chrome.optimizationguide.v1." - "HistoryClustersModuleRankingModelMetadata"; + "HistoryClustersModuleRankingModelMetadata" || + model_metadata.type_url() == + "type.googleapis.com/" + "google.internal.chrome.optimizationguide.v1." + "OnDeviceBaseModelMetadata"; } void RecordModelAvailableAtRegistration( @@ -199,8 +203,9 @@ } PredictionManager::~PredictionManager() { - if (prediction_model_download_manager_) + if (prediction_model_download_manager_) { prediction_model_download_manager_->RemoveObserver(this); + } } void PredictionManager::Initialize( @@ -352,8 +357,9 @@ static_cast<int>( *base_model_info.supported_model_engine_versions().begin())); - if (switches::IsModelOverridePresent()) + if (switches::IsModelOverridePresent()) { return; + } if (!ShouldFetchModels(off_the_record_, component_updates_enabled_provider_.Run())) { @@ -418,8 +424,9 @@ auto model_it = optimization_target_model_info_map_.find(registration_info.first); - if (model_it != optimization_target_model_info_map_.end()) + if (model_it != optimization_target_model_info_map_.end()) { model_info.set_version(model_it->second.get()->GetVersion()); + } models_info.push_back(model_info); if (optimization_guide_logger_->ShouldEnableDebugLogs()) { @@ -623,8 +630,9 @@ void PredictionManager::OnModelReady(const base::FilePath& base_model_dir, const proto::PredictionModel& model) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (switches::IsModelOverridePresent()) + if (switches::IsModelOverridePresent()) { return; + } DCHECK(model.model_info().has_version() && model.model_info().has_optimization_target()); @@ -812,8 +820,9 @@ } bool success = ProcessAndStoreLoadedModel(*model); DCHECK_EQ(optimization_target, model->model_info().optimization_target()); - if (record_availability_metrics) + if (record_availability_metrics) { RecordModelAvailableAtRegistration(optimization_target, success); + } OnProcessLoadedModel(*model, success); } @@ -848,12 +857,15 @@ bool PredictionManager::ProcessAndStoreLoadedModel( const proto::PredictionModel& model) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!model.model_info().has_optimization_target()) + if (!model.model_info().has_optimization_target()) { return false; - if (!model.model_info().has_version()) + } + if (!model.model_info().has_version()) { return false; - if (!model.has_model()) + } + if (!model.has_model()) { return false; + } if (!model_registration_info_map_.contains( model.model_info().optimization_target())) { return false; @@ -891,8 +903,9 @@ auto model_meta_it = optimization_target_model_info_map_.find(optimization_target); - if (model_meta_it != optimization_target_model_info_map_.end()) + if (model_meta_it != optimization_target_model_info_map_.end()) { return model_meta_it->second->GetVersion() != new_version; + } return true; }
diff --git a/components/optimization_guide/core/prediction_model_store.cc b/components/optimization_guide/core/prediction_model_store.cc index 5f9e9cb..f7eeb1e9 100644 --- a/components/optimization_guide/core/prediction_model_store.cc +++ b/components/optimization_guide/core/prediction_model_store.cc
@@ -166,6 +166,14 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!base_store_dir.empty()); + if (!background_task_runner_) { + // In unit tests, to avoid leaking a task runner between test runs, the task + // runner can be reset at the end of each test. In that case, we'll need to + // recreate it here. + background_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner( + {base::MayBlock(), base::TaskPriority::BEST_EFFORT}); + } + // Should not be initialized already. DCHECK(base_store_dir_.empty()); @@ -507,8 +515,7 @@ DETACH_FROM_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base_store_dir_ = base::FilePath(); - background_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT}); + background_task_runner_.reset(); } } // namespace optimization_guide
diff --git a/components/policy/resources/templates/policy_definitions/Network/BlockTruncatedCookies.yaml b/components/policy/resources/templates/policy_definitions/Network/BlockTruncatedCookies.yaml index d4f738b..b6f9b6a 100644 --- a/components/policy/resources/templates/policy_definitions/Network/BlockTruncatedCookies.yaml +++ b/components/policy/resources/templates/policy_definitions/Network/BlockTruncatedCookies.yaml
@@ -28,8 +28,8 @@ schema: type: boolean supported_on: -- android:118- -- chrome_os:118- -- chrome.*:118- +- android:118-126 +- chrome_os:118-126 +- chrome.*:118-126 tags: [] type: main
diff --git a/components/policy/test/data/pref_mapping/BlockTruncatedCookies.json b/components/policy/test/data/pref_mapping/BlockTruncatedCookies.json index ec0f2a2..5868d79 100644 --- a/components/policy/test/data/pref_mapping/BlockTruncatedCookies.json +++ b/components/policy/test/data/pref_mapping/BlockTruncatedCookies.json
@@ -1,22 +1,5 @@ [ { - "can_be_recommended": true, - "os": [ - "win", - "linux", - "mac", - "chromeos_ash", - "chromeos_lacros", - "android", - "fuchsia" - ], - "simple_policy_pref_mapping_test": { - "pref_name": "profile.cookie_block_truncated", - "default_value": true, - "values_to_test": [ - true, - false - ] - } + "reason_for_missing_test": "Policy was removed" } ]
diff --git a/components/privacy_sandbox/android/java/res/xml/tracking_protection_preferences.xml b/components/privacy_sandbox/android/java/res/xml/tracking_protection_preferences.xml index 51ba2cf..ce7e255a 100644 --- a/components/privacy_sandbox/android/java/res/xml/tracking_protection_preferences.xml +++ b/components/privacy_sandbox/android/java/res/xml/tracking_protection_preferences.xml
@@ -35,6 +35,20 @@ app:allowDividerBelow="false" /> <org.chromium.components.browser_ui.settings.ChromeSwitchPreference + android:key="ip_protection_toggle" + android:title="@string/tracking_protection_ip_protection_toggle_title" + android:summary="@string/tracking_protection_ip_protection_toggle_summary" + app:allowDividerBelow="false" + app:isPreferenceVisible="false" /> + + <org.chromium.components.browser_ui.settings.ChromeSwitchPreference + android:key="fingerprinting_protection_toggle" + android:title="@string/tracking_protection_fingerprinting_protection_toggle_title" + android:summary="@string/tracking_protection_fingerprinting_protection_toggle_summary" + app:allowDividerBelow="false" + app:isPreferenceVisible="false" /> + + <org.chromium.components.browser_ui.settings.ChromeSwitchPreference android:key="dnt_toggle" android:title="@string/tracking_protection_dnt_toggle_title" android:summary="@string/tracking_protection_dnt_toggle_summary"
diff --git a/components/privacy_sandbox/android/java/src/org/chromium/components/privacy_sandbox/TrackingProtectionDelegate.java b/components/privacy_sandbox/android/java/src/org/chromium/components/privacy_sandbox/TrackingProtectionDelegate.java index 4496d6e..67c5ce1 100644 --- a/components/privacy_sandbox/android/java/src/org/chromium/components/privacy_sandbox/TrackingProtectionDelegate.java +++ b/components/privacy_sandbox/android/java/src/org/chromium/components/privacy_sandbox/TrackingProtectionDelegate.java
@@ -24,6 +24,11 @@ void setDoNotTrack(boolean enabled); /** + * @return whether the IP protection preference should be shown. + */ + boolean shouldDisplayIpProtection(); + + /** * @return whether the IP protection is enabled. */ boolean isIpProtectionEnabled(); @@ -32,6 +37,11 @@ void setIpProtection(boolean enabled); /** + * @return whether the fingerprinting protection preference should be shown. + */ + boolean shouldDisplayFingerprintingProtection(); + + /** * @return whether the fingerprinting protection is enabled. */ boolean isFingerprintingProtectionEnabled();
diff --git a/components/privacy_sandbox/android/java/src/org/chromium/components/privacy_sandbox/TrackingProtectionSettings.java b/components/privacy_sandbox/android/java/src/org/chromium/components/privacy_sandbox/TrackingProtectionSettings.java index e00238de..027114e1 100644 --- a/components/privacy_sandbox/android/java/src/org/chromium/components/privacy_sandbox/TrackingProtectionSettings.java +++ b/components/privacy_sandbox/android/java/src/org/chromium/components/privacy_sandbox/TrackingProtectionSettings.java
@@ -51,6 +51,9 @@ // Must match keys in tracking_protection_preferences.xml. private static final String OFFBOARDING_NOTICE = "offboarding_notice"; private static final String PREF_BLOCK_ALL_TOGGLE = "block_all_3pcd_toggle"; + private static final String PREF_IP_PROTECTION_TOGGLE = "ip_protection_toggle"; + private static final String PREF_FINGERPRINTING_PROTECTION_TOGGLE = + "fingerprinting_protection_toggle"; private static final String PREF_DNT_TOGGLE = "dnt_toggle"; private static final String PREF_BULLET_TWO = "bullet_point_two"; private static final String ALLOWED_GROUP = "allowed_group"; @@ -90,6 +93,10 @@ ChromeSwitchPreference blockAll3PCookiesSwitch = (ChromeSwitchPreference) findPreference(PREF_BLOCK_ALL_TOGGLE); + ChromeSwitchPreference ipProtectionSwitch = + (ChromeSwitchPreference) findPreference(PREF_IP_PROTECTION_TOGGLE); + ChromeSwitchPreference fingerprintingProtectionSwitch = + (ChromeSwitchPreference) findPreference(PREF_FINGERPRINTING_PROTECTION_TOGGLE); ChromeSwitchPreference doNotTrackSwitch = (ChromeSwitchPreference) findPreference(PREF_DNT_TOGGLE); @@ -101,6 +108,29 @@ return true; }); + // IP protection switch. + if (mDelegate.shouldDisplayIpProtection()) { + ipProtectionSwitch.setVisible(true); + ipProtectionSwitch.setChecked(mDelegate.isIpProtectionEnabled()); + ipProtectionSwitch.setOnPreferenceChangeListener( + (preference, newValue) -> { + mDelegate.setIpProtection((boolean) newValue); + return true; + }); + } + + // Fingerprinting protection switch. + if (mDelegate.shouldDisplayFingerprintingProtection()) { + fingerprintingProtectionSwitch.setVisible(true); + fingerprintingProtectionSwitch.setChecked( + mDelegate.isFingerprintingProtectionEnabled()); + fingerprintingProtectionSwitch.setOnPreferenceChangeListener( + (preference, newValue) -> { + mDelegate.setFingerprintingProtection((boolean) newValue); + return true; + }); + } + // Do not track switch. doNotTrackSwitch.setChecked(mDelegate.isDoNotTrackEnabled()); doNotTrackSwitch.setOnPreferenceChangeListener(
diff --git a/components/privacy_sandbox/privacy_sandbox_features.cc b/components/privacy_sandbox/privacy_sandbox_features.cc index 0b83a83..3f040a8e 100644 --- a/components/privacy_sandbox/privacy_sandbox_features.cc +++ b/components/privacy_sandbox/privacy_sandbox_features.cc
@@ -230,4 +230,8 @@ &kPrivacySandboxActivityTypeStorage, kPrivacySandboxActivityTypeStorageWithinXDaysName, 60}; +BASE_FEATURE(kPrivacySandboxAdsDialogDisabledOnAll3PCBlock, + "PrivacySandboxAdsDialogDisabledOnAll3PCBlock", + base::FEATURE_ENABLED_BY_DEFAULT); + } // namespace privacy_sandbox
diff --git a/components/privacy_sandbox/privacy_sandbox_features.h b/components/privacy_sandbox/privacy_sandbox_features.h index f61bb4a..b9a841ff 100644 --- a/components/privacy_sandbox/privacy_sandbox_features.h +++ b/components/privacy_sandbox/privacy_sandbox_features.h
@@ -264,6 +264,10 @@ extern const base::FeatureParam<int> kPrivacySandboxActivityTypeStorageWithinXDays; +// Disables the Privacy Sandbox Ads Dialog when all 3pc are blocked. +COMPONENT_EXPORT(PRIVACY_SANDBOX_FEATURES) +BASE_DECLARE_FEATURE(kPrivacySandboxAdsDialogDisabledOnAll3PCBlock); + } // namespace privacy_sandbox #endif // COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_FEATURES_H_
diff --git a/components/privacy_sandbox/privacy_sandbox_test_util.cc b/components/privacy_sandbox/privacy_sandbox_test_util.cc index 8b3cb80..71a16ecf 100644 --- a/components/privacy_sandbox/privacy_sandbox_test_util.cc +++ b/components/privacy_sandbox/privacy_sandbox_test_util.cc
@@ -296,6 +296,18 @@ GetItemValue<std::string>(value), false); return; } + case (StateKey::kBlockAll3pcToggleEnabledUserPrefValue): { + SCOPED_TRACE("State Setup: Block all 3pc toggle enabled"); + testing_pref_service->SetUserPref(prefs::kBlockAll3pcToggleEnabled, + base::Value(GetItemValue<bool>(value))); + return; + } + case (StateKey::kTrackingProtection3pcdEnabledUserPrefValue): { + SCOPED_TRACE("State Setup: Tracking protection 3pcd enabled"); + testing_pref_service->SetUserPref(prefs::kTrackingProtection3pcdEnabled, + base::Value(GetItemValue<bool>(value))); + return; + } default: NOTREACHED_IN_MIGRATION(); }
diff --git a/components/privacy_sandbox/privacy_sandbox_test_util.h b/components/privacy_sandbox/privacy_sandbox_test_util.h index 35b5ecd..8ff901e 100644 --- a/components/privacy_sandbox/privacy_sandbox_test_util.h +++ b/components/privacy_sandbox/privacy_sandbox_test_util.h
@@ -170,6 +170,8 @@ kM1RestrictedNoticePreviouslyAcknowledged = 25, kAttestationsMap = 26, kBlockFledgeJoiningForEtldplus1 = 27, + kBlockAll3pcToggleEnabledUserPrefValue = 28, + kTrackingProtection3pcdEnabledUserPrefValue = 29, }; // Defines the input to the functions under test.
diff --git a/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc b/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc index a8f8193..21d74565 100644 --- a/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc +++ b/components/privacy_sandbox/privacy_sandbox_test_util_unittest.cc
@@ -57,6 +57,7 @@ } // namespace // TODO (crbug.com/1408187): Add coverage for all state / input / output keys. +// TODO (crbug.com/340589498): Parameterize tests in this file. class PrivacySandboxTestUtilTest : public testing::Test { public: PrivacySandboxTestUtilTest() @@ -182,6 +183,29 @@ } } +TEST_F(PrivacySandboxTestUtilTest, + StateKey_VerifykBlockAll3pcToggleEnabledUserPrefValueSetsPref) { + std::vector<bool> states = {true, false}; + for (auto state : states) { + ApplyTestState(StateKey::kBlockAll3pcToggleEnabledUserPrefValue, state); + EXPECT_EQ( + state, + prefs()->GetUserPref(prefs::kBlockAll3pcToggleEnabled)->GetBool()); + } +} + +TEST_F(PrivacySandboxTestUtilTest, + StateKey_VerifykTrackingProtection3pcdEnabledUserPrefValueSetsPref) { + std::vector<bool> states = {true, false}; + for (auto state : states) { + ApplyTestState(StateKey::kTrackingProtection3pcdEnabledUserPrefValue, + state); + EXPECT_EQ( + state, + prefs()->GetUserPref(prefs::kTrackingProtection3pcdEnabled)->GetBool()); + } +} + TEST_F(PrivacySandboxTestUtilTest, StateKey_SiteDataUserDefault) { std::vector<ContentSetting> states = {CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
diff --git a/components/privacy_sandbox_strings.grd b/components/privacy_sandbox_strings.grd index 71993495..6edbd464 100644 --- a/components/privacy_sandbox_strings.grd +++ b/components/privacy_sandbox_strings.grd
@@ -322,6 +322,18 @@ <message name="IDS_PRIVACY_SANDBOX_TRACKING_PROTECTION_SNACKBAR_ACTION" desc="Action of the Tracking Protection snackbar." formatter_data="android_java" translateable="false"> Change protections </message> + <message name="IDS_TRACKING_PROTECTION_IP_PROTECTION_TOGGLE_TITLE" desc="" formatter_data="android_java" translateable="false"> + Hide your IP address + </message> + <message name="IDS_TRACKING_PROTECTION_IP_PROTECTION_TOGGLE_SUMMARY" desc="" formatter_data="android_java" translateable="false"> + When you’re signed in to Chrome, this setting can limit what suspected trackers can see as you browse. When a page loads, some requests for content get sent through privacy servers. + </message> + <message name="IDS_TRACKING_PROTECTION_FINGERPRINTING_PROTECTION_TOGGLE_TITLE" desc="" formatter_data="android_java" translateable="false"> + Limit digital fingerprinting + </message> + <message name="IDS_TRACKING_PROTECTION_FINGERPRINTING_PROTECTION_TOGGLE_SUMMARY" desc="" formatter_data="android_java" translateable="false"> + Prevent sites from collecting settings from your browser and computer to create a unique digital fingerprint which can be used to track you. + </message> </messages> </release> </grit>
diff --git a/components/user_education/common/feature_promo_specification.cc b/components/user_education/common/feature_promo_specification.cc index 3c76c90c..ad4a400 100644 --- a/components/user_education/common/feature_promo_specification.cc +++ b/components/user_education/common/feature_promo_specification.cc
@@ -55,6 +55,7 @@ // Add the text names of allowlisted keyed notices here: static const char* const kAllowedPromoNames[] = { "IPH_DesktopPWAsLinkCapturingLaunch", + "IPH_ExplicitBrowserSigninPreferenceRemembered", "IPH_SignoutWebIntercept", }; for (const auto* promo_name : kAllowedPromoNames) {
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn index 1d5ee89a..d776e5d0 100644 --- a/components/vector_icons/BUILD.gn +++ b/components/vector_icons/BUILD.gn
@@ -96,9 +96,7 @@ "folder_chrome_refresh.icon", "folder_managed.icon", "folder_managed_refresh.icon", - "folder_managed_touch.icon", "folder_open.icon", - "folder_touch.icon", "font_download.icon", "font_download_chrome_refresh.icon", "font_download_off_chrome_refresh.icon",
diff --git a/components/vector_icons/folder_managed_touch.icon b/components/vector_icons/folder_managed_touch.icon deleted file mode 100644 index 6125a621..0000000 --- a/components/vector_icons/folder_managed_touch.icon +++ /dev/null
@@ -1,71 +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. - -CANVAS_DIMENSIONS, 24, -MOVE_TO, 14, 15, -R_V_LINE_TO, -1, -R_H_LINE_TO, -1, -R_V_LINE_TO, -1, -R_H_LINE_TO, 2, -R_V_LINE_TO, 3, -R_H_LINE_TO, -2, -R_V_LINE_TO, -1, -R_H_LINE_TO, 1, -CLOSE, -MOVE_TO, 10, 4, -R_LINE_TO, 2, 2, -R_H_LINE_TO, 8, -R_CUBIC_TO, 1.1f, 0, 2, 0.9f, 2, 2, -R_V_LINE_TO, 10, -R_CUBIC_TO, 0, 1.1f, -0.9f, 2, -2, 2, -H_LINE_TO, 4, -R_CUBIC_TO, -1.1f, 0, -2, -0.9f, -2, -2, -R_LINE_TO, 0.01f, -12, -R_CUBIC_TO, 0, -1.1f, 0.89f, -2, 1.99f, -2, -R_H_LINE_TO, 6, -CLOSE, -R_MOVE_TO, 3, 6, -H_LINE_TO, 8, -R_V_LINE_TO, 7, -R_H_LINE_TO, 8, -R_V_LINE_TO, -5, -R_H_LINE_TO, -3, -R_V_LINE_TO, -2, -CLOSE, -R_MOVE_TO, -4, 1, -R_H_LINE_TO, 1, -R_V_LINE_TO, 1, -H_LINE_TO, 9, -R_V_LINE_TO, -1, -CLOSE, -R_MOVE_TO, 2, 0, -R_H_LINE_TO, 1, -R_V_LINE_TO, 1, -R_H_LINE_TO, -1, -R_V_LINE_TO, -1, -CLOSE, -R_MOVE_TO, -2, 2, -R_H_LINE_TO, 1, -R_V_LINE_TO, 1, -H_LINE_TO, 9, -R_V_LINE_TO, -1, -CLOSE, -R_MOVE_TO, 2, 0, -R_H_LINE_TO, 1, -R_V_LINE_TO, 1, -R_H_LINE_TO, -1, -R_V_LINE_TO, -1, -CLOSE, -R_MOVE_TO, -2, 2, -R_H_LINE_TO, 1, -R_V_LINE_TO, 1, -H_LINE_TO, 9, -R_V_LINE_TO, -1, -CLOSE, -R_MOVE_TO, 2, 0, -R_H_LINE_TO, 1, -R_V_LINE_TO, 1, -R_H_LINE_TO, -1, -R_V_LINE_TO, -1, -CLOSE
diff --git a/components/vector_icons/folder_touch.icon b/components/vector_icons/folder_touch.icon deleted file mode 100644 index 7d4e6dfd..0000000 --- a/components/vector_icons/folder_touch.icon +++ /dev/null
@@ -1,17 +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. - -CANVAS_DIMENSIONS, 24, -MOVE_TO, 10, 4, -H_LINE_TO, 4, -R_CUBIC_TO, -1.1f, 0, -1.99f, 0.9f, -1.99f, 2, -LINE_TO, 2, 18, -R_CUBIC_TO, 0, 1.1f, 0.9f, 2, 2, 2, -R_H_LINE_TO, 16, -R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2, -V_LINE_TO, 8, -R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2, -R_H_LINE_TO, -8, -R_LINE_TO, -2, -2, -CLOSE
diff --git a/components/visited_url_ranking/internal/history_url_visit_data_fetcher.cc b/components/visited_url_ranking/internal/history_url_visit_data_fetcher.cc index 7638214..3dfb91e 100644 --- a/components/visited_url_ranking/internal/history_url_visit_data_fetcher.cc +++ b/components/visited_url_ranking/internal/history_url_visit_data_fetcher.cc
@@ -8,7 +8,6 @@ #include <utility> #include "base/containers/contains.h" -#include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "components/history/core/browser/history_service.h" #include "components/history/core/browser/history_types.h" @@ -23,7 +22,7 @@ using URLVisitVariant = URLVisitAggregate::URLVisitVariant; HistoryURLVisitDataFetcher::HistoryURLVisitDataFetcher( - base::WeakPtr<history::HistoryService> history_service) + history::HistoryService* history_service) : history_service_(history_service) {} HistoryURLVisitDataFetcher::~HistoryURLVisitDataFetcher() = default; @@ -77,8 +76,14 @@ history.visit_count += 1; history.total_foreground_duration += annotated_visit.context_annotations.total_foreground_duration; - // TODO(crbug.com/330580109): Add `in_cluster`, dismiss/done `status` - // signals. + + if (!history.last_app_id.has_value() && + annotated_visit.visit_row.app_id.has_value()) { + history.last_app_id = annotated_visit.visit_row.app_id; + } + + // TODO(crbug.com/340885723): Wire `in_cluster` signal. + // TODO(crbug.com/340887237): Wire `interaction_state` signal. } }
diff --git a/components/visited_url_ranking/internal/history_url_visit_data_fetcher.h b/components/visited_url_ranking/internal/history_url_visit_data_fetcher.h index 85492b4..194a8b7e36 100644 --- a/components/visited_url_ranking/internal/history_url_visit_data_fetcher.h +++ b/components/visited_url_ranking/internal/history_url_visit_data_fetcher.h
@@ -8,7 +8,7 @@ #include <utility> #include <vector> -#include "base/memory/weak_ptr.h" +#include "base/memory/raw_ptr.h" #include "base/task/cancelable_task_tracker.h" #include "components/visited_url_ranking/public/fetch_result.h" #include "components/visited_url_ranking/public/url_visit.h" @@ -24,8 +24,7 @@ // Fetches URL visit data from the history service. class HistoryURLVisitDataFetcher : public URLVisitDataFetcher { public: - explicit HistoryURLVisitDataFetcher( - base::WeakPtr<history::HistoryService> history_service); + explicit HistoryURLVisitDataFetcher(history::HistoryService* history_service); HistoryURLVisitDataFetcher(const HistoryURLVisitDataFetcher&) = delete; ~HistoryURLVisitDataFetcher() override; @@ -40,7 +39,7 @@ FetchOptions::FetchSources requested_fetch_sources, std::vector<history::AnnotatedVisit> annotated_visits); - const base::WeakPtr<history::HistoryService> history_service_; + const raw_ptr<history::HistoryService> history_service_; // The task tracker for the HistoryService callbacks. base::CancelableTaskTracker task_tracker_;
diff --git a/components/visited_url_ranking/internal/history_url_visit_data_fetcher_unittest.cc b/components/visited_url_ranking/internal/history_url_visit_data_fetcher_unittest.cc index eac05996..75eff16 100644 --- a/components/visited_url_ranking/internal/history_url_visit_data_fetcher_unittest.cc +++ b/components/visited_url_ranking/internal/history_url_visit_data_fetcher_unittest.cc
@@ -29,6 +29,7 @@ const GURL& url, float visibility_score, const std::string& originator_cache_guid, + const std::optional<std::string> app_id = std::nullopt, const base::Time visit_time = base::Time::Now()) { history::VisitContentModelAnnotations model_annotations; model_annotations.visibility_score = visibility_score; @@ -41,6 +42,7 @@ visit_row.visit_time = visit_time; visit_row.is_known_to_sync = true; visit_row.originator_cache_guid = originator_cache_guid; + visit_row.app_id = app_id; history::AnnotatedVisit annotated_visit; annotated_visit.url_row = std::move(url_row); @@ -89,7 +91,8 @@ -> base::CancelableTaskTracker::TaskId { std::vector<history::AnnotatedVisit> annotated_visits = {}; annotated_visits.emplace_back(SampleAnnotatedVisit( - 1, GURL(base::StrCat({kSampleSearchUrl, "1"})), 1.0f, "")); + 1, GURL(base::StrCat({kSampleSearchUrl, "1"})), 1.0f, "", + "sample_app_id")); annotated_visits.emplace_back(SampleAnnotatedVisit( 2, GURL(base::StrCat({kSampleSearchUrl, "2"})), 0.75f, "foreign_session_guid")); @@ -97,7 +100,7 @@ return 0; })); history_url_visit_fetcher_ = std::make_unique<HistoryURLVisitDataFetcher>( - mock_history_service_->AsWeakPtr()); + mock_history_service_.get()); } FetchResult FetchAndGetResult(const FetchOptions& options) { @@ -129,6 +132,11 @@ auto result = FetchAndGetResult(options); EXPECT_EQ(result.status, FetchResult::Status::kSuccess); EXPECT_EQ(result.data.size(), 2u); + + const auto entry_url = GURL(base::StrCat({kSampleSearchUrl, "1"})); + const auto* history = std::get_if<URLVisitAggregate::HistoryData>( + &result.data.at(entry_url.spec())); + EXPECT_EQ(history->last_app_id, "sample_app_id"); } INSTANTIATE_TEST_SUITE_P(All,
diff --git a/components/visited_url_ranking/internal/visited_url_ranking_service_impl.cc b/components/visited_url_ranking/internal/visited_url_ranking_service_impl.cc index 358911d..9a91d6e6 100644 --- a/components/visited_url_ranking/internal/visited_url_ranking_service_impl.cc +++ b/components/visited_url_ranking/internal/visited_url_ranking_service_impl.cc
@@ -4,6 +4,7 @@ #include "components/visited_url_ranking/internal/visited_url_ranking_service_impl.h" +#include <algorithm> #include <map> #include <memory> #include <queue> @@ -25,6 +26,26 @@ namespace visited_url_ranking { +namespace { + +base::Time GetVisitTime(const URLVisitAggregate::URLVisitVariant& visit) { + const URLVisitAggregate::TabData* tab_data = + std::get_if<URLVisitAggregate::TabData>(&visit); + if (tab_data) { + return tab_data->last_active; + } + + const URLVisitAggregate::HistoryData* history_data = + std::get_if<URLVisitAggregate::HistoryData>(&visit); + if (history_data) { + return history_data->last_visited.visit_row.visit_time; + } + + return base::Time::Max(); +} + +} // namespace + // Combines `URLVisitVariant` data obtained from various fetchers into // `URLVisitAggregate` objects. Leverages the `URLMergeKey` in order to // reconcile what data belongs to the same aggregate object. @@ -98,6 +119,33 @@ std::vector<URLVisitAggregate> visits, RankVisitAggregatesCallback callback) { // TODO(crbug.com/330577142): Implement `URLVisitAggregate` ranking logic. + + // To enable development and testing, below we implement a stub implementation + // that simply sorts |visits| by minimal |last_active|. + size_t num_visits = visits.size(); + + // Extract sort keys (|fetcher_data_map| may have any size) and create sort + // permutation, which also avoids object movement churn from direct sort. + std::vector<std::pair<base::Time, size_t>> keys; + keys.reserve(num_visits); + for (size_t i = 0; i < num_visits; ++i) { + const auto& aggregate = visits[i]; + base::Time min_last_visit_time = base::Time::Max(); + for (auto& key_value : aggregate.fetcher_data_map) { + min_last_visit_time = + std::min(min_last_visit_time, GetVisitTime(key_value.second)); + } + keys.emplace_back(min_last_visit_time, i); + } + // Sort from oldest to newest. + std::sort(keys.begin(), keys.end()); + + // Apply permutation, and reverse, so newest comes first. + std::vector<URLVisitAggregate> ranked_visits(num_visits); + for (size_t i = 0; i < num_visits; ++i) { + ranked_visits[num_visits - 1 - i] = std::move(visits[keys[i].second]); + } + std::move(callback).Run(ResultStatus::kSuccess, std::move(ranked_visits)); } void VisitedURLRankingServiceImpl::MergeVisitsAndCallback(
diff --git a/components/visited_url_ranking/public/url_visit.cc b/components/visited_url_ranking/public/url_visit.cc index 57eba738..dfc62fbf 100644 --- a/components/visited_url_ranking/public/url_visit.cc +++ b/components/visited_url_ranking/public/url_visit.cc
@@ -5,6 +5,7 @@ #include "components/visited_url_ranking/public/url_visit.h" #include <set> +#include <string> #include <utility> #include <variant> @@ -76,8 +77,17 @@ visit_count = 1; total_foreground_duration = last_visited.context_annotations.total_foreground_duration; + if (last_visited.visit_row.app_id.has_value()) { + last_app_id = last_visited.visit_row.app_id; + } } +URLVisitAggregate::HistoryData::HistoryData( + URLVisitAggregate::HistoryData&& other) = default; + +URLVisitAggregate::HistoryData& URLVisitAggregate::HistoryData::operator=( + URLVisitAggregate::HistoryData&& other) = default; + URLVisitAggregate::HistoryData::~HistoryData() = default; } // namespace visited_url_ranking
diff --git a/components/visited_url_ranking/public/url_visit.h b/components/visited_url_ranking/public/url_visit.h index 8581be3..efe10d4 100644 --- a/components/visited_url_ranking/public/url_visit.h +++ b/components/visited_url_ranking/public/url_visit.h
@@ -8,6 +8,7 @@ #include <memory> #include <optional> #include <set> +#include <string> #include <variant> #include <vector> @@ -102,12 +103,19 @@ struct HistoryData { explicit HistoryData(history::AnnotatedVisit annotated_visit); + HistoryData(const HistoryData&) = delete; + HistoryData(HistoryData&& other); + HistoryData& operator=(HistoryData&& other); ~HistoryData(); // The last annotated visit associated with the given URL visit in a given // time period. history::AnnotatedVisit last_visited; + // The last `app_id` value if any for any of the visits associated with the + // URL visit aggregate. + std::optional<std::string> last_app_id = std::nullopt; + // Whether any of the annotated visits for the given URL visit aggregate are // part of a cluster. bool in_cluster = false;
diff --git a/components/viz/common/viz_utils.cc b/components/viz/common/viz_utils.cc index 6eb0b442..e27c2a2 100644 --- a/components/viz/common/viz_utils.cc +++ b/components/viz/common/viz_utils.cc
@@ -11,6 +11,7 @@ #include "base/system/sys_info.h" #include "build/build_config.h" #include "cc/base/math_util.h" +#include "components/viz/common/frame_sinks/copy_output_request.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rrect_f.h" @@ -213,4 +214,34 @@ return false; } +void SetCopyOutoutRequestResultSize(CopyOutputRequest* request, + const gfx::Rect& src_rect, + const gfx::Size& output_size, + const gfx::Size& surface_size_in_pixels) { + CHECK(request); + if (!src_rect.IsEmpty()) { + request->set_area(src_rect); + } + if (output_size.IsEmpty()) { + return; + } + // The CopyOutputRequest API does not allow fixing the output size. Instead + // we have the set area and scale in such a way that it would result in the + // desired output size. + if (!request->has_area()) { + request->set_area(gfx::Rect(surface_size_in_pixels)); + } + request->set_result_selection(gfx::Rect(output_size)); + const gfx::Rect& area = request->area(); + // Viz would normally return an empty result for an empty area. + // However, this guard here is still necessary to protect against setting + // an illegal scaling ratio. + if (area.IsEmpty()) { + return; + } + request->SetScaleRatio( + gfx::Vector2d(area.width(), area.height()), + gfx::Vector2d(output_size.width(), output_size.height())); +} + } // namespace viz
diff --git a/components/viz/common/viz_utils.h b/components/viz/common/viz_utils.h index 2d4865d..1492902 100644 --- a/components/viz/common/viz_utils.h +++ b/components/viz/common/viz_utils.h
@@ -25,6 +25,8 @@ VIZ_COMMON_EXPORT bool AlwaysUseWideColorGamut(); #endif +class CopyOutputRequest; + // This takes a gfx::Rect and a clip region quad in the same space, // and returns a quad with the same proportions in the space -0.5->0.5. VIZ_COMMON_EXPORT bool GetScaledRegion(const gfx::Rect& rect, @@ -71,6 +73,13 @@ const DrawQuad* quad, const gfx::RectF& target_quad); +// Customizes the output sizes of a `CopyOutputRequest`. +VIZ_COMMON_EXPORT void SetCopyOutoutRequestResultSize( + CopyOutputRequest* request, + const gfx::Rect& src_rect, + const gfx::Size& output_size, + const gfx::Size& surface_size_in_pixels); + } // namespace viz #endif // COMPONENTS_VIZ_COMMON_VIZ_UTILS_H_
diff --git a/components/viz/host/host_frame_sink_manager.cc b/components/viz/host/host_frame_sink_manager.cc index f437063..7b13bd2 100644 --- a/components/viz/host/host_frame_sink_manager.cc +++ b/components/viz/host/host_frame_sink_manager.cc
@@ -312,7 +312,9 @@ const blink::SameDocNavigationScreenshotDestinationToken& destination_token) { auto it = screenshot_destinations_.find(destination_token); - CHECK(it != screenshot_destinations_.end()); + if (it == screenshot_destinations_.end()) { + return; + } screenshot_destinations_.erase(it); } @@ -445,11 +447,10 @@ if (it == screenshot_destinations_.end()) { return; } - SkBitmap immutable = - copy_output_result->ScopedAccessSkBitmap().GetOutScopedBitmap(); - immutable.setImmutable(); - std::move(it->second).Run(destination_token, std::move(immutable)); + auto callback = std::move(it->second); screenshot_destinations_.erase(it); + std::move(callback).Run( + copy_output_result->ScopedAccessSkBitmap().GetOutScopedBitmap()); } uint32_t HostFrameSinkManager::CacheBackBufferForRootSink( @@ -518,6 +519,12 @@ return has_resources; } +void HostFrameSinkManager::SetSameDocNavigationScreenshotSizeForTesting( + const gfx::Size& result_size) { + frame_sink_manager_->SetSameDocNavigationScreenshotSizeForTesting( // IN-TEST + result_size); +} + HostFrameSinkManager::FrameSinkData::FrameSinkData() = default; HostFrameSinkManager::FrameSinkData::FrameSinkData(FrameSinkData&& other) =
diff --git a/components/viz/host/host_frame_sink_manager.h b/components/viz/host/host_frame_sink_manager.h index 790ef5a7..2253c00 100644 --- a/components/viz/host/host_frame_sink_manager.h +++ b/components/viz/host/host_frame_sink_manager.h
@@ -201,10 +201,8 @@ std::unique_ptr<CopyOutputRequest> request, bool capture_exact_surface_id = false); - using ScreenshotDestinationReadyCallback = base::OnceCallback<void( - const blink::SameDocNavigationScreenshotDestinationToken& - destination_token, - SkBitmap copy_output)>; + using ScreenshotDestinationReadyCallback = + base::OnceCallback<void(const SkBitmap& copy_output)>; // Sets the callback which is invoked when a `CopyOutputResult` associated // with `destination_token` is received by the host/browser process from the // Viz process. Must be called once per `destination_token`. @@ -261,6 +259,9 @@ const blink::ViewTransitionToken& transition_token); bool HasUnclaimedViewTransitionResourcesForTest(); + void SetSameDocNavigationScreenshotSizeForTesting( + const gfx::Size& result_size); + const DebugRendererSettings& debug_renderer_settings() const { return debug_renderer_settings_; }
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 49614db8..ef64adc 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -436,22 +436,26 @@ if (enabled) { DBG_LOG("renderer.skia.render_pass_backings", "render_pass_backings_ = ["); - for (auto& kv : render_pass_backings) { + for (auto& [render_pass_id, backing] : render_pass_backings) { base::trace_event::TracedValueJSON value; base::trace_event::TracedValue::Dictionary( { - {"size", kv.second.size.ToString()}, - {"generate_mipmap", kv.second.generate_mipmap}, - {"color_space", kv.second.color_space.ToString()}, - {"format", kv.second.format.ToString()}, - {"mailbox", kv.second.mailbox.ToDebugString()}, - {"is_root", kv.second.is_root}, - {"is_scanout", kv.second.is_scanout}, - {"scanout_dcomp_surface", kv.second.scanout_dcomp_surface}, + {"size", backing.size.ToString()}, + {"generate_mipmap", backing.generate_mipmap}, + {"color_space", backing.color_space.ToString()}, + {"alpha_type", + backing.alpha_type == RenderPassAlphaType::kPremul ? "premul" + : "opaque"}, + {"format", backing.format.ToString()}, + {"mailbox", backing.mailbox.ToDebugString()}, + {"is_root", backing.is_root}, + {"is_scanout", backing.is_scanout}, + {"scanout_dcomp_surface", backing.scanout_dcomp_surface}, + {"drawn_rect", backing.drawn_rect.ToString()}, }) .WriteToValue(&value); DBG_LOG("renderer.skia.render_pass_backings", "%" PRIu64 ": %s", - kv.first.value(), value.ToFormattedJSON().c_str()); + render_pass_id.value(), value.ToFormattedJSON().c_str()); } DBG_LOG("renderer.skia.render_pass_backings", "]"); } @@ -2999,7 +3003,7 @@ if (auto backing = GetRenderPassBackingForDirectScanout( overlay.rpdq->render_pass_id); backing) { - DBG_LOG("delegated.overlays.log", + DBG_LOG("delegated.overlay.log", "Pass %" PRIu64 ": RPDQ overlay can scanout directly", overlay.rpdq->render_pass_id.value());
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 1be038db..5549f14 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc +++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -30,6 +30,7 @@ #include "components/viz/common/resources/bitmap_allocation.h" #include "components/viz/common/surfaces/surface_info.h" #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" @@ -924,6 +925,15 @@ &RemoveSurfaceReferenceAndDispatchCopyOutputRequestCallback, frame_sink_manager_->GetWeakPtr(), surface_info.id(), frame.metadata.screenshot_destination.value())); + if (const auto& size_for_testing = + frame_sink_manager_ + ->copy_output_request_result_size_for_testing(); // IN-TEST + UNLIKELY(!size_for_testing.IsEmpty())) { + SetCopyOutoutRequestResultSize(copy_request.get(), gfx::Rect(), + size_for_testing, + prev_surface->size_in_pixels()); + } + copy_request->set_result_task_runner( base::SequencedTaskRunner::GetCurrentDefault());
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 14607a0f..22f171d 100644 --- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc +++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -948,4 +948,11 @@ std::move(callback).Run(!transition_token_to_animation_manager_.empty()); } +void FrameSinkManagerImpl::SetSameDocNavigationScreenshotSizeForTesting( + const gfx::Size& result_size, + SetSameDocNavigationScreenshotSizeForTestingCallback callback) { + copy_output_request_result_size_for_testing_ = result_size; + std::move(callback).Run(); +} + } // namespace viz
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 c28c842..460f0c6 100644 --- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h +++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -169,6 +169,9 @@ const blink::ViewTransitionToken& transition_token) override; void HasUnclaimedViewTransitionResourcesForTest( HasUnclaimedViewTransitionResourcesForTestCallback callback) override; + void SetSameDocNavigationScreenshotSizeForTesting( + const gfx::Size& result_size, + SetSameDocNavigationScreenshotSizeForTestingCallback callback) override; void DestroyFrameSinkBundle(const FrameSinkBundleId& id); @@ -310,6 +313,10 @@ return &reserved_resource_id_tracker_; } + const gfx::Size& copy_output_request_result_size_for_testing() const { + return copy_output_request_result_size_for_testing_; + } + private: friend class FrameSinkManagerTest; friend class CompositorFrameSinkSupportTest; @@ -501,6 +508,8 @@ ReservedResourceIdTracker reserved_resource_id_tracker_; + gfx::Size copy_output_request_result_size_for_testing_; + base::WeakPtrFactory<FrameSinkManagerImpl> weak_factory_{this}; };
diff --git a/components/viz/service/surfaces/surface_manager.h b/components/viz/service/surfaces/surface_manager.h index ffe4eef9..b0c56e8 100644 --- a/components/viz/service/surfaces/surface_manager.h +++ b/components/viz/service/surfaces/surface_manager.h
@@ -135,15 +135,6 @@ // possibly because a renderer process has crashed. void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id); - // Register a relationship between two namespaces. This relationship means - // that surfaces from the child namespace will be displayed in the parent. - // Children are allowed to use any begin frame source that their parent can - // use. - void RegisterFrameSinkHierarchy(const FrameSinkId& parent_frame_sink_id, - const FrameSinkId& child_frame_sink_id); - void UnregisterFrameSinkHierarchy(const FrameSinkId& parent_frame_sink_id, - const FrameSinkId& child_frame_sink_id); - // Returns the top level root SurfaceId. Surfaces that are not reachable // from the top level root may be garbage collected. It will not be a valid // SurfaceId and will never correspond to a surface.
diff --git a/components/viz/test/test_frame_sink_manager.h b/components/viz/test/test_frame_sink_manager.h index 2d1ace3..3668f36 100644 --- a/components/viz/test/test_frame_sink_manager.h +++ b/components/viz/test/test_frame_sink_manager.h
@@ -84,6 +84,9 @@ const blink::ViewTransitionToken& transition_token) override {} void HasUnclaimedViewTransitionResourcesForTest( HasUnclaimedViewTransitionResourcesForTestCallback callback) override {} + void SetSameDocNavigationScreenshotSizeForTesting( + const gfx::Size& result_size, + SetSameDocNavigationScreenshotSizeForTestingCallback callback) override {} mojo::Receiver<mojom::FrameSinkManager> receiver_{this}; mojo::Remote<mojom::FrameSinkManagerClient> client_;
diff --git a/content/browser/DEPS b/content/browser/DEPS index b8b20d6..2fc0a9f 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS
@@ -136,7 +136,7 @@ "+components/os_crypt/async", "+services/network/test", ], - ".*test_utils\.(h|cc)": [ + ".*test_utils?(_.+)?\.(h|cc)": [ "+services/network/test", ], "browser_interface_binders\.cc": [
diff --git a/content/browser/attribution_reporting/attribution_internals_browsertest.cc b/content/browser/attribution_reporting/attribution_internals_browsertest.cc index fefd62d..55d238c 100644 --- a/content/browser/attribution_reporting/attribution_internals_browsertest.cc +++ b/content/browser/attribution_reporting/attribution_internals_browsertest.cc
@@ -863,6 +863,7 @@ SourceBuilder(now).BuildStored()) .SetReportTime(now) .SetPriority(7) + .SetReportId(AttributionReport::Id(1)) .Build(); std::vector<AttributionReport> stored_reports; @@ -875,10 +876,10 @@ callback) { std::move(callback).Run(stored_reports); }); report.set_report_time(report.report_time() + base::Hours(1)); - manager()->NotifyReportSent(report, - /*is_debug_report=*/false, - SendResult(SendResult::Status::kSent, net::OK, - /*http_response_code=*/200)); + + // Give the report a distinct ID to ensure that it won't overwrite the UI row + // for the stored report. + report.set_id(AttributionReport::Id(2)); EXPECT_CALL(*manager(), ClearData) .WillOnce([&](base::Time delete_begin, base::Time delete_end, @@ -918,6 +919,10 @@ // Wait for the table to rendered. TitleWatcher title_watcher(shell()->web_contents(), kCompleteTitle); ClickRefreshButton(); + manager()->NotifyReportSent(report, + /*is_debug_report=*/false, + SendResult(SendResult::Status::kSent, net::OK, + /*http_response_code=*/200)); ASSERT_EQ(kCompleteTitle, title_watcher.WaitAndGetTitle()); // Click the clear storage button and expect that the report table is emptied.
diff --git a/content/browser/browsing_data/browsing_data_filter_builder_impl.cc b/content/browser/browsing_data/browsing_data_filter_builder_impl.cc index cd3bd471..04a97bf9 100644 --- a/content/browser/browsing_data/browsing_data_filter_builder_impl.cc +++ b/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
@@ -219,9 +219,13 @@ } bool BrowsingDataFilterBuilderImpl::MatchesAllOriginsAndDomains() { - return mode_ == Mode::kPreserve && origins_.empty() && domains_.empty() && - !partitioned_cookies_only_ && - cookie_partition_key_collection_.ContainsAllKeys() && !HasStorageKey(); + return MatchesMostOriginsAndDomains() && origins_.empty() && + domains_.empty() && cookie_partition_key_collection_.ContainsAllKeys(); +} + +bool BrowsingDataFilterBuilderImpl::MatchesMostOriginsAndDomains() { + return mode_ == Mode::kPreserve && !partitioned_cookies_only_ && + !HasStorageKey(); } bool BrowsingDataFilterBuilderImpl::MatchesNothing() {
diff --git a/content/browser/browsing_data/browsing_data_filter_builder_impl.h b/content/browser/browsing_data/browsing_data_filter_builder_impl.h index 43a7a61..8e82a319 100644 --- a/content/browser/browsing_data/browsing_data_filter_builder_impl.h +++ b/content/browser/browsing_data/browsing_data_filter_builder_impl.h
@@ -42,6 +42,7 @@ bool MatchesWithSavedStorageKey( const blink::StorageKey& other_key) const override; bool MatchesAllOriginsAndDomains() override; + bool MatchesMostOriginsAndDomains() override; bool MatchesNothing() override; void SetPartitionedCookiesOnly(bool value) override; bool PartitionedCookiesOnly() const override;
diff --git a/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc b/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc index 79faae5..2a2dfeaf 100644 --- a/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc +++ b/content/browser/browsing_data/browsing_data_filter_builder_impl_unittest.cc
@@ -1155,4 +1155,62 @@ EXPECT_EQ(builder, *builder.Copy()); } +TEST(BrowsingDataFilterBuilderImplTest, DeleteModeDoesntMatchMost) { + BrowsingDataFilterBuilderImpl builder( + BrowsingDataFilterBuilder::Mode::kDelete); + + EXPECT_FALSE(builder.MatchesAllOriginsAndDomains()); + EXPECT_FALSE(builder.MatchesMostOriginsAndDomains()); +} + +TEST(BrowsingDataFilterBuilderImplTest, PreserveModeMatchesAll) { + BrowsingDataFilterBuilderImpl builder( + BrowsingDataFilterBuilder::Mode::kPreserve); + + EXPECT_TRUE(builder.MatchesAllOriginsAndDomains()); + EXPECT_TRUE(builder.MatchesMostOriginsAndDomains()); +} + +TEST(BrowsingDataFilterBuilderImplTest, + PreserveModeWithOriginsOrDomainsMatchesMost) { + BrowsingDataFilterBuilderImpl builder( + BrowsingDataFilterBuilder::Mode::kPreserve); + builder.AddOrigin(url::Origin::Create(GURL("http://example.test"))); + builder.AddRegisterableDomain("example.test"); + + EXPECT_FALSE(builder.MatchesAllOriginsAndDomains()); + EXPECT_TRUE(builder.MatchesMostOriginsAndDomains()); +} + +TEST(BrowsingDataFilterBuilderImplTest, + PreserveModeWithCookiePartitionKeysMatchesMost) { + BrowsingDataFilterBuilderImpl builder( + BrowsingDataFilterBuilder::Mode::kPreserve); + builder.SetCookiePartitionKeyCollection(net::CookiePartitionKeyCollection()); + + EXPECT_FALSE(builder.MatchesAllOriginsAndDomains()); + EXPECT_TRUE(builder.MatchesMostOriginsAndDomains()); +} + +TEST(BrowsingDataFilterBuilderImplTest, + PreserveModeWithStorageKeyDoesntMatchMost) { + BrowsingDataFilterBuilderImpl builder( + BrowsingDataFilterBuilder::Mode::kPreserve); + builder.SetStorageKey( + blink::StorageKey::CreateFromStringForTesting("http://example.test")); + + EXPECT_FALSE(builder.MatchesAllOriginsAndDomains()); + EXPECT_FALSE(builder.MatchesMostOriginsAndDomains()); +} + +TEST(BrowsingDataFilterBuilderImplTest, + PreserveModePartitionedCookiesOnlyDoesntMatchMost) { + BrowsingDataFilterBuilderImpl builder( + BrowsingDataFilterBuilder::Mode::kPreserve); + builder.SetPartitionedCookiesOnly(true); + + EXPECT_FALSE(builder.MatchesAllOriginsAndDomains()); + EXPECT_FALSE(builder.MatchesMostOriginsAndDomains()); +} + } // namespace content
diff --git a/content/browser/device_posture/foldable_apis_origin_trial_browsertest.cc b/content/browser/device_posture/foldable_apis_origin_trial_browsertest.cc index d46acb6be..e20a9b14 100644 --- a/content/browser/device_posture/foldable_apis_origin_trial_browsertest.cc +++ b/content/browser/device_posture/foldable_apis_origin_trial_browsertest.cc
@@ -139,8 +139,14 @@ std::unique_ptr<content::URLLoaderInterceptor> interceptor_; }; +// TODO(crbug.com/339983706): Fix flaky test on macOS. +#if BUILDFLAG(IS_MAC) +#define MAYBE_ValidOriginTrialToken DISABLED_ValidOriginTrialToken +#else +#define MAYBE_ValidOriginTrialToken ValidOriginTrialToken +#endif IN_PROC_BROWSER_TEST_F(FoldableAPIsOriginTrialBrowserTest, - ValidOriginTrialToken) { + MAYBE_ValidOriginTrialToken) { ASSERT_TRUE(NavigateToURL(shell(), kValidTokenUrl)); SetUpFoldableState(); EXPECT_TRUE(HasDevicePostureApi());
diff --git a/content/browser/network/http_cookie_browsertest.cc b/content/browser/network/http_cookie_browsertest.cc index 18c9ac318..f8117bc 100644 --- a/content/browser/network/http_cookie_browsertest.cc +++ b/content/browser/network/http_cookie_browsertest.cc
@@ -42,6 +42,7 @@ constexpr char kHostA[] = "a.test"; constexpr char kHostB[] = "b.test"; +constexpr char kHostC[] = "c.test"; constexpr char kSameSiteNoneCookieName[] = "samesite_none_cookie"; constexpr char kSameSiteStrictCookieName[] = "samesite_strict_cookie"; constexpr char kSameSiteLaxCookieName[] = "samesite_lax_cookie"; @@ -885,9 +886,178 @@ net::CookieStringIs(IsEmpty())); } +class AncestorChainBitEnabledThirdPartyCookiesBlockedTest + : public ContentBrowserTest, + public ::testing::WithParamInterface<bool> { + public: + AncestorChainBitEnabledThirdPartyCookiesBlockedTest() + : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { + feature_list_.InitWithFeatureStates( + {{net::features::kForceThirdPartyCookieBlocking, true}, + {net::features::kAncestorChainBitEnabledInPartitionedCookies, + AncestorChainBitEnabled()}}); + } + + bool AncestorChainBitEnabled() { return GetParam(); } + + ~AncestorChainBitEnabledThirdPartyCookiesBlockedTest() override = default; + + void SetUpOnMainThread() override { + ContentBrowserTest::SetUpOnMainThread(); + host_resolver()->AddRule("*", "127.0.0.1"); + https_server()->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES); + https_server()->AddDefaultHandlers(GetTestDataFilePath()); + https_server()->RegisterRequestHandler( + base::BindRepeating(&HandleEchoCookiesWithCorsRequest)); + ASSERT_TRUE(https_server()->Start()); + } + + WebContents* web_contents() const { return shell()->web_contents(); } + + net::EmbeddedTestServer* https_server() { return &https_server_; } + + GURL EchoCookiesUrl(const std::string& host) const { + return https_server_.GetURL(host, "/echoheader?Cookie"); + } + + std::string ExtractFrameContent(RenderFrameHost* frame) const { + return EvalJs(frame, "document.body.textContent").ExtractString(); + } + + private: + base::test::ScopedFeatureList feature_list_; + net::test_server::EmbeddedTestServer https_server_; +}; + +IN_PROC_BROWSER_TEST_P(AncestorChainBitEnabledThirdPartyCookiesBlockedTest, + TestSubresourceRedirects) { + // Initial frame tree A->B (B is an iframe) + // A cookie is set for site C. + // iframe B is navigated to site C. + // Frame tree becomes A->C (C is an iframe). + // Check if cookie set for C is present in C. + + // Embed an iframe containing B in A to create initial frame tree A->B. + ASSERT_EQ(content::ArrangeFramesAndGetContentFromLeaf( + web_contents(), https_server(), base::StrCat({kHostA, "(%s)"}), + {0}, EchoCookiesUrl(kHostB)), + "None"); + + // Set SameSite=None partitioned cookie for kHostC from embedded iframe B. + + net::CookiePartitionKey partition_key = + net::CookiePartitionKey::FromURLForTesting( + https_server()->GetURL(kHostA, "/"), + net::CookiePartitionKey::AncestorChainBit::kCrossSite); + + ASSERT_TRUE(SetCookie( + web_contents()->GetBrowserContext(), https_server()->GetURL(kHostC, "/"), + base::StrCat( + {kSameSiteNoneCookieName, "=1;Secure;SameSite=None;partitioned"}), + net::CookieOptions::SameSiteCookieContext( + net::CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE), + &partition_key)); + // confirm that there is a cookie with kHostC url in the mojom cookie manager + // and that the cookie is partitioned and third party. + std::vector<net::CanonicalCookie> cookies = GetCanonicalCookies( + web_contents()->GetBrowserContext(), https_server()->GetURL(kHostC, "/"), + net::CookiePartitionKeyCollection::FromOptional( + std::make_optional(partition_key))); + ASSERT_EQ(cookies.size(), 1u); + ASSERT_TRUE(cookies[0].IsPartitioned()); + ASSERT_TRUE(cookies[0].PartitionKey()->IsThirdParty()); + + // Navigate embedded iframe B to C + ASSERT_TRUE(NavigateToURLFromRenderer( + ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0), + EchoCookiesUrl(kHostC))); + + // Extract cookie from C + EXPECT_THAT( + ExtractFrameContent( + ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0)), + net::CookieStringIs(UnorderedElementsAre(Key(kSameSiteNoneCookieName)))); +} + +IN_PROC_BROWSER_TEST_P(AncestorChainBitEnabledThirdPartyCookiesBlockedTest, + TestTopLevelRedirects) { + // Navigate to Site A and set cookie on site A. + // Redirect from site A to site B and back to site A. + // Confirm cookie is present on site A after redirection. + + ASSERT_TRUE(NavigateToURL(web_contents(), EchoCookiesUrl(kHostA))); + // Check to make sure that there are no cookies set on kHostA. + ASSERT_THAT(ExtractFrameContent(web_contents()->GetPrimaryMainFrame()), + "None"); + net::CookiePartitionKey partition_key = + net::CookiePartitionKey::FromURLForTesting( + https_server()->GetURL(kHostA, "/"), + net::CookiePartitionKey::AncestorChainBit::kSameSite); + + ASSERT_TRUE(SetCookie( + web_contents()->GetBrowserContext(), https_server()->GetURL(kHostA, "/"), + base::StrCat( + {kSameSiteNoneCookieName, "=1;Secure;SameSite=None;partitioned"}), + net::CookieOptions::SameSiteCookieContext::MakeInclusive(), + &partition_key)); + + // Perform redirect from site A to site B and back to site A. + ASSERT_TRUE( + NavigateToURL(web_contents(), + RedirectUrl(https_server(), kHostB, EchoCookiesUrl(kHostA)), + EchoCookiesUrl(kHostA))); + + EXPECT_THAT( + ExtractFrameContent(web_contents()->GetPrimaryMainFrame()), + net::CookieStringIs(UnorderedElementsAre(Key(kSameSiteNoneCookieName)))); +} + +IN_PROC_BROWSER_TEST_P( + AncestorChainBitEnabledThirdPartyCookiesBlockedTest, + TestSameSiteEmbeddedResourceToCrossSiteEmbeddedResource) { + // Initial frame tree A1->A2 (A2 is an iframe) + // A cookie is set from top-level A1 for site B with kCrossSite ancestor chain + // bit. iframe A2 is navigated to site B. Frame tree becomes A1->B (B is an + // iframe). Check if cookie set from A1 is present in B. + + // Embed an iframe containing A in A to create initial frame tree A->A. + ASSERT_EQ(content::ArrangeFramesAndGetContentFromLeaf( + web_contents(), https_server(), base::StrCat({kHostA, "(%s)"}), + {0}, EchoCookiesUrl(kHostA)), + "None"); + + net::CookiePartitionKey partition_key = + net::CookiePartitionKey::FromURLForTesting( + https_server()->GetURL(kHostA, "/"), + net::CookiePartitionKey::AncestorChainBit::kCrossSite); + + ASSERT_TRUE(SetCookie( + web_contents()->GetBrowserContext(), https_server()->GetURL(kHostB, "/"), + base::StrCat( + {kSameSiteNoneCookieName, "=1;Secure;SameSite=None;Partitioned"}), + net::CookieOptions::SameSiteCookieContext::MakeInclusive(), + &partition_key)); + + // Navigate embedded iframe A2 to B + ASSERT_TRUE(NavigateToURLFromRenderer( + ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0), + EchoCookiesUrl(kHostB))); + + // Extract cookie from B + EXPECT_THAT( + ExtractFrameContent( + ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0)), + net::CookieStringIs(UnorderedElementsAre(Key(kSameSiteNoneCookieName)))); +} + INSTANTIATE_TEST_SUITE_P(/* no label */, HttpCookieBrowserTest, ::testing::Bool()); +INSTANTIATE_TEST_SUITE_P( + /* no label */, + AncestorChainBitEnabledThirdPartyCookiesBlockedTest, + ::testing::Bool()); + } // namespace } // namespace content
diff --git a/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc b/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc index b3a1974..595556d 100644 --- a/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc +++ b/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc
@@ -6,7 +6,7 @@ #include "base/test/scoped_feature_list.h" #include "content/browser/preloading/prefetch/prefetch_container.h" -#include "content/browser/preloading/prefetch/prefetch_test_utils.h" +#include "content/browser/preloading/prefetch/prefetch_test_util_internal.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/public/test/test_renderer_host.h" #include "services/network/public/cpp/features.h"
diff --git a/content/browser/preloading/prefetch/prefetch_container_unittest.cc b/content/browser/preloading/prefetch/prefetch_container_unittest.cc index d58ea60..baa592fb 100644 --- a/content/browser/preloading/prefetch/prefetch_container_unittest.cc +++ b/content/browser/preloading/prefetch/prefetch_container_unittest.cc
@@ -11,7 +11,7 @@ #include "content/browser/preloading/prefetch/prefetch_features.h" #include "content/browser/preloading/prefetch/prefetch_probe_result.h" #include "content/browser/preloading/prefetch/prefetch_status.h" -#include "content/browser/preloading/prefetch/prefetch_test_utils.h" +#include "content/browser/preloading/prefetch/prefetch_test_util_internal.h" #include "content/browser/preloading/prefetch/prefetch_type.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/public/browser/browser_context.h"
diff --git a/content/browser/preloading/prefetch/prefetch_document_manager_unittest.cc b/content/browser/preloading/prefetch/prefetch_document_manager_unittest.cc index 31b1a02..aead1e3 100644 --- a/content/browser/preloading/prefetch/prefetch_document_manager_unittest.cc +++ b/content/browser/preloading/prefetch/prefetch_document_manager_unittest.cc
@@ -11,7 +11,7 @@ #include "base/test/scoped_feature_list.h" #include "content/browser/preloading/prefetch/prefetch_features.h" #include "content/browser/preloading/prefetch/prefetch_service.h" -#include "content/browser/preloading/prefetch/prefetch_test_utils.h" +#include "content/browser/preloading/prefetch/prefetch_test_util_internal.h" #include "content/public/test/navigation_simulator.h" #include "content/public/test/test_browser_context.h" #include "content/test/test_render_frame_host.h"
diff --git a/content/browser/preloading/prefetch/prefetch_streaming_url_loader_unittest.cc b/content/browser/preloading/prefetch/prefetch_streaming_url_loader_unittest.cc index 8bd208a..d67e474 100644 --- a/content/browser/preloading/prefetch/prefetch_streaming_url_loader_unittest.cc +++ b/content/browser/preloading/prefetch/prefetch_streaming_url_loader_unittest.cc
@@ -9,7 +9,7 @@ #include "base/test/task_environment.h" #include "content/browser/preloading/prefetch/prefetch_features.h" #include "content/browser/preloading/prefetch/prefetch_response_reader.h" -#include "content/browser/preloading/prefetch/prefetch_test_utils.h" +#include "content/browser/preloading/prefetch/prefetch_test_util_internal.h" #include "mojo/public/cpp/bindings/receiver_set.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "services/network/public/cpp/resource_request.h"
diff --git a/content/browser/preloading/prefetch/prefetch_test_utils.cc b/content/browser/preloading/prefetch/prefetch_test_util_internal.cc similarity index 99% rename from content/browser/preloading/prefetch/prefetch_test_utils.cc rename to content/browser/preloading/prefetch/prefetch_test_util_internal.cc index f7181fa6..636adf3 100644 --- a/content/browser/preloading/prefetch/prefetch_test_utils.cc +++ b/content/browser/preloading/prefetch/prefetch_test_util_internal.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/browser/preloading/prefetch/prefetch_test_utils.h" +#include "content/browser/preloading/prefetch/prefetch_test_util_internal.h" #include "base/run_loop.h" #include "base/time/time.h"
diff --git a/content/browser/preloading/prefetch/prefetch_test_utils.h b/content/browser/preloading/prefetch/prefetch_test_util_internal.h similarity index 96% rename from content/browser/preloading/prefetch/prefetch_test_utils.h rename to content/browser/preloading/prefetch/prefetch_test_util_internal.h index 08836a5..b9fd6ab 100644 --- a/content/browser/preloading/prefetch/prefetch_test_utils.h +++ b/content/browser/preloading/prefetch/prefetch_test_util_internal.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_TEST_UTILS_H_ -#define CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_TEST_UTILS_H_ +#ifndef CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_TEST_UTIL_INTERNAL_H_ +#define CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_TEST_UTIL_INTERNAL_H_ #include <memory> #include <ostream> @@ -132,4 +132,4 @@ } // namespace content -#endif // CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_TEST_UTILS_H_ +#endif // CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_TEST_UTIL_INTERNAL_H_
diff --git a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc index 2edce61..349b6af 100644 --- a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc +++ b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc
@@ -25,7 +25,7 @@ #include "content/browser/preloading/prefetch/prefetch_params.h" #include "content/browser/preloading/prefetch/prefetch_probe_result.h" #include "content/browser/preloading/prefetch/prefetch_service.h" -#include "content/browser/preloading/prefetch/prefetch_test_utils.h" +#include "content/browser/preloading/prefetch/prefetch_test_util_internal.h" #include "content/browser/preloading/prefetch/prefetch_type.h" #include "content/browser/preloading/prefetch/prefetch_url_loader_helper.h" #include "content/browser/preloading/preloading.h"
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc index 5a47250b..d1b801a4 100644 --- a/content/browser/preloading/prerender/prerender_browsertest.cc +++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -40,7 +40,7 @@ #include "content/browser/back_forward_cache_test_util.h" #include "content/browser/preloading/prefetch/prefetch_features.h" #include "content/browser/preloading/prefetch/prefetch_service.h" -#include "content/browser/preloading/prefetch/prefetch_test_utils.h" +#include "content/browser/preloading/prefetch/prefetch_test_util_internal.h" #include "content/browser/preloading/preloading.h" #include "content/browser/preloading/preloading_attempt_impl.h" #include "content/browser/preloading/preloading_data_impl.h"
diff --git a/content/browser/renderer_host/navigation_entry_impl.cc b/content/browser/renderer_host/navigation_entry_impl.cc index 77874251..0de65101 100644 --- a/content/browser/renderer_host/navigation_entry_impl.cc +++ b/content/browser/renderer_host/navigation_entry_impl.cc
@@ -19,7 +19,9 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "components/url_formatter/url_formatter.h" +#include "components/viz/host/host_frame_sink_manager.h" #include "content/browser/child_process_security_policy_impl.h" +#include "content/browser/compositor/surface_utils.h" #include "content/browser/renderer_host/frame_tree_node.h" #include "content/browser/renderer_host/navigation_controller_impl.h" #include "content/browser/renderer_host/navigation_entry_restore_context_impl.h" @@ -441,7 +443,19 @@ ? InitialNavigationEntryState::kInitialNotForSynchronousAboutBlank : InitialNavigationEntryState::kNonInitial) {} -NavigationEntryImpl::~NavigationEntryImpl() {} +NavigationEntryImpl::~NavigationEntryImpl() { + if (same_document_navigation_entry_screenshot_token_.has_value()) { + // We get here if: + // - `DidCommitSameDocumentNavigation` sets the token, promising a + // screenshot was supposed to arrive. + // - However the navigation entry was destroyed before the screenshot could + // arrive. + viz::HostFrameSinkManager* manager = GetHostFrameSinkManager(); + CHECK(manager); + manager->InvalidateCopyOutputReadyCallback( + same_document_navigation_entry_screenshot_token_.value()); + } +} int NavigationEntryImpl::GetUniqueID() { return unique_id_; @@ -1243,4 +1257,16 @@ return GetBaseURLForDataURL().is_empty() ? GURL() : GetVirtualURL(); } +void NavigationEntryImpl::SetSameDocumentNavigationEntryScreenshotToken( + const std::optional<blink::SameDocNavigationScreenshotDestinationToken>& + token) { + viz::HostFrameSinkManager* manager = GetHostFrameSinkManager(); + CHECK(manager); + if (same_document_navigation_entry_screenshot_token_.has_value()) { + manager->InvalidateCopyOutputReadyCallback( + same_document_navigation_entry_screenshot_token_.value()); + } + same_document_navigation_entry_screenshot_token_ = token; +} + } // namespace content
diff --git a/content/browser/renderer_host/navigation_entry_impl.h b/content/browser/renderer_host/navigation_entry_impl.h index 81ce14a..62ac9ba 100644 --- a/content/browser/renderer_host/navigation_entry_impl.h +++ b/content/browser/renderer_host/navigation_entry_impl.h
@@ -509,6 +509,15 @@ return initial_navigation_entry_state_; } + void SetSameDocumentNavigationEntryScreenshotToken( + const std::optional<blink::SameDocNavigationScreenshotDestinationToken>& + token); + + const std::optional<blink::SameDocNavigationScreenshotDestinationToken>& + same_document_navigation_entry_screenshot_token() const { + return same_document_navigation_entry_screenshot_token_; + } + private: std::unique_ptr<NavigationEntryImpl> CloneAndReplaceInternal( scoped_refptr<FrameNavigationEntry> frame_entry, @@ -647,6 +656,14 @@ // See comment for the enum for explanation. InitialNavigationEntryState initial_navigation_entry_state_ = InitialNavigationEntryState::kNonInitial; + + // Used to map a screenshot for the last frame of this navigation entry + // captured in Viz and sent back to the browser process. The token is set when + // `DidCommitSameDocumentNavigation` is received in the browser process from + // the renderer; and reset when its corresponding screenshot is received by + // the browser process from Viz. + std::optional<blink::SameDocNavigationScreenshotDestinationToken> + same_document_navigation_entry_screenshot_token_; }; } // namespace content
diff --git a/content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot_browsertest.cc b/content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot_browsertest.cc index c1a77d7..f4bba8b 100644 --- a/content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot_browsertest.cc +++ b/content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot_browsertest.cc
@@ -11,7 +11,9 @@ #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" #include "cc/test/pixel_test_utils.h" +#include "components/viz/host/host_frame_sink_manager.h" #include "content/browser/browser_context_impl.h" +#include "content/browser/compositor/surface_utils.h" #include "content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot_cache.h" #include "content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot_manager.h" #include "content/browser/renderer_host/navigation_transitions/navigation_transition_utils.h" @@ -33,11 +35,13 @@ #include "content/shell/browser/shell_content_browser_client.h" #include "content/test/content_browser_test_utils_internal.h" #include "content/test/render_document_feature.h" +#include "mojo/public/cpp/bindings/sync_call_restrictions.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/default_handlers.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/android/view_android.h" #include "url/url_constants.h" namespace content { @@ -63,14 +67,20 @@ // that its surface can be copied. void NavigateTabAndWaitForScreenshotCached(WebContents* tab, NavigationControllerImpl& controller, - const GURL& destination) { + const GURL& destination, + bool same_doc_nav = false) { const int num_request_before_nav = NavigationTransitionUtils::GetNumCopyOutputRequestIssuedForTesting(); const int entries_count_before_nav = controller.GetEntryCount(); ScopedScreenshotCapturedObserverForTesting observer( controller.GetLastCommittedEntryIndex()); ASSERT_TRUE(NavigateToURL(tab, destination)); - WaitForCopyableViewInWebContents(tab); + // We don't need to wait for the same-doc navigations. When the browser + // receives the screenshot for same-doc navigations, the renderer must have + // submitted a new frame. Using the observer on screenshot capture is enough. + if (!same_doc_nav) { + WaitForCopyableViewInWebContents(tab); + } observer.Wait(); ASSERT_EQ(controller.GetEntryCount(), entries_count_before_nav + 1); ASSERT_EQ( @@ -83,14 +93,17 @@ void HistoryNavigateTabAndWaitForScreenshotCached( WebContents* tab, NavigationControllerImpl& controller, - int offset) { + int offset, + bool same_doc_nav = false) { const int num_request_before_nav = NavigationTransitionUtils::GetNumCopyOutputRequestIssuedForTesting(); const int entries_count_before_nav = controller.GetEntryCount(); ScopedScreenshotCapturedObserverForTesting observer( controller.GetLastCommittedEntryIndex()); ASSERT_TRUE(HistoryGoToOffset(tab, offset)); - WaitForCopyableViewInWebContents(tab); + if (!same_doc_nav) { + WaitForCopyableViewInWebContents(tab); + } observer.Wait(); ASSERT_EQ(controller.GetEntryCount(), entries_count_before_nav); ASSERT_EQ( @@ -171,13 +184,10 @@ } // namespace -class NavigationEntryScreenshotBrowserTest - : public ContentBrowserTest, - public ::testing::WithParamInterface< - ScreenshotCaptureTestNavigationType> { +class NavigationEntryScreenshotBrowserTestBase : public ContentBrowserTest { public: - NavigationEntryScreenshotBrowserTest() = default; - ~NavigationEntryScreenshotBrowserTest() override = default; + NavigationEntryScreenshotBrowserTestBase() = default; + ~NavigationEntryScreenshotBrowserTestBase() override = default; void SetUp() override { NavigationTransitionUtils::ResetNumCopyOutputRequestIssuedForTesting(); @@ -189,6 +199,118 @@ ContentBrowserTest::TearDown(); } + void SetUpOnMainThread() override { + ContentBrowserTest::SetUpOnMainThread(); + + ASSERT_TRUE( + base::FeatureList::IsEnabled(blink::features::kBackForwardTransitions)); + + host_resolver()->AddRule("*", "127.0.0.1"); + embedded_test_server()->ServeFilesFromSourceDirectory( + GetTestDataFilePath()); + net::test_server::RegisterDefaultHandlers(embedded_test_server()); + SetupCrossSiteRedirector(embedded_test_server()); + + ASSERT_TRUE(embedded_test_server()->Start()); + } + + static void ExpectBitmapRowsAreColor( + const SkBitmap& bitmap, + SkColor color, + std::optional<gfx::Rect> compare_region = std::nullopt) { + int num_pixel_mismatch = 0; + gfx::Rect err_bounding_box; + + int row_start = 0; + int row_end = bitmap.height(); + int col_start = 0; + int col_end = bitmap.width(); + + if (compare_region.has_value()) { + row_start = compare_region->y(); + row_end = compare_region->bottom(); + col_start = compare_region->x(); + col_end = compare_region->right(); + } + + for (int r = row_start; r < row_end; ++r) { + for (int c = col_start; c < col_end; ++c) { + if (bitmap.getColor(c, r) != color) { + ++num_pixel_mismatch; + err_bounding_box.Union(gfx::Rect(c, r, 1, 1)); + } + } + } + if (num_pixel_mismatch != 0) { + EXPECT_TRUE(false) + << "Number of pixel mismatches: " << num_pixel_mismatch + << "; error bounding box: " << err_bounding_box.ToString() + << "; bitmap size: " + << gfx::Size(bitmap.width(), bitmap.height()).ToString() + << "; expect color " << std::format("{:x}", color) + << "; actual bitmap " << cc::GetPNGDataUrl(bitmap); + } + } + + void ExpectScreenshotIsColor( + NavigationEntryScreenshot* screenshot, + SkColor color, + std::optional<gfx::Rect> compare_region = std::nullopt) { + EXPECT_NE(screenshot, nullptr); + EXPECT_EQ(screenshot->GetDimensions(), GetScaledViewportSize()); + + auto bitmap = screenshot->GetBitmapForTesting(); + ExpectBitmapRowsAreColor(bitmap, color, compare_region); + } + + void AssertOrderedScreenshotsAre( + NavigationControllerImpl& controller, + const std::vector<std::optional<SkColor>>& expected_screenshots, + std::optional<gfx::Rect> compare_region = std::nullopt) { + ASSERT_EQ(controller.GetEntryCount(), + static_cast<int>(expected_screenshots.size())); + for (int index = 0; index < controller.GetEntryCount(); ++index) { + auto* entry = controller.GetEntryAtIndex(index); + if (expected_screenshots[index].has_value()) { + auto* screenshot = PreviewScreenshotForEntry(entry); + ExpectScreenshotIsColor(screenshot, expected_screenshots[index].value(), + compare_region); + } else { + EXPECT_EQ(PreviewScreenshotForEntry(entry), nullptr); + } + } + } + + gfx::Size GetScaledViewportSize() { + // Scale down the size to avoid memory pressure causing cache purging. + return ScaleToRoundedSize( + web_contents()->GetNativeView()->GetPhysicalBackingSize(), + /*scale=*/0.1); + } + + size_t GetScaledViewportSizeInBytes() { + // 4 bytes per pixel. + return 4 * GetScaledViewportSize().Area64(); + } + + NavigationEntryScreenshotManager* GetManagerForTab(WebContents* tab) { + return BrowserContextImpl::From(tab->GetBrowserContext()) + ->GetNavigationEntryScreenshotManager(); + } + + WebContentsImpl* web_contents() { + return static_cast<WebContentsImpl*>(shell()->web_contents()); + } +}; + +class NavigationEntryScreenshotBrowserTest + : public NavigationEntryScreenshotBrowserTestBase, + public ::testing::WithParamInterface< + ScreenshotCaptureTestNavigationType> { + public: + NavigationEntryScreenshotBrowserTest() = default; + ~NavigationEntryScreenshotBrowserTest() override = default; + void SetUpCommandLine(base::CommandLine* command_line) override { std::vector<base::test::FeatureRefAndParams> enabled_features = { {blink::features::kBackForwardTransitions, {}}}; @@ -211,22 +333,11 @@ InitAndEnableRenderDocumentFeature(&scoped_feature_list_render_document_, RenderDocumentFeatureFullyEnabled()[0]); - ContentBrowserTest::SetUpCommandLine(command_line); + NavigationEntryScreenshotBrowserTestBase::SetUpCommandLine(command_line); } void SetUpOnMainThread() override { - ContentBrowserTest::SetUpOnMainThread(); - - ASSERT_TRUE( - base::FeatureList::IsEnabled(blink::features::kBackForwardTransitions)); - - host_resolver()->AddRule("*", "127.0.0.1"); - embedded_test_server()->ServeFilesFromSourceDirectory( - GetTestDataFilePath()); - net::test_server::RegisterDefaultHandlers(embedded_test_server()); - SetupCrossSiteRedirector(embedded_test_server()); - - ASSERT_TRUE(embedded_test_server()->Start()); + NavigationEntryScreenshotBrowserTestBase::SetUpOnMainThread(); // The default WebContents has only the initial navigation entry. This // WebContents does not have a RWHV associated with it, making @@ -259,77 +370,6 @@ GetScaledViewportSize()); } - static void ExpectBitmapRowsAreColor(const SkBitmap& bitmap, - int row_start, - int row_end_exclusive, - SkColor color) { - int num_pixel_mismatch = 0; - gfx::Rect err_bounding_box; - for (int r = row_start; r < row_end_exclusive; ++r) { - for (int c = 0; c < bitmap.width(); ++c) { - if (bitmap.getColor(c, r) != color) { - ++num_pixel_mismatch; - err_bounding_box.Union(gfx::Rect(c, r, 1, 1)); - } - } - } - if (num_pixel_mismatch != 0) { - EXPECT_TRUE(false) - << "Number of pixel mismatches: " << num_pixel_mismatch - << "; error bounding box: " << err_bounding_box.ToString() - << "; bitmap size: " - << gfx::Size(bitmap.width(), bitmap.height()).ToString(); - } - } - - void ExpectScreenshotIsColor(NavigationEntryScreenshot* screenshot, - SkColor color) { - EXPECT_NE(screenshot, nullptr); - EXPECT_EQ(screenshot->GetDimensions(), GetScaledViewportSize()); - - auto bitmap = screenshot->GetBitmapForTesting(); - ExpectBitmapRowsAreColor(bitmap, /*row_start=*/0, - /*row_end_exclusive=*/bitmap.height(), color); - } - - void AssertOrderedScreenshotsAre( - NavigationControllerImpl& controller, - const std::vector<std::optional<SkColor>>& expected_screenshots) { - ASSERT_EQ(controller.GetEntryCount(), - static_cast<int>(expected_screenshots.size())); - for (int index = 0; index < controller.GetEntryCount(); ++index) { - auto* entry = controller.GetEntryAtIndex(index); - if (expected_screenshots[index].has_value()) { - auto* screenshot = PreviewScreenshotForEntry(entry); - ExpectScreenshotIsColor(screenshot, - expected_screenshots[index].value()); - } else { - EXPECT_EQ(PreviewScreenshotForEntry(entry), nullptr); - } - } - } - - gfx::Size GetScaledViewportSize() { - // Scale down the size to avoid memory pressure causing cache purging. - return ScaleToRoundedSize( - web_contents()->GetRenderWidgetHostView()->GetVisibleViewportSize(), - /*scale=*/0.1); - } - - size_t GetScaledViewportSizeInBytes() { - // 4 bytes per pixel. - return 4 * GetScaledViewportSize().Area64(); - } - - NavigationEntryScreenshotManager* GetManagerForTab(WebContents* tab) { - return BrowserContextImpl::From(tab->GetBrowserContext()) - ->GetNavigationEntryScreenshotManager(); - } - - WebContentsImpl* web_contents() { - return static_cast<WebContentsImpl*>(shell()->web_contents()); - } - std::string GetNextHost() { return host_getter_->Get(); } GURL GetNextUrl(std::string_view path) { @@ -978,22 +1018,24 @@ // Expect the embedder's color matches. NavigationEntryScreenshotBrowserTest::ExpectBitmapRowsAreColor( - bitmap, /*row_start=*/0, /*row_end_exclusive=*/half_height, embedder); + bitmap, embedder, gfx::Rect(0, 0, bitmap.width(), half_height)); // Expect the iframe's color matches. Skip checking the middle row if the // height is an odd number. int iframe_height_start = is_height_odd ? half_height + 1 : half_height; NavigationEntryScreenshotBrowserTest::ExpectBitmapRowsAreColor( - bitmap, /*row_start=*/iframe_height_start, - /*row_end_exclusive=*/bitmap.height(), iframe); + bitmap, iframe, + gfx::Rect(0, iframe_height_start, bitmap.width(), half_height)); } } // namespace // Asserts that no screenshots captured for the navigations of iframes. // // TODO(crbug.com/40896219): Support iframe navigations. +// +// TODO(crbug.com/340929354): Reenable the test. IN_PROC_BROWSER_TEST_P(NavigationEntryScreenshotBrowserTest, - SameOriginIFrame_NotCaptured) { + DISABLED_SameOriginIFrame_NotCaptured) { const size_t page_size = GetScaledViewportSizeInBytes(); const size_t memory_budget = 10 * page_size; auto* manager = GetManagerForTab(web_contents()); @@ -1134,4 +1176,127 @@ .enable_bfcache = false}}), &DescribeNavType); +namespace { + +void NavigateTabAndWaitForScreenshotCachedSameDoc( + WebContents* tab, + NavigationControllerImpl& controller, + const GURL& destination) { + NavigateTabAndWaitForScreenshotCached(tab, controller, destination, true); +} + +void HistoryNavigateTabAndWaitForScreenshotCachedSameDoc( + WebContents* tab, + NavigationControllerImpl& controller, + int offset) { + HistoryNavigateTabAndWaitForScreenshotCached(tab, controller, offset, true); +} + +} // namespace + +class SameDocNavigationEntryScreenshotBrowserTest + : public NavigationEntryScreenshotBrowserTestBase { + public: + SameDocNavigationEntryScreenshotBrowserTest() = default; + ~SameDocNavigationEntryScreenshotBrowserTest() override = default; + + void SetUp() override { + if (base::SysInfo::GetAndroidHardwareEGL() == "emulation") { + // crbug.com/337886037 and crrev.com/c/5504854/comment/b81b8fb6_95fb1381/: + // The CopyOutputRequests crash the GPU process. ANGLE is exporting the + // native fence support on Android emulators but it doesn't work properly. + GTEST_SKIP(); + } + NavigationEntryScreenshotBrowserTestBase::SetUp(); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + std::vector<base::test::FeatureRefAndParams> enabled_features = { + {blink::features::kBackForwardTransitions, {}}, + {blink::features::kIncrementLocalSurfaceIdForMainframeSameDocNavigation, + {}}}; + + scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features, {}); + + // Disable the vertical scroll bar, otherwise they might show up on the + // screenshot, making the test flaky. + command_line->AppendSwitch(switches::kHideScrollbars); + NavigationEntryScreenshotBrowserTestBase::SetUpCommandLine(command_line); + } + + void SetUpOnMainThread() override { + NavigationEntryScreenshotBrowserTestBase::SetUpOnMainThread(); + + ASSERT_TRUE(NavigateToURL(web_contents(), embedded_test_server()->GetURL( + "/changing_color.html"))); + WaitForCopyableViewInWebContents(web_contents()); + + mojo::ScopedAllowSyncCallForTesting allowed_for_testing; + GetHostFrameSinkManager()->SetSameDocNavigationScreenshotSizeForTesting( + GetScaledViewportSize()); + } + + gfx::Rect GetCompareRegion() { return gfx::Rect(GetScaledViewportSize()); } + + GURL GetURL(const std::string& hash) { + return embedded_test_server()->GetURL("/changing_color.html" + hash); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(SameDocNavigationEntryScreenshotBrowserTest, Basic) { + const size_t page_size = GetScaledViewportSizeInBytes(); + const size_t memory_budget = 10 * page_size; + auto* manager = GetManagerForTab(web_contents()); + manager->SetMemoryBudgetForTesting(memory_budget); + auto& controller = web_contents()->GetController(); + + { + SCOPED_TRACE("[red*] -> [red&, green*]"); + NavigateTabAndWaitForScreenshotCachedSameDoc(web_contents(), controller, + GetURL("#green")); + AssertOrderedScreenshotsAre(controller, {SK_ColorRED, std::nullopt}, + GetCompareRegion()); + ASSERT_EQ(manager->GetCurrentCacheSize(), 1 * page_size); + } + { + SCOPED_TRACE("[red&, green*] -> [red&, green&, blue*]"); + NavigateTabAndWaitForScreenshotCachedSameDoc(web_contents(), controller, + GetURL("#blue")); + AssertOrderedScreenshotsAre(controller, + {SK_ColorRED, SK_ColorGREEN, std::nullopt}, + GetCompareRegion()); + ASSERT_EQ(manager->GetCurrentCacheSize(), 2 * page_size); + } + { + SCOPED_TRACE("[red&, green&, blue*] -> [red&, green&, blue&, red*]"); + NavigateTabAndWaitForScreenshotCachedSameDoc(web_contents(), controller, + GetURL("#red")); + AssertOrderedScreenshotsAre( + controller, {SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, std::nullopt}, + GetCompareRegion()); + ASSERT_EQ(manager->GetCurrentCacheSize(), 3 * page_size); + } + { + SCOPED_TRACE("[red&, green&, blue&, red*] -> [red&, green&, blue*, red&]"); + HistoryNavigateTabAndWaitForScreenshotCachedSameDoc(web_contents(), + controller, -1); + AssertOrderedScreenshotsAre( + controller, {SK_ColorRED, SK_ColorGREEN, std::nullopt, SK_ColorRED}, + GetCompareRegion()); + ASSERT_EQ(manager->GetCurrentCacheSize(), 3 * page_size); + } + { + SCOPED_TRACE("[red&, green&, blue*, red&] -> [red*, green&, blue&, red&]"); + HistoryNavigateTabAndWaitForScreenshotCachedSameDoc(web_contents(), + controller, -2); + AssertOrderedScreenshotsAre( + controller, {std::nullopt, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED}, + GetCompareRegion()); + ASSERT_EQ(manager->GetCurrentCacheSize(), 3 * page_size); + } +} + } // namespace content
diff --git a/content/browser/renderer_host/navigation_transitions/navigation_transition_utils.cc b/content/browser/renderer_host/navigation_transitions/navigation_transition_utils.cc index d2eb65d..928142a0 100644 --- a/content/browser/renderer_host/navigation_transitions/navigation_transition_utils.cc +++ b/content/browser/renderer_host/navigation_transitions/navigation_transition_utils.cc
@@ -4,6 +4,9 @@ #include "content/browser/renderer_host/navigation_transitions/navigation_transition_utils.h" +#include "components/viz/common/frame_sinks/copy_output_result.h" +#include "components/viz/host/host_frame_sink_manager.h" +#include "content/browser/compositor/surface_utils.h" #include "content/browser/renderer_host/frame_tree.h" #include "content/browser/renderer_host/frame_tree_node.h" #include "content/browser/renderer_host/navigation_request.h" @@ -55,30 +58,34 @@ GetTestScreenshotCallback().Run(index, test_copy, requested); } -void CacheScreenshotImpl(base::WeakPtr<NavigationControllerImpl> controller, - int navigation_entry_id, - const SkBitmap& bitmap) { - if (!controller) { - // The tab was destroyed by the time we receive the bitmap from the GPU. - return; +// Returns the first entry that matches `destination_token`. Returns null if no +// match is found. +NavigationEntryImpl* GetEntryForToken( + NavigationControllerImpl* controller, + const blink::SameDocNavigationScreenshotDestinationToken& + destination_token) { + for (int i = 0; i < controller->GetEntryCount(); ++i) { + if (auto* entry = controller->GetEntryAtIndex(i); + entry->same_document_navigation_entry_screenshot_token() == + destination_token) { + return entry; + } } + return nullptr; +} - NavigationEntryImpl* entry = - controller->GetEntryWithUniqueID(navigation_entry_id); - if (!entry) { - // The entry was deleted by the time we received the bitmap from the GPU. - // This can happen by clearing the session history, or when the - // `NavigationEntry` was replaced or deleted, etc. - return; - } +void CacheScreenshotImpl(NavigationControllerImpl& controller, + NavigationEntryImpl& entry, + const SkBitmap& bitmap) { + auto navigation_entry_id = entry.GetUniqueID(); if (GetTestScreenshotCallback()) { InvokeTestCallback( - controller->GetEntryIndexWithUniqueID(navigation_entry_id), bitmap, + controller.GetEntryIndexWithUniqueID(navigation_entry_id), bitmap, true); } - if (entry == controller->GetLastCommittedEntry()) { + if (&entry == controller.GetLastCommittedEntry()) { // TODO(crbug.com/40278616): We shouldn't cache the screenshot into // the navigation entry if the entry is re-navigated after we send out the // copy request. See the two cases below. @@ -100,7 +107,7 @@ if (bitmap.drawsNothing()) { // The GPU is not able to produce a valid bitmap. This is an error case. LOG(ERROR) << "Cannot generate a valid bitmap for entry " - << entry->GetUniqueID() << " url " << entry->GetURL(); + << entry.GetUniqueID() << " url " << entry.GetURL(); return; } @@ -108,23 +115,29 @@ immutable_copy.setImmutable(); auto screenshot = std::make_unique<NavigationEntryScreenshot>( - immutable_copy, entry->GetUniqueID()); + immutable_copy, entry.GetUniqueID()); NavigationEntryScreenshotCache* cache = - controller->GetNavigationEntryScreenshotCache(); - cache->SetScreenshot(entry, std::move(screenshot)); + controller.GetNavigationEntryScreenshotCache(); + cache->SetScreenshot(&entry, std::move(screenshot)); } -void CacheScreenshot(base::WeakPtr<NavigationControllerImpl> controller, - int navigation_entry_id, - const SkBitmap& bitmap) { - // `CacheScreenshot`, as the callback for `CopyFromExactSurface`, is not - // guaranteed to be executed on the same thread that it was submitted from - // (browser's UI thread). Since `NavigationEntryScreenshotCache` can only be - // accessed from the browser's UI thread, we explicitly post the caching task - // onto the UI thread. See https://crbug.com/1217049 for more context. - GetUIThreadTaskRunner({base::TaskPriority::USER_VISIBLE}) - ->PostTask(FROM_HERE, base::BindOnce(&CacheScreenshotImpl, controller, - navigation_entry_id, bitmap)); +void CacheScreenshotForCrossDocNavigations( + base::WeakPtr<NavigationControllerImpl> controller, + int navigation_entry_id, + const SkBitmap& bitmap) { + if (!controller) { + // The tab was destroyed by the time we receive the bitmap from the GPU. + return; + } + NavigationEntryImpl* entry = + controller->GetEntryWithUniqueID(navigation_entry_id); + if (!entry) { + // The entry was deleted by the time we received the bitmap from the GPU. + // This can happen by clearing the session history, or when the + // `NavigationEntry` was replaced or deleted, etc. + return; + } + CacheScreenshotImpl(*controller, *entry, bitmap); } // We only want to capture screenshots for navigation entries reachable via @@ -203,21 +216,8 @@ // be loaded might have different contents than when the screenshot was taken in // a previous load. A new screenshot should be taken when navigating away from // this entry again. -void RemoveScreenshotFromDestination( - const NavigationRequest& navigation_request) { - NavigationEntry* destination_entry = navigation_request.GetNavigationEntry(); - - if (!destination_entry) { - // We don't always have a destination entry (e.g., a new (non-history) - // subframe navigation). However if this is a session history navigation, we - // most-likely have a destination entry to navigate toward, from which we - // need to purge any existing screenshot. - return; - } - - NavigationControllerImpl& nav_controller = - navigation_request.frame_tree_node()->navigator().controller(); - +void RemoveScreenshotFromDestination(NavigationControllerImpl& nav_controller, + NavigationEntry* destination_entry) { if (!nav_controller.frame_tree().is_primary()) { // Navigations in the non-primary FrameTree can still have a destination // entry (e.g., Prerender's initial document-fetch request will create a @@ -237,6 +237,34 @@ CHECK(successfully_removed); } } + +void CacheScreenshotForSameDocNavigations( + base::WeakPtr<NavigationControllerImpl> controller, + int navigation_entry_id, + const SkBitmap& bitmap) { + CHECK(AreBackForwardTransitionsEnabled()); + + if (!controller) { + // The tab was destroyed by the time we receive the bitmap from the GPU. + return; + } + + auto* destination_entry = + controller->GetEntryWithUniqueID(navigation_entry_id); + + if (!destination_entry) { + // The entry was deleted by the time we received the bitmap from the GPU. + // This can happen by clearing the session history, or when the + // `NavigationEntry` was replaced or deleted, etc. + return; + } + + CacheScreenshotImpl(*controller, *destination_entry, bitmap); + + destination_entry->SetSameDocumentNavigationEntryScreenshotToken( + std::nullopt); +} + } // namespace void NavigationTransitionUtils::SetCapturedScreenshotSizeForTesting( @@ -257,12 +285,15 @@ GetTestScreenshotCallback() = std::move(screenshot_callback); } -void NavigationTransitionUtils::CaptureNavigationEntryScreenshot( - const NavigationRequest& navigation_request) { +void NavigationTransitionUtils:: + CaptureNavigationEntryScreenshotForCrossDocumentNavigations( + const NavigationRequest& navigation_request) { if (!AreBackForwardTransitionsEnabled()) { return; } + CHECK(!navigation_request.IsSameDocument()); + // The current conditions for whether to capture a screenshot depend on // `NavigationRequest::GetRenderFrameHost()`, so for now we should only get // here after the `RenderFrameHost` has been selected for a successful @@ -274,11 +305,22 @@ // `is_same_rfh_or_early_commit`. CHECK(navigation_request.HasRenderFrameHost()); + auto* destination_entry = navigation_request.GetNavigationEntry(); + if (!destination_entry) { + // We don't always have a destination entry (e.g., a new (non-history) + // subframe navigation). However if this is a session history navigation, we + // most-likely have a destination entry to navigate toward, from which we + // need to purge any existing screenshot. + return; + } + // Remove the screenshot from the destination before checking the conditions. // We might not capture for this navigation due to some conditions, but the // navigation still continues (to commit/finish), for which we need to remove // the screenshot from the destination entry. - RemoveScreenshotFromDestination(navigation_request); + RemoveScreenshotFromDestination( + navigation_request.frame_tree_node()->frame_tree().controller(), + destination_entry); if (!CanTraverseToPreviousEntryAfterNavigation(navigation_request)) { if (GetTestScreenshotCallback()) { InvokeTestCallbackForNoScreenshot(navigation_request); @@ -307,7 +349,8 @@ bool copied_via_delegate = navigation_request.GetDelegate()->MaybeCopyContentAreaAsBitmap( base::BindOnce( - &CacheScreenshot, nav_controller.GetWeakPtr(), + &CacheScreenshotForCrossDocNavigations, + nav_controller.GetWeakPtr(), nav_controller.GetLastCommittedEntry()->GetUniqueID())); if (!copied_via_delegate && @@ -339,10 +382,63 @@ static_cast<RenderWidgetHostViewBase*>(rwhv)->CopyFromExactSurface( /*src_rect=*/gfx::Rect(), output_size, - base::BindOnce(&CacheScreenshot, nav_controller.GetWeakPtr(), + base::BindOnce(&CacheScreenshotForCrossDocNavigations, + nav_controller.GetWeakPtr(), nav_controller.GetLastCommittedEntry()->GetUniqueID())); ++g_num_copy_requests_issued_for_testing; } +void NavigationTransitionUtils::SetSameDocumentNavigationEntryScreenshotToken( + const NavigationRequest& navigation_request, + const blink::SameDocNavigationScreenshotDestinationToken& + destination_token) { + if (!AreBackForwardTransitionsEnabled()) { + // The source of this call is from the renderer. We can't always trust the + // renderer thus fail safely. + return; + } + NavigationControllerImpl& nav_controller = + navigation_request.frame_tree_node()->navigator().controller(); + if (GetEntryForToken(&nav_controller, destination_token)) { + // Again, can't always trust the renderer to send a non-duplicated token. + return; + } + + CHECK(navigation_request.IsSameDocument()); + + if (auto* destination_entry = navigation_request.GetNavigationEntry()) { + RemoveScreenshotFromDestination(nav_controller, destination_entry); + } else { + // All renderer-initiated same-document navigations will not have a + // destination entry (see + // `NavigationRequest::CreateForSynchronousRendererCommit`). + } + + if (!CanTraverseToPreviousEntryAfterNavigation(navigation_request)) { + return; + } + + // NOTE: `destination_token` is to set on the last committed entry (the + // screenshot's destination), instead of the destination entry of this + // `navigation_request` (`navigation_request.GetNavigationEntry()`). + + // We won't reach here if the renderer hasn't requested a CopyOutputRequest, + // since the token in the DidCommitSameDocNavigation message will be nullopt. + ++g_num_copy_requests_issued_for_testing; + + // `blink::SameDocNavigationScreenshotDestinationToken` is guaranteed + // non-empty. + nav_controller.GetLastCommittedEntry() + ->SetSameDocumentNavigationEntryScreenshotToken(destination_token); + + CHECK(GetHostFrameSinkManager()); + + GetHostFrameSinkManager()->SetOnCopyOutputReadyCallback( + destination_token, + base::BindOnce(&CacheScreenshotForSameDocNavigations, + nav_controller.GetWeakPtr(), + nav_controller.GetLastCommittedEntry()->GetUniqueID())); +} + } // namespace content
diff --git a/content/browser/renderer_host/navigation_transitions/navigation_transition_utils.h b/content/browser/renderer_host/navigation_transitions/navigation_transition_utils.h index d0db9c9..4143c11 100644 --- a/content/browser/renderer_host/navigation_transitions/navigation_transition_utils.h +++ b/content/browser/renderer_host/navigation_transitions/navigation_transition_utils.h
@@ -7,6 +7,7 @@ #include "base/functional/callback.h" #include "content/common/content_export.h" +#include "third_party/blink/public/common/tokens/tokens.h" #include "third_party/skia/include/core/SkBitmap.h" namespace gfx { @@ -25,9 +26,18 @@ // Capture the `NavigationEntryScreenshot` for the old page, and store the // screenshot in the old page's NavigationEntry. // Should only be called immediately before the old page is unloaded. - static void CaptureNavigationEntryScreenshot( + static void CaptureNavigationEntryScreenshotForCrossDocumentNavigations( const NavigationRequest& navigation_request); + // Called when `DidCommitSameDocumentNavigation` arrives at the browser, and + // *before* the navigation commits. Ensures that a `NavigationEntryScreenshot` + // for the pre-navigation DOM state is cached when provided by the Viz + // process. + static void SetSameDocumentNavigationEntryScreenshotToken( + const NavigationRequest& navigation_request, + const blink::SameDocNavigationScreenshotDestinationToken& + destination_token); + // Used by tests to deterministically validate the memory budgeting / eviction // logic. CONTENT_EXPORT static void SetCapturedScreenshotSizeForTesting( @@ -40,8 +50,8 @@ CONTENT_EXPORT static void ResetNumCopyOutputRequestIssuedForTesting(); // Calls `screenshot_callback` with the index of the previous NavigationEntry - // when leaving a page, along with the generated bitmap captured by the - // CaptureNavigationEntryScreenshot function. + // when leaving a page, along with the generated bitmap captured captured for + // all navigations. CONTENT_EXPORT static void SetNavScreenshotCallbackForTesting( ScreenshotCallback screenshot_callback); };
diff --git a/content/browser/renderer_host/navigator.cc b/content/browser/renderer_host/navigator.cc index 8feb01b..5c1702ff 100644 --- a/content/browser/renderer_host/navigator.cc +++ b/content/browser/renderer_host/navigator.cc
@@ -505,8 +505,11 @@ // TODO(crbug.com/40278956): Move this into // `RenderFrameHostManager::CommitPending` to accommodate both regular // navigations and early-commit. - NavigationTransitionUtils::CaptureNavigationEntryScreenshot( - *navigation_request); + if (!was_within_same_document) { + NavigationTransitionUtils:: + CaptureNavigationEntryScreenshotForCrossDocumentNavigations( + *navigation_request); + } if (ui::PageTransitionIsMainFrame(params.transition)) { // Run tasks that must execute just before the commit.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 4413fdd..325edea 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -126,6 +126,7 @@ #include "content/browser/renderer_host/navigation_metrics_utils.h" #include "content/browser/renderer_host/navigation_request.h" #include "content/browser/renderer_host/navigation_state_keep_alive.h" +#include "content/browser/renderer_host/navigation_transitions/navigation_transition_utils.h" #include "content/browser/renderer_host/navigator.h" #include "content/browser/renderer_host/page_delegate.h" #include "content/browser/renderer_host/private_network_access_util.h" @@ -13967,6 +13968,14 @@ ukm::SourceIdType::NAVIGATION_ID)); } + if (is_same_document_navigation && + same_document_params->navigation_entry_screenshot_destination + .has_value()) { + NavigationTransitionUtils::SetSameDocumentNavigationEntryScreenshotToken( + *(navigation_request.get()), + same_document_params->navigation_entry_screenshot_destination.value()); + } + // TODO(crbug.com/40150370): Do not pass |params| to DidNavigate(). NavigationRequest* raw_navigation_request = navigation_request.get(); raw_navigation_request->frame_tree_node()->navigator().DidNavigate(
diff --git a/content/browser/resources/attribution_reporting/attribution_internals_table.ts b/content/browser/resources/attribution_reporting/attribution_internals_table.ts index 429a911f..3836d40 100644 --- a/content/browser/resources/attribution_reporting/attribution_internals_table.ts +++ b/content/browser/resources/attribution_reporting/attribution_internals_table.ts
@@ -170,9 +170,22 @@ this.clearRows(); } - if (this.getId_) { - this.updateRows([data]); - return; + let tr: DataRowElement<T>|undefined; + + const id = this.getId_ ? this.getId_(data, /*updated=*/ true) : undefined; + if (id !== undefined) { + tr = Array.prototype.find.call( + this.dataRows_(), + tr => id === this.getId_!(tr.data, /*updated=*/ false)); + + if (tr !== undefined) { + tr.data = data; + this.cols_!.forEach((render, idx) => render(tr!.cells[idx]!, data)); + } + } + + if (tr === undefined) { + tr = this.newRow_(data); } let nextTr: DataRowElement<T>|undefined; @@ -182,7 +195,6 @@ this.dataRows_(), tr => this.compare_!(tr.data, data) > 0); } - const tr = this.newRow_(data); if (nextTr) { nextTr.before(tr); } else {
diff --git a/content/browser/webid/fedcm_metrics.h b/content/browser/webid/fedcm_metrics.h index c7957d4..ee54133 100644 --- a/content/browser/webid/fedcm_metrics.h +++ b/content/browser/webid/fedcm_metrics.h
@@ -23,70 +23,74 @@ using RpMode = blink::mojom::RpMode; // This enum describes the status of a request id token call to the FedCM API. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. enum class FedCmRequestIdTokenStatus { // Don't change the meaning or the order of these values because they are // being recorded in metrics and in sync with the counterpart in enums.xml. - kSuccessUsingTokenInHttpResponse, - kTooManyRequests, - kAborted, - kUnhandledRequest, - kIdpNotPotentiallyTrustworthy, - kNotSelectAccount, - kConfigHttpNotFound, - kConfigNoResponse, - kConfigInvalidResponse, - kClientMetadataHttpNotFound, // obsolete - kClientMetadataNoResponse, // obsolete - kClientMetadataInvalidResponse, // obsolete - kAccountsHttpNotFound, - kAccountsNoResponse, - kAccountsInvalidResponse, - kIdTokenHttpNotFound, - kIdTokenNoResponse, - kIdTokenInvalidResponse, - kIdTokenInvalidRequest, // obsolete - kClientMetadataMissingPrivacyPolicyUrl, // obsolete - kThirdPartyCookiesBlocked, // obsolete - kDisabledInSettings, - kDisabledInFlags, - kWellKnownHttpNotFound, - kWellKnownNoResponse, - kWellKnownInvalidResponse, - kConfigNotInWellKnown, - kWellKnownTooBig, - kDisabledEmbargo, - kUserInterfaceTimedOut, // obsolete - kRpPageNotVisible, - kShouldEmbargo, - kNotSignedInWithIdp, - kAccountsListEmpty, - kWellKnownListEmpty, - kWellKnownInvalidContentType, - kConfigInvalidContentType, - kAccountsInvalidContentType, - kIdTokenInvalidContentType, - kSilentMediationFailure, - kIdTokenIdpErrorResponse, - kIdTokenCrossSiteIdpErrorResponse, - kOtherIdpChosen, - kMissingTransientUserActivation, - kReplacedByButtonMode, - kContinuationPopupClosedByUser, - kSuccessUsingIdentityProviderResolve, - kContinuationPopupClosedByIdentityProviderClose, - kInvalidFieldsSpecified, + kSuccessUsingTokenInHttpResponse = 0, + kTooManyRequests = 1, + kAborted = 2, + kUnhandledRequest = 3, + kIdpNotPotentiallyTrustworthy = 4, + kNotSelectAccount = 5, + kConfigHttpNotFound = 6, + kConfigNoResponse = 7, + kConfigInvalidResponse = 8, + kClientMetadataHttpNotFound = 9, // obsolete + kClientMetadataNoResponse = 10, // obsolete + kClientMetadataInvalidResponse = 11, // obsolete + kAccountsHttpNotFound = 12, + kAccountsNoResponse = 13, + kAccountsInvalidResponse = 14, + kIdTokenHttpNotFound = 15, + kIdTokenNoResponse = 16, + kIdTokenInvalidResponse = 17, + kIdTokenInvalidRequest = 18, // obsolete + kClientMetadataMissingPrivacyPolicyUrl = 19, // obsolete + kThirdPartyCookiesBlocked = 20, // obsolete + kDisabledInSettings = 21, + kDisabledInFlags = 22, + kWellKnownHttpNotFound = 23, + kWellKnownNoResponse = 24, + kWellKnownInvalidResponse = 25, + kConfigNotInWellKnown = 26, + kWellKnownTooBig = 27, + kDisabledEmbargo = 28, + kUserInterfaceTimedOut = 29, // obsolete + kRpPageNotVisible = 30, + kShouldEmbargo = 31, + kNotSignedInWithIdp = 32, + kAccountsListEmpty = 33, + kWellKnownListEmpty = 34, + kWellKnownInvalidContentType = 35, + kConfigInvalidContentType = 36, + kAccountsInvalidContentType = 37, + kIdTokenInvalidContentType = 38, + kSilentMediationFailure = 39, + kIdTokenIdpErrorResponse = 40, + kIdTokenCrossSiteIdpErrorResponse = 41, + kOtherIdpChosen = 42, + kMissingTransientUserActivation = 43, + kReplacedByButtonMode = 44, + kContinuationPopupClosedByUser = 45, + kSuccessUsingIdentityProviderResolve = 46, + kContinuationPopupClosedByIdentityProviderClose = 47, + kInvalidFieldsSpecified = 48, kMaxValue = kInvalidFieldsSpecified }; // This enum describes whether user sign-in states between IDP and browser // match. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. enum class FedCmSignInStateMatchStatus { // Don't change the meaning or the order of these values because they are // being recorded in metrics and in sync with the counterpart in enums.xml. - kMatch, - kIdpClaimedSignIn, - kBrowserObservedSignIn, + kMatch = 0, + kIdpClaimedSignIn = 1, + kBrowserObservedSignIn = 2, kMaxValue = kBrowserObservedSignIn }; @@ -94,56 +98,62 @@ // This enum describes whether the browser's knowledge of whether the user is // signed into the IDP based on observing signin/signout HTTP headers matches // the information returned by the accounts endpoint. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. enum class FedCmIdpSigninMatchStatus { // Don't change the meaning or the order of these values because they are // being recorded in metrics and in sync with the counterpart in enums.xml. - kMatchWithAccounts, - kMatchWithoutAccounts, - kUnknownStatusWithAccounts, - kUnknownStatusWithoutAccounts, - kMismatchWithNetworkError, - kMismatchWithNoContent, - kMismatchWithInvalidResponse, - kMismatchWithUnexpectedAccounts, + kMatchWithAccounts = 0, + kMatchWithoutAccounts = 1, + kUnknownStatusWithAccounts = 2, + kUnknownStatusWithoutAccounts = 3, + kMismatchWithNetworkError = 4, + kMismatchWithNoContent = 5, + kMismatchWithInvalidResponse = 6, + kMismatchWithUnexpectedAccounts = 7, kMaxValue = kMismatchWithUnexpectedAccounts }; // This enum describes the type of frame that invokes a FedCM API. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. enum class FedCmRequesterFrameType { // Do not change the meaning or order of these values since they are being // recorded in metrics and in sync with the counterpart in enums.xml. - kMainFrame, - kSameSiteIframe, - kCrossSiteIframe, + kMainFrame = 0, + kSameSiteIframe = 1, + kCrossSiteIframe = 2, kMaxValue = kCrossSiteIframe }; // This enum describes the status of a disconnect call to the FedCM API. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. enum class FedCmDisconnectStatus { // Don't change the meaning or the order of these values because they are // being recorded in metrics and in sync with the counterpart in enums.xml. - kSuccess, - kTooManyRequests, - kUnhandledRequest, - kNoAccountToDisconnect, - kDisconnectUrlIsCrossOrigin, - kDisconnectFailedOnServer, - kConfigHttpNotFound, - kConfigNoResponse, - kConfigInvalidResponse, - kDisabledInSettings, - kDisabledInFlags, - kWellKnownHttpNotFound, - kWellKnownNoResponse, - kWellKnownInvalidResponse, - kWellKnownListEmpty, - kConfigNotInWellKnown, - kWellKnownTooBig, - kWellKnownInvalidContentType, - kConfigInvalidContentType, - kIdpNotPotentiallyTrustworthy, + kSuccess = 0, + kTooManyRequests = 1, + kUnhandledRequest = 2, + kNoAccountToDisconnect = 3, + kDisconnectUrlIsCrossOrigin = 4, + kDisconnectFailedOnServer = 5, + kConfigHttpNotFound = 6, + kConfigNoResponse = 7, + kConfigInvalidResponse = 8, + kDisabledInSettings = 9, + kDisabledInFlags = 10, + kWellKnownHttpNotFound = 11, + kWellKnownNoResponse = 12, + kWellKnownInvalidResponse = 13, + kWellKnownListEmpty = 14, + kConfigNotInWellKnown = 15, + kWellKnownTooBig = 16, + kWellKnownInvalidContentType = 17, + kConfigInvalidContentType = 18, + kIdpNotPotentiallyTrustworthy = 19, kMaxValue = kIdpNotPotentiallyTrustworthy };
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index bd1d977..0ee2fc0 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -321,11 +321,6 @@ "java/src/org/chromium/content/browser/picker/TwoFieldDatePickerDialog.java", "java/src/org/chromium/content/browser/picker/WeekPicker.java", "java/src/org/chromium/content/browser/picker/WeekPickerDialog.java", - "java/src/org/chromium/content/browser/remoteobjects/RemoteObjectAuditorImpl.java", - "java/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImpl.java", - "java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java", - "java/src/org/chromium/content/browser/remoteobjects/RemoteObjectInjector.java", - "java/src/org/chromium/content/browser/remoteobjects/RemoteObjectRegistry.java", "java/src/org/chromium/content/browser/selection/LGEmailActionModeWorkaroundImpl.java", "java/src/org/chromium/content/browser/selection/MagnifierAnimator.java", "java/src/org/chromium/content/browser/selection/MagnifierSurfaceControl.java", @@ -662,7 +657,6 @@ "javatests/src/org/chromium/content/browser/input/StylusGestureEndToEndTest.java", "javatests/src/org/chromium/content/browser/input/TextSuggestionMenuTest.java", "javatests/src/org/chromium/content/browser/picker/DateTimePickerDialogTest.java", - "javatests/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImplTest.java", "javatests/src/org/chromium/content/browser/scheduler/NativePostTaskTest.java", "javatests/src/org/chromium/content/browser/scheduler/UiThreadSchedulerTest.java", "javatests/src/org/chromium/content/browser/scheduler/UncaughtExceptionTest.java", @@ -701,8 +695,6 @@ "junit/src/org/chromium/content/browser/input/ThreadedInputConnectionFactoryTest.java", "junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java", "junit/src/org/chromium/content/browser/picker/DateDialogNormalizerTest.java", - "junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java", - "junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectRegistryTest.java", "junit/src/org/chromium/content/browser/selection/MagnifierAnimatorTest.java", "junit/src/org/chromium/content/browser/selection/SelectActionMenuHelperTest.java", "junit/src/org/chromium/content/browser/selection/SelectionMenuCachedResultTest.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/JavascriptInjectorImpl.java b/content/public/android/java/src/org/chromium/content/browser/JavascriptInjectorImpl.java index c1f1a2c4..0d0259a 100644 --- a/content/public/android/java/src/org/chromium/content/browser/JavascriptInjectorImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/JavascriptInjectorImpl.java
@@ -12,7 +12,6 @@ import org.chromium.base.UserData; import org.chromium.build.annotations.DoNotInline; -import org.chromium.content.browser.remoteobjects.RemoteObjectInjector; import org.chromium.content.browser.webcontents.WebContentsImpl; import org.chromium.content.browser.webcontents.WebContentsImpl.UserDataFactory; import org.chromium.content_public.browser.JavascriptInjector; @@ -37,21 +36,17 @@ @DoNotInline private final Set<Object> mRetainedObjects = new HashSet<>(); private final Map<String, Pair<Object, Class>> mInjectedObjects = new HashMap<>(); private long mNativePtr; - private RemoteObjectInjector mInjector; - private Boolean mUseMojo; /** * @param webContents {@link WebContents} object. - * @param useMojo Whether to use {@link RemoteObjectInjector} methods - * @return {@link JavascriptInjector} object used for the give WebContents. - * Creates one if not present. + * @return {@link JavascriptInjector} object used for the give WebContents. Creates one if not + * present. */ - public static JavascriptInjector fromWebContents(WebContents webContents, boolean useMojo) { + public static JavascriptInjector fromWebContents(WebContents webContents) { JavascriptInjectorImpl javascriptInjector = ((WebContentsImpl) webContents) .getOrSetUserData( JavascriptInjectorImpl.class, UserDataFactoryLazyHolder.INSTANCE); - javascriptInjector.setUseMojo(useMojo); return javascriptInjector; } @@ -59,16 +54,6 @@ mNativePtr = JavascriptInjectorImplJni.get() .init(JavascriptInjectorImpl.this, webContents, mRetainedObjects); - mInjector = new RemoteObjectInjector(webContents); - webContents.addObserver(mInjector); - } - - public void setUseMojo(boolean useMojo) { - if (mUseMojo == null) { - mUseMojo = useMojo; - } else { - assert mUseMojo == useMojo; - } } @CalledByNative @@ -83,10 +68,7 @@ @Override public void setAllowInspection(boolean allow) { - assert mUseMojo != null; - if (mUseMojo) { - mInjector.setAllowInspection(allow); - } else if (mNativePtr != 0) { + if (mNativePtr != 0) { JavascriptInjectorImplJni.get() .setAllowInspection(mNativePtr, JavascriptInjectorImpl.this, allow); } @@ -97,10 +79,7 @@ Object object, String name, Class<? extends Annotation> requiredAnnotation) { if (object == null) return; - assert mUseMojo != null; - if (mUseMojo) { - mInjector.addInterface(object, name, requiredAnnotation); - } else if (mNativePtr != 0) { + if (mNativePtr != 0) { mInjectedObjects.put(name, new Pair<Object, Class>(object, requiredAnnotation)); JavascriptInjectorImplJni.get() .addInterface( @@ -114,15 +93,10 @@ @Override public void removeInterface(String name) { - assert mUseMojo != null; - if (mUseMojo) { - mInjector.removeInterface(name); - } else { - mInjectedObjects.remove(name); - if (mNativePtr != 0) { - JavascriptInjectorImplJni.get() - .removeInterface(mNativePtr, JavascriptInjectorImpl.this, name); - } + mInjectedObjects.remove(name); + if (mNativePtr != 0) { + JavascriptInjectorImplJni.get() + .removeInterface(mNativePtr, JavascriptInjectorImpl.this, name); } }
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA deleted file mode 100644 index 12293d9..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA +++ /dev/null
@@ -1,7 +0,0 @@ -monorail: { - component: "Mobile>WebView" -} -team_email: "android-webview-dev@chromium.org" -buganizer_public: { - component_id: 1456456 -}
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/DIR_METADATA b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/DIR_METADATA deleted file mode 100644 index de0888c0..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/DIR_METADATA +++ /dev/null
@@ -1,2 +0,0 @@ -mixins: "//content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA" -
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/OWNERS b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/OWNERS deleted file mode 100644 index 56ec958..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -oksamyt@chromium.org
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/README.md b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/README.md deleted file mode 100644 index 7fcc77ff..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/README.md +++ /dev/null
@@ -1,9 +0,0 @@ -# Remote Objects - -This is an implementation of the Blink mojo interfaces which allow objects -hosted out of process to be exposed to script. It is intended to ultimately -migrate the Gin/Java bridge used to implement -[`addJavascriptInterface`](https://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface%28java.lang.Object,%20java.lang.String%29) -in Android WebView. - -See also the [design doc](https://docs.google.com/document/d/1T8Zj_gZK7jHsy80Etk-Rw4hXMIW4QeaTtXjy5ZKP3X0/edit).
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectAuditorImpl.java b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectAuditorImpl.java deleted file mode 100644 index 1c72e9b8b..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectAuditorImpl.java +++ /dev/null
@@ -1,21 +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. - -package org.chromium.content.browser.remoteobjects; - -import android.os.Process; -import android.util.EventLog; - -final class RemoteObjectAuditorImpl implements RemoteObjectImpl.Auditor { - /** - * Event which should be logged if getClass is invoked. - * See frameworks/base/core/java/android/webkit/EventLogTags.logtags. - */ - private static final int sObjectGetClassInvocationAttemptLogTag = 70151; - - @Override - public void onObjectGetClassInvocationAttempt() { - EventLog.writeEvent(sObjectGetClassInvocationAttemptLogTag, Process.myUid()); - } -}
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImpl.java b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImpl.java deleted file mode 100644 index 4f9a96b..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImpl.java +++ /dev/null
@@ -1,111 +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. - -package org.chromium.content.browser.remoteobjects; - -import org.chromium.blink.mojom.RemoteObject; -import org.chromium.blink.mojom.RemoteObjectHost; -import org.chromium.mojo.bindings.InterfaceRequest; -import org.chromium.mojo.system.MojoException; - -import java.lang.ref.WeakReference; - -/** - * Exposes limited access to a set of Java objects over a Mojo interface. - * - * This object is split in two due to the need to ensure that the Mojo watcher does not keep the - * WebView alive through strong references. It is expected that the WebView be destroyed when it is - * collected by the runtime. - * - * To achieve this, all fields which might transitively point to the WebView are stored in a - * separate object, RemoteObjectRegistry, held weakly. It is held alive via a retaining set which is - * owned by the WebView. If the registry is collected, it means that the WebView is gone, and any - * further access to the Mojo interface should fail. - * - * {@link RemoteObjectImpl} similarly holds its target weakly; it is held alive via the map held in - * Internals. - */ -class RemoteObjectHostImpl implements RemoteObjectHost { - /** - * Auditor passed on to {@link RemoteObjectImpl}. - * Should not hold any strong references that may lead to the contents. - */ - private final RemoteObjectImpl.Auditor mAuditor; - - /** - * The registry which owns the underlying target objects, if still alive. - * See the class comment. - */ - private final WeakReference<RemoteObjectRegistry> mRegistry; - - private boolean mAllowInspection; - - RemoteObjectHostImpl( - RemoteObjectImpl.Auditor auditor, - RemoteObjectRegistry registry, - boolean allowInspection) { - mAuditor = auditor; - mRegistry = new WeakReference<>(registry); - mAllowInspection = allowInspection; - } - - public void setAllowInspection(boolean allow) { - mAllowInspection = allow; - } - - @Override - public void getObject(int objectId, InterfaceRequest<RemoteObject> request) { - try (InterfaceRequest<RemoteObject> autoClose = request) { - RemoteObjectRegistry registry = mRegistry.get(); - if (registry == null) { - return; - } - Object target = registry.getObjectById(objectId); - if (target == null) { - return; - } - RemoteObjectImpl impl = - new RemoteObjectImpl( - target, - registry.getSafeAnnotationClass(target), - mAuditor, - registry, - mAllowInspection); - RemoteObject.MANAGER.bind(impl, request); - } - } - - @Override - public void acquireObject(int objectId) { - RemoteObjectRegistry registry = mRegistry.get(); - if (registry == null) { - return; - } - registry.refObjectById(objectId); - } - - @Override - public void releaseObject(int objectId) { - RemoteObjectRegistry registry = mRegistry.get(); - if (registry == null) { - return; - } - registry.unrefObjectById(objectId); - } - - @Override - public void close() { - RemoteObjectRegistry registry = mRegistry.get(); - if (registry == null) { - return; - } - registry.close(); - mRegistry.clear(); - } - - @Override - public void onConnectionError(MojoException e) { - close(); - } -}
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java deleted file mode 100644 index e5d29ca9..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java +++ /dev/null
@@ -1,861 +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. - -package org.chromium.content.browser.remoteobjects; - -import androidx.annotation.IntDef; - -import org.chromium.blink.mojom.RemoteArrayType; -import org.chromium.blink.mojom.RemoteInvocationArgument; -import org.chromium.blink.mojom.RemoteInvocationError; -import org.chromium.blink.mojom.RemoteInvocationResult; -import org.chromium.blink.mojom.RemoteInvocationResultValue; -import org.chromium.blink.mojom.RemoteObject; -import org.chromium.blink.mojom.RemoteTypedArray; -import org.chromium.blink.mojom.SingletonJavaScriptValue; -import org.chromium.mojo.system.MojoException; -import org.chromium.mojo_base.BigBufferUtil; -import org.chromium.mojo_base.mojom.String16; - -import java.lang.annotation.Annotation; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.ref.WeakReference; -import java.lang.reflect.Array; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.DoubleBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.regex.Pattern; - -/** - * Exposes limited access to a Java object over a Mojo interface. - * - * For LiveConnect references, an archived version is available at: - * http://web.archive.org/web/20141022204935/http://jdk6.java.net/plugin2/liveconnect/ - */ -class RemoteObjectImpl implements RemoteObject { - /** - * Receives notification about events for auditing. - * - * Separated from this class proper to allow for unit testing in content_junit_tests, where the - * Android framework is not fully initialized. - * - * Implementations should take care not to hold a strong reference to anything that might keep - * the WebView contents alive due to a GC cycle. - */ - interface Auditor { - void onObjectGetClassInvocationAttempt(); - } - - /** - * Provides numeric identifier for Java objects to be exposed. - * These identifiers must not collide. - */ - interface ObjectIdAllocator { - int getObjectId(Object object, Class<? extends Annotation> safeAnnotationClass); - - Object getObjectById(int id); - - void unrefObjectByObject(Object object); - } - - /** Method which may not be called. */ - private static final Method sGetClassMethod; - - static { - try { - sGetClassMethod = Object.class.getMethod("getClass"); - } catch (NoSuchMethodException e) { - // java.lang.Object#getClass should always exist. - throw new RuntimeException(e); - } - } - - /** - * The object to which invocations should be directed. - * - * The target object cannot be referred to strongly, because it may contain - * references which form an uncollectable cycle. - */ - private final WeakReference<Object> mTarget; - - /** - * Annotation required on all exposed methods. - * If null, no annotation is required. - * In practice, this is usually {@link android.webkit.JavascriptInterface}. - */ - private final Class<? extends Annotation> mSafeAnnotationClass; - - /** - * Allocates IDs for other Java objects. - * - * Cannot be held strongly, because it may (via the objects it holds) contain - * references which form an uncollectable cycle. - */ - private final WeakReference<ObjectIdAllocator> mObjectIdAllocator; - - /** Receives notification about events for auditing. */ - private final Auditor mAuditor; - - /** Callable methods, indexed by name. */ - private final SortedMap<String, List<Method>> mMethods = new TreeMap<>(); - - /** If true, allows an object context's inspection when {@link #getMethods} is called. */ - private final boolean mAllowInspection; - - private boolean mNotifiedReleasedObject; - - public static final short UNSIGNED_BYTE_MASK = 0xff; - public static final int UNSIGNED_SHORT_MASK = 0xffff; - public static final long UNSIGNED_INT_MASK = 0xffffffffL; - - private static final Pattern sDoubleNumberPattern = - Pattern.compile( - "^(-?[0-9]+)(\\.0+)? ( ( (?:\\.[0-9]*[1-9])? )0* ) ((?:e.*)?)$", - Pattern.COMMENTS); - - public RemoteObjectImpl( - Object target, - Class<? extends Annotation> safeAnnotationClass, - Auditor auditor, - ObjectIdAllocator objectIdAllocator, - boolean allowInspection) { - mTarget = new WeakReference<>(target); - mSafeAnnotationClass = safeAnnotationClass; - mAuditor = auditor; - mObjectIdAllocator = new WeakReference<>(objectIdAllocator); - mAllowInspection = allowInspection; - mNotifiedReleasedObject = false; - - for (Method method : target.getClass().getMethods()) { - if (safeAnnotationClass != null && !method.isAnnotationPresent(safeAnnotationClass)) { - continue; - } - - String methodName = method.getName(); - List<Method> methodsWithName = mMethods.get(methodName); - if (methodsWithName == null) { - methodsWithName = new ArrayList<>(1); - mMethods.put(methodName, methodsWithName); - } - methodsWithName.add(method); - } - } - - @Override - public void hasMethod(String name, HasMethod_Response callback) { - callback.call(mMethods.containsKey(name)); - } - - @Override - public void getMethods(GetMethods_Response callback) { - if (!mAllowInspection) { - callback.call(new String[0]); - return; - } - Set<String> methodNames = mMethods.keySet(); - callback.call(methodNames.toArray(new String[methodNames.size()])); - } - - @Override - public void invokeMethod( - String name, RemoteInvocationArgument[] arguments, InvokeMethod_Response callback) { - Object target = mTarget.get(); - ObjectIdAllocator objectIdAllocator = mObjectIdAllocator.get(); - if (target == null || objectIdAllocator == null) { - // TODO(jbroman): Handle this. - return; - } - - int numArguments = arguments.length; - Method method = findMethod(name, numArguments); - if (method == null) { - callback.call(makeErrorResult(RemoteInvocationError.METHOD_NOT_FOUND)); - return; - } - if (method.equals(sGetClassMethod)) { - if (mAuditor != null) { - mAuditor.onObjectGetClassInvocationAttempt(); - } - callback.call(makeErrorResult(RemoteInvocationError.OBJECT_GET_CLASS_BLOCKED)); - return; - } - if (method.getReturnType().isArray()) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to not call methods that - // return arrays. Spec requires calling the method and converting the - // result to a JavaScript array. - RemoteInvocationResult result = new RemoteInvocationResult(); - result.value = new RemoteInvocationResultValue(); - result.value.setSingletonValue(SingletonJavaScriptValue.UNDEFINED); - callback.call(result); - return; - } - - Class<?>[] parameterTypes = method.getParameterTypes(); - Object[] args = new Object[numArguments]; - for (int i = 0; i < numArguments; i++) { - try { - args[i] = - convertArgument( - arguments[i], - parameterTypes[i], - StringCoercionMode.COERCE, - objectIdAllocator); - } catch (IllegalArgumentException e) { - callback.call(makeErrorResult(RemoteInvocationError.NON_ASSIGNABLE_TYPES)); - return; - } - } - - Object result = null; - try { - result = method.invoke(target, args); - } catch (IllegalAccessException | IllegalArgumentException | NullPointerException e) { - // These should never happen. - // - // IllegalAccessException: - // java.lang.Class#getMethods returns only public members, so |mMethods| should never - // contain any method for which IllegalAccessException would be thrown. - // - // IllegalArgumentException: - // Argument coercion logic is responsible for creating objects of a suitable Java - // type. - // - // NullPointerException: - // A user of this class is responsible for ensuring that the target is not collected. - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - e.getCause().printStackTrace(); - callback.call(makeErrorResult(RemoteInvocationError.EXCEPTION_THROWN)); - return; - } - - RemoteInvocationResult mojoResult = - convertResult( - result, method.getReturnType(), objectIdAllocator, mSafeAnnotationClass); - callback.call(mojoResult); - } - - @Override - public void notifyReleasedObject() { - mNotifiedReleasedObject = true; - } - - @Override - public void close() { - Object target = mTarget.get(); - ObjectIdAllocator objectIdAllocator = mObjectIdAllocator.get(); - // If |mNotifiedReleasedObject| is false, this outlives the RemoteObjectHost and the object - // is not unreferenced by the RemoteObjectHost. So, we should unreference the object when - // the mojo pipe is closed. - if (target != null && objectIdAllocator != null && !mNotifiedReleasedObject) { - objectIdAllocator.unrefObjectByObject(target); - } - - mTarget.clear(); - } - - @Override - public void onConnectionError(MojoException e) { - close(); - } - - private Method findMethod(String name, int numParameters) { - List<Method> methods = mMethods.get(name); - if (methods == null) { - return null; - } - - // LIVECONNECT_COMPLIANCE: We just take the first method with the correct - // number of arguments, while the spec proposes using cost-based algorithm: - // https://jdk6.java.net/plugin2/liveconnect/#OVERLOADED_METHODS - for (Method method : methods) { - if (method.getParameterTypes().length == numParameters) return method; - } - - return null; - } - - @IntDef({StringCoercionMode.DO_NOT_COERCE, StringCoercionMode.COERCE}) - @Retention(RetentionPolicy.SOURCE) - private @interface StringCoercionMode { - // Do not coerce non-strings to string; instead produce null. - // Used when coercing arguments inside arrays. - int DO_NOT_COERCE = 0; - - // Coerce into strings more aggressively. Applied when the parameter type is - // java.lang.String exactly. - int COERCE = 1; - } - - private static Object convertPrimitiveArrayElement(Number number, Class<?> parameterType) { - assert (parameterType.isPrimitive() && parameterType != boolean.class); - if (parameterType == byte.class) { - return number.byteValue(); - } else if (parameterType == char.class) { - return (char) (number.intValue() & UNSIGNED_SHORT_MASK); - } else if (parameterType == short.class) { - return number.shortValue(); - } else if (parameterType == int.class) { - return number.intValue(); - } else if (parameterType == long.class) { - return number.longValue(); - } else if (parameterType == float.class) { - return number.floatValue(); - } - - return number.doubleValue(); - } - - private abstract static class WrapBuffer { - protected Class<?> mParameterType; - protected int mLength; - - WrapBuffer(Class<?> parameterType) { - mParameterType = parameterType; - } - - public Object copyArray() { - if (mParameterType == boolean.class) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec - // requires converting to false for 0 or NaN, true otherwise. - // The default value of the boolean elements in a boolean array is false. - return new boolean[mLength]; - } else if (isFloatType() && mParameterType == char.class) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert floating-point types to - // 0. Spec requires converting doubles similarly to how we convert floating-point - // types to other numeric types. - // The default value of the char elements in a char array is 0. - return new char[mLength]; - } else if (mParameterType == String.class) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null for all. - // The default value of the String elements in a String array is null. - return new String[mLength]; - } - - Object result = Array.newInstance(mParameterType, mLength); - for (int i = 0; i < mLength; i++) { - Array.set(result, i, convertPrimitiveArrayElement(get(i), mParameterType)); - } - return result; - } - - protected abstract Number get(int index); - - protected boolean isFloatType() { - return false; - } - } - - private static class WrapByteBuffer extends WrapBuffer { - ByteBuffer mBuffer; - boolean mUnsigned; - - WrapByteBuffer(ByteBuffer buffer, Class<?> parameterType, boolean unsigned) { - super(parameterType); - mBuffer = buffer; - mLength = mBuffer.limit(); - mUnsigned = unsigned; - } - - @Override - public Object copyArray() { - if (mParameterType != byte.class) { - return super.copyArray(); - } - byte[] result = new byte[mLength]; - mBuffer.get(result); - return result; - } - - @Override - protected Number get(int index) { - byte number = mBuffer.get(index); - return (mUnsigned ? (short) (number & UNSIGNED_BYTE_MASK) : number); - } - } - - private static class WrapShortBuffer extends WrapBuffer { - ShortBuffer mBuffer; - boolean mUnsigned; - - WrapShortBuffer(ShortBuffer buffer, Class<?> parameterType, boolean unsigned) { - super(parameterType); - mBuffer = buffer; - mLength = mBuffer.limit(); - mUnsigned = unsigned; - } - - @Override - public Object copyArray() { - if (mParameterType != short.class) { - return super.copyArray(); - } - short[] result = new short[mLength]; - mBuffer.get(result); - return result; - } - - @Override - protected Number get(int index) { - short number = mBuffer.get(index); - return (mUnsigned ? (int) (number & UNSIGNED_SHORT_MASK) : number); - } - } - - private static class WrapIntBuffer extends WrapBuffer { - IntBuffer mBuffer; - boolean mUnsigned; - - WrapIntBuffer(IntBuffer buffer, Class<?> parameterType, boolean unsigned) { - super(parameterType); - mBuffer = buffer; - mLength = mBuffer.limit(); - mUnsigned = unsigned; - } - - @Override - public Object copyArray() { - if (mParameterType != int.class) { - return super.copyArray(); - } - int[] result = new int[mLength]; - mBuffer.get(result); - return result; - } - - @Override - protected Number get(int index) { - int number = mBuffer.get(index); - return (mUnsigned ? (long) (number & UNSIGNED_INT_MASK) : number); - } - } - - private static class WrapFloatBuffer extends WrapBuffer { - FloatBuffer mBuffer; - - WrapFloatBuffer(FloatBuffer buffer, Class<?> parameterType) { - super(parameterType); - mBuffer = buffer; - mLength = mBuffer.limit(); - } - - @Override - public Object copyArray() { - if (mParameterType != float.class) { - return super.copyArray(); - } - float[] result = new float[mLength]; - mBuffer.get(result); - return result; - } - - @Override - protected Number get(int index) { - return mBuffer.get(index); - } - - @Override - protected boolean isFloatType() { - return true; - } - } - - private static class WrapDoubleBuffer extends WrapBuffer { - DoubleBuffer mBuffer; - - WrapDoubleBuffer(DoubleBuffer buffer, Class<?> parameterType) { - super(parameterType); - mBuffer = buffer; - mLength = mBuffer.limit(); - } - - @Override - public Object copyArray() { - if (mParameterType != double.class) { - return super.copyArray(); - } - double[] result = new double[mLength]; - mBuffer.get(result); - return result; - } - - @Override - protected Number get(int index) { - return mBuffer.get(index); - } - - @Override - protected boolean isFloatType() { - return true; - } - } - - private static Object convertArgument( - RemoteInvocationArgument argument, - Class<?> parameterType, - @StringCoercionMode int stringCoercionMode, - ObjectIdAllocator objectIdAllocator) { - switch (argument.which()) { - case RemoteInvocationArgument.Tag.NumberValue: - // See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES. - // For conversion to numeric types, we need to replicate Java's type - // conversion rules. - double numberValue = argument.getNumberValue(); - if (parameterType == byte.class) { - return (byte) numberValue; - } else if (parameterType == char.class) { - if (isInt32(numberValue)) { - return (char) numberValue; - } else { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert double to 0. - // Spec requires converting doubles similarly to how we convert doubles to - // other numeric types. - return (char) 0; - } - } else if (parameterType == short.class) { - return (short) numberValue; - } else if (parameterType == int.class) { - return (int) numberValue; - } else if (parameterType == long.class) { - return (long) numberValue; - } else if (parameterType == float.class) { - return (float) numberValue; - } else if (parameterType == double.class) { - return numberValue; - } else if (parameterType == boolean.class) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec - // requires converting to false for 0 or NaN, true otherwise. - return false; - } else if (parameterType == String.class) { - return stringCoercionMode == StringCoercionMode.COERCE - ? doubleToString(numberValue) - : null; - } else if (parameterType.isArray()) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec - // requires raising a JavaScript exception. - return null; - } else { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec - // requires handling object equivalents of primitive types. - assert !parameterType.isPrimitive(); - return null; - } - case RemoteInvocationArgument.Tag.BooleanValue: - // See http://jdk6.java.net/plugin2/liveconnect/#JS_BOOLEAN_VALUES. - boolean booleanValue = argument.getBooleanValue(); - if (parameterType == boolean.class) { - return booleanValue; - } else if (parameterType.isPrimitive()) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0 for all - // non-boolean primitive types. Spec requires converting to 0 or 1. - return getPrimitiveZero(parameterType); - } else if (parameterType == String.class) { - return stringCoercionMode == StringCoercionMode.COERCE - ? Boolean.toString(booleanValue) - : null; - } else if (parameterType.isArray()) { - return null; - } else { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec - // requires handling java.lang.Boolean and java.lang.Object. - assert !parameterType.isPrimitive(); - return null; - } - case RemoteInvocationArgument.Tag.StringValue: - // See http://jdk6.java.net/plugin2/liveconnect/#JS_STRING_VALUES. - if (parameterType == String.class) { - return mojoStringToJavaString(argument.getStringValue()); - } else if (parameterType.isPrimitive()) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec - // requires using valueOf() method of corresponding object type, or - // converting to boolean based on whether the string is empty. - return getPrimitiveZero(parameterType); - } else if (parameterType.isArray()) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec - // requires raising a JavaScript exception. - return null; - } else { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec - // requires handling java.lang.Object. - return null; - } - case RemoteInvocationArgument.Tag.SingletonValue: - int singletonValue = argument.getSingletonValue(); - boolean isUndefined = singletonValue == SingletonJavaScriptValue.UNDEFINED; - if (parameterType == String.class) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert undefined to - // "undefined". Spec requires converting undefined to NULL. - return (argument.getSingletonValue() == SingletonJavaScriptValue.UNDEFINED - && stringCoercionMode == StringCoercionMode.COERCE) - ? "undefined" - : null; - } else if (parameterType.isPrimitive()) { - return getPrimitiveZero(parameterType); - } else if (parameterType.isArray()) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec - // requires raising a JavaScript exception. - return null; - } else { - return null; - } - case RemoteInvocationArgument.Tag.ArrayValue: - RemoteInvocationArgument[] arrayValue = argument.getArrayValue(); - if (parameterType.isArray()) { - Class<?> componentType = parameterType.getComponentType(); - - // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for - // multi-dimensional and object arrays. Spec requires handling them. - if (!componentType.isPrimitive() && componentType != String.class) { - return null; - } - - Object result = Array.newInstance(componentType, arrayValue.length); - for (int i = 0; i < arrayValue.length; i++) { - Object element = - convertArgument( - arrayValue[i], - componentType, - StringCoercionMode.DO_NOT_COERCE, - objectIdAllocator); - Array.set(result, i, element); - } - return result; - } else if (parameterType == String.class) { - return stringCoercionMode == StringCoercionMode.COERCE ? "undefined" : null; - } else if (parameterType.isPrimitive()) { - return getPrimitiveZero(parameterType); - } else { - // LIVECONNECT_COMPLIANCE: Existing behavior is to pass null. Spec requires - // converting if the target type is netscape.javascript.JSObject, otherwise - // raising a JavaScript exception. - return null; - } - case RemoteInvocationArgument.Tag.TypedArrayValue: - RemoteTypedArray typedArrayValue = argument.getTypedArrayValue(); - if (parameterType.isArray()) { - Class<?> componentType = parameterType.getComponentType(); - - // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for - // multi-dimensional and object arrays. Spec requires handling them. - if (!componentType.isPrimitive() && componentType != String.class) { - return null; - } else if (componentType.isArray()) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec - // requires raising a JavaScript exception. - return null; - } - - // TODO(crbug.com/40554401): Remove unnecessary copy for the performance. - ByteBuffer typedBuffer = - ByteBuffer.wrap( - BigBufferUtil.getBytesFromBigBuffer(typedArrayValue.buffer)); - typedBuffer.order(ByteOrder.nativeOrder()); - - if (typedArrayValue.type == RemoteArrayType.INT8_ARRAY) { - return new WrapByteBuffer(typedBuffer, componentType, false).copyArray(); - } else if (typedArrayValue.type == RemoteArrayType.UINT8_ARRAY) { - return new WrapByteBuffer(typedBuffer, componentType, true).copyArray(); - } else if (typedArrayValue.type == RemoteArrayType.INT16_ARRAY) { - return new WrapShortBuffer( - typedBuffer.asShortBuffer(), componentType, false) - .copyArray(); - } else if (typedArrayValue.type == RemoteArrayType.UINT16_ARRAY) { - return new WrapShortBuffer(typedBuffer.asShortBuffer(), componentType, true) - .copyArray(); - } else if (typedArrayValue.type == RemoteArrayType.INT32_ARRAY) { - return new WrapIntBuffer(typedBuffer.asIntBuffer(), componentType, false) - .copyArray(); - } else if (typedArrayValue.type == RemoteArrayType.UINT32_ARRAY) { - return new WrapIntBuffer(typedBuffer.asIntBuffer(), componentType, true) - .copyArray(); - } else if (typedArrayValue.type == RemoteArrayType.FLOAT32_ARRAY) { - return new WrapFloatBuffer(typedBuffer.asFloatBuffer(), componentType) - .copyArray(); - } else if (typedArrayValue.type == RemoteArrayType.FLOAT64_ARRAY) { - return new WrapDoubleBuffer(typedBuffer.asDoubleBuffer(), componentType) - .copyArray(); - } else { - return null; - } - } else if (parameterType == String.class) { - return stringCoercionMode == StringCoercionMode.COERCE ? "undefined" : null; - } else if (parameterType.isPrimitive()) { - return getPrimitiveZero(parameterType); - } else { - // LIVECONNECT_COMPLIANCE: Existing behavior is to pass null. Spec requires - // converting if the target type is netscape.javascript.JSObject, otherwise - // raising a JavaScript exception. - return null; - } - case RemoteInvocationArgument.Tag.ObjectIdValue: - if (parameterType == String.class) { - return stringCoercionMode == StringCoercionMode.COERCE ? "undefined" : null; - } else if (parameterType.isPrimitive()) { - return getPrimitiveZero(parameterType); - } else if (parameterType.isArray()) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec - // requires raising a JavaScript exception. - return null; - } - - Object object = objectIdAllocator.getObjectById(argument.getObjectIdValue()); - if (object == null) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to pass null. Spec - // requires converting if the target type is - // netscape.javascript.JSObject, otherwise raising a JavaScript - // exception. - return null; - } - if (parameterType.isInstance(object)) return object; - - throw new IllegalArgumentException("incompatible argument type with object id"); - default: - throw new RuntimeException("invalid wire argument type"); - } - } - - private static RemoteInvocationResult convertResult( - Object result, - Class<?> returnType, - ObjectIdAllocator objectIdAllocator, - Class<? extends Annotation> safeAnnotationClass) { - // Methods returning arrays should not be called (for legacy reasons). - assert !returnType.isArray(); - - // LIVECONNECT_COMPLIANCE: The specification suggests that the conversion should happen - // based on the type of the result value. Existing behavior is to rely on the declared - // return type of the method. This means, for instance, that a java.lang.String returned - // from a method declared as returning java.lang.Object will not be converted to a - // JavaScript string. - RemoteInvocationResultValue resultValue = new RemoteInvocationResultValue(); - if (returnType == void.class) { - resultValue.setSingletonValue(SingletonJavaScriptValue.UNDEFINED); - } else if (returnType == boolean.class) { - resultValue.setBooleanValue((Boolean) result); - } else if (returnType == char.class) { - resultValue.setNumberValue((Character) result); - } else if (returnType.isPrimitive()) { - resultValue.setNumberValue(((Number) result).doubleValue()); - } else if (returnType == String.class) { - if (result == null) { - // LIVECONNECT_COMPLIANCE: Existing behavior is to return undefined. - // Spec requires returning a null string. - resultValue.setSingletonValue(SingletonJavaScriptValue.UNDEFINED); - } else { - resultValue.setStringValue(javaStringToMojoString((String) result)); - } - } else if (result == null) { - resultValue.setSingletonValue(SingletonJavaScriptValue.NULL); - } else { - int objectId = objectIdAllocator.getObjectId(result, safeAnnotationClass); - resultValue.setObjectId(objectId); - } - RemoteInvocationResult mojoResult = new RemoteInvocationResult(); - mojoResult.value = resultValue; - return mojoResult; - } - - private static RemoteInvocationResult makeErrorResult(int error) { - assert error != RemoteInvocationError.OK; - RemoteInvocationResult result = new RemoteInvocationResult(); - result.error = error; - return result; - } - - /** - * Returns whether the value is an Int32 in the V8 API sense. - * That is, it has an integer value in [-2^31, 2^31) and is not negative zero. - */ - private static boolean isInt32(double doubleValue) { - return doubleValue % 1.0 == 0.0 - && doubleValue >= Integer.MIN_VALUE - && doubleValue <= Integer.MAX_VALUE - && (doubleValue != 0.0 || (1.0 / doubleValue) > 0.0); - } - - private static String doubleToString(double doubleValue) { - // For compatibility, imitate the existing behavior. - // The previous implementation applied Int64ToString to any integer that fit in 32 bits, - // except for negative zero, and base::StringPrintf("%.6lg", doubleValue) for all other - // values. - if (Double.isNaN(doubleValue)) { - return "nan"; - } - if (Double.isInfinite(doubleValue)) { - return doubleValue > 0 ? "inf" : "-inf"; - } - // Negative zero is mathematically an integer, but keeps its negative sign. - if (doubleValue == 0.0 && (1.0 / doubleValue) < 0.0) { - return "-0"; - } - // All other 32-bit signed integers are formatted without abbreviation. - if (doubleValue % 1.0 == 0.0 - && doubleValue >= Integer.MIN_VALUE - && doubleValue <= Integer.MAX_VALUE) { - return Integer.toString((int) doubleValue); - } - // Remove trailing zeroes and, if appropriate, the decimal point. - // Expression is somewhat complicated, in order to deal with scientific notation. Either - // group 2 will match (and so the decimal will be stripped along with zeroes), or group 3 - // will match (and the decimal will be left), but not both (since there cannot be more than - // one decimal point). Group 5 will match an exponential part. - return sDoubleNumberPattern - .matcher(String.format((Locale) null, "%.6g", doubleValue)) - .replaceAll("$1$4$5"); - } - - private static Object getPrimitiveZero(Class<?> parameterType) { - assert parameterType.isPrimitive(); - if (parameterType == boolean.class) { - return false; - } else if (parameterType == byte.class) { - return (byte) 0; - } else if (parameterType == char.class) { - return (char) 0; - } else if (parameterType == short.class) { - return (short) 0; - } else if (parameterType == int.class) { - return (int) 0; - } else if (parameterType == long.class) { - return (long) 0; - } else if (parameterType == float.class) { - return (float) 0; - } else if (parameterType == double.class) { - return (double) 0; - } else { - throw new RuntimeException("unexpected primitive type " + parameterType); - } - } - - private static String mojoStringToJavaString(String16 mojoString) { - short[] data = mojoString.data; - char[] chars = new char[data.length]; - for (int i = 0; i < chars.length; i++) { - chars[i] = (char) data[i]; - } - return String.valueOf(chars); - } - - private static String16 javaStringToMojoString(String string) { - short[] data = new short[string.length()]; - for (int i = 0; i < data.length; i++) { - data[i] = (short) string.charAt(i); - } - String16 mojoString = new String16(); - mojoString.data = data; - return mojoString; - } -}
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectInjector.java b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectInjector.java deleted file mode 100644 index dae12b6..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectInjector.java +++ /dev/null
@@ -1,190 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.content.browser.remoteobjects; - -import org.chromium.blink.mojom.RemoteObjectGateway; -import org.chromium.blink.mojom.RemoteObjectGatewayFactory; -import org.chromium.content.browser.webcontents.WebContentsImpl; -import org.chromium.content_public.browser.GlobalRenderFrameHostId; -import org.chromium.content_public.browser.RenderFrameHost; -import org.chromium.content_public.browser.WebContents; -import org.chromium.content_public.browser.WebContentsObserver; -import org.chromium.mojo.bindings.InterfaceRequest; -import org.chromium.mojo.system.Pair; -import org.chromium.mojo.system.impl.CoreImpl; - -import java.lang.annotation.Annotation; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Owned and constructed by JavascriptInjectorImpl. - * Could possibly be flattened into JavascriptInjectorImpl eventually, but may be nice to keep - * separate while there are separate codepaths. - */ -public final class RemoteObjectInjector extends WebContentsObserver { - /** - * Helper class for holding objects used to interact - * with the RemoteObjectGateway in the renderer. - */ - private static class RemoteObjectGatewayHelper { - public RemoteObjectGateway.Proxy gateway; - public RemoteObjectHostImpl host; - public RemoteObjectRegistry registry; - - public RemoteObjectGatewayHelper( - RemoteObjectGateway.Proxy newGateway, - RemoteObjectHostImpl newHost, - RemoteObjectRegistry newRegistry) { - gateway = newGateway; - host = newHost; - registry = newRegistry; - } - } - - private final Set<Object> mRetainingSet = new HashSet<>(); - private final Map<String, Pair<Object, Class<? extends Annotation>>> mInjectedObjects = - new HashMap<>(); - // TODO(crbug.com/40756645): This is essentially implementing DocumentUserData. Once a java - // equivalent of that is created, we should use it instead of managing RFH associated state - // here. - private final Map<GlobalRenderFrameHostId, RemoteObjectGatewayHelper> - mRemoteObjectGatewayHelpers = new HashMap<>(); - private boolean mAllowInspection = true; - - public RemoteObjectInjector(WebContents webContents) { - super(webContents); - } - - @Override - public void renderFrameCreated(GlobalRenderFrameHostId id) { - if (mInjectedObjects.isEmpty()) return; - - WebContents webContents = mWebContents.get(); - if (webContents == null) return; - - RenderFrameHost frameHost = webContents.getRenderFrameHostFromId(id); - if (frameHost == null) return; - - for (Map.Entry<String, Pair<Object, Class<? extends Annotation>>> entry : - mInjectedObjects.entrySet()) { - addInterfaceForFrame( - frameHost, entry.getKey(), entry.getValue().first, entry.getValue().second); - } - } - - @Override - public void renderFrameDeleted(GlobalRenderFrameHostId id) { - mRemoteObjectGatewayHelpers.remove(id); - } - - public void addInterface( - Object object, String name, Class<? extends Annotation> requiredAnnotation) { - WebContentsImpl webContents = (WebContentsImpl) mWebContents.get(); - if (webContents == null) return; - - Pair<Object, Class<? extends Annotation>> value = mInjectedObjects.get(name); - - // Nothing to do if the named object already exists. - if (value != null && value.first == object) return; - - if (value != null) { - // Remove existing name for replacement. - removeInterface(name); - } - - mInjectedObjects.put(name, new Pair<>(object, requiredAnnotation)); - - List<RenderFrameHost> frames = webContents.getAllRenderFrameHosts(); - for (RenderFrameHost frame : frames) { - // If there's no renderer frame yet, we will add the interface when - // it is created. - if (frame.isRenderFrameLive()) { - addInterfaceForFrame(frame, name, object, requiredAnnotation); - } - } - } - - public void removeInterface(String name) { - WebContentsImpl webContents = (WebContentsImpl) mWebContents.get(); - if (webContents == null) return; - - Pair<Object, Class<? extends Annotation>> value = mInjectedObjects.remove(name); - if (value == null) return; - - List<RenderFrameHost> frames = webContents.getAllRenderFrameHosts(); - for (RenderFrameHost frame : frames) { - removeInterfaceForFrame(frame, name, value.first); - } - } - - public void setAllowInspection(boolean allow) { - WebContentsImpl webContents = (WebContentsImpl) mWebContents.get(); - if (webContents == null) return; - - mAllowInspection = allow; - - List<RenderFrameHost> frames = webContents.getAllRenderFrameHosts(); - for (RenderFrameHost frame : frames) { - setAllowInspectionForFrame(frame); - } - } - - private void addInterfaceForFrame( - RenderFrameHost frameHost, - String name, - Object object, - Class<? extends Annotation> requiredAnnotation) { - RemoteObjectGatewayHelper helper = getRemoteObjectGatewayHelperForFrame(frameHost); - helper.gateway.addNamedObject( - name, helper.registry.getObjectId(object, requiredAnnotation)); - } - - private void removeInterfaceForFrame(RenderFrameHost frameHost, String name, Object object) { - RemoteObjectGatewayHelper helper = - mRemoteObjectGatewayHelpers.get(frameHost.getGlobalRenderFrameHostId()); - if (helper == null) return; - - helper.gateway.removeNamedObject(name); - helper.registry.unrefObjectByObject(object); - } - - private void setAllowInspectionForFrame(RenderFrameHost frameHost) { - RemoteObjectGatewayHelper helper = - mRemoteObjectGatewayHelpers.get(frameHost.getGlobalRenderFrameHostId()); - if (helper == null) return; - - helper.host.setAllowInspection(mAllowInspection); - } - - private RemoteObjectGatewayHelper getRemoteObjectGatewayHelperForFrame( - RenderFrameHost frameHost) { - GlobalRenderFrameHostId frameHostId = frameHost.getGlobalRenderFrameHostId(); - // Only create one instance of RemoteObjectHostImpl per frame and store it in a map so it is - // reused in future calls. - if (!mRemoteObjectGatewayHelpers.containsKey(frameHostId)) { - RemoteObjectRegistry registry = new RemoteObjectRegistry(mRetainingSet); - - // Construct a RemoteObjectHost implementation. - RemoteObjectHostImpl host = - new RemoteObjectHostImpl( - new RemoteObjectAuditorImpl(), registry, mAllowInspection); - - RemoteObjectGatewayFactory factory = - frameHost.getInterfaceToRendererFrame(RemoteObjectGatewayFactory.MANAGER); - - Pair<RemoteObjectGateway.Proxy, InterfaceRequest<RemoteObjectGateway>> result = - RemoteObjectGateway.MANAGER.getInterfaceRequest(CoreImpl.getInstance()); - factory.createRemoteObjectGateway(host, result.second); - mRemoteObjectGatewayHelpers.put( - frameHostId, new RemoteObjectGatewayHelper(result.first, host, registry)); - } - - return mRemoteObjectGatewayHelpers.get(frameHostId); - } -}
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectRegistry.java b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectRegistry.java deleted file mode 100644 index 43b0f9f..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectRegistry.java +++ /dev/null
@@ -1,127 +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. - -package org.chromium.content.browser.remoteobjects; - -import android.util.SparseArray; - -import java.lang.annotation.Annotation; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Set; - -/** - * Owns a set of objects on behalf of RemoteObjectHost's client. - * - * These objects could contain references which would keep the WebContents alive - * longer than expected, and so must not be held alive by any other GC root. - * - * The object's reference count is changed in the following cases: - * - When the wrapper object is created in the renderer, it is increased. - * - When the wrapper object is destroyed in the renderer, it is decreased via RemoteObjectHost - * in general. If the wrapper object, RemoteObject, outlives RemoteObjectHost, the object could - * not drop the reference via RemoteObjectHost. By explicitly notifying {@link RemoteObjectImpl} - * that the object has been released, it ensures that the object's reference is released by - * {@link RemoteObjectImpl} when the Mojo pipe is closed. - * - When the object is named in Java code, it is increased. - * - When the object is removed from the named objects in Java code, it is decreased. - * - */ -final class RemoteObjectRegistry implements RemoteObjectImpl.ObjectIdAllocator { - private final Set<? super RemoteObjectRegistry> mRetainingSet; - - private static class Entry { - Entry(int id, Object object, Class<? extends Annotation> safeAnnotationClass) { - this.id = id; - this.object = object; - this.safeAnnotationClass = safeAnnotationClass; - } - - // The ID assigned to the object, which can be used by the renderer - // to refer to it. - public final int id; - - // The injected object itself - public final Object object; - - // The number of outstanding references to this object. - // This includes: - // * wrapper objects in the renderer (removed when it closes the pipe) - // * names assigned to the object by developer Java code - public int referenceCount = 1; - - // The annotation class annotated to the object, which can be exposed - // to JavaScript code. - public Class<? extends Annotation> safeAnnotationClass; - } - - private final SparseArray<Entry> mEntriesById = new SparseArray<>(); - private final Map<Object, Entry> mEntriesByObject = new IdentityHashMap<>(); - private int mNextId; - - RemoteObjectRegistry(Set<? super RemoteObjectRegistry> retainingSet) { - retainingSet.add(this); - mRetainingSet = retainingSet; - } - - public void close() { - boolean removed = mRetainingSet.remove(this); - assert removed; - } - - public synchronized Class<? extends Annotation> getSafeAnnotationClass(Object object) { - Entry entry = mEntriesByObject.get(object); - return entry != null ? entry.safeAnnotationClass : null; - } - - @Override - public synchronized int getObjectId( - Object object, Class<? extends Annotation> safeAnnotationClass) { - Entry entry = mEntriesByObject.get(object); - if (entry != null) { - entry.referenceCount++; - return entry.id; - } - - int newId = mNextId++; - assert newId >= 0; - entry = new Entry(newId, object, safeAnnotationClass); - mEntriesById.put(newId, entry); - mEntriesByObject.put(object, entry); - return newId; - } - - @Override - public synchronized Object getObjectById(int id) { - Entry entry = mEntriesById.get(id); - return entry != null ? entry.object : null; - } - - @Override - public synchronized void unrefObjectByObject(Object object) { - unrefObject(mEntriesByObject.get(object)); - } - - public synchronized void refObjectById(int id) { - Entry entry = mEntriesById.get(id); - if (entry == null) return; - - entry.referenceCount++; - } - - public synchronized void unrefObjectById(int id) { - unrefObject(mEntriesById.get(id)); - } - - private synchronized void unrefObject(Entry entry) { - if (entry == null) return; - - entry.referenceCount--; - assert entry.referenceCount >= 0; - if (entry.referenceCount > 0) return; - - mEntriesById.remove(entry.id); - mEntriesByObject.remove(entry.object); - } -}
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/JavascriptInjector.java b/content/public/android/java/src/org/chromium/content_public/browser/JavascriptInjector.java index dfb9890..557c2a9 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/JavascriptInjector.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/JavascriptInjector.java
@@ -12,23 +12,22 @@ import java.util.Map; /** - * Interface that provides API used to inject user-defined objects that allow - * custom Javascript interfaces. + * Interface that provides API used to inject user-defined objects that allow custom Javascript + * interfaces. */ public interface JavascriptInjector { /** * @param webContents {@link WebContents} object. - * @param useMojo Whether to use {@link RemoteObjectInjector} methods - * @return {@link JavascriptInjector} object used for the give WebContents. - * Creates one if not present. + * @return {@link JavascriptInjector} object used for the give WebContents. Creates one if not + * present. */ - static JavascriptInjector fromWebContents(WebContents webContents, boolean useMojo) { - return JavascriptInjectorImpl.fromWebContents(webContents, useMojo); + static JavascriptInjector fromWebContents(WebContents webContents) { + return JavascriptInjectorImpl.fromWebContents(webContents); } /** - * Returns Javascript interface objects previously injected via - * {@link #addPossiblyUnsafeInterface(Object, String)}. + * Returns Javascript interface objects previously injected via {@link + * #addPossiblyUnsafeInterface(Object, String)}. * * @return the mapping of names to interface objects and corresponding annotation classes */
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java index 315d59d9..cce9704 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherHelperTest.java
@@ -37,7 +37,6 @@ import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; -import org.chromium.content_public.browser.test.ChildProcessAllocatorSettings; import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_shell_apk.ChildProcessLauncherTestHelperService; @@ -81,11 +80,10 @@ @Test @MediumTest @Feature({"ProcessManagement"}) - @ChildProcessAllocatorSettings( - sandboxedServiceCount = 2, - sandboxedServiceName = DEFAULT_SANDBOXED_PROCESS_SERVICE) @DisabledTest(message = "Flaky - crbug.com/752691") public void testBindServiceFromMultipleProcesses() throws RemoteException { + ChildProcessLauncherHelperImpl.setSandboxServicesSettingsForTesting( + /* factory= */ null, 2, DEFAULT_SANDBOXED_PROCESS_SERVICE); final Context context = InstrumentationRegistry.getTargetContext(); // Start the Helper service.
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java index ce276265..2943b0d 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java
@@ -11,8 +11,6 @@ import org.junit.runners.model.Statement; import org.chromium.base.Log; -import org.chromium.base.test.params.ParameterProvider; -import org.chromium.base.test.params.ParameterSet; import org.chromium.base.test.util.UrlUtils; import org.chromium.content_public.browser.JavascriptInjector; import org.chromium.content_public.browser.LoadUrlParams; @@ -22,40 +20,13 @@ import org.chromium.content_shell_apk.ContentShellActivityTestRule; import java.lang.annotation.Annotation; -import java.util.Arrays; -import java.util.List; /** ActivityTestRule with common functionality for testing the Java Bridge. */ public class JavaBridgeActivityTestRule extends ContentShellActivityTestRule { /** Shared name for batched JavaBridge tests. */ public static final String BATCH = "JavaBridgeActivityTestRule"; - /** {@link ParameterProvider} used for parameterized test that provides the Mojo usage state. */ - public static class MojoTestParams implements ParameterProvider { - private static List<ParameterSet> sMojoTestParams = - Arrays.asList( - new ParameterSet().value(false).name("MojoUnused"), - new ParameterSet().value(true).name("MojoUsed")); - - @Override - public List<ParameterSet> getParameters() { - return sMojoTestParams; - } - } - - /** {@link ParameterProvider} used for parameterized test that keeps the legacy tests. */ - public static class LegacyTestParams implements ParameterProvider { - private static List<ParameterSet> sLegacyTestParams = - Arrays.asList(new ParameterSet().value(false)); - - @Override - public List<ParameterSet> getParameters() { - return sLegacyTestParams; - } - } - private TestCallbackHelperContainer mTestCallbackHelperContainer; - private boolean mUseMojo; public static class Controller { private static final int RESULT_WAIT_TIME = 5000; @@ -155,7 +126,7 @@ public void run() { WebContents webContents = getWebContents(); JavascriptInjector injector = - JavascriptInjector.fromWebContents(webContents, mUseMojo); + JavascriptInjector.fromWebContents(webContents); injector.addPossiblyUnsafeInterface(object1, name1, requiredAnnotation); if (object2 != null && name2 != null) { injector.addPossiblyUnsafeInterface( @@ -171,10 +142,6 @@ } } - public void setupMojoTest(boolean useMojo) { - mUseMojo = useMojo; - } - public void synchronousPageReload() throws Throwable { TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = mTestCallbackHelperContainer.getOnPageFinishedHelper();
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java index bba18087..8f8e67b 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java
@@ -14,28 +14,21 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.chromium.base.test.params.BaseJUnit4RunnerDelegate; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterizedRunner; +import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.Feature; import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller; /** - * Part of the test suite for the Java Bridge. This class tests that we correctly convert - * JavaScript arrays to Java arrays when passing them to the methods of injected Java objects. + * Part of the test suite for the Java Bridge. This class tests that we correctly convert JavaScript + * arrays to Java arrays when passing them to the methods of injected Java objects. * - * The conversions should follow - * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in - * which the implementation differs from the spec are marked with - * LIVECONNECT_COMPLIANCE. - * FIXME: Consider making our implementation more compliant, if it will not - * break backwards-compatibility. See b/4408210. + * <p>The conversions should follow http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. + * Places in which the implementation differs from the spec are marked with LIVECONNECT_COMPLIANCE. + * FIXME: Consider making our implementation more compliant, if it will not break + * backwards-compatibility. See b/4408210. */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class) +@RunWith(BaseJUnit4ClassRunner.class) @Batch(JavaBridgeActivityTestRule.BATCH) public class JavaBridgeArrayCoercionTest { private static final double ASSERTION_DELTA = 0; @@ -198,11 +191,6 @@ // Two custom types used when testing passing objects. private static class CustomType {} - @UseMethodParameterBefore(JavaBridgeActivityTestRule.MojoTestParams.class) - public void setupMojoTest(boolean useMojo) { - mActivityTestRule.setupMojoTest(useMojo); - } - private TestObject mTestObject; @Before @@ -219,8 +207,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNumberInt32(boolean useMojo) throws Throwable { + public void testPassNumberInt32() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setBooleanArray([0]);"); Assert.assertFalse(mTestObject.waitForBooleanArray()[0]); // LIVECONNECT_COMPLIANCE: Should convert to boolean. @@ -266,8 +253,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNumberDouble(boolean useMojo) throws Throwable { + public void testPassNumberDouble() throws Throwable { // LIVECONNECT_COMPLIANCE: Should convert to boolean. mActivityTestRule.executeJavaScript("testObject.setBooleanArray([42.1]);"); Assert.assertFalse(mTestObject.waitForBooleanArray()[0]); @@ -312,8 +298,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNumberNaN(boolean useMojo) throws Throwable { + public void testPassNumberNaN() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setBooleanArray([Number.NaN]);"); Assert.assertFalse(mTestObject.waitForBooleanArray()[0]); @@ -356,8 +341,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNumberInfinity(boolean useMojo) throws Throwable { + public void testPassNumberInfinity() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setBooleanArray([Infinity]);"); Assert.assertFalse(mTestObject.waitForBooleanArray()[0]); @@ -403,8 +387,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassBoolean(boolean useMojo) throws Throwable { + public void testPassBoolean() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setBooleanArray([true]);"); Assert.assertTrue(mTestObject.waitForBooleanArray()[0]); mActivityTestRule.executeJavaScript("testObject.setBooleanArray([false]);"); @@ -470,8 +453,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassString(boolean useMojo) throws Throwable { + public void testPassString() throws Throwable { // LIVECONNECT_COMPLIANCE: Non-empty string should convert to true. mActivityTestRule.executeJavaScript("testObject.setBooleanArray([\"+042.10\"]);"); Assert.assertFalse(mTestObject.waitForBooleanArray()[0]); @@ -521,8 +503,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassJavaScriptObject(boolean useMojo) throws Throwable { + public void testPassJavaScriptObject() throws Throwable { // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. mActivityTestRule.executeJavaScript("testObject.setBooleanArray([{foo: 42}]);"); Assert.assertFalse(mTestObject.waitForBooleanArray()[0]); @@ -573,8 +554,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassJavaObject(boolean useMojo) throws Throwable { + public void testPassJavaObject() throws Throwable { // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. mActivityTestRule.executeJavaScript( "testObject.setBooleanArray([testObject.getObjectInstance()]);"); @@ -639,8 +619,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNull(boolean useMojo) throws Throwable { + public void testPassNull() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setByteArray([null]);"); Assert.assertEquals(0, mTestObject.waitForByteArray()[0]); @@ -682,8 +661,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassUndefined(boolean useMojo) throws Throwable { + public void testPassUndefined() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setByteArray([undefined]);"); Assert.assertEquals(0, mTestObject.waitForByteArray()[0]); @@ -724,8 +702,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassInt8Array(boolean useMojo) throws Throwable { + public void testPassInt8Array() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(1);"); mActivityTestRule.executeJavaScript("int8_array = new Int8Array(buffer);"); mActivityTestRule.executeJavaScript("int8_array[0] = 42;"); @@ -768,8 +745,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testPassInt8ArrayWithNagativeValue(boolean useMojo) throws Throwable { + public void testPassInt8ArrayWithNagativeValue() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(1);"); mActivityTestRule.executeJavaScript("int8_array = new Int8Array(buffer);"); mActivityTestRule.executeJavaScript("int8_array[0] = -1;"); @@ -800,8 +776,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassUint8Array(boolean useMojo) throws Throwable { + public void testPassUint8Array() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(1);"); mActivityTestRule.executeJavaScript("uint8_array = new Uint8Array(buffer);"); mActivityTestRule.executeJavaScript("uint8_array[0] = 42;"); @@ -843,8 +818,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testPassUint8ArrayWithMaxValue(boolean useMojo) throws Throwable { + public void testPassUint8ArrayWithMaxValue() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(1);"); mActivityTestRule.executeJavaScript("uint8_array = new Uint8Array(buffer);"); mActivityTestRule.executeJavaScript("uint8_array[0] = 255;"); @@ -875,8 +849,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassInt16Array(boolean useMojo) throws Throwable { + public void testPassInt16Array() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(2);"); mActivityTestRule.executeJavaScript("int16_array = new Int16Array(buffer);"); mActivityTestRule.executeJavaScript("int16_array[0] = 42;"); @@ -919,8 +892,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassUint16Array(boolean useMojo) throws Throwable { + public void testPassUint16Array() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(2);"); mActivityTestRule.executeJavaScript("uint16_array = new Uint16Array(buffer);"); mActivityTestRule.executeJavaScript("uint16_array[0] = 42;"); @@ -963,8 +935,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassUint16ArrayWithMaxValue(boolean useMojo) throws Throwable { + public void testPassUint16ArrayWithMaxValue() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(2);"); mActivityTestRule.executeJavaScript("uint16_array = new Uint16Array(buffer);"); mActivityTestRule.executeJavaScript("uint16_array[0] = 65535;"); @@ -998,8 +969,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassInt32Array(boolean useMojo) throws Throwable { + public void testPassInt32Array() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(4);"); mActivityTestRule.executeJavaScript("int32_array = new Int32Array(buffer);"); mActivityTestRule.executeJavaScript("int32_array[0] = 42;"); @@ -1042,8 +1012,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassUint32Array(boolean useMojo) throws Throwable { + public void testPassUint32Array() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(4);"); mActivityTestRule.executeJavaScript("uint32_array = new Uint32Array(buffer);"); mActivityTestRule.executeJavaScript("uint32_array[0] = 42;"); @@ -1086,8 +1055,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassUint32ArrayWithMaxValue(boolean useMojo) throws Throwable { + public void testPassUint32ArrayWithMaxValue() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(4);"); mActivityTestRule.executeJavaScript("uint32_array = new Uint32Array(buffer);"); mActivityTestRule.executeJavaScript("uint32_array[0] = 4294967295;"); @@ -1124,8 +1092,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassFloat32Array(boolean useMojo) throws Throwable { + public void testPassFloat32Array() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(4);"); mActivityTestRule.executeJavaScript("float32_array = new Float32Array(buffer);"); mActivityTestRule.executeJavaScript("float32_array[0] = 42.0;"); @@ -1168,8 +1135,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassFloat64Array(boolean useMojo) throws Throwable { + public void testPassFloat64Array() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(8);"); mActivityTestRule.executeJavaScript("float64_array = new Float64Array(buffer);"); mActivityTestRule.executeJavaScript("float64_array[0] = 42.0;");
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java index 9794614..24ef476 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java
@@ -14,11 +14,7 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.chromium.base.test.params.BaseJUnit4RunnerDelegate; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterizedRunner; +import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.Feature; import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller; @@ -26,15 +22,12 @@ /** * Part of the test suite for the Java Bridge. This class tests the general use of arrays. * - * The conversions should follow - * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in - * which the implementation differs from the spec are marked with - * LIVECONNECT_COMPLIANCE. - * FIXME: Consider making our implementation more compliant, if it will not - * break backwards-compatibility. See b/4408210. + * <p>The conversions should follow http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. + * Places in which the implementation differs from the spec are marked with LIVECONNECT_COMPLIANCE. + * FIXME: Consider making our implementation more compliant, if it will not break + * backwards-compatibility. See b/4408210. */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class) +@RunWith(BaseJUnit4ClassRunner.class) @Batch(JavaBridgeActivityTestRule.BATCH) public class JavaBridgeArrayTest { @Rule public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule(); @@ -115,11 +108,6 @@ } } - @UseMethodParameterBefore(JavaBridgeActivityTestRule.MojoTestParams.class) - public void setupMojoTest(boolean useMojo) { - mActivityTestRule.setupMojoTest(useMojo); - } - private TestObject mTestObject; @Before @@ -131,8 +119,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testArrayLength(boolean useMojo) throws Throwable { + public void testArrayLength() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setIntArray([42, 43, 44]);"); int[] result = mTestObject.waitForIntArray(); Assert.assertEquals(3, result.length); @@ -144,8 +131,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNull(boolean useMojo) throws Throwable { + public void testPassNull() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setIntArray(null);"); Assert.assertNull(mTestObject.waitForIntArray()); } @@ -153,8 +139,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassUndefined(boolean useMojo) throws Throwable { + public void testPassUndefined() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setIntArray(undefined);"); Assert.assertNull(mTestObject.waitForIntArray()); } @@ -162,8 +147,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassEmptyArray(boolean useMojo) throws Throwable { + public void testPassEmptyArray() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setIntArray([]);"); Assert.assertEquals(0, mTestObject.waitForIntArray().length); } @@ -173,8 +157,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassArrayToStringMethod(boolean useMojo) throws Throwable { + public void testPassArrayToStringMethod() throws Throwable { // LIVECONNECT_COMPLIANCE: Should call toString() on array. mActivityTestRule.executeJavaScript("testObject.setStringValue([42, 42, 42]);"); Assert.assertEquals("undefined", mTestObject.waitForStringValue()); @@ -185,8 +168,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassArrayToNonStringNonArrayMethod(boolean useMojo) throws Throwable { + public void testPassArrayToNonStringNonArrayMethod() throws Throwable { // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception. mActivityTestRule.executeJavaScript("testObject.setIntValue([42, 42, 42]);"); Assert.assertEquals(0, mTestObject.waitForIntValue()); @@ -195,8 +177,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNonArrayToArrayMethod(boolean useMojo) throws Throwable { + public void testPassNonArrayToArrayMethod() throws Throwable { // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception. mActivityTestRule.executeJavaScript("testObject.setIntArray(42);"); Assert.assertNull(mTestObject.waitForIntArray()); @@ -205,8 +186,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testObjectWithLengthProperty(boolean useMojo) throws Throwable { + public void testObjectWithLengthProperty() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setIntArray({length: 3, 1: 42});"); int[] result = mTestObject.waitForIntArray(); Assert.assertEquals(3, result.length); @@ -218,8 +198,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testNonNumericLengthProperty(boolean useMojo) throws Throwable { + public void testNonNumericLengthProperty() throws Throwable { // LIVECONNECT_COMPLIANCE: This should not count as an array, so we // should raise a JavaScript exception. mActivityTestRule.executeJavaScript("testObject.setIntArray({length: \"foo\"});"); @@ -229,8 +208,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testLengthOutOfBounds(boolean useMojo) throws Throwable { + public void testLengthOutOfBounds() throws Throwable { // LIVECONNECT_COMPLIANCE: This should not count as an array, so we // should raise a JavaScript exception. mActivityTestRule.executeJavaScript("testObject.setIntArray({length: -1});"); @@ -252,8 +230,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testSparseArray(boolean useMojo) throws Throwable { + public void testSparseArray() throws Throwable { mActivityTestRule.executeJavaScript( "var x = [42, 43]; x[3] = 45; testObject.setIntArray(x);"); int[] result = mTestObject.waitForIntArray(); @@ -269,8 +246,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testMethodReturningArrayNotCalled(boolean useMojo) throws Throwable { + public void testMethodReturningArrayNotCalled() throws Throwable { // We don't invoke methods which return arrays, but note that no // exception is raised. // LIVECONNECT_COMPLIANCE: Should call method and convert result to @@ -284,8 +260,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testMultiDimensionalArrayMethod(boolean useMojo) throws Throwable { + public void testMultiDimensionalArrayMethod() throws Throwable { // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays. mActivityTestRule.executeJavaScript("testObject.setIntIntArray([ [42, 43], [44, 45] ]);"); Assert.assertNull(mTestObject.waitForIntIntArray()); @@ -294,8 +269,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassMultiDimensionalArray(boolean useMojo) throws Throwable { + public void testPassMultiDimensionalArray() throws Throwable { // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays. mActivityTestRule.executeJavaScript("testObject.setIntArray([ [42, 43], [44, 45] ]);"); int[] result = mTestObject.waitForIntArray(); @@ -310,8 +284,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassArrayBuffer(boolean useMojo) throws Throwable { + public void testPassArrayBuffer() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(16);"); mActivityTestRule.executeJavaScript("testObject.setIntArray(buffer);"); Assert.assertNull(mTestObject.waitForIntArray()); @@ -326,8 +299,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassDataView(boolean useMojo) throws Throwable { + public void testPassDataView() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(16);"); mActivityTestRule.executeJavaScript("testObject.setIntArray(new DataView(buffer));"); Assert.assertNull(mTestObject.waitForIntArray());
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java index 5bc3c94..08229e9 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java
@@ -11,31 +11,19 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.chromium.base.test.params.BaseJUnit4RunnerDelegate; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterizedRunner; +import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.Feature; import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer; import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper; /** Common functionality for testing the Java Bridge. */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class) +@RunWith(BaseJUnit4ClassRunner.class) @Batch(JavaBridgeActivityTestRule.BATCH) public class JavaBridgeBareboneTest { @Rule public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule(); private TestCallbackHelperContainer mTestCallbackHelperContainer; - private boolean mUseMojo; - - @UseMethodParameterBefore(JavaBridgeActivityTestRule.MojoTestParams.class) - public void setupMojoTest(boolean useMojo) { - mUseMojo = useMojo; - mActivityTestRule.setupMojoTest(useMojo); - } private void injectDummyObject(final String name) throws Throwable { mActivityTestRule.runOnUiThread( @@ -43,7 +31,7 @@ @Override public void run() { mActivityTestRule - .getJavascriptInjector(mUseMojo) + .getJavascriptInjector() .addPossiblyUnsafeInterface(new Object(), name, null); } }); @@ -70,8 +58,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testImmediateAddition(boolean useMojo) throws Throwable { + public void testImmediateAddition() throws Throwable { injectDummyObject("testObject"); Assert.assertEquals("\"object\"", evaluateJsSync("typeof testObject")); } @@ -81,8 +68,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testNoImmediateAdditionAfterJSEvaluation(boolean useMojo) throws Throwable { + public void testNoImmediateAdditionAfterJSEvaluation() throws Throwable { evaluateJsSync("true"); injectDummyObject("testObject"); Assert.assertEquals("\"undefined\"", evaluateJsSync("typeof testObject")); @@ -91,8 +77,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testImmediateAdditionAfterReload(boolean useMojo) throws Throwable { + public void testImmediateAdditionAfterReload() throws Throwable { mActivityTestRule.synchronousPageReload(); injectDummyObject("testObject"); Assert.assertEquals("\"object\"", evaluateJsSync("typeof testObject")); @@ -101,8 +86,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testReloadAfterAddition(boolean useMojo) throws Throwable { + public void testReloadAfterAddition() throws Throwable { injectDummyObject("testObject"); mActivityTestRule.synchronousPageReload(); Assert.assertEquals("\"object\"", evaluateJsSync("typeof testObject"));
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java index cabc8deb7..d68d4d0 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
@@ -17,16 +17,12 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterizedRunner; +import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller; import org.chromium.content_public.browser.LoadUrlParams; -import org.chromium.content_public.browser.test.ContentJUnit4RunnerDelegate; import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer; import java.lang.annotation.ElementType; @@ -37,19 +33,12 @@ import java.util.concurrent.CountDownLatch; /** - * Part of the test suite for the Java Bridge. Tests a number of features including ... - * - The type of injected objects - * - The type of their methods - * - Replacing objects - * - Removing objects - * - Access control - * - Calling methods on returned objects - * - Multiply injected objects - * - Threading - * - Inheritance + * Part of the test suite for the Java Bridge. Tests a number of features including ... - The type + * of injected objects - The type of their methods - Replacing objects - Removing objects - Access + * control - Calling methods on returned objects - Multiply injected objects - Threading - + * Inheritance */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(ContentJUnit4RunnerDelegate.class) +@RunWith(BaseJUnit4ClassRunner.class) @Batch(JavaBridgeActivityTestRule.BATCH) public class JavaBridgeBasicsTest { @Rule public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule(); @@ -116,11 +105,6 @@ } } - @UseMethodParameterBefore(JavaBridgeActivityTestRule.MojoTestParams.class) - public void setupMojoTest(boolean useMojo) { - mActivityTestRule.setupMojoTest(useMojo); - } - TestController mTestController; @Before @@ -160,16 +144,14 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testTypeOfInjectedObject(boolean useMojo) throws Throwable { + public void testTypeOfInjectedObject() throws Throwable { Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController")); } @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testAdditionNotReflectedUntilReload(boolean useMojo) throws Throwable { + public void testAdditionNotReflectedUntilReload() throws Throwable { Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); InstrumentationRegistry.getInstrumentation() .runOnMainSync( @@ -177,7 +159,7 @@ @Override public void run() { mActivityTestRule - .getJavascriptInjector(useMojo) + .getJavascriptInjector() .addPossiblyUnsafeInterface( new Object(), "testObject", null); } @@ -190,8 +172,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testReplaceWithoutReloading(boolean useMojo) throws Throwable { + public void testReplaceWithoutReloading() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { @JavascriptInterface @@ -209,7 +190,7 @@ @Override public void run() { mActivityTestRule - .getJavascriptInjector(useMojo) + .getJavascriptInjector() .addPossiblyUnsafeInterface( new Object() { @JavascriptInterface @@ -232,8 +213,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testRemovalNotReflectedUntilReload(boolean useMojo) throws Throwable { + public void testRemovalNotReflectedUntilReload() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { @JavascriptInterface @@ -251,7 +231,7 @@ @Override public void run() { mActivityTestRule - .getJavascriptInjector(useMojo) + .getJavascriptInjector() .removeInterface("testObject"); } }); @@ -269,8 +249,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testRemoveObjectNotAdded(boolean useMojo) throws Throwable { + public void testRemoveObjectNotAdded() throws Throwable { TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = mActivityTestRule.getTestCallBackHelperContainer().getOnPageFinishedHelper(); int currentCallCount = onPageFinishedHelper.getCallCount(); @@ -279,9 +258,7 @@ new Runnable() { @Override public void run() { - mActivityTestRule - .getJavascriptInjector(useMojo) - .removeInterface("foo"); + mActivityTestRule.getJavascriptInjector().removeInterface("foo"); mActivityTestRule .getWebContents() .getNavigationController() @@ -295,8 +272,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testTypeOfMethod(boolean useMojo) throws Throwable { + public void testTypeOfMethod() throws Throwable { Assert.assertEquals( "function", executeJavaScriptAndGetStringResult("typeof testController.setStringValue")); @@ -305,8 +281,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testTypeOfInvalidMethod(boolean useMojo) throws Throwable { + public void testTypeOfInvalidMethod() throws Throwable { Assert.assertEquals( "undefined", executeJavaScriptAndGetStringResult("typeof testController.foo")); } @@ -314,17 +289,14 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testCallingInvalidMethodRaisesException(boolean useMojo) throws Throwable { + public void testCallingInvalidMethodRaisesException() throws Throwable { assertRaisesException("testController.foo()"); } @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testUncaughtJavaExceptionRaisesJavaScriptException(boolean useMojo) - throws Throwable { + public void testUncaughtJavaExceptionRaisesJavaScriptException() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { @JavascriptInterface @@ -339,24 +311,21 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testCallingAsConstructorRaisesException(boolean useMojo) throws Throwable { + public void testCallingAsConstructorRaisesException() throws Throwable { assertRaisesException("new testController.setStringValue('foo')"); } @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testCallingOnNonInjectedObjectRaisesException(boolean useMojo) throws Throwable { + public void testCallingOnNonInjectedObjectRaisesException() throws Throwable { assertRaisesException("testController.setStringValue.call({}, 'foo')"); } @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testCallingOnInstanceOfOtherClassRaisesException(boolean useMojo) throws Throwable { + public void testCallingOnInstanceOfOtherClassRaisesException() throws Throwable { mActivityTestRule.injectObjectAndReload(new Object(), "testObject"); Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController")); @@ -370,8 +339,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testTypeOfStaticMethod(boolean useMojo) throws Throwable { + public void testTypeOfStaticMethod() throws Throwable { mActivityTestRule.injectObjectAndReload(new ObjectWithStaticMethod(), "testObject"); mActivityTestRule.executeJavaScript( "testController.setStringValue(typeof testObject.staticMethod)"); @@ -382,8 +350,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testCallStaticMethod(boolean useMojo) throws Throwable { + public void testCallStaticMethod() throws Throwable { mActivityTestRule.injectObjectAndReload(new ObjectWithStaticMethod(), "testObject"); mActivityTestRule.executeJavaScript( "testController.setStringValue(testObject.staticMethod())"); @@ -393,8 +360,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testPrivateMethodNotExposed(boolean useMojo) throws Throwable { + public void testPrivateMethodNotExposed() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { private void method() {} @@ -421,8 +387,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testReplaceInjectedObject(boolean useMojo) throws Throwable { + public void testReplaceInjectedObject() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { @JavascriptInterface @@ -449,8 +414,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testInjectNullObjectIsIgnored(boolean useMojo) throws Throwable { + public void testInjectNullObjectIsIgnored() throws Throwable { mActivityTestRule.injectObjectAndReload(null, "testObject"); Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); } @@ -458,8 +422,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testReplaceInjectedObjectWithNullObjectIsIgnored(boolean useMojo) throws Throwable { + public void testReplaceInjectedObjectWithNullObjectIsIgnored() throws Throwable { mActivityTestRule.injectObjectAndReload(new Object(), "testObject"); Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); mActivityTestRule.injectObjectAndReload(null, "testObject"); @@ -469,9 +432,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testCallOverloadedMethodWithDifferentNumberOfArguments(boolean useMojo) - throws Throwable { + public void testCallOverloadedMethodWithDifferentNumberOfArguments() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { @JavascriptInterface @@ -505,9 +466,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testCallMethodWithWrongNumberOfArgumentsRaisesException(boolean useMojo) - throws Throwable { + public void testCallMethodWithWrongNumberOfArgumentsRaisesException() throws Throwable { assertRaisesException("testController.setIntValue()"); assertRaisesException("testController.setIntValue(42, 42)"); } @@ -515,8 +474,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testObjectPersistsAcrossPageLoads(boolean useMojo) throws Throwable { + public void testObjectPersistsAcrossPageLoads() throws Throwable { Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController")); mActivityTestRule.synchronousPageReload(); Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController")); @@ -525,8 +483,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testCustomPropertiesCleanedUpOnPageReloads(boolean useMojo) throws Throwable { + public void testCustomPropertiesCleanedUpOnPageReloads() throws Throwable { Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController")); mActivityTestRule.executeJavaScript("testController.myProperty = 42;"); Assert.assertEquals("42", executeJavaScriptAndGetStringResult("testController.myProperty")); @@ -539,8 +496,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testSameObjectInjectedMultipleTimes(boolean useMojo) throws Throwable { + public void testSameObjectInjectedMultipleTimes() throws Throwable { class TestObject { private int mNumMethodInvocations; @@ -560,8 +516,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testCallMethodOnReturnedObject(boolean useMojo) throws Throwable { + public void testCallMethodOnReturnedObject() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { @JavascriptInterface @@ -582,8 +537,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testReturnedObjectInjectedElsewhere(boolean useMojo) throws Throwable { + public void testReturnedObjectInjectedElsewhere() throws Throwable { class InnerObject { private int mNumMethodInvocations; @@ -616,8 +570,7 @@ @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) @CommandLineFlags.Add("js-flags=--expose-gc") - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testReturnedObjectIsGarbageCollected(boolean useMojo) throws Throwable { + public void testReturnedObjectIsGarbageCollected() throws Throwable { Assert.assertEquals("function", executeJavaScriptAndGetStringResult("typeof gc")); class InnerObject {} class TestObject { @@ -665,8 +618,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testSameReturnedObjectUsesSameWrapper(boolean useMojo) throws Throwable { + public void testSameReturnedObjectUsesSameWrapper() throws Throwable { class InnerObject {} final InnerObject innerObject = new InnerObject(); final Object injectedTestObject = @@ -688,8 +640,7 @@ @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) @CommandLineFlags.Add("js-flags=--expose-gc") - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testSameWrapperObjectsAreGarbageCollected(boolean useMojo) throws Throwable { + public void testSameWrapperObjectsAreGarbageCollected() throws Throwable { class InnerObject {} class TestObject { @JavascriptInterface @@ -705,7 +656,6 @@ // A weak reference is used to check InnerObject instance reachability. WeakReference<InnerObject> mWeakForInnerObject; } - ; final TestObject injectedTestObject = new TestObject(); mActivityTestRule.injectObjectAndReload(injectedTestObject, "injectedTestObject"); @@ -738,8 +688,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testMethodInvokedOnBackgroundThread(boolean useMojo) throws Throwable { + public void testMethodInvokedOnBackgroundThread() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { @JavascriptInterface @@ -764,8 +713,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testBlockingUiThreadDoesNotBlockCallsFromJs(boolean useMojo) { + public void testBlockingUiThreadDoesNotBlockCallsFromJs() { class TestObject { private CountDownLatch mLatch; @@ -815,8 +763,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testPublicInheritedMethod(boolean useMojo) throws Throwable { + public void testPublicInheritedMethod() throws Throwable { class Base { @JavascriptInterface public void method(int x) { @@ -834,8 +781,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testPrivateInheritedMethod(boolean useMojo) throws Throwable { + public void testPrivateInheritedMethod() throws Throwable { class Base { @JavascriptInterface private void method() {} @@ -849,8 +795,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testOverriddenMethod(boolean useMojo) throws Throwable { + public void testOverriddenMethod() throws Throwable { class Base { @JavascriptInterface public void method() { @@ -872,8 +817,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testEnumerateMembers(boolean useMojo) throws Throwable { + public void testEnumerateMembers() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { public void method() {} @@ -897,8 +841,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testReflectPublicMethod(boolean useMojo) throws Throwable { + public void testReflectPublicMethod() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { public Class<?> myGetClass() { @@ -921,8 +864,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testReflectPublicField(boolean useMojo) throws Throwable { + public void testReflectPublicField() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { public Class<?> myGetClass() { @@ -942,8 +884,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testReflectPrivateMethodRaisesException(boolean useMojo) throws Throwable { + public void testReflectPrivateMethodRaisesException() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { public Class<?> myGetClass() { @@ -966,8 +907,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testReflectPrivateFieldRaisesException(boolean useMojo) throws Throwable { + public void testReflectPrivateFieldRaisesException() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { @JavascriptInterface @@ -991,8 +931,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testAllowNonAnnotatedMethods(boolean useMojo) throws Throwable { + public void testAllowNonAnnotatedMethods() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { @JavascriptInterface @@ -1014,8 +953,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testAllowOnlyAnnotatedMethods(boolean useMojo) throws Throwable { + public void testAllowOnlyAnnotatedMethods() throws Throwable { mActivityTestRule.injectObjectAndReload( new Object() { @JavascriptInterface @@ -1050,9 +988,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testAnnotationRequirementRetainsPropertyAcrossObjects(boolean useMojo) - throws Throwable { + public void testAnnotationRequirementRetainsPropertyAcrossObjects() throws Throwable { class Test { @JavascriptInterface public String safe() { @@ -1104,8 +1040,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testAnnotationDoesNotGetInherited(boolean useMojo) throws Throwable { + public void testAnnotationDoesNotGetInherited() throws Throwable { class Base { @JavascriptInterface public void base() {} @@ -1134,8 +1069,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testCustomAnnotationRestriction(boolean useMojo) throws Throwable { + public void testCustomAnnotationRestriction() throws Throwable { class Test { @TestAnnotation public String checkTestAnnotationFoo() { @@ -1185,8 +1119,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testObjectsInspection(boolean useMojo) throws Throwable { + public void testObjectsInspection() throws Throwable { class Test { @JavascriptInterface public String m1() { @@ -1230,9 +1163,7 @@ new Runnable() { @Override public void run() { - mActivityTestRule - .getJavascriptInjector(useMojo) - .setAllowInspection(false); + mActivityTestRule.getJavascriptInjector().setAllowInspection(false); } }); @@ -1252,8 +1183,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testAccessToObjectGetClassIsBlocked(boolean useMojo) throws Throwable { + public void testAccessToObjectGetClassIsBlocked() throws Throwable { mActivityTestRule.injectObjectAndReload(new Object(), "testObject", null); Assert.assertEquals( "function", executeJavaScriptAndGetStringResult("typeof testObject.getClass")); @@ -1263,8 +1193,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testReplaceJavascriptInterface(boolean useMojo) throws Throwable { + public void testReplaceJavascriptInterface() throws Throwable { class Test { public Test(int value) { mValue = value; @@ -1289,8 +1218,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testMethodCalledOnAnotherInstance(boolean useMojo) throws Throwable { + public void testMethodCalledOnAnotherInstance() throws Throwable { class TestObject { private int mIndex; @@ -1320,8 +1248,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testWebViewAfterRenderViewSwapped(boolean useMojo) throws Throwable { + public void testWebViewAfterRenderViewSwapped() throws Throwable { class TestObject { private int mIndex;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java index 28d66459..55cea22f 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
@@ -15,10 +15,7 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterizedRunner; +import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisabledTest; @@ -28,7 +25,6 @@ import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.WebContents; -import org.chromium.content_public.browser.test.ContentJUnit4RunnerDelegate; import java.lang.ref.WeakReference; import java.util.concurrent.CountDownLatch; @@ -38,11 +34,9 @@ /** * Part of the test suite for the WebView's Java Bridge. * - * Ensures that injected objects are exposed to child frames as well as the - * main frame. + * <p>Ensures that injected objects are exposed to child frames as well as the main frame. */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(ContentJUnit4RunnerDelegate.class) +@RunWith(BaseJUnit4ClassRunner.class) @Batch(JavaBridgeActivityTestRule.BATCH) public class JavaBridgeChildFrameTest { @Rule public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule(); @@ -63,11 +57,6 @@ } } - @UseMethodParameterBefore(JavaBridgeActivityTestRule.MojoTestParams.class) - public void setupMojoTest(boolean useMojo) { - mActivityTestRule.setupMojoTest(useMojo); - } - TestController mTestController; @Before @@ -76,12 +65,10 @@ mActivityTestRule.injectObjectAndReload(mTestController, "testController"); } - // TODO(crbug.com/40144856): Fix flakiness when using MojoTestParams. @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testInjectedObjectPresentInChildFrame(boolean useMojo) throws Throwable { + public void testInjectedObjectPresentInChildFrame() throws Throwable { loadDataSync( mActivityTestRule.getWebContents().getNavigationController(), "<html><body><iframe></iframe></body></html>", @@ -105,8 +92,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testMainPageWrapperIsNotBrokenByChildFrame(boolean useMojo) throws Throwable { + public void testMainPageWrapperIsNotBrokenByChildFrame() throws Throwable { loadDataSync( mActivityTestRule.getWebContents().getNavigationController(), "<html><body><iframe></iframe></body></html>", @@ -131,12 +117,10 @@ // Verify that parent page and child frame each has own JS wrapper object. // Failing to do so exposes parent's context to the child. - // TODO(crbug.com/40144856): Fix flakiness when using MojoTestParams. @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class) - public void testWrapperIsNotSharedWithChildFrame(boolean useMojo) throws Throwable { + public void testWrapperIsNotSharedWithChildFrame() throws Throwable { // Test by setting a custom property on the parent page's injected // object and then checking that child frame doesn't see the property. loadDataSync( @@ -169,8 +153,7 @@ @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) @DisabledTest(message = "https://crbug.com/677053") - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testRemovingTransientObjectHolders(boolean useMojo) throws Throwable { + public void testRemovingTransientObjectHolders() throws Throwable { class Test { private Object mInner = new Object(); // Expecting the inner object to be retrieved twice. @@ -241,8 +224,7 @@ @Feature({"AndroidWebView", "Android-JavaBridge"}) @CommandLineFlags.Add("js-flags=--expose-gc") @DisabledTest(message = "https://crbug.com/646843") - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testHolderFrame(boolean useMojo) throws Throwable { + public void testHolderFrame() throws Throwable { class Test { WeakReference<Object> mWeakRefForInner; private CountDownLatch mLatch = new CountDownLatch(1);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java index 6d57eb49..1ed48ba 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java
@@ -14,11 +14,7 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.chromium.base.test.params.BaseJUnit4RunnerDelegate; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterizedRunner; +import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.UrlUtils; @@ -27,19 +23,15 @@ import java.io.File; /** - * Part of the test suite for the Java Bridge. This class tests that - * we correctly convert JavaScript values to Java values when passing them to - * the methods of injected Java objects. + * Part of the test suite for the Java Bridge. This class tests that we correctly convert JavaScript + * values to Java values when passing them to the methods of injected Java objects. * - * The conversions should follow - * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in - * which the implementation differs from the spec are marked with - * LIVECONNECT_COMPLIANCE. - * FIXME: Consider making our implementation more compliant, if it will not - * break backwards-compatibility. See b/4408210. + * <p>The conversions should follow http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. + * Places in which the implementation differs from the spec are marked with LIVECONNECT_COMPLIANCE. + * FIXME: Consider making our implementation more compliant, if it will not break + * backwards-compatibility. See b/4408210. */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class) +@RunWith(BaseJUnit4ClassRunner.class) @Batch(JavaBridgeActivityTestRule.BATCH) public class JavaBridgeCoercionTest { private static final double ASSERTION_DELTA = 0; @@ -197,11 +189,6 @@ private static class CustomType2 {} - @UseMethodParameterBefore(JavaBridgeActivityTestRule.MojoTestParams.class) - public void setupMojoTest(boolean useMojo) { - mActivityTestRule.setupMojoTest(useMojo); - } - private TestObject mTestObject; private static class TestController extends Controller { @@ -248,8 +235,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNumberInt32(boolean useMojo) throws Throwable { + public void testPassNumberInt32() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setByteValue(42);"); Assert.assertEquals(42, mTestObject.waitForByteValue()); mActivityTestRule.executeJavaScript( @@ -302,8 +288,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNumberDouble(boolean useMojo) throws Throwable { + public void testPassNumberDouble() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setByteValue(42.1);"); Assert.assertEquals(42, mTestObject.waitForByteValue()); mActivityTestRule.executeJavaScript( @@ -392,8 +377,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNumberNaN(boolean useMojo) throws Throwable { + public void testPassNumberNaN() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setByteValue(Number.NaN);"); Assert.assertEquals(0, mTestObject.waitForByteValue()); @@ -434,8 +418,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNumberInfinity(boolean useMojo) throws Throwable { + public void testPassNumberInfinity() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setByteValue(Infinity);"); Assert.assertEquals(-1, mTestObject.waitForByteValue()); @@ -479,8 +462,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassBoolean(boolean useMojo) throws Throwable { + public void testPassBoolean() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setBooleanValue(true);"); Assert.assertTrue(mTestObject.waitForBooleanValue()); mActivityTestRule.executeJavaScript("testObject.setBooleanValue(false);"); @@ -546,8 +528,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassString(boolean useMojo) throws Throwable { + public void testPassString() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setStringValue(\"+042.10\");"); Assert.assertEquals("+042.10", mTestObject.waitForStringValue()); @@ -600,8 +581,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassJavaScriptObject(boolean useMojo) throws Throwable { + public void testPassJavaScriptObject() throws Throwable { // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. mActivityTestRule.executeJavaScript("testObject.setObjectValue({foo: 42});"); Assert.assertNull(mTestObject.waitForObjectValue()); @@ -653,8 +633,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassJavaObject(boolean useMojo) throws Throwable { + public void testPassJavaObject() throws Throwable { mActivityTestRule.executeJavaScript( "testObject.setObjectValue(testObject.getObjectInstance());"); Assert.assertTrue(mTestObject.getObjectInstance() == mTestObject.waitForObjectValue()); @@ -733,8 +712,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassJavaObjectFromCustomClassLoader(boolean useMojo) throws Throwable { + public void testPassJavaObjectFromCustomClassLoader() throws Throwable { // Compiled bytecode (dex) for the following class: // // package org.example; @@ -764,7 +742,7 @@ @Override public void run() { mActivityTestRule - .getJavascriptInjector(useMojo) + .getJavascriptInjector() .addPossiblyUnsafeInterface(selfConsuming, "selfConsuming", null); } }); @@ -779,8 +757,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassNull(boolean useMojo) throws Throwable { + public void testPassNull() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setObjectValue(null);"); Assert.assertNull(mTestObject.waitForObjectValue()); @@ -819,8 +796,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassUndefined(boolean useMojo) throws Throwable { + public void testPassUndefined() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setObjectValue(undefined);"); Assert.assertNull(mTestObject.waitForObjectValue()); @@ -861,8 +837,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassArrayBuffer(boolean useMojo) throws Throwable { + public void testPassArrayBuffer() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(16);"); mActivityTestRule.executeJavaScript("testObject.setObjectValue(buffer);"); @@ -879,8 +854,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassDataView(boolean useMojo) throws Throwable { + public void testPassDataView() throws Throwable { mActivityTestRule.executeJavaScript("buffer = new ArrayBuffer(16);"); mActivityTestRule.executeJavaScript("testObject.setObjectValue(new DataView(buffer));"); @@ -894,8 +868,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassDateObject(boolean useMojo) throws Throwable { + public void testPassDateObject() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setDoubleValue(new Date(2000, 0, 1));"); Assert.assertEquals(0.0, mTestObject.waitForDoubleValue(), ASSERTION_DELTA); @@ -910,8 +883,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassRegExpObject(boolean useMojo) throws Throwable { + public void testPassRegExpObject() throws Throwable { mActivityTestRule.executeJavaScript("testObject.setStringValue(/abc/);"); Assert.assertEquals("undefined", mTestObject.waitForStringValue()); @@ -923,8 +895,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testPassFunctionObject(boolean useMojo) throws Throwable { + public void testPassFunctionObject() throws Throwable { mActivityTestRule.executeJavaScript("func = new Function('a', 'b', 'return a + b');"); mActivityTestRule.executeJavaScript("testObject.setStringValue(func);");
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java index fe106b1..c420a2d 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java
@@ -14,21 +14,13 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.chromium.base.test.params.BaseJUnit4RunnerDelegate; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterizedRunner; +import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.Feature; import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller; -/** - * Part of the test suite for the Java Bridge. This test tests the - * use of fields. - */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class) +/** Part of the test suite for the Java Bridge. This test tests the use of fields. */ +@RunWith(BaseJUnit4ClassRunner.class) @Batch(JavaBridgeActivityTestRule.BATCH) public class JavaBridgeFieldsTest { @Rule public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule(); @@ -65,11 +57,6 @@ // A custom type used when testing passing objects. private static class CustomType {} - @UseMethodParameterBefore(JavaBridgeActivityTestRule.MojoTestParams.class) - public void setupMojoTest(boolean useMojo) { - mActivityTestRule.setupMojoTest(useMojo); - } - TestObject mTestObject; @Before @@ -89,8 +76,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testFieldTypes(boolean useMojo) throws Throwable { + public void testFieldTypes() throws Throwable { Assert.assertEquals( "undefined", executeJavaScriptAndGetStringResult("typeof testObject.booleanField")); Assert.assertEquals(
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java index 386b9d1..be7d6ac 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java
@@ -14,11 +14,7 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.chromium.base.test.params.BaseJUnit4RunnerDelegate; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterizedRunner; +import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.Feature; import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller; @@ -27,15 +23,12 @@ * Part of the test suite for the Java Bridge. This test checks that we correctly convert Java * values to JavaScript values when returning them from the methods of injected Java objects. * - * The conversions should follow - * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in - * which the implementation differs from the spec are marked with - * LIVECONNECT_COMPLIANCE. - * FIXME: Consider making our implementation more compliant, if it will not - * break backwards-compatibility. See b/4408210. + * <p>The conversions should follow http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. + * Places in which the implementation differs from the spec are marked with LIVECONNECT_COMPLIANCE. + * FIXME: Consider making our implementation more compliant, if it will not break + * backwards-compatibility. See b/4408210. */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class) +@RunWith(BaseJUnit4ClassRunner.class) @Batch(JavaBridgeActivityTestRule.BATCH) public class JavaBridgeReturnValuesTest { @Rule public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule(); @@ -156,11 +149,6 @@ // A custom type used when testing passing objects. private static class CustomType {} - @UseMethodParameterBefore(JavaBridgeActivityTestRule.MojoTestParams.class) - public void setupMojoTest(boolean useMojo) { - mActivityTestRule.setupMojoTest(useMojo); - } - TestObject mTestObject; @Before @@ -184,8 +172,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testMethodReturnTypes(boolean useMojo) throws Throwable { + public void testMethodReturnTypes() throws Throwable { Assert.assertEquals( "boolean", executeJavaScriptAndGetStringResult("typeof testObject.getBooleanValue()")); @@ -238,8 +225,7 @@ @Test @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) - @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class) - public void testMethodReturnValues(boolean useMojo) throws Throwable { + public void testMethodReturnValues() throws Throwable { // We do the string comparison in JavaScript, to avoid relying on the // coercion algorithm from JavaScript to Java. Assert.assertTrue(executeJavaScriptAndGetBooleanResult("testObject.getBooleanValue()"));
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/DIR_METADATA b/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/DIR_METADATA deleted file mode 100644 index a1576e2b..0000000 --- a/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/DIR_METADATA +++ /dev/null
@@ -1 +0,0 @@ -mixins: "//content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA"
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/OWNERS b/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/OWNERS deleted file mode 100644 index 52fd0ad..0000000 --- a/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -file://content/public/android/java/src/org/chromium/content/browser/remoteobjects/OWNERS
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImplTest.java deleted file mode 100644 index 964a73dd..0000000 --- a/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImplTest.java +++ /dev/null
@@ -1,187 +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. - -package org.chromium.content.browser.remoteobjects; - -import static org.hamcrest.Matchers.isIn; -import static org.hamcrest.Matchers.not; - -import androidx.test.filters.SmallTest; - -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.chromium.base.test.BaseJUnit4ClassRunner; -import org.chromium.base.test.util.Feature; -import org.chromium.blink.mojom.RemoteObject; -import org.chromium.mojo.MojoTestRule; -import org.chromium.mojo.bindings.ConnectionErrorHandler; -import org.chromium.mojo.bindings.InterfaceRequest; -import org.chromium.mojo.system.MojoException; -import org.chromium.mojo.system.Pair; -import org.chromium.mojo.system.impl.CoreImpl; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.HashSet; -import java.util.Set; - -/** - * Tests the Mojo interface which vends RemoteObject interface handles. - * Ensures that the provided handles are properly bound. - */ -@RunWith(BaseJUnit4ClassRunner.class) -public final class RemoteObjectHostImplTest { - @Rule public MojoTestRule mMojoTestRule = new MojoTestRule(MojoTestRule.MojoCore.INITIALIZE); - - private final Set<RemoteObjectRegistry> mRetainingSet = new HashSet<>(); - private final RemoteObjectRegistry mRegistry = new RemoteObjectRegistry(mRetainingSet); - - /** - * Annotation which can be used in the way that {@link android.webkit.JavascriptInterface} - * would. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD}) - private @interface TestJavascriptInterface {} - - /** {@link ConnectionErrorHandler} that records any error it received. */ - private static class CapturingErrorHandler implements ConnectionErrorHandler { - private MojoException mLastMojoException; - - /** - * @see ConnectionErrorHandler#onConnectionError(MojoException) - */ - @Override - public void onConnectionError(MojoException e) { - mLastMojoException = e; - } - - /** Returns the last recorded exception. */ - public MojoException getLastMojoException() { - return mLastMojoException; - } - } - - @Test - @SmallTest - @Feature({"AndroidWebView", "Android-JavaBridge"}) - public void testClosesPipeIfObjectDoesNotExist() { - RemoteObjectHostImpl host = - new RemoteObjectHostImpl( - /* auditor= */ null, mRegistry, /* allowInspection= */ true); - - Pair<RemoteObject.Proxy, InterfaceRequest<RemoteObject>> result = - RemoteObject.MANAGER.getInterfaceRequest(CoreImpl.getInstance()); - CapturingErrorHandler errorHandler = new CapturingErrorHandler(); - result.first.getProxyHandler().setErrorHandler(errorHandler); - host.getObject(123, result.second); - - mMojoTestRule.runLoopUntilIdle(); - Assert.assertNotNull(errorHandler.getLastMojoException()); - } - - /** - * Tiny utility to capture the result of using RemoteObject. - * - * This verifies that it is working correctly. - */ - private static class HasMethodCapture implements RemoteObject.HasMethod_Response { - public Boolean methodExists; - - @Override - public void call(boolean result) { - methodExists = result; - } - } - - @Test - @SmallTest - @Feature({"AndroidWebView", "Android-JavaBridge"}) - public void testBindsPipeIfObjectExists() { - Object o = - new Object() { - @TestJavascriptInterface - public void frobnicate() {} - }; - int id = mRegistry.getObjectId(o, TestJavascriptInterface.class); - - RemoteObjectHostImpl host = - new RemoteObjectHostImpl( - /* auditor= */ null, mRegistry, /* allowInspection= */ true); - - Pair<RemoteObject.Proxy, InterfaceRequest<RemoteObject>> result = - RemoteObject.MANAGER.getInterfaceRequest(CoreImpl.getInstance()); - RemoteObject.Proxy remoteObject = result.first; - CapturingErrorHandler errorHandler = new CapturingErrorHandler(); - remoteObject.getProxyHandler().setErrorHandler(errorHandler); - host.getObject(id, result.second); - - HasMethodCapture frobnicate = new HasMethodCapture(); - remoteObject.hasMethod("frobnicate", frobnicate); - HasMethodCapture nonExistentMethod = new HasMethodCapture(); - remoteObject.hasMethod("nonExistentMethod", nonExistentMethod); - - mMojoTestRule.runLoopUntilIdle(); - Assert.assertNull(errorHandler.getLastMojoException()); - Assert.assertEquals(true, frobnicate.methodExists); - Assert.assertEquals(false, nonExistentMethod.methodExists); - } - - @Test - @SmallTest - @Feature({"AndroidWebView", "Android-JavaBridge"}) - public void testRelease() { - Object o = new Object(); - int id = mRegistry.getObjectId(o, TestJavascriptInterface.class); - - RemoteObjectHostImpl host = - new RemoteObjectHostImpl( - /* auditor= */ null, mRegistry, /* allowInspection= */ true); - - Assert.assertSame(o, mRegistry.getObjectById(id)); - host.releaseObject(id); - Assert.assertNull(mRegistry.getObjectById(id)); - } - - @Test - @SmallTest - @Feature({"AndroidWebView", "Android-JavaBridge"}) - public void testClose() { - RemoteObjectHostImpl host = - new RemoteObjectHostImpl( - /* auditor= */ null, mRegistry, /* allowInspection= */ true); - Assert.assertThat(mRegistry, isIn(mRetainingSet)); - host.close(); - Assert.assertThat(mRegistry, not(isIn(mRetainingSet))); - } - - @Test - @SmallTest - @Feature({"AndroidWebView", "Android-JavaBridge"}) - public void testClosePipeAfterHostClosesWithoutRelease() { - Object o = new Object(); - int id = mRegistry.getObjectId(o, TestJavascriptInterface.class); - - RemoteObjectHostImpl host = - new RemoteObjectHostImpl( - /* auditor= */ null, mRegistry, /* allowInspection= */ true); - - Pair<RemoteObject.Proxy, InterfaceRequest<RemoteObject>> result = - RemoteObject.MANAGER.getInterfaceRequest(CoreImpl.getInstance()); - RemoteObject.Proxy remoteObject = result.first; - host.getObject(id, result.second); - host.close(); - - Assert.assertSame(o, mRegistry.getObjectById(id)); - remoteObject.close(); - - mMojoTestRule.runLoopUntilIdle(); - Assert.assertNull(mRegistry.getObjectById(id)); - } -}
diff --git a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/DIR_METADATA b/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/DIR_METADATA deleted file mode 100644 index a1576e2b..0000000 --- a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/DIR_METADATA +++ /dev/null
@@ -1 +0,0 @@ -mixins: "//content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA"
diff --git a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/OWNERS b/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/OWNERS deleted file mode 100644 index 52fd0ad..0000000 --- a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -file://content/public/android/java/src/org/chromium/content/browser/remoteobjects/OWNERS
diff --git a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java b/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java deleted file mode 100644 index a8dbd71..0000000 --- a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java +++ /dev/null
@@ -1,1216 +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. - -package org.chromium.content.browser.remoteobjects; - -import static org.mockito.AdditionalMatchers.and; -import static org.mockito.AdditionalMatchers.aryEq; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.BlockJUnit4ClassRunner; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import org.chromium.blink.mojom.RemoteArrayType; -import org.chromium.blink.mojom.RemoteInvocationArgument; -import org.chromium.blink.mojom.RemoteInvocationError; -import org.chromium.blink.mojom.RemoteInvocationResult; -import org.chromium.blink.mojom.RemoteInvocationResultValue; -import org.chromium.blink.mojom.RemoteObject; -import org.chromium.blink.mojom.RemoteTypedArray; -import org.chromium.blink.mojom.SingletonJavaScriptValue; -import org.chromium.mojo_base.BigBufferUtil; -import org.chromium.mojo_base.mojom.String16; - -import java.lang.annotation.Annotation; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.Arrays; -import java.util.function.Consumer; - -/** - * Tests the implementation of the Mojo object which wraps invocations - * of Java methods. - * - * Unchecked cast warnings are suppressed because {@link org.mockito.Mockito#mock(Class)} does not - * provide a way to cleanly deal with generics. - */ -@SuppressWarnings("unchecked") -@RunWith(BlockJUnit4ClassRunner.class) -public final class RemoteObjectImplTest { - /** - * Annotation which can be used in the way that {@link android.webkit.JavascriptInterface} - * would. - * - * A separate one is used to ensure that RemoteObject is actually respecting the parameter. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD}) - private @interface TestJavascriptInterface {} - - @Mock private RemoteObjectImpl.Auditor mAuditor; - - @Mock private RemoteObjectImpl.ObjectIdAllocator mIdAllocator; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testHasMethodWithSafeAnnotationClass() { - Object target = - new Object() { - @TestJavascriptInterface - public void exposedMethod() {} - - @TestJavascriptInterface - public void anotherExposedMethod() {} - - @TestJavascriptInterface - public void anotherExposedMethod(int x) {} - - @TestJavascriptInterface - private void privateAnnotatedMethod() {} - - public void unannotatedMethod() {} - }; - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.HasMethod_Response hasMethodResponse; - - // This method is public and annotated; it should be exposed. - hasMethodResponse = mock(RemoteObject.HasMethod_Response.class); - remoteObject.hasMethod("exposedMethod", hasMethodResponse); - verify(hasMethodResponse).call(true); - - // This method is private; it should not be exposed. - hasMethodResponse = mock(RemoteObject.HasMethod_Response.class); - remoteObject.hasMethod("privateAnnotatedMethod", hasMethodResponse); - verify(hasMethodResponse).call(false); - - // This method is not annotated; it should not be exposed. - hasMethodResponse = mock(RemoteObject.HasMethod_Response.class); - remoteObject.hasMethod("unannotatedMethod", hasMethodResponse); - verify(hasMethodResponse).call(false); - - // getMethods should provide a result consistent with this. - // The result must also be in sorted order and have no duplicates. - RemoteObject.GetMethods_Response getMethodsResponse = - mock(RemoteObject.GetMethods_Response.class); - remoteObject.getMethods(getMethodsResponse); - verify(getMethodsResponse) - .call(aryEq(new String[] {"anotherExposedMethod", "exposedMethod"})); - } - - @Test - public void testHasMethodWithoutSafeAnnotationClass() { - Object target = - new Object() { - @TestJavascriptInterface - public void annotatedMethod() {} - - public void unannotatedMethod() {} - }; - - RemoteObject remoteObject = newRemoteObjectImpl(target, null); - RemoteObject.HasMethod_Response hasMethodResponse; - - // This method has an annotation; it should be exposed. - hasMethodResponse = mock(RemoteObject.HasMethod_Response.class); - remoteObject.hasMethod("annotatedMethod", hasMethodResponse); - verify(hasMethodResponse).call(true); - - // This method doesn't, but passing null skips the check. - hasMethodResponse = mock(RemoteObject.HasMethod_Response.class); - remoteObject.hasMethod("unannotatedMethod", hasMethodResponse); - verify(hasMethodResponse).call(true); - - // getMethods should provide a result consistent with this. - // The result must also be in sorted order. - // Note that this includes all of the normal java.lang.Object methods. - RemoteObject.GetMethods_Response getMethodsResponse = - mock(RemoteObject.GetMethods_Response.class); - remoteObject.getMethods(getMethodsResponse); - - ArgumentCaptor<String[]> methodsCaptor = ArgumentCaptor.forClass(String[].class); - verify(getMethodsResponse).call(methodsCaptor.capture()); - String[] methods = methodsCaptor.getValue(); - Assert.assertTrue(Arrays.asList(methods).contains("annotatedMethod")); - Assert.assertTrue(Arrays.asList(methods).contains("unannotatedMethod")); - Assert.assertTrue(Arrays.asList(methods).contains("hashCode")); - String[] sortedMethods = Arrays.copyOf(methods, methods.length); - Arrays.sort(sortedMethods); - Assert.assertArrayEquals(sortedMethods, methods); - } - - @Test - public void testInvokeMethodBasic() { - final Runnable runnable = mock(Runnable.class); - Object target = - new Object() { - @TestJavascriptInterface - public void frobnicate() { - runnable.run(); - } - }; - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("frobnicate", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod("frobnicate", new RemoteInvocationArgument[] {}, response); - - verify(runnable, times(2)).run(); - verify(response, times(2)).call(resultIsOk()); - } - - @Test - public void testInvokeMethodOverloadUsingArity() { - final Consumer<Integer> consumer = (Consumer<Integer>) mock(Consumer.class); - Object target = - new Object() { - @TestJavascriptInterface - public void frobnicate() { - consumer.accept(0); - } - - @TestJavascriptInterface - public void frobnicate(Object argument) { - consumer.accept(1); - } - }; - - // The method overload to be called depends on the number of arguments supplied. - // TODO(jbroman): Once it's possible to construct a non-trivial argument, do so. - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("frobnicate", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod( - "frobnicate", new RemoteInvocationArgument[] {numberArgument(0)}, response); - - InOrder inOrder = inOrder(consumer); - inOrder.verify(consumer).accept(0); - inOrder.verify(consumer).accept(1); - verify(response, times(2)).call(resultIsOk()); - } - - /** - * Reports to the runnable it is given when its static method is called. - * Works around the fact that a static method cannot capture variables. - */ - static class ObjectWithStaticMethod { - static Runnable sRunnable; - - @TestJavascriptInterface - public static void staticMethod() { - sRunnable.run(); - } - } - - @Test - public void testStaticMethod() { - // Static methods should work just like non-static ones. - - Object target = new ObjectWithStaticMethod(); - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - - Runnable runnable = mock(Runnable.class); - ObjectWithStaticMethod.sRunnable = runnable; - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("staticMethod", new RemoteInvocationArgument[] {}, response); - ObjectWithStaticMethod.sRunnable = null; - verify(runnable).run(); - verify(response).call(resultIsOk()); - - RemoteObject.HasMethod_Response hasMethodResponse = - mock(RemoteObject.HasMethod_Response.class); - remoteObject.hasMethod("staticMethod", hasMethodResponse); - verify(hasMethodResponse).call(true); - - RemoteObject.GetMethods_Response getMethodsResponse = - mock(RemoteObject.GetMethods_Response.class); - remoteObject.getMethods(getMethodsResponse); - verify(getMethodsResponse).call(aryEq(new String[] {"staticMethod"})); - } - - @Test - public void testInvokeMethodNotFound() { - Object target = - new Object() { - public void unexposedMethod() { - Assert.fail("Unexposed method should not be called."); - } - - @TestJavascriptInterface - public void exposedMethodWithWrongArity(Object argument) { - Assert.fail("Exposed method should only be called with the correct arity."); - } - }; - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("nonexistentMethod", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod("unexposedMethod", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod( - "exposedMethodWithWrongArity", new RemoteInvocationArgument[] {}, response); - - verify(response, times(3)).call(resultHasError(RemoteInvocationError.METHOD_NOT_FOUND)); - } - - @Test - public void testGetMethodsWithDisallowedInspection() { - Object target = - new Object() { - @TestJavascriptInterface - public void exposedMethod() {} - - @TestJavascriptInterface - public void anotherExposedMethod() {} - }; - - RemoteObject remoteObject = - newRemoteObjectImpl( - target, TestJavascriptInterface.class, /* allowInspection= */ false); - - // getMethods should be empty. - RemoteObject.GetMethods_Response getMethodsResponse = - mock(RemoteObject.GetMethods_Response.class); - remoteObject.getMethods(getMethodsResponse); - verify(getMethodsResponse).call(aryEq(new String[] {})); - } - - @Test - public void testObjectGetClassBlocked() { - Object target = new Object(); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - RemoteObject remoteObject = newRemoteObjectImpl(target, null); - remoteObject.invokeMethod("getClass", new RemoteInvocationArgument[] {}, response); - - verify(response).call(resultHasError(RemoteInvocationError.OBJECT_GET_CLASS_BLOCKED)); - verify(mAuditor).onObjectGetClassInvocationAttempt(); - } - - @Test - public void testOverloadedGetClassPermitted() { - final Runnable runnable = mock(Runnable.class); - Object target = - new Object() { - @TestJavascriptInterface - public void getClass(Object o) { - runnable.run(); - } - }; - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - remoteObject.invokeMethod( - "getClass", new RemoteInvocationArgument[] {numberArgument(0)}, response); - - verify(runnable).run(); - verify(response).call(resultIsOk()); - verify(mAuditor, never()).onObjectGetClassInvocationAttempt(); - } - - @Test - public void testMethodReturningArrayIgnored() { - Object target = - new Object() { - @TestJavascriptInterface - public int[] returnsIntArray() { - Assert.fail("Method returning array should not be called."); - return null; - } - }; - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("returnsIntArray", new RemoteInvocationArgument[] {}, response); - - verify(response).call(resultIsUndefined()); - } - - @Test - public void testInvocationTargetException() { - Object target = - new Object() { - @TestJavascriptInterface - public void exceptionThrowingMethod() throws Exception { - throw new Exception( - "This exception is expected during test. Do not be alarmed."); - } - }; - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod( - "exceptionThrowingMethod", new RemoteInvocationArgument[] {}, response); - - verify(response).call(resultHasError(RemoteInvocationError.EXCEPTION_THROWN)); - } - - private static class VariantConsumer { - private final Consumer<Object> mConsumer; - - public VariantConsumer(Consumer<Object> consumer) { - mConsumer = consumer; - } - - @TestJavascriptInterface - public void consumeByte(byte b) { - mConsumer.accept(b); - } - - @TestJavascriptInterface - public void consumeChar(char c) { - mConsumer.accept(c); - } - - @TestJavascriptInterface - public void consumeShort(short s) { - mConsumer.accept(s); - } - - @TestJavascriptInterface - public void consumeInt(int i) { - mConsumer.accept(i); - } - - @TestJavascriptInterface - public void consumeLong(long l) { - mConsumer.accept(l); - } - - @TestJavascriptInterface - public void consumeFloat(float f) { - mConsumer.accept(f); - } - - @TestJavascriptInterface - public void consumeDouble(double d) { - mConsumer.accept(d); - } - - @TestJavascriptInterface - public void consumeBoolean(boolean b) { - mConsumer.accept(b); - } - - @TestJavascriptInterface - public void consumeString(String s) { - mConsumer.accept(s); - } - - @TestJavascriptInterface - public void consumeObjectArray(Object[] oa) { - mConsumer.accept(oa); - } - - @TestJavascriptInterface - public void consumeBooleanArray(boolean[] ba) { - mConsumer.accept(ba); - } - - @TestJavascriptInterface - public void consumeIntArray(int[] ia) { - mConsumer.accept(ia); - } - - @TestJavascriptInterface - public void consumeFloatArray(float[] fa) { - mConsumer.accept(fa); - } - - @TestJavascriptInterface - public void consumeDoubleArray(double[] da) { - mConsumer.accept(da); - } - - @TestJavascriptInterface - public void consumeStringArray(String[] sa) { - mConsumer.accept(sa); - } - - @TestJavascriptInterface - public void consumeObject(Object o) { - mConsumer.accept(o); - } - } - - @Test - public void testArgumentConversionNumber() { - final Consumer<Object> consumer = (Consumer<Object>) mock(Consumer.class); - Object target = new VariantConsumer(consumer); - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod( - "consumeByte", new RemoteInvocationArgument[] {numberArgument(356)}, response); - remoteObject.invokeMethod( - "consumeChar", new RemoteInvocationArgument[] {numberArgument(356)}, response); - remoteObject.invokeMethod( - "consumeChar", new RemoteInvocationArgument[] {numberArgument(1.5)}, response); - remoteObject.invokeMethod( - "consumeChar", new RemoteInvocationArgument[] {numberArgument(-0.0)}, response); - remoteObject.invokeMethod( - "consumeShort", new RemoteInvocationArgument[] {numberArgument(32768)}, response); - remoteObject.invokeMethod( - "consumeInt", new RemoteInvocationArgument[] {numberArgument(-1.5)}, response); - remoteObject.invokeMethod( - "consumeLong", - new RemoteInvocationArgument[] {numberArgument(Double.POSITIVE_INFINITY)}, - response); - remoteObject.invokeMethod( - "consumeFloat", - new RemoteInvocationArgument[] {numberArgument(3.141592654)}, - response); - remoteObject.invokeMethod( - "consumeDouble", - new RemoteInvocationArgument[] {numberArgument(Double.NaN)}, - response); - remoteObject.invokeMethod( - "consumeBoolean", new RemoteInvocationArgument[] {numberArgument(1)}, response); - remoteObject.invokeMethod( - "consumeString", - new RemoteInvocationArgument[] {numberArgument(-1.66666666666)}, - response); - remoteObject.invokeMethod( - "consumeString", - new RemoteInvocationArgument[] {numberArgument(Double.NaN)}, - response); - remoteObject.invokeMethod( - "consumeString", - new RemoteInvocationArgument[] {numberArgument(Double.NEGATIVE_INFINITY)}, - response); - remoteObject.invokeMethod( - "consumeString", new RemoteInvocationArgument[] {numberArgument(-0.0)}, response); - remoteObject.invokeMethod( - "consumeString", - new RemoteInvocationArgument[] {numberArgument(123456789)}, - response); - remoteObject.invokeMethod( - "consumeString", - new RemoteInvocationArgument[] {numberArgument(123000000.1)}, - response); - remoteObject.invokeMethod( - "consumeObjectArray", new RemoteInvocationArgument[] {numberArgument(6)}, response); - remoteObject.invokeMethod( - "consumeObject", new RemoteInvocationArgument[] {numberArgument(6)}, response); - - verify(consumer).accept((byte) 100); - verify(consumer).accept('\u0164'); - verify(consumer, times(2)).accept('\u0000'); - verify(consumer).accept((short) -32768); - verify(consumer).accept((int) -1); - verify(consumer).accept(Long.MAX_VALUE); - verify(consumer).accept((float) 3.141592654); - verify(consumer).accept(Double.NaN); - verify(consumer).accept(false); - verify(consumer).accept("-1.66667"); - verify(consumer).accept("nan"); - verify(consumer).accept("-inf"); - verify(consumer).accept("-0"); - verify(consumer).accept("123456789"); - verify(consumer).accept("1.23e+08"); - verify(consumer, times(2)).accept(null); - verify(response, times(18)).call(resultIsOk()); - } - - @Test - public void testArgumentConversionBoolean() { - final Consumer<Object> consumer = (Consumer<Object>) mock(Consumer.class); - Object target = new VariantConsumer(consumer); - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod( - "consumeByte", new RemoteInvocationArgument[] {booleanArgument(true)}, response); - remoteObject.invokeMethod( - "consumeChar", new RemoteInvocationArgument[] {booleanArgument(true)}, response); - remoteObject.invokeMethod( - "consumeShort", new RemoteInvocationArgument[] {booleanArgument(true)}, response); - remoteObject.invokeMethod( - "consumeInt", new RemoteInvocationArgument[] {booleanArgument(true)}, response); - remoteObject.invokeMethod( - "consumeLong", new RemoteInvocationArgument[] {booleanArgument(true)}, response); - remoteObject.invokeMethod( - "consumeFloat", new RemoteInvocationArgument[] {booleanArgument(true)}, response); - remoteObject.invokeMethod( - "consumeDouble", new RemoteInvocationArgument[] {booleanArgument(true)}, response); - remoteObject.invokeMethod( - "consumeString", new RemoteInvocationArgument[] {booleanArgument(true)}, response); - remoteObject.invokeMethod( - "consumeString", new RemoteInvocationArgument[] {booleanArgument(false)}, response); - remoteObject.invokeMethod( - "consumeObjectArray", - new RemoteInvocationArgument[] {booleanArgument(true)}, - response); - remoteObject.invokeMethod( - "consumeObject", new RemoteInvocationArgument[] {booleanArgument(true)}, response); - - InOrder inOrder = inOrder(consumer); - inOrder.verify(consumer).accept((byte) 0); - inOrder.verify(consumer).accept('\u0000'); - inOrder.verify(consumer).accept((short) 0); - inOrder.verify(consumer).accept((int) 0); - inOrder.verify(consumer).accept((long) 0); - inOrder.verify(consumer).accept((float) 0); - inOrder.verify(consumer).accept((double) 0); - inOrder.verify(consumer).accept("true"); - inOrder.verify(consumer).accept("false"); - inOrder.verify(consumer, times(2)).accept(null); - } - - @Test - public void testArgumentConversionString() { - final Consumer<Object> consumer = (Consumer<Object>) mock(Consumer.class); - Object target = new VariantConsumer(consumer); - String stringWithNonAsciiCharacterAndUnpairedSurrogate = "caf\u00e9\ud800"; - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod( - "consumeByte", new RemoteInvocationArgument[] {stringArgument("hello")}, response); - remoteObject.invokeMethod( - "consumeChar", new RemoteInvocationArgument[] {stringArgument("hello")}, response); - remoteObject.invokeMethod( - "consumeShort", new RemoteInvocationArgument[] {stringArgument("hello")}, response); - remoteObject.invokeMethod( - "consumeInt", new RemoteInvocationArgument[] {stringArgument("hello")}, response); - remoteObject.invokeMethod( - "consumeLong", new RemoteInvocationArgument[] {stringArgument("hello")}, response); - remoteObject.invokeMethod( - "consumeFloat", new RemoteInvocationArgument[] {stringArgument("hello")}, response); - remoteObject.invokeMethod( - "consumeDouble", - new RemoteInvocationArgument[] {stringArgument("hello")}, - response); - remoteObject.invokeMethod( - "consumeString", - new RemoteInvocationArgument[] {stringArgument("hello")}, - response); - remoteObject.invokeMethod( - "consumeString", - new RemoteInvocationArgument[] { - stringArgument(stringWithNonAsciiCharacterAndUnpairedSurrogate) - }, - response); - remoteObject.invokeMethod( - "consumeObjectArray", - new RemoteInvocationArgument[] {stringArgument("hello")}, - response); - remoteObject.invokeMethod( - "consumeObject", - new RemoteInvocationArgument[] {stringArgument("hello")}, - response); - - InOrder inOrder = inOrder(consumer); - inOrder.verify(consumer).accept((byte) 0); - inOrder.verify(consumer).accept('\u0000'); - inOrder.verify(consumer).accept((short) 0); - inOrder.verify(consumer).accept((int) 0); - inOrder.verify(consumer).accept((long) 0); - inOrder.verify(consumer).accept((float) 0); - inOrder.verify(consumer).accept((double) 0); - inOrder.verify(consumer).accept("hello"); - inOrder.verify(consumer).accept(stringWithNonAsciiCharacterAndUnpairedSurrogate); - inOrder.verify(consumer, times(2)).accept(null); - } - - @Test - public void testArgumentConversionNull() { - final Consumer<Object> consumer = (Consumer<Object>) mock(Consumer.class); - Object target = new VariantConsumer(consumer); - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - RemoteInvocationArgument args[] = {nullArgument()}; - remoteObject.invokeMethod("consumeByte", args, response); - remoteObject.invokeMethod("consumeChar", args, response); - remoteObject.invokeMethod("consumeShort", args, response); - remoteObject.invokeMethod("consumeInt", args, response); - remoteObject.invokeMethod("consumeLong", args, response); - remoteObject.invokeMethod("consumeFloat", args, response); - remoteObject.invokeMethod("consumeDouble", args, response); - remoteObject.invokeMethod("consumeString", args, response); - remoteObject.invokeMethod("consumeObjectArray", args, response); - remoteObject.invokeMethod("consumeObject", args, response); - - verify(consumer).accept((byte) 0); - verify(consumer).accept('\u0000'); - verify(consumer).accept((short) 0); - verify(consumer).accept((int) 0); - verify(consumer).accept((long) 0); - verify(consumer).accept((float) 0); - verify(consumer).accept((double) 0); - verify(consumer, times(3)).accept(null); - } - - @Test - public void testArgumentConversionUndefined() { - final Consumer<Object> consumer = (Consumer<Object>) mock(Consumer.class); - Object target = new VariantConsumer(consumer); - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - RemoteInvocationArgument args[] = {undefinedArgument()}; - remoteObject.invokeMethod("consumeByte", args, response); - remoteObject.invokeMethod("consumeChar", args, response); - remoteObject.invokeMethod("consumeShort", args, response); - remoteObject.invokeMethod("consumeInt", args, response); - remoteObject.invokeMethod("consumeLong", args, response); - remoteObject.invokeMethod("consumeFloat", args, response); - remoteObject.invokeMethod("consumeDouble", args, response); - remoteObject.invokeMethod("consumeString", args, response); - remoteObject.invokeMethod("consumeObjectArray", args, response); - remoteObject.invokeMethod("consumeObject", args, response); - - verify(consumer).accept((byte) 0); - verify(consumer).accept('\u0000'); - verify(consumer).accept((short) 0); - verify(consumer).accept((int) 0); - verify(consumer).accept((long) 0); - verify(consumer).accept((float) 0); - verify(consumer).accept((double) 0); - verify(consumer).accept("undefined"); - verify(consumer, times(2)).accept(null); - } - - @Test - public void testArgumentConversionArray() { - final Consumer<Object> consumer = (Consumer<Object>) mock(Consumer.class); - Object target = new VariantConsumer(consumer); - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - RemoteInvocationArgument args[] = { - arrayArgument( - numberArgument(3.14159), - booleanArgument(true), - stringArgument("Hello"), - arrayArgument(), - undefinedArgument()) - }; - remoteObject.invokeMethod("consumeByte", args, response); - remoteObject.invokeMethod("consumeChar", args, response); - remoteObject.invokeMethod("consumeShort", args, response); - remoteObject.invokeMethod("consumeInt", args, response); - remoteObject.invokeMethod("consumeLong", args, response); - remoteObject.invokeMethod("consumeFloat", args, response); - remoteObject.invokeMethod("consumeDouble", args, response); - remoteObject.invokeMethod("consumeBoolean", args, response); - remoteObject.invokeMethod("consumeString", args, response); - remoteObject.invokeMethod("consumeIntArray", args, response); - remoteObject.invokeMethod("consumeStringArray", args, response); - remoteObject.invokeMethod("consumeObjectArray", args, response); - remoteObject.invokeMethod("consumeObject", args, response); - - verify(consumer).accept((byte) 0); - verify(consumer).accept('\u0000'); - verify(consumer).accept((short) 0); - verify(consumer).accept((int) 0); - verify(consumer).accept((long) 0); - verify(consumer).accept((float) 0); - verify(consumer).accept((double) 0); - verify(consumer).accept(false); - verify(consumer).accept("undefined"); - verify(consumer).accept(aryEq(new int[] {3, 0, 0, 0, 0})); - verify(consumer).accept(aryEq(new String[] {null, null, "Hello", null, null})); - verify(consumer, times(2)).accept(null); - } - - @Test - public void testArgumentConversionTypedIntArray() { - final Consumer<Object> consumer = (Consumer<Object>) mock(Consumer.class); - Object target = new VariantConsumer(consumer); - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - RemoteInvocationArgument args[] = { - typedArrayArgument( - RemoteArrayType.INT8_ARRAY, - BigBufferUtil.createBigBufferFromBytes(new byte[] {3, 2, 1, 0})) - }; - remoteObject.invokeMethod("consumeByte", args, response); - remoteObject.invokeMethod("consumeChar", args, response); - remoteObject.invokeMethod("consumeShort", args, response); - remoteObject.invokeMethod("consumeInt", args, response); - remoteObject.invokeMethod("consumeLong", args, response); - remoteObject.invokeMethod("consumeFloat", args, response); - remoteObject.invokeMethod("consumeDouble", args, response); - remoteObject.invokeMethod("consumeBoolean", args, response); - remoteObject.invokeMethod("consumeString", args, response); - remoteObject.invokeMethod("consumeBooleanArray", args, response); - remoteObject.invokeMethod("consumeIntArray", args, response); - remoteObject.invokeMethod("consumeFloatArray", args, response); - remoteObject.invokeMethod("consumeDoubleArray", args, response); - remoteObject.invokeMethod("consumeStringArray", args, response); - remoteObject.invokeMethod("consumeObjectArray", args, response); - remoteObject.invokeMethod("consumeObject", args, response); - - verify(consumer).accept((byte) 0); - verify(consumer).accept('\u0000'); - verify(consumer).accept((short) 0); - verify(consumer).accept((int) 0); - verify(consumer).accept((long) 0); - verify(consumer).accept((float) 0); - verify(consumer).accept((double) 0); - verify(consumer).accept(false); - verify(consumer).accept("undefined"); - verify(consumer).accept(aryEq(new boolean[] {false, false, false, false})); - verify(consumer).accept(aryEq(new int[] {3, 2, 1, 0})); - verify(consumer).accept(aryEq(new float[] {3, 2, 1, 0})); - verify(consumer).accept(aryEq(new double[] {3, 2, 1, 0})); - verify(consumer).accept(aryEq(new String[] {null, null, null, null})); - verify(consumer, times(2)).accept(null); - } - - @Test - public void testArgumentConversionTypedDoubleArray() { - final Consumer<Object> consumer = (Consumer<Object>) mock(Consumer.class); - Object target = new VariantConsumer(consumer); - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - RemoteInvocationArgument args[] = { - typedArrayArgument( - RemoteArrayType.FLOAT64_ARRAY, - BigBufferUtil.createBigBufferFromBytes( - new byte[] {51, 51, 51, 51, 51, 51, 36, 64})) - }; - - remoteObject.invokeMethod("consumeByte", args, response); - remoteObject.invokeMethod("consumeChar", args, response); - remoteObject.invokeMethod("consumeShort", args, response); - remoteObject.invokeMethod("consumeInt", args, response); - remoteObject.invokeMethod("consumeLong", args, response); - remoteObject.invokeMethod("consumeFloat", args, response); - remoteObject.invokeMethod("consumeDouble", args, response); - remoteObject.invokeMethod("consumeBoolean", args, response); - remoteObject.invokeMethod("consumeString", args, response); - remoteObject.invokeMethod("consumeBooleanArray", args, response); - remoteObject.invokeMethod("consumeIntArray", args, response); - remoteObject.invokeMethod("consumeFloatArray", args, response); - remoteObject.invokeMethod("consumeDoubleArray", args, response); - remoteObject.invokeMethod("consumeStringArray", args, response); - remoteObject.invokeMethod("consumeObjectArray", args, response); - remoteObject.invokeMethod("consumeObject", args, response); - - verify(consumer).accept((byte) 0); - verify(consumer).accept('\u0000'); - verify(consumer).accept((short) 0); - verify(consumer).accept((int) 0); - verify(consumer).accept((long) 0); - verify(consumer).accept((float) 0); - verify(consumer).accept((double) 0); - verify(consumer).accept(false); - verify(consumer).accept("undefined"); - verify(consumer).accept(aryEq(new boolean[] {false})); - verify(consumer).accept(aryEq(new int[] {10})); - verify(consumer).accept(aryEq(new float[] {10.1f})); - verify(consumer).accept(aryEq(new double[] {10.1})); - verify(consumer).accept(aryEq(new String[] {null})); - verify(consumer, times(2)).accept(null); - } - - @Test - public void testArgumentConversionObjectId() { - Object foo = new Object(); - Object target = - new Object() { - @TestJavascriptInterface - public Object getFoo() { - return foo; - } - - @TestJavascriptInterface - public boolean isFoo(Object object) { - return foo == object; - } - - @TestJavascriptInterface - public int isNotFoo(int number) { - return number; - } - }; - when(mIdAllocator.getObjectId(foo, TestJavascriptInterface.class)).thenReturn(42); - when(mIdAllocator.getObjectById(42)).thenReturn(foo); - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("getFoo", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod( - "isFoo", new RemoteInvocationArgument[] {objectIdArgument(42)}, response); - remoteObject.invokeMethod( - "isFoo", new RemoteInvocationArgument[] {objectIdArgument(100)}, response); - remoteObject.invokeMethod( - "isNotFoo", new RemoteInvocationArgument[] {objectIdArgument(42)}, response); - - verify(response).call(resultIsObject(42)); - verify(response).call(resultIsBoolean(true)); - verify(response).call(resultIsBoolean(false)); - verify(response).call(resultIsNumber(0)); - } - - @Test - public void testObjectNonAssignableType() { - class CustomType {} - Object foo = new Object(); - Object target = - new Object() { - @TestJavascriptInterface - public Object getFoo() { - return foo; - } - - @TestJavascriptInterface - public boolean exposedNonAssignableTypeMethodWithBooleanObject(Boolean value) { - return true; - } - - @TestJavascriptInterface - public boolean exposedNonAssignableTypeMethodWithCustomObject( - CustomType custom) { - return true; - } - }; - when(mIdAllocator.getObjectId(foo, TestJavascriptInterface.class)).thenReturn(42); - when(mIdAllocator.getObjectById(42)).thenReturn(foo); - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("getFoo", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod( - "exposedNonAssignableTypeMethodWithBooleanObject", - new RemoteInvocationArgument[] {objectIdArgument(42)}, - response); - remoteObject.invokeMethod( - "exposedNonAssignableTypeMethodWithCustomObject", - new RemoteInvocationArgument[] {objectIdArgument(42)}, - response); - - verify(response).call(resultIsObject(42)); - verify(response, times(2)).call(resultHasError(RemoteInvocationError.NON_ASSIGNABLE_TYPES)); - } - - @Test - public void testResultConversionVoid() { - Object target = - new Object() { - @TestJavascriptInterface - public void returnsVoid() {} - }; - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("returnsVoid", new RemoteInvocationArgument[] {}, response); - - verify(response).call(resultIsUndefined()); - } - - @Test - public void testConversionResultNumber() { - Object target = - new Object() { - @TestJavascriptInterface - public int returnsInt() { - return 42; - } - - @TestJavascriptInterface - public float returnsFloat() { - return -1.5f; - } - - @TestJavascriptInterface - public char returnsChar() { - return '\ufeed'; - } - }; - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("returnsInt", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod("returnsFloat", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod("returnsChar", new RemoteInvocationArgument[] {}, response); - - verify(response).call(resultIsNumber(42)); - verify(response).call(resultIsNumber(-1.5f)); - verify(response).call(resultIsNumber(0xfeed)); - } - - @Test - public void testConversionResultBoolean() { - Object target = - new Object() { - @TestJavascriptInterface - public boolean returnsTrue() { - return true; - } - - @TestJavascriptInterface - public boolean returnsFalse() { - return false; - } - }; - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("returnsTrue", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod("returnsFalse", new RemoteInvocationArgument[] {}, response); - - InOrder inOrder = inOrder(response); - inOrder.verify(response).call(resultIsBoolean(true)); - inOrder.verify(response).call(resultIsBoolean(false)); - } - - @Test - public void testConversionResultString() { - final String stringWithNonAsciiCharacterAndUnpairedSurrogate = "caf\u00e9\ud800"; - Object target = - new Object() { - @TestJavascriptInterface - public String returnsHello() { - return "Hello"; - } - - @TestJavascriptInterface - public String returnsExoticString() { - return stringWithNonAsciiCharacterAndUnpairedSurrogate; - } - - @TestJavascriptInterface - public String returnsNull() { - return null; - } - }; - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("returnsHello", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod( - "returnsExoticString", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod("returnsNull", new RemoteInvocationArgument[] {}, response); - - verify(response).call(resultIsString("Hello")); - verify(response).call(resultIsString(stringWithNonAsciiCharacterAndUnpairedSurrogate)); - verify(response).call(resultIsUndefined()); - } - - @Test - public void testConversionResultObject() { - final Object foo = new Object(); - Object target = - new Object() { - @TestJavascriptInterface - public Object getFoo() { - return foo; - } - - @TestJavascriptInterface - public Object getNull() { - return null; - } - }; - - when(mIdAllocator.getObjectId(foo, TestJavascriptInterface.class)).thenReturn(42); - - RemoteObject remoteObject = newRemoteObjectImpl(target, TestJavascriptInterface.class); - RemoteObject.InvokeMethod_Response response = - mock(RemoteObject.InvokeMethod_Response.class); - remoteObject.invokeMethod("getFoo", new RemoteInvocationArgument[] {}, response); - remoteObject.invokeMethod("getNull", new RemoteInvocationArgument[] {}, response); - - verify(response).call(resultIsObject(42)); - verify(response).call(resultIsNull()); - } - - private RemoteInvocationResult resultHasError(final int error) { - return ArgumentMatchers.argThat(result -> result.error == error); - } - - private RemoteInvocationResult resultIsOk() { - return resultHasError(RemoteInvocationError.OK); - } - - private RemoteInvocationResult resultIsUndefined() { - return and( - resultIsOk(), - ArgumentMatchers.argThat( - result -> { - return result.value != null - && result.value.which() - == RemoteInvocationResultValue.Tag.SingletonValue - && result.value.getSingletonValue() - == SingletonJavaScriptValue.UNDEFINED; - })); - } - - private RemoteInvocationResult resultIsNull() { - return and( - resultIsOk(), - ArgumentMatchers.argThat( - result -> { - return result.value != null - && result.value.which() - == RemoteInvocationResultValue.Tag.SingletonValue - && result.value.getSingletonValue() - == SingletonJavaScriptValue.NULL; - })); - } - - private RemoteInvocationResult resultIsNumber(final double numberValue) { - return and( - resultIsOk(), - ArgumentMatchers.argThat( - result -> { - return result.value != null - && result.value.which() - == RemoteInvocationResultValue.Tag.NumberValue - && result.value.getNumberValue() == numberValue; - })); - } - - private RemoteInvocationResult resultIsBoolean(final boolean booleanValue) { - return and( - resultIsOk(), - ArgumentMatchers.argThat( - result -> { - return result.value != null - && result.value.which() - == RemoteInvocationResultValue.Tag.BooleanValue - && result.value.getBooleanValue() == booleanValue; - })); - } - - private RemoteInvocationResult resultIsString(String stringValue) { - final short[] expectedData = new short[stringValue.length()]; - for (int i = 0; i < expectedData.length; i++) { - expectedData[i] = (short) stringValue.charAt(i); - } - return and( - resultIsOk(), - ArgumentMatchers.argThat( - result -> { - return result.value != null - && result.value.which() - == RemoteInvocationResultValue.Tag.StringValue - && Arrays.equals( - result.value.getStringValue().data, expectedData); - })); - } - - private RemoteInvocationResult resultIsObject(final int objectId) { - return and( - resultIsOk(), - ArgumentMatchers.argThat( - result -> { - return result.value != null - && result.value.which() - == RemoteInvocationResultValue.Tag.ObjectId - && result.value.getObjectId() == objectId; - })); - } - - private RemoteInvocationArgument numberArgument(double numberValue) { - RemoteInvocationArgument argument = new RemoteInvocationArgument(); - argument.setNumberValue(numberValue); - return argument; - } - - private RemoteInvocationArgument booleanArgument(boolean booleanValue) { - RemoteInvocationArgument argument = new RemoteInvocationArgument(); - argument.setBooleanValue(booleanValue); - return argument; - } - - private RemoteInvocationArgument stringArgument(String stringValue) { - String16 string16 = new String16(); - string16.data = new short[stringValue.length()]; - for (int i = 0; i < stringValue.length(); i++) { - string16.data[i] = (short) stringValue.charAt(i); - } - RemoteInvocationArgument argument = new RemoteInvocationArgument(); - argument.setStringValue(string16); - return argument; - } - - private RemoteInvocationArgument nullArgument() { - RemoteInvocationArgument argument = new RemoteInvocationArgument(); - argument.setSingletonValue(SingletonJavaScriptValue.NULL); - return argument; - } - - private RemoteInvocationArgument undefinedArgument() { - RemoteInvocationArgument argument = new RemoteInvocationArgument(); - argument.setSingletonValue(SingletonJavaScriptValue.UNDEFINED); - return argument; - } - - private RemoteInvocationArgument objectIdArgument(int objectId) { - RemoteInvocationArgument argument = new RemoteInvocationArgument(); - argument.setObjectIdValue(objectId); - return argument; - } - - private RemoteInvocationArgument arrayArgument(RemoteInvocationArgument... elements) { - RemoteInvocationArgument argument = new RemoteInvocationArgument(); - argument.setArrayValue(elements); - return argument; - } - - private RemoteInvocationArgument typedArrayArgument( - int type, org.chromium.mojo_base.mojom.BigBuffer buffer) { - RemoteInvocationArgument argument = new RemoteInvocationArgument(); - RemoteTypedArray typedArray = new RemoteTypedArray(); - typedArray.type = type; - typedArray.buffer = buffer; - argument.setTypedArrayValue(typedArray); - return argument; - } - - private RemoteObjectImpl newRemoteObjectImpl( - Object target, Class<? extends Annotation> annotation) { - return newRemoteObjectImpl(target, annotation, true); - } - - private RemoteObjectImpl newRemoteObjectImpl( - Object target, Class<? extends Annotation> annotation, boolean allowInspection) { - return new RemoteObjectImpl(target, annotation, mAuditor, mIdAllocator, allowInspection); - } -}
diff --git a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectRegistryTest.java b/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectRegistryTest.java deleted file mode 100644 index 8bb6b2d..0000000 --- a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectRegistryTest.java +++ /dev/null
@@ -1,71 +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. - -package org.chromium.content.browser.remoteobjects; - -import static org.hamcrest.Matchers.isIn; -import static org.hamcrest.Matchers.not; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.chromium.base.test.BaseRobolectricTestRunner; - -import java.util.HashSet; -import java.util.Set; - -/** Tests the object registry, which maintains bidirectional object/ID mappings. */ -@RunWith(BaseRobolectricTestRunner.class) -public final class RemoteObjectRegistryTest { - @Test - public void testMaintainsRetainingSet() { - // This is how the registry is expected to keep itself alive, despite only being held weakly - // from its main consumer. - Set<RemoteObjectRegistry> retainingSet = new HashSet<>(); - RemoteObjectRegistry registry = new RemoteObjectRegistry(retainingSet); - Assert.assertThat(registry, isIn(retainingSet)); - registry.close(); - Assert.assertThat(registry, not(isIn(retainingSet))); - } - - @Test - public void testGetObjectId() { - // We should get an ID that can be used to retrieve the object. - Set<RemoteObjectRegistry> retainingSet = new HashSet<>(); - RemoteObjectRegistry registry = new RemoteObjectRegistry(retainingSet); - Object o = new Object(); - int id = registry.getObjectId(o, null); - Assert.assertSame(o, registry.getObjectById(id)); - } - - @Test - public void testGetObjectIdSame() { - // The ID should be the same if retrieved twice. - Set<RemoteObjectRegistry> retainingSet = new HashSet<>(); - RemoteObjectRegistry registry = new RemoteObjectRegistry(retainingSet); - Object o = new Object(); - int id = registry.getObjectId(o, null); - Assert.assertEquals(id, registry.getObjectId(o, null)); - } - - @Test - public void testGetObjectIdAfterRemoval() { - // It should still work if we have previously added and removed the object. - Set<RemoteObjectRegistry> retainingSet = new HashSet<>(); - RemoteObjectRegistry registry = new RemoteObjectRegistry(retainingSet); - Object o = new Object(); - int id = registry.getObjectId(o, null); - registry.unrefObjectById(id); - int id2 = registry.getObjectId(o, null); - Assert.assertSame(o, registry.getObjectById(id2)); - } - - @Test - public void testReturnsNullForNonExistentObject() { - Set<RemoteObjectRegistry> retainingSet = new HashSet<>(); - RemoteObjectRegistry registry = new RemoteObjectRegistry(retainingSet); - Assert.assertNull(registry.getObjectById(123)); - } -}
diff --git a/content/public/browser/browsing_data_filter_builder.h b/content/public/browser/browsing_data_filter_builder.h index ce121c5..63e1135 100644 --- a/content/public/browser/browsing_data_filter_builder.h +++ b/content/public/browser/browsing_data_filter_builder.h
@@ -114,6 +114,11 @@ // Returns true if we're an empty preserve list, where we delete everything. virtual bool MatchesAllOriginsAndDomains() = 0; + // Returns true if we're deleting everything or nearly everything -- the mode + // is kPreserve, we're not restricted to partitioned cookies, and no + // StorageKey is set. + virtual bool MatchesMostOriginsAndDomains() = 0; + // Returns true if we're an empty delete list, where we delete nothing. virtual bool MatchesNothing() = 0;
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 46a2307..f9651ee99 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -141,7 +141,7 @@ CONTENT_EXPORT extern const char kGpuProcess[]; CONTENT_EXPORT extern const char kGpuSandboxStartEarly[]; CONTENT_EXPORT extern const char kGpuStartupDialog[]; -extern const char kHideScrollbars[]; +CONTENT_EXPORT extern const char kHideScrollbars[]; CONTENT_EXPORT extern const char kInProcessGPU[]; CONTENT_EXPORT extern const char kIPCConnectionTimeout[]; CONTENT_EXPORT extern const char kIsolateOrigins[];
diff --git a/content/public/test/android/BUILD.gn b/content/public/test/android/BUILD.gn index bca2697..87ca0e0f 100644 --- a/content/public/test/android/BUILD.gn +++ b/content/public/test/android/BUILD.gn
@@ -44,8 +44,6 @@ ] srcjar_deps = [ ":content_test_jni" ] sources = [ - "javatests/src/org/chromium/content_public/browser/test/ChildProcessAllocatorSettings.java", - "javatests/src/org/chromium/content_public/browser/test/ChildProcessAllocatorSettingsHook.java", "javatests/src/org/chromium/content_public/browser/test/ContentJUnit4ClassRunner.java", "javatests/src/org/chromium/content_public/browser/test/ContentJUnit4RunnerDelegate.java", "javatests/src/org/chromium/content_public/browser/test/NativeLibraryTestUtils.java",
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ChildProcessAllocatorSettings.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ChildProcessAllocatorSettings.java deleted file mode 100644 index fc22a71d..0000000 --- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ChildProcessAllocatorSettings.java +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.content_public.browser.test; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** An annotation used in test to hard-code some of the ChildProcessAllocator settings */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface ChildProcessAllocatorSettings { - int sandboxedServiceCount() default -1; - - String sandboxedServiceName() default ""; -}
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ChildProcessAllocatorSettingsHook.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ChildProcessAllocatorSettingsHook.java deleted file mode 100644 index 76c115b..0000000 --- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ChildProcessAllocatorSettingsHook.java +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.content_public.browser.test; - -import android.content.Context; - -import org.junit.runners.model.FrameworkMethod; - -import org.chromium.base.test.BaseJUnit4ClassRunner.TestHook; -import org.chromium.content.browser.ChildProcessLauncherHelperImpl; - -/** - * PreTestHook used to register the ChildProcessAllocatorSettings annotation. - * - * TODO(yolandyan): convert this to TestRule once content tests are changed JUnit4 - * */ -public final class ChildProcessAllocatorSettingsHook implements TestHook { - @Override - public void run(Context targetContext, FrameworkMethod testMethod) { - ChildProcessAllocatorSettings annotation = - testMethod.getAnnotation(ChildProcessAllocatorSettings.class); - if (annotation != null) { - ChildProcessLauncherHelperImpl.setSandboxServicesSettingsForTesting( - /* factory= */ null, - annotation.sandboxedServiceCount(), - annotation.sandboxedServiceName()); - } - } -}
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ContentJUnit4ClassRunner.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ContentJUnit4ClassRunner.java index 8b5768e..09a80f44 100644 --- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ContentJUnit4ClassRunner.java +++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ContentJUnit4ClassRunner.java
@@ -32,6 +32,7 @@ // Display ui scale-up on auto for tests by default, individual tests can restore this // scaling. DisplayUtil.setUiScalingFactorForAutomotiveForTesting(1.0f); + EmbeddedTestServer.initCerts(); } @Override @@ -43,15 +44,4 @@ new UiDisableIfSkipCheck(InstrumentationRegistry.getTargetContext()), new GmsCoreVersionRestrictionSkipCheck(getApplication().getApplicationContext())); } - - /** Change this static function to add default {@code PreTestHook}s. */ - @Override - protected List<TestHook> getPreTestHooks() { - return addToList(super.getPreTestHooks(), new ChildProcessAllocatorSettingsHook()); - } - - @Override - protected List<ClassHook> getPreClassHooks() { - return addToList(super.getPreClassHooks(), EmbeddedTestServer.getPreClassHook()); - } }
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java index 53b6d5e..01fd2c9 100644 --- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java +++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellActivityTestRule.java
@@ -228,18 +228,14 @@ } public JavascriptInjector getJavascriptInjector() { - return getJavascriptInjector(false); - } - - public JavascriptInjector getJavascriptInjector(boolean useMojo) { - return JavascriptInjector.fromWebContents(getWebContents(), useMojo); + return JavascriptInjector.fromWebContents(getWebContents()); } /** - * Waits for the Active shell to finish loading. This times out after - * WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT milliseconds and it shouldn't be used for long - * loading pages. Instead it should be used more for test initialization. The proper way - * to wait is to use a TestCallbackHelperContainer after the initial load is completed. + * Waits for the Active shell to finish loading. This times out after + * WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT milliseconds and it shouldn't be used for long loading + * pages. Instead it should be used more for test initialization. The proper way to wait is to + * use a TestCallbackHelperContainer after the initial load is completed. */ public void waitForActiveShellToBeDoneLoading() { // Wait for the Content Shell to be initialized.
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 44858e45..2544f8c2 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -111,8 +111,8 @@ "../browser/payments/stub_payment_credential.h", "../browser/preloading/prefetch/mock_prefetch_service_delegate.cc", "../browser/preloading/prefetch/mock_prefetch_service_delegate.h", - "../browser/preloading/prefetch/prefetch_test_utils.cc", - "../browser/preloading/prefetch/prefetch_test_utils.h", + "../browser/preloading/prefetch/prefetch_test_util_internal.cc", + "../browser/preloading/prefetch/prefetch_test_util_internal.h", "../browser/presentation/presentation_test_utils.cc", "../browser/presentation/presentation_test_utils.h", "../browser/private_aggregation/private_aggregation_test_utils.cc",
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist index 8c779705..e70ba5f 100644 --- a/content/test/content_test_bundle_data.filelist +++ b/content/test/content_test_bundle_data.filelist
@@ -5840,6 +5840,7 @@ data/cacheable.svg.mock-http-headers data/cacheable2.js data/cacheable2.js.mock-http-headers +data/changing_color.html data/click-nocontent-link.html data/click-noreferrer-links.html data/client_redirect.html
diff --git a/content/test/data/changing_color.html b/content/test/data/changing_color.html new file mode 100644 index 0000000..9695a92 --- /dev/null +++ b/content/test/data/changing_color.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> + <meta name="viewport" content="width=device-width, height=device-height"> +</head> +<body style="border: 0; margin: 0; padding: 0; overflow:hidden;"> +<a name="red"> + <div style="height: 100vh; background-color:#FF0000;"></div> +</a> +<a name="green"> + <div style="height: 100vh; background-color:#00FF00;"></div> +</a> +<a name="blue"> + <div style="height: 100vh; background-color:#0000FF;"></div> +</a> +</body> +</html>
diff --git a/device/fido/features.cc b/device/fido/features.cc index 88196679..638a339 100644 --- a/device/fido/features.cc +++ b/device/fido/features.cc
@@ -92,9 +92,9 @@ base::FEATURE_DISABLED_BY_DEFAULT); // Not yet enabled by default. -BASE_FEATURE(kWebAuthnGpmPin, - "WebAuthenticationGpmPin", - base::FEATURE_DISABLED_BY_DEFAULT); +const base::FeatureParam<bool> kWebAuthnGpmPin{ + &kWebAuthnEnclaveAuthenticator, kWebAuthnGpmPinFeatureParameterName, + /*default_value=*/false}; // Enabled in M118 on all platforms except ChromeOS. Enabled on M121 for // ChromeOS. Remove in or after M124.
diff --git a/device/fido/features.h b/device/fido/features.h index eaa28f7..3ecb917 100644 --- a/device/fido/features.h +++ b/device/fido/features.h
@@ -71,8 +71,9 @@ BASE_DECLARE_FEATURE(kWebAuthnEnclaveAuthenticator); // Enable use of Google Password Manager PIN. +const char kWebAuthnGpmPinFeatureParameterName[] = "WebAuthenticationGpmPin"; COMPONENT_EXPORT(DEVICE_FIDO) -BASE_DECLARE_FEATURE(kWebAuthnGpmPin); +extern const base::FeatureParam<bool> kWebAuthnGpmPin; // Filter a priori discovered credentials on google.com to those that have a // user id that starts with "GOOGLE_ACCOUNT:".
diff --git a/docs/updater/user_manual.md b/docs/updater/user_manual.md index 72a4d23..2751997 100644 --- a/docs/updater/user_manual.md +++ b/docs/updater/user_manual.md
@@ -92,6 +92,26 @@ make the system more resilient, apps may periodically repeat the installation and registration process. +#### CRURegistration library + +An Objective-C library to perform these operations is in development. When +available, applications will be able to initialize +[`CRURegistration`](https://chromium.googlesource.com/chromium/src/+/main/chrome/updater/mac/client_lib) +with their product IDs, then use `installUpdaterWithReply:` and +`registerVersion:existenceCheckerPath:serverURLString:reply:` to install the +updater (if needed) and register. These methods operate asynchronously using +[`dispatch/dispatch.h`](https://developer.apple.com/documentation/dispatch/dispatch_queue) +mechanisms. `CRURegistration` maintains an internal task queue, so clients can +call `register...` immediately after `install...` without waiting for a result. + +`CRURegistration` uses the helpers and command line binaries documented above. +To install the updater using `CRURegistration`, the updater must be embedded +as a Helper as documented above. + +`CRURegistration` is designed to depend only on APIs published in macOS SDKs +and compile as pure Objective-C (without requiring C++ support) so it can be +dropped into projects without incurring Chromium dependencies. + ## Uninstalling Applications and the Updater The updater will uninstall itself automatically when it has no applications to
diff --git a/extensions/browser/service_worker/service_worker_task_queue.cc b/extensions/browser/service_worker/service_worker_task_queue.cc index cc8a687..e926bb5 100644 --- a/extensions/browser/service_worker/service_worker_task_queue.cc +++ b/extensions/browser/service_worker/service_worker_task_queue.cc
@@ -135,17 +135,12 @@ return browser_state_ == BrowserState::kStarted && renderer_state_ == RendererState::kStarted && worker_id_.has_value(); } - bool has_pending_tasks() const { return !pending_tasks_.empty(); } - private: friend class ServiceWorkerTaskQueue; BrowserState browser_state_ = BrowserState::kInitial; RendererState renderer_state_ = RendererState::kInitial; - // Pending tasks that will be run once the worker becomes ready. - std::vector<PendingTask> pending_tasks_; - // Contains the worker's WorkerId associated with this WorkerState, once we // have discovered info about the worker. std::optional<WorkerId> worker_id_; @@ -233,11 +228,11 @@ WorkerState* worker_state = GetWorkerState(context_id); DCHECK(worker_state); if (g_test_observer) { + std::vector<PendingTask>* tasks = pending_tasks(context_id); g_test_observer->DidStartWorkerFail(context_id.extension_id, - worker_state->pending_tasks_.size(), - status_code); + tasks ? tasks->size() : 0, status_code); } - worker_state->pending_tasks_.clear(); + DeleteAllPendingTasks(context_id); // TODO(https://crbug/1062936): Needs more thought: extension would be in // perma-broken state after this as the registration wouldn't be stored if // this happens. @@ -448,18 +443,14 @@ const SequencedContextId context_id = {lazy_context_id.extension_id(), lazy_context_id.browser_context(), *activation_token}; - WorkerState* worker_state = GetWorkerState(context_id); - DCHECK(worker_state); - auto& tasks = worker_state->pending_tasks_; - // worker_state->pending_tasks_ having tasks means the - // worker has been requested to start and hasn't started yet. So - // `tasks.empty()` `false` means the worker is starting. `tasks.empty()` - // `true` means that we don't know if the worker is started so we'll try to - // start it to ensure it'll be ready for the task. This efficiency relies on - // the assumption that only this boolean controls whether we request the - // worker to start below. - bool needs_start_worker = tasks.empty(); - tasks.push_back(std::move(task)); + + // `HasPendingTasks(context_id)` `true` means the worker is starting. + // `HasPendingTasks(context_id)` `false` means that we don't know if the + // worker is started so we'll try to start it to ensure it'll be ready for the + // task. This efficiency relies on the assumption that only this boolean + // controls whether we request the worker to start below. + const bool worker_starting = HasPendingTasks(context_id); + AddPendingTaskForContext(std::move(task), context_id); if (!base::Contains(worker_registered_, context_id)) { // If the worker hasn't finished registration, wait for it to complete. The @@ -469,13 +460,12 @@ return; } - // Start worker if there aren't any tasks to dispatch to the worker (with - // `context_id`) in progress. Otherwise, assume the presence of pending tasks - // means we've started the worker and our start worker callback will run the - // pending tasks for us later. - if (needs_start_worker) { - RunTasksAfterStartWorker(context_id); + if (worker_starting) { + // When the worker finishes starting, the task queue will run `task`. + return; } + + RunTasksAfterStartWorker(context_id); } void ServiceWorkerTaskQueue::ActivateExtension(const Extension* extension) { @@ -488,6 +478,7 @@ activation_token}; DCHECK(!base::Contains(worker_state_map_, context_id)); worker_state_map_.try_emplace(context_id); + pending_tasks_map_.try_emplace(context_id); content::ServiceWorkerContext* service_worker_context = GetServiceWorkerContext(extension->id()); @@ -564,7 +555,7 @@ WorkerState* worker_state = GetWorkerState(context_id); DCHECK(worker_state); // TODO(lazyboy): Run orphaned tasks with nullptr ContextInfo. - worker_state->pending_tasks_.clear(); + pending_tasks_map_.erase(context_id); worker_state_map_.erase(context_id); worker_registered_.erase(context_id); @@ -618,6 +609,37 @@ } } +std::vector<ServiceWorkerTaskQueue::PendingTask>* +ServiceWorkerTaskQueue::pending_tasks(const SequencedContextId& context_id) { + return base::FindOrNull(pending_tasks_map_, context_id); +} + +std::vector<ServiceWorkerTaskQueue::PendingTask>& +ServiceWorkerTaskQueue::GetOrAddPendingTasks( + const SequencedContextId& context_id) { + return pending_tasks_map_[context_id]; +} + +void ServiceWorkerTaskQueue::AddPendingTaskForContext( + PendingTask&& pending_task, + const SequencedContextId& context_id) { + GetOrAddPendingTasks(context_id).push_back(std::move(pending_task)); +} + +void ServiceWorkerTaskQueue::DeleteAllPendingTasks( + const SequencedContextId& context_id) { + std::vector<PendingTask>* tasks = pending_tasks(context_id); + if (tasks) { + tasks->clear(); + } +} + +bool ServiceWorkerTaskQueue::HasPendingTasks( + const SequencedContextId& context_id) { + std::vector<PendingTask>* tasks = pending_tasks(context_id); + return tasks ? !tasks->empty() : false; +} + void ServiceWorkerTaskQueue::DidRegisterServiceWorker( const SequencedContextId& context_id, RegistrationReason reason, @@ -674,7 +696,7 @@ pending_registrations_.emplace(extension->id(), *GetCurrentActivationToken(extension->id())); - if (worker_state->has_pending_tasks()) { + if (HasPendingTasks(context_id)) { // TODO(lazyboy): If worker for |context_id| is already running, consider // not calling StartWorker. This should be straightforward now that service // worker's internal state is on the UI thread rather than the IO thread. @@ -753,7 +775,7 @@ return; } - // Running `pending_tasks_[context_id]` marks the completion of both + // Running the pending tasks below marks the completion of both // DidStartWorkerForScope and DidStartWorkerContext, change `browser_ready` // state of the worker so that new tasks can be queued up. worker_state->browser_state_ = BrowserState::kReady; @@ -761,10 +783,9 @@ g_test_observer->DidStartWorker(context_id.extension_id); } - DCHECK(worker_state->has_pending_tasks()) - << "Worker ready, but no tasks to run!"; + DCHECK(HasPendingTasks(context_id)) << "Worker ready, but no tasks to run!"; std::vector<PendingTask> tasks; - std::swap(worker_state->pending_tasks_, tasks); + std::swap(GetOrAddPendingTasks(context_id), tasks); DCHECK(worker_state->worker_id_); const auto& worker_id = *worker_state->worker_id_; for (auto& task : tasks) { @@ -874,8 +895,8 @@ const SequencedContextId context_id = {lazy_context_id.extension_id(), lazy_context_id.browser_context(), *activation_token}; - WorkerState* worker_state = GetWorkerState(context_id); - return worker_state ? worker_state->pending_tasks_.size() : 0; + std::vector<PendingTask>* tasks = pending_tasks(context_id); + return tasks ? tasks->size() : 0; } // static
diff --git a/extensions/browser/service_worker/service_worker_task_queue.h b/extensions/browser/service_worker/service_worker_task_queue.h index 98acb8b..a3aaf469 100644 --- a/extensions/browser/service_worker/service_worker_task_queue.h +++ b/extensions/browser/service_worker/service_worker_task_queue.h
@@ -43,9 +43,9 @@ // C1) Registering and starting a background worker: // Upon extension activation, this class registers the extension's // background worker if necessary. After that, if it has queued up tasks -// in |pending_tasks_|, then it moves on to starting the worker. Registration -// and start are initiated from this class. Once started, the worker is -// considered browser process ready. These workers are stored in +// in |pending_tasks_map_|, then it moves on to starting the worker. +// Registration and start are initiated from this class. Once started, the +// worker is considered browser process ready. These workers are stored in // |worker_state_map_| with |browser_ready| = false until we run tasks. // // C2) Listening for worker's state update from the renderer: @@ -60,7 +60,7 @@ // // Once a worker reaches readiness in both browser process // (DidStartWorkerForScope) and worker process (DidStartServiceWorkerContext), -// we consider the worker to be ready to run tasks from |pending_tasks_|. +// we consider the worker to be ready to run tasks from |pending_tasks_map_|. // Note that events from #C1 and #C2 are somewhat independent, e.g. it is // possible to see an Init state update from #C2 before #C1 has seen a start // worker completion. @@ -69,10 +69,9 @@ // This class also assigns a unique activation token to an extension // activation so that it can differentiate between two activations of a // particular extension (e.g. reloading an extension can cause two -// activations). |pending_tasks_|, worker registration and start (#C1) have -// activation tokens attached to them. -// The activation expires upon extension deactivation, and tasks are dropped -// from |pending_tasks_|. +// activations). |pending_tasks_map_|, worker registration and start (#C1) +// have activation tokens attached to them. The activation expires upon +// extension deactivation, and tasks are dropped from |pending_tasks_map_|. // // TODO(lazyboy): Clean up queue when extension is unloaded/uninstalled. class ServiceWorkerTaskQueue @@ -308,11 +307,41 @@ // Emit histograms when we know we're going to start the worker. void EmitWorkerWillBeStartedHistograms(const ExtensionId& extension_id); + // Returns the pending tasks for the activated extension. This returns + // `nullptr` if the vector has not been created yet for `context_id`. Should + // return non-null after activating extension and before deactivating + // extension. + std::vector<PendingTask>* pending_tasks(const SequencedContextId& context_id); + + // Returns the pending tasks for the activated extension. This creates an + // empty `std::vector<PendingTask>` for `context_id` if there is not one yet. + // TODO(crbug.com/40276609): Can we ensure `context_id` key has been set + // before this is called so we don't need to add it? + std::vector<ServiceWorkerTaskQueue::PendingTask>& GetOrAddPendingTasks( + const SequencedContextId& context_id); + + // Adds a pending task for the activated extension. + void AddPendingTaskForContext(PendingTask&& pending_task, + const SequencedContextId& context_id); + + // Stop tracking any pending tasks for this `context_id` for the activated + // extension. + void DeleteAllPendingTasks(const SequencedContextId& context_id); + + // Whether there are any pending tasks to run for the activated extension. + bool HasPendingTasks(const SequencedContextId& context_id); + std::map<content::ServiceWorkerContext*, int> observing_worker_contexts_; // The state of worker of each activated extension. std::map<SequencedContextId, WorkerState> worker_state_map_; + // TODO(crbug.com/40276609): Do we need to track this by `SequencedContextId` + // or could we use `ExtensionId` instead? + // `PendingTasks` for the activated extension that will be run as soon as the + // worker is started and ready. + std::map<SequencedContextId, std::vector<PendingTask>> pending_tasks_map_; + const raw_ptr<content::BrowserContext> browser_context_ = nullptr; // A map of Service Worker registrations if this instance is for an
diff --git a/gpu/command_buffer/service/dawn_platform.cc b/gpu/command_buffer/service/dawn_platform.cc index 1aa9b7f..1045ddb 100644 --- a/gpu/command_buffer/service/dawn_platform.cc +++ b/gpu/command_buffer/service/dawn_platform.cc
@@ -91,7 +91,8 @@ const char* uma_prefix) : dawn_caching_interface_(std::move(dawn_caching_interface)), uma_prefix_(uma_prefix), - cache_counts_(base::MakeRefCounted<CacheCounts>()) {} + cache_counts_(base::MakeRefCounted<CacheCounts>()), + startup_time_(base::Time::Now()) {} DawnPlatform::~DawnPlatform() = default; @@ -140,27 +141,29 @@ return result; } -void DawnPlatform::HistogramCustomCounts(const char* name, - int sample, - int min, - int max, - int bucketCount) { - std::string nameStr = name; +void DawnPlatform::HistogramCacheCountHelper(std::string name, + int sample, + int min, + int max, + int bucketCount) { bool post_task = false; - bool is_cache = nameStr.find("Cache"); - if (is_cache) { - if (nameStr.find("Hit")) { + if (name.find("Cache") != std::string::npos) { + if (name.find("Hit") != std::string::npos) { cache_counts_->cache_hit_count.fetch_add(1, std::memory_order_release); - } else if (nameStr.find("Miss")) { + } else if (name.find("Miss") != std::string::npos) { cache_counts_->cache_miss_count.fetch_add(1, std::memory_order_release); } post_task = cache_counts_->did_schedule_log.exchange( true, std::memory_order_acq_rel) == false; } - base::UmaHistogramCustomCounts(uma_prefix_ + nameStr, sample, min, max, - bucketCount); if (post_task) { + if ((base::Time::Now() - startup_time_).InSeconds() <= 90) { + base::UmaHistogramCustomCounts( + uma_prefix_ + name + ".90SecondsPostStartup", sample, min, max, + bucketCount); + } + // Record the stats soonish after the first call. // The 90 seconds comes from the 99 percentile of startup time on macos. base::ThreadPool::PostDelayedTask( @@ -168,22 +171,31 @@ base::BindOnce( [](const std::string& name, scoped_refptr<CacheCounts> cache_counts) { - if (name.find("Hit")) { - UMA_HISTOGRAM_COUNTS_10000(name, - cache_counts->cache_hit_count.load( - std::memory_order_acquire)); + if (name.find("Hit") != std::string::npos) { + base::UmaHistogramCounts10000( + name, cache_counts->cache_hit_count.load( + std::memory_order_acquire)); } else { - UMA_HISTOGRAM_COUNTS_10000(name, - cache_counts->cache_miss_count.load( - std::memory_order_acquire)); + base::UmaHistogramCounts10000( + name, cache_counts->cache_miss_count.load( + std::memory_order_acquire)); } }, - uma_prefix_ + nameStr + ".Counts.90SecondsPostStartup", - cache_counts_), + uma_prefix_ + name + ".Counts.90SecondsPostStartup", cache_counts_), base::Seconds(90)); } } +void DawnPlatform::HistogramCustomCounts(const char* name, + int sample, + int min, + int max, + int bucketCount) { + base::UmaHistogramCustomCounts(uma_prefix_ + name, sample, min, max, + bucketCount); + HistogramCacheCountHelper(name, sample, min, max, bucketCount); +} + void DawnPlatform::HistogramCustomCountsHPC(const char* name, int sample, int min, @@ -192,6 +204,7 @@ if (base::TimeTicks::IsHighResolution()) { base::UmaHistogramCustomCounts(uma_prefix_ + name, sample, min, max, bucketCount); + HistogramCacheCountHelper(name, sample, min, max, bucketCount); } }
diff --git a/gpu/command_buffer/service/dawn_platform.h b/gpu/command_buffer/service/dawn_platform.h index 645e753..018a0274 100644 --- a/gpu/command_buffer/service/dawn_platform.h +++ b/gpu/command_buffer/service/dawn_platform.h
@@ -5,10 +5,11 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_DAWN_PLATFORM_H_ #define GPU_COMMAND_BUFFER_SERVICE_DAWN_PLATFORM_H_ -#include <memory> - #include <dawn/platform/DawnPlatform.h> +#include <memory> + +#include "base/time/time.h" #include "gpu/command_buffer/service/dawn_caching_interface.h" namespace gpu::webgpu { @@ -76,9 +77,16 @@ ~CacheCounts(); }; + void HistogramCacheCountHelper(std::string name, + int sample, + int min, + int max, + int bucketCount); + std::unique_ptr<DawnCachingInterface> dawn_caching_interface_ = nullptr; std::string uma_prefix_; scoped_refptr<CacheCounts> cache_counts_; + base::Time startup_time_; }; } // namespace gpu::webgpu
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 7cfc1e0..f065ee0 100644 --- a/gpu/command_buffer/service/shared_image/shared_image_factory.cc +++ b/gpu/command_buffer/service/shared_image/shared_image_factory.cc
@@ -232,12 +232,6 @@ auto supported_format = GetFormatPixmapSupport(supported_formats); base::UmaHistogramEnumeration("GPU.SharedImage.FormatPixmapSupport", supported_format); - - // Check if hardware GMBs with RG88 format are ever created. - bool is_rg88_supported = - base::Contains(supported_formats, gfx::BufferFormat::RG_88); - base::UmaHistogramBoolean("GPU.SharedImage.IsRG88HardwareGMBSupported", - is_rg88_supported); } } set_format_supported_metric = true;
diff --git "a/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json" "b/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json" index 9318a01d..6ee5ee2 100644 --- "a/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json" +++ "b/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json"
@@ -26,6 +26,9 @@ "target_platform": "linux" }, "legacy_gclient_config": { + "apply_configs": [ + "chromium_with_telemetry_dependencies" + ], "config": "chromium" } }
diff --git "a/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json" "b/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json" index 2321562..ac2f76d 100644 --- "a/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json" +++ "b/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json"
@@ -23,6 +23,9 @@ "target_platform": "linux" }, "legacy_gclient_config": { + "apply_configs": [ + "chromium_with_telemetry_dependencies" + ], "config": "chromium" } }
diff --git a/infra/config/generated/builders/try/linux_chromium_compile_dbg_ng/properties.json b/infra/config/generated/builders/try/linux_chromium_compile_dbg_ng/properties.json index df11509..afd5986b 100644 --- a/infra/config/generated/builders/try/linux_chromium_compile_dbg_ng/properties.json +++ b/infra/config/generated/builders/try/linux_chromium_compile_dbg_ng/properties.json
@@ -26,6 +26,9 @@ "target_platform": "linux" }, "legacy_gclient_config": { + "apply_configs": [ + "chromium_with_telemetry_dependencies" + ], "config": "chromium" } }
diff --git a/infra/config/generated/builders/try/linux_chromium_dbg_ng/properties.json b/infra/config/generated/builders/try/linux_chromium_dbg_ng/properties.json index 8919593..f2048c5 100644 --- a/infra/config/generated/builders/try/linux_chromium_dbg_ng/properties.json +++ b/infra/config/generated/builders/try/linux_chromium_dbg_ng/properties.json
@@ -26,6 +26,9 @@ "target_platform": "linux" }, "legacy_gclient_config": { + "apply_configs": [ + "chromium_with_telemetry_dependencies" + ], "config": "chromium" } }
diff --git a/infra/config/generated/testing/mixins.pyl b/infra/config/generated/testing/mixins.pyl index 7cb90d57..9d121ee 100644 --- a/infra/config/generated/testing/mixins.pyl +++ b/infra/config/generated/testing/mixins.pyl
@@ -917,7 +917,7 @@ 'cpu': 'arm64', 'gpu': 'apple:m2', 'mac_model': 'Mac14,7', - 'os': 'Mac-14.3.1|Mac-14.4.1', + 'os': 'Mac-14.4.1', 'pool': 'chromium.tests.gpu', 'display_attached': '1', 'hidpi': '1', @@ -1006,7 +1006,7 @@ 'cpu': 'x86-64', 'gpu': '1002:67ef', 'hidpi': '1', - 'os': 'Mac-14.3.1|Mac-14.4.1', + 'os': 'Mac-14.4.1', 'pool': 'chromium.tests.gpu', 'display_attached': '1', }, @@ -1018,7 +1018,7 @@ 'cpu': 'x86-64', 'gpu': '1002:67ef', 'hidpi': '1', - 'os': 'Mac-13.5', + 'os': 'Mac-13.5|Mac-14.4.1', 'pool': 'chromium.tests.gpu', 'display_attached': '1', },
diff --git a/infra/config/generated/testing/variants.pyl b/infra/config/generated/testing/variants.pyl index f04533d..51477e0 100644 --- a/infra/config/generated/testing/variants.pyl +++ b/infra/config/generated/testing/variants.pyl
@@ -283,16 +283,16 @@ }, 'LACROS_VERSION_SKEW_DEV': { 'identifier': 'Lacros version skew testing ash dev', - 'description': 'Run with ash-chrome version 126.0.6455.0', + 'description': 'Run with ash-chrome version 126.0.6475.0', 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome', ], 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v126.0.6455.0', - 'revision': 'version:126.0.6455.0', + 'location': 'lacros_version_skew_tests_v126.0.6475.0', + 'revision': 'version:126.0.6475.0', }, ], },
diff --git a/infra/config/subprojects/chromium/ci/chromium.linux.star b/infra/config/subprojects/chromium/ci/chromium.linux.star index 5250c3b..2a685d96 100644 --- a/infra/config/subprojects/chromium/ci/chromium.linux.star +++ b/infra/config/subprojects/chromium/ci/chromium.linux.star
@@ -247,6 +247,11 @@ builder_spec = builder_config.builder_spec( gclient_config = builder_config.gclient_config( config = "chromium", + apply_configs = [ + # This is necessary due to child builders running the + # telemetry_perf_unittests suite. + "chromium_with_telemetry_dependencies", + ], ), chromium_config = builder_config.chromium_config( config = "chromium",
diff --git a/infra/config/targets/lacros-version-skew-variants.json b/infra/config/targets/lacros-version-skew-variants.json index 27d65aa..fb6bbb6 100644 --- a/infra/config/targets/lacros-version-skew-variants.json +++ b/infra/config/targets/lacros-version-skew-variants.json
@@ -17,16 +17,16 @@ }, "LACROS_VERSION_SKEW_DEV": { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "identifier": "Lacros version skew testing ash dev", "swarming": { "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ] }
diff --git a/infra/config/targets/mixins.star b/infra/config/targets/mixins.star index ce249a9..b028f85 100644 --- a/infra/config/targets/mixins.star +++ b/infra/config/targets/mixins.star
@@ -1184,7 +1184,7 @@ "cpu": "arm64", "gpu": "apple:m2", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu", "display_attached": "1", "hidpi": "1", @@ -1298,7 +1298,7 @@ "cpu": "x86-64", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu", "display_attached": "1", }, @@ -1312,7 +1312,7 @@ "cpu": "x86-64", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "display_attached": "1", },
diff --git a/internal b/internal index 284bc9f..88e16d7 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit 284bc9fe6264205e4b08170f549ce8e1d32e3caf +Subproject commit 88e16d7638ad0e2c73a70bbd704a06bacd4224ae
diff --git a/ios/build/tools/setup-gn.config b/ios/build/tools/setup-gn.config index d38ca3ce4..96037d3 100644 --- a/ios/build/tools/setup-gn.config +++ b/ios/build/tools/setup-gn.config
@@ -1,10 +1,3 @@ -[goma] -# Controls whether goma is enabled or not. If you generally use goma but -# want to disable goma for a single build, consider using the environment -# variable GOMA_DISABLED. -enabled = False -install = "$GOMA_DIR" - [xcode] # Controls settings for the generated Xcode project. If jobs is non-zero # it will be passed to the ninja invocation in Xcode project.
diff --git a/ios/build/tools/setup-gn.py b/ios/build/tools/setup-gn.py index df8e9c08..bb0a31c0 100755 --- a/ios/build/tools/setup-gn.py +++ b/ios/build/tools/setup-gn.py
@@ -116,12 +116,6 @@ """ args = [] - if self._settings.getboolean('goma', 'enabled'): - args.append(('use_goma', True)) - goma_dir = self._settings.getstring('goma', 'install') - if goma_dir: - args.append(('goma_dir', '"%s"' % os.path.expanduser(goma_dir))) - is_debug = self._config == 'Debug' official = self._config == 'Official' is_optim = self._config in ('Profile', 'Official')
diff --git a/ios/build/tools/update_deps.py b/ios/build/tools/update_deps.py index d5cf3ea..6c3b99c 100755 --- a/ios/build/tools/update_deps.py +++ b/ios/build/tools/update_deps.py
@@ -34,10 +34,6 @@ # The line containing the dependence in the error message. TRANSITIVE_DEPENDEE_LINE_NUMBER = 6 -# An error message that can be displayed at the beginning of the error. -# This is supposed to be temporary and will be removed in 2024. -TEMPORARY_ERROR = "The gn arg use_goma=true will be deprecated" - MISSING_PATTERNS = [ (3, "It is not in any dependency of"), (5, "The include file is in the target(s):"), @@ -128,10 +124,8 @@ def extract_missing_dependency(error, prefix, patterns, dependant_line, dependee_line): """Parse gn error message for missing direct dependency.""" - lines = [ - line for line in error.splitlines() - if not line.startswith(TEMPORARY_ERROR) - ] + lines = error.splitlines() + if len(lines) <= patterns[-1][0]: return False, None for line_number, pattern in patterns:
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 2689853b..12a9e702 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -1580,6 +1580,26 @@ flag_descriptions::kLensCircleToSearchEnabledName, flag_descriptions::kLensCircleToSearchEnabledDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kLensCircleToSearchEnabled)}, + {"autofill-enable-save-card-loading-and-confirmation", + flag_descriptions::kAutofillEnableSaveCardLoadingAndConfirmationName, + flag_descriptions:: + kAutofillEnableSaveCardLoadingAndConfirmationDescription, + flags_ui::kOsIos, + FEATURE_VALUE_TYPE( + autofill::features::kAutofillEnableSaveCardLoadingAndConfirmation)}, + {"autofill-enable-save-card-local-save-fallback", + flag_descriptions::kAutofillEnableSaveCardLocalSaveFallbackName, + flag_descriptions::kAutofillEnableSaveCardLocalSaveFallbackDescription, + flags_ui::kOsIos, + FEATURE_VALUE_TYPE( + autofill::features::kAutofillEnableSaveCardLocalSaveFallback)}, + {"autofill-enable-vcn-enroll-loading-and-confirmation", + flag_descriptions::kAutofillEnableVcnEnrollLoadingAndConfirmationName, + flag_descriptions:: + kAutofillEnableVcnEnrollLoadingAndConfirmationDescription, + flags_ui::kOsIos, + FEATURE_VALUE_TYPE( + autofill::features::kAutofillEnableVcnEnrollLoadingAndConfirmation)}, }; bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index d4be777..0108a02f 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -89,6 +89,23 @@ "When enabled, some extra metrics logging for Autofill Downstream will " "start."; +const char kAutofillEnableSaveCardLoadingAndConfirmationName[] = + "Enable save card loading and confirmation UX"; +const char kAutofillEnableSaveCardLoadingAndConfirmationDescription[] = + "When enabled, a loading spinner will be shown when uploading a card to " + "the server and a confirmation screen will be will be shown based on the " + "result of the upload. If the upload is unsuccessful in being uploaded to " + "the server, it will be saved locally."; + +const char kAutofillEnableSaveCardLocalSaveFallbackName[] = + "Enable save card local save fallback"; +const char kAutofillEnableSaveCardLocalSaveFallbackDescription[] = + "When enabled, if a card fails to be uploaded to the server, the card " + "details will be saved locally instead. If a card with the same card " + "number and expiration date already exists in the local database, this " + "will be a no-op and the existing card will not be updated with any card " + "details from the form."; + const char kAutofillEnableSupportForAdminLevel2Name[] = "Enables parsing and filling of administrative area level 2 fields"; const char kAutofillEnableSupportForAdminLevel2Description[] = @@ -113,6 +130,14 @@ "When enabled, card product name (instead of issuer network) will be shown " "in Payments UI."; +const char kAutofillEnableVcnEnrollLoadingAndConfirmationName[] = + "Enable showing loading and confirmation screens for virtual card " + "enrollment"; +const char kAutofillEnableVcnEnrollLoadingAndConfirmationDescription[] = + "When enabled, the virtual card enrollment screen will present a loading " + "spinner while enrolling the card to the server and present a confirmation " + "screen with the result when completed."; + const char kAutofillEnableVerveCardSupportName[] = "Enable autofill support for Verve cards"; const char kAutofillEnableVerveCardSupportDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index 1f0aedf..b9f226c 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -78,6 +78,16 @@ extern const char kAutofillEnableRemadeDownstreamMetricsName[]; extern const char kAutofillEnableRemadeDownstreamMetricsDescription[]; +// Title and description for the flag to enable loading and confirmation +// for save card. +extern const char kAutofillEnableSaveCardLoadingAndConfirmationName[]; +extern const char kAutofillEnableSaveCardLoadingAndConfirmationDescription[]; + +// Title and description for the flag to enable fallback for save card failure +// to upload and saves the card locally instead. +extern const char kAutofillEnableSaveCardLocalSaveFallbackName[]; +extern const char kAutofillEnableSaveCardLocalSaveFallbackDescription[]; + // Title and description for the flag that controls whether Autofill handles // administrative area level 2 fields. extern const char kAutofillEnableSupportForAdminLevel2Name[]; @@ -98,6 +108,11 @@ extern const char kAutofillEnableCardProductNameName[]; extern const char kAutofillEnableCardProductNameDescription[]; +// Title and description for the flag to enable loading and confirmation +// for virtual card enrollment. +extern const char kAutofillEnableVcnEnrollLoadingAndConfirmationName[]; +extern const char kAutofillEnableVcnEnrollLoadingAndConfirmationDescription[]; + // Title and description for flag to enable Verve card support for autofill. extern const char kAutofillEnableVerveCardSupportName[]; extern const char kAutofillEnableVerveCardSupportDescription[];
diff --git a/ios/chrome/browser/settings/model/sync/utils/sync_util.mm b/ios/chrome/browser/settings/model/sync/utils/sync_util.mm index e0b3f0c..4605baf 100644 --- a/ios/chrome/browser/settings/model/sync/utils/sync_util.mm +++ b/ios/chrome/browser/settings/model/sync/utils/sync_util.mm
@@ -300,11 +300,7 @@ signin::IdentityManager* identityManager = IdentityManagerFactory::GetForBrowserState(browser_state); - // TODO(crbug.com/40066949): Simplify this (remove the whole - // `if (!UseIdentityErrorInfobar(syncService)) {...}`) after kSync users are - // migrated to kSignin in phase 3. See ConsentLevel::kSync documentation for - // details. - if (!identityManager->HasPrimaryAccount(signin::ConsentLevel::kSync)) { + if (!identityManager->HasPrimaryAccount(signin::ConsentLevel::kSignin)) { return false; } }
diff --git a/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_egtest.mm b/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_egtest.mm index d15da74..5e7aaaa 100644 --- a/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_egtest.mm +++ b/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_egtest.mm
@@ -201,6 +201,17 @@ CardUnmaskPromptNavigationBarTitle()]; } +- (void)testCardUnmaskAuthenticationSelectionAcceptanceButtonIsSetInitially { + [self showAuthenticationSelection]; + + // Ensure the "Send" button is present (since the first option, OTP, is pre + // selected). + [[EarlGrey + selectElementWithMatcher:CardUnmaskAuthenticationSelectionSendButton()] + assertWithMatcher:grey_allOf(grey_enabled(), grey_sufficientlyVisible(), + nil)]; +} + - (void)testCardUnmaskAuthenticationSelectionAcceptanceButtonLabel { [self showAuthenticationSelection];
diff --git a/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_mediator.mm b/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_mediator.mm index b6a9ca1..c286ff3c1 100644 --- a/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_mediator.mm +++ b/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_mediator.mm
@@ -38,6 +38,9 @@ [consumer_ setCardUnmaskOptions:ConvertChallengeOptions()]; [consumer_ setFooterText:base::SysUTF16ToNSString( model_controller_->GetContentFooterText())]; + [consumer_ + setChallengeAcceptanceLabel:base::SysUTF16ToNSString( + model_controller_->GetOkButtonLabel())]; } CardUnmaskAuthenticationSelectionMediator::
diff --git a/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_mediator_unittest.mm b/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_mediator_unittest.mm index 68ecaddd..534f70c 100644 --- a/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_mediator_unittest.mm +++ b/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_mediator_unittest.mm
@@ -116,7 +116,7 @@ }; TEST_F(CardUnmaskAuthenticationSelectionMediatorTest, - SetsHeaderTitleAndHeaderTextAndOptionsAndFooter) { + SetsHeaderTitleAndHeaderTextAndOptionsAndFooterAndChallengeAcceptance) { OCMExpect([consumer() setHeaderTitle: l10n_util::GetNSString( @@ -132,12 +132,38 @@ setFooterText: l10n_util::GetNSString( IDS_AUTOFILL_CARD_UNMASK_AUTHENTICATION_SELECTION_DIALOG_CURRENT_INFO_NOT_SEEN_TEXT)]); + OCMExpect([consumer() + setChallengeAcceptanceLabel: + l10n_util::GetNSString( + IDS_AUTOFILL_CARD_UNMASK_AUTHENTICATION_SELECTION_DIALOG_OK_BUTTON_LABEL_SEND)]); InitializeMediator( {SmsAutofillChallengeOption(), CvcAutofillChallengeOption()}); } TEST_F(CardUnmaskAuthenticationSelectionMediatorTest, + SetsSendLabelInitiallyWhenSmsIsTheFirstChallengeOption) { + OCMExpect([consumer() + setChallengeAcceptanceLabel: + l10n_util::GetNSString( + IDS_AUTOFILL_CARD_UNMASK_AUTHENTICATION_SELECTION_DIALOG_OK_BUTTON_LABEL_SEND)]); + + InitializeMediator( + {SmsAutofillChallengeOption(), CvcAutofillChallengeOption()}); +} + +TEST_F(CardUnmaskAuthenticationSelectionMediatorTest, + SetsContinueLabelInitiallyWhenCvcIsTheFirstChallengeOption) { + OCMExpect([consumer() + setChallengeAcceptanceLabel: + l10n_util::GetNSString( + IDS_AUTOFILL_CARD_UNMASK_AUTHENTICATION_SELECTION_DIALOG_OK_BUTTON_LABEL_CONTINUE)]); + + InitializeMediator( + {CvcAutofillChallengeOption(), SmsAutofillChallengeOption()}); +} + +TEST_F(CardUnmaskAuthenticationSelectionMediatorTest, OnDidSelectChallengeOption_SetsButtonLabel) { CardUnmaskAuthenticationSelectionMediator* mediator = InitializeMediator({SmsAutofillChallengeOption()});
diff --git a/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_view_controller.mm b/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_view_controller.mm index dea21433..67ba9e13 100644 --- a/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_view_controller.mm +++ b/ios/chrome/browser/ui/autofill/authentication/card_unmask_authentication_selection_view_controller.mm
@@ -29,7 +29,7 @@ NSString* _headerText; NSString* _footerText; NSArray<CardUnmaskChallengeOptionIOS*>* _challengeOptions; - NSNumber* _selectedChallengeOptionIndex; + NSInteger _selectedChallengeOptionIndex; UITableViewDiffableDataSource<NSString*, NSNumber*>* _challengeOptionsDataSource; } @@ -59,7 +59,7 @@ NSNumber* itemId) { return [weakSelf provideCellForTableView:tableView indexPath:indexPath - challengeOptionIndex:itemId]; + challengeOptionIndex:itemId.integerValue]; }]; self.tableView.dataSource = _challengeOptionsDataSource; NSDiffableDataSourceSnapshot<NSString*, NSNumber*>* snapshot = @@ -137,8 +137,7 @@ didSelectRowAtIndexPath:(NSIndexPath*)indexPath { // Set a checkmark on the cell when being selected. CHECK((NSUInteger)indexPath.row < [_challengeOptions count]); - [self setSelectedChallengeOptionIndex:[NSNumber - numberWithInteger:indexPath.row]]; + [self setSelectedChallengeOptionIndex:indexPath.row]; [self.mutator didSelectChallengeOption:_challengeOptions[indexPath.row]]; } @@ -166,17 +165,15 @@ // Deques and sets up a cell for the challenge option at index. - (UITableViewCell*)provideCellForTableView:(UITableView*)tableView indexPath:(NSIndexPath*)indexPath - challengeOptionIndex:(NSNumber*)challengeOptionIndex { + challengeOptionIndex:(NSInteger)challengeOptionIndex { TableViewDetailIconCell* cell = DequeueTableViewCell<TableViewDetailIconCell>(self.tableView); cell.textLabel.text = _challengeOptions[indexPath.row].modeLabel; [cell setDetailText:_challengeOptions[indexPath.row].challengeInfo]; - BOOL isSelected = - (_selectedChallengeOptionIndex != nil && - [_selectedChallengeOptionIndex isEqualToNumber:challengeOptionIndex]); - [cell setAccessoryType:isSelected ? UITableViewCellAccessoryCheckmark - : UITableViewCellAccessoryNone]; + [cell setAccessoryType:_selectedChallengeOptionIndex == challengeOptionIndex + ? UITableViewCellAccessoryCheckmark + : UITableViewCellAccessoryNone]; [cell setTextLayoutConstraintAxis:UILayoutConstraintAxisVertical]; [cell setDetailTextNumberOfLines:0]; // Use as many lines as needed. @@ -204,19 +201,15 @@ } // Sets the selected challenge option, updating the circle/checkmark icon. -- (void)setSelectedChallengeOptionIndex:(NSNumber*)selectedIndex { - if ([_selectedChallengeOptionIndex isEqualToNumber:selectedIndex]) { +- (void)setSelectedChallengeOptionIndex:(NSInteger)selectedIndex { + if (_selectedChallengeOptionIndex == selectedIndex) { return; } NSDiffableDataSourceSnapshot<NSString*, NSNumber*>* snapshot = [_challengeOptionsDataSource snapshot]; - if (_selectedChallengeOptionIndex != nil) { - [snapshot reloadItemsWithIdentifiers:@[ _selectedChallengeOptionIndex ]]; - } + [snapshot reloadItemsWithIdentifiers:@[ @(_selectedChallengeOptionIndex) ]]; _selectedChallengeOptionIndex = selectedIndex; - if (_selectedChallengeOptionIndex != nil) { - [snapshot reloadItemsWithIdentifiers:@[ _selectedChallengeOptionIndex ]]; - } + [snapshot reloadItemsWithIdentifiers:@[ @(_selectedChallengeOptionIndex) ]]; [_challengeOptionsDataSource applySnapshotUsingReloadData:snapshot]; }
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_suggestion_label.mm b/ios/chrome/browser/ui/autofill/form_input_accessory/form_suggestion_label.mm index f0df202..a6f9613 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_suggestion_label.mm +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_suggestion_label.mm
@@ -147,14 +147,14 @@ TextLabel(suggestionText, [UIColor colorNamed:kTextPrimaryColor], YES); valueLabel.font = [UIFont systemFontOfSize:valueLabel.font.pointSize weight:UIFontWeightMedium]; - [stackView addArrangedSubview:valueLabel]; + [stackView addArrangedSubview:[self splitLabel:valueLabel]]; if ([suggestion.minorValue length] > 0) { UILabel* minorValueLabel = TextLabel( suggestion.minorValue, [UIColor colorNamed:kTextPrimaryColor], YES); minorValueLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption2]; - [stackView addArrangedSubview:minorValueLabel]; + [stackView addArrangedSubview:[self splitLabel:minorValueLabel]]; } if ([suggestion.displayDescription length] > 0) { @@ -163,7 +163,7 @@ [UIColor colorNamed:kTextSecondaryColor], NO); description.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption2]; - [stackView addArrangedSubview:description]; + [stackView addArrangedSubview:[self splitLabel:description]]; } [self setBackgroundColor:[self customBackgroundColor]]; @@ -300,4 +300,43 @@ return maxWidth; } +// Splits a credit card label into 2 labels, with one being an incompressible +// credit card number label. +- (UIView*)splitLabel:(UILabel*)label { + if (![self isCreditCardSuggestion]) { + return label; + } + + // Look for a credit card number in the string. Note that U+202A is the + // "Left-to-right embedding" character and U+202C is the "Pop directional + // formatting" character. Credit card numbers are surrounded by these two + // Unicode characters. + NSRange range = + [label.text rangeOfString:@"\U0000202a• • "]; + if (range.location == NSNotFound || range.location < 1) { + return label; + } + + // Split the string in pre and post credit card number labels. + UILabel* creditCardLabel = [[UILabel alloc] init]; + creditCardLabel.font = label.font; + creditCardLabel.text = [label.text substringFromIndex:range.location]; + // The credit card number should not be compressible. + [creditCardLabel + setContentCompressionResistancePriority:UILayoutPriorityRequired + forAxis:UILayoutConstraintAxisHorizontal]; + + // Remove credit card number from the original string. + label.text = [label.text substringToIndex:range.location - 1]; + + // Stack both labels horizontally. + UIStackView* stackView = [[UIStackView alloc] initWithArrangedSubviews:@[]]; + stackView.axis = UILayoutConstraintAxisHorizontal; + stackView.alignment = UIStackViewAlignmentCenter; + stackView.spacing = kSpacing; + [stackView addArrangedSubview:label]; + [stackView addArrangedSubview:creditCardLabel]; + return stackView; +} + @end
diff --git a/ios/web_view/tools/build.py b/ios/web_view/tools/build.py index f24a6eb..296eecc 100755 --- a/ios/web_view/tools/build.py +++ b/ios/web_view/tools/build.py
@@ -196,8 +196,6 @@ parser.add_argument('out_dir', nargs='?', default='out/IOSWebViewBuild', help='path to output directory') - parser.add_argument('--no_goma', action='store_true', - help='Prevents adding use_goma=true to the gn args.') parser.add_argument('--ninja_args', help='Additional gn args to pass through to ninja.') build_configs = ['Debug', 'Release'] @@ -224,8 +222,6 @@ output_name = 'ChromeWebView' extra_gn_options = [] - if not options.no_goma: - extra_gn_options.append('use_goma=true') # This prevents Breakpad from being included in the final binary to avoid # duplicate symbols with the client app. extra_gn_options.append('use_crash_key_stubs=true')
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins index 8f23851..dbbe554 100644 --- a/net/http/transport_security_state_static.pins +++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@ # hash function for preloaded entries again (we have already done so once). # -# Last updated: 2024-05-15 12:57 UTC +# Last updated: 2024-05-16 13:17 UTC PinsListTimestamp -1715777868 +1715865434 TestSPKI sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/net/http/transport_security_state_static_pins.json b/net/http/transport_security_state_static_pins.json index b37456d..b7a55f0 100644 --- a/net/http/transport_security_state_static_pins.json +++ b/net/http/transport_security_state_static_pins.json
@@ -31,7 +31,7 @@ // the 'static_spki_hashes' and 'bad_static_spki_hashes' fields in 'pinsets' // refer to, and the timestamp at which the pins list was last updated. // -// Last updated: 2024-05-15 12:57 UTC +// Last updated: 2024-05-16 13:17 UTC // { "pinsets": [
diff --git a/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java index 0b3d9979..e403d97 100644 --- a/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java +++ b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java
@@ -19,7 +19,6 @@ import org.chromium.base.Log; import org.chromium.base.ResettersForTesting; import org.chromium.base.ThreadUtils; -import org.chromium.base.test.BaseJUnit4ClassRunner.ClassHook; import org.chromium.base.test.util.UrlUtils; import org.chromium.net.X509Util; import org.chromium.net.test.util.CertTestUtil; @@ -523,11 +522,7 @@ } } - public static ClassHook getPreClassHook() { - return (targetContext, testClass) -> EmbeddedTestServer.setUpClass(testClass); - } - - public static void setUpClass(Class<?> clazz) { + public static void initCerts() { if (sTestRootInitDone) { return; }
diff --git a/net/test/embedded_test_server/http_response.h b/net/test/embedded_test_server/http_response.h index f35a19f..97f275f 100644 --- a/net/test/embedded_test_server/http_response.h +++ b/net/test/embedded_test_server/http_response.h
@@ -94,7 +94,11 @@ void set_code(HttpStatusCode code) { code_ = code; } std::string reason() const { - return reason_.value_or(GetHttpReasonPhrase(code_)); + if (reason_) { + return *reason_; + } else { + return GetHttpReasonPhrase(code_); + } } void set_reason(std::optional<std::string> reason) { reason_ = std::move(reason);
diff --git a/services/network/cookie_manager.cc b/services/network/cookie_manager.cc index 9cd091b..fee9086 100644 --- a/services/network/cookie_manager.cc +++ b/services/network/cookie_manager.cc
@@ -333,11 +333,6 @@ cookie_settings_.set_block_third_party_cookies(block); } -void CookieManager::BlockTruncatedCookies(bool block) { - OnSettingsWillChange(); - cookie_settings_.set_block_truncated_cookies(block); -} - void CookieManager::SetMitigationsEnabledFor3pcd(bool enable) { OnSettingsWillChange(); cookie_settings_.set_mitigations_enabled_for_3pcd(enable); @@ -359,7 +354,6 @@ const network::mojom::CookieManagerParams& params, CookieSettings* out) { out->set_block_third_party_cookies(params.block_third_party_cookies); - out->set_block_truncated_cookies(params.block_truncated_cookies); out->set_mitigations_enabled_for_3pcd(params.mitigations_enabled_for_3pcd); out->set_tracking_protection_enabled_for_3pcd( params.tracking_protection_enabled_for_3pcd);
diff --git a/services/network/cookie_manager.h b/services/network/cookie_manager.h index 1518b88..71178430 100644 --- a/services/network/cookie_manager.h +++ b/services/network/cookie_manager.h
@@ -114,7 +114,6 @@ AllowFileSchemeCookiesCallback callback) override; void SetForceKeepSessionState() override; void BlockThirdPartyCookies(bool block) override; - void BlockTruncatedCookies(bool block) override; void SetMitigationsEnabledFor3pcd(bool enable) override; void SetTrackingProtectionEnabledFor3pcd(bool enable) override;
diff --git a/services/network/cookie_settings.h b/services/network/cookie_settings.h index dc11ffa5..24cba5e 100644 --- a/services/network/cookie_settings.h +++ b/services/network/cookie_settings.h
@@ -90,10 +90,6 @@ void set_content_settings(ContentSettingsType type, const ContentSettingsForOneType& settings); - void set_block_truncated_cookies(bool block_truncated_cookies) { - block_truncated_cookies_ = block_truncated_cookies; - } - void set_mitigations_enabled_for_3pcd(bool enable) { mitigations_enabled_for_3pcd_ = enable; } @@ -106,10 +102,6 @@ tpcd_metadata_manager_ = manager; } - bool are_truncated_cookies_blocked() const { - return block_truncated_cookies_; - } - // Returns a predicate that takes the domain of a cookie and a bool whether // the cookie is secure and returns true if the cookie should be deleted on // exit. @@ -238,7 +230,6 @@ // Returns true if user blocks 3PC or 3PCD is on. bool block_third_party_cookies_ = net::cookie_util::IsForceThirdPartyCookieBlockingEnabled(); - bool block_truncated_cookies_ = true; bool mitigations_enabled_for_3pcd_ = false; // This bool makes sure the correct cookie exclusion reasons are used. bool tracking_protection_enabled_for_3pcd_ = false;
diff --git a/services/network/public/mojom/cookie_manager.mojom b/services/network/public/mojom/cookie_manager.mojom index 10d34fe..085af48 100644 --- a/services/network/public/mojom/cookie_manager.mojom +++ b/services/network/public/mojom/cookie_manager.mojom
@@ -18,15 +18,6 @@ // Whether or not third party cookies should be blocked. bool block_third_party_cookies = false; - // Whether or not truncated cookies should be ignored. Defaults to true but - // can be overridden in cases such as when the feature has been disabled via - // Enterprise Policy. Regardless of whether this value is true, the blocking - // of truncated cookies will not occur if the kBlockTruncatedCookies feature - // is disabled (thus, this default value is acceptable for WebView and other - // non-Chrome platforms where the feature flag is the primary means to control - // the value). - bool block_truncated_cookies = true; - // Whether tracking protection for 3PCD (prefs + UX) is enabled. bool tracking_protection_enabled_for_3pcd = false; @@ -491,11 +482,6 @@ // Enables/Disables blocking of third-party cookies. BlockThirdPartyCookies(bool block); - // Enables/Disables blocking of truncated cookies. This provides a way to - // change the setting at runtime, which allows the corresponding enterprise - // policy to not require a restart to take affect. - BlockTruncatedCookies(bool block); - // Enables/Disables mitigations for third-party cookies deprecation. SetMitigationsEnabledFor3pcd(bool enable);
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc index 52883c6..d2c94fe 100644 --- a/services/network/restricted_cookie_manager.cc +++ b/services/network/restricted_cookie_manager.cc
@@ -955,8 +955,7 @@ net::CanonicalCookie::Create( url, cookie, base::Time::Now(), /*server_time=*/std::nullopt, cookie_partition_key_, - cookie_settings().are_truncated_cookies_blocked(), - net::CookieSourceType::kScript, &status); + /*block_truncated=*/true, net::CookieSourceType::kScript, &status); if (!parsed_cookie) { if (cookie_observer_) { std::vector<network::mojom::CookieOrLineWithAccessResultPtr>
diff --git a/services/network/test/test_cookie_manager.h b/services/network/test/test_cookie_manager.h index 1a165f2..8885311 100644 --- a/services/network/test/test_cookie_manager.h +++ b/services/network/test/test_cookie_manager.h
@@ -61,7 +61,6 @@ SetContentSettingsCallback callback) override {} void SetForceKeepSessionState() override {} void BlockThirdPartyCookies(bool block) override {} - void BlockTruncatedCookies(bool block) override {} void SetMitigationsEnabledFor3pcd(bool enable) override {} void SetTrackingProtectionEnabledFor3pcd(bool enable) override {} void SetPreCommitCallbackDelayForTesting(base::TimeDelta delay) override {}
diff --git a/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom b/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom index c9056af..3ede19b 100644 --- a/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom +++ b/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom
@@ -23,6 +23,7 @@ import "services/viz/public/mojom/compositing/copy_output_result.mojom"; import "services/viz/public/mojom/compositing/video_detector_observer.mojom"; import "third_party/blink/public/mojom/tokens/tokens.mojom"; +import "ui/gfx/geometry/mojom/geometry.mojom"; // Initialization parameters for a RootCompositorFrameSink. struct RootCompositorFrameSinkParams { @@ -220,6 +221,11 @@ // testing only. [Sync] HasUnclaimedViewTransitionResourcesForTest() => (bool has_resources); + + // Customizes the CopyOutputRequest's result size during tests. + [Sync] + SetSameDocNavigationScreenshotSizeForTesting( + gfx.mojom.Size result_size) => (); }; // The FrameSinkManagerClient interface is implemented by the Display
diff --git a/services/webnn/tflite/graph_builder.cc b/services/webnn/tflite/graph_builder.cc index b75b755..4340d34 100644 --- a/services/webnn/tflite/graph_builder.cc +++ b/services/webnn/tflite/graph_builder.cc
@@ -1095,9 +1095,9 @@ auto GraphBuilder::SerializeGather(const mojom::Gather& gather) -> base::expected<OperatorOffset, std::string> { - // The WebNN indices must be one of type uint32, int32, int64, but TFLite - // indices need int32 or int64 type, so a cast operation need to be inserted - // before Gather if indices data type is uint32. + // The WebNN indices must be one of type uint32 or int64, but TFLite indices + // need int32 or int64 type, so a cast operation need to be inserted before + // Gather if indices data type is uint32. int32_t indices_tensor_index = operand_to_index_map_.at(gather.indices_operand_id); const mojom::Operand& indices_operand = GetOperand(gather.indices_operand_id); @@ -1112,8 +1112,7 @@ /*input_tensor_type=*/::tflite::TensorType_UINT32, indices_tensor_index, /*output_tensor_type=*/::tflite::TensorType_INT64)); } else { - CHECK(indices_operand.data_type == mojom::Operand::DataType::kInt64 || - indices_operand.data_type == mojom::Operand::DataType::kInt32); + CHECK_EQ(indices_operand.data_type, mojom::Operand::DataType::kInt64); } // The WebNN axis option is uint32 data type, but TFLite axis needs int32
diff --git a/testing/buildbot/chromium.angle.json b/testing/buildbot/chromium.angle.json index 7bca003..07ef80a 100644 --- a/testing/buildbot/chromium.angle.json +++ b/testing/buildbot/chromium.angle.json
@@ -687,7 +687,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -717,7 +717,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -758,7 +758,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -796,7 +796,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -836,7 +836,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -874,7 +874,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -913,7 +913,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -951,7 +951,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -988,7 +988,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false,
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 65587cb..6162902 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -5517,9 +5517,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5529,8 +5529,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": { @@ -5673,9 +5673,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5685,8 +5685,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": {
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json index 780c5ee..b59fc86d 100644 --- a/testing/buildbot/chromium.coverage.json +++ b/testing/buildbot/chromium.coverage.json
@@ -19694,9 +19694,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -19706,8 +19706,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": { @@ -19850,9 +19850,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -19862,8 +19862,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": {
diff --git a/testing/buildbot/chromium.dawn.json b/testing/buildbot/chromium.dawn.json index 745e858..b50eb075 100644 --- a/testing/buildbot/chromium.dawn.json +++ b/testing/buildbot/chromium.dawn.json
@@ -5168,7 +5168,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5197,7 +5197,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5225,7 +5225,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5254,7 +5254,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5283,7 +5283,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5310,7 +5310,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5342,7 +5342,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5374,7 +5374,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5399,7 +5399,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5433,7 +5433,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5467,7 +5467,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5506,7 +5506,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5546,7 +5546,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5586,7 +5586,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5625,7 +5625,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5666,7 +5666,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5701,7 +5701,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5735,7 +5735,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5775,7 +5775,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -5818,7 +5818,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6541,7 +6541,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6569,7 +6569,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6596,7 +6596,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6624,7 +6624,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6652,7 +6652,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6678,7 +6678,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6709,7 +6709,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6740,7 +6740,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6764,7 +6764,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6797,7 +6797,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6830,7 +6830,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6867,7 +6867,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6907,7 +6907,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6941,7 +6941,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -6974,7 +6974,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -7013,7 +7013,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -7055,7 +7055,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -7605,7 +7605,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7634,7 +7634,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7662,7 +7662,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7691,7 +7691,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7720,7 +7720,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7747,7 +7747,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7779,7 +7779,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7811,7 +7811,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7836,7 +7836,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7870,7 +7870,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7904,7 +7904,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7942,7 +7942,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -7983,7 +7983,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -8018,7 +8018,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -8052,7 +8052,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -8092,7 +8092,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -8135,7 +8135,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -8207,7 +8207,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8235,7 +8235,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8262,7 +8262,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8290,7 +8290,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8318,7 +8318,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8344,7 +8344,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8375,7 +8375,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8406,7 +8406,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8430,7 +8430,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8463,7 +8463,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8496,7 +8496,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8533,7 +8533,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8573,7 +8573,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8607,7 +8607,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8640,7 +8640,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8679,7 +8679,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -8721,7 +8721,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800,
diff --git a/testing/buildbot/chromium.fuchsia.fyi.json b/testing/buildbot/chromium.fuchsia.fyi.json index f74f702..9bb43995 100644 --- a/testing/buildbot/chromium.fuchsia.fyi.json +++ b/testing/buildbot/chromium.fuchsia.fyi.json
@@ -1087,64 +1087,6 @@ }, { "args": [ - "--num-retries=3", - "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json" - ], - "merge": { - "args": [ - "--verbose" - ], - "script": "//third_party/blink/tools/merge_web_test_results.py" - }, - "name": "blink_web_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "results_handler": "layout tests", - "swarming": { - "dimensions": { - "cpu": "arm64", - "inside_docker": "1", - "os": "Ubuntu-22.04|Ubuntu-20.04" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 5 - }, - "test": "blink_web_tests", - "test_id_prefix": "ninja://:blink_web_tests/" - }, - { - "args": [ - "--num-retries=3", - "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json" - ], - "merge": { - "args": [ - "--verbose" - ], - "script": "//third_party/blink/tools/merge_web_test_results.py" - }, - "name": "blink_wpt_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "results_handler": "layout tests", - "swarming": { - "dimensions": { - "cpu": "arm64", - "inside_docker": "1", - "os": "Ubuntu-22.04|Ubuntu-20.04" - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 7 - }, - "test": "blink_wpt_tests", - "test_id_prefix": "ninja://:blink_wpt_tests/" - }, - { - "args": [ "context_lost", "--show-stdout", "--browser=web-engine-shell",
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 96bef93b9..258f85c 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -41869,9 +41869,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -41880,8 +41880,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": { @@ -42019,9 +42019,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -42030,8 +42030,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": { @@ -43369,9 +43369,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -43381,8 +43381,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": { @@ -43525,9 +43525,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -43537,8 +43537,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": { @@ -44849,9 +44849,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -44860,8 +44860,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": { @@ -44999,9 +44999,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -45010,8 +45010,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": {
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index 5bbb93d..c7273757 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -12592,7 +12592,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -12621,7 +12621,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -12654,7 +12654,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -12680,7 +12680,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -12703,7 +12703,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -12730,7 +12730,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -12759,7 +12759,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -12799,7 +12799,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -12838,7 +12838,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -12877,7 +12877,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -12925,7 +12925,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -12973,7 +12973,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13021,7 +13021,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13060,7 +13060,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13099,7 +13099,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13142,7 +13142,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13190,7 +13190,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13238,7 +13238,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13286,7 +13286,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13326,7 +13326,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13366,7 +13366,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13406,7 +13406,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13445,7 +13445,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13484,7 +13484,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13523,7 +13523,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13562,7 +13562,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13603,7 +13603,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13646,7 +13646,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13687,7 +13687,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13729,7 +13729,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13770,7 +13770,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13810,7 +13810,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13839,7 +13839,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13869,7 +13869,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13903,7 +13903,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13930,7 +13930,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13954,7 +13954,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -13982,7 +13982,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14012,7 +14012,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14053,7 +14053,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14093,7 +14093,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14133,7 +14133,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14182,7 +14182,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14231,7 +14231,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14280,7 +14280,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14320,7 +14320,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14360,7 +14360,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14404,7 +14404,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14453,7 +14453,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14502,7 +14502,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14551,7 +14551,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14592,7 +14592,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14633,7 +14633,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14674,7 +14674,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14714,7 +14714,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14754,7 +14754,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14794,7 +14794,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14834,7 +14834,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14876,7 +14876,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14920,7 +14920,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -14962,7 +14962,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -15005,7 +15005,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -15047,7 +15047,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -15088,7 +15088,7 @@ "gpu": "apple:m2", "hidpi": "1", "mac_model": "Mac14,7", - "os": "Mac-14.3.1|Mac-14.4.1", + "os": "Mac-14.4.1", "pool": "chromium.tests.gpu" }, "expiration": 21600, @@ -17242,7 +17242,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17270,7 +17270,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17302,7 +17302,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17327,7 +17327,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17349,7 +17349,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17375,7 +17375,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17403,7 +17403,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17442,7 +17442,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17489,7 +17489,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17536,7 +17536,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17575,7 +17575,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17613,7 +17613,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17653,7 +17653,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17693,7 +17693,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17733,7 +17733,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17760,7 +17760,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17788,7 +17788,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17820,7 +17820,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17845,7 +17845,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17867,7 +17867,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17893,7 +17893,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17932,7 +17932,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -17979,7 +17979,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18017,7 +18017,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18055,7 +18055,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18097,7 +18097,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18144,7 +18144,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18183,7 +18183,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18221,7 +18221,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18260,7 +18260,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18288,7 +18288,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18316,7 +18316,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18348,7 +18348,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18373,7 +18373,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18395,7 +18395,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18421,7 +18421,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18449,7 +18449,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18488,7 +18488,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18526,7 +18526,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18573,7 +18573,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18620,7 +18620,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18658,7 +18658,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18696,7 +18696,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18743,7 +18743,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18790,7 +18790,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18829,7 +18829,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18868,7 +18868,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18906,7 +18906,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18944,7 +18944,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -18982,7 +18982,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -19022,7 +19022,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -19064,7 +19064,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -19104,7 +19104,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -19145,7 +19145,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800, @@ -19184,7 +19184,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "hard_timeout": 1800,
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json index efa428f..5e66c17 100644 --- a/testing/buildbot/chromium.gpu.json +++ b/testing/buildbot/chromium.gpu.json
@@ -2152,7 +2152,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2181,7 +2181,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2214,7 +2214,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2254,7 +2254,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2302,7 +2302,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2341,7 +2341,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2380,7 +2380,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2423,7 +2423,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2471,7 +2471,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2511,7 +2511,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2550,7 +2550,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2591,7 +2591,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2619,7 +2619,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2648,7 +2648,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2681,7 +2681,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2710,7 +2710,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2750,7 +2750,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2798,7 +2798,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2837,7 +2837,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2876,7 +2876,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2919,7 +2919,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -2967,7 +2967,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -3007,7 +3007,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -3046,7 +3046,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" }, @@ -3087,7 +3087,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu", "puppet_env": "production" },
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index 263da30..cdc0a9d 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -15796,12 +15796,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -15811,8 +15811,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": { @@ -15972,12 +15972,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 126.0.6455.0", + "description": "Run with ash-chrome version 126.0.6475.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -15987,8 +15987,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v126.0.6455.0", - "revision": "version:126.0.6455.0" + "location": "lacros_version_skew_tests_v126.0.6475.0", + "revision": "version:126.0.6475.0" } ], "dimensions": {
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json index 3fbf88f7..a466c82 100644 --- a/testing/buildbot/chromium.perf.fyi.json +++ b/testing/buildbot/chromium.perf.fyi.json
@@ -306,14 +306,14 @@ "can_use_on_swarming_builders": true, "dimensions": { "gpu": "10de", - "os": "Ubuntu-22.04", + "os": "Ubuntu", "pool": "chrome.tests.perf-fyi" }, "expiration": 7200, "hard_timeout": 21600, "io_timeout": 21600, "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 1 + "shards": 4 }, "test": "performance_test_suite", "trigger_script": {
diff --git a/testing/buildbot/filters/android.emulator_13.content_browsertests.filter b/testing/buildbot/filters/android.emulator_13.content_browsertests.filter index 70cd81d..e9396dd4 100644 --- a/testing/buildbot/filters/android.emulator_13.content_browsertests.filter +++ b/testing/buildbot/filters/android.emulator_13.content_browsertests.filter
@@ -45,9 +45,6 @@ # crbug.com/340585286 -FoldableAPIsOriginTrialBrowserTest.ValidOriginTrialToken -# crbug.com/340585314 --AttributionInternalsWebUiBrowserTest.WebUIWithPendingReportsClearStorage_ReportsRemoved - # crbug.com/340587779 -PerformanceTimelineBrowserTest.NoResourceTimingEntryForFileProtocol
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index 7cb90d57..9d121ee 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl
@@ -917,7 +917,7 @@ 'cpu': 'arm64', 'gpu': 'apple:m2', 'mac_model': 'Mac14,7', - 'os': 'Mac-14.3.1|Mac-14.4.1', + 'os': 'Mac-14.4.1', 'pool': 'chromium.tests.gpu', 'display_attached': '1', 'hidpi': '1', @@ -1006,7 +1006,7 @@ 'cpu': 'x86-64', 'gpu': '1002:67ef', 'hidpi': '1', - 'os': 'Mac-14.3.1|Mac-14.4.1', + 'os': 'Mac-14.4.1', 'pool': 'chromium.tests.gpu', 'display_attached': '1', }, @@ -1018,7 +1018,7 @@ 'cpu': 'x86-64', 'gpu': '1002:67ef', 'hidpi': '1', - 'os': 'Mac-13.5', + 'os': 'Mac-13.5|Mac-14.4.1', 'pool': 'chromium.tests.gpu', 'display_attached': '1', },
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index fe2d06a7..9a1fa26b 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -327,6 +327,9 @@ }, 'blink_web_tests': { 'remove_from': [ + # No arm64 apache suppport for fuchsia arm64 bots yet. + 'fuchsia-arm64-cast-receiver-rel', + 'fuchsia-fyi-arm64-dbg', 'Win10 Tests x64 (dbg)', 'win11-arm64-dbg-tests', ], @@ -618,6 +621,9 @@ 'Win10 Tests x64 (dbg)', 'devtools_frontend_linux_blink_light_rel', 'devtools_frontend_linux_blink_light_rel_fastbuild', + # No arm64 apache suppport for fuchsia arm64 bots yet. + 'fuchsia-arm64-cast-receiver-rel', + 'fuchsia-fyi-arm64-dbg', 'linux-rel-cft', 'mac-rel-cft', 'win-rel-cft',
diff --git a/testing/buildbot/tryserver.chromium.mac.json b/testing/buildbot/tryserver.chromium.mac.json index 6fa2c7d..bbac3e9 100644 --- a/testing/buildbot/tryserver.chromium.mac.json +++ b/testing/buildbot/tryserver.chromium.mac.json
@@ -17,7 +17,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -81,7 +81,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -143,7 +143,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -226,7 +226,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -296,7 +296,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -375,7 +375,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -463,7 +463,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -542,7 +542,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -612,7 +612,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -686,7 +686,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -809,7 +809,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -897,7 +897,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -977,7 +977,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -1049,7 +1049,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -1120,7 +1120,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -1226,7 +1226,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -1332,7 +1332,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -1402,7 +1402,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -1475,7 +1475,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -1551,7 +1551,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -1626,7 +1626,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false, @@ -1699,7 +1699,7 @@ "display_attached": "1", "gpu": "1002:67ef", "hidpi": "1", - "os": "Mac-13.5", + "os": "Mac-13.5|Mac-14.4.1", "pool": "chromium.tests.gpu" }, "idempotent": false,
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index f04533d..51477e0 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -283,16 +283,16 @@ }, 'LACROS_VERSION_SKEW_DEV': { 'identifier': 'Lacros version skew testing ash dev', - 'description': 'Run with ash-chrome version 126.0.6455.0', + 'description': 'Run with ash-chrome version 126.0.6475.0', 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6455.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome', ], 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v126.0.6455.0', - 'revision': 'version:126.0.6455.0', + 'location': 'lacros_version_skew_tests_v126.0.6475.0', + 'revision': 'version:126.0.6475.0', }, ], },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 16621a9..d71fd68 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -2310,6 +2310,28 @@ ] } ], + "AvoidScheduleWorkDuringNativeEventProcessing": [ + { + "platforms": [ + "android_webview", + "android", + "chromeos", + "chromeos_lacros", + "ios", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AvoidScheduleWorkDuringNativeEventProcessing" + ] + } + ] + } + ], "BFCachePerformanceManagerPolicy": [ { "platforms": [ @@ -4647,6 +4669,23 @@ ] } ], + "ComposeUiRefinement": [ + { + "platforms": [ + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "ComposeUiRefinement" + ] + } + ] + } + ], "CompressionDictionaryTransport": [ { "platforms": [ @@ -5829,12 +5868,12 @@ ], "experiments": [ { - "name": "Enabled1", + "name": "V1Enabled2_20240516", "params": { - "group_name": "enabled-arm-1", + "group_name": "enabled-v1-arm-2", "max_prompt_count": "5", "reprompt_duration": "7d", - "reprompt_duration_multiplier ": "2", + "reprompt_duration_multiplier": "2", "show_app_menu_chip": "false", "show_info_bar": "true", "updated_info_bar_copy": "true" @@ -16199,6 +16238,23 @@ ] } ], + "PumpFastToSleepAndroid": [ + { + "platforms": [ + "android_weblayer", + "android_webview", + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "PumpFastToSleepAndroid" + ] + } + ] + } + ], "PushMessagingDisallowSenderIDs": [ { "platforms": [ @@ -19952,6 +20008,24 @@ ] } ], + "TabStateFlatBuffer": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled_20240713", + "params": { + "migrate_stale_tabs": "false" + }, + "enable_features": [ + "TabStateFlatBuffer" + ] + } + ] + } + ], "TabStripStartupRefactoring": [ { "platforms": [
diff --git a/third_party/blink/renderer/core/css/css_anchor_query_enums.h b/third_party/blink/renderer/core/css/css_anchor_query_enums.h index db113d8..dc93709 100644 --- a/third_party/blink/renderer/core/css/css_anchor_query_enums.h +++ b/third_party/blink/renderer/core/css/css_anchor_query_enums.h
@@ -20,6 +20,8 @@ ~kCSSAnchorQueryTypesNone; enum class CSSAnchorValue { + kInside, + kOutside, kTop, kLeft, kRight,
diff --git a/third_party/blink/renderer/core/css/css_axis_value.h b/third_party/blink/renderer/core/css/css_axis_value.h index bda8896..ce4c30c 100644 --- a/third_party/blink/renderer/core/css/css_axis_value.h +++ b/third_party/blink/renderer/core/css/css_axis_value.h
@@ -9,6 +9,10 @@ #include "third_party/blink/renderer/core/css_value_keywords.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { namespace cssvalue { @@ -17,7 +21,7 @@ explicit CSSAxisValue(CSSValueID axis_name); CSSAxisValue(double x, double y, double z); - String CustomCSSText() const; + WTF::String CustomCSSText() const; double X() const;
diff --git a/third_party/blink/renderer/core/css/css_border_image_slice_value.h b/third_party/blink/renderer/core/css/css_border_image_slice_value.h index 6438b0c..afa4adf0 100644 --- a/third_party/blink/renderer/core/css/css_border_image_slice_value.h +++ b/third_party/blink/renderer/core/css/css_border_image_slice_value.h
@@ -30,6 +30,10 @@ #include "third_party/blink/renderer/core/css/css_quad_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { namespace cssvalue { @@ -37,7 +41,7 @@ public: CSSBorderImageSliceValue(CSSQuadValue* slices, bool fill); - String CustomCSSText() const; + WTF::String CustomCSSText() const; // TODO(sashab): Change this to a quad of CSSPrimitiveValues, or add separate // methods for topSlice(), leftSlice(), etc.
diff --git a/third_party/blink/renderer/core/css/css_bracketed_value_list.h b/third_party/blink/renderer/core/css/css_bracketed_value_list.h index ba34dc1..1ab4714 100644 --- a/third_party/blink/renderer/core/css/css_bracketed_value_list.h +++ b/third_party/blink/renderer/core/css/css_bracketed_value_list.h
@@ -34,6 +34,10 @@ #include "third_party/blink/renderer/core/css/css_value_list.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { namespace cssvalue { @@ -41,7 +45,7 @@ public: CSSBracketedValueList(); - String CustomCSSText() const; + WTF::String CustomCSSText() const; void TraceAfterDispatch(blink::Visitor* visitor) const { CSSValueList::TraceAfterDispatch(visitor);
diff --git a/third_party/blink/renderer/core/css/css_cursor_image_value.h b/third_party/blink/renderer/core/css/css_cursor_image_value.h index 52acc89..11e4591 100644 --- a/third_party/blink/renderer/core/css/css_cursor_image_value.h +++ b/third_party/blink/renderer/core/css/css_cursor_image_value.h
@@ -25,6 +25,10 @@ #include "third_party/blink/renderer/platform/wtf/casting.h" #include "ui/gfx/geometry/point.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { namespace cssvalue { @@ -39,7 +43,7 @@ const gfx::Point& HotSpot() const { return hot_spot_; } const CSSValue& ImageValue() const { return *image_value_; } - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSCursorImageValue&) const;
diff --git a/third_party/blink/renderer/core/css/css_cyclic_variable_value.h b/third_party/blink/renderer/core/css/css_cyclic_variable_value.h index aa29c36..cde7f8d 100644 --- a/third_party/blink/renderer/core/css/css_cyclic_variable_value.h +++ b/third_party/blink/renderer/core/css/css_cyclic_variable_value.h
@@ -10,6 +10,10 @@ #include "third_party/blink/renderer/core/css/css_invalid_variable_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CSSValuePool; @@ -25,7 +29,7 @@ explicit CSSCyclicVariableValue(base::PassKey<CSSValuePool>) : CSSInvalidVariableValue(kCyclicVariableValueClass) {} - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSCyclicVariableValue&) const { return true; }
diff --git a/third_party/blink/renderer/core/css/css_function_value.h b/third_party/blink/renderer/core/css/css_function_value.h index f5c105b0..69b8c15 100644 --- a/third_party/blink/renderer/core/css/css_function_value.h +++ b/third_party/blink/renderer/core/css/css_function_value.h
@@ -9,6 +9,10 @@ #include "third_party/blink/renderer/core/css_value_keywords.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CSSFunctionValue : public CSSValueList { @@ -16,7 +20,7 @@ CSSFunctionValue(CSSValueID id) : CSSValueList(kFunctionClass, kCommaSeparator), value_id_(id) {} - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSFunctionValue& other) const { return value_id_ == other.value_id_ && CSSValueList::Equals(other);
diff --git a/third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h b/third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h index 008c6cf..d0e6757 100644 --- a/third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h +++ b/third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h
@@ -9,6 +9,10 @@ #include "third_party/blink/renderer/core/css_value_keywords.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { namespace cssvalue { @@ -33,7 +37,7 @@ DCHECK(id == CSSValueID::kAutoFill || id == CSSValueID::kAutoFit); } - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSGridAutoRepeatValue&) const; CSSValueID AutoRepeatID() const { return auto_repeat_id_; }
diff --git a/third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h b/third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h index c9ae067..8bcc4da8 100644 --- a/third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h +++ b/third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h
@@ -10,6 +10,10 @@ #include "third_party/blink/renderer/core/css_value_keywords.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { namespace cssvalue { @@ -29,7 +33,7 @@ DCHECK_GT(repetitions, 0UL); } - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSGridIntegerRepeatValue&) const; wtf_size_t Repetitions() const { return repetitions_; }
diff --git a/third_party/blink/renderer/core/css/css_image_set_value.h b/third_party/blink/renderer/core/css/css_image_set_value.h index 1d933940..4cf6250 100644 --- a/third_party/blink/renderer/core/css/css_image_set_value.h +++ b/third_party/blink/renderer/core/css/css_image_set_value.h
@@ -31,6 +31,10 @@ #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CSSImageSetOptionValue; @@ -47,7 +51,7 @@ const CSSImageSetOptionValue* GetBestOption(const float device_scale_factor); - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool HasFailedOrCanceledSubresources() const;
diff --git a/third_party/blink/renderer/core/css/css_inherited_value.h b/third_party/blink/renderer/core/css/css_inherited_value.h index a5d10004..5ce377c 100644 --- a/third_party/blink/renderer/core/css/css_inherited_value.h +++ b/third_party/blink/renderer/core/css/css_inherited_value.h
@@ -26,6 +26,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CORE_EXPORT CSSInheritedValue : public CSSValue { @@ -36,7 +40,7 @@ // Create() to get the pooled value. CSSInheritedValue() : CSSValue(kInheritedClass) {} - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSInheritedValue&) const { return true; }
diff --git a/third_party/blink/renderer/core/css/css_initial_color_value.h b/third_party/blink/renderer/core/css/css_initial_color_value.h index 66be1f5..f3cc46c 100644 --- a/third_party/blink/renderer/core/css/css_initial_color_value.h +++ b/third_party/blink/renderer/core/css/css_initial_color_value.h
@@ -10,6 +10,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CSSValuePool; @@ -22,7 +26,7 @@ explicit CSSInitialColorValue(base::PassKey<CSSValuePool>) : CSSValue(kInitialColorValueClass) {} - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSInitialColorValue&) const { return true; }
diff --git a/third_party/blink/renderer/core/css/css_initial_value.h b/third_party/blink/renderer/core/css/css_initial_value.h index 0e2aebd..abddcf4 100644 --- a/third_party/blink/renderer/core/css/css_initial_value.h +++ b/third_party/blink/renderer/core/css/css_initial_value.h
@@ -26,6 +26,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CORE_EXPORT CSSInitialValue : public CSSValue { @@ -34,7 +38,7 @@ CSSInitialValue() : CSSValue(kInitialClass) {} - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSInitialValue&) const { return true; }
diff --git a/third_party/blink/renderer/core/css/css_invalid_variable_value.h b/third_party/blink/renderer/core/css/css_invalid_variable_value.h index a5b3f27..9e6e411 100644 --- a/third_party/blink/renderer/core/css/css_invalid_variable_value.h +++ b/third_party/blink/renderer/core/css/css_invalid_variable_value.h
@@ -9,6 +9,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { // A value which represents custom properties that are invalid at computed- @@ -23,7 +27,7 @@ // Create() to get the pooled value. CSSInvalidVariableValue() : CSSValue(kInvalidVariableValueClass) {} - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSInvalidVariableValue&) const { return true; }
diff --git a/third_party/blink/renderer/core/css/css_layout_function_value.h b/third_party/blink/renderer/core/css/css_layout_function_value.h index 18f0f0d..ec42c4e 100644 --- a/third_party/blink/renderer/core/css/css_layout_function_value.h +++ b/third_party/blink/renderer/core/css/css_layout_function_value.h
@@ -9,6 +9,10 @@ #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CSSCustomIdentValue; @@ -19,7 +23,7 @@ public: CSSLayoutFunctionValue(CSSCustomIdentValue* name, bool is_inline); - String CustomCSSText() const; + WTF::String CustomCSSText() const; AtomicString GetName() const; bool IsInline() const { return is_inline_; }
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node.cc b/third_party/blink/renderer/core/css/css_math_expression_node.cc index 8b7f34e..220a6d98 100644 --- a/third_party/blink/renderer/core/css/css_math_expression_node.cc +++ b/third_party/blink/renderer/core/css/css_math_expression_node.cc
@@ -2851,6 +2851,10 @@ CSSAnchorValue CSSValueIDToAnchorValueEnum(CSSValueID value) { switch (value) { + case CSSValueID::kInside: + return CSSAnchorValue::kInside; + case CSSValueID::kOutside: + return CSSAnchorValue::kOutside; case CSSValueID::kTop: return CSSAnchorValue::kTop; case CSSValueID::kLeft: @@ -3234,10 +3238,10 @@ switch (anchor_query_type) { case CSSAnchorQueryType::kAnchor: value = css_parsing_utils::ConsumeIdent< - CSSValueID::kTop, CSSValueID::kLeft, CSSValueID::kRight, - CSSValueID::kBottom, CSSValueID::kStart, CSSValueID::kEnd, - CSSValueID::kSelfStart, CSSValueID::kSelfEnd, CSSValueID::kCenter>( - tokens); + CSSValueID::kInside, CSSValueID::kOutside, CSSValueID::kTop, + CSSValueID::kLeft, CSSValueID::kRight, CSSValueID::kBottom, + CSSValueID::kStart, CSSValueID::kEnd, CSSValueID::kSelfStart, + CSSValueID::kSelfEnd, CSSValueID::kCenter>(tokens); if (!value) { value = css_parsing_utils::ConsumePercent( tokens, context_, CSSPrimitiveValue::ValueRange::kAll);
diff --git a/third_party/blink/renderer/core/css/css_pending_system_font_value.h b/third_party/blink/renderer/core/css/css_pending_system_font_value.h index bceb2452..ba6a980 100644 --- a/third_party/blink/renderer/core/css/css_pending_system_font_value.h +++ b/third_party/blink/renderer/core/css/css_pending_system_font_value.h
@@ -9,6 +9,10 @@ #include "third_party/blink/renderer/core/css_value_keywords.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { namespace cssvalue { @@ -41,7 +45,7 @@ return system_font_id_ == other.system_font_id_; } - String CustomCSSText() const; + WTF::String CustomCSSText() const; void TraceAfterDispatch(blink::Visitor*) const;
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5 index 55ac796..4c7db34 100644 --- a/third_party/blink/renderer/core/css/css_properties.json5 +++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -320,13 +320,13 @@ "border-radius", "border-outline-visited-color", "border-width", + "clip", "clip-path", "color", "compositing", "filter-data", "inset", "layout", - "list-item", "margin", "mask", "opacity", @@ -335,10 +335,11 @@ "paint", "reshape", "scroll-anchor", + "scrollbar-style", "stroke", - "table", "text-decoration", "transform-property", + "visibility", "visual-overflow", "z-index", ], @@ -2121,7 +2122,7 @@ }, valid_for_permission_element: true, valid_for_page_context: true, - invalidate: ["border-radius"], + invalidate: ["border-radius", "paint"], }, { name: "border-bottom-right-radius", @@ -2143,7 +2144,7 @@ }, valid_for_permission_element: true, valid_for_page_context: true, - invalidate: ["border-radius"], + invalidate: ["border-radius", "paint"], }, { name: "border-bottom-style", @@ -2200,7 +2201,7 @@ keywords: ["separate", "collapse"], typedom_types: ["Keyword"], default_value: "separate", - invalidate: ["table"], + invalidate: ["layout", "paint"], }, { name: "border-image-outset", @@ -2455,7 +2456,7 @@ }, valid_for_permission_element: true, valid_for_page_context: true, - invalidate: ["border-radius"], + invalidate: ["border-radius", "paint"], }, { name: "border-top-right-radius", @@ -2477,7 +2478,7 @@ }, valid_for_permission_element: true, valid_for_page_context: true, - invalidate: ["border-radius"], + invalidate: ["border-radius", "paint"], }, { name: "border-top-style", @@ -2635,7 +2636,7 @@ keywords: ["top", "bottom"], typedom_types: ["Keyword"], default_value: "top", - invalidate: ["table"], + invalidate: ["layout", "paint"], }, { name: "caret-color", @@ -2679,6 +2680,7 @@ converter: "ConvertClip", keywords: ["auto"], typedom_types: ["Keyword"], + invalidate: ["clip"], }, { name: "clip-path", @@ -3000,7 +3002,7 @@ keywords: ["show", "hide"], typedom_types: ["Keyword"], default_value: "show", - invalidate: ["table"], + invalidate: ["layout", "paint"], }, { name: "fill", @@ -3598,7 +3600,7 @@ keywords: ["outside", "inside"], typedom_types: ["Keyword"], default_value: "outside", - invalidate: ["list-item"], + invalidate: ["layout", "paint"], }, { name: "list-style-type", @@ -3616,7 +3618,7 @@ "decimal", "none" ], style_builder_custom_functions: ["value"], - invalidate: ["list-item"], + invalidate: ["layout", "paint"], }, { name: "margin-bottom", @@ -4468,7 +4470,7 @@ // have a priority higher than inset-area which is already at priority:1. priority: 2, valid_for_permission_element: true, - invalidate: ["layout", "scroll-anchor"], + invalidate: ["clip", "layout", "scroll-anchor"], }, { name: "position-anchor", @@ -4667,6 +4669,7 @@ default_value: "nullptr", wrapper_pointer_name: "Member", include_paths: ["third_party/blink/renderer/core/style/style_scrollbar_color.h"], + invalidate: ["scrollbar-style"], runtime_flag: "ScrollbarColor", }, { @@ -4694,7 +4697,7 @@ keywords: ["auto", "thin", "none"], default_value: "auto", typedom_types: ["Keyword"], - invalidate: ["layout", "paint"], + invalidate: ["layout", "paint", "scrollbar-style"], runtime_flag: "ScrollbarWidth", }, { @@ -5349,7 +5352,7 @@ ], typedom_types: ["Keyword"], default_value: "auto", - invalidate: ["table"], + invalidate: ["layout", "paint"], }, { name: "tab-size", @@ -5968,7 +5971,7 @@ valid_for_cue: true, valid_for_permission_element: true, valid_for_page_context: true, - invalidate: ["paint"], + invalidate: ["paint", "visibility"], }, { name: "x",
diff --git a/third_party/blink/renderer/core/css/css_quad_value.h b/third_party/blink/renderer/core/css/css_quad_value.h index 39df17e..897464a6 100644 --- a/third_party/blink/renderer/core/css/css_quad_value.h +++ b/third_party/blink/renderer/core/css/css_quad_value.h
@@ -26,6 +26,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CORE_EXPORT CSSQuadValue : public CSSValue { @@ -59,7 +63,7 @@ TypeForSerialization SerializationType() { return serialization_type_; } - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSQuadValue& other) const { return base::ValuesEquivalent(top_, other.top_) &&
diff --git a/third_party/blink/renderer/core/css/css_ray_value.h b/third_party/blink/renderer/core/css/css_ray_value.h index 98eadbf..c7c51ae 100644 --- a/third_party/blink/renderer/core/css/css_ray_value.h +++ b/third_party/blink/renderer/core/css/css_ray_value.h
@@ -8,6 +8,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CSSIdentifierValue; @@ -29,7 +33,7 @@ const CSSValue* CenterX() const { return center_x_.Get(); } const CSSValue* CenterY() const { return center_y_.Get(); } - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSRayValue&) const;
diff --git a/third_party/blink/renderer/core/css/css_reflect_value.h b/third_party/blink/renderer/core/css/css_reflect_value.h index 1b6e5749..2dc0e5d 100644 --- a/third_party/blink/renderer/core/css/css_reflect_value.h +++ b/third_party/blink/renderer/core/css/css_reflect_value.h
@@ -30,6 +30,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CSSIdentifierValue; @@ -51,7 +55,7 @@ CSSPrimitiveValue* Offset() const { return offset_.Get(); } CSSValue* Mask() const { return mask_.Get(); } - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSReflectValue&) const;
diff --git a/third_party/blink/renderer/core/css/css_revert_layer_value.h b/third_party/blink/renderer/core/css/css_revert_layer_value.h index 650427b1..0b76df31 100644 --- a/third_party/blink/renderer/core/css/css_revert_layer_value.h +++ b/third_party/blink/renderer/core/css/css_revert_layer_value.h
@@ -11,6 +11,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CSSValuePool; @@ -24,7 +28,7 @@ explicit CSSRevertLayerValue(base::PassKey<CSSValuePool>) : CSSValue(kRevertLayerClass) {} - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSRevertLayerValue&) const { return true; }
diff --git a/third_party/blink/renderer/core/css/css_revert_value.h b/third_party/blink/renderer/core/css/css_revert_value.h index 065525e..96ef473d 100644 --- a/third_party/blink/renderer/core/css/css_revert_value.h +++ b/third_party/blink/renderer/core/css/css_revert_value.h
@@ -11,6 +11,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CSSValuePool; @@ -24,7 +28,7 @@ explicit CSSRevertValue(base::PassKey<CSSValuePool>) : CSSValue(kRevertClass) {} - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSRevertValue&) const { return true; }
diff --git a/third_party/blink/renderer/core/css/css_scroll_value.h b/third_party/blink/renderer/core/css/css_scroll_value.h index e10c6ca..3e30f42 100644 --- a/third_party/blink/renderer/core/css/css_scroll_value.h +++ b/third_party/blink/renderer/core/css/css_scroll_value.h
@@ -9,6 +9,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { namespace cssvalue { @@ -20,7 +24,7 @@ const CSSValue* Scroller() const { return scroller_.Get(); } const CSSValue* Axis() const { return axis_.Get(); } - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSScrollValue&) const; void TraceAfterDispatch(blink::Visitor*) const;
diff --git a/third_party/blink/renderer/core/css/css_shadow_value.h b/third_party/blink/renderer/core/css/css_shadow_value.h index 9e96305..d03a04c 100644 --- a/third_party/blink/renderer/core/css/css_shadow_value.h +++ b/third_party/blink/renderer/core/css/css_shadow_value.h
@@ -26,6 +26,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CSSIdentifierValue; @@ -41,7 +45,7 @@ CSSIdentifierValue* style, CSSValue* color); - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSShadowValue&) const;
diff --git a/third_party/blink/renderer/core/css/css_unicode_range_value.h b/third_party/blink/renderer/core/css/css_unicode_range_value.h index f49be2e..078b4c1 100644 --- a/third_party/blink/renderer/core/css/css_unicode_range_value.h +++ b/third_party/blink/renderer/core/css/css_unicode_range_value.h
@@ -30,6 +30,10 @@ #include "third_party/blink/renderer/platform/wtf/casting.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_uchar.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { namespace cssvalue { @@ -41,7 +45,7 @@ UChar32 From() const { return from_; } UChar32 To() const { return to_; } - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSUnicodeRangeValue&) const;
diff --git a/third_party/blink/renderer/core/css/css_unset_value.h b/third_party/blink/renderer/core/css/css_unset_value.h index 8db2d62..648ef19 100644 --- a/third_party/blink/renderer/core/css/css_unset_value.h +++ b/third_party/blink/renderer/core/css/css_unset_value.h
@@ -11,6 +11,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CSSValuePool; @@ -23,7 +27,7 @@ explicit CSSUnsetValue(base::PassKey<CSSValuePool>) : CSSValue(kUnsetClass) {} - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSUnsetValue&) const { return true; }
diff --git a/third_party/blink/renderer/core/css/css_value.h b/third_party/blink/renderer/core/css/css_value.h index c5488aa..93e14b94 100644 --- a/third_party/blink/renderer/core/css/css_value.h +++ b/third_party/blink/renderer/core/css/css_value.h
@@ -31,8 +31,6 @@ class String; } // namespace WTF -using WTF::String; - namespace blink { class Document; @@ -44,7 +42,7 @@ // TODO(sashab): Remove this method and move logic to the caller. static CSSValue* Create(const Length& value, float zoom); - String CssText() const; + WTF::String CssText() const; bool IsNumericLiteralValue() const { return class_type_ == kNumericLiteralClass; @@ -231,7 +229,7 @@ bool IsScopedValue() const { return !needs_tree_scope_population_; } #if DCHECK_IS_ON() - String ClassTypeToString() const; + WTF::String ClassTypeToString() const; #endif void TraceAfterDispatch(blink::Visitor* visitor) const {}
diff --git a/third_party/blink/renderer/core/css/css_value_list.h b/third_party/blink/renderer/core/css/css_value_list.h index da972d4..dca94840 100644 --- a/third_party/blink/renderer/core/css/css_value_list.h +++ b/third_party/blink/renderer/core/css/css_value_list.h
@@ -27,6 +27,10 @@ #include "third_party/blink/renderer/platform/wtf/casting.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { class CORE_EXPORT CSSValueList : public CSSValue { @@ -77,7 +81,7 @@ bool HasValue(const CSSValue&) const; CSSValueList* Copy() const; - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSValueList&) const; const CSSValueList& PopulateWithTreeScope(const TreeScope*) const;
diff --git a/third_party/blink/renderer/core/css/css_view_value.h b/third_party/blink/renderer/core/css/css_view_value.h index 7c0c40a..39eb7d91 100644 --- a/third_party/blink/renderer/core/css/css_view_value.h +++ b/third_party/blink/renderer/core/css/css_view_value.h
@@ -9,6 +9,10 @@ #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" +namespace WTF { +class String; +} // namespace WTF + namespace blink { namespace cssvalue { @@ -20,7 +24,7 @@ const CSSValue* Axis() const { return axis_.Get(); } const CSSValue* Inset() const { return inset_.Get(); } - String CustomCSSText() const; + WTF::String CustomCSSText() const; bool Equals(const CSSViewValue&) const; void TraceAfterDispatch(blink::Visitor*) const;
diff --git a/third_party/blink/renderer/core/css/cssom/css_url_image_value.h b/third_party/blink/renderer/core/css/cssom/css_url_image_value.h index 8d7a894..f4f4ee1 100644 --- a/third_party/blink/renderer/core/css/cssom/css_url_image_value.h +++ b/third_party/blink/renderer/core/css/cssom/css_url_image_value.h
@@ -29,7 +29,7 @@ FlushReason, SourceImageStatus*, const gfx::SizeF&, - const AlphaDisposition alpha_disposition = kPremultiplyAlpha) final; + const AlphaDisposition alpha_disposition) final; bool IsAccelerated() const final; // CSSStyleValue
diff --git a/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc b/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc index 56decaae2..2d9aea3 100644 --- a/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc +++ b/third_party/blink/renderer/core/css/invalidation/invalidation_set.cc
@@ -37,6 +37,7 @@ #include "third_party/blink/renderer/core/css/resolver/style_resolver.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h" +#include "third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" @@ -192,6 +193,7 @@ } CHECK_NE(&other, this); + InvalidationSetToSelectorMap::CombineScope combine_scope(this, &other); if (auto* invalidation_set = DynamicTo<SiblingInvalidationSet>(this)) { SiblingInvalidationSet& siblings = *invalidation_set; @@ -328,6 +330,9 @@ return; } CHECK(!class_name.empty()); + InvalidationSetToSelectorMap::RecordInvalidationSetEntry( + this, InvalidationSetToSelectorMap::SelectorFeatureType::kClass, + class_name); classes_.Add(backing_flags_, class_name); } @@ -336,6 +341,8 @@ return; } CHECK(!id.empty()); + InvalidationSetToSelectorMap::RecordInvalidationSetEntry( + this, InvalidationSetToSelectorMap::SelectorFeatureType::kId, id); ids_.Add(backing_flags_, id); } @@ -344,6 +351,9 @@ return; } CHECK(!tag_name.empty()); + InvalidationSetToSelectorMap::RecordInvalidationSetEntry( + this, InvalidationSetToSelectorMap::SelectorFeatureType::kTagName, + tag_name); tag_names_.Add(backing_flags_, tag_name); } @@ -352,6 +362,9 @@ return; } CHECK(!attribute.empty()); + InvalidationSetToSelectorMap::RecordInvalidationSetEntry( + this, InvalidationSetToSelectorMap::SelectorFeatureType::kAttribute, + attribute); attributes_.Add(backing_flags_, attribute); }
diff --git a/third_party/blink/renderer/core/css/rule_set.cc b/third_party/blink/renderer/core/css/rule_set.cc index b64fb89..2fb7c40b 100644 --- a/third_party/blink/renderer/core/css/rule_set.cc +++ b/third_party/blink/renderer/core/css/rule_set.cc
@@ -50,6 +50,7 @@ #include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h" #include "third_party/blink/renderer/core/html/track/text_track_cue.h" #include "third_party/blink/renderer/core/html_names.h" +#include "third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h" #include "third_party/blink/renderer/core/style/computed_style_constants.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" @@ -630,10 +631,14 @@ RuleData rule_data(rule, selector_index, rule_count_, style_scope, add_rule_flags, bloom_hash_backing_); ++rule_count_; - if (features_.CollectFeaturesFromSelector(rule_data.Selector(), - style_scope) == - RuleFeatureSet::kSelectorNeverMatches) { - return; + { + InvalidationSetToSelectorMap::SelectorScope selector_scope(rule, + selector_index); + if (features_.CollectFeaturesFromSelector(rule_data.Selector(), + style_scope) == + RuleFeatureSet::kSelectorNeverMatches) { + return; + } } FindBestRuleSetAndAdd<BucketCoverage::kCompute>(rule_data.MutableSelector(),
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc index 3134e14..9a6cb37a 100644 --- a/third_party/blink/renderer/core/css/style_engine.cc +++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -91,6 +91,7 @@ #include "third_party/blink/renderer/core/html/track/text_track.h" #include "third_party/blink/renderer/core/html_names.h" #include "third_party/blink/renderer/core/inspector/console_message.h" +#include "third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h" #include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h" #include "third_party/blink/renderer/core/layout/geometry/logical_size.h" #include "third_party/blink/renderer/core/layout/geometry/physical_size.h" @@ -741,6 +742,7 @@ DCHECK(GetDocument().IsActive()); DCHECK(IsMainThread()); TRACE_EVENT0("blink", "Document::updateActiveStyle"); + InvalidationSetToSelectorMap::StartOrStopTrackingIfNeeded(); UpdateViewport(); UpdateActiveStyleSheets(); UpdateGlobalRuleSet();
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 87f6a9b..212e0da4 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
@@ -68,7 +68,7 @@ FlushReason, SourceImageStatus*, const gfx::SizeF&, - const AlphaDisposition alpha_disposition = kPremultiplyAlpha) = 0; + const AlphaDisposition alpha_disposition) = 0; // IMPORTANT: Result must be independent of whether destinationContext is // already tainted because this function may be used to determine whether
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h index 9d6252b2..a042102 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -195,7 +195,7 @@ FlushReason, SourceImageStatus*, const gfx::SizeF&, - const AlphaDisposition alpha_disposition = kPremultiplyAlpha) override; + const AlphaDisposition alpha_disposition) override; bool WouldTaintOrigin() const override; gfx::SizeF ElementSize(const gfx::SizeF&, const RespectImageOrientationEnum) const override;
diff --git a/third_party/blink/renderer/core/html/canvas/image_element_base.h b/third_party/blink/renderer/core/html/canvas/image_element_base.h index 064c91c..30991e7 100644 --- a/third_party/blink/renderer/core/html/canvas/image_element_base.h +++ b/third_party/blink/renderer/core/html/canvas/image_element_base.h
@@ -37,7 +37,7 @@ FlushReason, SourceImageStatus*, const gfx::SizeF&, - const AlphaDisposition alpha_disposition = kPremultiplyAlpha) override; + const AlphaDisposition alpha_disposition) override; bool WouldTaintOrigin() const override;
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.h b/third_party/blink/renderer/core/html/media/html_video_element.h index cc1ea09..65b94ad 100644 --- a/third_party/blink/renderer/core/html/media/html_video_element.h +++ b/third_party/blink/renderer/core/html/media/html_video_element.h
@@ -119,7 +119,7 @@ FlushReason, SourceImageStatus*, const gfx::SizeF&, - const AlphaDisposition alpha_disposition = kPremultiplyAlpha) override; + const AlphaDisposition alpha_disposition) override; bool IsVideoElement() const override { return true; } bool WouldTaintOrigin() const override; gfx::SizeF ElementSize(const gfx::SizeF&,
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc index fef5a81..2507d06 100644 --- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc +++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
@@ -658,8 +658,9 @@ std::optional<gfx::Rect> crop_rect, const ImageBitmapOptions* options) { SourceImageStatus status; - scoped_refptr<Image> image_input = canvas->GetSourceImageForCanvas( - FlushReason::kCreateImageBitmap, &status, gfx::SizeF()); + scoped_refptr<Image> image_input = + canvas->GetSourceImageForCanvas(FlushReason::kCreateImageBitmap, &status, + gfx::SizeF(), kPremultiplyAlpha); if (status != kNormalSourceImageStatus) return; DCHECK(IsA<StaticBitmapImage>(image_input.get()));
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.h b/third_party/blink/renderer/core/imagebitmap/image_bitmap.h index c00b5a25..b73ca58 100644 --- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.h +++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
@@ -112,7 +112,7 @@ FlushReason, SourceImageStatus*, const gfx::SizeF&, - const AlphaDisposition alpha_disposition = kPremultiplyAlpha) override; + const AlphaDisposition alpha_disposition) override; bool WouldTaintOrigin() const override { return image_ ? !image_->OriginClean() : false; }
diff --git a/third_party/blink/renderer/core/inspector/build.gni b/third_party/blink/renderer/core/inspector/build.gni index 2e9feeb..13062c25 100644 --- a/third_party/blink/renderer/core/inspector/build.gni +++ b/third_party/blink/renderer/core/inspector/build.gni
@@ -106,6 +106,8 @@ "inspector_task_runner.h", "inspector_trace_events.cc", "inspector_trace_events.h", + "invalidation_set_to_selector_map.cc", + "invalidation_set_to_selector_map.h", "legacy_dom_snapshot_agent.cc", "legacy_dom_snapshot_agent.h", "locale_controller.cc", @@ -142,6 +144,7 @@ "inspector_media_context_impl_unittest.cc", "inspector_session_state_test.cc", "inspector_style_resolver_test.cc", + "invalidation_set_to_selector_map_test.cc", "main_thread_debugger_test.cc", "protocol_parser_test.cc", "protocol_unittest.cc",
diff --git a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc index 7a2a368..9d196b51 100644 --- a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc +++ b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
@@ -29,6 +29,7 @@ #include "third_party/blink/renderer/core/inspector/inspector_animation_agent.h" #include "third_party/blink/renderer/core/inspector/inspector_network_agent.h" #include "third_party/blink/renderer/core/inspector/inspector_page_agent.h" +#include "third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h" #include "third_party/blink/renderer/core/layout/hit_test_location.h" #include "third_party/blink/renderer/core/layout/hit_test_result.h" #include "third_party/blink/renderer/core/layout/layout_image.h" @@ -634,6 +635,22 @@ SetNodeInfo(dict, &node, "nodeId", "nodeName"); dict.Add("reason", reason); } +void FillSelectors( + perfetto::TracedDictionary& dict, + const InvalidationSet& invalidation_set, + InvalidationSetToSelectorMap::SelectorFeatureType feature_type, + const AtomicString& feature_value) { + const InvalidationSetToSelectorMap::IndexedSelectorList* selectors = + InvalidationSetToSelectorMap::Lookup(&invalidation_set, feature_type, + feature_value); + if (selectors != nullptr && selectors->size() > 0) { + dict.Add("selectorCount", selectors->size()); + auto array = dict.AddArray("selectors"); + for (auto selector : *selectors) { + array.Append(selector->GetSelectorText()); + } + } +} } // namespace inspector_style_invalidator_invalidate_event void inspector_style_invalidator_invalidate_event::Data( @@ -652,6 +669,24 @@ const String& selector_part) { auto dict = std::move(context).WriteDictionary(); FillCommonPart(dict, element, reason); + InvalidationSetToSelectorMap::SelectorFeatureType feature_type = + InvalidationSetToSelectorMap::SelectorFeatureType::kUnknown; + if (reason == kInvalidationSetMatchedClass) { + feature_type = InvalidationSetToSelectorMap::SelectorFeatureType::kClass; + } else if (reason == kInvalidationSetMatchedId) { + feature_type = InvalidationSetToSelectorMap::SelectorFeatureType::kId; + } else if (reason == kInvalidationSetMatchedTagName) { + feature_type = InvalidationSetToSelectorMap::SelectorFeatureType::kTagName; + } else if (reason == kInvalidationSetMatchedAttribute) { + feature_type = + InvalidationSetToSelectorMap::SelectorFeatureType::kAttribute; + } + if (feature_type != + InvalidationSetToSelectorMap::SelectorFeatureType::kUnknown) { + FillSelectors(dict, invalidation_set, feature_type, + AtomicString(selector_part)); + } + { auto array = dict.AddArray("invalidationList"); array.Append(invalidation_set);
diff --git a/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.cc b/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.cc new file mode 100644 index 0000000..4216e3f --- /dev/null +++ b/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.cc
@@ -0,0 +1,207 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h" + +#include "base/trace_event/trace_event.h" +#include "third_party/blink/renderer/core/css/invalidation/invalidation_set.h" + +namespace blink { + +InvalidationSetToSelectorMap::IndexedSelector::IndexedSelector( + StyleRule* style_rule, + unsigned selector_index) + : style_rule_(style_rule), selector_index_(selector_index) {} + +void InvalidationSetToSelectorMap::IndexedSelector::Trace( + Visitor* visitor) const { + visitor->Trace(style_rule_); +} + +StyleRule* InvalidationSetToSelectorMap::IndexedSelector::GetStyleRule() const { + return style_rule_; +} + +unsigned InvalidationSetToSelectorMap::IndexedSelector::GetSelectorIndex() + const { + return selector_index_; +} + +String InvalidationSetToSelectorMap::IndexedSelector::GetSelectorText() const { + return style_rule_->SelectorAt(selector_index_).SelectorText(); +} + +// static +CORE_EXPORT void InvalidationSetToSelectorMap::StartOrStopTrackingIfNeeded() { + DEFINE_STATIC_LOCAL( + const unsigned char*, is_tracing_enabled, + (TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT( + "devtools.timeline.invalidationTracking")))); + + Persistent<InvalidationSetToSelectorMap>& instance = GetInstanceReference(); + if (*is_tracing_enabled && instance == nullptr) { + instance = MakeGarbageCollected<InvalidationSetToSelectorMap>(); + } else if (!*is_tracing_enabled && instance != nullptr) { + instance.Clear(); + } +} + +// static +void InvalidationSetToSelectorMap::BeginSelector(StyleRule* style_rule, + unsigned selector_index) { + InvalidationSetToSelectorMap* instance = GetInstanceReference().Get(); + if (instance == nullptr) { + return; + } + + CHECK(instance->current_selector_ == nullptr); + instance->current_selector_ = + MakeGarbageCollected<IndexedSelector>(style_rule, selector_index); +} + +// static +void InvalidationSetToSelectorMap::EndSelector() { + InvalidationSetToSelectorMap* instance = GetInstanceReference().Get(); + if (instance == nullptr) { + return; + } + + CHECK(instance->current_selector_ != nullptr); + instance->current_selector_.Clear(); +} + +InvalidationSetToSelectorMap::SelectorScope::SelectorScope( + StyleRule* style_rule, + unsigned selector_index) { + InvalidationSetToSelectorMap::BeginSelector(style_rule, selector_index); +} +InvalidationSetToSelectorMap::SelectorScope::~SelectorScope() { + InvalidationSetToSelectorMap::EndSelector(); +} + +// static +void InvalidationSetToSelectorMap::RecordInvalidationSetEntry( + const InvalidationSet* invalidation_set, + SelectorFeatureType type, + const AtomicString& value) { + InvalidationSetToSelectorMap* instance = GetInstanceReference().Get(); + if (instance == nullptr) { + return; + } + + // Ignore entries that get added during a combine operation. Those get + // handled when the combine operation begins. + if (instance->combine_recursion_depth_ > 0) { + return; + } + + CHECK(instance->current_selector_ != nullptr); + InvalidationSetEntryMap* entry_map = + instance->invalidation_set_map_ + ->insert(invalidation_set, + MakeGarbageCollected<InvalidationSetEntryMap>()) + .stored_value->value.Get(); + IndexedSelectorList* indexed_selector_list = + entry_map + ->insert(InvalidationSetEntry(type, value), + MakeGarbageCollected<IndexedSelectorList>()) + .stored_value->value.Get(); + indexed_selector_list->insert(instance->current_selector_); +} + +// static +void InvalidationSetToSelectorMap::BeginInvalidationSetCombine( + const InvalidationSet* target, + const InvalidationSet* source) { + InvalidationSetToSelectorMap* instance = GetInstanceReference().Get(); + if (instance == nullptr) { + return; + } + instance->combine_recursion_depth_++; + + // `source` may not be in the map if it contains only information that is not + // tracked such as self-invalidation, or if it was created before tracking + // started. + // TODO(crbug.com/337076014): Re-visit rule sets that already existed when + // tracking started so that invalidation sets for them can be included. + if (instance->invalidation_set_map_->Contains(source)) { + InvalidationSetEntryMap* target_entry_map = + instance->invalidation_set_map_ + ->insert(target, MakeGarbageCollected<InvalidationSetEntryMap>()) + .stored_value->value.Get(); + auto source_entry_it = instance->invalidation_set_map_->find(source); + CHECK(source_entry_it != instance->invalidation_set_map_->end()); + for (auto source_selector_list_it : *(source_entry_it->value)) { + IndexedSelectorList* target_selector_list = + target_entry_map + ->insert(source_selector_list_it.key, + MakeGarbageCollected<IndexedSelectorList>()) + .stored_value->value.Get(); + for (auto source_selector : *(source_selector_list_it.value)) { + target_selector_list->insert(source_selector); + } + } + } +} + +// static +void InvalidationSetToSelectorMap::EndInvalidationSetCombine() { + InvalidationSetToSelectorMap* instance = GetInstanceReference().Get(); + if (instance == nullptr) { + return; + } + + CHECK_GT(instance->combine_recursion_depth_, 0u); + instance->combine_recursion_depth_--; +} + +InvalidationSetToSelectorMap::CombineScope::CombineScope( + const InvalidationSet* target, + const InvalidationSet* source) { + InvalidationSetToSelectorMap::BeginInvalidationSetCombine(target, source); +} + +InvalidationSetToSelectorMap::CombineScope::~CombineScope() { + InvalidationSetToSelectorMap::EndInvalidationSetCombine(); +} + +// static +const InvalidationSetToSelectorMap::IndexedSelectorList* +InvalidationSetToSelectorMap::Lookup(const InvalidationSet* invalidation_set, + SelectorFeatureType type, + const AtomicString& value) { + const InvalidationSetToSelectorMap* instance = GetInstanceReference().Get(); + if (instance == nullptr) { + return nullptr; + } + + auto entry_it = instance->invalidation_set_map_->find(invalidation_set); + if (entry_it != instance->invalidation_set_map_->end()) { + auto selector_list_it = + entry_it->value->find(InvalidationSetEntry(type, value)); + if (selector_list_it != entry_it->value->end()) { + return selector_list_it->value; + } + } + + return nullptr; +} + +InvalidationSetToSelectorMap::InvalidationSetToSelectorMap() { + invalidation_set_map_ = MakeGarbageCollected<InvalidationSetMap>(); +} + +void InvalidationSetToSelectorMap::Trace(Visitor* visitor) const { + visitor->Trace(invalidation_set_map_); + visitor->Trace(current_selector_); +} + +// static +Persistent<InvalidationSetToSelectorMap>& +InvalidationSetToSelectorMap::GetInstanceReference() { + DEFINE_STATIC_LOCAL(Persistent<InvalidationSetToSelectorMap>, instance, ()); + return instance; +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h b/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h new file mode 100644 index 0000000..2ff0ad9 --- /dev/null +++ b/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h
@@ -0,0 +1,119 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INVALIDATION_SET_TO_SELECTOR_MAP_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INVALIDATION_SET_TO_SELECTOR_MAP_H_ + +#include "third_party/blink/renderer/core/css/style_rule.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/member.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" +#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" + +namespace blink { + +class InvalidationSet; +class StyleRule; + +// Implements a back-mapping from InvalidationSet entries to the selectors that +// placed them there, for use in diagnostic traces. +// Only active while the appropriate tracing configuration is enabled. +class InvalidationSetToSelectorMap final + : public GarbageCollected<InvalidationSetToSelectorMap> { + public: + // A small helper to bundle together a StyleRule plus an index into its + // selector list. + class IndexedSelector final : public GarbageCollected<IndexedSelector> { + public: + IndexedSelector(StyleRule* style_rule, unsigned selector_index); + void Trace(Visitor*) const; + StyleRule* GetStyleRule() const; + unsigned GetSelectorIndex() const; + String GetSelectorText() const; + + private: + Member<StyleRule> style_rule_; + unsigned selector_index_; + }; + using IndexedSelectorList = HeapHashSet<Member<IndexedSelector>>; + + enum class SelectorFeatureType { + kUnknown, + kClass, + kId, + kTagName, + kAttribute + }; + + // Instantiates a new mapping if a diagnostic tracing session with the + // appropriate configuration has started, or deletes an existing mapping if + // tracing is no longer enabled. + CORE_EXPORT static void StartOrStopTrackingIfNeeded(); + + // Call at the start and end of indexing features for a given selector. + static void BeginSelector(StyleRule* style_rule, unsigned selector_index); + static void EndSelector(); + + // Helper object for a Begin/EndSelector pair. + class SelectorScope { + public: + SelectorScope(StyleRule* style_rule, unsigned selector_index); + ~SelectorScope(); + }; + + // Call for each feature recorded to an invalidation set. + static void RecordInvalidationSetEntry( + const InvalidationSet* invalidation_set, + SelectorFeatureType type, + const AtomicString& value); + + // Call at the start and end of an invalidation set combine operation. + static void BeginInvalidationSetCombine(const InvalidationSet* target, + const InvalidationSet* source); + static void EndInvalidationSetCombine(); + + // Helper object for a Begin/EndInvalidationSetCombine pair. + class CombineScope { + public: + CombineScope(const InvalidationSet* target, const InvalidationSet* source); + ~CombineScope(); + }; + + // Given an invalidation set and a selector feature representing an entry in + // that invalidation set, returns a list of selectors that contributed to that + // entry existing in that invalidation set. + static const IndexedSelectorList* Lookup( + const InvalidationSet* invalidation_set, + SelectorFeatureType type, + const AtomicString& value); + + InvalidationSetToSelectorMap(); + void Trace(Visitor*) const; + + protected: + friend class InvalidationSetToSelectorMapTest; + CORE_EXPORT static Persistent<InvalidationSetToSelectorMap>& + GetInstanceReference(); + + private: + // The back-map is stored in two levels: first from an invalidation set + // pointer to a map of entries, then from each entry to a list of selectors. + // We don't retain a strong pointer to the InvalidationSet because we don't + // need it for any purpose other than as a lookup key. + using InvalidationSetEntry = std::pair<SelectorFeatureType, AtomicString>; + using InvalidationSetEntryMap = + HeapHashMap<InvalidationSetEntry, Member<IndexedSelectorList>>; + using InvalidationSetMap = + HeapHashMap<const InvalidationSet*, Member<InvalidationSetEntryMap>>; + + Member<InvalidationSetMap> invalidation_set_map_; + Member<IndexedSelector> current_selector_; + unsigned combine_recursion_depth_ = 0; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INVALIDATION_SET_TO_SELECTOR_MAP_H_
diff --git a/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map_test.cc b/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map_test.cc new file mode 100644 index 0000000..2eb5e74 --- /dev/null +++ b/third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map_test.cc
@@ -0,0 +1,201 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/inspector/invalidation_set_to_selector_map.h" + +#include "base/test/trace_event_analyzer.h" +#include "third_party/blink/renderer/core/dom/element.h" +#include "third_party/blink/renderer/core/html_names.h" +#include "third_party/blink/renderer/core/testing/page_test_base.h" + +namespace blink { + +class InvalidationSetToSelectorMapTest : public PageTestBase { + protected: + void SetUp() override { + PageTestBase::SetUp(); + CHECK(GetInstance() == nullptr); + } + void TearDown() override { + PageTestBase::TearDown(); + + // Ensure we do not carry over an instance from one test to another. + InvalidationSetToSelectorMap::StartOrStopTrackingIfNeeded(); + CHECK(GetInstance() == nullptr); + } + + void StartTracing() { + trace_analyzer::Start( + TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking")); + } + void StartTracingWithoutInvalidationTracking() { + trace_analyzer::Start(TRACE_DISABLED_BY_DEFAULT("devtools.timeline")); + } + std::unique_ptr<trace_analyzer::TraceAnalyzer> StopTracing() { + return trace_analyzer::Stop(); + } + InvalidationSetToSelectorMap* GetInstance() { + return InvalidationSetToSelectorMap::GetInstanceReference().Get(); + } +}; + +TEST_F(InvalidationSetToSelectorMapTest, TrackerLifetime) { + ASSERT_EQ(GetInstance(), nullptr); + + StartTracing(); + SetBodyInnerHTML(R"HTML(<div id=d>D</div>)HTML"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_NE(GetInstance(), nullptr); + GetElementById("d")->setAttribute(html_names::kStyleAttr, + AtomicString("color: red")); + UpdateAllLifecyclePhasesForTest(); + EXPECT_NE(GetInstance(), nullptr); + + StopTracing(); + GetElementById("d")->setAttribute(html_names::kStyleAttr, + AtomicString("color: green")); + UpdateAllLifecyclePhasesForTest(); + EXPECT_EQ(GetInstance(), nullptr); + + StartTracingWithoutInvalidationTracking(); + GetElementById("d")->setAttribute(html_names::kStyleAttr, + AtomicString("color: blue")); + UpdateAllLifecyclePhasesForTest(); + EXPECT_EQ(GetInstance(), nullptr); + StopTracing(); +} + +TEST_F(InvalidationSetToSelectorMapTest, ClassMatch) { + StartTracing(); + SetBodyInnerHTML(R"HTML( + <style> + .a .x { color: red; } + .b .x { color: green; } + .c .x { color: blue; } + </style> + <div id=parent class=a>Parent + <div class=x>Child</div> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + + GetElementById("parent")->setAttribute(html_names::kClassAttr, + AtomicString("b")); + UpdateAllLifecyclePhasesForTest(); + + auto analyzer = StopTracing(); + trace_analyzer::TraceEventVector events; + analyzer->FindEvents(trace_analyzer::Query::EventNameIs( + "StyleInvalidatorInvalidationTracking"), + &events); + size_t found_event_count = 0; + for (auto event : events) { + ASSERT_TRUE(event->HasDictArg("data")); + base::Value::Dict data_dict = event->GetKnownArgAsDict("data"); + std::string* reason = data_dict.FindString("reason"); + if (reason != nullptr && *reason == "Invalidation set matched class") { + base::Value::List* selector_list = data_dict.FindList("selectors"); + if (selector_list != nullptr) { + EXPECT_EQ(selector_list->size(), 1u); + EXPECT_EQ((*selector_list)[0], ".b .x"); + found_event_count++; + } + } + } + EXPECT_EQ(found_event_count, 1u); +} + +TEST_F(InvalidationSetToSelectorMapTest, ClassMatchWithMultipleInvalidations) { + StartTracing(); + SetBodyInnerHTML(R"HTML( + <style> + .a .x { color: red; } + .b .x { color: green; } + .c .x { color: blue; } + </style> + <div id=parent class=a>Parent + <div class=x>Child</div> + <div class=x>Child</div> + <div class=x>Child</div> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + + GetElementById("parent")->setAttribute(html_names::kClassAttr, + AtomicString("b")); + UpdateAllLifecyclePhasesForTest(); + + auto analyzer = StopTracing(); + trace_analyzer::TraceEventVector events; + analyzer->FindEvents(trace_analyzer::Query::EventNameIs( + "StyleInvalidatorInvalidationTracking"), + &events); + size_t found_event_count = 0; + for (auto event : events) { + ASSERT_TRUE(event->HasDictArg("data")); + base::Value::Dict data_dict = event->GetKnownArgAsDict("data"); + std::string* reason = data_dict.FindString("reason"); + if (reason != nullptr && *reason == "Invalidation set matched class") { + base::Value::List* selector_list = data_dict.FindList("selectors"); + if (selector_list != nullptr) { + EXPECT_EQ(selector_list->size(), 1u); + EXPECT_EQ((*selector_list)[0], ".b .x"); + found_event_count++; + } + } + } + EXPECT_EQ(found_event_count, 3u); +} + +TEST_F(InvalidationSetToSelectorMapTest, ClassMatchWithCombine) { + StartTracing(); + SetBodyInnerHTML(R"HTML( + <style> + .a .x { color: red; } + .b .x { color: green; } + .c .x { color: blue; } + </style> + <style> + .b .w .x { color: black; } + </style> + <div id=parent class=a>Parent + <div class=x>Child</div> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + + GetElementById("parent")->setAttribute(html_names::kClassAttr, + AtomicString("b")); + UpdateAllLifecyclePhasesForTest(); + + auto analyzer = StopTracing(); + trace_analyzer::TraceEventVector events; + analyzer->FindEvents(trace_analyzer::Query::EventNameIs( + "StyleInvalidatorInvalidationTracking"), + &events); + size_t found_event_count = 0; + for (auto event : events) { + ASSERT_TRUE(event->HasDictArg("data")); + base::Value::Dict data_dict = event->GetKnownArgAsDict("data"); + std::string* reason = data_dict.FindString("reason"); + if (reason != nullptr && *reason == "Invalidation set matched class") { + base::Value::List* selector_list = data_dict.FindList("selectors"); + if (selector_list != nullptr) { + EXPECT_EQ(selector_list->size(), 2u); + // The map stores selectors in a HeapHashSet; they can be output to the + // trace event list in either order. + if ((*selector_list)[0] == ".b .x") { + EXPECT_EQ((*selector_list)[1], ".b .w .x"); + } else { + EXPECT_EQ((*selector_list)[0], ".b .w .x"); + EXPECT_EQ((*selector_list)[1], ".b .x"); + } + found_event_count++; + } + } + } + EXPECT_EQ(found_event_count, 1u); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/anchor_evaluator_impl.cc b/third_party/blink/renderer/core/layout/anchor_evaluator_impl.cc index 54c9198..f1f11f0 100644 --- a/third_party/blink/renderer/core/layout/anchor_evaluator_impl.cc +++ b/third_party/blink/renderer/core/layout/anchor_evaluator_impl.cc
@@ -56,6 +56,33 @@ } } +// https://drafts.csswg.org/css-anchor-position-1/#valdef-anchor-inside +// https://drafts.csswg.org/css-anchor-position-1/#valdef-anchor-outside +CSSAnchorValue PhysicalAnchorValueFromInsideOutside(CSSAnchorValue anchor_value, + bool is_y_axis, + bool is_right_or_bottom) { + switch (anchor_value) { + case CSSAnchorValue::kInside: { + if (is_y_axis) { + return is_right_or_bottom ? CSSAnchorValue::kBottom + : CSSAnchorValue::kTop; + } + return is_right_or_bottom ? CSSAnchorValue::kRight + : CSSAnchorValue::kLeft; + } + case CSSAnchorValue::kOutside: { + if (is_y_axis) { + return is_right_or_bottom ? CSSAnchorValue::kTop + : CSSAnchorValue::kBottom; + } + return is_right_or_bottom ? CSSAnchorValue::kLeft + : CSSAnchorValue::kRight; + } + default: + return anchor_value; + } +} + } // namespace PhysicalAnchorReference::PhysicalAnchorReference( @@ -228,6 +255,8 @@ anchor_value = PhysicalAnchorValueFromLogicalOrAuto( anchor_value, container_converter.GetWritingDirection(), self_writing_direction, is_y_axis); + anchor_value = PhysicalAnchorValueFromInsideOutside(anchor_value, is_y_axis, + is_right_or_bottom); LayoutUnit value; switch (anchor_value) { case CSSAnchorValue::kCenter: { @@ -286,6 +315,10 @@ value += LayoutUnit::FromFloatRound(size * percentage / 100); break; } + case CSSAnchorValue::kInside: + case CSSAnchorValue::kOutside: + // Should have been handled by `PhysicalAnchorValueFromInsideOutside`. + [[fallthrough]]; case CSSAnchorValue::kStart: case CSSAnchorValue::kEnd: case CSSAnchorValue::kSelfStart:
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index 3b1e502..76481222 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -913,12 +913,6 @@ diff.SetNeedsRecomputeVisualOverflow(); } - bool has_clip = HasOutOfFlowPosition() && !HasAutoClip(); - bool other_has_clip = other.HasOutOfFlowPosition() && !other.HasAutoClip(); - if (has_clip != other_has_clip || (has_clip && Clip() != other.Clip())) { - diff.SetCSSClipChanged(); - } - if (DiffCompositingReasonsChanged(other, field_diff)) { diff.SetCompositingReasonsChanged(); } @@ -935,6 +929,13 @@ if (field_diff & kBorderRadius) { diff.SetBorderRadiusChanged(); } + if (field_diff & kClip) { + bool has_clip = HasOutOfFlowPosition() && !HasAutoClip(); + bool other_has_clip = other.HasOutOfFlowPosition() && !other.HasAutoClip(); + if (has_clip != other_has_clip || (has_clip && Clip() != other.Clip())) { + diff.SetCSSClipChanged(); + } + } if (field_diff & kClipPath) { diff.SetClipPathChanged(); } @@ -950,12 +951,26 @@ if (field_diff & kOpacity) { diff.SetOpacityChanged(); } + if (field_diff & kScrollbarStyle) { + if (HasPseudoElementStyle(kPseudoIdScrollbar) != + other.HasPseudoElementStyle(kPseudoIdScrollbar) || + UsesStandardScrollbarStyle() != other.UsesStandardScrollbarStyle()) { + diff.SetNeedsFullLayout(); + diff.SetNeedsNormalPaintInvalidation(); + } + } if (field_diff & kTextDecoration) { diff.SetTextDecorationOrColorChanged(); } if (field_diff & kTransformProperty) { diff.SetTransformPropertyChanged(); } + if (field_diff & kVisibility) { + if ((Visibility() == EVisibility::kCollapse) != + (other.Visibility() == EVisibility::kCollapse)) { + diff.SetNeedsFullLayout(); + } + } if (field_diff & kZIndex) { diff.SetZIndexChanged(); } @@ -980,23 +995,7 @@ bool ComputedStyle::DiffNeedsFullLayoutAndPaintInvalidation( const ComputedStyle& other, uint32_t field_diff) const { - // FIXME: Not all cases in this method need both full layout and paint - // invalidation. - // Should move cases into DiffNeedsFullLayout() if - // - don't need paint invalidation at all; - // - or the layoutObject knows how to exactly invalidate paints caused by the - // layout change instead of forced full paint invalidation. - - if (ComputedStyleBase::DiffNeedsFullLayoutAndPaintInvalidation(*this, - other)) { - return true; - } - if (IsDisplayTableType(Display())) { - if (field_diff & kTable) { - return true; - } - // In the collapsing border model, 'hidden' suppresses other borders, while // 'none' does not, so these style differences can be width differences. if ((BorderCollapse() == EBorderCollapse::kCollapse) && @@ -1018,15 +1017,6 @@ other.BorderRightStyle() == EBorderStyle::kHidden))) { return true; } - } else if (IsDisplayListItem()) { - if (field_diff & kListItem) { - return true; - } - } - - if ((Visibility() == EVisibility::kCollapse) != - (other.Visibility() == EVisibility::kCollapse)) { - return true; } // Movement of non-static-positioned object is special cased in @@ -1144,10 +1134,6 @@ return true; } - if (field_diff & kBorderRadius) { - return true; - } - if ((field_diff & kOutline) && !OutlineVisuallyEqual(other)) { return true; }
diff --git a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 index 862a35ee..36b16ad 100644 --- a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 +++ b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
@@ -31,19 +31,6 @@ }, data: [ { - name: "DiffNeedsFullLayoutAndPaintInvalidation", - methods_to_diff: [ - { - method: "HasPseudoElementStyle(kPseudoIdScrollbar)", - field_dependencies: ["StyleType"] - }, - { - method: "UsesStandardScrollbarStyle()", - field_dependencies: ["StyleType"] - }, - ], - }, - { name: "DiffNeedsPaintInvalidation", methods_to_diff: [ {
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 index 72988d6..d3b579c 100644 --- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 +++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -245,6 +245,7 @@ reset_on_new_style: true, custom_compare: true, computed_style_custom_functions: ["getter"], + invalidate: ["scrollbar-style"], }, // Whether any non-universal highlight selectors were found when collecting // rules for the originating element. Stored in the *originating* style, and @@ -358,6 +359,7 @@ default_value: "true", field_group: "visual", computed_style_custom_functions: ["setter"], + invalidate: ["clip"], }, { name: "HasAutoZIndex",
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc index a95b9bf6..c823dab8 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -92,6 +92,8 @@ namespace blink { +using ::cc::UsePaintCache; + BASE_FEATURE(kDisableCanvasOverdrawOptimization, "DisableCanvasOverdrawOptimization", base::FEATURE_DISABLED_BY_DEFAULT); @@ -1980,7 +1982,8 @@ } } else { image = image_source->GetSourceImageForCanvas( - FlushReason::kDrawImage, &source_image_status, default_object_size); + FlushReason::kDrawImage, &source_image_status, default_object_size, + kPremultiplyAlpha); if (source_image_status == kUndecodableSourceImageStatus) { exception_state.ThrowDOMException( DOMExceptionCode::kInvalidStateError, @@ -2181,7 +2184,8 @@ gfx::SizeF default_object_size(Width(), Height()); scoped_refptr<Image> image_for_rendering = image_source->GetSourceImageForCanvas(FlushReason::kCreatePattern, - &status, default_object_size); + &status, default_object_size, + kPremultiplyAlpha); switch (status) { case kNormalSourceImageStatus: @@ -2310,7 +2314,7 @@ SourceImageStatus source_image_status = kInvalidSourceImageStatus; scoped_refptr<Image> image = image_source->GetSourceImageForCanvas( FlushReason::kDrawMesh, &source_image_status, - gfx::SizeF(Width(), Height())); + gfx::SizeF(Width(), Height()), kPremultiplyAlpha); switch (source_image_status) { case kUndecodableSourceImageStatus: exception_state.ThrowDOMException(
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h index 3577f7e..a797e29b 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
@@ -56,7 +56,6 @@ enum class V8CanvasStyleType; class GPUTexture; class V8UnionCanvasFilterOrString; -using cc::UsePaintCache; class MODULES_EXPORT BaseRenderingContext2D : public CanvasPath { public: @@ -715,7 +714,7 @@ void DrawPathInternal(const CanvasPath&, CanvasRenderingContext2DState::PaintType, SkPathFillType, - UsePaintCache); + cc::UsePaintCache); void DrawImageInternal(cc::PaintCanvas*, CanvasImageSource*, Image*, @@ -725,7 +724,7 @@ const cc::PaintFlags*); void ClipInternal(const Path&, const String& winding_rule_string, - UsePaintCache); + cc::UsePaintCache); bool IsPointInPathInternal(const Path&, const double x, @@ -786,7 +785,7 @@ CanvasResourceProvider& resource_provider); bool origin_tainted_by_content_ = false; - UsePaintCache path2d_use_paint_cache_; + cc::UsePaintCache path2d_use_paint_cache_; int num_readbacks_performed_ = 0; unsigned read_count_ = 0; base::HashingLRUCache<String, CachedColor> color_cache_{8};
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc index a8edc36..b6693401 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc
@@ -68,6 +68,7 @@ using ::cc::SaveOp; using ::cc::SetMatrixOp; using ::cc::TranslateOp; +using ::cc::UsePaintCache; using ::testing::IsEmpty; using ::testing::Not; using ::testing::Pointee;
diff --git a/third_party/blink/renderer/modules/shapedetection/shape_detector.cc b/third_party/blink/renderer/modules/shapedetection/shape_detector.cc index 903397a..7b58d22 100644 --- a/third_party/blink/renderer/modules/shapedetection/shape_detector.cc +++ b/third_party/blink/renderer/modules/shapedetection/shape_detector.cc
@@ -92,7 +92,8 @@ SourceImageStatus source_image_status = kInvalidSourceImageStatus; scoped_refptr<Image> image = canvas_image_source->GetSourceImageForCanvas( - FlushReason::kShapeDetector, &source_image_status, size); + FlushReason::kShapeDetector, &source_image_status, size, + kPremultiplyAlpha); if (!image || source_image_status != kNormalSourceImageStatus) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, "Invalid element or state.");
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc index a082b48..4dfa612 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -767,7 +767,7 @@ SourceImageStatus status = kInvalidSourceImageStatus; auto image = image_source->GetSourceImageForCanvas( - FlushReason::kCreateVideoFrame, &status, source_size); + FlushReason::kCreateVideoFrame, &status, source_size, kPremultiplyAlpha); if (!image || status != kNormalSourceImageStatus) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, "Invalid source state");
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.h b/third_party/blink/renderer/modules/webcodecs/video_frame.h index 7992f63..e1c288d 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame.h +++ b/third_party/blink/renderer/modules/webcodecs/video_frame.h
@@ -128,7 +128,7 @@ FlushReason, SourceImageStatus*, const gfx::SizeF&, - const AlphaDisposition alpha_disposition = kPremultiplyAlpha) override; + const AlphaDisposition alpha_disposition) override; gfx::SizeF ElementSize(const gfx::SizeF&, const RespectImageOrientationEnum) const override;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index b8940bc..7a4b7b2c 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -6082,7 +6082,7 @@ SourceImageStatus source_image_status = kInvalidSourceImageStatus; scoped_refptr<Image> image = context_host->GetSourceImageForCanvas( FlushReason::kWebGLTexImage, &source_image_status, - gfx::SizeF(*params.width, *params.height)); + gfx::SizeF(*params.width, *params.height), kPremultiplyAlpha); if (source_image_status != kNormalSourceImageStatus) return;
diff --git a/third_party/blink/renderer/platform/image-decoders/BUILD.gn b/third_party/blink/renderer/platform/image-decoders/BUILD.gn index 3f45cc71..63c87fe7 100644 --- a/third_party/blink/renderer/platform/image-decoders/BUILD.gn +++ b/third_party/blink/renderer/platform/image-decoders/BUILD.gn
@@ -76,9 +76,12 @@ sources += [ "avif/avif_image_decoder.cc", "avif/avif_image_decoder.h", + "avif/crabbyavif_image_decoder.cc", + "avif/crabbyavif_image_decoder.h", ] deps += [ + "//third_party/crabbyavif", "//third_party/libavif", "//third_party/libavifinfo", ] @@ -120,7 +123,10 @@ } if (enable_av1_decoder) { - sources += [ "avif/avif_image_decoder_test.cc" ] + sources += [ + "avif/avif_image_decoder_test.cc", + "avif/crabbyavif_image_decoder_test.cc", + ] } } @@ -135,6 +141,7 @@ "//third_party/blink/renderer/platform/wtf", ] seed_corpuses = [ "//third_party/blink/web_tests/images/bmp-suite/good" ] + # TODO: crbug.com/324586211 - raise the memory limit to avoid OOMs in the # fuzzer harness. This can be removed once the global memory limit is raised. libfuzzer_options = [ "rss_limit_mb=4096" ]
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc index 7467b46..cc29007 100644 --- a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc +++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
@@ -31,6 +31,7 @@ #include "media/media_buildflags.h" #include "skia/ext/cicp.h" #include "third_party/blink/public/common/buildflags.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.h" #include "third_party/blink/renderer/platform/image-decoders/exif_reader.h" @@ -46,6 +47,7 @@ #if BUILDFLAG(ENABLE_AV1_DECODER) #include "third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h" +#include "third_party/blink/renderer/platform/image-decoders/avif/crabbyavif_image_decoder.h" #endif namespace blink { @@ -188,7 +190,9 @@ return "image/bmp"; } #if BUILDFLAG(ENABLE_AV1_DECODER) - if (AVIFImageDecoder::MatchesAVIFSignature(fast_reader)) { + if (base::FeatureList::IsEnabled(blink::features::kCrabbyAvif) + ? CrabbyAVIFImageDecoder::MatchesAVIFSignature(fast_reader) + : AVIFImageDecoder::MatchesAVIFSignature(fast_reader)) { return "image/avif"; } #endif @@ -294,9 +298,15 @@ max_decoded_bytes); #if BUILDFLAG(ENABLE_AV1_DECODER) } else if (mime_type == "image/avif") { - decoder = std::make_unique<AVIFImageDecoder>( - alpha_option, high_bit_depth_decoding_option, color_behavior, - max_decoded_bytes, animation_option); + if (base::FeatureList::IsEnabled(blink::features::kCrabbyAvif)) { + decoder = std::make_unique<CrabbyAVIFImageDecoder>( + alpha_option, high_bit_depth_decoding_option, color_behavior, + max_decoded_bytes, animation_option); + } else { + decoder = std::make_unique<AVIFImageDecoder>( + alpha_option, high_bit_depth_decoding_option, color_behavior, + max_decoded_bytes, animation_option); + } #endif }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 8b7a2ef..7abeb8f 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -3524,7 +3524,7 @@ // Maintain author-defined ::selection highlight colors, even if they // match the text color. name: "SelectionRespectsColors", - status: "experimental", + status: "stable", }, { name: "SendBeaconThrowForBlobWithNonSimpleType", @@ -4052,6 +4052,13 @@ status: "experimental", }, { + // Unblock queued blocking touchmove after the main thread handles the + // touchstart and the first touchmove and they didn't call + // preventDefault(), instead of waiting for the browser to send + // touchscrollstarted. + name: "UnblockTouchMoveEarlier", + }, + { name: "UnclosedFormControlIsInvalid", status: "experimental", },
diff --git a/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.cc b/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.cc index 8b86eb00..35f0c3cd 100644 --- a/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.cc +++ b/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.cc
@@ -18,6 +18,7 @@ #include "third_party/blink/public/common/input/web_gesture_event.h" #include "third_party/blink/public/common/input/web_input_event_attribution.h" #include "third_party/blink/public/common/input/web_mouse_wheel_event.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" namespace blink { @@ -182,7 +183,11 @@ const ui::LatencyInfo& latency_info, mojom::blink::DidOverscrollParamsPtr overscroll, std::optional<cc::TouchAction> touch_action) { - // callback_ can be null in tests. + // callback_ is null if we have already run it, in cases + // 1. the event had been a blocking touchmove before it was unblocked; + // 2. the event is an non-blocking event, and its callback was called when + // the event was queued, then a blocking event was coalesced into the + // the event. if (callback_) { std::move(callback_).Run(ack_result, latency_info, std::move(overscroll), touch_action); @@ -191,10 +196,12 @@ if (!blocking_coalesced_callbacks_.empty()) { ui::LatencyInfo coalesced_latency_info = latency_info; coalesced_latency_info.set_coalesced(); - for (auto&& callback : blocking_coalesced_callbacks_) { - coalesced_latency_info.set_trace_id(callback.second); - std::move(callback.first) - .Run(ack_result, coalesced_latency_info, nullptr, std::nullopt); + for (auto& callback : blocking_coalesced_callbacks_) { + if (callback.first) { + coalesced_latency_info.set_trace_id(callback.second); + std::move(callback.first) + .Run(ack_result, coalesced_latency_info, nullptr, std::nullopt); + } } } @@ -207,6 +214,29 @@ ? WebInputEventResult::kHandledApplication : WebInputEventResult::kNotHandled); } + + queue->UnblockQueuedBlockingTouchMovesIfNeeded(event_->Event(), ack_result); + } + + struct CallbackInfo { + HandledEventCallback callback; + ui::LatencyInfo latency_info; + }; + void TakeCallbacksInto(Vector<CallbackInfo>& callbacks) { + if (callback_) { + callbacks.emplace_back(std::move(callback_), event_->latency_info()); + } + if (!blocking_coalesced_callbacks_.empty()) { + ui::LatencyInfo coalesced_latency_info = event_->latency_info(); + coalesced_latency_info.set_coalesced(); + for (auto& callback : blocking_coalesced_callbacks_) { + if (callback.first) { + coalesced_latency_info.set_trace_id(callback.second); + callbacks.emplace_back(std::move(callback.first), + coalesced_latency_info); + } + } + } } bool originally_cancelable() const { return originally_cancelable_; } @@ -353,9 +383,9 @@ originally_cancelable = touch_event->dispatch_type == WebInputEvent::DispatchType::kBlocking; - // Adjust the |dispatchType| on the event since the compositor - // determined all event listeners are passive. if (!is_blocking) { + // Adjust the `dispatch_type` on the event since the compositor + // determined all event listeners are passive. touch_event->dispatch_type = WebInputEvent::DispatchType::kListenersNonBlockingPassive; } @@ -791,4 +821,75 @@ needs_low_latency_until_pointer_up_ = true; } +void MainThreadEventQueue::UnblockQueuedBlockingTouchMovesIfNeeded( + const WebInputEvent& dispatched_event, + mojom::blink::InputEventResultState ack_result) { + if (!RuntimeEnabledFeatures::UnblockTouchMoveEarlierEnabled()) { + return; + } + if (!WebInputEvent::IsTouchEventType(dispatched_event.GetType())) { + return; + } + + bool should_unblock_queued_touch_moves = false; + { + auto& touch_event = static_cast<const WebTouchEvent&>(dispatched_event); + if (touch_event.touch_start_or_first_touch_move) { + bool is_not_consumed_blocking = + touch_event.dispatch_type == WebInputEvent::DispatchType::kBlocking && + ack_result == mojom::blink::InputEventResultState::kNotConsumed; + if (touch_event.GetType() == WebInputEvent::Type::kTouchStart) { + blocking_touch_start_not_consumed_ = is_not_consumed_blocking; + } else { + // `event` is the first touch move. + CHECK_EQ(touch_event.GetType(), WebInputEvent::Type::kTouchMove); + should_unblock_queued_touch_moves = + blocking_touch_start_not_consumed_ && is_not_consumed_blocking; + } + } + } + if (!should_unblock_queued_touch_moves) { + return; + } + + // Neither the touchstart nor the first touchmove was consumed. The browser + // process will make the remaining of the touch sequence non-blocking, but + // we need to unblock the already queued blocking touchmove events and run + // the callbacks (collected in a vector to avoid locking during callbacks). + Vector<QueuedWebInputEvent::CallbackInfo> callbacks; + { + base::AutoLock lock(shared_state_lock_); + for (size_t i = 0; i < shared_state_.events_.size(); ++i) { + MainThreadEventQueueTask* task = shared_state_.events_.at(i).get(); + if (!task->IsWebInputEvent()) { + continue; + } + auto* queued_event = static_cast<QueuedWebInputEvent*>(task); + WebInputEvent* event = + queued_event->mutable_coalesced_event()->EventPointer(); + if (event->GetType() == WebInputEvent::Type::kTouchStart || + event->GetType() == WebInputEvent::Type::kTouchEnd) { + break; + } + if (event->GetType() != WebInputEvent::Type::kTouchMove) { + continue; + } + + auto* touch_event = static_cast<WebTouchEvent*>(event); + if (!touch_event->touch_start_or_first_touch_move && + touch_event->dispatch_type == + WebInputEvent::DispatchType::kBlocking) { + touch_event->dispatch_type = + WebInputEvent::DispatchType::kEventNonBlocking; + queued_event->TakeCallbacksInto(callbacks); + } + } + } + for (auto& callback_info : callbacks) { + std::move(callback_info.callback) + .Run(mojom::blink::InputEventResultState::kNotConsumed, + callback_info.latency_info, nullptr, std::nullopt); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.h b/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.h index 6dfcd1b6..6e2a171 100644 --- a/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.h +++ b/third_party/blink/renderer/platform/widget/input/main_thread_event_queue.h
@@ -170,6 +170,10 @@ void ClearRafFallbackTimerForTesting(); + void UnblockQueuedBlockingTouchMovesIfNeeded( + const WebInputEvent& dispatched_event, + mojom::blink::InputEventResultState ack_result); + friend class QueuedWebInputEvent; friend class MainThreadEventQueueTest; friend class MainThreadEventQueueInitializationTest; @@ -177,6 +181,7 @@ const bool allow_raf_aligned_input_; bool last_touch_start_forced_nonblocking_due_to_fling_ = false; bool has_pointerrawupdate_handlers_ = false; + bool blocking_touch_start_not_consumed_ = false; // These variables are read on the compositor thread but are // written on the main thread, so we use atomics to keep them
diff --git a/third_party/blink/renderer/platform/widget/input/main_thread_event_queue_unittest.cc b/third_party/blink/renderer/platform/widget/input/main_thread_event_queue_unittest.cc index 9d52ea2..02fb0a7 100644 --- a/third_party/blink/renderer/platform/widget/input/main_thread_event_queue_unittest.cc +++ b/third_party/blink/renderer/platform/widget/input/main_thread_event_queue_unittest.cc
@@ -2,14 +2,16 @@ // 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/platform/widget/input/main_thread_event_queue.h" + #include <stddef.h> #include <new> #include <tuple> #include <utility> -#include <vector> #include "base/auto_reset.h" +#include "base/containers/adapters.h" #include "base/functional/bind.h" #include "base/strings/string_util.h" #include "base/test/test_simple_task_runner.h" @@ -22,7 +24,8 @@ #include "third_party/blink/public/common/input/web_mouse_wheel_event.h" #include "third_party/blink/public/platform/scheduler/test/web_mock_thread_scheduler.h" #include "third_party/blink/renderer/platform/scheduler/test/fake_widget_scheduler.h" -#include "third_party/blink/renderer/platform/widget/input/main_thread_event_queue.h" +#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { namespace { @@ -82,6 +85,11 @@ virtual blink::WebCoalescedInputEvent* taskAsEvent() = 0; virtual unsigned taskAsClosure() const = 0; + virtual void Print(std::ostream* os) const = 0; + + friend void PrintTo(const HandledTask& task, std::ostream* os) { + task.Print(os); + } }; class HandledEvent : public HandledTask { @@ -96,6 +104,15 @@ return 0; } + void Print(std::ostream* os) const override { + *os << "event_type: " << event_.Event().GetType(); + if (WebInputEvent::IsTouchEventType(event_.Event().GetType())) { + auto& touch_event = static_cast<const WebTouchEvent&>(event_.Event()); + *os << " touch_id: " << touch_event.unique_touch_event_id + << " dispatch_type: " << touch_event.dispatch_type; + } + } + private: blink::WebCoalescedInputEvent event_; }; @@ -110,6 +127,7 @@ return nullptr; } unsigned taskAsClosure() const override { return closure_id_; } + void Print(std::ostream* os) const override { NOTREACHED(); } private: unsigned closure_id_; @@ -121,26 +139,55 @@ kCalledAfterHandleEvent, }; +void PrintTo(CallbackReceivedState state, std::ostream* os) { + const char* kCallbackReceivedStateToString[] = { + "Pending", "CalledWhileHandlingEvent", "CalledAfterHandleEvent"}; + *os << kCallbackReceivedStateToString[static_cast<int>(state)]; +} + class ReceivedCallback { public: ReceivedCallback() : ReceivedCallback(CallbackReceivedState::kPending, false) {} - ReceivedCallback(CallbackReceivedState state, bool coalesced_latency) - : state_(state), coalesced_latency_(coalesced_latency) {} + ReceivedCallback(CallbackReceivedState state, + bool coalesced_latency, + wtf_size_t after_handled_tasks = kNotFound) + : state_(state), + coalesced_latency_(coalesced_latency), + after_handled_tasks_(after_handled_tasks) {} bool operator==(const ReceivedCallback& other) const { return state_ == other.state_ && - coalesced_latency_ == other.coalesced_latency_; + coalesced_latency_ == other.coalesced_latency_ && + // Tests not caring about after_handled_tasks_ can leave it as + // kNotFound to ignore it. + (after_handled_tasks_ == kNotFound || + other.after_handled_tasks_ == kNotFound || + after_handled_tasks_ == other.after_handled_tasks_); + } + friend void PrintTo(const ReceivedCallback& callback, std::ostream* os) { + PrintTo(callback.state_, os); + if (callback.coalesced_latency_) { + *os << " coalesced"; + } + if (callback.after_handled_tasks_ != kNotFound) { + *os << " after_handled_tasks=" << callback.after_handled_tasks_; + } } private: CallbackReceivedState state_; bool coalesced_latency_; + // The number of handled tasks when the callback is run, for tests to check + // the order of event handling and callbacks. + wtf_size_t after_handled_tasks_; }; class HandledEventCallbackTracker { public: - HandledEventCallbackTracker() : handling_event_(false) { + explicit HandledEventCallbackTracker( + const Vector<std::unique_ptr<HandledTask>>& handled_tasks) + : handling_event_(false), handled_tasks_(handled_tasks) { weak_this_ = weak_ptr_factory_.GetWeakPtr(); } @@ -152,7 +199,7 @@ return callback; } - void DidHandleEvent(size_t index, + void DidHandleEvent(wtf_size_t index, blink::mojom::InputEventResultState ack_result, const ui::LatencyInfo& latency, mojom::blink::DidOverscrollParamsPtr params, @@ -160,21 +207,30 @@ callbacks_received_[index] = ReceivedCallback( handling_event_ ? CallbackReceivedState::kCalledWhileHandlingEvent : CallbackReceivedState::kCalledAfterHandleEvent, - latency.coalesced()); + latency.coalesced(), handled_tasks_.size()); } - const std::vector<ReceivedCallback>& GetReceivedCallbacks() const { + const Vector<ReceivedCallback>& GetReceivedCallbacks() const { return callbacks_received_; } bool handling_event_; private: - std::vector<ReceivedCallback> callbacks_received_; + Vector<ReceivedCallback> callbacks_received_; + const Vector<std::unique_ptr<HandledTask>>& handled_tasks_; base::WeakPtr<HandledEventCallbackTracker> weak_this_; base::WeakPtrFactory<HandledEventCallbackTracker> weak_ptr_factory_{this}; }; +MATCHER_P3(IsHandledTouchEvent, event_type, touch_id, dispatch_type, "") { + CHECK(WebInputEvent::IsTouchEventType(event_type)); + auto& event = static_cast<const WebTouchEvent&>(arg->taskAsEvent()->Event()); + return event.GetType() == event_type && + event.unique_touch_event_id == touch_id && + event.dispatch_type == dispatch_type; +} + class MockWidgetScheduler : public scheduler::FakeWidgetScheduler { public: MockWidgetScheduler() = default; @@ -184,12 +240,16 @@ }; class MainThreadEventQueueTest : public testing::Test, - public MainThreadEventQueueClient { + public testing::WithParamInterface<bool>, + public MainThreadEventQueueClient, + private ScopedUnblockTouchMoveEarlierForTest { public: MainThreadEventQueueTest() - : main_task_runner_(new base::TestSimpleTaskRunner()) { + : ScopedUnblockTouchMoveEarlierForTest(GetParam()), + main_task_runner_(new base::TestSimpleTaskRunner()) { widget_scheduler_ = base::MakeRefCounted<MockWidgetScheduler>(); - handler_callback_ = std::make_unique<HandledEventCallbackTracker>(); + handler_callback_ = + std::make_unique<HandledEventCallbackTracker>(handled_tasks_); } void SetUp() override { @@ -198,7 +258,7 @@ queue_->ClearRafFallbackTimerForTesting(); } - void HandleEvent(WebInputEvent& event, + void HandleEvent(const WebInputEvent& event, blink::mojom::InputEventResultState ack_result) { base::AutoReset<bool> in_handle_event(&handler_callback_->handling_event_, true); @@ -255,12 +315,16 @@ bool HandleInputEvent(const blink::WebCoalescedInputEvent& event, std::unique_ptr<cc::EventMetrics> metrics, HandledEventCallback callback) override { + if (will_handle_input_event_callback_) { + will_handle_input_event_callback_.Run(event); + } + if (!handle_input_event_) return false; auto handled_event = std::make_unique<HandledEvent>(event); handled_tasks_.push_back(std::move(handled_event)); - std::move(callback).Run(blink::mojom::InputEventResultState::kNotConsumed, - event.latency_info(), nullptr, std::nullopt); + std::move(callback).Run(main_thread_ack_state_, event.latency_info(), + nullptr, std::nullopt); return true; } void InputEventsDispatched(bool raf_aligned) override { @@ -271,20 +335,24 @@ } void SetNeedsMainFrame() override { needs_main_frame_ = true; } - std::vector<ReceivedCallback> GetAndResetCallbackResults() { + Vector<ReceivedCallback> GetAndResetCallbackResults() { std::unique_ptr<HandledEventCallbackTracker> callback = - std::make_unique<HandledEventCallbackTracker>(); + std::make_unique<HandledEventCallbackTracker>(handled_tasks_); handler_callback_.swap(callback); return callback->GetReceivedCallbacks(); } void set_handle_input_event(bool handle) { handle_input_event_ = handle; } + void set_main_thread_ack_state(blink::mojom::InputEventResultState state) { + main_thread_ack_state_ = state; + } + protected: scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_; scoped_refptr<MockWidgetScheduler> widget_scheduler_; scoped_refptr<MainThreadEventQueue> queue_; - std::vector<std::unique_ptr<HandledTask>> handled_tasks_; + Vector<std::unique_ptr<HandledTask>> handled_tasks_; std::unique_ptr<HandledEventCallbackTracker> handler_callback_; bool needs_main_frame_ = false; @@ -292,10 +360,19 @@ bool raf_aligned_events_dispatched_ = false; bool non_raf_aligned_events_dispatched_ = false; base::TimeTicks frame_time_; + blink::mojom::InputEventResultState main_thread_ack_state_ = + blink::mojom::InputEventResultState::kNotConsumed; unsigned closure_count_ = 0; + + // This allows a test to simulate concurrent action in the compositor thread + // when the main thread is dispatching events in the queue. + base::RepeatingCallback<void(const blink::WebCoalescedInputEvent&)> + will_handle_input_event_callback_; }; -TEST_F(MainThreadEventQueueTest, ClientDoesntHandleInputEvent) { +INSTANTIATE_TEST_SUITE_P(All, MainThreadEventQueueTest, ::testing::Bool()); + +TEST_P(MainThreadEventQueueTest, ClientDoesntHandleInputEvent) { // Prevent MainThreadEventQueueClient::HandleInputEvent() from handling the // event, and have it return false. Then the MainThreadEventQueue should // call the handled callback. @@ -317,7 +394,7 @@ HandleEvent(event2, blink::mojom::InputEventResultState::kNotConsumed); RunPendingTasksWithSimulatedRaf(); - std::vector<ReceivedCallback> received = GetAndResetCallbackResults(); + Vector<ReceivedCallback> received = GetAndResetCallbackResults(); // We didn't handle the event in the client method. EXPECT_EQ(handled_tasks_.size(), 0u); // There's 1 reply callback for our 1 event. @@ -331,7 +408,7 @@ CallbackReceivedState::kCalledAfterHandleEvent, false))); } -TEST_F(MainThreadEventQueueTest, NonBlockingWheel) { +TEST_P(MainThreadEventQueueTest, NonBlockingWheel) { WebMouseWheelEvent kEvents[4] = { SyntheticWebMouseWheelEventBuilder::Build( 10, 10, 0, 53, 0, ui::ScrollGranularity::kScrollByPixel), @@ -425,7 +502,7 @@ } } -TEST_F(MainThreadEventQueueTest, NonBlockingTouch) { +TEST_P(MainThreadEventQueueTest, NonBlockingTouch) { EXPECT_CALL(*widget_scheduler_, DidHandleInputEventOnMainThread(testing::_, testing::_)) .Times(0); @@ -521,7 +598,7 @@ } } -TEST_F(MainThreadEventQueueTest, BlockingTouch) { +TEST_P(MainThreadEventQueueTest, BlockingTouch) { SyntheticWebTouchEvent kEvents[4]; kEvents[0].PressPoint(10, 10); kEvents[1].PressPoint(10, 10); @@ -575,7 +652,7 @@ CallbackReceivedState::kCalledWhileHandlingEvent, false))); } -TEST_F(MainThreadEventQueueTest, InterleavedEvents) { +TEST_P(MainThreadEventQueueTest, InterleavedEvents) { WebMouseWheelEvent kWheelEvents[2] = { SyntheticWebMouseWheelEventBuilder::Build( 10, 10, 0, 53, 0, ui::ScrollGranularity::kScrollByPixel), @@ -640,7 +717,7 @@ } } -TEST_F(MainThreadEventQueueTest, RafAlignedMouseInput) { +TEST_P(MainThreadEventQueueTest, RafAlignedMouseInput) { WebMouseEvent mouseDown = SyntheticWebMouseEventBuilder::Build( WebInputEvent::Type::kMouseDown, 10, 10, 0); @@ -729,7 +806,7 @@ handled_tasks_.at(4)->taskAsEvent()->Event().GetModifiers()); } -TEST_F(MainThreadEventQueueTest, RafAlignedTouchInput) { +TEST_P(MainThreadEventQueueTest, RafAlignedTouchInput) { SyntheticWebTouchEvent kEvents[3]; kEvents[0].PressPoint(10, 10); kEvents[1].PressPoint(10, 10); @@ -806,7 +883,7 @@ CallbackReceivedState::kCalledAfterHandleEvent, false))); } -TEST_F(MainThreadEventQueueTest, RafAlignedTouchInputCoalescedMoves) { +TEST_P(MainThreadEventQueueTest, RafAlignedTouchInputCoalescedMoves) { SyntheticWebTouchEvent kEvents[2]; kEvents[0].PressPoint(10, 10); kEvents[0].MovePoint(0, 50, 50); @@ -876,7 +953,7 @@ CallbackReceivedState::kCalledWhileHandlingEvent, false))); } -TEST_F(MainThreadEventQueueTest, RafAlignedTouchInputThrottlingMoves) { +TEST_P(MainThreadEventQueueTest, RafAlignedTouchInputThrottlingMoves) { EXPECT_CALL(*widget_scheduler_, DidHandleInputEventOnMainThread(testing::_, testing::_)) .Times(3); @@ -922,7 +999,7 @@ EXPECT_EQ(0u, event_queue().size()); } -TEST_F(MainThreadEventQueueTest, LowLatency) { +TEST_P(MainThreadEventQueueTest, LowLatency) { SyntheticWebTouchEvent kEvents[2]; kEvents[0].PressPoint(10, 10); kEvents[1].PressPoint(10, 10); @@ -996,7 +1073,7 @@ EXPECT_EQ(0u, event_queue().size()); } -TEST_F(MainThreadEventQueueTest, BlockingTouchesDuringFling) { +TEST_P(MainThreadEventQueueTest, BlockingTouchesDuringFling) { SyntheticWebTouchEvent kEvents; kEvents.PressPoint(10, 10); kEvents.touch_start_or_first_touch_move = true; @@ -1081,7 +1158,7 @@ EXPECT_TRUE(Equal(kEvents, *last_touch_event)); } -TEST_F(MainThreadEventQueueTest, BlockingTouchesOutsideFling) { +TEST_P(MainThreadEventQueueTest, BlockingTouchesOutsideFling) { SyntheticWebTouchEvent kEvents; kEvents.PressPoint(10, 10); kEvents.touch_start_or_first_touch_move = true; @@ -1156,7 +1233,7 @@ EXPECT_TRUE(Equal(kEvents, *last_touch_event)); } -TEST_F(MainThreadEventQueueTest, QueueingEventTimestampRecorded) { +TEST_P(MainThreadEventQueueTest, QueueingEventTimestampRecorded) { WebMouseEvent kEvent = SyntheticWebMouseEventBuilder::Build( blink::WebInputEvent::Type::kMouseDown); // Set event timestamp to be in the past to simulate actual event @@ -1179,30 +1256,7 @@ EXPECT_LT(kHandledEvent->TimeStamp(), kHandledEvent->QueuedTimeStamp()); } -class MainThreadEventQueueInitializationTest - : public testing::Test, - public MainThreadEventQueueClient { - public: - MainThreadEventQueueInitializationTest() = default; - - bool HandleInputEvent(const blink::WebCoalescedInputEvent& event, - std::unique_ptr<cc::EventMetrics> metrics, - HandledEventCallback callback) override { - std::move(callback).Run(blink::mojom::InputEventResultState::kNotConsumed, - event.latency_info(), nullptr, std::nullopt); - return true; - } - - void InputEventsDispatched(bool raf_aligned) override {} - void SetNeedsMainFrame() override {} - - protected: - scoped_refptr<MainThreadEventQueue> queue_; - blink::scheduler::WebMockThreadScheduler widget_scheduler_; - scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_; -}; - -TEST_F(MainThreadEventQueueTest, QueuingTwoClosures) { +TEST_P(MainThreadEventQueueTest, QueuingTwoClosures) { EXPECT_FALSE(main_task_runner_->HasPendingTask()); EXPECT_EQ(0u, event_queue().size()); @@ -1216,7 +1270,7 @@ EXPECT_EQ(2u, handled_tasks_.at(1)->taskAsClosure()); } -TEST_F(MainThreadEventQueueTest, QueuingClosureWithRafEvent) { +TEST_P(MainThreadEventQueueTest, QueuingClosureWithRafEvent) { SyntheticWebTouchEvent kEvents[2]; kEvents[0].PressPoint(10, 10); kEvents[1].PressPoint(10, 10); @@ -1265,7 +1319,7 @@ handled_tasks_.at(3)->taskAsEvent()->Event().GetType()); } -TEST_F(MainThreadEventQueueTest, QueuingClosuresBetweenEvents) { +TEST_P(MainThreadEventQueueTest, QueuingClosuresBetweenEvents) { SyntheticWebTouchEvent kEvents[2]; kEvents[0].PressPoint(10, 10); kEvents[1].PressPoint(10, 10); @@ -1300,7 +1354,7 @@ handled_tasks_.at(3)->taskAsEvent()->Event().GetType()); } -TEST_F(MainThreadEventQueueTest, BlockingTouchMoveBecomesNonBlocking) { +TEST_P(MainThreadEventQueueTest, BlockingTouchMoveBecomesNonBlocking) { SyntheticWebTouchEvent kEvents[2]; kEvents[0].PressPoint(10, 10); kEvents[0].MovePoint(0, 20, 20); @@ -1348,7 +1402,7 @@ .dispatch_type); } -TEST_F(MainThreadEventQueueTest, BlockingTouchMoveWithTouchEnd) { +TEST_P(MainThreadEventQueueTest, BlockingTouchMoveWithTouchEnd) { SyntheticWebTouchEvent kEvents[2]; kEvents[0].PressPoint(10, 10); kEvents[0].MovePoint(0, 20, 20); @@ -1388,7 +1442,212 @@ .dispatch_type); } -TEST_F(MainThreadEventQueueTest, UnbufferedDispatchTouchEvent) { +TEST_P(MainThreadEventQueueTest, + UnblockTouchMoveAfterTouchStartAndFirstTouchMoveNotConsumed) { + if (!RuntimeEnabledFeatures::UnblockTouchMoveEarlierEnabled()) { + return; + } + + SyntheticWebTouchEvent touch_start; + touch_start.PressPoint(10, 10); + touch_start.touch_start_or_first_touch_move = true; + ASSERT_EQ(WebInputEvent::Type::kTouchStart, touch_start.GetType()); + ASSERT_EQ(WebInputEvent::DispatchType::kBlocking, touch_start.dispatch_type); + + SyntheticWebTouchEvent touch_moves[3]; + for (auto& touch_move : touch_moves) { + touch_move.MovePoint(0, 20, 30); + ASSERT_EQ(WebInputEvent::Type::kTouchMove, touch_move.GetType()); + ASSERT_EQ(WebInputEvent::DispatchType::kBlocking, touch_move.dispatch_type); + } + touch_moves[0].touch_start_or_first_touch_move = true; + + struct WillHandleInputEventCallback { + void Run(const WebCoalescedInputEvent& event) { + test.set_main_thread_ack_state( + blink::mojom::InputEventResultState::kNotConsumed); + if (event.Event().GetType() == WebInputEvent::Type::kTouchStart && + consume_touch_start) { + test.set_main_thread_ack_state( + blink::mojom::InputEventResultState::kConsumed); + } + auto touch_id = static_cast<const WebTouchEvent&>(event.Event()) + .unique_touch_event_id; + if (touch_id == touch_moves[0].unique_touch_event_id && + consume_first_touch_move) { + test.set_main_thread_ack_state( + blink::mojom::InputEventResultState::kConsumed); + } + // Simulates two new blocking touchmove events enqueued while the first + // touchmove is being dispatched, respectively. + if (touch_id == touch_moves[0].unique_touch_event_id) { + test.HandleEvent(touch_moves[1], + blink::mojom::InputEventResultState::kNotConsumed); + test.HandleEvent(touch_moves[2], + blink::mojom::InputEventResultState::kNotConsumed); + } + } + + MainThreadEventQueueTest& test; + const SyntheticWebTouchEvent* touch_moves; + bool consume_touch_start = false; + bool consume_first_touch_move = false; + }; + WillHandleInputEventCallback will_handle_input_event_callback{*this, + touch_moves}; + + will_handle_input_event_callback_ = + base::BindRepeating(&WillHandleInputEventCallback::Run, + base::Unretained(&will_handle_input_event_callback)); + + EXPECT_FALSE(main_task_runner_->HasPendingTask()); + EXPECT_EQ(0u, event_queue().size()); + EXPECT_CALL(*widget_scheduler_, + DidHandleInputEventOnMainThread(testing::_, testing::_)) + .Times(4); + HandleEvent(touch_start, blink::mojom::InputEventResultState::kNotConsumed); + HandleEvent(touch_moves[0], + blink::mojom::InputEventResultState::kNotConsumed); + EXPECT_EQ(2u, event_queue().size()); + RunPendingTasksWithSimulatedRaf(); + EXPECT_EQ(0u, event_queue().size()); + EXPECT_FALSE(main_task_runner_->HasPendingTask()); + EXPECT_FALSE(needs_main_frame_); + EXPECT_THAT( + GetAndResetCallbackResults(), + testing::ElementsAre( + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 1u), + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 2u), + // These callbacks were run just after handling the first touchmove. + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 2u), + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, true, + 2u))); + EXPECT_THAT( + handled_tasks_, + ::testing::ElementsAre( + // touch_start should remain blocking. + IsHandledTouchEvent(WebInputEvent::Type::kTouchStart, + touch_start.unique_touch_event_id, + WebInputEvent::DispatchType::kBlocking), + // touch_moves[0] should remain blocking. + IsHandledTouchEvent(WebInputEvent::Type::kTouchMove, + touch_moves[0].unique_touch_event_id, + WebInputEvent::DispatchType::kBlocking), + // touch_moves[1] was unblocked while it was in the queue. + // touch_moves[2] was coalesced into touch_moves[1]. + IsHandledTouchEvent(WebInputEvent::Type::kTouchMove, + touch_moves[1].unique_touch_event_id, + WebInputEvent::DispatchType::kEventNonBlocking))); + + // Start another touch sequence, with the first touch_move consumed. This + // is not in a standalone test case to test the last unblocking status won't + // leak into this sequence. + handled_tasks_.clear(); + will_handle_input_event_callback.consume_first_touch_move = true; + EXPECT_CALL(*widget_scheduler_, + DidHandleInputEventOnMainThread(testing::_, testing::_)) + .Times(4); + HandleEvent(touch_start, blink::mojom::InputEventResultState::kNotConsumed); + HandleEvent(touch_moves[0], + blink::mojom::InputEventResultState::kNotConsumed); + RunPendingTasksWithSimulatedRaf(); + EXPECT_THAT( + GetAndResetCallbackResults(), + testing::ElementsAre( + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 1u), + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 2u), + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 3u), + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, true, + 3u))); + EXPECT_THAT(handled_tasks_, + ::testing::ElementsAre( + IsHandledTouchEvent(WebInputEvent::Type::kTouchStart, + touch_start.unique_touch_event_id, + WebInputEvent::DispatchType::kBlocking), + IsHandledTouchEvent(WebInputEvent::Type::kTouchMove, + touch_moves[0].unique_touch_event_id, + WebInputEvent::DispatchType::kBlocking), + IsHandledTouchEvent(WebInputEvent::Type::kTouchMove, + touch_moves[1].unique_touch_event_id, + WebInputEvent::DispatchType::kBlocking))); + + // Start another touch sequence, with the touch start consumed. + handled_tasks_.clear(); + will_handle_input_event_callback.consume_touch_start = true; + will_handle_input_event_callback.consume_first_touch_move = false; + EXPECT_CALL(*widget_scheduler_, + DidHandleInputEventOnMainThread(testing::_, testing::_)) + .Times(4); + HandleEvent(touch_start, blink::mojom::InputEventResultState::kNotConsumed); + HandleEvent(touch_moves[0], + blink::mojom::InputEventResultState::kNotConsumed); + RunPendingTasksWithSimulatedRaf(); + EXPECT_THAT( + GetAndResetCallbackResults(), + testing::ElementsAre( + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 1u), + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 2u), + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 3u), + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, true, + 3u))); + EXPECT_THAT(handled_tasks_, + ::testing::ElementsAre( + IsHandledTouchEvent(WebInputEvent::Type::kTouchStart, + touch_start.unique_touch_event_id, + WebInputEvent::DispatchType::kBlocking), + IsHandledTouchEvent(WebInputEvent::Type::kTouchMove, + touch_moves[0].unique_touch_event_id, + WebInputEvent::DispatchType::kBlocking), + IsHandledTouchEvent(WebInputEvent::Type::kTouchMove, + touch_moves[1].unique_touch_event_id, + WebInputEvent::DispatchType::kBlocking))); + + // Start another touch sequence, neither the touch start nor the first touch + // move are consumed, like the first touch sequence. + handled_tasks_.clear(); + will_handle_input_event_callback.consume_touch_start = false; + EXPECT_CALL(*widget_scheduler_, + DidHandleInputEventOnMainThread(testing::_, testing::_)) + .Times(4); + HandleEvent(touch_start, blink::mojom::InputEventResultState::kNotConsumed); + HandleEvent(touch_moves[0], + blink::mojom::InputEventResultState::kNotConsumed); + RunPendingTasksWithSimulatedRaf(); + EXPECT_THAT( + GetAndResetCallbackResults(), + testing::ElementsAre( + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 1u), + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 2u), + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, + false, 2u), + ReceivedCallback(CallbackReceivedState::kCalledAfterHandleEvent, true, + 2u))); + EXPECT_THAT( + handled_tasks_, + ::testing::ElementsAre( + IsHandledTouchEvent(WebInputEvent::Type::kTouchStart, + touch_start.unique_touch_event_id, + WebInputEvent::DispatchType::kBlocking), + IsHandledTouchEvent(WebInputEvent::Type::kTouchMove, + touch_moves[0].unique_touch_event_id, + WebInputEvent::DispatchType::kBlocking), + IsHandledTouchEvent(WebInputEvent::Type::kTouchMove, + touch_moves[1].unique_touch_event_id, + WebInputEvent::DispatchType::kEventNonBlocking))); +} + +TEST_P(MainThreadEventQueueTest, UnbufferedDispatchTouchEvent) { SyntheticWebTouchEvent kEvents[3]; kEvents[0].PressPoint(10, 10); kEvents[1].PressPoint(10, 10); @@ -1425,7 +1684,7 @@ EXPECT_FALSE(needs_main_frame_); } -TEST_F(MainThreadEventQueueTest, PointerEventsCoalescing) { +TEST_P(MainThreadEventQueueTest, PointerEventsCoalescing) { queue_->HasPointerRawUpdateEventHandlers(true); WebMouseEvent mouse_move = SyntheticWebMouseEventBuilder::Build( WebInputEvent::Type::kMouseMove, 10, 10, 0); @@ -1454,7 +1713,7 @@ EXPECT_FALSE(needs_main_frame_); } -TEST_F(MainThreadEventQueueTest, PointerRawUpdateEvents) { +TEST_P(MainThreadEventQueueTest, PointerRawUpdateEvents) { WebMouseEvent mouse_move = SyntheticWebMouseEventBuilder::Build( WebInputEvent::Type::kMouseMove, 10, 10, 0); @@ -1496,7 +1755,7 @@ EXPECT_FALSE(needs_main_frame_); } -TEST_F(MainThreadEventQueueTest, UnbufferedDispatchMouseEvent) { +TEST_P(MainThreadEventQueueTest, UnbufferedDispatchMouseEvent) { WebMouseEvent mouse_down = SyntheticWebMouseEventBuilder::Build( WebInputEvent::Type::kMouseDown, 10, 10, 0); WebMouseEvent mouse_move = SyntheticWebMouseEventBuilder::Build( @@ -1537,7 +1796,7 @@ // are not coalesced with other events. During pointer lock, // kRelativeMotionEvent is sent to the Renderer only to update the new screen // position. Events of this kind shouldn't be dispatched or coalesced. -TEST_F(MainThreadEventQueueTest, PointerEventsWithRelativeMotionCoalescing) { +TEST_P(MainThreadEventQueueTest, PointerEventsWithRelativeMotionCoalescing) { WebMouseEvent mouse_move = SyntheticWebMouseEventBuilder::Build( WebInputEvent::Type::kMouseMove, 10, 10, 0); @@ -1634,7 +1893,7 @@ // Verifies that after rAF-aligned or non-rAF-aligned events are dispatched, // clients are notified that the dispatch is done. -TEST_F(MainThreadEventQueueTest, InputEventsDispatchedNotified) { +TEST_P(MainThreadEventQueueTest, InputEventsDispatchedNotified) { WebKeyboardEvent key_down(WebInputEvent::Type::kRawKeyDown, 0, base::TimeTicks::Now()); WebKeyboardEvent key_up(WebInputEvent::Type::kKeyUp, 0,
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py index 2389f4f..bfd5a1a2 100644 --- a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py +++ b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py
@@ -341,6 +341,10 @@ url: str screenshot: str + @staticmethod + def decode_image(screenshot: 'ReftestScreenshot') -> bytes: + return base64.b64decode(screenshot['screenshot'].strip()) + @dataclass class BrowserOutput: @@ -862,51 +866,83 @@ html_diff_content.encode()) def _write_screenshots(self, test_name: str, artifacts: Artifacts, - screenshots: List[ReftestScreenshot]): + screenshot1: ReftestScreenshot, + screenshot2: ReftestScreenshot): """Write actual, expected, and diff screenshots to disk, if possible. Arguments: - test_name: Web test name (a path). + test_name: Web test name (a URL whose path is relative to + `web_tests/`). artifacts: Artifact manager. - screenshots: Each element represents a screenshot of either the test - result or one of its references. + screenshot1: A screenshot of either the test page or one of its + references that failed comparison. + screenshot2: The screenshot compared against `screenshot1`. + + The screenshots may be in either order and may represent any compatible + comparison (test against reference, or match ref against mismatch ref). Returns: The diff stats if the screenshots are different. """ - # Remember the two images so we can diff them later. - _, test_url = self.port.get_suite_name_and_base_test(test_name) - test_url = self.path_finder.strip_wpt_path(test_url) - actual_image_bytes = b'' - expected_image_bytes = b'' + _, base_test = self.port.get_suite_name_and_base_test(test_name) + test_url = self.path_finder.strip_wpt_path(base_test) - for screenshot in screenshots: - if not isinstance(screenshot, dict): - # Skip the relation string, like '!=' or '=='. - continue - # The URL produced by wptrunner will have a leading "/", which we - # trim away for easier comparison to the WPT name below. - url = screenshot['url'] - if url.startswith('/'): - url = url[1:] - image_bytes = base64.b64decode(screenshot['screenshot'].strip()) + wpt_dir = self.port.wpt_dir(base_test) + assert wpt_dir, f'{base_test!r} is not a WPT' + manifest = self.port.wpt_manifest(wpt_dir) + # `test_url` is the globally mounted URL (i.e., its canonical ID), + # whereas `url_from_root`'s path part is relative to the test root + # (i.e., `external/wpt` or `wpt_internal`). These URLs happen to be + # identical for `external/wpt`, which wptserve mounts to `/`. + url_from_root = base_test[len(f'{wpt_dir}/'):] + relation_by_ref = { + url: relation + for relation, url in manifest.extract_reference_list(url_from_root) + } + assert set(relation_by_ref.values()) <= {'==', '!='} - screenshot_key = 'expected_image' - file_suffix = test_failures.FILENAME_SUFFIX_EXPECTED - if url == test_url: - screenshot_key = 'actual_image' - file_suffix = test_failures.FILENAME_SUFFIX_ACTUAL - actual_image_bytes = image_bytes + test_screenshot = match_screenshot = mismatch_screenshot = None + for screenshot in [screenshot1, screenshot2]: + # Compare URLs with a leading `/` to follow the convention + # wptrunner uses. There can only be up to one of each type of + # screenshot. + if screenshot['url'] == f'/{test_url}': + assert not test_screenshot + test_screenshot = screenshot + elif relation_by_ref[screenshot['url']] == '==': + assert not match_screenshot + match_screenshot = screenshot else: - expected_image_bytes = image_bytes + assert not mismatch_screenshot + mismatch_screenshot = screenshot - screenshot_subpath = self.port.output_filename( - test_name, file_suffix, '.png') - artifacts.CreateArtifact(screenshot_key, screenshot_subpath, - image_bytes) + # Because fuzzy rules allow matches without pixel-by-pixel equality, + # the screenshots in a mismatch failure may be slightly different, so we + # still extract both. + if mismatch_screenshot: + expected = mismatch_screenshot + # For tests with both match and mismatch references, the references + # may be compared if the match reference is found to be equivalent + # to the test page. + actual = test_screenshot or match_screenshot + else: + expected, actual = match_screenshot, test_screenshot + + assert expected + expected_image = ReftestScreenshot.decode_image(expected) + expected_subpath = self.port.output_filename( + test_name, test_failures.FILENAME_SUFFIX_EXPECTED, '.png') + artifacts.CreateArtifact('expected_image', expected_subpath, + expected_image) + + assert actual + actual_image = ReftestScreenshot.decode_image(actual) + actual_subpath = self.port.output_filename( + test_name, test_failures.FILENAME_SUFFIX_ACTUAL, '.png') + artifacts.CreateArtifact('actual_image', actual_subpath, actual_image) diff_bytes, stats, error = self.port.diff_image( - expected_image_bytes, actual_image_bytes) + expected_image, actual_image) if error: _log.error( 'Error creating diff image for %s ' @@ -942,8 +978,11 @@ self._write_text_results(result, artifacts) screenshots = (extra or {}).get('reftest_screenshots') or [] if screenshots: + # Remove the relation operator `==` or `!=` between the + # screenshot objects. + screenshot1, _, screenshot2 = screenshots image_diff_stats = self._write_screenshots( - result.name, artifacts, screenshots) + result.name, artifacts, screenshot1, screenshot2) if message: self._write_log(result.name, artifacts, 'crash_log',
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py index 93d6fc6..3b8a55c 100644 --- a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py
@@ -41,8 +41,16 @@ 'reftest': { 'reftest.html': [ 'c3f2fb6f436da59d43aeda0a7e8a018084557033', - [None, [['reftest-ref.html', '==']], {}], - ] + [None, [['/reftest-ref.html', '==']], {}], + ], + 'reftest-multiple.html': [ + 'c3f2fb6f436da59d43aeda0a7e8a018084557033', + [ + None, + [['/reftest-ref.html', '=='], + ['/reftest-mismatch.html', '!=']], {} + ], + ], }, 'testharness': { 'test.html': [ @@ -75,7 +83,10 @@ 'reftest': { 'reftest.html': [ 'c3f2fb6f436da59d43aeda0a7e8a018084557033', - [None, [['reftest-ref.html', '==']], {}], + [ + None, + [['/wpt_internal/reftest-ref.html', '==']], {} + ], ], }, 'testharness': { @@ -90,6 +101,14 @@ }, })) self.fs.write_text_file( + self.path_finder.path_from_web_tests('VirtualTestSuites'), + json.dumps([{ + 'prefix': 'fake-vts', + 'platforms': ['Linux'], + 'bases': ['external/wpt/reftest-multiple.html'], + 'args': ['--enable-features=FakeFeature'], + }])) + self.fs.write_text_file( self.path_finder.path_from_blink_tools('blinkpy', 'web_tests', 'results.html'), 'results-viewer-body') @@ -699,7 +718,7 @@ 'reftest_screenshots': [{ 'url': '/reftest.html', 'screenshot': 'abcd', - }, { + }, '==', { 'url': '/reftest-ref.html', 'screenshot': 'bcde', }], @@ -725,6 +744,44 @@ '> abcd', ])) + def test_extract_screenshots_match_and_mismatch(self): + self._event(action='test_start', + test='/reftest-multiple.html', + subsuite='fake-vts') + self._event(action='test_end', + test='/reftest-multiple.html', + subsuite='fake-vts', + status='FAIL', + expected='PASS', + extra={ + 'reftest_screenshots': [{ + 'url': '/reftest-ref.html', + 'screenshot': 'abcd', + }, '!=', { + 'url': '/reftest-mismatch.html', + 'screenshot': 'abcd', + }], + }) + self.assertEqual( + self.fs.read_binary_file( + self.fs.join('/mock-checkout', 'out', 'Default', + 'layout-test-results', 'virtual', 'fake-vts', + 'external', 'wpt', + 'reftest-multiple-actual.png')), + base64.b64decode('abcd')) + self.assertEqual( + self.fs.read_binary_file( + self.fs.join('/mock-checkout', 'out', 'Default', + 'layout-test-results', 'virtual', 'fake-vts', + 'external', 'wpt', + 'reftest-multiple-expected.png')), + base64.b64decode('abcd')) + self.assertFalse( + self.fs.exists( + self.fs.join('/mock-checkout', 'out', 'Default', + 'layout-test-results', 'virtual', 'fake-vts', + 'external', 'wpt', 'reftest-multiple-diff.png'))) + def test_extract_screenshots_for_wpt_internal(self): self._event(action='test_start', test='/wpt_internal/reftest.html') self._event(action='test_end', @@ -735,8 +792,8 @@ 'reftest_screenshots': [{ 'url': '/wpt_internal/reftest.html', 'screenshot': 'abcd', - }, { - 'url': 'wpt_internal/reftest-ref.html', + }, '==', { + 'url': '/wpt_internal/reftest-ref.html', 'screenshot': 'bcde', }], }) @@ -990,31 +1047,28 @@ return_value=(..., diff_stats, ...)): for _ in range(2): self._event(action='suite_start') - self._event(action='test_start', test='/test.html') - self._event(action='test_status', - test='/test.html', - status='FAIL', - expected='PASS', - subtest='subtest') + self._event(action='test_start', test='/reftest.html') self._event(action='process_output', process='101', command='chromedriver --port=101', data='[101:101:INFO] This is Chrome version 125') self._event(action='test_end', - test='/test.html', - status='OK', + test='/reftest.html', + status='FAIL', + expected='PASS', extra={ 'reftest_screenshots': [{ - 'url': '/test.html', + 'url': '/reftest-ref.html', 'screenshot': 'abcd', + }, '==', { + 'url': '/reftest.html', + 'screenshot': 'bcde', }], 'browser_pid': 101, }) - self._event(action='test_start', test='/reftest.html') - self._event(action='test_end', - test='/reftest.html', - status='PASS') + self._event(action='test_start', test='/test.html') + self._event(action='test_end', test='/test.html', status='OK') self._event(action='suite_end') self.processor.process_results_json() @@ -1023,13 +1077,13 @@ self.fs.join('/mock-checkout', 'out', 'Default', 'layout-test-results', 'full_results.json'))) self.assertEqual(full_json['num_regressions'], 1) - unexpected_fail = full_json['tests']['external']['wpt']['test.html'] + unexpected_fail = full_json['tests']['external']['wpt']['reftest.html'] self.assertTrue(unexpected_fail['has_stderr']) self.assertEqual(unexpected_fail['artifacts']['stderr'], [ self.fs.join('layout-test-results', 'external', 'wpt', - 'test-stderr.txt'), + 'reftest-stderr.txt'), self.fs.join('layout-test-results', 'retry_1', 'external', 'wpt', - 'test-stderr.txt'), + 'reftest-stderr.txt'), ]) self.assertEqual(unexpected_fail['image_diff_stats'], diff_stats) @@ -1044,8 +1098,9 @@ failing_results = json.loads(failing_results_match['json']) self.assertIn('external', failing_results['tests']) self.assertIn('wpt', failing_results['tests']['external']) - self.assertIn('test.html', failing_results['tests']['external']['wpt']) - self.assertNotIn('reftest.html', + self.assertIn('reftest.html', + failing_results['tests']['external']['wpt']) + self.assertNotIn('test.html', failing_results['tests']['external']['wpt']) self.assertRegex(self.fs.read_text_file(path_to_failing_results), 'ADD_RESULTS\(.*\);$')
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index c06023f812..bb6a9449 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2529,6 +2529,7 @@ crbug.com/626703 external/wpt/uievents/mouse/mouse_boundary_events_after_removing_last_over_element.html [ Failure ] # ====== New tests from wpt-importer added here ====== +external/wpt/notifications/instance.https.window.html [ Timeout ] crbug.com/340657191 [ Linux ] external/wpt/html/semantics/forms/the-select-element/stylable-select/native-popup-with-datalist.tentative.html [ Failure ] crbug.com/340167179 [ Win11-arm64 ] external/wpt/fetch/api/request/request-consume.any.serviceworker.html [ Failure Timeout ] crbug.com/340167179 [ Win11-arm64 ] external/wpt/fetch/api/request/request-consume.any.worker.html [ Failure Timeout ] @@ -7138,7 +7139,7 @@ [ Debug Mac14 ] http/tests/webfont/font-display-intervention.html [ Failure Pass ] [ Debug Mac14 ] media/controls/closed-captions-dynamic-update.html [ Failure Pass ] [ Debug Mac14 ] scrollbars/scrollbar-iframe-click-does-not-blur-content.html [ Failure Pass ] -[ Debug Mac14 ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/fedcm-multi-idp-mediation-optional.https.html [ Failure Timeout Pass ] +[ Debug Mac14 ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/fedcm-multi-idp-mediation-optional.https.html [ Failure Pass Timeout ] [ Debug Mac14 ] virtual/fenced-frame-mparch/external/wpt/fenced-frame/disallowed-navigations-dangling-markup-urn.https.html [ Failure Pass ] [ Debug Mac14 ] virtual/fenced-frame-mparch/external/wpt/html/anonymous-iframe/embedding.tentative.https.window.html?13-last [ Failure Pass ] [ Debug Mac14 ] virtual/fenced-frame-mparch/external/wpt/html/anonymous-iframe/embedding.tentative.https.window.html?8-8 [ Failure ]
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 e653efcd..096ae4e 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
@@ -143564,7 +143564,7 @@ ] ], "text-box-trim-start-001.html": [ - "17d4acdea054c76804dd05ad83b301015f7a8e32", + "35ac848aa6291db0508fd4df3f0bf2e7f2f43e07", [ "css/css-inline/text-box-trim/text-box-trim-start-001.html?class=cap", [ @@ -143604,6 +143604,76 @@ ] ], {} + ], + [ + "css/css-inline/text-box-trim/text-box-trim-start-001.html?class=vlr,alphabetic", + [ + [ + "/css/css-inline/text-box-trim/text-box-trim-start-001-ref.html?class=vlr,alphabetic", + "==" + ] + ], + {} + ], + [ + "css/css-inline/text-box-trim/text-box-trim-start-001.html?class=vlr,leading", + [ + [ + "/css/css-inline/text-box-trim/text-box-trim-start-001-ref.html?class=vlr,leading", + "==" + ] + ], + {} + ], + [ + "css/css-inline/text-box-trim/text-box-trim-start-001.html?class=vlr,text", + [ + [ + "/css/css-inline/text-box-trim/text-box-trim-start-001-ref.html?class=vlr,text", + "==" + ] + ], + {} + ], + [ + "css/css-inline/text-box-trim/text-box-trim-start-001.html?class=vrl,cap", + [ + [ + "/css/css-inline/text-box-trim/text-box-trim-start-001-ref.html?class=vrl,cap", + "==" + ] + ], + {} + ], + [ + "css/css-inline/text-box-trim/text-box-trim-start-001.html?class=vrl,ex", + [ + [ + "/css/css-inline/text-box-trim/text-box-trim-start-001-ref.html?class=vrl,ex", + "==" + ] + ], + {} + ], + [ + "css/css-inline/text-box-trim/text-box-trim-start-001.html?class=vrl,leading", + [ + [ + "/css/css-inline/text-box-trim/text-box-trim-start-001-ref.html?class=vrl,leading", + "==" + ] + ], + {} + ], + [ + "css/css-inline/text-box-trim/text-box-trim-start-001.html?class=vrl,text", + [ + [ + "/css/css-inline/text-box-trim/text-box-trim-start-001-ref.html?class=vrl,text", + "==" + ] + ], + {} ] ] } @@ -275733,7 +275803,7 @@ ] ], "popover-anchor-display.tentative.html": [ - "a713540094a03ab52b5fd315551554581b362913", + "3dbd6c9a24dd3d420e8e943a8e1e679618180fb5", [ null, [ @@ -296875,11 +296945,11 @@ [] ], "digital-identity-helper.js": [ - "2020d6cda7271be351da9a9849014899bd68df01", + "8fff82745172154972dcda4c3c6cb98d4a5af5e1", [] ], "digital-identity-iframe.html": [ - "8e193ff09f90fb09b8e676849a0d9dbdb0f043b1", + "8b3a424d1e21d381b76849deb261762aec016298", [] ], "echoing-nester.html": [ @@ -324158,7 +324228,7 @@ [] ], "text-box-trim-start-001-ref.html": [ - "ac5f7d776302c61923f0edcb281c6f72dbd52b0c", + "40067cc592504c4622ded772b545a3e3a29e57dd", [] ] } @@ -349044,7 +349114,7 @@ [] ], "echo-policy-nested.html.headers": [ - "419a3c3dd16dcf7d6dfdcbcd86ad26314f9ac368", + "ab319fc4ceb1d583a04832d665efb36bc87628a2", [] ], "echo-policy.py": [ @@ -349253,11 +349323,11 @@ }, "required-policy": { "document-policy.html.headers": [ - "20629ac15f53b45818e4357a33f544b7f523e466", + "ab319fc4ceb1d583a04832d665efb36bc87628a2", [] ], "required-document-policy.html.headers": [ - "ac1bf268b50a75411e6819abbadc8e493dd9a612", + "230ffe282a107537195993cf252f683ad1c97f52", [] ], "separate-document-policies.html.headers": [ @@ -371933,7 +372003,7 @@ ], "resources": { "stylable-select-styles.css": [ - "bb613823e79750438277857eebe9ef9d0bdb839b", + "7f4c8b6c448af5ac01bdf85c906ecd8bc18bff79", [] ], "stylable-select-utils.js": [ @@ -382746,7 +382816,15 @@ [] ], "getnotifications-sw.js": [ - "331913b99358922f7d9743a8dc49218bc93004c2", + "ad2c11c6d5fca8492bc7f52bceaa15011d602037", + [] + ], + "instance-checks.js": [ + "31ff0b870937d5452607f4b99ae72d7db7610fe2", + [] + ], + "instance-sw.js": [ + "f08b17e15f8407ea7bef6ce47a040af9fd8db3bb", [] ], "lang.https-expected.txt": [ @@ -382759,11 +382837,11 @@ ], "resources": { "custom-data.js": [ - "b21d28a1bb390575f34206c87aae1f7fd8655fd7", + "49a5c60d811338cc898bc64b1cbe8b3e41c54ca8", [] ], "helpers.js": [ - "ca44e32f7f4921011226b9647bc4ba5d76495980", + "6b418be03ed2d7c0697163b2758667172201289b", [] ], "icon.png": [ @@ -386260,7 +386338,7 @@ [] ], "document-reporting-bypass-report-to.https.sub.html.sub.headers": [ - "b2a3d20f482151a27a545c8894805737a57ff035", + "bbdd968c04f79d7fa1d324283f19b764b8e8cd4f", [] ], "document-reporting-default-endpoint.https.sub.html.sub.headers": [ @@ -386268,11 +386346,11 @@ [] ], "document-reporting-named-endpoints.https.sub.html.sub.headers": [ - "2d5a308db27f7b2595114bf7e4fd8fa9612dfc0e", + "89b7b1afec5165368db7cf724516dfa02bf4c052", [] ], "document-reporting-override-endpoint.https.sub.html.sub.headers": [ - "46954f4d5cbc9a17a9bcbf91481e905748441edd", + "f9c9bf45c44b49f58072f1558141c6ba583ca0bf", [] ], "document-reporting-path-absolute.https.sub.html.sub.headers": [ @@ -399600,7 +399678,7 @@ [] ], "gather.json": [ - "a01654637f14e29d3cdb69609b583e2f223cb3d7", + "acd7ad8775e6df514547ed5871d386b42b82c78a", [] ], "gemm.json": [ @@ -440662,7 +440740,7 @@ ] ], "digital-identity.https.html": [ - "8ae9caa002d061862098b30341147601da6d10e0", + "cc279735bd7b5320a3eeb530144bd7b1a9e44c69", [ null, { @@ -443826,7 +443904,7 @@ ] ], "inset-area-basic.html": [ - "b89d0e2428965172ae769c7d1ac5a5ecb17c0170", + "3ede9dcd92584b4d50a5def737826f416a209c87", [ null, {} @@ -443882,7 +443960,7 @@ ] ], "inset-area-with-insets.html": [ - "2482b443130ec9a11a4d92e08d5c180126434c4f", + "f6a4cd3665224e1d71d78773256f655b0e9309e8", [ null, {} @@ -443954,7 +444032,7 @@ ] ], "position-anchor-basics.html": [ - "f9fe9dd6f8f1ad73076536ca00e8ea5ddc37df25", + "8039903c39a571480fc9117331dfa01b0ee6354a", [ null, {} @@ -444108,7 +444186,7 @@ ] ], "property-interpolations.html": [ - "954e5642dd7499474d147447699c07b50b5a4d1d", + "ddfad852f8917a662ed1b3936f577f4f3e91acf2", [ null, {} @@ -452791,14 +452869,14 @@ ] ], "font-palette-values-invalid.html": [ - "b93a48fb37df58702d50f05fb9f745749ddb3a25", + "a3a0a88ba68c8fcc1f8b00054d7b12bc08d4b7af", [ null, {} ] ], "font-palette-values-valid.html": [ - "99fceff2344ccead12a0af0c1ab5450070311e56", + "328e9a7dbf116f11a372ef72bd436c19b917d23c", [ null, {} @@ -483287,28 +483365,28 @@ }, "required-policy": { "document-policy.html": [ - "aaa8d6920018efd0b3871cc46f201887fdaeec37", + "4beaf3f2164aaa75c05f9d2dfa2e2ace811e7ecf", [ null, {} ] ], "no-document-policy.html": [ - "8a3624440f3358381e3e51f9850dfc9285c4487f", + "00a721e8150db5d43f9d8c9b610c6c3aea84f42b", [ null, {} ] ], "required-document-policy-nested.html": [ - "33de2533a25517943a4ad7c2594d8fe03d1df485", + "0adba51c1999a283943df4f5756f2881255556c8", [ null, {} ] ], "required-document-policy.html": [ - "1058e3582abd836958ecc9d075fc18f76a77f95c", + "f710e6c8f2a28e678a5aa4346004e6cecf83faf5", [ null, {} @@ -582754,6 +582832,15 @@ } ] ], + "select-accessibility-minimum-target-size.tentative.html": [ + "364efd1554219493a5b9262c18a12317b9571037", + [ + null, + { + "testdriver": true + } + ] + ], "select-datalist-options-idl.tentative.html": [ "92eabdc5d8d341b6d4c16af3bb8b60700869daf8", [ @@ -609908,11 +609995,38 @@ } ] ], - "instance.https.html": [ - "5ccc6cd1e3a8ea01161469fefdba562ab8eea84d", + "instance.https.window.js": [ + "ba7c103048fef2111875aafb8c82eb763073c661", [ - null, - {} + "notifications/instance.https.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "/service-workers/service-worker/resources/test-helpers.sub.js" + ], + [ + "script", + "resources/helpers.js" + ], + [ + "script", + "resources/custom-data.js" + ], + [ + "script", + "instance-checks.js" + ] + ] + } ] ], "lang.https.html": [ @@ -614195,7 +614309,7 @@ ] ], "pointerevent_after_target_appended.html": [ - "712670d6479c819732825f8dad3609f9872001fe", + "a5cb82088e85a548159a8c0ab7700700fa10b4cd", [ "pointerevents/pointerevent_after_target_appended.html?mouse", { @@ -614237,7 +614351,7 @@ ] ], "pointerevent_after_target_removed.html": [ - "b63e8b92d18d11ac979a8da2b5753bc8126d3b05", + "97a1a83fc874a780f63651d1d52589d2d0dbe22e", [ "pointerevents/pointerevent_after_target_removed.html?mouse", { @@ -614422,6 +614536,15 @@ } ] ], + "pointerevent_capture_mouse_and_release_and_capture_again.html": [ + "d060338116c415b4aaf88aec07c5443b87e205da", + [ + null, + { + "testdriver": true + } + ] + ], "pointerevent_capture_suppressing_mouse.html": [ "0d7756335d1d9e7a5baf0a2f213963124d9850ef", [ @@ -614431,6 +614554,15 @@ } ] ], + "pointerevent_capture_touch_and_release_at_got_capture.html": [ + "095b67010d45db909e318207abe2bc1ca92f976f", + [ + null, + { + "testdriver": true + } + ] + ], "pointerevent_change-touch-action-onpointerdown_touch.html": [ "40dbbed72f437172bab73fde62ee487b6150b10d", [ @@ -628639,7 +628771,7 @@ ] ], "document-reporting-bypass-report-to.https.sub.html": [ - "394bc9e40a0a8b3dba5c2f176230d1e73dc0c46b", + "f599ef8511b9931fa1961cec33954254daec8fe8", [ null, {} @@ -628662,7 +628794,7 @@ ] ], "document-reporting-named-endpoints.https.sub.html": [ - "c24601147a2a2aac5dee708c9ec7a2f73594dde7", + "3e659872e05bf55d2efdeca3a6528a28f1191689", [ null, {} @@ -628676,7 +628808,7 @@ ] ], "document-reporting-override-endpoint.https.sub.html": [ - "9264786093e7a9f524727ad98a0c13b61e133bd2", + "e10f82a5e36a53b79833bde627db9cc4bc2755f2", [ null, {} @@ -634492,7 +634624,7 @@ "service-workers": { "cache-storage": { "cache-abort.https.any.js": [ - "960d1bb1bffd7dfa6ec8a35b6428baff231352e4", + "99f29b0a08bae82f4be0c0dee98ce5b31a941a48", [ "service-workers/cache-storage/cache-abort.https.any.html", { @@ -637851,7 +637983,7 @@ }, "shadow-dom": { "Document-caretPositionFromPoint.tentative.html": [ - "2b97546d2e257ce0bf2cd5275058df01e40f6eed", + "f3053ee71150932451729aeab07dc1eb2c7920a1", [ null, {} @@ -638028,6 +638160,13 @@ {} ] ], + "declarative-shadow-dom-write-to-iframe.html": [ + "ab0af5878de4d957337fb8284950571310a1bb19", + [ + null, + {} + ] + ], "declarative-with-disabled-shadow.html": [ "bcf53403addb673b609ecbc2a4299d84a701fc3e", [ @@ -682396,7 +682535,7 @@ ] ], "gather.https.any.js": [ - "184e8033e6624cfd433494d7c01f917195c5b65d", + "96082437289e87c4a98cd8c5336a2c15c33a0bc0", [ "webnn/validation_tests/gather.https.any.html", { @@ -723713,7 +723852,14 @@ ] ], "set_permission.py": [ - "18f8e6fed000fe2cc6ae04adfa0cc965b89b5edc", + "574f2149841dd69e579bebca6efaaf25b007c255", + [ + null, + {} + ] + ], + "user_context.py": [ + "b45ddb12b7e59093210dfdf55d3d9008918b0b41", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-inside-outside.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-inside-outside.html new file mode 100644 index 0000000..aefd586 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-inside-outside.html
@@ -0,0 +1,54 @@ +<!DOCTYPE html> +<title>CSS Anchor Positioning: anchor(inside/outside)</title> +<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#valdef-anchor-inside"> +<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#valdef-anchor-outside"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<style> + #cb { + position: relative; + width: 400px; + height: 400px; + border: 1px solid black; + } + #anchor { + position: absolute; + top: 250px; + left: 150px; + background-color: skyblue; + width: 50px; + height: 50px; + anchor-name: --a; + } + .target { + position: absolute; + position-anchor: --a; + background-color: tomato; + width: 10px; + height: 10px; + } +</style> +<div id=cb> + <div id=anchor></div> + <div class=target style="left:anchor(inside)" data-offset-x=150></div> + <div class=target style="left:anchor(outside)" data-offset-x=200></div> + <div class=target style="right:anchor(inside)" data-offset-x=190></div> + <div class=target style="right:anchor(outside)" data-offset-x=140></div> + <div class=target style="top:anchor(inside)" data-offset-y=250></div> + <div class=target style="top:anchor(outside)" data-offset-y=300></div> + <div class=target style="bottom:anchor(inside)" data-offset-y=290></div> + <div class=target style="bottom:anchor(outside)" data-offset-y=240></div> + <!-- Logical --> + <div class=target style="inset-inline-start:anchor(inside)" data-offset-x=150></div> + <div class=target style="inset-inline-start:anchor(outside)" data-offset-x=200></div> + <div class=target style="inset-inline-end:anchor(inside)" data-offset-x=190></div> + <div class=target style="inset-inline-end:anchor(outside)" data-offset-x=140></div> + <div class=target style="inset-block-start:anchor(inside)" data-offset-y=250></div> + <div class=target style="inset-block-start:anchor(outside)" data-offset-y=300></div> + <div class=target style="inset-block-end:anchor(inside)" data-offset-y=290></div> + <div class=target style="inset-block-end:anchor(outside)" data-offset-y=240></div> +</div> +<script> + addEventListener('load', () => checkLayout('.target')); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-parse-valid.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-parse-valid.html index 4690775..f3069649 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-parse-valid.html +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-parse-valid.html
@@ -24,6 +24,8 @@ ]; const anchorSides = [ + 'inside', + 'outside', 'left', 'right', 'top',
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html index b93a48fb..a3a0a88 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html +++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-invalid.html
@@ -135,13 +135,18 @@ @font-palette-values --A { override-colors: 0 light-dark(white, currentcolor); } + +/* 23 */ +@font-palette-values --A { + override-colors: 0 color-mix(in lch, red, color-mix(in lch, currentcolor, black)); +} </style> </head> <body> <script> let rules = document.getElementById("style").sheet.cssRules; test(function() { - assert_equals(rules.length, 23); + assert_equals(rules.length, 24); }); test(function() { @@ -331,6 +336,13 @@ assert_equals(text.indexOf("override-colors"), -1); assert_equals(rule.overrideColors, ""); }); + +test(function() { + let text = rules[23].cssText; + let rule = rules[23]; + assert_equals(text.indexOf("override-colors"), -1); + assert_equals(rule.overrideColors, ""); +}); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html index 99fceff2..328e9a7d 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html +++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/parsing/font-palette-values-valid.html
@@ -108,6 +108,11 @@ @font-palette-values --Q { override-colors: 0 color-mix(in lch, red, blue); } + +/* 18 */ +@font-palette-values --R { + override-colors: 0 color-mix(in lch, color-mix(in lch, red, blue), color-mix(in lch, green, white)); +} </style> </head> <body> @@ -398,6 +403,14 @@ assert_equals(rule.basePalette, ""); assert_equals(rule.overrideColors, "0 color-mix(in lch, red, blue)"); }); + +test(function() { + let rule = rules[18]; + assert_equals(rule.name, "--R"); + assert_equals(rule.fontFamily, ""); + assert_equals(rule.basePalette, ""); + assert_equals(rule.overrideColors, "0 color-mix(in lch, color-mix(in lch, red, blue), color-mix(in lch, green, white))"); +}); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/notifications/getnotifications-sw.js b/third_party/blink/web_tests/external/wpt/notifications/getnotifications-sw.js index 331913b9..ad2c11c 100644 --- a/third_party/blink/web_tests/external/wpt/notifications/getnotifications-sw.js +++ b/third_party/blink/web_tests/external/wpt/notifications/getnotifications-sw.js
@@ -1,4 +1,5 @@ importScripts("/resources/testharness.js"); +importScripts("resources/helpers.js"); async function cleanup() { for (const n of await registration.getNotifications()) { @@ -29,14 +30,9 @@ } } -async function untilActivate() { - if (registration.active) { - return; - } - return new Promise(resolve => { - addEventListener("activate", resolve, { once: true }); - }); -} +promise_setup(async () => { + await untilActivate(); +}); promise_test(async t => { await new Promise((resolve, reject) => { @@ -45,7 +41,7 @@ resolve(); } }); - untilActivate().then(() => postAll("notification-create")).catch(reject); + postAll("notification-create").catch(reject); }); await test_notification(t, "Created from window"); }, "Get notification created from window");
diff --git a/third_party/blink/web_tests/external/wpt/notifications/instance-checks.js b/third_party/blink/web_tests/external/wpt/notifications/instance-checks.js new file mode 100644 index 0000000..31ff0b87 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/notifications/instance-checks.js
@@ -0,0 +1,40 @@ +const notification_args = [ + "Radio check", + { + dir: "ltr", + lang: "aa", + body: "This is a radio check.", + tag: "radio_check999", + icon: `${location.origin}/icon.png`, + data: fakeCustomData, + } +]; + +// promise_tests because we need to wait for promise_setup +function notification_instance_test(createFn, testTitle) { + let n; + promise_test(async t => { + n = await createFn(t); + }, `${testTitle}: Setup`); + promise_test(async () => { + assert_equals("Radio check", n.title) + }, `${testTitle}: Attribute exists with expected value: title`) + promise_test(async () => { + assert_equals("ltr", n.dir) + }, `${testTitle}: Attribute exists with expected value: dir`) + promise_test(async () => { + assert_equals("aa", n.lang) + }, `${testTitle}: Attribute exists with expected value: lang`) + promise_test(async () => { + assert_equals("This is a radio check.", n.body) + }, `${testTitle}: Attribute exists with expected value: body`) + promise_test(async () => { + assert_equals("radio_check999", n.tag) + }, `${testTitle}: Attribute exists with expected value: tag`) + promise_test(async () => { + assert_equals(`${location.origin}/icon.png`, n.icon) + }, `${testTitle}: Attribute exists with expected value: icon`) + promise_test(async () => { + assert_custom_data(n.data); + }, `${testTitle}: Attribute exists with expected value: data`) +}
diff --git a/third_party/blink/web_tests/external/wpt/notifications/instance-sw.js b/third_party/blink/web_tests/external/wpt/notifications/instance-sw.js new file mode 100644 index 0000000..f08b17e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/notifications/instance-sw.js
@@ -0,0 +1,34 @@ +importScripts("/resources/testharness.js"); +importScripts("resources/helpers.js"); +importScripts("resources/custom-data.js"); +importScripts("instance-checks.js"); + +promise_setup(async () => { + await untilActivate(); +}); + +notification_instance_test(async t => { + t.add_cleanup(closeAllNotifications); + + await registration.showNotification(...notification_args); + + let notifications = await registration.getNotifications(); + assert_equals(notifications.length, 1, "The list should include one notification"); + + return notifications[0]; +}, "getNotifications()"); + +// Doing this separately because this times out on Blink and GeckoView +notification_instance_test(async t => { + t.add_cleanup(closeAllNotifications); + + await registration.showNotification(...notification_args); + + let notifications = await registration.getNotifications(); + assert_equals(notifications.length, 1, "The list should include one notification"); + + notifications[0].close(); + const ev = await new Promise(resolve => addEventListener("notificationclose", resolve, { once: true })); + + return ev.notification; +}, "notificationclose");
diff --git a/third_party/blink/web_tests/external/wpt/notifications/instance.https.html b/third_party/blink/web_tests/external/wpt/notifications/instance.https.html deleted file mode 100644 index 5ccc6cd..0000000 --- a/third_party/blink/web_tests/external/wpt/notifications/instance.https.html +++ /dev/null
@@ -1,60 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Notification instance basic tests</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="resources/custom-data.js"></script> -<script> -var n = new Notification("Radio check", - { - dir: "ltr", - lang: "aa", - body: "This is a radio check.", - tag: "radio_check999", - icon: "http://example.com/icon.png", - data: fakeCustomData, - } -) -n.onshow = function() { - n.close() -} -test(function() { - assert_true(n instanceof Notification) -},"Notification instance exists.") -test(function() { - assert_true("close" in n) -},"Attribute exists: close") -test(function() { - assert_true("onclick" in n) -},"Attribute exists: onclick") -test(function() { - assert_true("onshow" in n) -},"Attribute exists: onshow") -test(function() { - assert_true("onerror" in n) -},"Attribute exists: onerror") -test(function() { - assert_true("onclose" in n) -},"Attribute exists: onclose") -test(function() { - assert_equals("Radio check", n.title) -},"Attribute exists with expected value: title") -test(function() { - assert_equals("ltr", n.dir) -},"Attribute exists with expected value: dir") -test(function() { - assert_equals("aa", n.lang) -},"Attribute exists with expected value: lang") -test(function() { - assert_equals("This is a radio check.", n.body) -},"Attribute exists with expected value: body") -test(function() { - assert_equals("radio_check999", n.tag) -},"Attribute exists with expected value: tag") -test(function() { - assert_equals("http://example.com/icon.png", n.icon) -},"Attribute exists with expected value: icon") -test(function() { - assert_custom_data(n.data); -},"Attribute exists with expected value: data") -</script>
diff --git a/third_party/blink/web_tests/external/wpt/notifications/instance.https.window.js b/third_party/blink/web_tests/external/wpt/notifications/instance.https.window.js new file mode 100644 index 0000000..ba7c103 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/notifications/instance.https.window.js
@@ -0,0 +1,18 @@ +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=/service-workers/service-worker/resources/test-helpers.sub.js +// META: script=resources/helpers.js +// META: script=resources/custom-data.js +// META: script=instance-checks.js + +promise_setup(async () => { + await trySettingPermission("granted"); +}); + +notification_instance_test(() => { + const n = new Notification(...notification_args); + n.close(); + return n; +}, "new Notification()"); + +service_worker_test("instance-sw.js", "Service worker test setup");
diff --git a/third_party/blink/web_tests/external/wpt/notifications/resources/custom-data.js b/third_party/blink/web_tests/external/wpt/notifications/resources/custom-data.js index b21d28a..49a5c60d 100644 --- a/third_party/blink/web_tests/external/wpt/notifications/resources/custom-data.js +++ b/third_party/blink/web_tests/external/wpt/notifications/resources/custom-data.js
@@ -1,8 +1,7 @@ var fakeCustomData = (function() { var buffer = new ArrayBuffer(2); new DataView(buffer).setInt16(0, 42, true); - var canvas = document.createElement("canvas"); - canvas.width = canvas.height = 100; + var canvas = new OffscreenCanvas(100, 100); var context = canvas.getContext("2d"); var map = new Map();
diff --git a/third_party/blink/web_tests/external/wpt/notifications/resources/helpers.js b/third_party/blink/web_tests/external/wpt/notifications/resources/helpers.js index ca44e32..6b418be 100644 --- a/third_party/blink/web_tests/external/wpt/notifications/resources/helpers.js +++ b/third_party/blink/web_tests/external/wpt/notifications/resources/helpers.js
@@ -33,3 +33,13 @@ throw new Error(`Should have the permission ${perm} to continue`); } } + +// Use this in service workers where activation is required e.g. when testing showNotification() +async function untilActivate() { + if (registration.active) { + return; + } + return new Promise(resolve => { + addEventListener("activate", resolve, { once: true }); + }); +}
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_after_target_appended.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_after_target_appended.html index 712670d6..a5cb820 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_after_target_appended.html +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_after_target_appended.html
@@ -158,15 +158,29 @@ setup(); + const hoverable = pointer_type != "touch"; + // Tests for dispatched pointer events. - addPromiseTestForNewChild("pointerdown", "pointer", [ - "pointerover@parent", "pointerenter@parent", - "pointerdown@parent", "(child-attached)", - "pointerout@parent", "pointerover@child", "pointerenter@child", - "pointerup@child", - "pointerdown@child", "pointerup@child", - "pointerout@child", "pointerleave@child", "pointerleave@parent" - ]); + addPromiseTestForNewChild( + "pointerdown", + "pointer", + hoverable + ? ["pointerover@parent", "pointerenter@parent", + "pointerdown@parent", "(child-attached)", + "pointerout@parent", "pointerover@child", "pointerenter@child", + "pointerup@child", + "pointerdown@child", "pointerup@child", + "pointerout@child", "pointerleave@child", "pointerleave@parent"] + : ["pointerover@parent", "pointerenter@parent", + "pointerdown@parent", "(child-attached)", + // pointerup should imply a pointermove over the attached child. + "pointerout@parent", "pointerover@child", "pointerenter@child", + // pointerup should cause pointerout/pointerleave if the input source is not hoverable. + "pointerup@child", "pointerout@child", "pointerleave@child", "pointerleave@parent", + // then, pointerdown should imply a pointermove again. + "pointerover@child", "pointerenter@child", "pointerenter@parent", "pointerdown@child", + "pointerup@child", "pointerout@child", "pointerleave@child", "pointerleave@parent"] + ); addPromiseTestForNewChild("pointerup", "pointer", [ "pointerover@parent", "pointerenter@parent", "pointerdown@parent", "pointerup@parent", "(child-attached)",
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_after_target_removed.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_after_target_removed.html index b63e8b9..97a1a83 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_after_target_removed.html +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_after_target_removed.html
@@ -104,19 +104,43 @@ setup(); + const hoverable = pointer_type != "touch"; + // Tests for dispatched pointer events. - addPromiseTest("pointerdown", "pointer", [ - "pointerover@child", "pointerenter@parent", "pointerenter@child", - "pointerdown@child", "(child-removed)", "pointerover@parent", "pointerup@parent", - "pointerdown@parent", "pointerup@parent", - "pointerout@parent", "pointerleave@parent" - ]); - addPromiseTest("pointerup", "pointer", [ - "pointerover@child", "pointerenter@parent", "pointerenter@child", - "pointerdown@child", "pointerup@child", "(child-removed)", - "pointerover@parent", "pointerdown@parent", "pointerup@parent", - "pointerout@parent", "pointerleave@parent" - ]); + addPromiseTest( + "pointerdown", + "pointer", + hoverable + ? ["pointerover@child", "pointerenter@parent", "pointerenter@child", + "pointerdown@child", "(child-removed)", "pointerover@parent", "pointerup@parent", + "pointerdown@parent", "pointerup@parent", + "pointerout@parent", "pointerleave@parent"] + : ["pointerover@child", "pointerenter@parent", "pointerenter@child", "pointerdown@child", + "(child-removed)", "pointerover@parent", + // pointerup should cause pointerout/pointerleave if the input source is not hoverable. + "pointerup@parent", "pointerout@parent", "pointerleave@parent", + // then, pointerdown should imply a pointermove again. + "pointerover@parent", "pointerenter@parent", "pointerdown@parent", + "pointerup@parent", "pointerout@parent", "pointerleave@parent"] + ); + addPromiseTest( + "pointerup", + "pointer", + hoverable + ? ["pointerover@child", "pointerenter@parent", "pointerenter@child", + "pointerdown@child", "pointerup@child", "(child-removed)", + "pointerover@parent", "pointerdown@parent", "pointerup@parent", + "pointerout@parent", "pointerleave@parent"] + : ["pointerover@child", "pointerenter@parent", "pointerenter@child", + "pointerdown@child", "pointerup@child", "(child-removed)", + // only pointerleave should be fired if the input source is not hoverable + // because pointerup removed the pointerout event target which is not + // received pointerover event, but the pointer becomes invalid. + "pointerleave@parent", + // then, pointerdown should imply a pointermove again. + "pointerover@parent", "pointerenter@parent", "pointerdown@parent", "pointerup@parent", + "pointerout@parent", "pointerleave@parent"] + ); // Same tests for dispatched compatibility mouse events. addPromiseTest("mousedown", "mouse", [
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_mouse_and_release_and_capture_again.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_mouse_and_release_and_capture_again.html new file mode 100644 index 0000000..d060338 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_mouse_and_release_and_capture_again.html
@@ -0,0 +1,90 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<title>Testing pointer events for mouse when capturing the pointer with different element from the pointerdown target and +release it at got capture and capture it again at lost the first capture</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script> +"use strict"; + +addEventListener("load", () => { + promise_test(async () => { + const listener = document.getElementById("listener"); + const target = document.getElementById("target"); + let events = []; + function logEvent(event) { + events.push({ + type: event.type, + target: event.target, + pointerType: event.pointerType, + }); + } + function stringifyEvents(events) { + if (!events.length) { + return "[]"; + } + let result = ""; + for (const event of events) { + if (result == "") { + result = "["; + } else { + result += ", "; + } + result += `${event.type}@${ + event.target.id ? event.target.id : event.target.localName + }(pointerType=${event.pointerType})`; + } + result += "]"; + return result; + } + target.addEventListener("pointerdown", event => { + logEvent(event); + listener.setPointerCapture(event.pointerId); + }); + listener.addEventListener("gotpointercapture", event => { + logEvent(event); + listener.releasePointerCapture(event.pointerId); + }); + listener.addEventListener("lostpointercapture", event => { + logEvent(event); + listener.setPointerCapture(event.pointerId); + }); + listener.addEventListener("pointerover", logEvent); + listener.addEventListener("pointermove", logEvent); + listener.addEventListener("pointerup", logEvent); + listener.addEventListener("pointerout", logEvent); + + await new test_driver.Actions() + .pointerMove(0, 0, {origin: target}) + .pointerDown() + .pointerMove(1, 1, {origin: target}) + .pointerUp() + .send(); + + const expectedEvents = [ + {type: "pointerdown", target: target, pointerType: "mouse"}, + {type: "pointerover", target: listener, pointerType: "mouse"}, + {type: "gotpointercapture", target: listener, pointerType: "mouse"}, + {type: "pointermove", target: listener, pointerType: "mouse"}, + {type: "lostpointercapture", target: listener, pointerType: "mouse"}, + // The pointer is over the target, not over the listener. Therefore, + // when the listener loses the capture, pointerout should be fired on + // the listener since it won't receive pointer events until the pointer + // moves over the listener. + {type: "pointerout", target: listener, pointerType: "mouse"}, + ]; + assert_equals(stringifyEvents(events), stringifyEvents(expectedEvents)); + }, "A pointerout should be fired on the capturing element after losing the capture"); +}, {once: true}); +</script> +</head> +<body> + <div id="listener">div id=listener</div> + <div id="target">div id=target</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_touch_and_release_at_got_capture.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_touch_and_release_at_got_capture.html new file mode 100644 index 0000000..095b670 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_touch_and_release_at_got_capture.html
@@ -0,0 +1,88 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<title>Testing pointer events for touch when capturing the pointer with different element from the pointerdown target and release it at got pointer capture</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script> +"use strict"; + +addEventListener("load", () => { + promise_test(async () => { + const listener = document.getElementById("listener"); + const target = document.getElementById("target"); + let events = []; + function logEvent(event) { + events.push({ + type: event.type, + target: event.target, + pointerType: event.pointerType, + isPrimary: event.isPrimary, + }); + } + function stringifyEvents(events) { + if (!events.length) { + return "[]"; + } + let result = ""; + for (const event of events) { + if (result == "") { + result = "["; + } else { + result += ", "; + } + result += `${event.type}@${ + event.target.id ? event.target.id : event.target.localName + }(pointerType=${event.pointerType},isPrimary=${event.isPrimary})`; + } + result += "]"; + return result; + } + target.addEventListener("pointerdown", event => { + logEvent(event); + listener.setPointerCapture(event.pointerId); + }); + listener.addEventListener("gotpointercapture", event => { + logEvent(event); + listener.releasePointerCapture(event.pointerId); + }); + listener.addEventListener("lostpointercapture", logEvent); + listener.addEventListener("pointerover", logEvent); + listener.addEventListener("pointermove", logEvent); + listener.addEventListener("pointerup", logEvent); + listener.addEventListener("pointerout", logEvent); + + await new test_driver.Actions() + .addPointer("touch_pointer", "touch") + .pointerMove(0, 0, {origin: target}) + .pointerDown() + .pointerMove(1, 1, {origin: target}) + .pointerUp() + .send(); + + const expectedEvents = [ + {type: "pointerdown", target: target, pointerType: "touch", isPrimary: true}, + {type: "pointerover", target: listener, pointerType: "touch", isPrimary: true}, + {type: "gotpointercapture", target: listener, pointerType: "touch", isPrimary: true}, + {type: "pointermove", target: listener, pointerType: "touch", isPrimary: true}, + {type: "lostpointercapture", target: listener, pointerType: "touch", isPrimary: true}, + // The pointer is over the target, not over the listener. Therefore, + // when the listener loses the capture, pointerout should be fired on + // the listener since it won't receive pointer events until the pointer + // moves over the listener. + {type: "pointerout", target: listener, pointerType: "touch", isPrimary: true}, + ]; + assert_equals(stringifyEvents(events), stringifyEvents(expectedEvents)); + }, "A pointerout should be fired on the capturing element after losing the capture"); +}, {once: true}); +</script> +</head> +<body> + <div id="listener">div id=listener</div> + <div id="target">div id=target</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/declarative-shadow-dom-write-to-iframe.html b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/declarative-shadow-dom-write-to-iframe.html new file mode 100644 index 0000000..ab0af58 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/declarative-shadow-dom-write-to-iframe.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>`document.write` on inner iframe handles declarative shadow DOM</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<iframe></iframe> +<script> +promise_test(async () => { + await new Promise(res => window.addEventListener("load", res)); + let elem = document.querySelector("iframe"); + elem.contentDocument.write(` + <div> + <template shadowrootmode="open"><slot></slot></template> + <p>Test</p> + </div> + `); + let container = elem.contentDocument.querySelector("div"); + assert_true(!!container, "write should occur"); + assert_true(!!container.shadowRoot, "write should create shadowroot"); + assert_equals(container.innerText, "Test", "div should still contain text"); +}, "`document.write` on inner iframe handles declarative shadow DOM"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-drawImage-hbd.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-drawImage-hbd.any.js new file mode 100644 index 0000000..f03fce7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-drawImage-hbd.any.js
@@ -0,0 +1,31 @@ +// META: global=window,dedicatedworker +// META: script=/webcodecs/utils.js + +test(_ => { + let width = 48; + let height = 36; + let expectedPixel = kSRGBPixel; + let canvasOptions = undefined; + let imageSetting = undefined; + let tolerance = 5; + let vfInit = + {format: 'I420P10', timestamp: 0, codedWidth: width, codedHeight: height}; + let data = new Uint16Array(3 * width * height / 2); + let uOffset = width * height; + let vOffset = uOffset + width * height / 4; + // RGB(50, 100, 150) converted to 8-bit YCbCr using BT.709 YUV matrix, then + // shifted to produce approximate 10-bit YUV colors. It would be more accurate + // to directly compute 10-bit colors. + data.fill(96 << 2, 0, uOffset); + data.fill(155 << 2, uOffset, vOffset); + data.fill(104 << 2, vOffset); + let frame = new VideoFrame(data, vfInit); + let canvas = new OffscreenCanvas(width, height); + let ctx = canvas.getContext('2d', canvasOptions); + ctx.drawImage(frame, 0, 0); + testCanvas(ctx, width, height, expectedPixel, imageSetting, + (actual, expected) => { + assert_approx_equals(actual, expected, tolerance); + }); + frame.close(); +}, 'drawImage with 10-bit YUV VideoFrame');
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/external/permissions/set_permission/set_permission.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/external/permissions/set_permission/set_permission.py index 18f8e6f..574f21498 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/external/permissions/set_permission/set_permission.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/external/permissions/set_permission/set_permission.py
@@ -100,41 +100,3 @@ origin=origin, ) assert await get_permission_state(bidi_session, new_tab, "geolocation") == "prompt" - - -@pytest.mark.asyncio -async def test_set_permission_user_context(bidi_session, new_tab, url, create_user_context): - test_url = url("/common/blank.html", protocol="https") - - user_context = await create_user_context() - # new_tab is in the default user context. new_tab2 is in the non-default user context. - new_tab2 = await bidi_session.browsing_context.create(type_hint="tab", user_context=user_context) - - # Navigate a context in the default user context. - await bidi_session.browsing_context.navigate( - context=new_tab["context"], - url=test_url, - wait="complete", - ) - - # Navigate a context in the non-default user context. - await bidi_session.browsing_context.navigate( - context=new_tab2["context"], - url=test_url, - wait="complete", - ) - - origin = await get_context_origin(bidi_session, new_tab) - - assert await get_permission_state(bidi_session, new_tab, "geolocation") == "prompt" - assert await get_permission_state(bidi_session, new_tab2, "geolocation") == "prompt" - - await bidi_session.permissions.set_permission( - descriptor={"name": "geolocation"}, - state="granted", - origin=origin, - user_context=user_context, - ) - - assert await get_permission_state(bidi_session, new_tab, "geolocation") == "prompt" - assert await get_permission_state(bidi_session, new_tab2, "geolocation") == "granted"
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/external/permissions/set_permission/user_context.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/external/permissions/set_permission/user_context.py new file mode 100644 index 0000000..b45ddb1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/external/permissions/set_permission/user_context.py
@@ -0,0 +1,131 @@ +import pytest + +from . import get_context_origin, get_permission_state + +pytestmark = pytest.mark.asyncio + + +async def test_set_permission_user_context( + bidi_session, new_tab, url, create_user_context +): + test_url = url("/common/blank.html", protocol="https", domain="alt") + + user_context = await create_user_context() + # new_tab is in the default user context. new_tab2 is in the non-default user context. + new_tab2 = await bidi_session.browsing_context.create( + type_hint="tab", user_context=user_context + ) + + # Navigate a context in the default user context. + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=test_url, + wait="complete", + ) + + # Navigate a context in the non-default user context. + await bidi_session.browsing_context.navigate( + context=new_tab2["context"], + url=test_url, + wait="complete", + ) + + origin = await get_context_origin(bidi_session, new_tab) + + assert await get_permission_state(bidi_session, new_tab, "geolocation") == "prompt" + assert await get_permission_state(bidi_session, new_tab2, "geolocation") == "prompt" + + await bidi_session.permissions.set_permission( + descriptor={"name": "geolocation"}, + state="granted", + origin=origin, + user_context=user_context, + ) + + assert await get_permission_state(bidi_session, new_tab, "geolocation") == "prompt" + assert ( + await get_permission_state(bidi_session, new_tab2, "geolocation") == "granted" + ) + + # Create another tab in the non-default user context + new_tab3 = await bidi_session.browsing_context.create( + type_hint="tab", user_context=user_context + ) + await bidi_session.browsing_context.navigate( + context=new_tab3["context"], + url=test_url, + wait="complete", + ) + + # Make sure that the permission state is still present. + assert ( + await get_permission_state(bidi_session, new_tab3, "geolocation") == "granted" + ) + + +async def test_set_permission_with_reload(bidi_session, url, create_user_context): + user_context = await create_user_context() + new_tab = await bidi_session.browsing_context.create( + type_hint="tab", user_context=user_context + ) + + test_url = url("/common/blank.html", protocol="https") + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=test_url, + wait="complete", + ) + + origin = await get_context_origin(bidi_session, new_tab) + + await bidi_session.permissions.set_permission( + descriptor={"name": "geolocation"}, + state="granted", + origin=origin, + user_context=user_context, + ) + + assert await get_permission_state(bidi_session, new_tab, "geolocation") == "granted" + + await bidi_session.browsing_context.reload( + context=new_tab["context"], + wait="complete", + ) + + # Make sure that permission state is still set. + assert await get_permission_state(bidi_session, new_tab, "geolocation") == "granted" + + +async def test_reset_permission(bidi_session, url, create_user_context): + test_url = url("/common/blank.html", protocol="https") + + user_context = await create_user_context() + new_tab = await bidi_session.browsing_context.create( + type_hint="tab", user_context=user_context + ) + + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=test_url, + wait="complete", + ) + + origin = await get_context_origin(bidi_session, new_tab) + + await bidi_session.permissions.set_permission( + descriptor={"name": "geolocation"}, + state="granted", + origin=origin, + user_context=user_context, + ) + + assert await get_permission_state(bidi_session, new_tab, "geolocation") == "granted" + + # Reset the permission state + await bidi_session.permissions.set_permission( + descriptor={"name": "geolocation"}, + state="prompt", + origin=origin, + user_context=user_context, + ) + assert await get_permission_state(bidi_session, new_tab, "geolocation") == "prompt"
diff --git a/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/gather.json b/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/gather.json index acd7ad87..a0165463 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/gather.json +++ b/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/gather.json
@@ -51,56 +51,6 @@ } }, { - "name": "gather float32 1D tensor and int32 0D scalar indices default options", - "inputs": { - "input": { - "shape": [24], - "data": [ - -66.05901336669922, - -68.9197006225586, - -77.02045440673828, - -26.158037185668945, - 89.0337142944336, - -45.89653396606445, - 43.84803771972656, - 48.81806945800781, - 51.79948425292969, - 41.94132614135742, - -1.1303654909133911, - -50.42131042480469, - 90.2870101928711, - 55.620765686035156, - 44.92119598388672, - 56.828636169433594, - 10.829925537109375, - -19.693084716796875, - -37.696800231933594, - 43.11057662963867, - 0.9129875898361206, - -7.699817180633545, - 25.76774024963379, - 73.60064697265625 - ], - "type": "float32" - }, - "indices": { - "shape": [], - "data": [ - 4 - ], - "type": "int32" - } - }, - "expected": { - "name": "output", - "shape": [], - "data": [ - 89.0337142944336 - ], - "type": "float32" - } - }, - { "name": "gather float32 1D tensor and int64 0D scalar indices default options", "inputs": { "input": {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/gather.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/gather.https.any.js index 9608243..184e803 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/gather.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/gather.https.any.js
@@ -8,7 +8,7 @@ { name: '[gather] Test gather with default options and 0-D indices', input: {dataType: 'int32', dimensions: [3]}, - indices: {dataType: 'int64', dimensions: []}, + indices: {dataType: 'uint64', dimensions: []}, output: {dataType: 'int32', dimensions: []} }, {
diff --git a/third_party/chromite b/third_party/chromite index 5ff757e..8d0f67b 160000 --- a/third_party/chromite +++ b/third_party/chromite
@@ -1 +1 @@ -Subproject commit 5ff757e963883d28db6d5b9856e5c7fcc63cdcb0 +Subproject commit 8d0f67b603baecf2da3e1ad830062e356430f5ab
diff --git a/third_party/chromium-variations b/third_party/chromium-variations index 83915e3..c90f785 160000 --- a/third_party/chromium-variations +++ b/third_party/chromium-variations
@@ -1 +1 @@ -Subproject commit 83915e39be4ead9df32167feafc7c2639d603d5a +Subproject commit c90f785907da5911ca61f1116990ad6a7fdb6f67
diff --git a/third_party/crabbyavif/BUILD.gn b/third_party/crabbyavif/BUILD.gn index b2b3c12..14a5813d 100644 --- a/third_party/crabbyavif/BUILD.gn +++ b/third_party/crabbyavif/BUILD.gn
@@ -133,7 +133,6 @@ "src/src/capi/mod.rs", "src/src/capi/reformat.rs", "src/src/capi/types.rs", - "src/src/capi/utils.rs", "src/src/codecs/dav1d.rs", "src/src/codecs/mod.rs", "src/src/decoder/gainmap.rs",
diff --git a/third_party/crabbyavif/src b/third_party/crabbyavif/src index ef17807..2a37e62 160000 --- a/third_party/crabbyavif/src +++ b/third_party/crabbyavif/src
@@ -1 +1 @@ -Subproject commit ef17807890f60bee1398a752d53204c369076aca +Subproject commit 2a37e62739815ac00d1195e88135e8b1e5f38c87
diff --git a/third_party/dawn b/third_party/dawn index d4d6d18a..724dd785 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit d4d6d18aec677d0e43edac057c0595ed3973f4b7 +Subproject commit 724dd7855543eb1d4c75c517de7b576b092bfd7f
diff --git a/third_party/depot_tools b/third_party/depot_tools index 274689c..e0038c0 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit 274689c4a55104b92bf66248d03249ce0175aa02 +Subproject commit e0038c0721935fc3d8119e02c19553f2fee8f8fd
diff --git a/third_party/jni_zero/jni_zero.h b/third_party/jni_zero/jni_zero.h index 2827f95..3461850 100644 --- a/third_party/jni_zero/jni_zero.h +++ b/third_party/jni_zero/jni_zero.h
@@ -750,7 +750,7 @@ template <typename T> concept IsObjectContainer = - IsContainer<T> && !std::integral<typename T::value_type>; + IsContainer<T> && !std::is_arithmetic_v<typename T::value_type>; } // namespace internal // Partial specialization for converting java arrays into std containers
diff --git a/third_party/jni_zero/test/sample_for_tests.cc b/third_party/jni_zero/test/sample_for_tests.cc index c332f48e..5841ffb 100644 --- a/third_party/jni_zero/test/sample_for_tests.cc +++ b/third_party/jni_zero/test/sample_for_tests.cc
@@ -17,6 +17,7 @@ namespace jni_zero::internal { static_assert(IsContainer<std::vector<std::string>>); static_assert(!IsObjectContainer<std::vector<char>>); +static_assert(!IsObjectContainer<std::vector<float>>); static_assert(!IsObjectContainer<std::string>); static_assert(IsObjectContainer<std::vector<std::string>>); static_assert(IsObjectContainer<std::vector<std::string*>>);
diff --git a/third_party/lit/v3_0/BUILD.gn b/third_party/lit/v3_0/BUILD.gn index 850660b..0167d6f 100644 --- a/third_party/lit/v3_0/BUILD.gn +++ b/third_party/lit/v3_0/BUILD.gn
@@ -19,6 +19,7 @@ # - a few chrome/browser/resources/ folders that hold small UIs. # Update when the migration enters its next phase. "//chrome/browser/resources/side_panel/customize_chrome:build_ts", + "//chrome/browser/resources/side_panel/history_clusters:build_ts", "//chrome/browser/resources/side_panel/reading_list:build_ts", "//chrome/browser/resources/side_panel/shared:build_ts", "//chrome/browser/resources/welcome:build_ts",
diff --git a/third_party/openscreen/src b/third_party/openscreen/src index 6a097c7..a74a035 160000 --- a/third_party/openscreen/src +++ b/third_party/openscreen/src
@@ -1 +1 @@ -Subproject commit 6a097c705fc4bb3d79bcb4a45f71b7a198ba40f8 +Subproject commit a74a035f778762b1c31ae1e9393eefdbf07be714
diff --git a/third_party/pdfium b/third_party/pdfium index 547d961..f98c54d 160000 --- a/third_party/pdfium +++ b/third_party/pdfium
@@ -1 +1 @@ -Subproject commit 547d96118caf46c07b3e520a971992b6909696bd +Subproject commit f98c54df162cd2a9324dad9e5b9453425311527d
diff --git a/third_party/perfetto b/third_party/perfetto index 3f851ca..e03af0c 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit 3f851caa743d632b338f79ee30e9ae2929eed22d +Subproject commit e03af0caee1bf0b7ece55e42e607d738f65f9c7b
diff --git a/third_party/polymer/v3_0/BUILD.gn b/third_party/polymer/v3_0/BUILD.gn index bbf2c65..b6d6d2e 100644 --- a/third_party/polymer/v3_0/BUILD.gn +++ b/third_party/polymer/v3_0/BUILD.gn
@@ -137,8 +137,6 @@ "//chrome/browser/resources/settings_shared:build_ts", "//chrome/browser/resources/side_panel/bookmarks:build_ts", "//chrome/browser/resources/side_panel/commerce:build_ts", - "//chrome/browser/resources/side_panel/customize_chrome:build_ts", - "//chrome/browser/resources/side_panel/history_clusters:build_ts", "//chrome/browser/resources/side_panel/performance_controls:build_ts", "//chrome/browser/resources/side_panel/read_anything:build_ts", "//chrome/browser/resources/side_panel/shared:build_ts",
diff --git a/third_party/robolectric/3pp/fetch.py b/third_party/robolectric/3pp/fetch.py index 647c9e6..14e0c55 100755 --- a/third_party/robolectric/3pp/fetch.py +++ b/third_party/robolectric/3pp/fetch.py
@@ -38,33 +38,6 @@ 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/6.0.1_r3-robolectric-r1-i6/android-all-instrumented-6.0.1_r3-robolectric-r1-i6.jar', 'android-all-instrumented-5.0.2_r3-robolectric-r0-i6.jar': 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/5.0.2_r3-robolectric-r0-i6/android-all-instrumented-5.0.2_r3-robolectric-r0-i6.jar', - # i4 versions left in until migration to robolectric 4.12.1 is complete. - 'android-all-instrumented-14-robolectric-10818077-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/14-robolectric-10818077-i4/android-all-instrumented-14-robolectric-10818077-i4.jar', - 'android-all-instrumented-13-robolectric-9030017-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/13-robolectric-9030017-i4/android-all-instrumented-13-robolectric-9030017-i4.jar', - 'android-all-instrumented-12.1-robolectric-8229987-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/12.1-robolectric-8229987-i4/android-all-instrumented-12.1-robolectric-8229987-i4.jar', - 'android-all-instrumented-12-robolectric-7732740-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/12-robolectric-7732740-i4/android-all-instrumented-12-robolectric-7732740-i4.jar', - 'android-all-instrumented-11-robolectric-6757853-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/11-robolectric-6757853-i4/android-all-instrumented-11-robolectric-6757853-i4.jar', - 'android-all-instrumented-10-robolectric-5803371-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/10-robolectric-5803371-i4/android-all-instrumented-10-robolectric-5803371-i4.jar', - 'android-all-instrumented-9-robolectric-4913185-2-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/9-robolectric-4913185-2-i4/android-all-instrumented-9-robolectric-4913185-2-i4.jar', - 'android-all-instrumented-8.1.0-robolectric-4611349-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/8.1.0-robolectric-4611349-i4/android-all-instrumented-8.1.0-robolectric-4611349-i4.jar', - 'android-all-instrumented-8.0.0_r4-robolectric-r1-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/8.0.0_r4-robolectric-r1-i4/android-all-instrumented-8.0.0_r4-robolectric-r1-i4.jar', - 'android-all-instrumented-7.1.0_r7-robolectric-r1-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/7.1.0_r7-robolectric-r1-i4/android-all-instrumented-7.1.0_r7-robolectric-r1-i4.jar', - 'android-all-instrumented-7.0.0_r1-robolectric-r1-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/7.0.0_r1-robolectric-r1-i4/android-all-instrumented-7.0.0_r1-robolectric-r1-i4.jar', - 'android-all-instrumented-6.0.1_r3-robolectric-r1-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/6.0.1_r3-robolectric-r1-i4/android-all-instrumented-6.0.1_r3-robolectric-r1-i4.jar', - 'android-all-instrumented-5.0.2_r3-robolectric-r0-i4.jar': - 'https://repo1.maven.org/maven2/org/robolectric/android-all-instrumented/5.0.2_r3-robolectric-r0-i4/android-all-instrumented-5.0.2_r3-robolectric-r0-i4.jar', }
diff --git a/third_party/robolectric/OWNERS b/third_party/robolectric/OWNERS index 10989b97..596e1a0 100644 --- a/third_party/robolectric/OWNERS +++ b/third_party/robolectric/OWNERS
@@ -1,3 +1,4 @@ agrieve@chromium.org bjoyce@chromium.org +mheikal@chromium.org wnwen@chromium.org
diff --git a/third_party/skia b/third_party/skia index 0bbcd81..530fa37 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 0bbcd8152d32b349e5eee99b29bccc5fcd58ce9b +Subproject commit 530fa373b797bf1ade172ef591134ea6cc401271
diff --git a/third_party/wayland-protocols/BUILD.gn b/third_party/wayland-protocols/BUILD.gn index db15b95e..68b46ea 100644 --- a/third_party/wayland-protocols/BUILD.gn +++ b/third_party/wayland-protocols/BUILD.gn
@@ -196,3 +196,7 @@ "src/unstable/xdg-shell/xdg-shell-unstable-v6.xml", ] } + +wayland_protocol("xdg_toplevel_drag_protocol") { + sources = [ "src/staging/xdg-toplevel-drag/xdg-toplevel-drag-v1.xml" ] +}
diff --git a/third_party/webrtc b/third_party/webrtc index b25c747..2192284 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit b25c747d5d318827869fe8304bd975285b33bf57 +Subproject commit 21922847462881016e05b008ffbf7d25c602074b
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index caab53f4..f301fbc 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -10034,6 +10034,12 @@ </description> </action> +<action + name="ExplicitBrowserSigninPreferenceRemembered_IPHPromo_SettingsPageOpened"> + <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <description>Please enter the description of the metric.</description> +</action> + <action name="ExploreSites.ContextMenu"> <owner>chili@chromium.org</owner> <owner>dewittj@chromium.org</owner> @@ -42737,6 +42743,8 @@ label="For Download toolbar button feature."/> <suffix name="EphemeralTab" label="For Ephemeral Tab."/> <suffix name="ExperimentalAIPromo" label="For Experimental AI feature."/> + <suffix name="ExplicitBrowserSigninPreferenceRemembered" + label="For Explicit Browser Signin Preference Remembered feature."/> <suffix name="ExploreSitesTile" label="For Explore Sites feature."/> <suffix name="ExtensionsMenu" label="For Extensions menu opening."/> <suffix name="ExtensionsRequestAccessButton"
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 7254dbc..10aaee8 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -16759,6 +16759,7 @@ <int value="-1980328793" label="trace-upload-url"/> <int value="-1978625006" label="PcieBillboardNotification:disabled"/> <int value="-1978116081" label="SeaPen:disabled"/> + <int value="-1978003156" label="EnableExtensibleEnterpriseSSO:disabled"/> <int value="-1977496883" label="ViewPasswords:enabled"/> <int value="-1976050618" label="AppDeduplicationService:disabled"/> <int value="-1975970208" label="(Obsolete) TranslateSubFrames:disabled"/> @@ -18668,6 +18669,8 @@ <int value="-1151014496" label="NearbySharingDeviceContacts:disabled"/> <int value="-1150980351" label="CrosWebAppInstallDialog:enabled"/> <int value="-1150485573" label="HistoryClustersPersistedClusters:enabled"/> + <int value="-1149710408" + label="WebAuthenticationEnclaveAuthenticator:enabled"/> <int value="-1148764533" label="CrOSLateBootAudioAecRequiredForCrasProcessor:enabled"/> <int value="-1148269796" label="ProjectorUseUSMForS3:disabled"/> @@ -19009,6 +19012,7 @@ <int value="-998731974" label="WinUseBrowserSpellChecker:enabled"/> <int value="-998310305" label="OmniboxContextMenuShowFullUrls:disabled"/> <int value="-998255750" label="ExperimentalKeyboardLockUI:enabled"/> + <int value="-997652636" label="EnableExtensibleEnterpriseSSO:enabled"/> <int value="-997491100" label="ShareUsageRanking:disabled"/> <int value="-997185008" label="LensFullscreenSearch:disabled"/> <int value="-996868396" label="SmartDimNewMlAgent:enabled"/> @@ -19764,6 +19768,8 @@ <int value="-657808907" label="CopyLinkToText:disabled"/> <int value="-657656374" label="AppListBubble:disabled"/> <int value="-656743717" label="HelpAppDiscoverTab:enabled"/> + <int value="-656630541" + label="WebAuthenticationEnclaveAuthenticator:disabled"/> <int value="-655608107" label="MediaAppCustomColors:enabled"/> <int value="-655294302" label="UseMlServiceForNonLongformHandwritingOnAllBoards:disabled"/>
diff --git a/tools/metrics/histograms/metadata/android/enums.xml b/tools/metrics/histograms/metadata/android/enums.xml index cad59bc..ca5d5f1 100644 --- a/tools/metrics/histograms/metadata/android/enums.xml +++ b/tools/metrics/histograms/metadata/android/enums.xml
@@ -536,6 +536,7 @@ <int value="101" label="WebViewCompat.isAudioMuted"/> <int value="102" label="WebSettingsCompat.setWebauthnSupport"/> <int value="103" label="WebSettingsCompat.getWebauthnSupport"/> + <int value="104" label="WebSettingsCompat.setPreloadingEnabled"/> </enum> <enum name="ArmCpuPart">
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml index 96e0e6a0..d56b88fe 100644 --- a/tools/metrics/histograms/metadata/android/histograms.xml +++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -5608,12 +5608,15 @@ </histogram> <histogram name="Android.WebView.InputStreamTime" units="ms" - expires_after="2023-12-04"> + expires_after="2024-11-16"> <owner>jam@chromium.org</owner> <owner>cduvall@chromium.org</owner> + <owner>stefanoduo@google.com</owner> <summary> Measures how long InputStreams take from creation to completion. This is - emitted for all streams whether they succeed or fail. + emitted for all streams whether they succeed or fail. This metric was + expired between December 2023 and May 2024. Data from that period will be + incomplete. </summary> </histogram>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 8d8ae04..4b8a15d3 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -4855,7 +4855,7 @@ </histogram> <histogram name="Ash.Mahi.ButtonClicked" enum="PanelButton" - expires_after="2025-04-04"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -4874,7 +4874,7 @@ </histogram> <histogram name="Ash.Mahi.QuestionAnswer.LoadingTime" units="ms" - expires_after="2025-04-10"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -4904,7 +4904,7 @@ </histogram> <histogram name="Ash.Mahi.Summary.LoadingTime" units="ms" - expires_after="2025-04-10"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -4914,7 +4914,7 @@ </histogram> <histogram name="Ash.Mahi.UserJourneyTime" units="ms" - expires_after="2025-04-10"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -4971,7 +4971,7 @@ </histogram> <histogram name="Ash.MessageCenter.Scroll.PresentationTime" units="ms" - expires_after="2024-10-01"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -4981,7 +4981,7 @@ </histogram> <histogram name="Ash.MessageCenter.Scroll.PresentationTime.MaxLatency" - units="ms" expires_after="2025-04-16"> + units="ms" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5126,7 +5126,7 @@ </histogram> <histogram name="Ash.Notification.ClearAllStacked.AnimationSmoothness" - units="%" expires_after="2024-11-03"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5138,7 +5138,7 @@ </histogram> <histogram name="Ash.Notification.ClearAllVisible.AnimationSmoothness" - units="%" expires_after="2024-11-03"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5149,7 +5149,7 @@ </histogram> <histogram name="Ash.Notification.CountOfNotificationsInOneGroup" - units="Notifications" expires_after="2024-11-12"> + units="Notifications" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5159,7 +5159,7 @@ </histogram> <histogram name="Ash.Notification.ExpandOrCollapse.AnimationSmoothness" - units="%" expires_after="2024-11-03"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5183,7 +5183,7 @@ </histogram> <histogram name="Ash.Notification.GroupNotificationAdded" - enum="GroupNotificationType" expires_after="2025-01-14"> + enum="GroupNotificationType" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5203,7 +5203,7 @@ </histogram> <histogram name="Ash.Notification.MoveDown.AnimationSmoothness" units="%" - expires_after="2024-11-03"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5235,7 +5235,7 @@ </histogram> <histogram name="Ash.Notification.SwipeControl.FadeIn.AnimationSmoothness" - units="%" expires_after="2025-01-28"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5246,7 +5246,7 @@ </histogram> <histogram name="Ash.NotificationPopup.AnimationSmoothness" units="%" - expires_after="2024-09-22"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>amehfooz@chromium.org</owner> <owner>tbarzic@chromium.org</owner> @@ -5259,7 +5259,7 @@ </histogram> <histogram name="Ash.NotificationPopup.OnTopOfSurfacesPopupCount" - units="popups" expires_after="2024-08-22"> + units="popups" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5271,7 +5271,7 @@ </histogram> <histogram name="Ash.NotificationPopup.OnTopOfSurfacesType" - enum="NotifierCollisionSurfaceType" expires_after="2024-08-22"> + enum="NotifierCollisionSurfaceType" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5284,7 +5284,7 @@ <histogram name="Ash.NotificationView.ConvertSingleToGroup.{Animation}.AnimationSmoothness" - units="%" expires_after="2024-05-14"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5300,7 +5300,7 @@ <histogram name="Ash.NotificationView.ExpandButton.BoundsChange.AnimationSmoothness" - units="%" expires_after="2025-01-28"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5311,7 +5311,7 @@ </histogram> <histogram name="Ash.NotificationView.ExpandButton.ClickAction" - enum="ExpandButtonClickAction" expires_after="2025-04-30"> + enum="ExpandButtonClickAction" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5323,7 +5323,7 @@ <histogram name="Ash.NotificationView.ExpandButton.ConvertSingleToGroup.{Animation}.AnimationSmoothness" - units="%" expires_after="2024-05-14"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5340,7 +5340,7 @@ <histogram name="Ash.NotificationView.ImageContainerView.ScaleDown.AnimationSmoothness" - units="%" expires_after="2025-01-28"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5371,7 +5371,7 @@ </histogram> <histogram name="Ash.NotificationView.NotificationAdded.Type" - enum="NotificationViewType" expires_after="2024-10-20"> + enum="NotificationViewType" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5381,7 +5381,7 @@ </histogram> <histogram name="Ash.NotificationView.{ChildView}.FadeIn.AnimationSmoothness" - units="%" expires_after="2025-01-28"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5406,7 +5406,7 @@ </histogram> <histogram name="Ash.NotificationView.{ChildView}.FadeOut.AnimationSmoothness" - units="%" expires_after="2025-01-28"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -5430,7 +5430,7 @@ <histogram name="Ash.NotificationView.{ChildView}.ScaleAndTranslate.AnimationSmoothness" - units="%" expires_after="2024-06-02"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -6529,7 +6529,7 @@ </histogram> <histogram name="Ash.PrivacyIndicators.AnimationSmoothness" units="%" - expires_after="2024-09-19"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -6541,7 +6541,7 @@ </histogram> <histogram name="Ash.PrivacyIndicators.AppAccessUpdate.Type" enum="AppType" - expires_after="2024-09-29"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -6552,7 +6552,7 @@ </histogram> <histogram name="Ash.PrivacyIndicators.IndicatorShowsDuration" units="ms" - expires_after="2024-11-19"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -6562,7 +6562,7 @@ </histogram> <histogram name="Ash.PrivacyIndicators.LaunchSettings" enum="AppType" - expires_after="2024-09-29"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -6573,7 +6573,7 @@ </histogram> <histogram name="Ash.PrivacyIndicators.NumberOfAppsAccessingCamera" - units="count" expires_after="2025-01-21"> + units="count" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -6583,7 +6583,7 @@ </histogram> <histogram name="Ash.PrivacyIndicators.NumberOfAppsAccessingMicrophone" - units="count" expires_after="2024-09-19"> + units="count" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -6593,7 +6593,7 @@ </histogram> <histogram name="Ash.PrivacyIndicators.NumberOfRepeatedShows" units="shows" - expires_after="2025-03-24"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -6604,7 +6604,7 @@ </histogram> <histogram name="Ash.PrivacyIndicators.NumberOfShowsPerSession" units="shows" - expires_after="2025-01-21"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -6614,7 +6614,7 @@ </histogram> <histogram name="Ash.PrivacyIndicators.ShowType" enum="PrivacyIndicatorsType" - expires_after="2024-05-26"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -6624,7 +6624,7 @@ </histogram> <histogram name="Ash.PrivacyIndicators.Source" enum="PrivacyIndicatorsSource" - expires_after="2024-09-15"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -6634,7 +6634,7 @@ </histogram> <histogram name="Ash.PrivacyIndicators.{Icon}.AnimationSmoothness" units="%" - expires_after="2024-09-19"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8068,7 +8068,7 @@ </histogram> <histogram name="Ash.StatusArea.TrayBackgroundView.BounceIn" units="%" - expires_after="2024-11-03"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8080,7 +8080,7 @@ </histogram> <histogram name="Ash.StatusArea.TrayBackgroundView.FadeIn" units="%" - expires_after="2025-02-05"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8092,7 +8092,7 @@ </histogram> <histogram name="Ash.StatusArea.TrayBackgroundView.Hide" units="%" - expires_after="2024-11-03"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8122,7 +8122,7 @@ </histogram> <histogram name="Ash.StatusArea.TrayItemView.Hide" units="%" - expires_after="2024-11-03"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8133,7 +8133,7 @@ </histogram> <histogram name="Ash.StatusArea.TrayItemView.Show" units="%" - expires_after="2024-11-03"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8144,7 +8144,7 @@ </histogram> <histogram name="Ash.StatusAreaShowBubble.PresentationTime" units="ms" - expires_after="2024-09-29"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>amehfooz@chromium.org</owner> <owner>tbarzic@chromium.org</owner> @@ -8451,7 +8451,7 @@ </histogram> <histogram name="Ash.VideoConference.NumberOfRepeatedShows" units="shows" - expires_after="2024-09-22"> + expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8462,7 +8462,7 @@ </histogram> <histogram name="Ash.VideoConference.ReturnToApp.Click" - enum="VideoConferenceAppType" expires_after="2024-09-22"> + enum="VideoConferenceAppType" expires_after="2025-02-01"> <owner>leandre@google.com</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8473,7 +8473,7 @@ <histogram name="Ash.VideoConference.ReturnToAppButton.FadeOut.AnimationSmoothness" - units="%" expires_after="2025-04-20"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8485,7 +8485,7 @@ <histogram name="Ash.VideoConference.ReturnToAppPanel.BoundsChange.AnimationSmoothness" - units="%" expires_after="2025-04-20"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8496,7 +8496,7 @@ </histogram> <histogram name="Ash.VideoConference.{ViewName}.FadeIn.AnimationSmoothness" - units="%" expires_after="2025-04-20"> + units="%" expires_after="2025-02-01"> <owner>leandre@chromium.org</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8511,7 +8511,7 @@ </histogram> <histogram name="Ash.VideoConferenceTray.BackgroundBlur.Click" - enum="BackgroundBlurState" expires_after="2024-09-22"> + enum="BackgroundBlurState" expires_after="2025-02-01"> <owner>leandre@google.com</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8552,7 +8552,7 @@ </histogram> <histogram name="Ash.VideoConferenceTray.StopScreenShareButton.Click" - enum="BooleanClicked" expires_after="2025-03-16"> + enum="BooleanClicked" expires_after="2025-02-01"> <owner>leandre@google.com</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8562,7 +8562,7 @@ </histogram> <histogram name="Ash.VideoConferenceTray.ToggleBubbleButton.Click" - enum="BooleanOpened" expires_after="2024-09-22"> + enum="BooleanOpened" expires_after="2025-02-01"> <owner>leandre@google.com</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8572,7 +8572,7 @@ </histogram> <histogram name="Ash.VideoConferenceTray.{Device}MuteButton.Click" - enum="BooleanMuted" expires_after="2024-09-22"> + enum="BooleanMuted" expires_after="2025-02-01"> <owner>leandre@google.com</owner> <owner>cros-status-area-eng@google.com</owner> <summary> @@ -8587,7 +8587,7 @@ </histogram> <histogram name="Ash.VideoConferenceTray.{EffectName}.Click" - enum="BooleanEnabled" expires_after="2024-09-22"> + enum="BooleanEnabled" expires_after="2025-02-01"> <owner>leandre@google.com</owner> <owner>cros-status-area-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml index 9b0c8a85..8d98ec00 100644 --- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml +++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -163,6 +163,9 @@ <variant name="IPH_EphemeralTab" summary="new label on the context menu for Ephemeral Tab"/> <variant name="IPH_ExperimentalAIPromo" summary="Experimental AI promo"/> + <variant name="IPH_ExplicitBrowserSigninPreferenceRemembered" + summary="Confirmation message that the explicit browser signin + preference was remembered"/> <variant name="IPH_ExploreSitesTile" summary="Explore Sites feature"/> <variant name="IPH_ExtensionsMenu" summary="extensions menu opened"/> <variant name="IPH_ExtensionsRequestAccessButton"
diff --git a/tools/metrics/histograms/metadata/gpu/histograms.xml b/tools/metrics/histograms/metadata/gpu/histograms.xml index 6fd65197a..5a39504 100644 --- a/tools/metrics/histograms/metadata/gpu/histograms.xml +++ b/tools/metrics/histograms/metadata/gpu/histograms.xml
@@ -1375,18 +1375,6 @@ </summary> </histogram> -<histogram name="GPU.SharedImage.IsRG88HardwareGMBSupported" enum="Boolean" - expires_after="2024-10-06"> - <owner>hitawala@chromium.org</owner> - <owner>graphics-dev@chromium.org</owner> - <summary> - Tracks if shared images are created with hardware GpuMemoryBuffers of RG88 - format on Ozone based platforms. Result is a bool that reports if RG88 - format is supported for creating shared images with hardware GMBs. This is - logged once per gpu process launch. - </summary> -</histogram> - <histogram name="GPU.SkiaBackendType" enum="SkiaBackendType" expires_after="2025-02-01"> <owner>kylechar@chromium.org</owner> @@ -1707,6 +1695,26 @@ </histogram> <histogram + name="GPU.{GraphiteDawnOrWebGPU}.{Cacheable}.{CacheHitMiss}.90SecondsPostStartup" + units="microseconds" expires_after="2024-12-29"> + <owner>hitawala@chromium.org</owner> + <owner>mdb.webgpu-dev-team@google.com</owner> + <summary> + Tracks the amount of time in microseconds it takes for a cached call to + {Cacheable}.{CacheHitMiss} to complete without error when we have a cache + hit or miss within 90 seconds of browser start up. Based off the + {Cacheable}.CacheHit and {Cacheable}.CacheMiss metrics above. Recorded only + for clients that support high-resolution clocks. + </summary> + <token key="Cacheable" variants="WebGPUCacheable"/> + <token key="GraphiteDawnOrWebGPU" variants="GraphiteDawnOrWebGPU"/> + <token key="CacheHitMiss"> + <variant name="CacheHit"/> + <variant name="CacheMiss"/> + </token> +</histogram> + +<histogram name="GPU.{GraphiteDawnOrWebGPU}.{Cacheable}.{CacheHitMiss}.Counts.90SecondsPostStartup" units="count" expires_after="2024-12-29"> <owner>hitawala@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/enums.xml b/tools/metrics/histograms/metadata/others/enums.xml index 40d2bbc..6d3da1e4 100644 --- a/tools/metrics/histograms/metadata/others/enums.xml +++ b/tools/metrics/histograms/metadata/others/enums.xml
@@ -57,7 +57,7 @@ <int value="10" label="Unexpected side panel open"/> </enum> -<!-- LINT.ThenChange(//chrome/browser/ui/lens/lens_overlay_controller.h:DismissalSource) --> +<!-- LINT.ThenChange(//chrome/browser/ui/lens/lens_overlay_dismissal_source.h:LensOverlayDismissalSource) --> <!-- LINT.IfChange(LensOverlayInvocationSource) --> @@ -71,7 +71,7 @@ <int value="5" label="Omnibox button"/> </enum> -<!-- LINT.ThenChange(//chrome/browser/ui/lens/lens_overlay_controller.h:InvocationSource) --> +<!-- LINT.ThenChange(//chrome/browser/ui/lens/lens_overlay_invocation_source.h:LensOverlayInvocationSource) --> <!-- LINT.IfChange(LensPermissionBubbleUserAction) -->
diff --git a/tools/metrics/histograms/metadata/performance_controls/histograms.xml b/tools/metrics/histograms/metadata/performance_controls/histograms.xml index 1146d94..672e88e 100644 --- a/tools/metrics/histograms/metadata/performance_controls/histograms.xml +++ b/tools/metrics/histograms/metadata/performance_controls/histograms.xml
@@ -76,6 +76,17 @@ </summary> </histogram> +<histogram name="PerformanceControls.MemorySaver.DiscardRingTreatment" + enum="BooleanEnabled" expires_after="2025-05-07"> + <owner>charlesmeng@chromium.org</owner> + <owner>chrome-performance-ui-sea@google.com</owner> + <summary> + Logs whether the inactive tabs appearance pref is enabled, whenever the user + makes a change to it through the settings page. This will be used to measure + how many users opt out of seeing the discard ring on inactive tabs. + </summary> +</histogram> + <histogram name="PerformanceControls.MemorySaver.IPHEnableMode" enum="BooleanEnabled" expires_after="2024-09-22"> <owner>agale@chromium.org</owner>
diff --git a/tools/origin_trials/generate_token.py b/tools/origin_trials/generate_token.py index fedfe93..5009aa3 100755 --- a/tools/origin_trials/generate_token.py +++ b/tools/origin_trials/generate_token.py
@@ -122,10 +122,22 @@ return "{0}://{1}:{2}".format(origin.scheme, origin.hostname, port) def ExpiryFromArgs(args): + expiry: int if args.expire_timestamp: - return int(args.expire_timestamp) - return (int(time.time()) + (int(args.expire_days) * 86400)) + expiry = int(args.expire_timestamp) + else: + expiry = (int(time.time()) + (int(args.expire_days) * 86400)) + if expiry > 2**31 - 1: + # The maximum expiry timestamp is bound by the maximum value of a signed + # 32-bit integer (2^31-1). + # TODO(crbug.com/40872096): All expiries after 2038-01-19 03:14:07 UTC + # will raise this error, so add support for a larger range of values + # before then. + raise argparse.ArgumentTypeError( + "%d (%s UTC) is beyond the range of supported expiries" % + (expiry, datetime.utcfromtimestamp(expiry))) + return expiry def GenerateTokenData(version, origin, is_subdomain, is_third_party, usage_restriction, feature_name, expiry):
diff --git a/tools/perf/core/bot_platforms.py b/tools/perf/core/bot_platforms.py index 27ec922..f4a7b294 100644 --- a/tools/perf/core/bot_platforms.py +++ b/tools/perf/core/bot_platforms.py
@@ -39,7 +39,8 @@ is_calibration=False, run_reference_build=False, pinpoint_only=False, - executables=None): + executables=None, + crossbench=None): benchmark_configs = benchmark_configs.Frozenset() self._name = name self._description = description @@ -51,6 +52,7 @@ self.run_reference_build = run_reference_build self.pinpoint_only = pinpoint_only self.executables = executables or frozenset() + self.crossbench = crossbench or frozenset() assert num_shards self._num_shards = num_shards # pylint: disable=redefined-outer-name @@ -193,6 +195,16 @@ self.repeat = 1 +class CrossbenchConfig: + + def __init__(self, name, crossbench_name, estimated_runtime=60, stories=None): + self.name = name + self.crossbench_name = crossbench_name + self.estimated_runtime = estimated_runtime + self.stories = stories or ['default'] + self.repeat = 1 + + class PerfSuite(object): def __init__(self, configs): self._configs = dict() @@ -339,6 +351,17 @@ flags=['--xvfb'], estimated_runtime=estimated_runtime) + +def _crossbench_speedometer3_0(estimated_runtime=60): + return CrossbenchConfig('speedometer3.crossbench', + 'speedometer_3.0', + estimated_runtime=estimated_runtime) + + +_CROSSBENCH_BENCHMARKS = frozenset([ + _crossbench_speedometer3_0(), +]) + _CHROME_HEALTH_BENCHMARK_CONFIGS_DESKTOP = PerfSuite([ _GetBenchmarkConfig('system_health.common_desktop') ]) @@ -591,7 +614,8 @@ _FUCHSIA_PERF_NELSON_BENCHMARK_CONFIGS _LINUX_PERF_FYI_BENCHMARK_CONFIGS = PerfSuite([ _GetBenchmarkConfig('speedometer2'), - _GetBenchmarkConfig('speedometer2-nominorms') + _GetBenchmarkConfig('speedometer2-nominorms'), + _GetBenchmarkConfig('speedometer3'), ]) _LINUX_PERF_CALIBRATION_BENCHMARK_CONFIGS = PerfSuite([ _GetBenchmarkConfig('speedometer2'), @@ -890,8 +914,9 @@ LINUX_PERF_FYI = PerfPlatform('linux-perf-fyi', '', _LINUX_PERF_FYI_BENCHMARK_CONFIGS, - 1, + 4, 'linux', + crossbench=_CROSSBENCH_BENCHMARKS, is_fyi=True) # Calibration bots
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py index 3c79d2b..1220a8a 100755 --- a/tools/perf/core/perf_data_generator.py +++ b/tools/perf/core/perf_data_generator.py
@@ -220,7 +220,7 @@ 'linux', 'dimension': { 'gpu': '10de', - 'os': 'Ubuntu-22.04', + 'os': 'Ubuntu', 'pool': 'chrome.tests.perf-fyi', }, },
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 630a1dc..8bcafa4 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/v45.0/linux-arm64/trace_processor_shell" }, "win": { - "hash": "73ee58519851534c5248eb6511311bbe2fe931e6", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/44b3d8456c4a942e862bfcf14d998f5f3ff0d2c4/trace_processor_shell.exe" + "hash": "4bb514760a289123a95ee6e3a9665a38e6d06575", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/e03af0caee1bf0b7ece55e42e607d738f65f9c7b/trace_processor_shell.exe" }, "linux_arm": { "hash": "f7cc2e856e9ee1260e9691c078f3771193eb4dea", @@ -21,8 +21,8 @@ "full_remote_path": "perfetto-luci-artifacts/v45.0/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "a794e3fe62d056ac972131ef0ba3bc290fa983a7", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/26055b167a94a8483779c807e5869ce5f8505f7c/trace_processor_shell" + "hash": "4481ef5b3d14b6baa6bf69daa8e0bd1759d2a783", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/e03af0caee1bf0b7ece55e42e607d738f65f9c7b/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/perf/core/shard_maps/linux-perf-fyi_map.json b/tools/perf/core/shard_maps/linux-perf-fyi_map.json index b3062d041..b9b1bdb 100644 --- a/tools/perf/core/shard_maps/linux-perf-fyi_map.json +++ b/tools/perf/core/shard_maps/linux-perf-fyi_map.json
@@ -1,20 +1,85 @@ { "0": { "benchmarks": { + "speedometer2": { + "abridged": false + }, "speedometer2-nominorms": { "abridged": false }, + "speedometer3": { + "abridged": false + } + }, + "crossbench": { + "speedometer3.crossbench": { + "crossbench_name": "speedometer_3.0" + } + } + }, + "1": { + "benchmarks": { "speedometer2": { "abridged": false + }, + "speedometer2-nominorms": { + "abridged": false + }, + "speedometer3": { + "abridged": false + } + }, + "crossbench": { + "speedometer3.crossbench": { + "crossbench_name": "speedometer_3.0" + } + } + }, + "2": { + "benchmarks": { + "speedometer2": { + "abridged": false + }, + "speedometer2-nominorms": { + "abridged": false + }, + "speedometer3": { + "abridged": false + } + }, + "crossbench": { + "speedometer3.crossbench": { + "crossbench_name": "speedometer_3.0" + } + } + }, + "3": { + "benchmarks": { + "speedometer2": { + "abridged": false + }, + "speedometer2-nominorms": { + "abridged": false + }, + "speedometer3": { + "abridged": false + } + }, + "crossbench": { + "speedometer3.crossbench": { + "crossbench_name": "speedometer_3.0" } } }, "extra_infos": { - "num_stories": 2, - "predicted_min_shard_time": 20, + "num_stories": 16, + "predicted_min_shard_time": 90, "predicted_min_shard_index": 0, - "predicted_max_shard_time": 20, + "predicted_max_shard_time": 90, "predicted_max_shard_index": 0, - "shard #0": 20 + "shard #0": 90, + "shard #1": 90, + "shard #2": 90, + "shard #3": 90 } } \ No newline at end of file
diff --git a/tools/perf/core/sharding_map_generator.py b/tools/perf/core/sharding_map_generator.py index cd001d7..6095fbea 100644 --- a/tools/perf/core/sharding_map_generator.py +++ b/tools/perf/core/sharding_map_generator.py
@@ -3,6 +3,7 @@ # found in the LICENSE file. import collections +import core.bot_platforms import core.path_util import core.cli_utils @@ -279,8 +280,18 @@ # Format the benchmark's stories by indices benchmarks_in_shard = collections.OrderedDict() executables_in_shard = collections.OrderedDict() + crossbench_in_shard = collections.OrderedDict() for b in benchmarks: - if benchmark_name_to_config[b].is_telemetry: + config = benchmark_name_to_config[b] + if isinstance(config, core.bot_platforms.CrossbenchConfig): + crossbench_in_shard[b] = {'crossbench_name': config.crossbench_name} + first_story = all_stories[b].index(benchmarks[b][0]) + last_story = all_stories[b].index(benchmarks[b][-1]) + 1 + if first_story != 0: + crossbench_in_shard[b]['begin'] = first_story + if last_story != len(all_stories[b]): + crossbench_in_shard[b]['end'] = last_story + elif config.is_telemetry: benchmarks_in_shard[b] = {} first_story = all_stories[b].index(benchmarks[b][0]) last_story = all_stories[b].index(benchmarks[b][-1]) + 1 @@ -290,7 +301,6 @@ benchmarks_in_shard[b]['end'] = last_story benchmarks_in_shard[b]['abridged'] = benchmark_name_to_config[b].abridged else: - config = benchmark_name_to_config[b] executables_in_shard[b] = {} if config.flags: executables_in_shard[b]['arguments'] = config.flags @@ -300,6 +310,8 @@ sharding_map[str(shard_index)]['benchmarks'] = benchmarks_in_shard if executables_in_shard: sharding_map[str(shard_index)]['executables'] = executables_in_shard + if crossbench_in_shard: + sharding_map[str(shard_index)]['crossbench'] = crossbench_in_shard def _gather_timing_data(benchmarks_to_shard, timing_data, repeat): @@ -317,7 +329,7 @@ run_count = b.repeat if repeat else 1 for s in b.stories: test_name = '%s/%s' % (b.name, s) - test_duration = DEFAULT_STORY_DURATION + test_duration = getattr(b, 'estimated_runtime', DEFAULT_STORY_DURATION) if test_name in timing_data_dict: test_duration = timing_data_dict[test_name] * run_count timing_data_list.append((test_name, test_duration))
diff --git a/tools/perf/core/sharding_map_generator_unittest.py b/tools/perf/core/sharding_map_generator_unittest.py index 4a3b232..b48ae578 100644 --- a/tools/perf/core/sharding_map_generator_unittest.py +++ b/tools/perf/core/sharding_map_generator_unittest.py
@@ -8,6 +8,7 @@ import os import unittest +from core import bot_platforms from core import sharding_map_generator @@ -176,3 +177,16 @@ self.assertIn('benchmark_1', sharding_map['2']['benchmarks']) self.assertIn('benchmark_1', sharding_map['3']['benchmarks']) self.assertIn('benchmark_1', sharding_map['4']['benchmarks']) + + def testGenerateShardingMapWithCrossbench(self): + benchmarks_data, timing_data, = self._generate_test_data( + [[10, 20, 30], [65, 55, 5, 45], [50, 40, 30, 20, 10]]) + benchmarks_data.append( + bot_platforms.CrossbenchConfig('cb_benchmark_0', 'cb_benchmark_0_name')) + sharding_map = sharding_map_generator.generate_sharding_map( + benchmarks_data, timing_data, 3, None) + self.assertIn('crossbench', sharding_map['2']) + self.assertIn('cb_benchmark_0', sharding_map['2']['crossbench']) + self.assertEqual( + 'cb_benchmark_0_name', + sharding_map['2']['crossbench']['cb_benchmark_0']['crossbench_name'])
diff --git a/tools/perf/cross_device_test_config.py b/tools/perf/cross_device_test_config.py index 76340f34..d609238 100644 --- a/tools/perf/cross_device_test_config.py +++ b/tools/perf/cross_device_test_config.py
@@ -147,6 +147,12 @@ 'Speedometer3': 20, }, }, + 'linux-perf-fyi': { + 'speedometer2': 4, + 'speedometer2-nominorms': 4, + 'speedometer3': 4, + 'speedometer3.crossbench': 4, + }, 'win-10_laptop_low_end-perf': { 'jetstream2': { 'JetStream2': 5,
diff --git a/tools/perf/generate_perf_sharding.py b/tools/perf/generate_perf_sharding.py index 72a76224..6ec032b 100755 --- a/tools/perf/generate_perf_sharding.py +++ b/tools/perf/generate_perf_sharding.py
@@ -147,8 +147,8 @@ if builder: with open(builder.timing_file_path) as f: timing_data = json.load(f) - benchmarks_to_shard = ( - list(builder.benchmark_configs) + list(builder.executables)) + benchmarks_to_shard = (list(builder.benchmark_configs) + + list(builder.executables) + list(builder.crossbench)) repeat_config = cross_device_test_config.TARGET_DEVICES.get(builder.name, {}) sharding_map = sharding_map_generator.generate_sharding_map( benchmarks_to_shard,
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc index 5e98ece..913e8c41 100644 --- a/ui/accessibility/accessibility_features.cc +++ b/ui/accessibility/accessibility_features.cc
@@ -15,13 +15,6 @@ namespace features { -BASE_FEATURE(kAccessibilityFocusHighlight, - "AccessibilityFocusHighlight", - base::FEATURE_ENABLED_BY_DEFAULT); -bool IsAccessibilityFocusHighlightEnabled() { - return base::FeatureList::IsEnabled(::features::kAccessibilityFocusHighlight); -} - BASE_FEATURE(kAccessibilityPdfOcrForSelectToSpeak, "kAccessibilityPdfOcrForSelectToSpeak", #if BUILDFLAG(IS_CHROMEOS)
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h index a2b620e3..479602c9 100644 --- a/ui/accessibility/accessibility_features.h +++ b/ui/accessibility/accessibility_features.h
@@ -43,11 +43,6 @@ namespace features { -// Draw a visual highlight around the focused element on the page -// briefly whenever focus changes. -AX_BASE_EXPORT BASE_DECLARE_FEATURE(kAccessibilityFocusHighlight); -AX_BASE_EXPORT bool IsAccessibilityFocusHighlightEnabled(); - // Enable PDF OCR for Select-to-Speak. It will be disabled by default on // platforms other than ChromeOS as STS is available only on ChromeOS. AX_BASE_EXPORT BASE_DECLARE_FEATURE(kAccessibilityPdfOcrForSelectToSpeak);
diff --git a/ui/accessibility/extensions/BUILD.gn b/ui/accessibility/extensions/BUILD.gn index 288e141..72d6e20 100644 --- a/ui/accessibility/extensions/BUILD.gn +++ b/ui/accessibility/extensions/BUILD.gn
@@ -23,7 +23,6 @@ testonly = true if (is_chromeos_ash) { deps = [ - ":caretbrowsing_tests", ":colorenhancer_tests", ":highcontrast_tests", "chromevoxclassic:chromevox_tests", @@ -286,17 +285,7 @@ "caretbrowsing/caret_19_on.png", "caretbrowsing/caret_19.png", "caretbrowsing/caret_48.png", - "caretbrowsing/caretbrowsing.css", - "caretbrowsing/caretbrowsing.js", - "caretbrowsing/increase_brightness.png", "caretbrowsing/manifest.json", - "caretbrowsing/node_util.js", - "caretbrowsing/options.html", - "caretbrowsing/options.js", - "caretbrowsing/selection_util.js", - "caretbrowsing/storage.js", - "caretbrowsing/traverse_util.js", - "//third_party/accessibility-audit/axs_testing.js", ] copy("caretbrowsing_copy") { @@ -305,33 +294,6 @@ } if (is_chromeos_ash) { - test("caretbrowsing_tests") { - deps = [ ":caretbrowsing_webui_js_tests" ] - deps += webui_test_deps - - data = js2gtest_js_libraries - } - - js2gtest("caretbrowsing_webui_js_tests") { - test_type = "webui" - sources = [ - "caretbrowsing/node_util_test.js", - "caretbrowsing/selection_util_test.js", - "caretbrowsing/storage_test.js", - ] - gen_include_files = [ - "caretbrowsing/node_util.js", - "caretbrowsing/selection_util.js", - "caretbrowsing/storage.js", - "caretbrowsing/traverse_util.js", - "testing/webstore_extension_test_base.js", - "//chrome/browser/resources/chromeos/accessibility/common/testing/callback_helper.js", - "//chrome/browser/resources/chromeos/accessibility/common/testing/mock_storage.js", - ] - - defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] - } - test("highcontrast_tests") { deps = [ ":highcontrast_webui_js_tests" ] deps += webui_test_deps
diff --git a/ui/accessibility/extensions/caretbrowsing/background.js b/ui/accessibility/extensions/caretbrowsing/background.js index 3c9d7f7..1ed94b6 100644 --- a/ui/accessibility/extensions/caretbrowsing/background.js +++ b/ui/accessibility/extensions/caretbrowsing/background.js
@@ -6,82 +6,5 @@ * @fileoverview Script that runs on the background page. */ -importScripts('storage.js'); -Storage.initialize(); - -CONTENT_SCRIPTS = [ - 'accessibility_utils.js', 'node_util.js', 'selection_util.js', - 'traverse_util.js', 'storage.js', 'caret_browsing.js' -]; - -/** - * The class handling the Caret Browsing background page, which keeps - * track of the current state, handles the browser action button, and - * initializes the content script in all running tabs when the extension - * is first loaded. - * @constructor - */ -const CaretBkgnd = function() {}; - -/** - * Change the browser action icon and tooltip based on the enabled state. - */ -CaretBkgnd.setIcon = function() { - chrome.action.setIcon( - {'path': Storage.enabled ? - '../caret_19_on.png' : - '../caret_19.png'}); - chrome.action.setTitle( - {'title': Storage.enabled ? - 'Turn Off Caret Browsing (F7)' : - 'Turn On Caret Browsing (F7)' }); -}; - -/** - * This is called when the extension is first loaded, so that it can be - * immediately used in all already-open tabs. It's not needed for any - * new tabs that open after that, the content script will be automatically - * injected into any new tab. - */ -CaretBkgnd.injectContentScripts = function() { - chrome.windows.getAll({'populate': true}, function(windows) { - for (const w of windows) { - for (const tab of w.tabs) { - chrome.scripting.executeScript( - { - target: {tabId: tab.id, allFrames: true}, - files: CONTENT_SCRIPTS, - }, - function(result) { - // Ignore. - chrome.runtime.lastError; - }); - } - } - }); -}; - -/** - * Toggle caret browsing on or off, and update the browser action icon and - * all open tabs. - */ -CaretBkgnd.toggle = function() { - Storage.enabled = !Storage.enabled; - CaretBkgnd.setIcon(); -}; - -/** - * Initialize the background script. Set the initial value of the flag - * based on the saved preference in localStorage, update the browser action, - * inject into running tabs, and then set up communication with content - * scripts in tabs. Also check for prefs updates (from the options page) - * and send them to content scripts. - */ -CaretBkgnd.init = function() { - CaretBkgnd.setIcon(); - chrome.action.onClicked.addListener(CaretBkgnd.toggle); - Storage.ENABLED.listeners.push(CaretBkgnd.setIcon); -}; - -CaretBkgnd.init(); -self.addEventListener('install', CaretBkgnd.injectContentScripts); +console.log('Caret browsing has been built into the browser! You can ' + + 'continue to use it exactly as you have been.'); \ No newline at end of file
diff --git a/ui/accessibility/extensions/caretbrowsing/caretbrowsing.css b/ui/accessibility/extensions/caretbrowsing/caretbrowsing.css deleted file mode 100644 index e39dbd4..0000000 --- a/ui/accessibility/extensions/caretbrowsing/caretbrowsing.css +++ /dev/null
@@ -1,28 +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. */ - -.CaretBrowsing_Caret { - position: absolute; - z-index: 2147483647; - min-height: 10px; - background-color: #000; -} - -.CaretBrowsing_AnimateCaret { - position: absolute; - z-index: 2147483647; - min-height: 10px; -} - -.CaretBrowsing_FlashVert { - position: absolute; - z-index: 2147483647; - background: linear-gradient( - 270deg, - rgba(128, 128, 255, 0) 0%, - rgba(128, 128, 255, 0.3) 45%, - rgba(128, 128, 255, 0.8) 50%, - rgba(128, 128, 255, 0.3) 65%, - rgba(128, 128, 255, 0) 100%); -}
diff --git a/ui/accessibility/extensions/caretbrowsing/caretbrowsing.js b/ui/accessibility/extensions/caretbrowsing/caretbrowsing.js deleted file mode 100644 index 47e0c25..0000000 --- a/ui/accessibility/extensions/caretbrowsing/caretbrowsing.js +++ /dev/null
@@ -1,1079 +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. */ - -/** - * @fileoverview Caret browsing content script, runs in each frame. - * - * The behavior is based on Mozilla's spec whenever possible: - * http://www.mozilla.org/access/keyboard/proposal - * - * The one exception is that Esc is used to escape out of a form control, - * rather than their proposed key (which doesn't seem to work in the - * latest Firefox anyway). - * - * Some details about how Chrome selection works, which will help in - * understanding the code: - * - * The Selection object (window.getSelection()) has four components that - * completely describe the state of the caret or selection: - * - * base and anchor: this is the start of the selection, the fixed point. - * extent and focus: this is the end of the selection, the part that - * moves when you hold down shift and press the left or right arrows. - * - * When the selection is a cursor, the base, anchor, extent, and focus are - * all the same. - * - * There's only one time when the base and anchor are not the same, or the - * extent and focus are not the same, and that's when the selection is in - * an ambiguous state - i.e. it's not clear which edge is the focus and which - * is the anchor. As an example, if you double-click to select a word, then - * the behavior is dependent on your next action. If you press Shift+Right, - * the right edge becomes the focus. But if you press Shift+Left, the left - * edge becomes the focus. - * - * When the selection is in an ambiguous state, the base and extent are set - * to the position where the mouse clicked, and the anchor and focus are set - * to the boundaries of the selection. - * - * The only way to set the selection and give it direction is to use - * the non-standard Selection.setBaseAndExtent method. If you try to use - * Selection.addRange(), the anchor will always be on the left and the focus - * will always be on the right, making it impossible to manipulate - * selections that move from right to left. - * - * Finally, Chrome will throw an exception if you try to set an invalid - * selection - a selection where the left and right edges are not the same, - * but it doesn't span any visible characters. A common example is that - * there are often many whitespace characters in the DOM that are not - * visible on the page; trying to select them will fail. Another example is - * any node that's invisible or not displayed. - * - * While there are probably many possible methods to determine what is - * selectable, this code uses the method of determining if there's a valid - * bounding box for the range or not - keep moving the cursor forwards until - * the range from the previous position and candidate next position has a - * valid bounding box. - */ - -Storage.initialize(); - -/** - * The class handling the Caret Browsing implementation in the page. - * Installs a keydown listener that always responds to the F7 key, - * sets up communication with the background page, and then when caret - * browsing is enabled, response to various key events to move the caret - * or selection within the text content of the document. Uses the native - * Chrome selection wherever possible, but displays its own flashing - * caret using a DIV because there's no native caret available. - * @constructor - */ -class CaretBrowsing { - constructor() { - /** - * Tracks whether to keep caret browsing enabled on this page even when it's - * flipped off. This is used on the options page. - * @type {boolean} - */ - this.forceEnabled = false; - - /** - * Tracks whether this window / iframe is focused. The caret isn't shown on - * pages that are not focused, which is especially important so that carets - * aren't shown in two iframes of the same tab. - * @type {boolean} - */ - this.isWindowFocused = false; - - /** - * Tracks whether the caret is actually visible. This is true only if - * Storage.enabled and this.isWindowFocused are both true. - * @type {boolean} - */ - this.isCaretVisible = false; - - /** - * The actual caret HTML element, an absolute-positioned flashing line. - * @type {Element} - */ - this.caretElement; - - /** - * The x-position of the caret, in absolute pixels. - * @type {number} - */ - this.caretX = 0; - - /** - * The y-position of the caret, in absolute pixels. - * @type {number} - */ - this.caretY = 0; - - /** - * The width of the caret in pixels. - * @type {number} - */ - this.caretWidth = 0; - - /** - * The height of the caret in pixels. - * @type {number} - */ - this.caretHeight = 0; - - /** - * The caret's foreground color. - * @type {string} - */ - this.caretForeground = '#000'; - - /** - * The caret's background color. - * @type {string} - */ - this.caretBackground = '#fff'; - - /** - * Tracks whether the selection is collapsed, i.e. are the start and end - * locations the same? If so, our blinking caret image is shown; otherwise - * the Chrome selection is shown. - * @type {boolean} - */ - this.isSelectionCollapsed = false; - - /** - * The id returned by window.setInterval for our blink function, so - * we can cancel it when caret browsing is disabled. - * @type {?number} - */ - this.blinkFunctionId = null; - - /** - * The desired x-coordinate to match when moving the caret up and down. - * To match the behavior as documented in Mozilla's caret browsing spec - * (http://www.mozilla.org/access/keyboard/proposal), we keep track of the - * initial x position when the user starts moving the caret up and down, - * so that the x position doesn't drift as you move throughout lines, but - * stays as close as possible to the initial position. This is reset when - * moving left or right or clicking. - * @type {?number} - */ - this.targetX = null; - - /** - * A flag that flips on or off as the caret blinks. - * @type {boolean} - */ - this.blinkFlag = true; - - /** - * Whether or not we're on a Mac - which affects modifier keys. - * @type {boolean} - */ - this.isMac = (navigator.appVersion.indexOf("Mac") != -1); - - this.init(); - } - - /** - * If there's no initial selection, set the cursor just before the - * first text character in the document. - */ - setInitialCursor() { - const sel = window.getSelection(); - if (sel.rangeCount > 0) { - return; - } - - const start = new Cursor(document.body, 0, ''); - const end = new Cursor(document.body, 0, ''); - const nodesCrossed = []; - const result = TraverseUtil.getNextChar(start, end, nodesCrossed, true); - if (result == null) { - return; - } - SelectionUtil.setAndValidateSelection(start, start); - } - - /** - * Set the caret element's normal style, i.e. not when animating. - */ - setCaretElementNormalStyle() { - const element = this.caretElement; - element.className = 'CaretBrowsing_Caret'; - element.style.opacity = this.isSelectionCollapsed ? '1.0' : '0.0'; - element.style.left = this.caretX + 'px'; - element.style.top = this.caretY + 'px'; - element.style.width = this.caretWidth + 'px'; - element.style.height = this.caretHeight + 'px'; - element.style.color = this.caretForeground; - } - - /** - * Animate the caret element into the normal style. - */ - animateCaretElement() { - const element = this.caretElement; - element.style.left = (this.caretX - 50) + 'px'; - element.style.top = (this.caretY - 100) + 'px'; - element.style.width = (this.caretWidth + 100) + 'px'; - element.style.height = (this.caretHeight + 200) + 'px'; - element.className = 'CaretBrowsing_AnimateCaret'; - - // Start the animation. The setTimeout is so that the old values will get - // applied first, so we can animate to the new values. - window.setTimeout(() => { - if (!this.caretElement) { - return; - } - this.setCaretElementNormalStyle(); - element.style['transition'] = 'all 0.8s ease-in'; - const listener = () => { - element.removeEventListener( - 'transitionend', listener, false); - element.style['transition'] = 'none'; - } - element.addEventListener( - 'transitionend', listener, false); - }, 0); - } - - /** - * Quick flash and then show the normal caret style. - */ - flashCaretElement() { - const x = this.caretX; - const y = this.caretY; - const height = this.caretHeight; - - const vert = document.createElement('div'); - vert.className = 'CaretBrowsing_FlashVert'; - vert.style.left = (x - 6) + 'px'; - vert.style.top = (y - 100) + 'px'; - vert.style.width = '11px'; - vert.style.height = (200) + 'px'; - document.body.appendChild(vert); - - window.setTimeout(() => { - document.body.removeChild(vert); - if (this.caretElement) { - this.setCaretElementNormalStyle(); - } - }, 250); - } - - /** - * Create the caret element. This assumes that caretX, caretY, - * caretWidth, and caretHeight have all been set. The caret is - * animated in so the user can find it when it first appears. - */ - createCaretElement() { - const element = document.createElement('div'); - element.className = 'CaretBrowsing_Caret'; - document.body.appendChild(element); - this.caretElement = element; - - if (Storage.onEnable === FlourishType.ANIMATE) { - this.animateCaretElement(); - } else if (Storage.onEnable === FlourishType.FLASH) { - this.flashCaretElement(); - } else { - this.setCaretElementNormalStyle(); - } - } - - /** - * Recreate the caret element, triggering any intro animation. - */ - recreateCaretElement() { - if (this.caretElement) { - window.clearInterval(this.blinkFunctionId); - this.caretElement.parentElement.removeChild( - this.caretElement); - this.caretElement = null; - this.updateIsCaretVisible(); - } - } - - /** - * Compute the new location of the caret or selection and update - * the element as needed. - * @param {boolean} scrollToSelection If true, will also scroll the page - * to the caret / selection location. - */ - updateCaretOrSelection(scrollToSelection) { - const previousX = this.caretX; - const previousY = this.caretY; - - const sel = window.getSelection(); - if (sel.rangeCount == 0) { - if (this.caretElement) { - this.isSelectionCollapsed = false; - this.caretElement.style.opacity = '0.0'; - } - return; - } - - const range = sel.getRangeAt(0); - if (!range) { - if (this.caretElement) { - this.isSelectionCollapsed = false; - this.caretElement.style.opacity = '0.0'; - } - return; - } - - if (NodeUtil.isControlThatNeedsArrowKeys(document.activeElement)) { - let node = document.activeElement; - this.caretWidth = node.offsetWidth; - this.caretHeight = node.offsetHeight; - this.caretX = 0; - this.caretY = 0; - while (node.offsetParent) { - this.caretX += node.offsetLeft; - this.caretY += node.offsetTop; - node = node.offsetParent; - } - this.isSelectionCollapsed = false; - } else if ( - range.startOffset != range.endOffset || - range.startContainer != range.endContainer) { - const rect = range.getBoundingClientRect(); - if (!rect) { - return; - } - this.caretX = rect.left + window.pageXOffset; - this.caretY = rect.top + window.pageYOffset; - this.caretWidth = rect.width; - this.caretHeight = rect.height; - this.isSelectionCollapsed = false; - } else { - const rect = SelectionUtil.getCursorRect(new Cursor( - range.startContainer, range.startOffset, - TraverseUtil.getNodeText(range.startContainer))); - this.caretX = rect.left; - this.caretY = rect.top; - this.caretWidth = rect.width; - this.caretHeight = rect.height; - this.isSelectionCollapsed = true; - } - - if (!this.caretElement) { - this.createCaretElement(); - } else { - const element = this.caretElement; - if (this.isSelectionCollapsed) { - element.style.opacity = '1.0'; - element.style.left = this.caretX + 'px'; - element.style.top = this.caretY + 'px'; - element.style.width = this.caretWidth + 'px'; - element.style.height = this.caretHeight + 'px'; - } else { - element.style.opacity = '0.0'; - } - } - - let elem = range.startContainer; - if (elem.constructor == Text) - elem = elem.parentElement; - const style = window.getComputedStyle(elem); - const bg = axs.utils.getBgColor(style, elem); - const fg = axs.utils.getFgColor(style, elem, bg); - this.caretBackground = axs.color.colorToString(bg); - this.caretForeground = axs.color.colorToString(fg); - - if (scrollToSelection) { - // Scroll just to the "focus" position of the selection, - // the part the user is manipulating. - const rect = SelectionUtil.getCursorRect(new Cursor( - sel.focusNode, sel.focusOffset, - TraverseUtil.getNodeText(sel.focusNode))); - - const yscroll = window.pageYOffset; - const pageHeight = window.innerHeight; - const caretY = rect.top; - const caretHeight = Math.min(rect.height, 30); - if (yscroll + pageHeight < caretY + caretHeight) { - window.scroll(0, (caretY + caretHeight - pageHeight + 100)); - } else if (caretY < yscroll) { - window.scroll(0, (caretY - 100)); - } - } - - if (Math.abs(previousX - this.caretX) > 500 || - Math.abs(previousY - this.caretY) > 100) { - if (Storage.onJump === FlourishType.ANIMATE) { - this.animateCaretElement(); - } else if (Storage.onJump === FlourishType.FLASH) { - this.flashCaretElement(); - } - } - } - - /** - * Determines if the modifier key is held down that should cause - * the cursor to move by word rather than by character. - * @param {Event} evt A keyboard event. - * @return {boolean} True if the cursor should move by word. - */ - isMoveByWordEvent(evt) { - if (this.isMac) { - return evt.altKey; - } else { - return evt.ctrlKey; - } - } - - /** - * Moves the cursor forwards to the next valid position. - * @param {Cursor} cursor The current cursor location. - * On exit, the cursor will be at the next position. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @return {?string} The character reached, or null if the bottom of the - * document has been reached. - */ - forwards(cursor, nodesCrossed) { - const previousCursor = cursor.clone(); - const result = TraverseUtil.forwardsChar(cursor, nodesCrossed); - - // Work around the fact that TraverseUtil.forwardsChar returns once per - // char in a block of text, rather than once per possible selection - // position in a block of text. - if (result && cursor.node != previousCursor.node && cursor.index > 0) { - cursor.index = 0; - } - - return result; - } - - /** - * Moves the cursor backwards to the previous valid position. - * @param {Cursor} cursor The current cursor location. - * On exit, the cursor will be at the previous position. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @return {?string} The character reached, or null if the top of the - * document has been reached. - */ - backwards(cursor, nodesCrossed) { - const previousCursor = cursor.clone(); - const result = TraverseUtil.backwardsChar(cursor, nodesCrossed); - - // Work around the fact that TraverseUtil.backwardsChar returns once per - // char in a block of text, rather than once per possible selection - // position in a block of text. - if (result && - cursor.node != previousCursor.node && - cursor.index < cursor.text.length) { - cursor.index = cursor.text.length; - } - - return result; - } - - /** - * Called when the user presses the right arrow. If there's a selection, - * moves the cursor to the end of the selection range. If it's a cursor, - * moves past one character. - * @param {Event} evt The DOM event. - * @return {boolean} True if the default action should be performed. - */ - moveRight(evt) { - this.targetX = null; - - const sel = window.getSelection(); - if (!evt.shiftKey && !SelectionUtil.isCollapsed(sel)) { - const right = SelectionUtil.makeRightCursor(sel); - SelectionUtil.setAndValidateSelection(right, right); - return false; - } - - const start = SelectionUtil.isAmbiguous(sel) ? - SelectionUtil.makeLeftCursor(sel) : - SelectionUtil.makeAnchorCursor(sel); - const end = SelectionUtil.isAmbiguous(sel) ? - SelectionUtil.makeRightCursor(sel) : - SelectionUtil.makeFocusCursor(sel); - let previousEnd = end.clone(); - const nodesCrossed = []; - while (true) { - let result; - if (this.isMoveByWordEvent(evt)) { - result = TraverseUtil.getNextWord(previousEnd, end, nodesCrossed); - } else { - previousEnd = end.clone(); - result = this.forwards(end, nodesCrossed); - } - - if (result === null) { - return this.moveLeft(evt); - } - - if (SelectionUtil.setAndValidateSelection( - evt.shiftKey ? start : end, end)) { - break; - } - } - - if (!evt.shiftKey) { - nodesCrossed.push(end.node); - NodeUtil.setFocusToFirstFocusable(nodesCrossed); - } - - return false; - } - - /** - * Called when the user presses the left arrow. If there's a selection, - * moves the cursor to the start of the selection range. If it's a cursor, - * moves backwards past one character. - * @param {Event} evt The DOM event. - * @return {boolean} True if the default action should be performed. - */ - moveLeft(evt) { - this.targetX = null; - - const sel = window.getSelection(); - if (!evt.shiftKey && !SelectionUtil.isCollapsed(sel)) { - const left = SelectionUtil.makeLeftCursor(sel); - SelectionUtil.setAndValidateSelection(left, left); - return false; - } - - const start = SelectionUtil.isAmbiguous(sel) ? - SelectionUtil.makeLeftCursor(sel) : - SelectionUtil.makeFocusCursor(sel); - const end = SelectionUtil.isAmbiguous(sel) ? - SelectionUtil.makeRightCursor(sel) : - SelectionUtil.makeAnchorCursor(sel); - let previousStart = start.clone(); - const nodesCrossed = []; - while (true) { - let result; - if (this.isMoveByWordEvent(evt)) { - result = TraverseUtil.getPreviousWord( - start, previousStart, nodesCrossed); - } else { - previousStart = start.clone(); - result = this.backwards(start, nodesCrossed); - } - - if (result === null) { - break; - } - - if (SelectionUtil.setAndValidateSelection( - evt.shiftKey ? end : start, start)) { - break; - } - } - - if (!evt.shiftKey) { - nodesCrossed.push(start.node); - NodeUtil.setFocusToFirstFocusable(nodesCrossed); - } - - return false; - } - - - /** - * Called when the user presses the down arrow. If there's a selection, - * moves the cursor to the end of the selection range. If it's a cursor, - * attempts to move to the equivalent horizontal pixel position in the - * subsequent line of text. If this is impossible, go to the first character - * of the next line. - * @param {Event} evt The DOM event. - * @return {boolean} True if the default action should be performed. - */ - moveDown(evt) { - const sel = window.getSelection(); - if (!evt.shiftKey && !SelectionUtil.isCollapsed(sel)) { - const right = SelectionUtil.makeRightCursor(sel); - SelectionUtil.setAndValidateSelection(right, right); - return false; - } - - const start = SelectionUtil.isAmbiguous(sel) ? - SelectionUtil.makeLeftCursor(sel) : - SelectionUtil.makeAnchorCursor(sel); - const end = SelectionUtil.isAmbiguous(sel) ? - SelectionUtil.makeRightCursor(sel) : - SelectionUtil.makeFocusCursor(sel); - const endRect = SelectionUtil.getCursorRect(end); - if (this.targetX === null) { - this.targetX = endRect.left; - } - const previousEnd = end.clone(); - let leftPos = end.clone(); - const rightPos = end.clone(); - let bestPos = null; - let bestY = null; - let bestDelta = null; - let bestHeight = null; - const nodesCrossed = []; - let y = -1; - while (true) { - if (null === this.forwards(rightPos, nodesCrossed)) { - if (SelectionUtil.setAndValidateSelection( - evt.shiftKey ? start : leftPos, leftPos)) { - break; - } else { - return this.moveLeft(evt); - } - break; - } - const range = document.createRange(); - range.setStart(leftPos.node, leftPos.index); - range.setEnd(rightPos.node, rightPos.index); - const rect = range.getBoundingClientRect(); - if (rect && rect.width < rect.height) { - y = rect.top + window.pageYOffset; - - // Return the best match so far if we get half a line past the best. - if (bestY != null && y > bestY + bestHeight / 2) { - if (SelectionUtil.setAndValidateSelection( - evt.shiftKey ? start : bestPos, bestPos)) { - break; - } else { - bestY = null; - } - } - - // Stop here if we're an entire line the wrong direction - // (for example, we reached the top of the next column). - if (y < endRect.top - endRect.height) { - if (SelectionUtil.setAndValidateSelection( - evt.shiftKey ? start : leftPos, leftPos)) { - break; - } - } - - // Otherwise look to see if this current position is on the - // next line and better than the previous best match, if any. - if (y >= endRect.top + endRect.height) { - const deltaLeft = Math.abs(this.targetX - rect.left); - if ((bestDelta == null || deltaLeft < bestDelta) && - (leftPos.node != end.node || leftPos.index != end.index)) { - bestPos = leftPos.clone(); - bestY = y; - bestDelta = deltaLeft; - bestHeight = rect.height; - } - const deltaRight = Math.abs(this.targetX - rect.right); - if (bestDelta == null || deltaRight < bestDelta) { - bestPos = rightPos.clone(); - bestY = y; - bestDelta = deltaRight; - bestHeight = rect.height; - } - - // Return the best match so far if the deltas are getting worse, - // not better. - if (bestDelta != null && - deltaLeft > bestDelta && - deltaRight > bestDelta) { - if (SelectionUtil.setAndValidateSelection( - evt.shiftKey ? start : bestPos, bestPos)) { - break; - } else { - bestY = null; - } - } - } - } - leftPos = rightPos.clone(); - } - - if (!evt.shiftKey) { - NodeUtil.setFocusToNode(leftPos.node); - } - - return false; - } - - /** - * Called when the user presses the up arrow. If there's a selection, - * moves the cursor to the start of the selection range. If it's a cursor, - * attempts to move to the equivalent horizontal pixel position in the - * previous line of text. If this is impossible, go to the last character - * of the previous line. - * @param {Event} evt The DOM event. - * @return {boolean} True if the default action should be performed. - */ - moveUp(evt) { - const sel = window.getSelection(); - if (!evt.shiftKey && !SelectionUtil.isCollapsed(sel)) { - const left = SelectionUtil.makeLeftCursor(sel); - SelectionUtil.setAndValidateSelection(left, left); - return false; - } - - const start = SelectionUtil.isAmbiguous(sel) ? - SelectionUtil.makeLeftCursor(sel) : - SelectionUtil.makeFocusCursor(sel); - const end = SelectionUtil.isAmbiguous(sel) ? - SelectionUtil.makeRightCursor(sel) : - SelectionUtil.makeAnchorCursor(sel); - const startRect = SelectionUtil.getCursorRect(start); - if (this.targetX === null) { - this.targetX = startRect.left; - } - const previousStart = start.clone(); - const leftPos = start.clone(); - let rightPos = start.clone(); - let bestPos = null; - let bestY = null; - let bestDelta = null; - let bestHeight = null; - const nodesCrossed = []; - let y = 999999; - while (true) { - if (null === this.backwards(leftPos, nodesCrossed)) { - SelectionUtil.setAndValidateSelection( - evt.shiftKey ? end : rightPos, rightPos); - break; - } - const range = document.createRange(); - range.setStart(leftPos.node, leftPos.index); - range.setEnd(rightPos.node, rightPos.index); - const rect = range.getBoundingClientRect(); - if (rect && rect.width < rect.height) { - y = rect.top + window.pageYOffset; - - // Return the best match so far if we get half a line past the best. - if (bestY != null && y < bestY - bestHeight / 2) { - if (SelectionUtil.setAndValidateSelection( - evt.shiftKey ? end : bestPos, bestPos)) { - break; - } else { - bestY = null; - } - } - - // Exit if we're an entire line the wrong direction - // (for example, we reached the bottom of the previous column.) - if (y > startRect.top + startRect.height) { - if (SelectionUtil.setAndValidateSelection( - evt.shiftKey ? end : rightPos, rightPos)) { - break; - } - } - - // Otherwise look to see if this current position is on the - // next line and better than the previous best match, if any. - if (y <= startRect.top - startRect.height) { - const deltaLeft = Math.abs(this.targetX - rect.left); - if (bestDelta == null || deltaLeft < bestDelta) { - bestPos = leftPos.clone(); - bestY = y; - bestDelta = deltaLeft; - bestHeight = rect.height; - } - const deltaRight = Math.abs(this.targetX - rect.right); - if ((bestDelta == null || deltaRight < bestDelta) && - (rightPos.node != start.node || rightPos.index != start.index)) { - bestPos = rightPos.clone(); - bestY = y; - bestDelta = deltaRight; - bestHeight = rect.height; - } - - // Return the best match so far if the deltas are getting worse, - // not better. - if (bestDelta != null && - deltaLeft > bestDelta && - deltaRight > bestDelta) { - if (SelectionUtil.setAndValidateSelection( - evt.shiftKey ? end : bestPos, bestPos)) { - break; - } else { - bestY = null; - } - } - } - } - rightPos = leftPos.clone(); - } - - if (!evt.shiftKey) { - NodeUtil.setFocusToNode(rightPos.node); - } - - return false; - } - - /** - * Set the document's selection to surround a control, so that the next - * arrow key they press will allow them to explore the content before - * or after a given control. - * @param {Node} control The control to escape from. - */ - escapeFromControl(control) { - control.blur(); - - let start = new Cursor(control, 0, ''); - let previousStart = start.clone(); - let end = new Cursor(control, 0, ''); - let previousEnd = end.clone(); - - const nodesCrossed = []; - while (true) { - if (null === this.backwards(start, nodesCrossed)) { - break; - } - - const r = document.createRange(); - r.setStart(start.node, start.index); - r.setEnd(previousStart.node, previousStart.index); - if (r.getBoundingClientRect()) { - break; - } - previousStart = start.clone(); - } - while (true) { - if (null === this.forwards(end, nodesCrossed)) { - break; - } - if (NodeUtil.isDescendantOfNode(end.node, control)) { - previousEnd = end.clone(); - continue; - } - - const r = document.createRange(); - r.setStart(previousEnd.node, previousEnd.index); - r.setEnd(end.node, end.index); - if (r.getBoundingClientRect()) { - break; - } - } - - if (!NodeUtil.isDescendantOfNode(previousStart.node, control)) { - start = previousStart.clone(); - } - - if (!NodeUtil.isDescendantOfNode(previousEnd.node, control)) { - end = previousEnd.clone(); - } - - SelectionUtil.setAndValidateSelection(start, end); - - window.setTimeout(() => { - this.updateCaretOrSelection(true); - }, 0); - } - - /** - * Toggle whether caret browsing is enabled or not. - */ - toggle() { - if (this.forceEnabled) { - this.recreateCaretElement(); - return; - } - - Storage.enabled = !Storage.enabled; - this.updateIsCaretVisible(); - } - - /** - * Event handler, called when a key is pressed. - * @param {Event} evt The DOM event. - * @return {boolean} True if the default action should be performed. - */ - onKeyDown(evt) { - if (evt.defaultPrevented) { - return; - } - - if (evt.keyCode == 118) { // F7 - this.toggle(); - } - - if (!Storage.enabled) { - return true; - } - - if (evt.target && - NodeUtil.isControlThatNeedsArrowKeys( - /** @type (Node) */ (evt.target))) { - if (evt.keyCode == 27) { - this.escapeFromControl(/** @type {Node} */(evt.target)); - evt.preventDefault(); - evt.stopPropagation(); - return false; - } else { - return true; - } - } - - // If the current selection doesn't have a range, try to escape out of - // the current control. If that fails, return so we don't fail whe - // trying to move the cursor or selection. - let sel = window.getSelection(); - if (sel.rangeCount == 0) { - if (document.activeElement) { - this.escapeFromControl(document.activeElement); - sel = window.getSelection(); - } - - if (sel.rangeCount == 0) { - return true; - } - } - - if (this.caretElement) { - this.caretElement.style.visibility = 'visible'; - this.blinkFlag = true; - } - - let result = true; - switch (evt.keyCode) { - case 37: - result = this.moveLeft(evt); - break; - case 38: - result = this.moveUp(evt); - break; - case 39: - result = this.moveRight(evt); - break; - case 40: - result = this.moveDown(evt); - break; - } - - if (result == false) { - evt.preventDefault(); - evt.stopPropagation(); - } - - window.setTimeout(() => { - this.updateCaretOrSelection(result == false); - }, 0); - - return result; - } - - /** - * Event handler, called when the mouse is clicked. Chrome already - * sets the selection when the mouse is clicked, all we need to do is - * update our cursor. - * @param {Event} evt The DOM event. - * @return {boolean} True if the default action should be performed. - */ - onClick(evt) { - if (!Storage.enabled) { - return true; - } - window.setTimeout(() => { - this.targetX = null; - this.updateCaretOrSelection(false); - }, 0); - return true; - } - - /** - * Called at a regular interval. Blink the cursor by changing its visibility. - */ - caretBlinkFunction() { - if (this.caretElement) { - if (this.blinkFlag) { - this.caretElement.style.backgroundColor = - this.caretForeground; - this.blinkFlag = false; - } else { - this.caretElement.style.backgroundColor = - this.caretBackground; - this.blinkFlag = true; - } - } - } - - /** - * Update whether or not the caret is visible, based on whether caret browsing - * is enabled and whether this window / iframe has focus. - */ - updateIsCaretVisible() { - this.isCaretVisible = - (Storage.enabled && this.isWindowFocused); - if (this.isCaretVisible && !this.caretElement) { - this.setInitialCursor(); - this.updateCaretOrSelection(true); - if (this.caretElement) { - this.blinkFunctionId = window.setInterval( - this.caretBlinkFunction, 500); - } - } else if (!this.isCaretVisible && - this.caretElement) { - window.clearInterval(this.blinkFunctionId); - if (this.caretElement) { - this.isSelectionCollapsed = false; - this.caretElement.parentElement.removeChild( - this.caretElement); - this.caretElement = null; - } - } - } - - /** - * Called when the prefs get updated. - */ - onPrefsUpdated() { - this.recreateCaretElement(); - } - - /** - * Called when this window / iframe gains focus. - */ - onWindowFocus() { - this.isWindowFocused = true; - this.updateIsCaretVisible(); - } - - /** - * Called when this window / iframe loses focus. - */ - onWindowBlur() { - this.isWindowFocused = false; - this.updateIsCaretVisible(); - } - - /** - * Initializes caret browsing by adding event listeners and extension - * message listeners. - */ - init() { - this.isWindowFocused = document.hasFocus(); - - document.addEventListener('keydown', this.onKeyDown.bind(this), false); - document.addEventListener('click', this.onClick.bind(this), false); - window.addEventListener('focus', this.onWindowFocus.bind(this), false); - window.addEventListener('blur', this.onWindowBlur.bind(this), false); - } -} - -window.setTimeout(() => { - - // Make sure the script only loads once. - if (!window['caretBrowsingLoaded']) { - window['caretBrowsingLoaded'] = true; - window.caretBrowsing = new CaretBrowsing(); - - if (document.body.getAttribute('caretbrowsing') == 'on') { - caretBrowsing.forceEnabled = true; - Storage.enabled = true; - caretBrowsing.updateIsCaretVisible(); - } - - Storage.ENABLED.listeners.push(() => caretBrowsing.onPrefsUpdated()); - Storage.ON_ENABLE.listeners.push(() => caretBrowsing.onPrefsUpdated()); - Storage.ON_JUMP.listeners.push(() => caretBrowsing.onPrefsUpdated()); - - caretBrowsing.onPrefsUpdated(); - } - -}, 0);
diff --git a/ui/accessibility/extensions/caretbrowsing/increase_brightness.png b/ui/accessibility/extensions/caretbrowsing/increase_brightness.png deleted file mode 100644 index 7f427fb9..0000000 --- a/ui/accessibility/extensions/caretbrowsing/increase_brightness.png +++ /dev/null Binary files differ
diff --git a/ui/accessibility/extensions/caretbrowsing/manifest.json b/ui/accessibility/extensions/caretbrowsing/manifest.json index 07299d0..67f963bf 100644 --- a/ui/accessibility/extensions/caretbrowsing/manifest.json +++ b/ui/accessibility/extensions/caretbrowsing/manifest.json
@@ -1,13 +1,8 @@ { "name": "__MSG_CARET_BROWSING_APPNAME__", - "version": "1.0.2", + "version": "1.1.0", "description": "__MSG_CARET_BROWSING_APPDESC__", "manifest_version": 3, - "permissions": [ - "scripting", - "storage" - ], - "host_permissions": [ "<all_urls>" ], "background": { "service_worker": "background.js" }, @@ -15,30 +10,10 @@ "default_icon": "caret_19.png", "default_title": "__MSG_CARET_BROWSING_APPNAME__" }, - "content_scripts": [ - { - "matches": [ - "<all_urls>" - ], - "all_frames": true, - "css": [ - "caretbrowsing.css" - ], - "js": [ - "axs_testing.js", - "traverse_util.js", - "node_util.js", - "selection_util.js", - "storage.js", - "caretbrowsing.js" - ] - } - ], "default_locale": "en", "icons": { "16": "caret_16.png", "48": "caret_48.png", "128": "caret_128.png" - }, - "options_page": "options.html" + } }
diff --git a/ui/accessibility/extensions/caretbrowsing/node_util.js b/ui/accessibility/extensions/caretbrowsing/node_util.js deleted file mode 100644 index c87d017..0000000 --- a/ui/accessibility/extensions/caretbrowsing/node_util.js +++ /dev/null
@@ -1,164 +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. - -/** A collection of functions for dealing with DOM nodes. */ -class NodeUtil { - /** - * Return whether a node is focusable. This includes nodes whose tabindex - * attribute is set to "-1" explicitly - these nodes are not in the tab - * order, but they should still be focused if the user navigates to them - * using linear or smart DOM navigation. - * - * Note that when the tabIndex property of an Element is -1, that doesn't - * tell us whether the tabIndex attribute is missing or set to "-1" - * explicitly, so we have to check the attribute. - * - * @param {Object} targetNode The node to check if it's focusable. - * @return {boolean} True if the node is focusable. - */ - static isFocusable(targetNode) { - if (!targetNode || typeof (targetNode.tabIndex) != 'number') { - return false; - } - - if (targetNode.tabIndex >= 0) { - return true; - } - - if (targetNode.hasAttribute && targetNode.hasAttribute('tabindex') && - targetNode.getAttribute('tabindex') == '-1') { - return true; - } - - return false; - } - - /** - * Determines whether or not a node is or is the descendant of another node. - * - * @param {Object} node The node to be checked. - * @param {Object} ancestor The node to see if it's a descendant of. - * @return {boolean} True if the node is ancestor or is a descendant of it. - */ - static isDescendantOfNode(node, ancestor) { - while (node && ancestor) { - if (node.isSameNode(ancestor)) { - return true; - } - node = node.parentNode; - } - return false; - } - - /** - * Check if a node is a control that normally allows the user to interact - * with it using arrow keys. We won't override the arrow keys when such a - * control has focus, the user must press Escape to do caret browsing outside - * that control. - * @param {Node} node A node to check. - * @return {boolean} True if this node is a control that the user can - * interact with using arrow keys. - */ - static isControlThatNeedsArrowKeys(node) { - if (!node) { - return false; - } - - if (node == document.body || node != document.activeElement) { - return false; - } - - if (node.constructor == HTMLSelectElement) { - return true; - } - - if (node.constructor == HTMLInputElement) { - switch (node.type) { - case 'email': - case 'number': - case 'password': - case 'search': - case 'text': - case 'tel': - case 'url': - case '': - return true; // All of these are text boxes. - case 'datetime': - case 'datetime-local': - case 'date': - case 'month': - case 'radio': - case 'range': - case 'week': - return true; // These are other input elements that use arrows. - } - } - - // Handle focusable ARIA controls. - if (node.getAttribute && NodeUtil.isFocusable(node)) { - const role = node.getAttribute('role'); - switch (role) { - case 'combobox': - case 'grid': - case 'gridcell': - case 'listbox': - case 'menu': - case 'menubar': - case 'menuitem': - case 'menuitemcheckbox': - case 'menuitemradio': - case 'option': - case 'radiogroup': - case 'scrollbar': - case 'slider': - case 'spinbutton': - case 'tab': - case 'tablist': - case 'textbox': - case 'tree': - case 'treegrid': - case 'treeitem': - return true; - } - } - - return false; - } - - /** - * Set focus to a node if it's focusable. If it's an input element, - * select the text, otherwise it doesn't appear focused to the user. - * Every other control behaves normally if you just call focus() on it. - * @param {Node} node The node to focus. - * @return {boolean} True if the node was focused. - */ - static setFocusToNode(node) { - while (node && node != document.body) { - if (NodeUtil.isFocusable(node) && node.constructor != HTMLIFrameElement) { - node.focus(); - if (node.constructor == HTMLInputElement && node.select) { - node.select(); - } - return true; - } - node = node.parentNode; - } - - return false; - } - - /** - * Set focus to the first focusable node in the given list. - * @param {!Array<!Node>} nodeList An array of nodes to focus. - * @return {boolean} True if the node was focused. - */ - static setFocusToFirstFocusable(nodeList) { - for (let i = 0; i < nodeList.length; i++) { - if (NodeUtil.setFocusToNode(nodeList[i])) { - return true; - } - } - return false; - } -}
diff --git a/ui/accessibility/extensions/caretbrowsing/node_util_test.js b/ui/accessibility/extensions/caretbrowsing/node_util_test.js deleted file mode 100644 index 38825f7..0000000 --- a/ui/accessibility/extensions/caretbrowsing/node_util_test.js +++ /dev/null
@@ -1,171 +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. - -GEN_INCLUDE(['node_util.js']); - -GEN_INCLUDE(['../testing/webstore_extension_test_base.js']); - -/** Test fixture for node_util.js. */ -NodeUtilUnitTest = class extends WebstoreExtensionTest {}; - -TEST_F('NodeUtilUnitTest', 'IsFocusable', function() { - assertFalse(NodeUtil.isFocusable(null)); - - // Nodes with no tab index are not focusable. - const noTabIndex = document.createElement('div'); - assertFalse(NodeUtil.isFocusable(noTabIndex)); - - // Nodes with a positive number tab index are focusable. - const positiveTabIndex = document.createElement('div'); - positiveTabIndex.tabIndex = 1; - assertTrue(NodeUtil.isFocusable(positiveTabIndex)); - - // Nodes with a tab index of 0 are focusable. - const zeroTabIndex = document.createElement('div'); - zeroTabIndex.tabIndex = 0; - assertTrue(NodeUtil.isFocusable(zeroTabIndex)); - - // Some nodes have an implicit non-negative tab index. - const button = document.createElement('button'); - assertTrue(NodeUtil.isFocusable(button)); - - // Nodes with a negative tab index that's not -1 are not focusable. - const negativeTwoTabIndex = document.createElement('button'); - negativeTwoTabIndex.tabIndex = -2; - assertFalse(NodeUtil.isFocusable(negativeTwoTabIndex)); - - // Nodes with an explicitly set tab index of -1 are focusable. - const negativeOneDiv = document.createElement('div'); - negativeOneDiv.tabIndex = -1; - assertTrue(NodeUtil.isFocusable(negativeOneDiv)); - - const negativeOneButton = document.createElement('button'); - negativeOneButton.tabIndex = -1; - assertTrue(NodeUtil.isFocusable(negativeOneButton)); -}); - -TEST_F('NodeUtilUnitTest', 'IsDescendantOfNode', function() { - const grandparent = document.createElement('div'); - const parent = document.createElement('p'); - const child = document.createElement('span'); - const orphan = document.createElement('img'); - - grandparent.appendChild(parent); - parent.appendChild(child); - - assertTrue(NodeUtil.isDescendantOfNode(parent, grandparent)); - assertTrue(NodeUtil.isDescendantOfNode(child, grandparent)); - assertTrue(NodeUtil.isDescendantOfNode(child, parent)); - - assertFalse(NodeUtil.isDescendantOfNode(orphan, parent)); - assertFalse(NodeUtil.isDescendantOfNode(orphan, grandparent)); - assertFalse(NodeUtil.isDescendantOfNode(orphan, parent)); - - assertFalse(NodeUtil.isDescendantOfNode(grandparent, parent)); - assertFalse(NodeUtil.isDescendantOfNode(grandparent, child)); - assertFalse(NodeUtil.isDescendantOfNode(parent, child)); - assertFalse(NodeUtil.isDescendantOfNode(grandparent, orphan)); - assertFalse(NodeUtil.isDescendantOfNode(parent, orphan)); - assertFalse(NodeUtil.isDescendantOfNode(child, orphan)); -}); - -TEST_F('NodeUtilUnitTest', 'SetFocusToNode', function() { - let focusCount; - let selectCount; - - // Calling on a focusable node should focus that node. - const button = document.createElement('button'); - button.focus = () => focusCount++; - button.select = () => selectCount--; - - focusCount = 0; - selectCount = 0; - assertTrue(NodeUtil.setFocusToNode(button)); - assertEquals(1, focusCount); - assertEquals(0, selectCount); - - // Calling on an iframe (even a focusable one) should not focus anything. - const iframe = document.createElement('iframe'); - iframe.tabIndex = 0; - iframe.focus = () => focusCount--; - iframe.select = () => selectCount--; - - focusCount = 0; - selectCount = 0; - assertFalse(NodeUtil.setFocusToNode(iframe)); - assertEquals(0, focusCount); - assertEquals(0, selectCount); - - // Calling on a focusable input should select the input contents. - const input = document.createElement('input'); - input.focus = () => focusCount++; - input.select = () => selectCount++; - - focusCount = 0; - selectCount = 0; - assertTrue(NodeUtil.setFocusToNode(input)); - assertEquals(1, focusCount); - assertEquals(1, selectCount); - - // Calling on the child of a focusable node should focus the parent. - const focusableDiv = document.createElement('div'); - focusableDiv.tabIndex = 0; - focusableDiv.focus = () => focusCount++; - focusableDiv.select = () => selectCount--; - const p = document.createElement('p'); - p.focus = () => focusCount--; - p.select = () => selectCount--; - focusableDiv.appendChild(p); - - focusCount = 0; - selectCount = 0; - assertTrue(NodeUtil.setFocusToNode(p)); - assertEquals(1, focusCount); - assertEquals(0, selectCount); - - // Calling on a non-focusable node with no ancestors other than document.body - // should return false. - const img = document.createElement('img'); - img.focus = () => focusCount--; - img.select = () => selectCount--; - document.body.appendChild(img); - document.body.focus = () => focusCount--; - document.body.select = () => selectCount--; - - focusCount = 0; - selectCount = 0; - assertFalse(NodeUtil.setFocusToNode(img)); - assertEquals(0, focusCount); - assertEquals(0, selectCount); -}); - -TEST_F('NodeUtilUnitTest', 'SetFocusToFirstFocusable', function() { - let focusACount = 0; - let focusPCount = 0; - let focusButtonCount = 0; - - const a = document.createElement('a'); - a.focus = () => focusACount++; - const p = document.createElement('p'); - p.focus = () => focusPCount++; - const button = document.createElement('button'); - button.focus = () => focusButtonCount++; - - assertTrue(NodeUtil.setFocusToFirstFocusable([a, p, button])); - assertEquals(1, focusACount); - assertEquals(0, focusPCount); - assertEquals(0, focusButtonCount); - - focusACount = 0; - assertTrue(NodeUtil.setFocusToFirstFocusable([p, button, a])); - assertEquals(0, focusACount); - assertEquals(0, focusPCount); - assertEquals(1, focusButtonCount); - - // Passing in a list with no focusable elements returns false. - assertFalse(NodeUtil.setFocusToFirstFocusable([p])); - - // Passing in an empty list returns false. - assertFalse(NodeUtil.setFocusToFirstFocusable([])); -});
diff --git a/ui/accessibility/extensions/caretbrowsing/options.html b/ui/accessibility/extensions/caretbrowsing/options.html deleted file mode 100644 index 0a93302..0000000 --- a/ui/accessibility/extensions/caretbrowsing/options.html +++ /dev/null
@@ -1,160 +0,0 @@ -<html> -<head> - <title>Caret Browsing Options</title> - <style> - body { - font-family: Lucida Grande, sans-serif, arial, helvetica; - width: 920px; - margin-left: auto; - margin-right: auto; - } - .banner { - width: 100%; - float: left; - } - .banner_left { - padding: 8px; - float: left; - } - .banner_right { - padding: 8px; - } - .body_wrapper { - width: 100%; - float: left; - } - .body_left { - border: 0; - padding: 0; - margin: 0; - width: 50%; - float: left; - } - .body_right { - border: 0; - padding: 0; - margin: 0; - width: 46%; - float: left; - } - .body_inner { - padding: 0 32px; - } - body.mac .nonmac { - display: none; - } - body.nonmac .mac { - display: none; - } - body.cros .noncros { - display: none; - } - body.noncros .cros { - display: none; - } - .key { - border: 1px solid #666; - color: #444; - padding: 0.2em 0.8em; - margin: 0 0.3em; - background: #eee; - } - p { - line-height: 1.6em; - } - fieldset { - margin-bottom: 1em; - } - fieldset div { - margin: 0.6em 0; - } - p.cros img { - vertical-align: middle; - } - </style> - <link href="caretbrowsing.css" rel="stylesheet" type="text/css"> - <script src="axs_testing.js"></script> - <script src="traverse_util.js"></script> - <script src="storage.js"></script> - <script src="caretbrowsing.js"></script> - <script src="options.js"></script> -</head> -<body caretbrowsing="on"> - -<div class="banner"> - <div class="banner_left"> - <img src="caret_128.png" class="logo" alt=""> - </div> - <div class="banner_right"> - <h1 i18n-content="caret_browsing_appName"></h1> - <p i18n-content="caret_browsing_subheading1"></p> - <p i18n-content="caret_browsing_subheading2"></p> - </div> -</div> - -<div class="body_wrapper"> - <div class="body_left"> - <div class="body_inner"> - <h2 i18n-content="caret_browsing_keyboardCommands"></h2> - - <p class="noncros" i18n-content="caret_browsing_enableDisableNonCros"></p> - <p class="cros" i18n-content="caret_browsing_enableDisableCros"></p> - - <div i18n-content="caret_browsing_navHelp"></div> - - <p class="nonmac" i18n-content="caret_browsing_moveByWordsNonMac"></p> - <p class="mac" i18n-content="caret_browsing_moveByWordsMac"></p> - - <div i18n-content="caret_browsing_focusHelp"></div> - </div> - </div> - <div class="body_right"> - <div class="body_inner"> - <h2></h2> - - <fieldset> - <legend i18n-content="caret_browsing_whenEnabled"></legend> - - <div> - <input type="radio" id="onenable_anim" name="onenable" value="anim"> - <label for="onenable_anim" i18n-content="caret_browsing_animation"></label> - </div> - - <div> - <input type="radio" id="onenable_flash" name="onenable" value="flash"> - <label for="onenable_flash" i18n-content="caret_browsing_flash"></label> - </div> - - <div> - <input type="radio" id="onenable_nothing" name="onenable" value="none"> - <label for="onenable_nothing" i18n-content="caret_browsing_noFeedback"></label> - </div> - - </fieldset> - - <fieldset> - <legend i18n-content="caret_browsing_jump"></legend> - - <div> - <input type="radio" id="onjump_anim" name="onjump" value="anim"> - <label for="onjump_anim" i18n-content="caret_browsing_animation"></label> - </div> - - <div> - <input type="radio" id="onjump_flash" name="onjump" value="flash"> - <label for="onjump_flash" i18n-content="caret_browsing_flash"></label> - </div> - - <div> - <input type="radio" id="onjump_nothing" name="onjump" value="none"> - <label for="onjump_nothing" i18n-content="caret_browsing_noFeedback"></label> - </div> - - </fieldset> - - </div> - </div> -</div> - -</body> -</html>
diff --git a/ui/accessibility/extensions/caretbrowsing/options.js b/ui/accessibility/extensions/caretbrowsing/options.js deleted file mode 100644 index 1a2a9e5..0000000 --- a/ui/accessibility/extensions/caretbrowsing/options.js +++ /dev/null
@@ -1,56 +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. */ - -Storage.initialize(); - -function setRadio(name, defaultValue) { - let value = Storage[name]; - const controls = document.querySelectorAll( - 'input[type="radio"][name="' + name + '"]'); - for (let i = 0; i < controls.length; i++) { - const c = controls[i]; - if (c.value == value) { - c.checked = true; - } - c.addEventListener('change', function(evt) { - if (evt.target.checked) { - Storage[evt.target.name] = evt.target.value; - } - }, false); - } -} - -function load() { - const isMac = (navigator.appVersion.indexOf("Mac") != -1); - if (isMac) { - document.body.classList.add('mac'); - } else { - document.body.classList.add('nonmac'); - } - - const isCros = (navigator.appVersion.indexOf("CrOS") != -1); - if (isCros) { - document.body.classList.add('cros'); - } else { - document.body.classList.add('noncros'); - } - - setRadio('onenable', 'anim'); - setRadio('onjump', 'flash'); - - const heading = document.querySelector('h1'); - const sel = window.getSelection(); - sel.setBaseAndExtent(heading, 0, heading, 0); - - document.title = - chrome.i18n.getMessage('caret_browsing_caretBrowsingOptions'); - const i18nElements = document.querySelectorAll('*[i18n-content]'); - for (let i = 0; i < i18nElements.length; i++) { - const elem = i18nElements[i]; - const msg = elem.getAttribute('i18n-content'); - elem.innerHTML = chrome.i18n.getMessage(msg); - } -} - -window.addEventListener('load', load, false);
diff --git a/ui/accessibility/extensions/caretbrowsing/selection_util.js b/ui/accessibility/extensions/caretbrowsing/selection_util.js deleted file mode 100644 index b03e901..0000000 --- a/ui/accessibility/extensions/caretbrowsing/selection_util.js +++ /dev/null
@@ -1,162 +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. - -/** A collection of functions for dealing with selections. */ -class SelectionUtil { - /** - * Get the rectangle for a cursor position. This is tricky because - * you can't get the bounding rectangle of an empty range, so this function - * computes the rect by trying a range including one character earlier or - * later than the cursor position. - * @param {Cursor} cursor A single cursor position. - * @return {{left: number, top: number, width: number, height: number}} - * The bounding rectangle of the cursor. - */ - static getCursorRect(cursor) { - let node = cursor.node; - const index = cursor.index; - const rect = {left: 0, top: 0, width: 1, height: 0}; - if (node.constructor == Text) { - let left = index; - let right = index; - const max = node.data.length; - const newRange = document.createRange(); - while (left > 0 || right < max) { - if (left > 0) { - left--; - newRange.setStart(node, left); - newRange.setEnd(node, index); - const rangeRect = newRange.getBoundingClientRect(); - if (rangeRect && rangeRect.width && rangeRect.height) { - rect.left = rangeRect.right; - rect.top = rangeRect.top; - rect.height = rangeRect.height; - break; - } - } - if (right < max) { - right++; - newRange.setStart(node, index); - newRange.setEnd(node, right); - const rangeRect = newRange.getBoundingClientRect(); - if (rangeRect && rangeRect.width && rangeRect.height) { - rect.left = rangeRect.left; - rect.top = rangeRect.top; - rect.height = rangeRect.height; - break; - } - } - } - } else { - rect.height = node.offsetHeight; - while (node !== null) { - rect.left += node.offsetLeft; - rect.top += node.offsetTop; - node = node.offsetParent; - } - } - rect.left += window.pageXOffset; - rect.top += window.pageYOffset; - return rect; - } - - /** - * Return true if the selection directionality is ambiguous, which happens - * if, for example, the user double-clicks in the middle of a word to select - * it. In that case, the selection should extend by the right edge if the - * user presses right, and by the left edge if the user presses left. - * @param {Selection} sel The selection. - * @return {boolean} True if the selection directionality is ambiguous. - */ - static isAmbiguous(sel) { - return ( - sel.anchorNode != sel.baseNode || sel.anchorOffset != sel.baseOffset || - sel.focusNode != sel.extentNode || sel.focusOffset != sel.extentOffset); - } - - /** - * Create a Cursor from the anchor position of the selection, the - * part that doesn't normally move. - * @param {Selection} sel The selection. - * @return {Cursor} A cursor pointing to the selection's anchor location. - */ - static makeAnchorCursor(sel) { - return new Cursor( - sel.anchorNode, sel.anchorOffset, - TraverseUtil.getNodeText(sel.anchorNode)); - } - - /** - * Create a Cursor from the focus position of the selection. - * @param {Selection} sel The selection. - * @return {Cursor} A cursor pointing to the selection's focus location. - */ - static makeFocusCursor(sel) { - return new Cursor( - sel.focusNode, sel.focusOffset, - TraverseUtil.getNodeText(sel.focusNode)); - } - - /** - * Create a Cursor from the left boundary of the selection - the boundary - * closer to the start of the document. - * @param {Selection} sel The selection. - * @return {Cursor} A cursor pointing to the selection's left boundary. - */ - static makeLeftCursor(sel) { - const range = sel.rangeCount == 1 ? sel.getRangeAt(0) : null; - if (range && range.endContainer == sel.anchorNode && - range.endOffset == sel.anchorOffset) { - return SelectionUtil.makeFocusCursor(sel); - } else { - return SelectionUtil.makeAnchorCursor(sel); - } - } - - /** - * Create a Cursor from the right boundary of the selection - the boundary - * closer to the end of the document. - * @param {Selection} sel The selection. - * @return {Cursor} A cursor pointing to the selection's right boundary. - */ - static makeRightCursor(sel) { - const range = sel.rangeCount == 1 ? sel.getRangeAt(0) : null; - if (range && range.endContainer == sel.anchorNode && - range.endOffset == sel.anchorOffset) { - return SelectionUtil.makeAnchorCursor(sel); - } else { - return SelectionUtil.makeFocusCursor(sel); - } - } - - /** - * Try to set the window's selection to be between the given start and end - * cursors, and return whether or not it was successful. - * @param {Cursor} start The start position. - * @param {Cursor} end The end position. - * @return {boolean} True if the selection was successfully set. - */ - static setAndValidateSelection(start, end) { - const sel = window.getSelection(); - sel.setBaseAndExtent(start.node, start.index, end.node, end.index); - - if (sel.rangeCount != 1) { - return false; - } - - return ( - sel.anchorNode == start.node && sel.anchorOffset == start.index && - sel.focusNode == end.node && sel.focusOffset == end.index); - } - - /** - * Note: the built-in function by the same name is unreliable. - * @param {Selection} sel The selection. - * @return {boolean} True if the start and end positions are the same. - */ - static isCollapsed(sel) { - return ( - sel.anchorOffset == sel.focusOffset && sel.anchorNode == sel.focusNode); - } -}
diff --git a/ui/accessibility/extensions/caretbrowsing/selection_util_test.js b/ui/accessibility/extensions/caretbrowsing/selection_util_test.js deleted file mode 100644 index 0a75ff01..0000000 --- a/ui/accessibility/extensions/caretbrowsing/selection_util_test.js +++ /dev/null
@@ -1,169 +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. - -GEN_INCLUDE(['selection_util.js', 'traverse_util.js']); - -GEN_INCLUDE(['../testing/webstore_extension_test_base.js']); - -/** Test fixture for selection_util.js. */ -SelectionUtilUnitTest = class extends WebstoreExtensionTest {}; - -/** - * @param {chrome.automation.Rect} expected - * @param {chrome.automation.Rect} actual - * @return {boolean} - */ -function checkRect(expected, actual) { - assertEquals(expected.left, actual.left); - assertEquals(expected.top, actual.top); - assertEquals(expected.width, actual.width); - assertEquals(expected.height, actual.height); -} - -/** - * @param {Cursor} expected - * @param {Cursor} actual - * @return {boolean} - */ -function checkCursor(expected, actual) { - assertEquals(expected.node, actual.node); - assertEquals(expected.index, actual.index); - assertEquals(expected.text, actual.text); -} - -TEST_F('SelectionUtilUnitTest', 'GetCursorRect', function() { - const text = document.createTextNode('My Favorite Things'); - const div = document.createElement('div'); - div.appendChild(text); - document.body.appendChild(div); - div.style = 'position: absolute; left: 100px; top: 70px'; - - let cursor = new Cursor(text, 0, text.nodeValue); - let expected = {left: 100, top: 70, width: 1, height: 19}; - let actual = SelectionUtil.getCursorRect(cursor); - checkRect(expected, actual); - - cursor.index = 3; - expected = {left: 126, top: 70, width: 1, height: 19}; - actual = SelectionUtil.getCursorRect(cursor); - checkRect(expected, actual); - - const button = document.createElement('button'); - button.textContent = 'Get soundtrack'; - button.style = 'position: absolute; left: 10px; top: 0px'; - document.body.appendChild(button); - - cursor = new Cursor(button, 0, button.textContent); - expected = {left: 10, top: 0, width: 1, height: 22}; - actual = SelectionUtil.getCursorRect(cursor); - checkRect(expected, actual); -}); - -TEST_F('SelectionUtilUnitTest', 'IsAmbiguous', function() { - const text = - document.createTextNode('Raindrops on roses and whiskers on kittens'); - let selection = window.getSelection(); - selection.setBaseAndExtent(text, 13, text, 31); /* roses and whiskers */ - assertFalse(SelectionUtil.isAmbiguous(selection)); - - selection.setBaseAndExtent(text, 31, text, 13); - assertFalse(SelectionUtil.isAmbiguous(selection)); - - // Mock a situation where the selection is ambiguous. - selection = { - anchorNode: text, - baseNode: text, - anchorOffset: 13, - baseOffset: 31, - focusNode: text, - extentNode: text, - focusOffset: 31, - extentOffset: 13 - }; - assertTrue(SelectionUtil.isAmbiguous(selection)); -}); - -TEST_F('SelectionUtilUnitTest', 'MakeCursor', function() { - const text = - document.createTextNode('Bright copper kettles and warm woolen mittens'); - document.body.appendChild(text); - - const selection = window.getSelection(); - selection.setBaseAndExtent(text, 7, text, 21); /* copper kettles */ - - const leftCursor = new Cursor(text, 7, text.nodeValue); - const rightCursor = new Cursor(text, 21, text.nodeValue); - - let actual = SelectionUtil.makeAnchorCursor(selection); - checkCursor(leftCursor, actual); - - actual = SelectionUtil.makeFocusCursor(selection); - checkCursor(rightCursor, actual); - - actual = SelectionUtil.makeLeftCursor(selection); - checkCursor(leftCursor, actual); - - actual = SelectionUtil.makeRightCursor(selection); - checkCursor(rightCursor, actual); - - // Reverse the focus and anchor. - selection.setBaseAndExtent(text, 21, text, 7); - - actual = SelectionUtil.makeAnchorCursor(selection); - checkCursor(rightCursor, actual); - - actual = SelectionUtil.makeFocusCursor(selection); - checkCursor(leftCursor, actual); - - actual = SelectionUtil.makeLeftCursor(selection); - checkCursor(leftCursor, actual); - - actual = SelectionUtil.makeRightCursor(selection); - checkCursor(rightCursor, actual); -}); - -TEST_F('SelectionUtilUnitTest', 'SetAndValidateSelection', function() { - const text = - document.createTextNode('Brown paper packages tied up with strings'); - const start = new Cursor(text, 6, text.nodeValue); - let end = new Cursor(text, 20, text.nodeValue); - - // Trying to set the selection to a node not in the document should return - // false. - assertFalse(SelectionUtil.setAndValidateSelection(start, end)); - - document.body.appendChild(text); - assertTrue(SelectionUtil.setAndValidateSelection(start, end)); - - // Validate that the selection was set properly. - const selection = window.getSelection(); - assertEquals(text, selection.anchorNode); - assertEquals(6, selection.anchorOffset); - assertEquals(text, selection.focusNode); - assertEquals(20, selection.focusOffset); - - // Check that a selection across nodes works properly. - const secondText = - document.createTextNode('These are a few of my favorite things'); - document.body.appendChild(secondText); - end = new Cursor(secondText, 5, secondText.nodeValue); - assertTrue(SelectionUtil.setAndValidateSelection(start, end)); - - assertEquals(text, selection.anchorNode); - assertEquals(6, selection.anchorOffset); - assertEquals(secondText, selection.focusNode); - assertEquals(5, selection.focusOffset); -}); - -TEST_F('SelectionUtilUnitTest', 'IsCollapsed', function() { - const text = document.createTextNode('When the dog bites'); - document.body.appendChild(text); - - const selection = window.getSelection(); - selection.setBaseAndExtent(text, 0, text, 0); - assertTrue(SelectionUtil.isCollapsed(selection)); - - selection.setBaseAndExtent(text, 0, text, 4); - assertFalse(SelectionUtil.isCollapsed(selection)); -});
diff --git a/ui/accessibility/extensions/caretbrowsing/storage.js b/ui/accessibility/extensions/caretbrowsing/storage.js deleted file mode 100644 index 515a8482..0000000 --- a/ui/accessibility/extensions/caretbrowsing/storage.js +++ /dev/null
@@ -1,172 +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. - -/** @enum {string} */ -const FlourishType = { - ANIMATE: 'anim', - FLASH: 'flash', - NONE: 'none', -}; - -/** - * Class to handle interactions with the chrome.storage API and values that are - * stored that way. - */ -class Storage { - /** - * @param {function()=} opt_callbackForTesting - * @private - */ - constructor(opt_callbackForTesting) { - /** @private {boolean} */ - this.enabled_ = Storage.ENABLED.defaultValue; - /** @private {!FlourishType} */ - this.onEnable_ = Storage.ON_ENABLE.defaultValue; - /** @private {!FlourishType} */ - this.onJump_ = Storage.ON_JUMP.defaultValue; - - this.init_(opt_callbackForTesting); - } - - // ======= Public Methods ======= - - static initialize() { - if (!Storage.instance) { - Storage.instance = new Storage(); - } - } - - /** @return {boolean} */ - static get enabled() { return Storage.instance.enabled_; } - /** @return {!FlourishType} */ - static get onEnable() { return Storage.instance.onEnable_; } - /** @return {!FlourishType} */ - static get onJump() { return Storage.instance.onJump_; } - - /** @param {boolean} newValue */ - static set enabled(newValue) { - Storage.instance.setOrResetValue_(Storage.ENABLED, newValue); - Storage.instance.store_(Storage.ENABLED); - } - - /** @param {!FlourishType} newBehavior */ - static set onEnable(newBehavior) { - Storage.instance.setOrResetValue_(Storage.ON_ENABLE, newBehavior); - Storage.instance.store_(Storage.ON_ENABLE); - } - - /** @param {!FlourishType} newBehavior */ - static set onJump(newBehavior) { - Storage.instance.setOrResetValue_(Storage.ON_JUMP, newBehavior); - Storage.instance.store_(Storage.ON_JUMP); - } - - // ======= Private Methods ======= - - /** - * @param {!Storage.Value} container - * @param {*} newValue - * @private - */ - setOrResetValue_(container, newValue) { - if (newValue === container.get()) { - return; - } - - if (container.validate(newValue)) { - container.set(newValue); - } else { - container.reset(); - } - - container.listeners.forEach(listener => listener(newValue)); - } - - /** - * @param {function()=} opt_callback - * @private - */ - init_(opt_callback) { - chrome.storage.onChanged.addListener(this.onChange_); - chrome.storage.local.get(null /* all values */, (results) => { - const storedValues = Storage.ALL_VALUES.filter(v => results[v.key]); - for (const value of storedValues) { - this.setOrResetValue_(value, results[value.key]); - } - opt_callback ? opt_callback() : undefined; - }); - } - - /** - * @param {!Object<string, chrome.storage.StorageChange>} changes - * @private - */ - onChange_(changes) { - const changedValues = Storage.ALL_VALUES.filter(v => changes[v.key]); - for (const value of changedValues) { - Storage.instance.setOrResetValue_(value, changes[value.key].newValue); - } - } - - /** - * @param {!Storage.Value} value - * @private - */ - store_(value) { - chrome.storage.local.set({ [value.key]: value.get() }); - } - - // ======= Stored Values ======= - - /** - * @typedef {{ - * key: string, - * defaultValue: *, - * validate: function(*): boolean, - * get: function: *, - * set: function(*), - * reset: function(), - * listeners: !Array<function(*)> - * }} - */ - static Value; - - /** @const {!Storage.Value} */ - static ENABLED = { - key: 'enabled', - defaultValue: false, - validate: (enabled) => enabled === true || enabled === false, - get: () => Storage.instance.enabled_, - set: (enabled) => Storage.instance.enabled_ = enabled, - reset: () => Storage.instance.enabled_ = Storage.ENABLED.defaultValue, - listeners: [], - }; - - /** @const {!Storage.Value} */ - static ON_ENABLE = { - key: 'onenable', - defaultValue: FlourishType.ANIMATE, - validate: (onEnable) => Object.values(FlourishType).includes(onEnable), - get: () => Storage.instance.onEnable_, - set: (onEnable) => Storage.instance.onEnable_ = onEnable, - reset: () => Storage.instance.onEnable_ = Storage.ON_ENABLE.defaultValue, - listeners: [], - }; - - /** @const {!Storage.Value} */ - static ON_JUMP = { - key: 'onjump', - defaultValue: FlourishType.FLASH, - validate: (onJump) => Object.values(FlourishType).includes(onJump), - get: () => Storage.instance.onJump_, - set: (onJump) => Storage.instance.onJump_ = onJump, - reset: () => Storage.instance.onJump_ = Storage.ON_JUMP.defaultValue, - listeners: [], - }; - - /** @const {!Array<!Storage.Value>} */ - static ALL_VALUES = [ - Storage.ENABLED, Storage.ON_ENABLE, Storage.ON_JUMP, - ]; -}
diff --git a/ui/accessibility/extensions/caretbrowsing/storage_test.js b/ui/accessibility/extensions/caretbrowsing/storage_test.js deleted file mode 100644 index 9dc7e06..0000000 --- a/ui/accessibility/extensions/caretbrowsing/storage_test.js +++ /dev/null
@@ -1,137 +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. - -GEN_INCLUDE(['storage.js']); - -GEN_INCLUDE([ - '../webstore_extension_test_base.js', - '//chrome/browser/resources/chromeos/accessibility/common/testing/' + - 'callback_helper.js', - '//chrome/browser/resources/chromeos/accessibility/common/testing/' + - 'mock_storage.js', -]); - -/** Test fixture for storage.js. */ -CaretBrowsingStorageTest = class extends WebstoreExtensionTest { - /** @override */ - setUp() { - this.callbackHelper_ = new CallbackHelper(this); - chrome.storage = MockStorage; - Storage.initialize(); - } - - /** - * Increments a counter, to wait for all callbacks to be completed before - * finishing the test. - * @param {Function=} opt_callback - * @return {Function} - */ - newCallback(opt_callback) { - return this.callbackHelper_.wrap(opt_callback); - } -}; - -TEST_F('CaretBrowsingStorageTest', 'DefaultValues', function() { - assertEquals(false, Storage.enabled); - assertEquals(FlourishType.ANIMATE, Storage.onEnable); - assertEquals(FlourishType.FLASH, Storage.onJump); -}); - -TEST_F('CaretBrowsingStorageTest', 'SetValues', function() { - // enabled - Storage.enabled = true; - assertEquals(true, Storage.enabled); - let storedValue = MockStorage.local_[Storage.ENABLED.key]; - assertEquals('boolean', typeof (storedValue)); - assertEquals(true, storedValue); - - // onEnable - Storage.onEnable = FlourishType.NONE; - assertEquals(FlourishType.NONE, Storage.onEnable); - storedValue = MockStorage.local_[Storage.ON_ENABLE.key]; - assertTrue(Object.values(FlourishType).includes(storedValue)); - assertEquals(FlourishType.NONE, storedValue); - - // onJump - Storage.onJump = FlourishType.ANIMATE; - assertEquals(FlourishType.ANIMATE, Storage.onJump); - storedValue = MockStorage.local_[Storage.ON_JUMP.key]; - assertTrue(Object.values(FlourishType).includes(storedValue)); - assertEquals(FlourishType.ANIMATE, storedValue); -}); - -TEST_F('CaretBrowsingStorageTest', 'SetInvalidValues', function() { - // enabled - Storage.enabled = 7; // enabled must be a boolean - assertEquals(false, Storage.enabled); - storedValue = MockStorage.local_[Storage.ENABLED.key]; - assertEquals(false, storedValue); - - // onEnable - Storage.onEnable = true; // onEnable must be a FlourishType. - assertEquals(FlourishType.ANIMATE, Storage.onEnable); - storedValue = MockStorage.local_[Storage.ON_ENABLE.key]; - assertTrue(Object.values(FlourishType).includes(storedValue)); - assertEquals(FlourishType.ANIMATE, storedValue); - - // onJump - Storage.onJump = 'x'; // onJump must be a FlourishType. - assertEquals(FlourishType.FLASH, Storage.onJump); - storedValue = MockStorage.local_[Storage.ON_JUMP.key]; - assertTrue(Object.values(FlourishType).includes(storedValue)); - assertEquals(FlourishType.FLASH, storedValue); -}); - -TEST_F('CaretBrowsingStorageTest', 'Listeners', function() { - Storage.ENABLED.listeners.push(this.newCallback(newVal => { - assertEquals(true, newVal); - Storage.ENABLED.listeners.pop(); - })); - Storage.enabled = true; - - Storage.ON_ENABLE.listeners.push(this.newCallback(newVal => { - assertEquals(FlourishType.NONE, newVal); - Storage.ON_ENABLE.listeners.pop(); - })); - Storage.onEnable = FlourishType.NONE; - - Storage.ON_JUMP.listeners.push(this.newCallback(newVal => { - assertEquals(FlourishType.ANIMATE, newVal); - Storage.ON_JUMP.listeners.pop(); - })); - Storage.onJump = FlourishType.ANIMATE; - -}); - -TEST_F('CaretBrowsingStorageTest', 'InitialFetch', function() { - // Make sure any values from previous tests are cleared. - MockStorage.local_ = {}; - - Storage.enabled = true; - Storage.onJump = FlourishType.NONE; - - // Simulate re-starting the extension by creating a new instance. - Storage.instance = new Storage(this.newCallback(() => { - assertEquals(FlourishType.NONE, Storage.onJump); - assertEquals(true, Storage.enabled); - - // Check that unset values are at default. - assertEquals(FlourishType.ANIMATE, Storage.onEnable); - })); -}); - -TEST_F('CaretBrowsingStorageTest', 'OnChange', function() { - Storage.ON_ENABLE.listeners.push(this.newCallback((newVal) => { - assertEquals(FlourishType.NONE, newVal); - Storage.ON_ENABLE.listeners.pop(); - })); - - - MockStorage.callOnChangedListeners({ - [Storage.ON_ENABLE.key]: FlourishType.NONE }); - - // Check that the value was set properly, in addition to the callbacks being - // called. - assertEquals(FlourishType.NONE, Storage.onEnable); -});
diff --git a/ui/accessibility/extensions/caretbrowsing/traverse_util.js b/ui/accessibility/extensions/caretbrowsing/traverse_util.js deleted file mode 100644 index 1485be8..0000000 --- a/ui/accessibility/extensions/caretbrowsing/traverse_util.js +++ /dev/null
@@ -1,869 +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. */ - -/** - * @fileoverview Low-level DOM traversal utility functions to find the - * next (or previous) character, word, sentence, line, or paragraph, - * in a completely stateless manner without actually manipulating the - * selection. - */ - -/** - * A class to represent a cursor location in the document, - * like the start position or end position of a selection range. - * - * Later this may be extended to support "virtual text" for an object, - * like the ALT text for an image. - * - * Note: we cache the text of a particular node at the time we - * traverse into it. Later we should add support for dynamically - * reloading it. - * @param {Node} node The DOM node. - * @param {number} index The index of the character within the node. - * @param {string} text The cached text contents of the node. - * @constructor - */ -Cursor = function(node, index, text) { - this.node = node; - this.index = index; - this.text = text; -}; - -/** - * @return {Cursor} A new cursor pointing to the same location. - */ -Cursor.prototype.clone = function() { - return new Cursor(this.node, this.index, this.text); -}; - -/** - * Modify this cursor to point to the location that another cursor points to. - * @param {Cursor} otherCursor The cursor to copy from. - */ -Cursor.prototype.copyFrom = function(otherCursor) { - this.node = otherCursor.node; - this.index = otherCursor.index; - this.text = otherCursor.text; -}; - -/** - * Utility functions for stateless DOM traversal. - * @constructor - */ -TraverseUtil = function() {}; - -/** - * Gets the text representation of a node. This allows us to substitute - * alt text, names, or titles for html elements that provide them. - * @param {Node} node A DOM node. - * @return {string} A text string representation of the node. - */ -TraverseUtil.getNodeText = function(node) { - if (node.constructor == Text) { - return node.data; - } else { - return ''; - } -}; - -/** - * Return true if a node should be treated as a leaf node, because - * its children are properties of the object that shouldn't be traversed. - * - * TODO(dmazzoni): replace this with a predicate that detects nodes with - * ARIA roles and other objects that have their own description. - * For now we just detect a couple of common cases. - * - * @param {Node} node A DOM node. - * @return {boolean} True if the node should be treated as a leaf node. - */ -TraverseUtil.treatAsLeafNode = function(node) { - return node.childNodes.length == 0 || - node.nodeName == 'SELECT' || - node.nodeName == 'OBJECT'; -}; - -/** - * Return true only if a single character is whitespace. - * From https://developer.mozilla.org/en/Whitespace_in_the_DOM, - * whitespace is defined as one of the characters - * "\t" TAB \u0009 - * "\n" LF \u000A - * "\r" CR \u000D - * " " SPC \u0020. - * - * @param {string} c A string containing a single character. - * @return {boolean} True if the character is whitespace, otherwise false. - */ -TraverseUtil.isWhitespace = function(c) { - return (c == ' ' || c == '\n' || c == '\r' || c == '\t'); -}; - -/** - * Set the selection to the range between the given start and end cursors. - * @param {Cursor} start The desired start of the selection. - * @param {Cursor} end The desired end of the selection. - * @return {Selection} the selection object. - */ -TraverseUtil.setSelection = function(start, end) { - const sel = window.getSelection(); - sel.removeAllRanges(); - const range = document.createRange(); - range.setStart(start.node, start.index); - range.setEnd(end.node, end.index); - sel.addRange(range); - - return sel; -}; - -/** - * Use the computed CSS style to figure out if this DOM node is currently - * visible. - * @param {Node} node A HTML DOM node. - * @return {boolean} Whether or not the html node is visible. - */ -TraverseUtil.isVisible = function(node) { - if (!node.style) - return true; - const style = window.getComputedStyle(/** @type {Element} */(node), null); - return (!!style && style.display != 'none' && style.visibility != 'hidden'); -}; - -/** - * Use the class name to figure out if this DOM node should be traversed. - * @param {Node} node A HTML DOM node. - * @return {boolean} Whether or not the html node should be traversed. - */ -TraverseUtil.isSkipped = function(node) { - if (node.constructor == Text) - node = node.parentElement; - if (node.className == 'CaretBrowsing_Caret' || - node.className == 'CaretBrowsing_AnimateCaret') { - return true; - } - return false; -}; - -/** - * Moves the cursor forwards until it has crossed exactly one character. - * @param {Cursor} cursor The cursor location where the search should start. - * On exit, the cursor will be immediately to the right of the - * character returned. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @return {?string} The character found, or null if the bottom of the - * document has been reached. - */ -TraverseUtil.forwardsChar = function(cursor, nodesCrossed) { - while (true) { - // Move down until we get to a leaf node. - let childNode = null; - if (!TraverseUtil.treatAsLeafNode(cursor.node)) { - for (let i = cursor.index; i < cursor.node.childNodes.length; i++) { - const node = cursor.node.childNodes[i]; - if (TraverseUtil.isSkipped(node)) { - nodesCrossed.push(node); - continue; - } - if (TraverseUtil.isVisible(node)) { - childNode = node; - break; - } - } - } - if (childNode) { - cursor.node = childNode; - cursor.index = 0; - cursor.text = TraverseUtil.getNodeText(cursor.node); - if (cursor.node.constructor != Text) { - nodesCrossed.push(cursor.node); - } - continue; - } - - // Return the next character from this leaf node. - if (cursor.index < cursor.text.length) - return cursor.text[cursor.index++]; - - // Move to the next sibling, going up the tree as necessary. - while (cursor.node != null) { - // Try to move to the next sibling. - let siblingNode = null; - for (let node = cursor.node.nextSibling; - node != null; - node = node.nextSibling) { - if (TraverseUtil.isSkipped(node)) { - nodesCrossed.push(node); - continue; - } - if (TraverseUtil.isVisible(node)) { - siblingNode = node; - break; - } - } - if (siblingNode) { - cursor.node = siblingNode; - cursor.text = TraverseUtil.getNodeText(siblingNode); - cursor.index = 0; - - if (cursor.node.constructor != Text) { - nodesCrossed.push(cursor.node); - } - - break; - } - - // Otherwise, move to the parent. - if (cursor.node.parentNode && - cursor.node.parentNode.constructor != HTMLBodyElement) { - cursor.node = cursor.node.parentNode; - cursor.text = null; - cursor.index = 0; - } else { - return null; - } - } - } -}; - -/** - * Moves the cursor backwards until it has crossed exactly one character. - * @param {Cursor} cursor The cursor location where the search should start. - * On exit, the cursor will be immediately to the left of the - * character returned. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @return {?string} The previous character, or null if the top of the - * document has been reached. - */ -TraverseUtil.backwardsChar = function(cursor, nodesCrossed) { - while (true) { - // Move down until we get to a leaf node. - let childNode = null; - if (!TraverseUtil.treatAsLeafNode(cursor.node)) { - for (let i = cursor.index - 1; i >= 0; i--) { - const node = cursor.node.childNodes[i]; - if (TraverseUtil.isSkipped(node)) { - nodesCrossed.push(node); - continue; - } - if (TraverseUtil.isVisible(node)) { - childNode = node; - break; - } - } - } - if (childNode) { - cursor.node = childNode; - cursor.text = TraverseUtil.getNodeText(cursor.node); - if (cursor.text.length) - cursor.index = cursor.text.length; - else - cursor.index = cursor.node.childNodes.length; - if (cursor.node.constructor != Text) - nodesCrossed.push(cursor.node); - continue; - } - - // Return the previous character from this leaf node. - if (cursor.text.length > 0 && cursor.index > 0) { - return cursor.text[--cursor.index]; - } - - // Move to the previous sibling, going up the tree as necessary. - while (true) { - // Try to move to the previous sibling. - let siblingNode = null; - for (let node = cursor.node.previousSibling; - node != null; - node = node.previousSibling) { - if (TraverseUtil.isSkipped(node)) { - nodesCrossed.push(node); - continue; - } - if (TraverseUtil.isVisible(node)) { - siblingNode = node; - break; - } - } - if (siblingNode) { - cursor.node = siblingNode; - cursor.text = TraverseUtil.getNodeText(siblingNode); - if (cursor.text.length) - cursor.index = cursor.text.length; - else - cursor.index = cursor.node.childNodes.length; - if (cursor.node.constructor != Text) - nodesCrossed.push(cursor.node); - break; - } - - // Otherwise, move to the parent. - if (cursor.node.parentNode && - cursor.node.parentNode.constructor != HTMLBodyElement) { - cursor.node = cursor.node.parentNode; - cursor.text = null; - cursor.index = 0; - } else { - return null; - } - } - } -}; - -/** - * Finds the next character, starting from endCursor. Upon exit, startCursor - * and endCursor will surround the next character. If skipWhitespace is - * true, will skip until a real character is found. Otherwise, it will - * attempt to select all of the whitespace between the initial position - * of endCursor and the next non-whitespace character. - * @param {Cursor} startCursor On exit, points to the position before - * the char. - * @param {Cursor} endCursor The position to start searching for the next - * char. On exit, will point to the position past the char. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @param {boolean} skipWhitespace If true, will keep scanning until a - * non-whitespace character is found. - * @return {?string} The next char, or null if the bottom of the - * document has been reached. - */ -TraverseUtil.getNextChar = function( - startCursor, endCursor, nodesCrossed, skipWhitespace) { - - // Save the starting position and get the first character. - startCursor.copyFrom(endCursor); - let c = TraverseUtil.forwardsChar(endCursor, nodesCrossed); - if (c == null) - return null; - - // Keep track of whether the first character was whitespace. - const initialWhitespace = TraverseUtil.isWhitespace(c); - - // Keep scanning until we find a non-whitespace or non-skipped character. - while ((TraverseUtil.isWhitespace(c)) || - (TraverseUtil.isSkipped(endCursor.node))) { - c = TraverseUtil.forwardsChar(endCursor, nodesCrossed); - if (c == null) - return null; - } - if (skipWhitespace || !initialWhitespace) { - // If skipWhitepace is true, or if the first character we encountered - // was not whitespace, return that non-whitespace character. - startCursor.copyFrom(endCursor); - startCursor.index--; - return c; - } - else { - for (let i = 0; i < nodesCrossed.length; i++) { - if (TraverseUtil.isSkipped(nodesCrossed[i])) { - // We need to make sure that startCursor and endCursor aren't - // surrounding a skippable node. - endCursor.index--; - startCursor.copyFrom(endCursor); - startCursor.index--; - return ' '; - } - } - // Otherwise, return all of the whitespace before that last character. - endCursor.index--; - return ' '; - } -}; - -/** - * Finds the previous character, starting from startCursor. Upon exit, - * startCursor and endCursor will surround the previous character. - * If skipWhitespace is true, will skip until a real character is found. - * Otherwise, it will attempt to select all of the whitespace between - * the initial position of endCursor and the next non-whitespace character. - * @param {Cursor} startCursor The position to start searching for the - * char. On exit, will point to the position before the char. - * @param {Cursor} endCursor The position to start searching for the next - * char. On exit, will point to the position past the char. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @param {boolean} skipWhitespace If true, will keep scanning until a - * non-whitespace character is found. - * @return {?string} The previous char, or null if the top of the - * document has been reached. - */ -TraverseUtil.getPreviousChar = function( - startCursor, endCursor, nodesCrossed, skipWhitespace) { - - // Save the starting position and get the first character. - endCursor.copyFrom(startCursor); - let c = TraverseUtil.backwardsChar(startCursor, nodesCrossed); - if (c == null) - return null; - - // Keep track of whether the first character was whitespace. - const initialWhitespace = TraverseUtil.isWhitespace(c); - - // Keep scanning until we find a non-whitespace or non-skipped character. - while ((TraverseUtil.isWhitespace(c)) || - (TraverseUtil.isSkipped(startCursor.node))) { - c = TraverseUtil.backwardsChar(startCursor, nodesCrossed); - if (c == null) - return null; - } - if (skipWhitespace || !initialWhitespace) { - // If skipWhitepace is true, or if the first character we encountered - // was not whitespace, return that non-whitespace character. - endCursor.copyFrom(startCursor); - endCursor.index++; - return c; - } else { - for (let i = 0; i < nodesCrossed.length; i++) { - if (TraverseUtil.isSkipped(nodesCrossed[i])) { - startCursor.index++; - endCursor.copyFrom(startCursor); - endCursor.index++; - return ' '; - } - } - // Otherwise, return all of the whitespace before that last character. - startCursor.index++; - return ' '; - } -}; - -/** - * Finds the next word, starting from endCursor. Upon exit, startCursor - * and endCursor will surround the next word. A word is defined to be - * a string of 1 or more non-whitespace characters in the same DOM node. - * @param {Cursor} startCursor On exit, will point to the beginning of the - * word returned. - * @param {Cursor} endCursor The position to start searching for the next - * word. On exit, will point to the end of the word returned. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @return {?string} The next word, or null if the bottom of the - * document has been reached. - */ -TraverseUtil.getNextWord = function(startCursor, endCursor, - nodesCrossed) { - - // Find the first non-whitespace or non-skipped character. - const cursor = endCursor.clone(); - let c = TraverseUtil.forwardsChar(cursor, nodesCrossed); - if (c == null) - return null; - while ((TraverseUtil.isWhitespace(c)) || - (TraverseUtil.isSkipped(cursor.node))) { - c = TraverseUtil.forwardsChar(cursor, nodesCrossed); - if (c == null) - return null; - } - - // Set startCursor to the position immediately before the first - // character in our word. It's safe to decrement |index| because - // forwardsChar guarantees that the cursor will be immediately to the - // right of the returned character on exit. - startCursor.copyFrom(cursor); - startCursor.index--; - - // Keep building up our word until we reach a whitespace character or - // would cross a tag. Don't actually return any tags crossed, because this - // word goes up until the tag boundary but not past it. - endCursor.copyFrom(cursor); - let word = c; - const newNodesCrossed = []; - c = TraverseUtil.forwardsChar(cursor, newNodesCrossed); - if (c == null) { - return word; - } - while (!TraverseUtil.isWhitespace(c) && - newNodesCrossed.length == 0) { - word += c; - endCursor.copyFrom(cursor); - c = TraverseUtil.forwardsChar(cursor, newNodesCrossed); - if (c == null) { - return word; - } - } - return word; -}; - -/** - * Finds the previous word, starting from startCursor. Upon exit, startCursor - * and endCursor will surround the previous word. A word is defined to be - * a string of 1 or more non-whitespace characters in the same DOM node. - * @param {Cursor} startCursor The position to start searching for the - * previous word. On exit, will point to the beginning of the - * word returned. - * @param {Cursor} endCursor On exit, will point to the end of the - * word returned. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @return {?string} The previous word, or null if the bottom of the - * document has been reached. - */ -TraverseUtil.getPreviousWord = function(startCursor, endCursor, - nodesCrossed) { - // Find the first non-whitespace or non-skipped character. - const cursor = startCursor.clone(); - let c = TraverseUtil.backwardsChar(cursor, nodesCrossed); - if (c == null) - return null; - while ((TraverseUtil.isWhitespace(c) || - (TraverseUtil.isSkipped(cursor.node)))) { - c = TraverseUtil.backwardsChar(cursor, nodesCrossed); - if (c == null) - return null; - } - - // Set endCursor to the position immediately after the first - // character we've found (the last character of the word, since we're - // searching backwards). - endCursor.copyFrom(cursor); - endCursor.index++; - - // Keep building up our word until we reach a whitespace character or - // would cross a tag. Don't actually return any tags crossed, because this - // word goes up until the tag boundary but not past it. - startCursor.copyFrom(cursor); - let word = c; - const newNodesCrossed = []; - c = TraverseUtil.backwardsChar(cursor, newNodesCrossed); - if (c == null) - return word; - while (!TraverseUtil.isWhitespace(c) && - newNodesCrossed.length == 0) { - word = c + word; - startCursor.copyFrom(cursor); - c = TraverseUtil.backwardsChar(cursor, newNodesCrossed); - if (c == null) - return word; - } - - return word; -}; - -/** - * Finds the next sentence, starting from endCursor. Upon exit, - * startCursor and endCursor will surround the next sentence. - * - * @param {Cursor} startCursor On exit, marks the beginning of the sentence. - * @param {Cursor} endCursor The position to start searching for the next - * sentence. On exit, will point to the end of the returned string. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @param {Object} breakTags Associative array of tags that should break - * the sentence. - * @return {?string} The next sentence, or null if the bottom of the - * document has been reached. - */ -TraverseUtil.getNextSentence = function( - startCursor, endCursor, nodesCrossed, breakTags) { - return TraverseUtil.getNextString( - startCursor, endCursor, nodesCrossed, - function(str, word, nodes) { - if (str.substr(-1) == '.') - return true; - for (let i = 0; i < nodes.length; i++) { - if (TraverseUtil.isSkipped(nodes[i])) { - return true; - } - const style = window.getComputedStyle(nodes[i], null); - if (style && (style.display != 'inline' || - breakTags[nodes[i].tagName])) { - return true; - } - } - return false; - }); -}; - -/** - * Finds the previous sentence, starting from startCursor. Upon exit, - * startCursor and endCursor will surround the previous sentence. - * - * @param {Cursor} startCursor The position to start searching for the next - * sentence. On exit, will point to the start of the returned string. - * @param {Cursor} endCursor On exit, the end of the returned string. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @param {Object} breakTags Associative array of tags that should break - * the sentence. - * @return {?string} The previous sentence, or null if the bottom of the - * document has been reached. - */ -TraverseUtil.getPreviousSentence = function( - startCursor, endCursor, nodesCrossed, breakTags) { - return TraverseUtil.getPreviousString( - startCursor, endCursor, nodesCrossed, - function(str, word, nodes) { - if (word.substr(-1) == '.') - return true; - for (let i = 0; i < nodes.length; i++) { - if (TraverseUtil.isSkipped(nodes[i])) { - return true; - } - const style = window.getComputedStyle(nodes[i], null); - if (style && (style.display != 'inline' || - breakTags[nodes[i].tagName])) { - return true; - } - } - return false; - }); -}; - -/** - * Finds the next line, starting from endCursor. Upon exit, - * startCursor and endCursor will surround the next line. - * - * @param {Cursor} startCursor On exit, marks the beginning of the line. - * @param {Cursor} endCursor The position to start searching for the next - * line. On exit, will point to the end of the returned string. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @param {number} lineLength The maximum number of characters in a line. - * @param {Object} breakTags Associative array of tags that should break - * the line. - * @return {?string} The next line, or null if the bottom of the - * document has been reached. - */ -TraverseUtil.getNextLine = function( - startCursor, endCursor, nodesCrossed, lineLength, breakTags) { - return TraverseUtil.getNextString( - startCursor, endCursor, nodesCrossed, - function(str, word, nodes) { - if (str.length + word.length + 1 > lineLength) - return true; - for (let i = 0; i < nodes.length; i++) { - if (TraverseUtil.isSkipped(nodes[i])) { - return true; - } - const style = window.getComputedStyle(nodes[i], null); - if (style && (style.display != 'inline' || - breakTags[nodes[i].tagName])) { - return true; - } - } - return false; - }); -}; - -/** - * Finds the previous line, starting from startCursor. Upon exit, - * startCursor and endCursor will surround the previous line. - * - * @param {Cursor} startCursor The position to start searching for the next - * line. On exit, will point to the start of the returned string. - * @param {Cursor} endCursor On exit, the end of the returned string. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @param {number} lineLength The maximum number of characters in a line. - * @param {Object} breakTags Associative array of tags that should break - * the sentence. - * @return {?string} The previous line, or null if the bottom of the - * document has been reached. - */ -TraverseUtil.getPreviousLine = function( - startCursor, endCursor, nodesCrossed, lineLength, breakTags) { - return TraverseUtil.getPreviousString( - startCursor, endCursor, nodesCrossed, - function(str, word, nodes) { - if (str.length + word.length + 1 > lineLength) - return true; - for (let i = 0; i < nodes.length; i++) { - if (TraverseUtil.isSkipped(nodes[i])) { - return true; - } - const style = window.getComputedStyle(nodes[i], null); - if (style && (style.display != 'inline' || - breakTags[nodes[i].tagName])) { - return true; - } - } - return false; - }); -}; - -/** - * Finds the next paragraph, starting from endCursor. Upon exit, - * startCursor and endCursor will surround the next paragraph. - * - * @param {Cursor} startCursor On exit, marks the beginning of the paragraph. - * @param {Cursor} endCursor The position to start searching for the next - * paragraph. On exit, will point to the end of the returned string. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @return {?string} The next paragraph, or null if the bottom of the - * document has been reached. - */ -TraverseUtil.getNextParagraph = function(startCursor, endCursor, - nodesCrossed) { - return TraverseUtil.getNextString( - startCursor, endCursor, nodesCrossed, - function(str, word, nodes) { - for (let i = 0; i < nodes.length; i++) { - if (TraverseUtil.isSkipped(nodes[i])) { - return true; - } - const style = window.getComputedStyle(nodes[i], null); - if (style && style.display != 'inline') { - return true; - } - } - return false; - }); -}; - -/** - * Finds the previous paragraph, starting from startCursor. Upon exit, - * startCursor and endCursor will surround the previous paragraph. - * - * @param {Cursor} startCursor The position to start searching for the next - * paragraph. On exit, will point to the start of the returned string. - * @param {Cursor} endCursor On exit, the end of the returned string. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @return {?string} The previous paragraph, or null if the bottom of the - * document has been reached. - */ -TraverseUtil.getPreviousParagraph = function( - startCursor, endCursor, nodesCrossed) { - return TraverseUtil.getPreviousString( - startCursor, endCursor, nodesCrossed, - function(str, word, nodes) { - for (let i = 0; i < nodes.length; i++) { - if (TraverseUtil.isSkipped(nodes[i])) { - return true; - } - const style = window.getComputedStyle(nodes[i], null); - if (style && style.display != 'inline') { - return true; - } - } - return false; - }); -}; - -/** - * Customizable function to return the next string of words in the DOM, based - * on provided functions to decide when to break one string and start - * the next. This can be used to get the next sentence, line, paragraph, - * or potentially other granularities. - * - * Finds the next contiguous string, starting from endCursor. Upon exit, - * startCursor and endCursor will surround the next string. - * - * The breakBefore function takes three parameters, and - * should return true if the string should be broken before the proposed - * next word: - * str The string so far. - * word The next word to be added. - * nodesCrossed The nodes crossed in reaching this next word. - * - * @param {Cursor} startCursor On exit, will point to the beginning of the - * next string. - * @param {Cursor} endCursor The position to start searching for the next - * string. On exit, will point to the end of the returned string. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @param {function(string, string, Array<string>)} breakBefore - * Function that takes the string so far, next word to be added, and - * nodes crossed, and returns true if the string should be ended before - * adding this word. - * @return {?string} The next string, or null if the bottom of the - * document has been reached. - */ -TraverseUtil.getNextString = function( - startCursor, endCursor, nodesCrossed, breakBefore) { - // Get the first word and set the start cursor to the start of the - // first word. - const wordStartCursor = endCursor.clone(); - const wordEndCursor = endCursor.clone(); - let newNodesCrossed = []; - let str = ''; - let word = TraverseUtil.getNextWord( - wordStartCursor, wordEndCursor, newNodesCrossed); - if (word == null) - return null; - startCursor.copyFrom(wordStartCursor); - - // Always add the first word when the string is empty, and then keep - // adding more words as long as breakBefore returns false - while (!str || !breakBefore(str, word, newNodesCrossed)) { - // Append this word, set the end cursor to the end of this word, and - // update the returned list of nodes crossed to include ones we crossed - // in reaching this word. - if (str) - str += ' '; - str += word; - nodesCrossed = nodesCrossed.concat(newNodesCrossed); - endCursor.copyFrom(wordEndCursor); - - // Get the next word and go back to the top of the loop. - newNodesCrossed = []; - word = TraverseUtil.getNextWord( - wordStartCursor, wordEndCursor, newNodesCrossed); - if (word == null) - return str; - } - - return str; -}; - -/** - * Customizable function to return the previous string of words in the DOM, - * based on provided functions to decide when to break one string and start - * the next. See getNextString, above, for more details. - * - * Finds the previous contiguous string, starting from startCursor. Upon exit, - * startCursor and endCursor will surround the next string. - * - * @param {Cursor} startCursor The position to start searching for the - * previous string. On exit, will point to the beginning of the - * string returned. - * @param {Cursor} endCursor On exit, will point to the end of the - * string returned. - * @param {Array<Node>} nodesCrossed Any HTML nodes crossed between the - * initial and final cursor position will be pushed onto this array. - * @param {function(string, string, Array<string>)} breakBefore - * Function that takes the string so far, the word to be added, and - * nodes crossed, and returns true if the string should be ended before - * adding this word. - * @return {?string} The next string, or null if the top of the - * document has been reached. - */ -TraverseUtil.getPreviousString = function( - startCursor, endCursor, nodesCrossed, breakBefore) { - // Get the first word and set the end cursor to the end of the - // first word. - const wordStartCursor = startCursor.clone(); - const wordEndCursor = startCursor.clone(); - let newNodesCrossed = []; - let str = ''; - let word = TraverseUtil.getPreviousWord( - wordStartCursor, wordEndCursor, newNodesCrossed); - if (word == null) - return null; - endCursor.copyFrom(wordEndCursor); - - // Always add the first word when the string is empty, and then keep - // adding more words as long as breakBefore returns false - while (!str || !breakBefore(str, word, newNodesCrossed)) { - // Prepend this word, set the start cursor to the start of this word, and - // update the returned list of nodes crossed to include ones we crossed - // in reaching this word. - if (str) - str = ' ' + str; - str = word + str; - nodesCrossed = nodesCrossed.concat(newNodesCrossed); - startCursor.copyFrom(wordStartCursor); - - // Get the previous word and go back to the top of the loop. - newNodesCrossed = []; - word = TraverseUtil.getPreviousWord( - wordStartCursor, wordEndCursor, newNodesCrossed); - if (word == null) - return str; - } - - return str; -};
diff --git a/ui/accessibility/extensions/chromevoxclassic/manifest.json.jinja2 b/ui/accessibility/extensions/chromevoxclassic/manifest.json.jinja2 index 89f534c..b463fdba 100644 --- a/ui/accessibility/extensions/chromevoxclassic/manifest.json.jinja2 +++ b/ui/accessibility/extensions/chromevoxclassic/manifest.json.jinja2
@@ -23,7 +23,7 @@ "manifest_version": 2, "name": "Screen Reader", "options_page": "chromevox/background/options.html", - "permissions": [ "accessibilityPrivate", "bookmarks", "history", "notifications", "storage", "tabs", "tts", "<all_urls>" ], + "permissions": [ "accessibilityPrivate", "history", "notifications", "storage", "tabs", "tts", "<all_urls>" ], "update_url": "https://clients2.google.com/service/update2/crx", "version": "53.0.2784.11", "web_accessible_resources": [ "chromevox/background/keymaps/next_keymap.json", "chromevox/injected/api.js", "chromevox/injected/api_util.js", "chromevox/injected/mathjax.js", "chromevox/injected/mathjax_external_util.js", "webcomponents-bundle.js" ]
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc index 5c16c11..8c95bc4 100644 --- a/ui/android/delegated_frame_host_android.cc +++ b/ui/android/delegated_frame_host_android.cc
@@ -21,6 +21,7 @@ #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/common/surfaces/surface_id.h" +#include "components/viz/common/viz_utils.h" #include "components/viz/host/host_frame_sink_manager.h" #include "ui/android/view_android.h" #include "ui/android/window_android.h" @@ -160,25 +161,8 @@ request->set_result_task_runner( base::SequencedTaskRunner::GetCurrentDefault()); - if (!src_subrect.IsEmpty()) - request->set_area(src_subrect); - if (!output_size.IsEmpty()) { - // The CopyOutputRequest API does not allow fixing the output size. Instead - // we have the set area and scale in such a way that it would result in the - // desired output size. - if (!request->has_area()) - request->set_area(gfx::Rect(surface_size_in_pixels_)); - request->set_result_selection(gfx::Rect(output_size)); - const gfx::Rect& area = request->area(); - // Viz would normally return an empty result for an empty area. - // However, this guard here is still necessary to protect against setting - // an illegal scaling ratio. - if (area.IsEmpty()) - return; - request->SetScaleRatio( - gfx::Vector2d(area.width(), area.height()), - gfx::Vector2d(output_size.width(), output_size.height())); - } + viz::SetCopyOutoutRequestResultSize(request.get(), src_subrect, output_size, + surface_size_in_pixels_); host_frame_sink_manager_->RequestCopyOfOutput(surface_id, std::move(request), capture_exact_surface_id);
diff --git a/ui/views/window/dialog_client_view.cc b/ui/views/window/dialog_client_view.cc index 2aaa3b8..2129831b 100644 --- a/ui/views/window/dialog_client_view.cc +++ b/ui/views/window/dialog_client_view.cc
@@ -508,10 +508,6 @@ .SetLinkedColumnSizeLimit(layout_provider->GetDistanceMetric( DISTANCE_BUTTON_MAX_LINKABLE_WIDTH)); - // Track which columns to link sizes under MD. - constexpr size_t kViewToColumnIndex[] = {1, 3, 5}; - std::vector<size_t> columns_to_link; - // Skip views that are not a button, or are a specific subclass of Button // that should never be linked. Otherwise, link everything. auto should_link = [](views::View* view) { @@ -519,19 +515,27 @@ !IsViewClass<ImageButton>(view); }; - for (size_t view_index = 0; view_index < kNumButtons; ++view_index) { - if (views[view_index]) { - RemoveFillerView(view_index); - button_row_container_->ReorderChildView(views[view_index], view_index); - if (should_link(views[view_index])) { - columns_to_link.push_back(kViewToColumnIndex[view_index]); - } + for (size_t i = 0; i < kNumButtons; ++i) { + if (views[i]) { + RemoveFillerView(i); + button_row_container_->ReorderChildView(views[i], i); } else { - AddFillerView(view_index); + AddFillerView(i); } } - layout->LinkColumnSizes(columns_to_link); + { + std::vector<size_t> cols; + for (size_t i = 0; i < kNumButtons; ++i) { + if (should_link(views[i])) { + // View columns are interspersed with padding columns, so view i is at + // column i * 2 + 1 in the TableLayout (view 0 is in column 1, view 1 is + // in column 3, etc). + cols.push_back(i * 2 + 1); + } + } + layout->LinkColumnSizes(cols); + } // The default focus is lost when child views are added back into the dialog. // This restores focus if the button is still available.
diff --git a/ui/webui/resources/cr_components/history_embeddings/history_embeddings.html b/ui/webui/resources/cr_components/history_embeddings/history_embeddings.html index 0c373adc..5f08203b 100644 --- a/ui/webui/resources/cr_components/history_embeddings/history_embeddings.html +++ b/ui/webui/resources/cr_components/history_embeddings/history_embeddings.html
@@ -99,7 +99,7 @@ <cr-url-list-item url="[[item.url.url]]" title="[[item.title]]" description="[[item.urlForDisplay]]" on-click="onResultClick_" on-auxclick="onResultClick_" - as-anchor always-show-suffix> + as-anchor as-anchor-target="_blank" always-show-suffix> <span slot="suffix">[[item.relativeTime]]</span> <cr-icon-button slot="suffix" iron-icon="cr:more-vert" on-click="onMoreActionsClick_">
diff --git a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html.ts b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html.ts index e8d46bcc..8cc021af 100644 --- a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html.ts +++ b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html.ts
@@ -7,6 +7,7 @@ import {nothing} from '//resources/lit/v3_0/lit.rollup.js'; export function getHtml(this: CrDialogElement) { + // clang-format off return html` <dialog id="dialog" @close="${this.onNativeDialogClose_}" @cancel="${this.onNativeDialogCancel_}" part="dialog" @@ -19,11 +20,12 @@ <h2 id="title" class="title-container" tabindex="-1"> <slot name="title"></slot> </h2> - <cr-icon-button id="close" class="icon-clear" - ?hidden="${!this.showCloseButton}" - aria-label="${this.closeText || nothing}" - @click="${this.cancel}" @keypress="${this.onCloseKeypress_}"> - </cr-icon-button> + ${this.showCloseButton ? html` + <cr-icon-button id="close" class="icon-clear" + aria-label="${this.closeText || nothing}" + @click="${this.cancel}" @keypress="${this.onCloseKeypress_}"> + </cr-icon-button> + ` : ''} </div> <slot name="header"></slot> <div class="body-container" id="container" show-bottom-shadow @@ -34,4 +36,5 @@ <slot name="footer"></slot> </div> </dialog>`; + // clang-format on }
diff --git a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.ts b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.ts index 014d591..f3fd068d 100644 --- a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.ts +++ b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.ts
@@ -25,7 +25,6 @@ import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; import {CrContainerShadowMixinLit} from '../cr_container_shadow_mixin_lit.js'; -import type {CrIconButtonElement} from '../cr_icon_button/cr_icon_button.js'; import type {CrInputElement} from '../cr_input/cr_input.js'; import {getCss} from './cr_dialog.css.js'; @@ -35,7 +34,6 @@ export interface CrDialogElement { $: { - close: CrIconButtonElement, dialog: HTMLDialogElement, }; }
diff --git a/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html.ts b/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html.ts index ccb2999..2219d1c9 100644 --- a/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html.ts +++ b/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html.ts
@@ -7,10 +7,11 @@ import type {CrLinkRowElement} from './cr_link_row.js'; export function getHtml(this: CrLinkRowElement) { + // clang-format off return html` -<cr-icon id="startIcon" .icon="${this.startIcon}" ?hidden="${!this.startIcon}" - aria-hidden="true"> -</cr-icon> + ${this.startIcon ? html` +<cr-icon id="startIcon" .icon="${this.startIcon}" aria-hidden="true"></cr-icon> + `: ''} <div id="labelWrapper" ?hidden="${this.shouldHideLabelWrapper_()}"> <div id="label" aria-hidden="${!this.ariaShowLabel}"> ${this.label} @@ -31,4 +32,5 @@ aria-describedby="buttonAriaDescription" aria-labelledby="label subLabel" ?disabled="${this.disabled}"> </cr-icon-button>`; + // clang-format on }
diff --git a/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.html.ts b/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.html.ts index 4fd9c74..6af78ca 100644 --- a/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.html.ts +++ b/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.html.ts
@@ -30,6 +30,7 @@ export function getHtml(this: CrUrlListItemElement) { return html` <a id="anchor" .href="${this.url}" ?hidden="${!this.asAnchor}" + target="${this.asAnchorTarget}" aria-label="${this.getItemAriaLabel_()}" aria-description="${this.getItemAriaDescription_() || nothing}"> </a>
diff --git a/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.ts b/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.ts index 0b914ff..a259ffa 100644 --- a/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.ts +++ b/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.ts
@@ -23,7 +23,7 @@ export interface CrUrlListItemElement { $: { - anchor: HTMLElement, + anchor: HTMLAnchorElement, badgesContainer: HTMLElement, badges: HTMLSlotElement, button: HTMLElement, @@ -117,11 +117,13 @@ * activate. */ asAnchor: {type: Boolean}, + asAnchorTarget: {type: String}, }; } alwaysShowSuffix: boolean = false; asAnchor: boolean = false; + asAnchorTarget: string = '_self'; itemAriaLabel?: string; itemAriaDescription?: string; count?: number;
diff --git a/ui/webui/resources/tools/codemods/lit_migration_templates.mjs b/ui/webui/resources/tools/codemods/lit_migration_templates.mjs index c240499..c5dd93e 100644 --- a/ui/webui/resources/tools/codemods/lit_migration_templates.mjs +++ b/ui/webui/resources/tools/codemods/lit_migration_templates.mjs
@@ -27,8 +27,14 @@ const LISTENER_BINDING_REGEX = /on-(?<eventName>[a-zA-Z-]+)="(?<listenerName>[a-zA-Z_]+)"/g; +// Regular expression to extract any "${this.foo}" ocurrences in the HTML +// template, referring to TS methods or member variables. +const TS_REFERENCE_REGEX = + /"\$\{this\.(?<reference>[a-zA-Z_]+)\}"/g; + function processFile(file) { const basename = path.basename(file, '.ts'); + const tsFile = path.join(path.dirname(file), basename + '.ts'); const htmlFile = path.join(path.dirname(file), basename + '.html'); const cssFile = path.join(path.dirname(file), basename + '.css'); @@ -59,6 +65,19 @@ // Step 5: Write updated HTML content to disk fs.writeFileSync(htmlFile, htmlContent, 'utf8'); + + // Step 6: Extract all methods/variables being referenced from the template + // and if they are 'private' change them to 'protected'. + const references = Array.from( + htmlContent.matchAll(TS_REFERENCE_REGEX)).map(m => m[1]); + if (references.length > 0) { + let tsContent = fs.readFileSync(tsFile, 'utf8'); + for (const ref of references) { + tsContent = tsContent.replace(`private ${ref}`, `protected ${ref}`); + } + // Step 7: Write updated TS content to disk + fs.writeFileSync(tsFile, tsContent, 'utf8'); + } } function main() {
diff --git a/v8 b/v8 index f0366cb..06b1e2c 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit f0366cb2215c9ee342a870b52db0769aad7b20d4 +Subproject commit 06b1e2c29489af4922ca60a44347ce0ef7c36ebb